I beseech you dear monks to read my question. I know its a bit of code and text but I made good efforts to keep it tight
I'm on the learning road and I'm building an API wrapper as practise. Note, I'm not using Moose/Moo and building this to learn perl and perl OOP
I'm writing a wrapper over stack exchange api.
Usage would look like this (currently prints urls for testing) :
# for the following API urls:
##http://api.stackexchange.com/answers/{ids}/comments/?query_str
##http://api.stackexchange.com/answers/?query_str
use Net::StackExchange;
my $a = Net::StackExchange->new();
print $a->answers->{answers_comments}->(123,134,145,{
order=> "desc",
sort=>"votes"
});
######## THE ABOVE PRINTS:
#http://api.stackexchange.com/answers/123;134;145/comments?sort=votes&
+order=desc
print $a->answers->{answers}->({
order=> "desc",
sort=>"votes"
});
######## THE ABOVE PRINTS:
#http://api.stackexchange.com/answers/?sort=votes&order=desc
Mostly urls are of the form api/{name}/{ids_list}/{anothename} or api/{name}/. After that there are query params which are represented by a hash in my code.
My questions begin:
- Does the consumer code look ok? Is it neat enough abstraction to have anonymous functions like this: $object->answers->{answers_comments}->(..)
- Is there I way I can build methods so my consumer code looks like $object->answers->answers_comments() would that be correct/better/perl-ish?
- Inside my anonymous why don't I have a reference to $self?
My Code
On my disk it looks like this:
Net-StackExchange/
├── Changes
├── MANIFEST
├── Makefile.PL
├── README
├── ignore.txt
├── lib
│ └── Net
│ ├── StackExchange
│ │ ├── V2
│ │ │ ├── Answers.pm
│ │ │ └── Common.pm
│ │ └── V2.pm
│ └── StackExchange.pm
└── t
├── 00-load.t
├── boilerplate.t
├── manifest.t
├── pod-coverage.t
└── pod.t
The code in each of the FOUR pm files
###################
# Inside StackExchange.pm
###################
sub new {
return Net::StackExchange::V2->new();
}
###################
# Inside V2.pm
###################
sub new {
my ($class) = @_;
my $self = {};
bless $self, $class;
return $self;
}
sub answers {
return Net::StackExchange::V2::Answers->new();
}
###################
# Inside Answers.pm
###################
use Net::StackExchange::V2::Common qw(query no_params one_param);
sub new {
my ($class) = @_;
my $self = {
site => "stackoverflow",
answers => no_params("answers"),
answers_comments => one_param("answers","comments"),
};
bless $self, $class;
return $self;
}
#################################################
#################################################
# THIS IS WHAT NEEDS ATTENTION
# Inside Common.pm
#################################################
use constant BASE_URL => "http://api.stackexchange.com/";
our @ISA = qw(Exporter);
our @EXPORT = qw(query no_params one_param);
sub query {
#get the hash from the last param and use it for the query str
my $queryStrHash = pop @_;
#add rest of the params into the url.
my $url = join("/",@_);
my @params = ();
while ( my ($key, $value) = each(%$queryStrHash) ) {
push @params, $key."=".$value;
}
my $query = '?'.join '&',@params;
return BASE_URL.$url.$query;
}
##function to generate a function that generates url with
#a name and no parameters..
sub no_params {
#WHY don't I get $self = shift here?
my $name = shift;
return sub {
#WHY don't I get $self = shift here?
my $queryStr = pop @_;
return query($name, $queryStr);
}
}
##function to generate a function that generates url
#with a name and one parameter..
sub one_param {
my $param1 = shift;
my $param2 = shift;
return sub {
my $q = pop @_;
my @ids = @_;
return query($param1, join(";",@ids), $param2, $q);
}
}