Mar 11, 2012

Adventures with SOAP using Perl: Part 2 ( SOAP::Data::Builder )

Start by reading the first 2 parts :

  1. Part 0 Prelude (setup server.pl)
  2. Part 1 SOAP::Lite

SOAP::Data::Builder is simply a wrapper around SOAP::Data and SOAP::Serializer for SOAP::Lite. I used it because it made my life easier building nested complicated SOAP objects. However for Part 2 I will simply be showing how to use it to do the same code as Part 1. Unfortunately since Part 1 is so Simple this actually makes SOAP::Data::Builder more complex than SOAP::Lite would be for this. In a future installment I will attempt to show more complex examples, but I will explain them less. Now let's take a look at the code.

#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use SOAP::Lite +trace => [ 'debug' ];
use SOAP::Data::Builder;

my $req = SOAP::Lite->new(
    readable   => 1,
    proxy      => 'http://localhost:8877',
    ns         => 'http://namesservice.thomas_bayer.com/',
);

my $sb = SOAP::Data::Builder->new;

$sb->add_elem(
    name  => 'name',
    value => 'Mark',
);

my $res = $req->getNameInfo( $sb->to_soap_data );

say '-' x 3;

unless ( defined $res->fault ) {
    say scalar $res->valueof('//country');
} else {
    say $res->fault->{faultstring};
    say $res->fault->{detail}{error};
}

As you can see this is much the same as the final code in Part 1, and if you run it, it does exactly the same thing. The first difference you'll notice is the self explanatory creation of the SOAP::Data::Builder object. After that comes the ->add_elem method call, which will simply create an element with a given element name and a value for that element.

Once you've finished adding elements to your $sb object, then you can call pass $sb->to_soap_data to the method that you're calling on SOAP::Lite, this generates the structure that SOAP::Lite needs to be able to make your request.

The only thing I didn't like about SOAP::Data::Builder is if you don't pass the right parameters to ->add_elem it will not croak or error in any way that will really tell you what went wrong. Simple patches to this can fix it.

Mar 4, 2012

Simple scripting CLI with Expect.pm

Expect is use primarily for sending Input to Command Line programs that Prompt and wait for input. For starters you'll need an executable script and I've pasted one that I got elsewhere for a demo.

#!/usr/bin/env perl
# slightly modified from http://www.tizag.com/perlT/perluserinput.php
use 5.014;;
use warnings;


print "How old are you?";
my $age = <>;

print "What is your favorite color?";
my $color = <>;

say "You are $age, and your favorite color is $color.";
It's trivial, you should probably run it just to see what it does. Now take a look at our Expect Script.

Although you can read the comments yourself, let's go over it anyways. ->spawn takes a list of arguments, with the first being a command, and the rest being any command line arguments, or options passed to said script. I could have easily just put the command in spawn, but I though I'd show a more dynamic example. After that you'll notice I've hard coded 2 sets of params that could possibly be fed into the program. I also have created some 1 at a time iterators, this simply makes it easier to iterate them in expect. Now onto the Expect object itself.

If you've read the documentation you'll notice there are 3 debug settings, with 3 being the most verbose, and some verbose settings. None of this appeared to be as verbose as I could get, however turning on ->exp_internal(1); printed everything I needed to understand expect and debug what I was doing wrong. The ->spawn method of course forks and execs our command, the output of which then gets iterated by ->expect.

The first argument to ->expect is the timeout, which is measured in seconds. The timeout is how long expect will wait for the output to match one of the regexes. You could set it to undef if you want to wait forever, or if it's just a program that has some startup time before it prompts set it to a few seconds. The timeout will (by default) be used again in between each prompt.

After timeout you can specify a list of array refs, each of which has 2 elements. The first is a regular expression that will allow you to tell expect how to recognize a prompt. The second is a coderef which allows you to tell expect what to do if it's corresponding match is hit. Both regexes will be run against every line, checking to see if they match.

Inside of our coderef we can use ->send to send input to the prompt. Remember send doesn't automatically press enter, so be sure to add your newlines. exp_continue means after match continue using this ->expect call to try to match the next line.

When running the script you'll notice the second regex never matches, but if reading the 'internal' output you'll see that it is attempting to.

The last line is a call to ->before which in this case, not very intuitively prints everything that was in the pty after the last match, or more appropriately, before the program exited. You'll also notice that it collects the thing that you sent to the last match.

That's the basics of what I've discovered, I'm not sure I fully understand how it all works yet (which means my explanations might not be 100% correct), but perhaps me writing this will help someone else get started with Expect. Happy Hacking!