File Coverage

blib/lib/Net/Amazon/MechanicalTurk.pm
Criterion Covered Total %
statement 74 181 40.8
branch 10 66 15.1
condition 1 9 11.1
subroutine 21 32 65.6
pod 7 7 100.0
total 113 295 38.3


line stmt bran cond sub pod time code
1             package Net::Amazon::MechanicalTurk;
2 18     18   494853 use warnings;
  18         48  
  18         587  
3 18     18   92 use strict;
  18         34  
  18         538  
4 18     18   141 use Carp;
  18         39  
  18         1733  
5 18     18   112 use Config;
  18         33  
  18         1072  
6 18     18   10829 use Net::Amazon::MechanicalTurk::Constants ':ALL';
  18         44  
  18         4500  
7 18     18   10507 use Net::Amazon::MechanicalTurk::BaseObject;
  18         58  
  18         620  
8 18     18   14522 use Net::Amazon::MechanicalTurk::Transport;
  18         62  
  18         542  
9 18     18   12202 use Net::Amazon::MechanicalTurk::Response;
  18         60  
  18         530  
10 18     18   11081 use Net::Amazon::MechanicalTurk::PagedResultsIterator;
  18         46  
  18         462  
11 18     18   10197 use Net::Amazon::MechanicalTurk::Properties;
  18         49  
  18         520  
12 18     18   11960 use Net::Amazon::MechanicalTurk::OSUtil;
  18         50  
  18         550  
13 18     18   98 use Net::Amazon::MechanicalTurk::ModuleUtil;
  18         69  
  18         392  
14 18     18   10470 use Net::Amazon::MechanicalTurk::FilterChain;
  18         53  
  18         460  
15 18     18   25373 use MIME::Base64;
  18         30799  
  18         4160  
16 18     18   20085 use Digest::HMAC_SHA1 qw{ hmac_sha1 };
  18         131766  
  18         2373  
17 18     18   17905 use URI;
  18         88684  
  18         38690  
18              
19             =head1 NAME
20              
21             Net::Amazon::MechanicalTurk - Amazon Mechanical Turk SDK for Perl
22              
23             =head1 VERSION
24              
25             Version 1.02
26              
27             =cut
28              
29             our $VERSION = '1.02';
30              
31             =head1 CONFIGURATION
32              
33             Configuring your access keys and web service urls.
34              
35             MechanicalTurk needs access keys for authentication.
36             If you do not specify all of the relevant attributes,
37             The file mturk.properties is read from your home directory
38             for this information.
39              
40             Run the command:
41              
42             perl -MNet::Amazon::MechanicalTurk::Configurer -e configure
43              
44             to help you create this file.
45              
46             =head1 SYNOPSIS
47              
48             Module for MechanicalTurk API.
49              
50             use Net::Amazon::MechanicalTurk;
51              
52             # Create a new MechTurk client
53             my $mturk = Net::Amazon::MechanicalTurk->new();
54              
55              
56             # Create a new MechTurk client without using mturk.properties
57             my $mturk = Net::Amazon::MechanicalTurk->new(
58             serviceUrl => 'https://mechanicalturk.sandbox.amazonaws.com/?Service=AWSMechanicalTurkRequester',
59             serviceVersion => '2007-06-21',
60             accessKey => '1AAAAA1A1AAAAA11AA11',
61             secretKey => '1aAaAAAAAAAA+aAaAaaaaaaAAA/AAAAAA1a1aAaa'
62             );
63              
64              
65             # Get your balance
66             my $balance = $mturk->GetAccountBalance->{AvailableBalance}[0]{Amount}[0];
67             print "Your balance is $balance\n";
68              
69              
70             # CreateHIT
71             my $question = "Tell me something interesting.";
72              
73             my $questionXml = <
74            
75            
76            
77             1
78            
79             $question
80            
81            
82            
83            
84            
85            
86             END_XML
87              
88             my $result = $mturk->CreateHIT(
89             Title => 'Answer a question',
90             Description => 'Test HIT from Perl',
91             Keywords => 'hello, world',
92             Reward => {
93             CurrencyCode => 'USD',
94             Amount => 0.01
95             },
96             RequesterAnnotation => 'Test Hit',
97             AssignmentDurationInSeconds => 60 * 60,
98             AutoApprovalDelayInSeconds => 60 * 60 * 10,
99             MaxAssignments => 1,
100             LifetimeInSeconds => 60 * 60,
101             Question => $questionXml
102             );
103              
104             printf "Created HIT:\n";
105             printf "HITId: %s\n", $result->{HITId}[0];
106             printf "HITTypeId: %s\n", $result->{HITTypeId}[0];
107              
108              
109             # Approve all submitted assignments
110             my $hits = $mturk->GetReviewableHITsAll;
111             while (my $hit = $hits->next) {
112             my $hitId = $hit->{HITId}[0];
113             my $assignments = $mturk->GetAssignmentsForHITAll(
114             HITId => $hitId,
115             AssignmentStatus => 'Submitted'
116             );
117             while (my $assignment = $assignments->next) {
118             my $assignmentId = $assignment->{AssignmentId}[0];
119             $mturk->ApproveAssignment( AssignmentId => $assignmentId );
120             }
121             }
122              
123             =head1 ERROR HANDLING
124              
125             Most methods indicate an error condition through die or Carp::croak.
126             This is similar to throwing an exception in other languages.
127             To catch an error, use eval:
128              
129             eval {
130             $mturk->callSomeMethod();
131             };
132             if ($@) { # catch an error
133             warn "The following error occurred: ", $@, "\n";
134              
135             # You can access the error code through the last response object.
136             print "Error Code: ", $mturk->response->errorCode, "\n";
137              
138             # You can also access the last request made.
139             print "Error while calling operation, ",
140             $mturk->request->{Operation}, "\n";
141             }
142              
143              
144             =head1 WEB SERVICE METHODS
145              
146             All of the operations listed in the MechanicalTurk API may be called
147             on a MechanicalTurk instance. To see a list of those operations and
148             what parameters they take see the following URL:
149              
150             http://docs.amazonwebservices.com/AWSMechanicalTurkRequester/2007-06-21/
151              
152             =head2 WEB SERVICE RESULTS
153              
154             The MechanicalTurk web service returns XML for a request. This module will
155             parse the XML into a generic perl data structure consisting of hashes
156             and arrays. This data structure is then looked through to find a result.
157             A result is the first child element under the root element whose element
158             name is not OperationRequest. The XML returned by the webservice contains
159             information rarely used. (If you ever need this extra information it
160             is available through the response attribute on the MechanicalTurk instance.)
161              
162             Although the results are normal data structures, they also
163             have methods added to them through the package
164              
165             Net::Amazon::MechanicalTurk::DataStructure.
166              
167             This package provides a few methods, however the most useful one during
168             development is toString. The toString method will help you figure out how
169             to access the information you need from the result. Here is an example
170             of the result as returned by GetAccountBalance.
171              
172             my $result = $mturk->GetAccountBalance;
173             print $result->toString, "\n";
174             printf "Available Balance: %s\n", $result->{AvailableBalance}[0]{Amount}[0];
175              
176             <>
177             [AvailableBalance]
178             [0]
179             [Amount]
180             [0] 10000.00
181             [CurrencyCode]
182             [0] USD
183             [FormattedPrice]
184             [0] $10,000.00
185             [OnHoldBalance]
186             [0]
187             [Amount]
188             [0] 0.00
189             [CurrencyCode]
190             [0] USD
191             [FormattedPrice]
192             [0] $0.00
193             [Request]
194             [0]
195             [IsValid]
196             [0] True
197              
198             Available Balance: 10000.00
199              
200             Implementation Note: Hash values always contain arrays, even when the
201             WSDL/XSD specifies that child element of another element only occurs
202             once. This perl module does not use the WSDL or XSD for reading or
203             generating XML and does not know if a child element should occur once
204             or many times. It treats the XML as if the element could always occur
205             more than once. It could have been written to condense a single
206             occurence in an array to 1 scalar item, however this would require
207             API users to test if a value is a SCALAR or an ARRAY.
208              
209              
210             =head1 ITERATING METHODS
211              
212             Some of the MechanicalTurk operations, such as GetAssignmentsForHIT
213             are limited in the number of results returned. These methods have
214             the parameters PageSize and PageNumber, which can be used to go
215             through an entire list of results.
216              
217             Instead of writing the code to iterate through all of the results
218             using pages, you can make a call to that method with the word 'All'
219             appended to the method name. An object will be returned, which has
220             a method called next, which will return the next item in the results
221             or undef when there are no more results.
222              
223             Example using an iterator for the GetAssignmentsForHIT operation:
224              
225             my $assignments = $mturk->GetAssignmentsForHITAll(
226             HITId => $hitId,
227             AssignmentStatus => 'Submitted'
228             );
229             while (my $assignment = $assignments->next) {
230             my $assignmentId = $assignment->{AssignmentId}[0];
231             $mturk->ApproveAssignment( AssignmentId => $assignmentId );
232             }
233              
234             =head1 EXTENDED METHODS
235              
236             Methods which provide additional functionaliy on top of Mechanical Turk
237              
238             Extra methods are available through a dynamic extension mechanism.
239             Modules under Net::Amazon::MechanicalTurk::Command add extra functionality
240             to the MechanicalTurk client.
241              
242             Explanation:
243              
244             If you were to call the method listOperations, the module
245             Net::Amazon::MechanicalTurk::Command::ListOperations would be loaded
246             and the method listOperations would be added to the MechanicalTurk
247             client.
248              
249              
250             See the perldocs for those commands:
251              
252             =over
253              
254             L.
255              
256             L.
257              
258             L.
259              
260             L.
261              
262             L.
263              
264             L.
265              
266             L.
267              
268             L.
269              
270             =back
271              
272             =head1 ATTRIBUTE METHODS
273              
274             =over 4
275              
276             =item accessKey or access_key
277              
278             Get or set the access key used for authentication.
279              
280             =item secretKey or secret_key
281              
282             Get or set the secret key used for signing web service requests.
283              
284             =item serviceUrl or service_url
285              
286             Get or set the endpoint for the webservice. If this url contains
287             the query parameters, Version and/or Service. Then the values
288             for serviceVersion and serviceName will also be set.
289              
290             =item serviceName or service_name
291              
292             Get or set the service name of the web service.
293              
294             =item serviceVersion or service_version
295              
296             Get or set the version of the web service.
297              
298             =item requesterUrl or requester_url
299              
300             Get or set the URL for the requester website. This is only used for display purposes.
301              
302             =item workerUrl or worker_url
303              
304             Get or set the URL for the worker website. This is only used for display purposes.
305              
306             =item response
307              
308             Get the last response from a web service call.
309             This will be of type Net::Amazon::MechanicalTurk::Response.
310              
311             =item request
312              
313             Get the last request used for a web service call.
314             This will be a hash of all the parameters sent to the transport.
315              
316             =item filterChain
317              
318             Get the filterChain used for intercepting web service calls.
319             This is for advanced use cases and internal use.
320             This attribute will be of type Net::Amazon::MechanicalTurk::FilterChain.
321              
322             =item transport
323              
324             Get or set the transport used for sending web service requests.
325              
326             The default transport is of type
327             Net::Amazon::MechanicalTurk::Transport::RESTTransport.
328              
329             Hint: You can get to the underlying LWP::UserAgent through the RESTTransport
330             to set connection timeouts.
331              
332             $mturk->transport->userAgent->timeout(10);
333              
334             =back
335              
336             =cut
337              
338              
339             our @ISA = qw{ Net::Amazon::MechanicalTurk::BaseObject };
340             our $AUTOLOAD;
341              
342             Net::Amazon::MechanicalTurk->attributes(qw{
343             accessKey
344             secretKey
345             serviceName
346             serviceVersion
347             requesterUrl
348             workerUrl
349             response
350             request
351             config
352             configProperties
353             filterChain
354             });
355              
356             # Create attribute aliases to support configuration from the properties file.
357             # (The java command line tool used underscores for its values)
358             # ( Global config uses AccessKeyId and SecretAccessKey )
359             Net::Amazon::MechanicalTurk->methodAlias(
360             'access_key' => 'accessKey',
361             'AccessKeyId' => 'accessKey',
362             'secret_key' => 'secretKey',
363             'SecretAccessKey' => 'secretKey',
364             'service_url' => 'serviceUrl',
365             'service_name' => 'serviceName',
366             'service_version' => 'serviceVersion',
367             'requester_url' => 'requesterUrl',
368             'worker_url' => 'workerUrl'
369             );
370              
371             =head1 Constructor
372              
373             =over
374              
375             =item init
376              
377             Initialize a new MechanicalTurk client
378              
379             =back
380              
381             =cut
382              
383             sub init {
384 17     17 1 196 my $self = shift;
385 17         223 $self->setAttributes(@_);
386 17         143 $self->_applyConfig;
387 17         228 $self->setAttributesIfNotDefined(
388             transport => Net::Amazon::MechanicalTurk::Transport->create,
389             serviceName => "AWSMechanicalTurkRequester",
390             serviceVersion => $DEFAULT_SERVICE_VERSION,
391             serviceUrl => $SANDBOX_URL,
392             );
393 0         0 foreach my $attr (qw{
394             accessKey
395             secretKey
396             serviceUrl
397             serviceVersion})
398             {
399 0 0       0 if (!defined($self->$attr)) {
400 0         0 die "Missing value for $attr.\n" .
401             "This value may be specified in a config file.\n" .
402             "Which may be specified in the following ways:\n" .
403             " 1. Set an environment variable named $PROP_ENVNAME to the path of the file.\n".
404             " 2. Put the file named $PROP_FILENAME in the current working directory.\n\n" .
405             "Example File::\n\n" .
406             "access_key: \n" .
407             "secret_key: \n" .
408             "service_url: $SANDBOX_URL\n" .
409             "service_version: $DEFAULT_SERVICE_VERSION\n\n" .
410             "Alternatively, you may run the command:\n\n" .
411             " " . $Config{perlpath} . " -MNet::Amazon::MechanicalTurk::Configurer -e configure\n\n" .
412             "to setup global (per-user) configuration values.\n"
413             }
414             }
415 0         0 $self->filterChain(Net::Amazon::MechanicalTurk::FilterChain->new);
416 0 0       0 if (!defined $self->requesterUrl) {
417 0 0       0 $self->requesterUrl($self->isProduction ? $PRODUCTION_REQUESTER_URL : $SANDBOX_REQUESTER_URL);
418             }
419 0 0       0 if (!defined $self->workerUrl) {
420 0 0       0 $self->workerUrl($self->isProduction ? $PRODUCTION_WORKER_URL : $SANDBOX_WORKER_URL);
421             }
422             }
423              
424             =head1 Utility Methods
425              
426             =over
427              
428             =item isProduction
429              
430             Tests whether or not the current serviceUrl is for production.
431              
432             =cut
433              
434             sub isProduction {
435 0     0 1 0 my $self = shift;
436 0         0 return $self->serviceUrl =~ /mechanicalturk\.amazonaws\.com/i;
437             }
438              
439             =item isSandbox
440              
441             Tests whether or not the current serviceUrl is for the MechanicalTurk
442             sandbox environment.
443              
444             =cut
445              
446             sub isSandbox {
447 0     0 1 0 my $self = shift;
448 0         0 return $self->serviceUrl =~ /mechanicalturk\.sandbox\.amazonaws.com/i;
449             }
450              
451             =back
452              
453             =head1 Getters/Setters
454              
455             =over
456              
457             =item serviceUrl
458              
459             serviceUrl determines which host the client communicates with.
460             Can be given a full Url, or can be set to one of the named urls:
461             * Sanbox
462             * Production
463              
464             =cut
465              
466             sub serviceUrl {
467             # In addition to setting the serviceUrl the url is parsed for parameters
468             # that set the serviceName and serviceVersion.
469 17     17 1 193 my $self = shift;
470 17         50 my $attrName = "Net::Amazon::MechanicalTurk::serviceUrl";
471 17 50       86 if ($#_ >= 0) {
472 17         43 my $serviceUrl = shift;
473              
474             # Allow for named endpoints
475 17 50       180 if ($serviceUrl =~ m/^Sandbox$/i) {
    50          
476 0         0 $serviceUrl = $SANDBOX_URL;
477             }
478             elsif ($serviceUrl =~ m/^Prod(uction)?$/i) {
479 0         0 $serviceUrl = $PRODUCTION_URL;
480             }
481              
482 17         158 my $uri = URI->new($serviceUrl);
483 17         190984 my %params = $uri->query_form;
484 17 50       3013 if (exists $params{Service}) {
485 0         0 $self->serviceName($params{Service});
486             }
487 17 50       76 if (exists $params{Version}) {
488 0         0 $self->serviceVersion($params{Version});
489             }
490 17         553 $self->{$attrName} = $serviceUrl;
491             }
492 17         93 return $self->{$attrName};
493             }
494              
495             =item transport
496              
497             transport is the object that handles actual comunications with the service.
498             Pass in an initialized transport or parameters to be passed to Net::Amazon::MechanicalTurk::Transport->create.
499              
500             =cut
501              
502             sub transport {
503 0     0 1 0 my $self = shift;
504 0         0 my $attrName = "Net::Amazon::MechanicalTurk::transport";
505 0 0       0 if ($#_ >= 0) {
506 0         0 my $transport = shift;
507 0 0       0 if (UNIVERSAL::isa($transport, "Net::Amazon::MechanicalTurk::Transport")) {
508 0         0 $self->{$attrName} = $transport;
509             }
510             else {
511 0         0 $self->{$attrName} = Net::Amazon::MechanicalTurk::Transport->create($transport, @_);
512             }
513             }
514 0         0 return $self->{$attrName};
515             }
516              
517             =back
518              
519             =head1 Mechanical Turk API calls
520              
521             =over
522              
523             =item iterator
524              
525             iterator retrieves a Net::Amazon:MechanicalTurk::PagedResultsIterator for the requested operation and parameters
526              
527             =cut
528              
529             sub iterator {
530 0     0 1 0 my $self = shift;
531 0         0 my $operation = shift;
532              
533 0         0 my %params;
534 0 0 0     0 if ($#_ == 0 and UNIVERSAL::isa($_[0], "ARRAY")) {
535 0         0 $params{$operation} = shift;
536             }
537             else {
538 0 0       0 %params = ($#_ == 0) ? %{$_[0]} : @_;
  0         0  
539             }
540              
541 0         0 return Net::Amazon::MechanicalTurk::PagedResultsIterator->new(
542             mturk => $self,
543             operation => $operation,
544             params => \%params
545             );
546             }
547              
548             =item call
549              
550             call simply invokes the requested operation with the provided parameters and returns the result
551              
552             =cut
553              
554             sub call {
555 0     0 1 0 my $self = shift;
556 0         0 my $operation = shift;
557              
558 0         0 my %params;
559 0 0 0     0 if ($#_ == 0 and UNIVERSAL::isa($_[0], "ARRAY")) {
560 0         0 $params{$operation} = shift;
561             }
562             else {
563 0 0       0 %params = ($#_ == 0) ? %{$_[0]} : @_;
  0         0  
564             }
565              
566 0         0 return $self->filterChain->execute(\&_call, $self, $operation, \%params);
567             }
568              
569             =back
570              
571             =cut
572              
573             # Private methods
574              
575             sub _call {
576 0     0   0 my ($self, $operation, $params) = @_;
577              
578 0         0 $self->debugMessage("Calling operation $operation.");
579              
580 0         0 my $timestamp = $self->_createTimestamp;
581 0         0 my $request = {
582             Service => $self->serviceName,
583             AWSAccessKeyId => $self->accessKey,
584             Version => $self->serviceVersion,
585             Operation => $operation,
586             Signature => $self->_createSignature($operation, $timestamp),
587             Timestamp => $timestamp
588             };
589 0         0 while (my ($k,$v) = each %$params) {
590 0         0 $request->{$k} = $v;
591             }
592              
593 0         0 $self->request($request);
594              
595 0         0 my $response;
596 0         0 eval {
597 0         0 my $xml = $self->transport->call($self, $operation, $request);
598 0         0 $response = Net::Amazon::MechanicalTurk::Response->new(xml => $xml);
599             };
600 0 0       0 if ($@) {
601 0         0 $response = Net::Amazon::MechanicalTurk::Response->new->clientError('TransportError', $@);
602             }
603              
604 0 0       0 if ($self->debug) {
605 0         0 $self->debugMessage($response->toString);
606             }
607              
608 0         0 $self->response($response);
609 0 0       0 if ($response->errorCode) {
610 0         0 Carp:croak("[" . $response->errorCode . "] " . $response->errorMessage);
611             }
612              
613 0         0 return $response->result;
614             }
615              
616             sub _createTimestamp {
617 0     0   0 my @time = gmtime(time());
618 0         0 return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",
619             $time[5] + 1900,
620             $time[4] + 1,
621             $time[3],
622             $time[2],
623             $time[1],
624             $time[0],
625             );
626             }
627              
628             sub _createSignature {
629 0     0   0 my ($self, $operation, $timestamp) = @_;
630 0         0 my $str = $self->serviceName . $operation . $timestamp;
631 0         0 my $signature = encode_base64(hmac_sha1($str, $self->secretKey));
632 0         0 chomp($signature);
633 0         0 return $signature;
634             }
635              
636             sub _applyConfig {
637 17     17   56 my ($self) = @_;
638              
639             # Find config files
640 17 50       153 if (!$self->config) {
641 17 50       354 if (exists $ENV{$PROP_ENVNAME}) {
    50          
642 0         0 $self->config($ENV{$PROP_ENVNAME});
643             }
644             elsif (-f $PROP_FILENAME) {
645 0         0 $self->config($PROP_FILENAME);
646             }
647             }
648              
649 17         147 $self->_applyConfigFile;
650              
651 17         175 my $homedir = Net::Amazon::MechanicalTurk::OSUtil->homeDirectory;
652 17 50 33     437 if ($homedir and -f "$homedir/$PROP_GLOBAL_DIR/$PROP_GLOBAL_AUTH") {
653 0         0 $self->config("$homedir/$PROP_GLOBAL_DIR/$PROP_GLOBAL_AUTH");
654 0         0 $self->_applyConfigFile; # re-apply with global defaults ( will not override other config )
655             }
656             }
657              
658             sub _applyConfigFile {
659 17     17   49 my ($self) = @_;
660             # Apply values from config
661 17 50       81 if ($self->config) {
662 0           my $props = Net::Amazon::MechanicalTurk::Properties->read($self->config);
663 0           $self->configProperties($props);
664 0           while (my ($k,$v) = each %$props) {
665 0 0         if (UNIVERSAL::can($self, $k)) {
666 0           eval {
667 0 0         if (!defined($self->$k)) {
668 0           $self->$k($v);
669             }
670             };
671             }
672             }
673              
674             # Look for properties which set debug on for a class
675 0           while (my ($k,$v) = each %$props) {
676 0 0         if ($k =~ /^(.*)(::|-)DEBUG/) {
677 0           my $module = $1;
678 0           $module =~ s/-/::/g;
679 0 0         if (Net::Amazon::MechanicalTurk::ModuleUtil->tryRequire($module)) {
680 0           eval {
681 0           $module->debug($v);
682             };
683 0 0         if ($@) {
684 0           warn "Can't set debug on module ($module) - $@.";
685             }
686             }
687             }
688             }
689              
690 0           $self->debugMessage("Loaded config from " . $self->config);
691             }
692             }
693              
694             # Hook for calling API methods by operation name
695              
696             sub AUTOLOAD {
697 0     0     my ($self) = @_;
698 0           my $operation = $AUTOLOAD;
699 0           $operation =~ s/^.*://;
700              
701             # There are 3 different type of AUTOLOADED method calls
702             # for the MechTurk client.
703             #
704             # 1. Basic API calls against the service.
705             # These start with an uppercase letter but do not end in 'All'.
706             # These methods are given to the call method.
707             # 2. Iterating calls against the service.
708             # Many MechanicalTurk service calls take a PageSize and PageNumber
709             # parameter. These are used to get a subset of items.
710             # If you call an service call, but add the word All to the end
711             # an iterator will be returned which knows when to make the next
712             # actual call, while your iterating.
713             # 3. High level commands.
714             # This client supports some very high level methods for bulk loading
715             # of hits, bulk approving assignments, downloading results, etc...
716             # These methods may be large and need optional modules so the
717             # loading of those methods are defered. The method is looked for
718             # in a module named:
719             #
720             # Net::Amazon::MechanicalTurk::Command::
721             #
722             # (Where module is the name of the method with the first letter upper cased.)
723             #
724              
725              
726             # MechanicalTurk operations start with an uppercase.
727              
728 0           my $sub;
729 0 0         if ($operation !~ /^[A-Z]/) {
    0          
730 0           my $module = "Net::Amazon::MechanicalTurk::Command::" . ucfirst($operation);
731 0 0         if (Net::Amazon::MechanicalTurk::ModuleUtil->tryRequire($module)) {
732 0           $sub = UNIVERSAL::can($module, $operation);
733             }
734 0 0         if (!$sub) {
735 0           Carp::croak("Method $operation does not exist on class " . ref($self) . ".");
736             }
737             }
738             elsif ($operation =~ /^(.+)All$/) {
739             # Special handling for methods ending with ALL
740             # An iterator is created which can be used
741             # to go across all pages.
742 0           $operation = $1;
743             $sub = sub {
744 0     0     my $_self = shift;
745 0           return $_self->iterator($operation, @_);
746 0           };
747             }
748             else {
749             $sub = sub {
750 0     0     my $_self = shift;
751 0           return $_self->call($operation, @_);
752 0           };
753             }
754 18     18   215 no strict 'refs';
  18         64  
  18         1651  
755 0           *{"${AUTOLOAD}"} = $sub;
  0            
756 0           goto &$sub;
757             }
758              
759             =head1 BUGS
760              
761             Please report any bugs or feature requests through the Amazon Web Services
762             Developer Connection.
763              
764             L
765              
766             =head1 SUPPORT
767              
768             You can find documentation for this module with the perldoc command.
769              
770             perldoc Net::Amazon::MechanicalTurk
771              
772             You can also look for information at:
773              
774             =over
775              
776             =item
777              
778             L
779              
780             =item
781              
782             L
783              
784             =back
785              
786             =head1 COPYRIGHT & LICENSE
787              
788             Copyright (c) 2007 Amazon Technologies, Inc.
789              
790             Licensed under the Apache License, Version 2.0 (the "License");
791             you may not use this file except in compliance with the License.
792             You may obtain a copy of the License at
793              
794             http://www.apache.org/licenses/LICENSE-2.0
795              
796             Unless required by applicable law or agreed to in writing, software
797             distributed under the License is distributed on an "AS IS" BASIS,
798             WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
799             See the License for the specific language governing permissions and
800             limitations under the License.
801              
802             =cut
803              
804             1; # End of Net::Amazon::MechanicalTurk