Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re: Perl templating/macro creating using 'BEGIN'...

by Corion (Pope)
on Sep 27, 2010 at 17:04 UTC ( #862248=note: print w/replies, xml ) Need Help??


in reply to Perl templating/macro creating using 'BEGIN'...

BEGIN { sub main_package_vars { foreach(@_) { eval "sub $_ { my \$p = shift; \$p->{$_} = \$_[0] if \@_; \$p->{$_}; }" } } }

Why do you put this in a BEGIN block? It serves no purpose, at least when Perl looks at it.

Also, why are you using string-eval, when the plain eval works just as well. Also see Class::Accessor.

sub main_package_vars { foreach my $name (@_) { no strict 'refs'; *{ $name } = sub { my $p = shift; $p->{$name} = $_[0] if @_; $p->{$name}; }" } }

In this next snippet from MyPackage, I don't understand why you use string-eval, and also why you try to execute the same statement twice:

BEGIN { eval "*package_vars2 = \*main::main_package_vars"; *package_vars3 = \*main::main_package_vars; }

The subroutine package_vars3 does not exist:

package_vars3( qw(one two three) );

What problem are you trying to solve? Do you want to have a hash using which you get/set variables?

Maybe an object based on a plain hash using AUTOLOAD is already enough? If you want control over what keys get stored, again, see Class::Accessor.</c>

Replies are listed 'Best First'.
Re^2: Perl templating/macro creating using 'BEGIN'...
by perl-diddler (Hermit) on Sep 27, 2010 at 17:39 UTC
    The first 'main_package_vars' is in a BEGIN block because it is a duplicate of the one below it. I want to move the BEGIN block out of the package declaration and into the 'main' block.

    Then I want to use the package_vars definition in 'main'. I.e. I started with a BEGIN block only in a package like this (which works, but doesn't work if I remove the BEGIN block as you seem(?) to be suggesting).

    #!/usr/bin/perl -w use strict; use feature ':5.10'; package MyPackage; { BEGIN { sub package_vars { foreach(@_) { eval "sub $_ { my \$p = shift; \$p->{$_} = \$_[0] if \@_; \$p->{$_}; }" } } } package_vars( qw(one two three) ); sub new { my $package=shift; my $parms=$_[0]; my $this={}; foreach(%$parms) { $this->{$_}=$parms->{$_}; } bless $this, $package; } } package main; my $p=new MyPackage({three => 3,}); $p->two(1); printf "two=%d, three=%d\n",$p->two, $p->three;
    Now I try moving the BEGIN block out of the package and into main (thus 'main_package_vars'), and import it's functionality into the local package.

    That's the problem I'm trying to solve. How to have my subroutine definition for 'package_vars' in 'main', and use it from a package, like in this (which doesn't work because package_vars, isn't being 'called' in MyPackage, now that it's been moved to main).

    #!/usr/bin/perl -w use strict; use feature ':5.10'; BEGIN { sub package_vars { foreach(@_) { eval "sub $_ { my \$p = shift; \$p->{$_} = \$_[0] if \@_; \$p->{$_}; }" } } } package MyPackage; *package_vars=\&main::package_vars; { package_vars( qw(one two three) ); sub new { my $package=shift; my $parms=$_[0]; my $this={}; foreach(%$parms) { $this->{$_}=$parms->{$_}; } bless $this, $package; } } package main; my $p=new MyPackage({three => 3,}); $p->two(1); printf "two=%d, three=%d\n",$p->two, $p->three;
    The first version I posted had samples of the routine package_vars in each location where I could try changing the line that says 'package_vars3( qw(one two three));' to a line without the '3', and, call the original working version, vs. attempts at trying some way to call the version of 'package_vars' that was moved to main.

    Is that more clear?

      Some of the steps you take are somewhat clear, but I'm really wondering about the goal you're trying to reach by these steps. To me, it really seems as if you're trying to duplicate the functionality of Class::Accessor. The usage of Class::Accessor would be:

      package MyPackage; use parent qw(Class::Accessor); __PACKAGE__->mk_accessors(qw(two three)); package main; use strict; my $f = MyPackage->new({three => 3}); $f->two(1); printf "two=%d, three=%d\n",$f->two, $f->three;

      This seems to be your use case, so why reinvent the wheel?

Re^2: Perl templating/macro creating using 'BEGIN'...
by perl-diddler (Hermit) on Sep 27, 2010 at 17:57 UTC
    Also, why are you using string-eval, when the plain eval works just as well.
    Because it didn't work when I tried it. Perhaps your perl works differently?
    #!/usr/bin/perl -w use strict; use feature ':5.10'; package MyPackage; { BEGIN { sub package_vars { foreach(@_) { eval sub $_ { my \$p = shift; \$p->{$_} = \$_[0] if \@_; \$p->{$_}; }; } } } package_vars( qw(one two three) ); sub new { my $package=shift; my $parms=$_[0]; my $this={}; foreach(%$parms) { $this->{$_}=$parms->{$_}; } bless $this, $package; } } package main; my $p=new MyPackage({three => 3,}); $p->two(1); printf "two=%d, three=%d\n",$p->two, $p->three;
    I got: Illegal declaration of anonymous subroutine at pck0.pl line 10. What do you get?

      Sorry - you don't even need "plain eval". Just assigning the anonymous subroutine to the glob is all that's needed and creates a named subroutine from the anonymous subroutine.

        Sorry - you don't even need "plain eval". Just assigning the anonymous subroutine to the glob is all that's needed and creates a named subroutine from the anonymous subroutine.
        What glob? (and what anonymous subroutine?)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://862248]
help
Chatterbox?
[Corion]: ambrus: Yes but I also need to implement the file / IO watcher, because Prima has that (in Prima::File), and I need to supply the appropriate thing to make push_write etc. work with Prima
[ambrus]: Corion: yes, you need to implement the io watcher, which should be simple because Prima::File is basically that, and the timer watcher form Prima::Timer
[Corion]: ... or so I think. As I said, I'm somewhat vague on how to make AnyEvent cooperate with a callback-driven IO event loop that gives me callbacks when data is available or can be written
[ambrus]: what push_write thing? I don't think you need that. that's implemented generically by AnyEvent::Handle
[Corion]: ambrus: Yeah, that's what I think as well. But you give me an idea, maybe I should start with implementing the timer, as that should be far simpler and with fewer edge-cases/nasty interaction than the file watcher
[ambrus]: You only provide the watcher part that tells when the handle is readable or writable, not the actual writing and reading.
[Corion]: ambrus: Hmmm. It makes sense that AnyEvent would implement the push_write itself, but I think I don't have a good idea of where the boundary between AnyEvent and the underlying event system lies... Implementing the timer should give me a better idea
[ambrus]: Corion: push_write is in the higher level abstraction of AnyEvent::Handle, not in the watcher
[Corion]: ambrus: Hmm - rereading Prima::File, that merrily coincides with what Prima does - it tells you "you can read", and you're supposed to read from the fh yourself. I thought it called you with the data already read, which would've been harder to integrate
[ambrus]: you just need an io watcher, created by &AnyEvent::Impl:: Whatever::io(...)

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (8)
As of 2016-12-08 12:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    On a regular basis, I'm most likely to spy upon:













    Results (141 votes). Check out past polls.