• Query about Perl syntax

    From Henry Law@21:1/5 to All on Mon Nov 30 12:35:44 2020
    I'm just getting into Mojolicious. Within the tutorial, in one of the
    sections on testing I find this code (abbreviated a little - it's not runnable):

    use Test::More;
    use Test::Mojo;
    ...
    # Test if the HTML login form exists
    get_ok('/')
    ->status_is(200)
    ->element_exists('form input[name="user"]')
    ->element_exists('form input[name="pass"]')
    ->element_exists('form input[type="submit"]');

    The syntax of the last five lines surprises me. It looks like a chain of
    five method calls, where the result of the "get_ok" method has itself a "status_is" method, which returns a result which has an "element_exists"
    method ... all the way down until the last "element_exists" method
    returns a status to the $t object, which then talks to Test::More.

    Much has changed in Perl, and in other things like HTML for that matter,
    since I started programming, and I'm an amateur so I don't get exposed to continuing education: in short I'm horribly out of date. So is my interpretation of that last statement correct, in terms of its functional steps? Or is there some change in Perl syntax which means that it works
    in some other way?

    --
    Henry Law n e w s @ l a w s h o u s e . o r g
    Manchester, England

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Henry Law@21:1/5 to All on Mon Nov 30 13:35:11 2020
    On Mon, 30 Nov 2020 19:16:18 +0000, hymie! wrote:

    The short and simple answer is that the method call both changes the
    object and returns the changed object.

    Ah! I see. So the returned object is of the same class (indeed, it's
    the same object) and has the same methods, which can be called again and
    again. Clever!

    --
    Henry Law n e w s @ l a w s h o u s e . o r g
    Manchester, England

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From hymie!@21:1/5 to who on Mon Nov 30 19:16:18 2020
    In our last episode, the evil Dr. Lacto had captured our hero,
    Henry Law <news@lawshouse.org>, who said:

    # Test if the HTML login form exists
    get_ok('/')
    ->status_is(200)
    ->element_exists('form input[name="user"]')
    ->element_exists('form input[name="pass"]')
    ->element_exists('form input[type="submit"]');

    The short and simple answer is that the method call both changes the object
    and returns the changed object. So the consecutive method calls all
    change the underlying object $t . It's basically a shorthand for

    $t = $t->get_ok('/');
    $t = $t->status_is(200);
    $t = $t->element_exists('form input[name="user"]');
    $t = $t->element_exists('form input[name="pass"]');
    $t = $t->element_exists('form input[type="submit"]');

    --hymie! http://nasalinux.net/~hymie hymie@nasalinux.net

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Henry Law on Wed Dec 2 16:33:18 2020
    Henry Law <news@lawshouse.org> writes:
    On Mon, 30 Nov 2020 19:16:18 +0000, hymie! wrote:

    The short and simple answer is that the method call both changes the
    object and returns the changed object.

    Ah! I see. So the returned object is of the same class (indeed, it's
    the same object) and has the same methods, which can be called again and again. Clever!

    Well, "sort-of". This kind of chaining is very bad if one ever needs to
    debug this code: The substatements making up this complex statement are
    neither breakable nor is it possible to insert code between them without breaking up the expression first.

    IMHO, that's a "classic" example of "optimizing for elegance at the
    expense of maintainability".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randal L. Schwartz@21:1/5 to All on Wed Dec 2 11:36:24 2020
    "Henry" == Henry Law <news@lawshouse.org> writes:

    Henry> Ah! I see. So the returned object is of the same class (indeed,
    Henry> it's the same object) and has the same methods, which can be
    Henry> called again and again. Clever!

    That's only by design choice of the programmer. Methods that do this
    can be chained:

    sub enable_shipping {
    my $self = shift;
    [act on $self for the shipping side-effect]
    return $self;
    }

    In other words, the object itself needs to be returned from the method
    for the next method in the chain to have something to bite on.

    Dart does this better, having stolen the idea from Smalltalk. Methods
    are invoked with a single dot for normal behavior (return from method
    becomes return from overall expression) or with two dots, where the
    current value is input to the method (which typically has side-effects),
    but also remains the return value from the expression. In Dart and
    Smalltalk, this is called a "cascade", and can come in very handy.

    So that original text would look like

    t.get_ok('/') this value is input to all the following
    ..status_is(200)
    ..element_exists('form input[name="user"]')
    ..element_exists('form input[name="pass"]')
    ..element_exists('form input[type="submit"]');

    The return value is the result of t.get_ok(). And none of the other
    methods have to be built specially. It's very slick.

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
    Still trying to think of something clever for the fourth line of this .sig

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randal L. Schwartz@21:1/5 to All on Thu Dec 3 01:52:17 2020
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:

    Rainer> Well, "sort-of". This kind of chaining is very bad if one ever needs to Rainer> debug this code: The substatements making up this complex statement are Rainer> neither breakable nor is it possible to insert code between them without
    Rainer> breaking up the expression first.

    I use them extensively in my File::Finder. Then again, I don't debug
    much. :)

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
    Still trying to think of something clever for the fourth line of this .sig

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Randal L. Schwartz on Thu Dec 3 18:33:09 2020
    merlyn@stonehenge.com (Randal L. Schwartz) writes:
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:

    Rainer> Well, "sort-of". This kind of chaining is very bad if one ever needs to
    Rainer> debug this code: The substatements making up this complex statement are
    Rainer> neither breakable nor is it possible to insert code between them without
    Rainer> breaking up the expression first.

    I use them extensively in my File::Finder. Then again, I don't debug
    much. :)

    I don't see any examples in

    https://metacpan.org/source/MERLYN/File-Finder-0.53/lib%2FFile%2FFinder.pm

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randal L. Schwartz@21:1/5 to All on Fri Dec 4 12:54:45 2020
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:


    Rainer> I don't see any examples in

    Rainer> https://metacpan.org/source/MERLYN/File-Finder-0.53/lib%2FFile%2FFinder.pm

    at the very bottom: "show 202 lines of pod". You must've noot clicked
    that. How long have you been using metacpan? :)

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
    Still trying to think of something clever for the fourth line of this .sig

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Randal L. Schwartz on Fri Dec 4 21:46:37 2020
    merlyn@stonehenge.com (Randal L. Schwartz) writes:
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:


    Rainer> I don't see any examples in

    Rainer> https://metacpan.org/source/MERLYN/File-Finder-0.53/lib%2FFile%2FFinder.pm

    at the very bottom: "show 202 lines of pod". You must've noot clicked
    that. How long have you been using metacpan? :)

    There's no code in the documentation. And I never use metacpan, at least
    not routinely.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randal L. Schwartz@21:1/5 to All on Sat Dec 5 15:15:17 2020
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:
    at the very bottom: "show 202 lines of pod". You must've noot clicked
    that. How long have you been using metacpan? :)

    Rainer> There's no code in the documentation.

    Wow. You're blinded, or something. Take a look at the formatted
    version:

    https://metacpan.org/pod/File::Finder

    I see about 50 lines of code.

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
    Still trying to think of something clever for the fourth line of this .sig

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Randal L. Schwartz on Sun Dec 6 11:21:12 2020
    merlyn@stonehenge.com (Randal L. Schwartz) writes:
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:
    at the very bottom: "show 202 lines of pod". You must've noot clicked
    that. How long have you been using metacpan? :)

    Rainer> There's no code in the documentation.

    Wow. You're blinded, or something. Take a look at the formatted
    version:

    https://metacpan.org/pod/File::Finder

    I see about 50 lines of code.

    There's no example of expression chaining in there either. And after the
    "I use it extensively ..." I had expected to see this in the code of the
    module itself, meaning, this amusing arrangments of statements a la

    if (state[-3] < 3.144 / 22.5) {
    state[25] = state[-139]
    } else {
    etas[-52] = etas[931]
    }

    etc

    NB: The code doesn't really contain this statement which is a bit of an exaggeration.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randal L. Schwartz@21:1/5 to All on Mon Dec 7 08:03:53 2020
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:

    Rainer> There's no example of expression chaining in there either.

    In the pod for File::Finder:

    Synopsis:

    use File::Finder;
    ## simulate "-type f"
    my $all_files = File::Finder->type('f');

    ## any rule can be extended:
    my $all_files_printer = $all_files->print;

    ## traditional use: generating "wanted" subroutines:
    use File::Find;
    find($all_files_printer, @starting_points);

    ## or, we can gather up the results immediately:
    my @results = $all_files->in(@starting_points);

    ## -depth and -follow are noted, but need a bit of help for find:
    my $deep_dirs = File::Finder->depth->type('d')->ls->exec('rmdir','{}'); find($deep_dirs->as_options, @places);

    Examples in pod:

    my $files_print = $files->print;

    my $files_depth_print = $files->depth->print;

    my $big_or_old_files =
    $files->left->size("+50")->or->atime("+30")->right;

    my @names = File::Finder->in("/tmp");

    in File::Finder::Steps:

    my $big_or_old = File::Finder
    ->type('f')
    ->left
    ->size("+100")->or->mtime("+90")
    ->right;
    find($big_or_old->ls, "/tmp");

    # list all non-files in /tmp
    File::Finder->not->type('f')->ls->in("/tmp");

    # list all files and dirs, but don't descend into CVS dir contents: File::Finder->type('d')->name('CVS')->prune->comma->ls->in('.');

    my $pm_files = File::Finder->name('*.pm')->in('.');
    my $pm_files_too = File::Finder->name(qr/pm$/)->in('.');

    my $files = File::Finder->type('f');
    # find files that are exactly mode 644
    my $files_644 = $files->perm(0644);
    # find files that are at least world executable:
    my $files_world_exec = $files->perm("-1");
    # find files that have some executable bit set:
    my $files_exec = $files->perm("+0111");

    my $blaster = File::Finder->atime("+30")->eval(sub { unlink });

    my $old = File::Finder->atime("+30");
    my $big = File::Finder->size("+100");
    my $old_or_big = File::Finder->eval($old)->or->eval($big);
    my $killer = File::Finder->eval(sub { unlink });
    my $kill_old_or_big =
    File::Finder->eval($old_or_big)->ls->eval($killer); $kill_old_or_big->in('/tmp');

    my $plugh_files = File::Finder->type('f')->contains(qr/plugh/);

    Truly, Rainer, I sincerely doubt your ability to read a perldoc page
    now. {sigh}

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
    Still trying to think of something clever for the fourth line of this .sig

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Randal L. Schwartz on Wed Dec 9 19:46:41 2020
    merlyn@stonehenge.com (Randal L. Schwartz) writes:
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:
    Rainer> There's no example of expression chaining in there either.

    [...]

    ## -depth and -follow are noted, but need a bit of help for find:
    my $deep_dirs = File::Finder->depth->type('d')->ls->exec('rmdir','{}'); find($deep_dirs->as_options, @places);

    [...]

    my $files_depth_print = $files->depth->print;

    my $big_or_old_files =
    $files->left->size("+50")->or->atime("+30")->right;

    Truly, Rainer, I sincerely doubt your ability to read a perldoc page
    now. {sigh}

    I wasn't particularly interested in the contents as I still had expected
    to find this in the code.

    So, File::Finder emulates a domain specific mini-language via chained
    method calls. Out of my head, this seems like a bit of a weird idea but
    as I've never tried to solve this problem myself, this isn't exactly an
    "in depth" assessment.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randal L. Schwartz@21:1/5 to All on Wed Dec 9 12:30:24 2020
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:

    Rainer> I wasn't particularly interested in the contents as I still had expected
    Rainer> to find this in the code.

    Find *what* in the code?

    Rainer> So, File::Finder emulates a domain specific mini-language via
    Rainer> chained method calls. Out of my head, this seems like a bit of a Rainer> weird idea but as I've never tried to solve this problem myself, Rainer> this isn't exactly an "in depth" assessment.

    I learned Smalltalk Cascades almost a decade before I started with
    Perl. It felt natural to do this. Also, File::Find::Rule also did it
    this way, but I found that the non-equivalence to File::Find always
    threw me off, so I wrote my own that did relate better.

    print "Just another Perl hacker," # the original

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
    Still trying to think of something clever for the fourth line of this .sig

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Randal L. Schwartz on Thu Dec 10 16:48:13 2020
    merlyn@stonehenge.com (Randal L. Schwartz) writes:
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:

    Rainer> I wasn't particularly interested in the contents as I still had expected
    Rainer> to find this in the code.

    Find *what* in the code?

    Chaining of methods with side-effects via returned object. As that's
    just in the interface, "I use it extensivly in ..." should perhaps
    rather have been "I imagine users of ... to use it extensively".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Randal L. Schwartz@21:1/5 to All on Thu Dec 10 23:35:33 2020
    "Rainer" == Rainer Weikusat <rweikusat@talktalk.net> writes:

    Find *what* in the code?

    Rainer> Chaining of methods with side-effects via returned object. As
    Rainer> that's just in the interface, "I use it extensivly in ..."
    Rainer> should perhaps rather have been "I imagine users of ... to use
    Rainer> it extensively".

    Ahh, but that's for the users of the module to use! I just provide the implementation and the API, except for a few uses in the docs and the
    tests.

    And there's the two magazine articles I wrote on it.

    http://www.stonehenge.com/merlyn/LinuxMag/col73.html http://www.stonehenge.com/merlyn/PerlJournal/col08.html

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 <merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/Dart consulting, Technical writing, Comedy, etc. etc.
    Still trying to think of something clever for the fourth line of this .sig

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)