I wanted to build an awesome place for people to discuss module specific issues, but I don't have any more time for this, and there are much better places to discuss Perl-related issues. I'd recommend asking your question on Stack Overflow or on Perl Monks.
If you are looking for a Perl tutorial or Perl-related news, I hope these links will serve you well.
Posted on 2012-01-19 08:22:16.728429-08 by wsppan
sub command dispatching confusion
I understand how the app dispatches to the correct command via the command_map dispatch table but where is the dispatch table for the command's subcommands?

In package My::Queue:
sub command_map { console => 'CLI::Framework::Command::Console', alias => 'CLI::Framework::Command::Alias', 'cmd-list' => 'CLI::Framework::Command::List', enqueue => 'My::Queue::Command::Enqueue', dequeue => 'My::Queue::Command::Dequeue', print => 'My::Queue::Command::Print', property => 'My::Queue::Command::Property', }

in My::Queue::Command::Property:
sub subcommand_alias { l => 'list', s => 'set', }

How does the app know that subcommands list and set get dispatched to My::Queue::Command::Property::List and My::Queue::Command::Property::Set?
Does the app just look for a class that inherits from My::Queue::Command::Property with a name that matches /[Ss]et/ or /[Ll]ist/ ?

Thanks in advance for your help!
Direct Responses: 13610 | Write a response
Posted on 2012-01-19 19:00:21.675004-08 by kerisman in response to 13606
Re: sub command dispatching confusion
It's based on inheritance. My::Queue::Command::Property::List and My::Queue::Command::Property::Set both inherit from My::Queue::Command::Property, so CLIF knows they're subcommands. CLIF reads the symbol table to find this information. It has nothing to do with class names (the names line up in the example only because common class naming convention is being followed).
Direct Responses: 13613 | Write a response
Posted on 2012-01-20 11:00:05.81278-08 by wsppan in response to 13610
Re: sub command dispatching confusion
Sorry for being so dense but how does it know that the words used for the commands ('list' and 'set') map to the correct subcommand class.
In other words, if I create the command line app to run like:

bash$ examples/queue --qin=/tmp/qfile --qout=/tmp/qfile property foo

And I create a class that inherits from My::Queue::Command::Property called My::Queue::Command::Property::Bar that I want to be used for the subcommand 'foo'.

How does the app know that 'foo' maps to 'My::Queue::Command::Property::Bar' without a subcommand dispatch table?

Thanks again for your help. Your framework is very elegant and well thought out.
Direct Responses: 13614 | Write a response
Posted on 2012-01-22 16:04:11.412584-08 by kerisman in response to 13613
Re: sub command dispatching confusion
You would create the class for the "foo" command like this:
package My::Queue::Command::Property::Foo; use base qw( My::Queue::Command::Property );

...and the class for the "bar" command (which you want to be a subcommand of "foo") like this:
package My::Queue::Command::Property::Bar; use base qw( My::Queue::Command::Property::Foo );

Thus, the class hierarchy reflects the command/subcommand relationship. Again, it's about inheritance, not naming conventions. You're left in control of the naming decisions.
Thanks, glad you're enjoying CLIF!
Direct Responses: 13616 | Write a response
Posted on 2012-01-23 08:23:41.637503-08 by wsppan in response to 13614
Re: sub command dispatching confusion
I did not want a subcommand of foo called bar. It seems from your example that if I want a 'property' subcommand called 'foo' I *MUST* have a Class call 'Foo' that inherits from the Property class.
If I want a 'property' subcommand called 'bar' I *MUST" have a class called 'Bar' that inherits from the 'Property' class.
If I want a 'foo' subcommand called 'blarg' I must have a class called 'Blarg' that inherits from the Foo class.

In other words, I can create a Command called 'requeue' that can map to any class that is a subcommand of CLI::Framework::Command (i.e. My::Queue::Command::Baz), via the command_map() method by adding the following to the return list

requeue => 'My::Queue::Command::Baz',


If I wanted to create a subcommand of 'requeue' called 'random', I *Must* create a class called 'Random' that is a subclass of 'My::Queue::Command::Baz'. The command line would look like:

examples/queue --qin=/tmp/qfile --qout=/tmp/qfile requeue random


There seems to be no way for me to name the class anything but 'Random' if I want the correct class to be instantiated when I call the 'random' subcommand of 'requeue'.

The class name for the 'list' subcommand of the 'property' command must be called List.
The class name for the 'set' subcommand of the 'property' command must be called Set.
Otherwise, how does the Property class know which subclass to call since both List and Set are subclasses of Property. How is 'set' mapped to 'Set' and 'list' mapped to List?

Again, my apologies if I have not made myself clear and/or not groking your explanations. Thank you for your patience.
Direct Responses: 13617 | Write a response
Posted on 2012-01-25 13:14:15.990528-08 by kerisman in response to 13616
Re: sub command dispatching confusion
You can use subcommand_alias() to give a subcommand whatever name you choose. In fact, the "queue" example does this for My::Queue::Command::Property. It defines subcommand_alias to enable 'l' and 's' as alternatives for the default names (so "queue property s" is the same as "queue property set" and "queue property l" is the same as "queue property list").
Direct Responses: 13618 | Write a response
Posted on 2012-01-26 08:38:14.225895-08 by wsppan in response to 13617
Re: sub command dispatching confusion
I can use subcommand_alias() to give a subcommand whatever alias I choose.
The name of the subcommand has to match the name of the class that inherits from My::Queue::Command::Property

I am not looking for a way to name a command anything I want. I am looking to understand how the subcommand dispatching works.
Let me try and give a concrete example using examples/queue:

first, I delete the subcommand_alias() method from My::Queue::Command::Property
next, I create a class called My::Queue::Command::Property::Gist that inherits from My::Queue::Command::Property (it's run() method just returns "GOT HERE!\n")
Right now, without me defining any subcommand dispatch table, I have a subcommand on the commandline called 'gist'. It must be called 'gist'
$ examples/queue property gist My::Queue::Command::Property::notify...() about to run My::Queue::Command::Property::Gist GOT HERE! $ examples/queue property Gist property: work with queue properties ARGUMENTS (subcommands) list: list queue properties set: set queue properties gist: the gist of it

If I change the class name to My::Queue::Command::Property::gist
it still works with the 'gist' sub-command.

So, my question are, how does the subcommand dispatching work?

How does CLI know that 'gist' maps to 'My::Queue::Command::Property::[Gg]ist'?

What if I create 2 subcommands classes that inherit from My::Queue::Command::Property:
My::Queue::Command::Property::Gist
My::OtherModule:Property::Gist

Which one gets mapped to the 'gist' subcommand?

What is becoming obvious, if I want to have a subcommand of 'property' called 'gist' (without subcommand aliases), I must have a subcommand class named Gg]ist that inherits from My::Queue::Command::Property.
If I want to use an existing class named 'MyGist' for the 'gist' subcommand, I would need to make it inherit from the property class, and use 'gist' as the subcommand alias on the command line:
sub subcommand_alias { 'gist' => 'mygist', } $ examples/queue property gist My::Queue::Command::Property::notify...() about to run My::Queue::Command::Property::MyGist GOT HERE! $ examples/queue property mygist My::Queue::Command::Property::notify...() about to run My::Queue::Command::Property::MyGist GOT HERE!


Is this correct?
Direct Responses: 13629 | Write a response
Posted on 2012-02-03 11:02:22.813976-08 by wsppan in response to 13618
Re: sub command dispatching confusion
OK, figured it out. Subclass dispatching works like this. It finds all the subclasses of the command class (via inheritance) and adds them to the _subcommands field of the command class:

CLI::Framework::Command::register_subcommand(lib/CLI/Framework/Command.pm:264): 264: my $subcommand_name = $subcommand_obj->name(); CLI::Framework::Command::register_subcommand(lib/CLI/Framework/Command.pm:265): 265: $cmd->{_subcommands}->{$subcommand_name} = $subcommand_obj;

and the name() method is:
sub name { my ($cmd) = @_; # Use base name of package as command name... my $pkg = ref $cmd; my @pkg_parts = split /::/, $pkg; return lc $pkg_parts[-1]; }


If I want to use a different subcommand name I can override the name() method in my subcommand class.

Still not sure what happens if I create 2 subcommands classes (no overrides to name()) that inherit from My::Queue::Command::Property:

My::Queue::Command::Property::List
My::Other::Property::List

Which one gets called with the 'list' subcommand?
Direct Responses: Write a response