Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

RFC: new.pm - a perl -e use/new shortener

by Dallaylaen (Friar)
on Dec 24, 2016 at 11:20 UTC ( #1178455=perlmeditation: print w/replies, xml ) Need Help??

I tend to use perl one-liners extensively, mostly for testing purposes. In particular, I often load a module with a loooooooooong name only to instantiate it once. And it's boooooooring to type the whole name twice.

So I came up with an idea of a one-liner shortener along the lines of:

perl -we 'use new qw(My::Very::Long::Module x foo 42); print $x->get_f +oo;'
Which is a rough equivalent of
perl -we 'use My::Very::Long::Module; our $x = My::Very::Long::Module- +>new( foo => 42 ); print $x->get_foo;'

And I have a proof-of-concept implementation that works as follows:

  • require module being called;
  • create a new instance;
  • create a package variable in the calling package (so that strict doesn't complain);
  • set that variable to instance from above.

Here it is.

package new; use strict; use warnings; =head1 NAME new - shorted require Foo; Foo->new(...) to just one call =head1 SYNOPSYS use new qw(My::Very::Long::Module x foo 42); is an exact equivalent of our $x; BEGIN { require My::Very::Long::Module; $x = My::Very::Long::Module->new( foo => 42 ); }; or a rough equivalent of use My::Very::Long::Module; our $x = My::Very::Long::Module->new( foo => 42 ); Not a big deal in a real program, but may save some typing in a one-liner test script. Works well under C<use strict;>. =cut $Carp::Internal{ (__PACKAGE__) }++; sub import { my ($self, $target, $name, @args) = @_; my $filename = $target; $filename =~ s#::#/#g; $filename .= ".pm"; require $filename; my $obj = $target->new( @args ); my $caller = caller; $name ||= 'new'; my $sym = join "::", $caller, $name; no strict qw(refs vars); *$sym = \$$sym; $$sym = $obj; }; 1;

Made purely for fun, but maybe there's some point in it after all.

UPDATE Available as gist.

Replies are listed 'Best First'.
Re: RFC: new.pm - a perl -e use/new shortener
by 1nickt (Prior) on Dec 24, 2016 at 11:54 UTC

    This is really cool. You can use the -M sugar allowing comma-separated args to simplify the syntax further:

    $ cat text.txt hello, world $ perl -Mnew=Path::Tiny,file,text.txt -E' say $file->slurp; ' hello, world
    I think a good improvement would be to load the strict and warnings pragmas automatically.

    (Also suggest: $ABSTRACT =~ s/shorted/shortens/;)


    The way forward always starts with a minimal test.
      Mentioning -M from perlrun is a good point.

      > I think a good improvement would be to load the strict and warnings pragmas automatically.

      I tend to disagree, especially regarding strict.

      strict is a must for longer scripts, but don't really pay off with one liners which need to be concise.

      If ever this should be optional.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

Re: RFC: new.pm - a perl -e use/new shortener (class name)
by tye (Sage) on Dec 24, 2016 at 18:00 UTC

    I'd much rather have a good way to get the class name into a variable so that I can use it for more than one call to new() and to use in calls to other class methods. The effect is to allow the programmer to use a variable as an alias for the long class name. Using a variable is nice because it provides the ability to define the scope for which you want that alias to apply. Having the helper module import a variable thwarts the ability to chose the scope and also makes the code less obvious when being read.

    my $log = require 'Log::Logger::Log4Perl::SysLog';

    The above even "works" if your module ends with "__PACKAGE__" instead of ending with "1"... except that it then only works for the first time a particular module is required. It would be good if there were an INC global in Perl that cached the value returned from the first call to require so that subsequent calls returned the same value.

    At the very least, improve your module so that the variable name is passed to it as '$x' instead of as 'x' so the meaning of the code becomes slightly more obvious.

    - tye        

Re: RFC: new.pm - a perl -e use/new shortener (default variable)
by LanX (Bishop) on Dec 24, 2016 at 13:04 UTC
    I like this a lot, just one suggestion

    > use new qw(My::Very::Long::Module x foo 42)

    If conciseness is your goal,better try to make the variable name (here x) optional and default to something like $new or $obj or only $o.

    Though I'm not sure about the best syntax for an optional var, probably something like

    use new qw(My::Very::Long::Module>x foo 42)

    Other options are | or * but any solution should play well with the -M option, ie shouldn't confuse the shell/CLI on various OSes.

    update: untested

    perl -Mnew=My::Very::Long::Module>x,foo,42

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      A ">" would clash with shell metacharacters and require escaping. I'm thinking of something like
      x=My::Class:Name.method arg arg ....
      instead. Both x and method default to "new" if omitted, which is at least consistent with the module name.
        Hi

        > x=My::Class:Name.method arg arg

        I suppose you meant x=My::Class::Name.method arg arg with double colon after Class :)

        But apart of this, it looks good for me!

        I tested the call with -M and -m with a fake module which just print the args of the import() , using my oldest available perl(brew) version.

        $ perl -MNew=X=Y::Y::Y.meth,1,2,3 -e'print "$]\n"' New , X=Y::Y::Y.meth , 1 , 2 , 3 5.006002 $ perl -mNew=X=Y::Y::Y.meth,1,2,3 -e'print "$]\n"' New , X=Y::Y::Y.meth , 1 , 2 , 3 5.006002

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Re: RFC: new.pm - a perl -e use/new shortener
by jdporter (Canon) on Dec 27, 2016 at 21:02 UTC

    Nice idea! But I don't like the idea that you have to pass in the name of the variable to be assigned, for its consequence that it can't be a lexical variable.

    The idea is to 'require' a module and invoke some method of it in one call, right?
    Here's my take:

    # package 'Factory', exports function 'fab' (short for "fabricate") package Factory; use base 'Exporter'; @EXPORT = qw( fab ); use Carp qw(croak); use strict; use warnings; sub fab($$@) { my $class_name = shift; my $ctor_name = shift; $class_name =~ /[^\w:]/ and croak; eval 'require '.$class_name; $class_name->$ctor_name(@_) } 1;

    Use it in a one-liner:

    perl -MFactory -le "my $x = fab 'My::Very::Long::Module', 'new', foo = +> 42; print $x->get_foo;"

    Pedantry: Technically, Perl 5 (that is, its intrinsic object programming system) does not have constructors. What we typically name new are typically factory methods.
    (I say "typically" because, by Wall, Perl gives you enough rope to shoot yourself in the foot.)

    I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
Re: RFC: new.pm - a perl -e use/new shortener (constructor)
by LanX (Bishop) on Dec 24, 2016 at 13:15 UTC
    As a side note: new is not a builtin in Perl.

    Classes are free to choose any method as constructor and are even free to have multiple of them.

    Though I'm not aware of an example right now.

    Update: this case is a negligence, no code needed, just mention in doc.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      Good point, say, DBI->connect(...); behaves much like a constructor. However, this would clutter the interface, making it less funny. And many Very::Long::Modules are in fact parts of a big production system that standardizes constructors. Maybe there is a way though, need to think more...

        As I already said, in the rare cases one can always fall back to explicit code.

        Just making it clear in documentation that some modules fail should be enough.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Re: RFC: new.pm - a perl -e use/new shortener
by LanX (Bishop) on Dec 24, 2016 at 15:29 UTC
    Another suggestion, you could provide the possibility to choose from a list of abbreviations of longer module names.

    Something like a stringified alias hash in an environment variable

    PERL_MOD_ALIASES = "MVLM => 'My::Very::Long::Module'"

    One liners are good for daily work which normally always cover the same modules.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re: RFC: new.pm - a perl -e use/new shortener
by perlancar (Monk) on Dec 30, 2016 at 10:32 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://1178455]
Approved by 1nickt
Front-paged by Corion
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2017-11-21 05:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In order to be able to say "I know Perl", you must have:













    Results (295 votes). Check out past polls.

    Notices?