File Coverage

blib/lib/Net/Twitter.pm
Criterion Covered Total %
statement 81 83 97.5
branch 21 28 75.0
condition 11 14 78.5
subroutine 16 16 100.0
pod 1 1 100.0
total 130 142 91.5


line stmt bran cond sub pod time code
1             package Net::Twitter;
2             $Net::Twitter::VERSION = '4.01010';
3 30     38   1298206 use Moose;
  30         8696436  
  30         195  
4 30     38   163285 use Carp::Clan qw/^(?:Net::Twitter|Moose|Class::MOP)/;
  30         37274  
  30         148  
5 30     30   15564 use JSON;
  30         171593  
  30         221  
6 30     30   15495 use Net::Twitter::Core;
  30         86  
  30         1225  
7 30     30   18624 use Digest::SHA qw/sha1_hex/;
  30         63753  
  30         1962  
8 30     30   172 use Class::Load ();
  30         40  
  30         412  
9              
10 30     30   108 use namespace::autoclean;
  30         36  
  30         239  
11              
12             has '_trait_namespace' => (
13             Moose->VERSION >= '0.85' ? (is => 'bare') : (),
14             default => 'Net::Twitter::Role',
15             );
16              
17             # See Net/Twitter.pod for documentation, Net/Twitter/Core.pm for implementation.
18             #
19             # For transparent back compat, Net::Twitter->new() creates a Net::Twitter::Core
20             # with the 'Legacy' trait.
21              
22             # transform_trait and resolve_traits stolen from MooseX::Traits
23             sub _transform_trait {
24 67     67   107 my ($class, $name) = @_;
25 67         335 my $namespace = $class->meta->find_attribute_by_name('_trait_namespace');
26 67         12259 my $base;
27 67 50       370 if($namespace->has_default){
28 67         740 $base = $namespace->default;
29 67 50       424 if(ref $base eq 'CODE'){
30 0         0 $base = $base->();
31             }
32             }
33              
34 67 50       161 return $name unless $base;
35 67 50       212 return $1 if $name =~ /^[+](.+)$/;
36 67         173 return "$base\::$name";
37             }
38              
39             sub _resolve_traits {
40 46     46   92 my ($class, @traits) = @_;
41              
42             return map {
43 46 100       83 unless ( ref ) {
  71         198  
44 67         227 $_ = $class->_transform_trait($_);
45 67         254 Class::Load::load_class($_);
46             }
47 71         2389 $_;
48             } @traits;
49             }
50              
51             sub _isa {
52 80     80   267080 my $self = shift;
53 80         96 my $isa = shift;
54              
55 80   100     605 return $isa eq __PACKAGE__ || $self->SUPER::isa($isa)
56             };
57              
58             sub _create_anon_class {
59 51     51   102 my ($superclasses, $traits, $immutable, $package) = @_;
60              
61             # Do we already have a meta class?
62 51 100       619 return $package->meta if $package->can('meta');
63              
64 44         66 my $meta;
65             $meta = Net::Twitter::Core->meta->create_anon_class(
66             superclasses => $superclasses,
67             roles => $traits,
68 44     39   322 methods => { meta => sub { $meta }, isa => \&_isa },
  39     39   31858  
        37      
69             cache => 0,
70             package => $package,
71             );
72 44         989830 $meta->make_immutable(inline_constructor => $immutable);
73              
74 44         12862 return $meta;
75             }
76              
77             {
78             my $serial_number = 0;
79             my %serial_for_params;
80              
81             sub _name_for_anon_class {
82 46     46   67 my @t = @{$_[0]};
  46         108  
83              
84 46         65 my @comps;
85 46         130 while ( @t ) {
86 67         96 my $t = shift @t;
87 67 100       165 if ( ref $t[0] eq 'HASH' ) {
88 4         27 my $params = shift @t;
89 4         73 my $sig = sha1_hex(JSON->new->utf8->encode($params));
90 4   66     27 my $sn = $serial_for_params{$sig} ||= ++$serial_number;
91 4         9 $t .= "_$sn";
92             }
93 67         370 $t =~ s/(?:::|\W)/_/g;
94 67         298 push @comps, $t;
95             }
96              
97 46         549 my $ver = $Net::Twitter::Core::VERSION;
98 46         267 $ver =~ s/\W/_/g;
99              
100 46         280 return __PACKAGE__ . "_v${ver}_" . join '__', 'with', sort @comps;
101             }
102             }
103              
104             sub new {
105 46     46 1 224950 my $class = shift;
106              
107 46 50       174 croak '"new" is not an instance method' if ref $class;
108              
109 46 50 33     339 my %args = @_ == 1 && ref $_[0] eq 'HASH' ? %{$_[0]} : @_;
  0         0  
110              
111 46         117 my $traits = delete $args{traits};
112              
113 46 100       281 if ( defined (my $legacy = delete $args{legacy}) ) {
114 10 50       28 croak "Options 'legacy' and 'traits' are mutually exclusive. Use only one."
115             if $traits;
116              
117 10 100       31 $traits = [ $legacy ? 'Legacy' : 'API::REST' ];
118             }
119              
120 46   100     182 $traits ||= [ qw/Legacy/ ];
121              
122             # ensure we have the OAuth trait if we have a consumer key (unless we've
123             # specified AppAuth)
124 46 100 100     202 if ( $args{consumer_key} && !grep $_ eq 'AppAuth', @$traits ) {
125 4         15 $traits = [ (grep $_ ne 'OAuth', @$traits), 'OAuth' ];
126             }
127              
128             # create a unique name for the created class based on trait names and parameters
129 46         288 my $anon_class_name = _name_for_anon_class($traits);
130              
131 46         190 $traits = [ $class->_resolve_traits(@$traits) ];
132              
133 46         132 my $superclasses = [ 'Net::Twitter::Core' ];
134 46         170 my $meta = _create_anon_class($superclasses, $traits, 1, $anon_class_name);
135              
136             # create a Net::Twitter::Core object with roles applied
137 46         1558 my $new = $meta->name->new(%args);
138              
139             # rebless it to include a superclass, if we're being subclassed
140 46 100       165 if ( $class ne __PACKAGE__ ) {
141 5         15 unshift @$superclasses, $class;
142 5         16 my $final_meta = _create_anon_class(
143             $superclasses, $traits, 0, join '::', $class, $anon_class_name
144             );
145 5         27 bless $new, $final_meta->name;
146             }
147              
148 46         322 return $new;
149             }
150              
151             __PACKAGE__->meta->make_immutable(inline_constructor => 0);
152              
153             1;
154              
155             __END__
156              
157             =head1 NAME
158              
159             Net::Twitter - A perl interface to the Twitter API
160              
161             =head1 VERSION
162              
163             version 4.01010
164              
165             =head1 DESCRIPTION
166              
167             See Net/Twitter.pod