Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Thanks for following up on this. I took a minute or two to organize and separate the files into a typical <code>lib/Power/Control.pm</code> and <code>lib/Power/Control/Command/On.pm</code> layout and cleaned up a few things and here's the output I got:</p> <pre><code>[localhost ~/tmp%] perl stackex-pc --ip=127.0.0.1 --device=pants on The device name is pants The ip address is 127.0.0.1 This is the command "on" </code></pre> <p>Which I think is more or less what you want. I'll add my explanation of what I think was going on below but first I'll include my files and you can try this at home. If it works then you can accept my answer. If I give a decent explanation then others can vote me up!! First, here's the script:</p> <pre><code>#! /usr/local/bin/perl # # stackex-pc # Question: http://stackoverflow.com/questions/17054798 use strict; use warnings; use lib 'lib' ; use Power::Control; # ---- EXECUTION ---- Power::Control-&gt;run(); # Launch command </code></pre> <p>And here's the packages: </p> <pre><code># lib/Power/Control.pm # Question: http://stackoverflow.com/questions/17054798 package Power::Control; use base qw( CLI::Framework ); use strict; use warnings; our ($data, $opts, $self); sub usage_text { qq{ $0 [--verbose|v]: OPTIONS: --verbose -v: be vebose ARGUMENTS (subcommands): on: power on the device off: power off the device reboot: reboot the device version: show PDU version status: show PDU status sysstat: show PDU sysstatus } } sub option_spec { [ 'device|d=s' =&gt; 'device name' ], [ 'ip=s' =&gt; 'ip address' ], [ 'user|u=s' =&gt; 'user name' ], [ 'password|p=s' =&gt; 'password' ], [ 'interval|i=s' =&gt; 'interval' ], [ 'brand|b=s' =&gt; 'brand' ], [ 'community|c=s' =&gt; 'community' ], [ 'version|v=s' =&gt; 'version' ], } sub command_map { on =&gt; 'Power::Control::Command::On', off =&gt; 'Power::Control::Command::Off', reboot =&gt; 'Power::Control::Command::Reboot', version =&gt; 'Power::Control::Command::Version', status =&gt; 'Power::Control::Command::Status', sysstat =&gt; 'Power::Control::Command::Sysstat', } sub command_alias { r =&gt; 'reboot', v =&gt; 'version', st =&gt; 'status', sys =&gt; 'sysstat', } sub init { ($self, $opts) = @_; print "\n The device name is $opts-&gt;{device}\n"; print "\n The ip address is $opts-&gt;{ip}\n"; } 1; </code></pre> <p>As mentioned I separated the files in a module directory type layout so there's a second file. I did this for my own convenience, so don't feel you have to do the same thing.</p> <pre><code># lib/Power/Control/Command/On.pm # Question: http://stackoverflow.com/questions/17054798 package Power::Control::Command::On; use base qw( CLI::Framework::Command ); use strict; use warnings; use Power::Control; sub usage_text { q{ on [--d=&lt;device name&gt;: Power on the device } } sub run { print "\n This is the command \"on\" \n"; exit ; } 1; </code></pre> <p>I think the reason your first approach didn't work was - just as the error message indicated - uninitialized variables. My attempted explanation follows:</p> <ol> <li><p>I needed to place <code>use lib 'lib';</code> <em>before</em> <code>use Power::Control;</code> otherwise the script would not have a complete @INC and was unable to find <code>Power::Control</code>. When I fixed this I got the same error as you. This suggests that you may have set up your CLI::Framework differently or had put your own modules somewhere in the @INC.</p></li> <li><p>If you change <code>"our $data ;</code> on line 53 of <code>lib/Power/Control.pm</code> <code>our $data = "in the global scope";</code> - which is otherwise undefined - you'll see that message when you run the script. The "$data" value is not getting set from inside the the init() subroutine If you replace <code>print "\n The ip address is $data\n";</code> in the init() subroutine around line 60 in <code>lib/Power/Control.pm</code> with <code>print "\n The ip address is $opts-&gt;{ip}\n";</code> you'll get output more like you expect. You'll also get a sense for the effect of different lexical values for variable if you change <code>$data =</code> inside <code>init()</code> to read <code>my $otherdata = ...</code> and adjust the <code>print</code> line accordingly.</p></li> <li><p>I'm not done yet! I'll review/edit my explanation and add a few references about variable scope and just what the <code>$data</code> variable is doing inside this <code>CLI::Framework</code> app.</p></li> </ol> <p>BTW, it's tricky, but you can figure out a lot of this by running the script in the perl debugger by simply adding the <code>-d</code> switch to your command:</p> <p><code>perl -d pc --ip=dsfa --device dsfasdf on</code>.</p> <p>and then stepping through the script as it runs, trying to dump variable values, tracing, etc. </p> <p>If you try puttiing the <code>on</code> command argument <em>before</em> the <code>--ip=</code> options you'll see another kind of problem: the command line argument parsing is a bit fragile. There is likely an elegant check you could add to fix that too or at least make the <code>Failed parsing of command options</code> a bit more meaningful (e.g. send the usage screen to the user).</p> <p>Good luck with your project.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload