[svn-upgrade] Integrating new upstream version, libcpandb-perl (0.13)
Ansgar Burchardt
14 years ago
0 | 0 | Changes for Perl extension CPANDB |
1 | 1 | |
2 | 0.12 | |
2 | 0.13 Mon 19 Apr 2010 | |
3 | - Updated ORLite::POD-generated documentation. | |
4 | - Added documentation on additional methods | |
5 | ||
6 | 0.12 Mon 26 Oct 2009 | |
3 | 7 | - Added documentation for cpangraph (in POD) |
4 | 8 | |
5 | 9 | 0.11 Thu 1 Oct 2009 |
24 | 24 | script/cpangraph |
25 | 25 | t/01_compile.t |
26 | 26 | t/02_release.t |
27 | t/97_meta.t | |
28 | t/98_pod.t | |
29 | t/99_pmv.t | |
27 | xt/meta.t | |
28 | xt/pmv.t | |
29 | xt/pod.t |
0 | 0 | --- |
1 | 1 | abstract: 'An ORLite-based ORM Database API' |
2 | 2 | author: |
3 | - 'Adam Kennedy.' | |
3 | - '- 2010 Adam Kennedy.' | |
4 | 4 | build_requires: |
5 | 5 | ExtUtils::MakeMaker: 6.42 |
6 | 6 | LWP::Online: 1.07 |
8 | 8 | configure_requires: |
9 | 9 | ExtUtils::MakeMaker: 6.42 |
10 | 10 | distribution_type: module |
11 | generated_by: 'Module::Install version 0.91' | |
11 | generated_by: 'Module::Install version 0.95' | |
12 | 12 | license: perl |
13 | 13 | meta-spec: |
14 | 14 | url: http://module-build.sourceforge.net/META-spec-v1.4.html |
19 | 19 | directory: |
20 | 20 | - inc |
21 | 21 | - t |
22 | - xt | |
22 | 23 | requires: |
23 | 24 | DateTime: 0.50 |
24 | 25 | Getopt::Long: 2.33 |
32 | 33 | ChangeLog: http://fisheye2.atlassian.com/changelog/cpan/trunk/CPANDB |
33 | 34 | license: http://dev.perl.org/licenses/ |
34 | 35 | repository: http://svn.ali.as/cpan/trunk/CPANDB |
35 | version: 0.12 | |
36 | version: 0.13 |
0 | 0 | NAME |
1 | 1 | CPANDB - An ORLite-based ORM Database API |
2 | 2 | |
3 | SYNOPSIS | |
4 | TO BE COMPLETED | |
5 | ||
6 | 3 | DESCRIPTION |
7 | TO BE COMPLETED | |
4 | CPANDB is an module for accessing CPAN metadata merged from many | |
5 | different CPAN websites into a single simple object model. | |
8 | 6 | |
9 | 7 | METHODS |
10 | 8 | dsn |
48 | 46 | |
49 | 47 | The "dbh" method returns a DBI::db object, or throws an exception on |
50 | 48 | error. |
49 | ||
50 | begin | |
51 | CPANDB->begin; | |
52 | ||
53 | The "begin" method indicates the start of a transaction. | |
54 | ||
55 | In the same way that ORLite allows only a single connection, likewise it | |
56 | allows only a single application-wide transaction. | |
57 | ||
58 | No indication is given as to whether you are currently in a transaction | |
59 | or not, all code should be written neutrally so that it works either way | |
60 | or doesn't need to care. | |
61 | ||
62 | Returns true or throws an exception on error. | |
63 | ||
64 | rollback | |
65 | The "rollback" method rolls back the current transaction. If called | |
66 | outside of a current transaction, it is accepted and treated as a null | |
67 | operation. | |
68 | ||
69 | Once the rollback has been completed, the database connection falls back | |
70 | into auto-commit state. If you wish to immediately start another | |
71 | transaction, you will need to issue a separate ->begin call. | |
72 | ||
73 | If a transaction exists at END-time as the process exits, it will be | |
74 | automatically rolled back. | |
75 | ||
76 | Returns true or throws an exception on error. | |
77 | ||
78 | do | |
79 | CPANDB->do( | |
80 | 'insert into table ( foo, bar ) values ( ?, ? )', {}, | |
81 | \$foo_value, | |
82 | \$bar_value, | |
83 | ); | |
84 | ||
85 | The "do" method is a direct wrapper around the equivalent DBI method, | |
86 | but applied to the appropriate locally-provided connection or | |
87 | transaction. | |
88 | ||
89 | It takes the same parameters and has the same return values and error | |
90 | behaviour. | |
51 | 91 | |
52 | 92 | selectall_arrayref |
53 | 93 | The "selectall_arrayref" method is a direct wrapper around the |
116 | 156 | The "pragma" method provides a convenient method for fetching a pragma |
117 | 157 | for a datase. See the SQLite documentation for more details. |
118 | 158 | |
159 | distribution | |
160 | my $dist = CPANDB->distribution('Config-Tiny'); | |
161 | ||
162 | The "distribution" method is a convenient shortcut for direct access to | |
163 | the CPANDB::Distribution object for a single named distribution. | |
164 | ||
165 | graph | |
166 | my $everything = CPANDB->graph; | |
167 | ||
168 | Originally created as a proof of concept for Graph integration, the | |
169 | "graph" method creates a single giant Graph::Directed object | |
170 | representing the dependency structure of the entire CPAN at a | |
171 | distribution-to-distribution level. | |
172 | ||
173 | The graphing features of CPANDB are considered optional. To use this | |
174 | method you will need to install Graph::Directed yourself, and set up a | |
175 | dependency in any code that uses Graph features. | |
176 | ||
119 | 177 | SUPPORT |
120 | CPANDB is based on ORLite 1.23. | |
178 | CPANDB is based on ORLite $ORLite::VERSION. | |
121 | 179 | |
122 | Documentation created by ORLite::Pod 0.06. | |
180 | Documentation created by ORLite::Pod $ORLite::Pod::VERSION. | |
123 | 181 | |
124 | 182 | For general support please see the support section of the main project |
125 | 183 | documentation. |
126 | 184 | |
127 | 185 | COPYRIGHT |
128 | Copyright 2009 Adam Kennedy. | |
186 | Copyright 2009 - 2010 Adam Kennedy. | |
129 | 187 | |
130 | 188 | This program is free software; you can redistribute it and/or modify it |
131 | 189 | under the same terms as Perl itself. |
3 | 3 | use strict 'vars'; |
4 | 4 | use vars qw{$VERSION}; |
5 | 5 | BEGIN { |
6 | $VERSION = '0.91'; | |
6 | $VERSION = '0.95'; | |
7 | 7 | } |
8 | 8 | |
9 | 9 | # Suspend handler for "redefined" warnings |
8 | 8 | |
9 | 9 | use vars qw{$VERSION @ISA $ISCORE}; |
10 | 10 | BEGIN { |
11 | $VERSION = '0.91'; | |
11 | $VERSION = '0.95'; | |
12 | 12 | @ISA = 'Module::Install::Base'; |
13 | 13 | $ISCORE = 1; |
14 | 14 | } |
3 | 3 | use strict; |
4 | 4 | use vars qw{$VERSION $ISCORE}; |
5 | 5 | BEGIN { |
6 | $VERSION = '0.91'; | |
6 | $VERSION = '0.95'; | |
7 | 7 | $ISCORE = 1; |
8 | 8 | *inc::Module::Install::DSL::VERSION = *VERSION; |
9 | 9 | @inc::Module::Install::DSL::ISA = __PACKAGE__; |
38 | 38 | } |
39 | 39 | |
40 | 40 | # Convert the basic syntax to code |
41 | my $code = "package main;\n\n" | |
41 | my $code = "INIT {\n" | |
42 | . "package main;\n\n" | |
42 | 43 | . dsl2code($dsl) |
43 | . "\n\nWriteAll();\n"; | |
44 | . "\n\nWriteAll();\n" | |
45 | . "}\n"; | |
44 | 46 | |
45 | 47 | # Execute the script |
46 | 48 | eval $code; |
47 | print STDERR "Failed to execute the generated code" if $@; | |
49 | print STDERR "Failed to execute the generated code...\n$@" if $@; | |
48 | 50 | |
49 | 51 | exit(0); |
50 | 52 | } |
5 | 5 | |
6 | 6 | use vars qw{$VERSION @ISA $ISCORE}; |
7 | 7 | BEGIN { |
8 | $VERSION = '0.91'; | |
8 | $VERSION = '0.95'; | |
9 | 9 | @ISA = 'Module::Install::Base'; |
10 | 10 | $ISCORE = 1; |
11 | 11 | } |
6 | 6 | |
7 | 7 | use vars qw{$VERSION @ISA $ISCORE}; |
8 | 8 | BEGIN { |
9 | $VERSION = '0.91'; | |
9 | $VERSION = '0.95'; | |
10 | 10 | @ISA = 'Module::Install::Base'; |
11 | 11 | $ISCORE = 1; |
12 | 12 | } |
24 | 24 | die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; |
25 | 25 | } |
26 | 26 | |
27 | # In automated testing, always use defaults | |
28 | if ( $ENV{AUTOMATED_TESTING} and ! $ENV{PERL_MM_USE_DEFAULT} ) { | |
27 | # In automated testing or non-interactive session, always use defaults | |
28 | if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { | |
29 | 29 | local $ENV{PERL_MM_USE_DEFAULT} = 1; |
30 | 30 | goto &ExtUtils::MakeMaker::prompt; |
31 | 31 | } else { |
33 | 33 | } |
34 | 34 | } |
35 | 35 | |
36 | # Store a cleaned up version of the MakeMaker version, | |
37 | # since we need to behave differently in a variety of | |
38 | # ways based on the MM version. | |
39 | my $makemaker = eval $ExtUtils::MakeMaker::VERSION; | |
40 | ||
41 | # If we are passed a param, do a "newer than" comparison. | |
42 | # Otherwise, just return the MakeMaker version. | |
43 | sub makemaker { | |
44 | ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 | |
45 | } | |
46 | ||
47 | # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified | |
48 | # as we only need to know here whether the attribute is an array | |
49 | # or a hash or something else (which may or may not be appendable). | |
50 | my %makemaker_argtype = ( | |
51 | C => 'ARRAY', | |
52 | CONFIG => 'ARRAY', | |
53 | # CONFIGURE => 'CODE', # ignore | |
54 | DIR => 'ARRAY', | |
55 | DL_FUNCS => 'HASH', | |
56 | DL_VARS => 'ARRAY', | |
57 | EXCLUDE_EXT => 'ARRAY', | |
58 | EXE_FILES => 'ARRAY', | |
59 | FUNCLIST => 'ARRAY', | |
60 | H => 'ARRAY', | |
61 | IMPORTS => 'HASH', | |
62 | INCLUDE_EXT => 'ARRAY', | |
63 | LIBS => 'ARRAY', # ignore '' | |
64 | MAN1PODS => 'HASH', | |
65 | MAN3PODS => 'HASH', | |
66 | META_ADD => 'HASH', | |
67 | META_MERGE => 'HASH', | |
68 | PL_FILES => 'HASH', | |
69 | PM => 'HASH', | |
70 | PMLIBDIRS => 'ARRAY', | |
71 | PMLIBPARENTDIRS => 'ARRAY', | |
72 | PREREQ_PM => 'HASH', | |
73 | CONFIGURE_REQUIRES => 'HASH', | |
74 | SKIP => 'ARRAY', | |
75 | TYPEMAPS => 'ARRAY', | |
76 | XS => 'HASH', | |
77 | # VERSION => ['version',''], # ignore | |
78 | # _KEEP_AFTER_FLUSH => '', | |
79 | ||
80 | clean => 'HASH', | |
81 | depend => 'HASH', | |
82 | dist => 'HASH', | |
83 | dynamic_lib=> 'HASH', | |
84 | linkext => 'HASH', | |
85 | macro => 'HASH', | |
86 | postamble => 'HASH', | |
87 | realclean => 'HASH', | |
88 | test => 'HASH', | |
89 | tool_autosplit => 'HASH', | |
90 | ||
91 | # special cases where you can use makemaker_append | |
92 | CCFLAGS => 'APPENDABLE', | |
93 | DEFINE => 'APPENDABLE', | |
94 | INC => 'APPENDABLE', | |
95 | LDDLFLAGS => 'APPENDABLE', | |
96 | LDFROM => 'APPENDABLE', | |
97 | ); | |
98 | ||
36 | 99 | sub makemaker_args { |
37 | my $self = shift; | |
100 | my ($self, %new_args) = @_; | |
38 | 101 | my $args = ( $self->{makemaker_args} ||= {} ); |
39 | %$args = ( %$args, @_ ); | |
102 | foreach my $key (keys %new_args) { | |
103 | if ($makemaker_argtype{$key} eq 'ARRAY') { | |
104 | $args->{$key} = [] unless defined $args->{$key}; | |
105 | unless (ref $args->{$key} eq 'ARRAY') { | |
106 | $args->{$key} = [$args->{$key}] | |
107 | } | |
108 | push @{$args->{$key}}, | |
109 | ref $new_args{$key} eq 'ARRAY' | |
110 | ? @{$new_args{$key}} | |
111 | : $new_args{$key}; | |
112 | } | |
113 | elsif ($makemaker_argtype{$key} eq 'HASH') { | |
114 | $args->{$key} = {} unless defined $args->{$key}; | |
115 | foreach my $skey (keys %{ $new_args{$key} }) { | |
116 | $args->{$key}{$skey} = $new_args{$key}{$skey}; | |
117 | } | |
118 | } | |
119 | elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { | |
120 | $self->makemaker_append($key => $new_args{$key}); | |
121 | } | |
122 | else { | |
123 | if (defined $args->{$key}) { | |
124 | warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; | |
125 | } | |
126 | $args->{$key} = $new_args{$key}; | |
127 | } | |
128 | } | |
40 | 129 | return $args; |
41 | 130 | } |
42 | 131 | |
43 | 132 | # For mm args that take multiple space-seperated args, |
44 | 133 | # append an argument to the current list. |
45 | 134 | sub makemaker_append { |
46 | my $self = sShift; | |
135 | my $self = shift; | |
47 | 136 | my $name = shift; |
48 | 137 | my $args = $self->makemaker_args; |
49 | $args->{name} = defined $args->{$name} | |
50 | ? join( ' ', $args->{name}, @_ ) | |
138 | $args->{$name} = defined $args->{$name} | |
139 | ? join( ' ', $args->{$name}, @_ ) | |
51 | 140 | : join( ' ', @_ ); |
52 | 141 | } |
53 | 142 | |
106 | 195 | %test_dir = (); |
107 | 196 | require File::Find; |
108 | 197 | File::Find::find( \&_wanted_t, $dir ); |
198 | if ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { | |
199 | File::Find::find( \&_wanted_t, 'xt' ); | |
200 | } | |
109 | 201 | $self->tests( join ' ', map { "$_/*.t" } sort keys %test_dir ); |
110 | 202 | } |
111 | 203 | |
129 | 221 | # an underscore, even though its own version may contain one! |
130 | 222 | # Hence the funny regexp to get rid of it. See RT #35800 |
131 | 223 | # for details. |
132 | $self->build_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ ); | |
133 | $self->configure_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ ); | |
224 | my $v = $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/; | |
225 | $self->build_requires( 'ExtUtils::MakeMaker' => $v ); | |
226 | $self->configure_requires( 'ExtUtils::MakeMaker' => $v ); | |
134 | 227 | } else { |
135 | 228 | # Allow legacy-compatibility with 5.005 by depending on the |
136 | 229 | # most recent EU:MM that supported 5.005. |
137 | $self->build_requires( 'ExtUtils::MakeMaker' => 6.42 ); | |
230 | $self->build_requires( 'ExtUtils::MakeMaker' => 6.42 ); | |
138 | 231 | $self->configure_requires( 'ExtUtils::MakeMaker' => 6.42 ); |
139 | 232 | } |
140 | 233 | |
142 | 235 | my $args = $self->makemaker_args; |
143 | 236 | $args->{DISTNAME} = $self->name; |
144 | 237 | $args->{NAME} = $self->module_name || $self->name; |
145 | $args->{VERSION} = $self->version; | |
146 | 238 | $args->{NAME} =~ s/-/::/g; |
239 | $args->{VERSION} = $self->version or die <<'EOT'; | |
240 | ERROR: Can't determine distribution version. Please specify it | |
241 | explicitly via 'version' in Makefile.PL, or set a valid $VERSION | |
242 | in a module, and provide its file path via 'version_from' (or | |
243 | 'all_from' if you prefer) in Makefile.PL. | |
244 | EOT | |
245 | ||
246 | $DB::single = 1; | |
147 | 247 | if ( $self->tests ) { |
148 | $args->{test} = { TESTS => $self->tests }; | |
248 | my @tests = split ' ', $self->tests; | |
249 | my %seen; | |
250 | $args->{test} = { | |
251 | TESTS => (join ' ', grep {!$seen{$_}++} @tests), | |
252 | }; | |
253 | } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { | |
254 | $args->{test} = { | |
255 | TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), | |
256 | }; | |
149 | 257 | } |
150 | 258 | if ( $] >= 5.005 ) { |
151 | 259 | $args->{ABSTRACT} = $self->abstract; |
152 | $args->{AUTHOR} = $self->author; | |
153 | } | |
154 | if ( eval($ExtUtils::MakeMaker::VERSION) >= 6.10 ) { | |
155 | $args->{NO_META} = 1; | |
156 | } | |
157 | if ( eval($ExtUtils::MakeMaker::VERSION) > 6.17 and $self->sign ) { | |
260 | $args->{AUTHOR} = join ', ', @{$self->author || []}; | |
261 | } | |
262 | if ( $self->makemaker(6.10) ) { | |
263 | $args->{NO_META} = 1; | |
264 | #$args->{NO_MYMETA} = 1; | |
265 | } | |
266 | if ( $self->makemaker(6.17) and $self->sign ) { | |
158 | 267 | $args->{SIGN} = 1; |
159 | 268 | } |
160 | 269 | unless ( $self->is_admin ) { |
161 | 270 | delete $args->{SIGN}; |
162 | 271 | } |
163 | ||
164 | # Merge both kinds of requires into prereq_pm | |
272 | if ( $self->makemaker(6.31) and $self->license ) { | |
273 | $args->{LICENSE} = $self->license; | |
274 | } | |
275 | ||
165 | 276 | my $prereq = ($args->{PREREQ_PM} ||= {}); |
166 | 277 | %$prereq = ( %$prereq, |
167 | map { @$_ } | |
278 | map { @$_ } # flatten [module => version] | |
168 | 279 | map { @$_ } |
169 | 280 | grep $_, |
170 | ($self->configure_requires, $self->build_requires, $self->requires) | |
281 | ($self->requires) | |
171 | 282 | ); |
172 | 283 | |
173 | 284 | # Remove any reference to perl, PREREQ_PM doesn't support it |
174 | 285 | delete $args->{PREREQ_PM}->{perl}; |
175 | 286 | |
176 | # merge both kinds of requires into prereq_pm | |
287 | # Merge both kinds of requires into BUILD_REQUIRES | |
288 | my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); | |
289 | %$build_prereq = ( %$build_prereq, | |
290 | map { @$_ } # flatten [module => version] | |
291 | map { @$_ } | |
292 | grep $_, | |
293 | ($self->configure_requires, $self->build_requires) | |
294 | ); | |
295 | ||
296 | # Remove any reference to perl, BUILD_REQUIRES doesn't support it | |
297 | delete $args->{BUILD_REQUIRES}->{perl}; | |
298 | ||
299 | # Delete bundled dists from prereq_pm | |
177 | 300 | my $subdirs = ($args->{DIR} ||= []); |
178 | 301 | if ($self->bundles) { |
179 | 302 | foreach my $bundle (@{ $self->bundles }) { |
180 | 303 | my ($file, $dir) = @$bundle; |
181 | 304 | push @$subdirs, $dir if -d $dir; |
182 | delete $prereq->{$file}; | |
183 | } | |
305 | delete $build_prereq->{$file}; #Delete from build prereqs only | |
306 | } | |
307 | } | |
308 | ||
309 | unless ( $self->makemaker('6.55_03') ) { | |
310 | %$prereq = (%$prereq,%$build_prereq); | |
311 | delete $args->{BUILD_REQUIRES}; | |
184 | 312 | } |
185 | 313 | |
186 | 314 | if ( my $perl_version = $self->perl_version ) { |
187 | 315 | eval "use $perl_version; 1" |
188 | 316 | or die "ERROR: perl: Version $] is installed, " |
189 | 317 | . "but we need version >= $perl_version"; |
190 | } | |
191 | ||
192 | $args->{INSTALLDIRS} = $self->installdirs; | |
193 | ||
194 | my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_})} keys %$args; | |
318 | ||
319 | if ( $self->makemaker(6.48) ) { | |
320 | $args->{MIN_PERL_VERSION} = $perl_version; | |
321 | } | |
322 | } | |
323 | ||
324 | if ($self->installdirs) { | |
325 | warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; | |
326 | $args->{INSTALLDIRS} = $self->installdirs; | |
327 | } | |
328 | ||
329 | my %args = map { | |
330 | ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) | |
331 | } keys %$args; | |
195 | 332 | |
196 | 333 | my $user_preop = delete $args{dist}->{PREOP}; |
197 | if (my $preop = $self->admin->preop($user_preop)) { | |
334 | if ( my $preop = $self->admin->preop($user_preop) ) { | |
198 | 335 | foreach my $key ( keys %$preop ) { |
199 | 336 | $args{dist}->{$key} = $preop->{$key}; |
200 | 337 | } |
264 | 401 | |
265 | 402 | __END__ |
266 | 403 | |
267 | #line 394 | |
404 | #line 531 |
5 | 5 | |
6 | 6 | use vars qw{$VERSION @ISA $ISCORE}; |
7 | 7 | BEGIN { |
8 | $VERSION = '0.91'; | |
8 | $VERSION = '0.95'; | |
9 | 9 | @ISA = 'Module::Install::Base'; |
10 | 10 | $ISCORE = 1; |
11 | 11 | } |
18 | 18 | name |
19 | 19 | module_name |
20 | 20 | abstract |
21 | author | |
22 | 21 | version |
23 | 22 | distribution_type |
24 | 23 | tests |
42 | 41 | |
43 | 42 | my @array_keys = qw{ |
44 | 43 | keywords |
44 | author | |
45 | 45 | }; |
46 | ||
47 | *authors = \&author; | |
46 | 48 | |
47 | 49 | sub Meta { shift } |
48 | 50 | sub Meta_BooleanKeys { @boolean_keys } |
229 | 231 | die("The path '$file' does not exist, or is not a file"); |
230 | 232 | } |
231 | 233 | |
234 | $self->{values}{all_from} = $file; | |
235 | ||
232 | 236 | # Some methods pull from POD instead of code. |
233 | 237 | # If there is a matching .pod, use that instead |
234 | 238 | my $pod = $file; |
239 | 243 | $self->name_from($file) unless $self->name; |
240 | 244 | $self->version_from($file) unless $self->version; |
241 | 245 | $self->perl_version_from($file) unless $self->perl_version; |
242 | $self->author_from($pod) unless $self->author; | |
246 | $self->author_from($pod) unless @{$self->author || []}; | |
243 | 247 | $self->license_from($pod) unless $self->license; |
244 | 248 | $self->abstract_from($pod) unless $self->abstract; |
245 | 249 | |
384 | 388 | } |
385 | 389 | } |
386 | 390 | |
387 | sub perl_version_from { | |
388 | my $self = shift; | |
391 | sub _extract_perl_version { | |
389 | 392 | if ( |
390 | Module::Install::_read($_[0]) =~ m/ | |
391 | ^ | |
393 | $_[0] =~ m/ | |
394 | ^\s* | |
392 | 395 | (?:use|require) \s* |
393 | 396 | v? |
394 | 397 | ([\d_\.]+) |
397 | 400 | ) { |
398 | 401 | my $perl_version = $1; |
399 | 402 | $perl_version =~ s{_}{}g; |
403 | return $perl_version; | |
404 | } else { | |
405 | return; | |
406 | } | |
407 | } | |
408 | ||
409 | sub perl_version_from { | |
410 | my $self = shift; | |
411 | my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); | |
412 | if ($perl_version) { | |
400 | 413 | $self->perl_version($perl_version); |
401 | 414 | } else { |
402 | 415 | warn "Cannot determine perl version info from $_[0]\n"; |
416 | 429 | ([^\n]*) |
417 | 430 | /ixms) { |
418 | 431 | my $author = $1 || $2; |
419 | $author =~ s{E<lt>}{<}g; | |
420 | $author =~ s{E<gt>}{>}g; | |
432 | ||
433 | # XXX: ugly but should work anyway... | |
434 | if (eval "require Pod::Escapes; 1") { | |
435 | # Pod::Escapes has a mapping table. | |
436 | # It's in core of perl >= 5.9.3, and should be installed | |
437 | # as one of the Pod::Simple's prereqs, which is a prereq | |
438 | # of Pod::Text 3.x (see also below). | |
439 | $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } | |
440 | { | |
441 | defined $2 | |
442 | ? chr($2) | |
443 | : defined $Pod::Escapes::Name2character_number{$1} | |
444 | ? chr($Pod::Escapes::Name2character_number{$1}) | |
445 | : do { | |
446 | warn "Unknown escape: E<$1>"; | |
447 | "E<$1>"; | |
448 | }; | |
449 | }gex; | |
450 | } | |
451 | elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { | |
452 | # Pod::Text < 3.0 has yet another mapping table, | |
453 | # though the table name of 2.x and 1.x are different. | |
454 | # (1.x is in core of Perl < 5.6, 2.x is in core of | |
455 | # Perl < 5.9.3) | |
456 | my $mapping = ($Pod::Text::VERSION < 2) | |
457 | ? \%Pod::Text::HTML_Escapes | |
458 | : \%Pod::Text::ESCAPES; | |
459 | $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } | |
460 | { | |
461 | defined $2 | |
462 | ? chr($2) | |
463 | : defined $mapping->{$1} | |
464 | ? $mapping->{$1} | |
465 | : do { | |
466 | warn "Unknown escape: E<$1>"; | |
467 | "E<$1>"; | |
468 | }; | |
469 | }gex; | |
470 | } | |
471 | else { | |
472 | $author =~ s{E<lt>}{<}g; | |
473 | $author =~ s{E<gt>}{>}g; | |
474 | } | |
421 | 475 | $self->author($author); |
422 | 476 | } else { |
423 | 477 | warn "Cannot determine author info from $_[0]\n"; |
424 | 478 | } |
425 | 479 | } |
426 | 480 | |
481 | sub _extract_license { | |
482 | my $pod = shift; | |
483 | my $matched; | |
484 | return __extract_license( | |
485 | ($matched) = $pod =~ m/ | |
486 | (=head \d \s+ (?:licen[cs]e|licensing)\b.*?) | |
487 | (=head \d.*|=cut.*|)\z | |
488 | /ixms | |
489 | ) || __extract_license( | |
490 | ($matched) = $pod =~ m/ | |
491 | (=head \d \s+ (?:copyrights?|legal)\b.*?) | |
492 | (=head \d.*|=cut.*|)\z | |
493 | /ixms | |
494 | ); | |
495 | } | |
496 | ||
497 | sub __extract_license { | |
498 | my $license_text = shift or return; | |
499 | my @phrases = ( | |
500 | 'under the same (?:terms|license) as (?:perl|the perl programming language)' => 'perl', 1, | |
501 | 'under the terms of (?:perl|the perl programming language) itself' => 'perl', 1, | |
502 | 'Artistic and GPL' => 'perl', 1, | |
503 | 'GNU general public license' => 'gpl', 1, | |
504 | 'GNU public license' => 'gpl', 1, | |
505 | 'GNU lesser general public license' => 'lgpl', 1, | |
506 | 'GNU lesser public license' => 'lgpl', 1, | |
507 | 'GNU library general public license' => 'lgpl', 1, | |
508 | 'GNU library public license' => 'lgpl', 1, | |
509 | 'BSD license' => 'bsd', 1, | |
510 | 'Artistic license' => 'artistic', 1, | |
511 | 'GPL' => 'gpl', 1, | |
512 | 'LGPL' => 'lgpl', 1, | |
513 | 'BSD' => 'bsd', 1, | |
514 | 'Artistic' => 'artistic', 1, | |
515 | 'MIT' => 'mit', 1, | |
516 | 'proprietary' => 'proprietary', 0, | |
517 | ); | |
518 | while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { | |
519 | $pattern =~ s#\s+#\\s+#gs; | |
520 | if ( $license_text =~ /\b$pattern\b/i ) { | |
521 | return $license; | |
522 | } | |
523 | } | |
524 | } | |
525 | ||
427 | 526 | sub license_from { |
428 | 527 | my $self = shift; |
429 | if ( | |
430 | Module::Install::_read($_[0]) =~ m/ | |
431 | ( | |
432 | =head \d \s+ | |
433 | (?:licen[cs]e|licensing|copyright|legal)\b | |
434 | .*? | |
435 | ) | |
436 | (=head\\d.*|=cut.*|) | |
437 | \z | |
438 | /ixms ) { | |
439 | my $license_text = $1; | |
440 | my @phrases = ( | |
441 | 'under the same (?:terms|license) as (?:perl|the perl programming language) itself' => 'perl', 1, | |
442 | 'GNU general public license' => 'gpl', 1, | |
443 | 'GNU public license' => 'gpl', 1, | |
444 | 'GNU lesser general public license' => 'lgpl', 1, | |
445 | 'GNU lesser public license' => 'lgpl', 1, | |
446 | 'GNU library general public license' => 'lgpl', 1, | |
447 | 'GNU library public license' => 'lgpl', 1, | |
448 | 'BSD license' => 'bsd', 1, | |
449 | 'Artistic license' => 'artistic', 1, | |
450 | 'GPL' => 'gpl', 1, | |
451 | 'LGPL' => 'lgpl', 1, | |
452 | 'BSD' => 'bsd', 1, | |
453 | 'Artistic' => 'artistic', 1, | |
454 | 'MIT' => 'mit', 1, | |
455 | 'proprietary' => 'proprietary', 0, | |
456 | ); | |
457 | while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { | |
458 | $pattern =~ s{\s+}{\\s+}g; | |
459 | if ( $license_text =~ /\b$pattern\b/i ) { | |
460 | $self->license($license); | |
461 | return 1; | |
462 | } | |
463 | } | |
464 | } | |
465 | ||
466 | warn "Cannot determine license info from $_[0]\n"; | |
467 | return 'unknown'; | |
528 | if (my $license=_extract_license(Module::Install::_read($_[0]))) { | |
529 | $self->license($license); | |
530 | } else { | |
531 | warn "Cannot determine license info from $_[0]\n"; | |
532 | return 'unknown'; | |
533 | } | |
468 | 534 | } |
469 | 535 | |
470 | 536 | sub _extract_bugtracker { |
471 | my @links = $_[0] =~ m#L<(\Qhttp://rt.cpan.org/\E[^>]+)>#g; | |
537 | my @links = $_[0] =~ m#L<( | |
538 | \Qhttp://rt.cpan.org/\E[^>]+| | |
539 | \Qhttp://github.com/\E[\w_]+/[\w_]+/issues| | |
540 | \Qhttp://code.google.com/p/\E[\w_\-]+/issues/list | |
541 | )>#gx; | |
472 | 542 | my %links; |
473 | 543 | @links{@links}=(); |
474 | 544 | @links=keys %links; |
484 | 554 | return 0; |
485 | 555 | } |
486 | 556 | if ( @links > 1 ) { |
487 | warn "Found more than on rt.cpan.org link in $_[0]\n"; | |
557 | warn "Found more than one bugtracker link in $_[0]\n"; | |
488 | 558 | return 0; |
489 | 559 | } |
490 | 560 |
5 | 5 | |
6 | 6 | use vars qw{$VERSION @ISA $ISCORE}; |
7 | 7 | BEGIN { |
8 | $VERSION = '0.91'; | |
8 | $VERSION = '0.95'; | |
9 | 9 | @ISA = 'Module::Install::Base'; |
10 | 10 | $ISCORE = 1; |
11 | 11 | } |
5 | 5 | |
6 | 6 | use vars qw{$VERSION @ISA $ISCORE}; |
7 | 7 | BEGIN { |
8 | $VERSION = '0.91'; | |
8 | $VERSION = '0.95'; | |
9 | 9 | @ISA = 'Module::Install::Base'; |
10 | 10 | $ISCORE = 1; |
11 | 11 | } |
5 | 5 | |
6 | 6 | use vars qw{$VERSION @ISA $ISCORE}; |
7 | 7 | BEGIN { |
8 | $VERSION = '0.91';; | |
8 | $VERSION = '0.95';; | |
9 | 9 | @ISA = qw{Module::Install::Base}; |
10 | 10 | $ISCORE = 1; |
11 | 11 | } |
25 | 25 | |
26 | 26 | $self->check_nmake if $args{check_nmake}; |
27 | 27 | unless ( $self->makemaker_args->{PL_FILES} ) { |
28 | $self->makemaker_args( PL_FILES => {} ); | |
28 | # XXX: This still may be a bit over-defensive... | |
29 | unless ($self->makemaker(6.25)) { | |
30 | $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; | |
31 | } | |
29 | 32 | } |
30 | 33 | |
31 | 34 | # Until ExtUtils::MakeMaker support MYMETA.yml, make sure |
18 | 18 | |
19 | 19 | use 5.005; |
20 | 20 | use strict 'vars'; |
21 | use Cwd (); | |
22 | use File::Find (); | |
23 | use File::Path (); | |
24 | use FindBin; | |
21 | 25 | |
22 | 26 | use vars qw{$VERSION $MAIN}; |
23 | 27 | BEGIN { |
27 | 31 | # This is not enforced yet, but will be some time in the next few |
28 | 32 | # releases once we can make sure it won't clash with custom |
29 | 33 | # Module::Install extensions. |
30 | $VERSION = '0.91'; | |
34 | $VERSION = '0.95'; | |
31 | 35 | |
32 | 36 | # Storage for the pseudo-singleton |
33 | 37 | $MAIN = undef; |
37 | 41 | |
38 | 42 | } |
39 | 43 | |
40 | ||
41 | ||
42 | ||
43 | ||
44 | # Whether or not inc::Module::Install is actually loaded, the | |
45 | # $INC{inc/Module/Install.pm} is what will still get set as long as | |
46 | # the caller loaded module this in the documented manner. | |
47 | # If not set, the caller may NOT have loaded the bundled version, and thus | |
48 | # they may not have a MI version that works with the Makefile.PL. This would | |
49 | # result in false errors or unexpected behaviour. And we don't want that. | |
50 | my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; | |
51 | unless ( $INC{$file} ) { die <<"END_DIE" } | |
44 | sub import { | |
45 | my $class = shift; | |
46 | my $self = $class->new(@_); | |
47 | my $who = $self->_caller; | |
48 | ||
49 | #------------------------------------------------------------- | |
50 | # all of the following checks should be included in import(), | |
51 | # to allow "eval 'require Module::Install; 1' to test | |
52 | # installation of Module::Install. (RT #51267) | |
53 | #------------------------------------------------------------- | |
54 | ||
55 | # Whether or not inc::Module::Install is actually loaded, the | |
56 | # $INC{inc/Module/Install.pm} is what will still get set as long as | |
57 | # the caller loaded module this in the documented manner. | |
58 | # If not set, the caller may NOT have loaded the bundled version, and thus | |
59 | # they may not have a MI version that works with the Makefile.PL. This would | |
60 | # result in false errors or unexpected behaviour. And we don't want that. | |
61 | my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; | |
62 | unless ( $INC{$file} ) { die <<"END_DIE" } | |
52 | 63 | |
53 | 64 | Please invoke ${\__PACKAGE__} with: |
54 | 65 | |
60 | 71 | |
61 | 72 | END_DIE |
62 | 73 | |
63 | ||
64 | ||
65 | ||
66 | ||
67 | # If the script that is loading Module::Install is from the future, | |
68 | # then make will detect this and cause it to re-run over and over | |
69 | # again. This is bad. Rather than taking action to touch it (which | |
70 | # is unreliable on some platforms and requires write permissions) | |
71 | # for now we should catch this and refuse to run. | |
72 | if ( -f $0 ) { | |
73 | my $s = (stat($0))[9]; | |
74 | ||
75 | # If the modification time is only slightly in the future, | |
76 | # sleep briefly to remove the problem. | |
77 | my $a = $s - time; | |
78 | if ( $a > 0 and $a < 5 ) { sleep 5 } | |
79 | ||
80 | # Too far in the future, throw an error. | |
81 | my $t = time; | |
82 | if ( $s > $t ) { die <<"END_DIE" } | |
74 | # This reportedly fixes a rare Win32 UTC file time issue, but | |
75 | # as this is a non-cross-platform XS module not in the core, | |
76 | # we shouldn't really depend on it. See RT #24194 for detail. | |
77 | # (Also, this module only supports Perl 5.6 and above). | |
78 | eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; | |
79 | ||
80 | # If the script that is loading Module::Install is from the future, | |
81 | # then make will detect this and cause it to re-run over and over | |
82 | # again. This is bad. Rather than taking action to touch it (which | |
83 | # is unreliable on some platforms and requires write permissions) | |
84 | # for now we should catch this and refuse to run. | |
85 | if ( -f $0 ) { | |
86 | my $s = (stat($0))[9]; | |
87 | ||
88 | # If the modification time is only slightly in the future, | |
89 | # sleep briefly to remove the problem. | |
90 | my $a = $s - time; | |
91 | if ( $a > 0 and $a < 5 ) { sleep 5 } | |
92 | ||
93 | # Too far in the future, throw an error. | |
94 | my $t = time; | |
95 | if ( $s > $t ) { die <<"END_DIE" } | |
83 | 96 | |
84 | 97 | Your installer $0 has a modification time in the future ($s > $t). |
85 | 98 | |
88 | 101 | Please correct this, then run $0 again. |
89 | 102 | |
90 | 103 | END_DIE |
91 | } | |
92 | ||
93 | ||
94 | ||
95 | ||
96 | ||
97 | # Build.PL was formerly supported, but no longer is due to excessive | |
98 | # difficulty in implementing every single feature twice. | |
99 | if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } | |
104 | } | |
105 | ||
106 | ||
107 | # Build.PL was formerly supported, but no longer is due to excessive | |
108 | # difficulty in implementing every single feature twice. | |
109 | if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } | |
100 | 110 | |
101 | 111 | Module::Install no longer supports Build.PL. |
102 | 112 | |
106 | 116 | |
107 | 117 | END_DIE |
108 | 118 | |
109 | ||
110 | ||
111 | ||
112 | ||
113 | # To save some more typing in Module::Install installers, every... | |
114 | # use inc::Module::Install | |
115 | # ...also acts as an implicit use strict. | |
116 | $^H |= strict::bits(qw(refs subs vars)); | |
117 | ||
118 | ||
119 | ||
120 | ||
121 | ||
122 | use Cwd (); | |
123 | use File::Find (); | |
124 | use File::Path (); | |
125 | use FindBin; | |
119 | #------------------------------------------------------------- | |
120 | ||
121 | # To save some more typing in Module::Install installers, every... | |
122 | # use inc::Module::Install | |
123 | # ...also acts as an implicit use strict. | |
124 | $^H |= strict::bits(qw(refs subs vars)); | |
125 | ||
126 | #------------------------------------------------------------- | |
127 | ||
128 | unless ( -f $self->{file} ) { | |
129 | require "$self->{path}/$self->{dispatch}.pm"; | |
130 | File::Path::mkpath("$self->{prefix}/$self->{author}"); | |
131 | $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); | |
132 | $self->{admin}->init; | |
133 | @_ = ($class, _self => $self); | |
134 | goto &{"$self->{name}::import"}; | |
135 | } | |
136 | ||
137 | *{"${who}::AUTOLOAD"} = $self->autoload; | |
138 | $self->preload; | |
139 | ||
140 | # Unregister loader and worker packages so subdirs can use them again | |
141 | delete $INC{"$self->{file}"}; | |
142 | delete $INC{"$self->{path}.pm"}; | |
143 | ||
144 | # Save to the singleton | |
145 | $MAIN = $self; | |
146 | ||
147 | return 1; | |
148 | } | |
126 | 149 | |
127 | 150 | sub autoload { |
128 | 151 | my $self = shift; |
151 | 174 | }; |
152 | 175 | } |
153 | 176 | |
154 | sub import { | |
155 | my $class = shift; | |
156 | my $self = $class->new(@_); | |
157 | my $who = $self->_caller; | |
158 | ||
159 | unless ( -f $self->{file} ) { | |
160 | require "$self->{path}/$self->{dispatch}.pm"; | |
161 | File::Path::mkpath("$self->{prefix}/$self->{author}"); | |
162 | $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); | |
163 | $self->{admin}->init; | |
164 | @_ = ($class, _self => $self); | |
165 | goto &{"$self->{name}::import"}; | |
166 | } | |
167 | ||
168 | *{"${who}::AUTOLOAD"} = $self->autoload; | |
169 | $self->preload; | |
170 | ||
171 | # Unregister loader and worker packages so subdirs can use them again | |
172 | delete $INC{"$self->{file}"}; | |
173 | delete $INC{"$self->{path}.pm"}; | |
174 | ||
175 | # Save to the singleton | |
176 | $MAIN = $self; | |
177 | ||
178 | return 1; | |
179 | } | |
180 | ||
181 | 177 | sub preload { |
182 | 178 | my $self = shift; |
183 | 179 | unless ( $self->{extensions} ) { |
347 | 343 | return $call; |
348 | 344 | } |
349 | 345 | |
346 | # Done in evals to avoid confusing Perl::MinimumVersion | |
347 | eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; | |
350 | 348 | sub _read { |
351 | 349 | local *FH; |
352 | if ( $] >= 5.006 ) { | |
353 | open( FH, '<', $_[0] ) or die "open($_[0]): $!"; | |
354 | } else { | |
355 | open( FH, "< $_[0]" ) or die "open($_[0]): $!"; | |
356 | } | |
350 | open( FH, '<', $_[0] ) or die "open($_[0]): $!"; | |
357 | 351 | my $string = do { local $/; <FH> }; |
358 | 352 | close FH or die "close($_[0]): $!"; |
359 | 353 | return $string; |
360 | 354 | } |
355 | END_NEW | |
356 | sub _read { | |
357 | local *FH; | |
358 | open( FH, "< $_[0]" ) or die "open($_[0]): $!"; | |
359 | my $string = do { local $/; <FH> }; | |
360 | close FH or die "close($_[0]): $!"; | |
361 | return $string; | |
362 | } | |
363 | END_OLD | |
361 | 364 | |
362 | 365 | sub _readperl { |
363 | 366 | my $string = Module::Install::_read($_[0]); |
378 | 381 | return $string; |
379 | 382 | } |
380 | 383 | |
384 | # Done in evals to avoid confusing Perl::MinimumVersion | |
385 | eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; | |
381 | 386 | sub _write { |
382 | 387 | local *FH; |
383 | if ( $] >= 5.006 ) { | |
384 | open( FH, '>', $_[0] ) or die "open($_[0]): $!"; | |
385 | } else { | |
386 | open( FH, "> $_[0]" ) or die "open($_[0]): $!"; | |
387 | } | |
388 | open( FH, '>', $_[0] ) or die "open($_[0]): $!"; | |
388 | 389 | foreach ( 1 .. $#_ ) { |
389 | 390 | print FH $_[$_] or die "print($_[0]): $!"; |
390 | 391 | } |
391 | 392 | close FH or die "close($_[0]): $!"; |
392 | 393 | } |
394 | END_NEW | |
395 | sub _write { | |
396 | local *FH; | |
397 | open( FH, "> $_[0]" ) or die "open($_[0]): $!"; | |
398 | foreach ( 1 .. $#_ ) { | |
399 | print FH $_[$_] or die "print($_[0]): $!"; | |
400 | } | |
401 | close FH or die "close($_[0]): $!"; | |
402 | } | |
403 | END_OLD | |
393 | 404 | |
394 | 405 | # _version is for processing module versions (eg, 1.03_05) not |
395 | 406 | # Perl versions (eg, 5.8.1). |
426 | 437 | |
427 | 438 | 1; |
428 | 439 | |
429 | # Copyright 2008 - 2009 Adam Kennedy. | |
440 | # Copyright 2008 - 2010 Adam Kennedy. |
10 | 10 | TO BE COMPLETED |
11 | 11 | |
12 | 12 | =head1 METHODS |
13 | ||
14 | =head2 base | |
15 | ||
16 | my $namespace = CPANDB::Author->base; # Returns 'CPANDB' | |
17 | ||
18 | Normally you will only need to work directly with a table class, | |
19 | and only with one ORLite package. | |
20 | ||
21 | However, if for some reason you need to work with multiple ORLite packages | |
22 | at the same time without hardcoding the root namespace all the time, you | |
23 | can determine the root namespace from an object or table class with the | |
24 | C<base> method. | |
25 | ||
26 | =head2 table | |
27 | ||
28 | print CPANDB::Author->table; # Returns 'author' | |
29 | ||
30 | While you should not need the name of table for any simple operations, | |
31 | from time to time you may need it programatically. If you do need it, | |
32 | you can use the C<table> method to get the table name. | |
33 | ||
34 | =head2 load | |
35 | ||
36 | my $object = CPANDB::Author->load( $author ); | |
37 | ||
38 | If your table has single column primary key, a C<load> method will be | |
39 | generated in the class. If there is no primary key, the method is not | |
40 | created. | |
41 | ||
42 | The C<load> method provides a shortcut mechanism for fetching a single | |
43 | object based on the value of the primary key. However it should only | |
44 | be used for cases where your code trusts the record to already exists. | |
45 | ||
46 | It returns a C<CPANDB::Author> object, or throws an exception if the | |
47 | object does not exist. | |
13 | 48 | |
14 | 49 | =head2 select |
15 | 50 | |
35 | 70 | context. |
36 | 71 | |
37 | 72 | Throws an exception on error, typically directly from the L<DBI> layer. |
73 | ||
74 | =head2 iterate | |
75 | ||
76 | CPANDB::Author->iterate( sub { | |
77 | print $_->author . "\n"; | |
78 | } ); | |
79 | ||
80 | The C<iterate> method enables the processing of large tables one record at | |
81 | a time without loading having to them all into memory in advance. | |
82 | ||
83 | This plays well to the strength of SQLite, allowing it to do the work of | |
84 | loading arbitrarily large stream of records from disk while retaining the | |
85 | full power of Perl when processing the records. | |
86 | ||
87 | The last argument to C<iterate> must be a subroutine reference that will be | |
88 | called for each element in the list, with the object provided in the topic | |
89 | variable C<$_>. | |
90 | ||
91 | This makes the C<iterate> code fragment above functionally equivalent to the | |
92 | following, except with an O(1) memory cost instead of O(n). | |
93 | ||
94 | foreach ( CPANDB::Author->select ) { | |
95 | print $_->author . "\n"; | |
96 | } | |
97 | ||
98 | You can filter the list via SQL in the same way you can with C<select>. | |
99 | CPANDB::Author->iterate( | |
100 | 'order by ?', 'author', | |
101 | sub { | |
102 | print $_->author . "\n"; | |
103 | } | |
104 | ); | |
105 | ||
106 | You can also use it in raw form from the root namespace for better control. | |
107 | Using this form also allows for the use of arbitrarily complex queries, | |
108 | including joins. Instead of being objects, rows are provided as C<ARRAY> | |
109 | references when used in this form. | |
110 | CPANDB->iterate( | |
111 | 'select name from author order by author', | |
112 | sub { | |
113 | print $_->[0] . "\n"; | |
114 | } | |
115 | ); | |
38 | 116 | |
39 | 117 | =head2 count |
40 | 118 | |
64 | 142 | =head2 author |
65 | 143 | |
66 | 144 | if ( $object->author ) { |
67 | print "Object has been inserted\n"; | |
145 | print "Object has been inserted\\n"; | |
68 | 146 | } else { |
69 | print "Object has not been inserted\n"; | |
147 | print "Object has not been inserted\\n"; | |
70 | 148 | } |
71 | 149 | |
72 | 150 | Returns true, or throws an exception on error. |
93 | 171 | |
94 | 172 | =head1 COPYRIGHT |
95 | 173 | |
96 | Copyright 2009 Adam Kennedy. | |
174 | Copyright 2009 - 2010 Adam Kennedy. | |
97 | 175 | |
98 | 176 | This program is free software; you can redistribute |
99 | 177 | it and/or modify it under the same terms as Perl itself. |
10 | 10 | TO BE COMPLETED |
11 | 11 | |
12 | 12 | =head1 METHODS |
13 | ||
14 | =head2 base | |
15 | ||
16 | my $namespace = CPANDB::Dependency->base; # Returns 'CPANDB' | |
17 | ||
18 | Normally you will only need to work directly with a table class, | |
19 | and only with one ORLite package. | |
20 | ||
21 | However, if for some reason you need to work with multiple ORLite packages | |
22 | at the same time without hardcoding the root namespace all the time, you | |
23 | can determine the root namespace from an object or table class with the | |
24 | C<base> method. | |
25 | ||
26 | =head2 table | |
27 | ||
28 | print CPANDB::Dependency->table; # Returns 'dependency' | |
29 | ||
30 | While you should not need the name of table for any simple operations, | |
31 | from time to time you may need it programatically. If you do need it, | |
32 | you can use the C<table> method to get the table name. | |
33 | ||
34 | =head2 load | |
35 | ||
36 | my $object = CPANDB::Dependency->load( $distribution ); | |
37 | ||
38 | If your table has single column primary key, a C<load> method will be | |
39 | generated in the class. If there is no primary key, the method is not | |
40 | created. | |
41 | ||
42 | The C<load> method provides a shortcut mechanism for fetching a single | |
43 | object based on the value of the primary key. However it should only | |
44 | be used for cases where your code trusts the record to already exists. | |
45 | ||
46 | It returns a C<CPANDB::Dependency> object, or throws an exception if the | |
47 | object does not exist. | |
13 | 48 | |
14 | 49 | =head2 select |
15 | 50 | |
36 | 71 | |
37 | 72 | Throws an exception on error, typically directly from the L<DBI> layer. |
38 | 73 | |
74 | =head2 iterate | |
75 | ||
76 | CPANDB::Dependency->iterate( sub { | |
77 | print $_->distribution . "\n"; | |
78 | } ); | |
79 | ||
80 | The C<iterate> method enables the processing of large tables one record at | |
81 | a time without loading having to them all into memory in advance. | |
82 | ||
83 | This plays well to the strength of SQLite, allowing it to do the work of | |
84 | loading arbitrarily large stream of records from disk while retaining the | |
85 | full power of Perl when processing the records. | |
86 | ||
87 | The last argument to C<iterate> must be a subroutine reference that will be | |
88 | called for each element in the list, with the object provided in the topic | |
89 | variable C<$_>. | |
90 | ||
91 | This makes the C<iterate> code fragment above functionally equivalent to the | |
92 | following, except with an O(1) memory cost instead of O(n). | |
93 | ||
94 | foreach ( CPANDB::Dependency->select ) { | |
95 | print $_->distribution . "\n"; | |
96 | } | |
97 | ||
98 | You can filter the list via SQL in the same way you can with C<select>. | |
99 | CPANDB::Dependency->iterate( | |
100 | 'order by ?', 'distribution', | |
101 | sub { | |
102 | print $_->distribution . "\n"; | |
103 | } | |
104 | ); | |
105 | ||
106 | You can also use it in raw form from the root namespace for better control. | |
107 | Using this form also allows for the use of arbitrarily complex queries, | |
108 | including joins. Instead of being objects, rows are provided as C<ARRAY> | |
109 | references when used in this form. | |
110 | CPANDB->iterate( | |
111 | 'select name from dependency order by distribution', | |
112 | sub { | |
113 | print $_->[0] . "\n"; | |
114 | } | |
115 | ); | |
116 | ||
39 | 117 | =head2 count |
40 | 118 | |
41 | 119 | # How many objects are in the table |
64 | 142 | =head2 distribution |
65 | 143 | |
66 | 144 | if ( $object->distribution ) { |
67 | print "Object has been inserted\n"; | |
145 | print "Object has been inserted\\n"; | |
68 | 146 | } else { |
69 | print "Object has not been inserted\n"; | |
147 | print "Object has not been inserted\\n"; | |
70 | 148 | } |
71 | 149 | |
72 | 150 | Returns true, or throws an exception on error. |
73 | ||
74 | 151 | |
75 | 152 | REMAINING ACCESSORS TO BE COMPLETED |
76 | 153 | |
93 | 170 | FOREIGN KEY ( |
94 | 171 | distribution |
95 | 172 | ) |
96 | REFERENCES distribition ( | |
173 | REFERENCES distribution ( | |
97 | 174 | distribution |
98 | 175 | ) |
99 | 176 | , |
114 | 191 | |
115 | 192 | =head1 COPYRIGHT |
116 | 193 | |
117 | Copyright 2009 Adam Kennedy. | |
194 | Copyright 2009 - 2010 Adam Kennedy. | |
118 | 195 | |
119 | 196 | This program is free software; you can redistribute |
120 | 197 | it and/or modify it under the same terms as Perl itself. |
5 | 5 | use DateTime (); |
6 | 6 | use ORLite::Statistics; |
7 | 7 | |
8 | our $VERSION = '0.11'; | |
8 | our $VERSION = '0.13'; | |
9 | 9 | |
10 | 10 | my $today = DateTime->today( time_zone => 'UTC' ); |
11 | 11 | |
36 | 36 | $_[0]->age->in_units('months'); |
37 | 37 | } |
38 | 38 | |
39 | sub quadrant { | |
39 | sub quartile { | |
40 | 40 | my $self = shift; |
41 | 41 | |
42 | 42 | # Get the boundary dates |
43 | my @quadrant = ref($self)->_quadrant; | |
44 | ||
45 | # Find which quadrant we are in | |
43 | my @quartile = ref($self)->_quartile; | |
44 | ||
45 | # Find which quartile we are in | |
46 | 46 | my $uploaded = $self->uploaded; |
47 | if ( $uploaded gt $quadrant[0] ) { | |
47 | if ( $uploaded gt $quartile[0] ) { | |
48 | 48 | return 1; |
49 | } elsif ( $uploaded gt $quadrant[1] ) { | |
49 | } elsif ( $uploaded gt $quartile[1] ) { | |
50 | 50 | return 2; |
51 | } elsif ( $uploaded gt $quadrant[2] ) { | |
51 | } elsif ( $uploaded gt $quartile[2] ) { | |
52 | 52 | return 3; |
53 | 53 | } else { |
54 | 54 | return 4; |
57 | 57 | |
58 | 58 | my @QUADRANT = (); |
59 | 59 | |
60 | sub _quadrant { | |
60 | sub _quartile { | |
61 | 61 | return @QUADRANT if @QUADRANT; |
62 | 62 | |
63 | 63 | # Start with the total number of distributions |
66 | 66 | my $mod = $rows % 4; |
67 | 67 | my $range = ($rows - $mod) / 4; |
68 | 68 | |
69 | # Find the last row in each quadrant | |
69 | # Find the last row in each quartile | |
70 | 70 | foreach ( 1 .. 4 ) { |
71 | 71 | my $offset = ($range * $_) + $mod - 1; |
72 | 72 | |
80 | 80 | # Find the upload date for the resulting row |
81 | 81 | my @object = $class->select("order by uploaded desc limit 1 offset $offset"); |
82 | 82 | unless ( @object == 1 ) { |
83 | die("Failed to find edge of quadrant $_"); | |
83 | die("Failed to find edge of quartile $_"); | |
84 | 84 | } |
85 | 85 | |
86 | 86 | push @QUADRANT, $object[0]->uploaded; |
1 | 1 | |
2 | 2 | CPANDB::Distribution - CPANDB class for the distribution table |
3 | 3 | |
4 | =head1 SYNOPSIS | |
5 | ||
6 | TO BE COMPLETED | |
7 | ||
8 | 4 | =head1 DESCRIPTION |
9 | 5 | |
10 | TO BE COMPLETED | |
6 | B<CPANDB::Distribution> provides an object representation of a distribution | |
7 | in the CPAN. Because many CPAN websites are oriented around distributions, | |
8 | this class serves as one of the primary integration points for the various | |
9 | different CPAN databases providing information on popularity and testing data. | |
10 | ||
11 | Distributions are also the primary plane on which graph-aware algorithms are | |
12 | run, and on which metrics are calculated. | |
11 | 13 | |
12 | 14 | =head1 METHODS |
15 | ||
16 | =head2 base | |
17 | ||
18 | my $namespace = CPANDB::Distribution->base; # Returns 'CPANDB' | |
19 | ||
20 | Normally you will only need to work directly with a table class, | |
21 | and only with one ORLite package. | |
22 | ||
23 | However, if for some reason you need to work with multiple ORLite packages | |
24 | at the same time without hardcoding the root namespace all the time, you | |
25 | can determine the root namespace from an object or table class with the | |
26 | C<base> method. | |
27 | ||
28 | =head2 table | |
29 | ||
30 | print CPANDB::Distribution->table; # Returns 'distribution' | |
31 | ||
32 | While you should not need the name of table for any simple operations, | |
33 | from time to time you may need it programatically. If you do need it, | |
34 | you can use the C<table> method to get the table name. | |
35 | ||
36 | =head2 load | |
37 | ||
38 | my $object = CPANDB::Distribution->load( $distribution ); | |
39 | ||
40 | If your table has single column primary key, a C<load> method will be | |
41 | generated in the class. If there is no primary key, the method is not | |
42 | created. | |
43 | ||
44 | The C<load> method provides a shortcut mechanism for fetching a single | |
45 | object based on the value of the primary key. However it should only | |
46 | be used for cases where your code trusts the record to already exists. | |
47 | ||
48 | It returns a C<CPANDB::Distribution> object, or throws an exception if the | |
49 | object does not exist. | |
13 | 50 | |
14 | 51 | =head2 select |
15 | 52 | |
36 | 73 | |
37 | 74 | Throws an exception on error, typically directly from the L<DBI> layer. |
38 | 75 | |
76 | =head2 iterate | |
77 | ||
78 | CPANDB::Distribution->iterate( sub { | |
79 | print $_->distribution . "\n"; | |
80 | } ); | |
81 | ||
82 | The C<iterate> method enables the processing of large tables one record at | |
83 | a time without loading having to them all into memory in advance. | |
84 | ||
85 | This plays well to the strength of SQLite, allowing it to do the work of | |
86 | loading arbitrarily large stream of records from disk while retaining the | |
87 | full power of Perl when processing the records. | |
88 | ||
89 | The last argument to C<iterate> must be a subroutine reference that will be | |
90 | called for each element in the list, with the object provided in the topic | |
91 | variable C<$_>. | |
92 | ||
93 | This makes the C<iterate> code fragment above functionally equivalent to the | |
94 | following, except with an O(1) memory cost instead of O(n). | |
95 | ||
96 | foreach ( CPANDB::Distribution->select ) { | |
97 | print $_->distribution . "\n"; | |
98 | } | |
99 | ||
100 | You can filter the list via SQL in the same way you can with C<select>. | |
101 | CPANDB::Distribution->iterate( | |
102 | 'order by ?', 'distribution', | |
103 | sub { | |
104 | print $_->distribution . "\n"; | |
105 | } | |
106 | ); | |
107 | ||
108 | You can also use it in raw form from the root namespace for better control. | |
109 | Using this form also allows for the use of arbitrarily complex queries, | |
110 | including joins. Instead of being objects, rows are provided as C<ARRAY> | |
111 | references when used in this form. | |
112 | CPANDB->iterate( | |
113 | 'select name from distribution order by distribution', | |
114 | sub { | |
115 | print $_->[0] . "\n"; | |
116 | } | |
117 | ); | |
118 | ||
39 | 119 | =head2 count |
40 | 120 | |
41 | 121 | # How many objects are in the table |
59 | 139 | |
60 | 140 | Throws an exception on error, typically directly from the L<DBI> layer. |
61 | 141 | |
142 | =head2 uploaded_datetime | |
143 | ||
144 | For situations in which date math will be done, the C<uploaded_datetime> | |
145 | method can be used to access the date of the most decent release as a | |
146 | L<DateTime> object. | |
147 | ||
148 | Returns a L<DateTime> object with date attributes, without a time set, | |
149 | and set at the UTC timezone in the 'C' locale. | |
150 | ||
151 | =head2 age | |
152 | ||
153 | The B<age> method finds the age of a distribution in L<DateTime> terms, | |
154 | and where high age is considered a negative property. It is calculated as | |
155 | the time between the current day and the date of the last release of the | |
156 | distribution. | |
157 | ||
158 | Returns a L<DateTime::Duration> object, with maximum resolution at the 'day' | |
159 | level. | |
160 | ||
161 | =head2 age_months | |
162 | ||
163 | When expressing the age of a module in the CPAN, the most normal unit to use | |
164 | is the month. Releasing more than once a month is considered high pace for a | |
165 | CPAN distribution, while releasing every few months or even once per several | |
166 | months is fairly reasonable for mature modules. | |
167 | ||
168 | For situations when a single numeric value is desired to represent a | |
169 | distribution's age, the C<age_months> thus provides a direct calculation of | |
170 | this value. | |
171 | ||
172 | Returns the age in months as an integer, with a value of zero if the module | |
173 | has been released within the last month. | |
174 | ||
175 | =head2 quartile | |
176 | ||
177 | The C<quartile> method determines which statstical age quartile the | |
178 | distribution falls into, between 1 and 4. | |
179 | ||
180 | Quartile 1 represents "new" or "current" modules, which have seen | |
181 | a release in at least the last year. | |
182 | ||
183 | Distributions in the first quadrant are usually going to work and be up to | |
184 | date, as the author is likely to be present (for new modules) or maintains | |
185 | the module to a reasonable level of diligence (for older modules). | |
186 | ||
187 | Quartile 2 represents "mature" or "stale" modules, which have seen a release | |
188 | in the last several years, but not recently. | |
189 | ||
190 | Smaller distributions with high CPAN Testers PASS rates and low or no bug counts | |
191 | are often simply "mature" as they are essentially "finished" and don't need to | |
192 | be extended. These will often see a new release only every 2 or 3 years to fix | |
193 | trivial issues or match changes in some underlying dependency which has changed. | |
194 | ||
195 | Larger distributions with non-perfect CPAN Tester PASS rates (or those with high | |
196 | bug counts) can be considered to be "stale". However, their authors are still | |
197 | likely to be around. Contacting the author may result in new releases due to the | |
198 | your attention, or the author might be interested in handing off the module for | |
199 | maintenance. | |
200 | ||
201 | Quartile 3 represents "old" or "rotten" modules, which have not seen a release | |
202 | in the last several years. | |
203 | ||
204 | Modules with high number of other modules depending on them in this range may | |
205 | simply be "old" and suffering from benign neglect due to the author moving on to | |
206 | other careers, languages, or projects and not annointing a replacement | |
207 | ||
208 | They aren't actively broken, but nobody remains to maintain them and they may | |
209 | have crufty and hard to learn codebases. Due to entrenched workarounds for any | |
210 | bugs they have, they can also be risky to change. | |
211 | ||
212 | Modules without downstream dependencies in this zone are often "rotten", broken | |
213 | due to changes in the modules around them and abandoned by anything that used | |
214 | to depend on them. | |
215 | ||
216 | It can also be common to find modules in this range labelled as "DEPRECATED" in | |
217 | the abstract. | |
218 | ||
219 | Quartile 4 represents the garbage dump of the CPAN. These modules tend to | |
220 | largely be abandoned modules, ideas that failed dramatically, Acme:: joke | |
221 | modules that have never needed updated releases, or modules who have been | |
222 | replaced wholesale by updated core techniques or dramatically superior | |
223 | replacements. | |
224 | ||
225 | The oldest of these modules date from the age of Perl 4 and the earliest Perl 5. | |
226 | ||
227 | =head2 dependency_graph | |
228 | ||
229 | This method generates a L<Graph::Directed> object linking the distribution to | |
230 | all the other distributions that are needed by it to work, recursively. | |
231 | ||
232 | =head2 dependants_graph | |
233 | ||
234 | This method generates a L<Graph::Directed> object linking the distribution to | |
235 | all the other distributions that use the distribution, recursively. | |
236 | ||
237 | =head2 dependency_easy | |
238 | ||
239 | This method generates a L<Graph::Easy> object linking the distribution to | |
240 | all the other distributions that are needed by it to work, recursively. | |
241 | ||
242 | =head2 dependants_easy | |
243 | ||
244 | This method generates a L<Graph::Easy> object linking the distribution to | |
245 | all the other distributions that use the distribution, recursively. | |
246 | ||
247 | =head2 dependency_graphviz | |
248 | ||
249 | This method generates a L<Graphviz> object linking the distribution to | |
250 | all the other distributions that are needed by it to work, recursively. | |
251 | ||
252 | =head2 dependants_graphviz | |
253 | ||
254 | This method generates a L<Graphviz> object linking the distribution to | |
255 | all the other distributions that use the distribution, recursively. | |
256 | ||
257 | =head2 dependency_xgmml | |
258 | ||
259 | This method generates a L<Graph::XGMML> object linking the distribution to | |
260 | all the other distributions that are needed by it to work, recursively. | |
261 | ||
262 | =head2 dependants_xgmml | |
263 | ||
264 | This method generates a L<Graph::XGMML> object linking the distribution to | |
265 | all the other distributions that use the distribution, recursively. | |
266 | ||
62 | 267 | =head1 ACCESSORS |
63 | 268 | |
64 | 269 | =head2 distribution |
65 | 270 | |
66 | 271 | if ( $object->distribution ) { |
67 | print "Object has been inserted\n"; | |
272 | print "Object has been inserted\\n"; | |
68 | 273 | } else { |
69 | print "Object has not been inserted\n"; | |
274 | print "Object has not been inserted\\n"; | |
70 | 275 | } |
71 | 276 | |
72 | 277 | Returns true, or throws an exception on error. |
73 | ||
74 | 278 | |
75 | 279 | REMAINING ACCESSORS TO BE COMPLETED |
76 | 280 | |
112 | 316 | |
113 | 317 | =head1 COPYRIGHT |
114 | 318 | |
115 | Copyright 2009 Adam Kennedy. | |
319 | Copyright 2009 - 2010 Adam Kennedy. | |
116 | 320 | |
117 | 321 | This program is free software; you can redistribute |
118 | 322 | it and/or modify it under the same terms as Perl itself. |
10 | 10 | TO BE COMPLETED |
11 | 11 | |
12 | 12 | =head1 METHODS |
13 | ||
14 | =head2 base | |
15 | ||
16 | my $namespace = CPANDB::Module->base; # Returns 'CPANDB' | |
17 | ||
18 | Normally you will only need to work directly with a table class, | |
19 | and only with one ORLite package. | |
20 | ||
21 | However, if for some reason you need to work with multiple ORLite packages | |
22 | at the same time without hardcoding the root namespace all the time, you | |
23 | can determine the root namespace from an object or table class with the | |
24 | C<base> method. | |
25 | ||
26 | =head2 table | |
27 | ||
28 | print CPANDB::Module->table; # Returns 'module' | |
29 | ||
30 | While you should not need the name of table for any simple operations, | |
31 | from time to time you may need it programatically. If you do need it, | |
32 | you can use the C<table> method to get the table name. | |
33 | ||
34 | =head2 load | |
35 | ||
36 | my $object = CPANDB::Module->load( $module ); | |
37 | ||
38 | If your table has single column primary key, a C<load> method will be | |
39 | generated in the class. If there is no primary key, the method is not | |
40 | created. | |
41 | ||
42 | The C<load> method provides a shortcut mechanism for fetching a single | |
43 | object based on the value of the primary key. However it should only | |
44 | be used for cases where your code trusts the record to already exists. | |
45 | ||
46 | It returns a C<CPANDB::Module> object, or throws an exception if the | |
47 | object does not exist. | |
13 | 48 | |
14 | 49 | =head2 select |
15 | 50 | |
35 | 70 | context. |
36 | 71 | |
37 | 72 | Throws an exception on error, typically directly from the L<DBI> layer. |
73 | ||
74 | =head2 iterate | |
75 | ||
76 | CPANDB::Module->iterate( sub { | |
77 | print $_->module . "\n"; | |
78 | } ); | |
79 | ||
80 | The C<iterate> method enables the processing of large tables one record at | |
81 | a time without loading having to them all into memory in advance. | |
82 | ||
83 | This plays well to the strength of SQLite, allowing it to do the work of | |
84 | loading arbitrarily large stream of records from disk while retaining the | |
85 | full power of Perl when processing the records. | |
86 | ||
87 | The last argument to C<iterate> must be a subroutine reference that will be | |
88 | called for each element in the list, with the object provided in the topic | |
89 | variable C<$_>. | |
90 | ||
91 | This makes the C<iterate> code fragment above functionally equivalent to the | |
92 | following, except with an O(1) memory cost instead of O(n). | |
93 | ||
94 | foreach ( CPANDB::Module->select ) { | |
95 | print $_->module . "\n"; | |
96 | } | |
97 | ||
98 | You can filter the list via SQL in the same way you can with C<select>. | |
99 | CPANDB::Module->iterate( | |
100 | 'order by ?', 'module', | |
101 | sub { | |
102 | print $_->module . "\n"; | |
103 | } | |
104 | ); | |
105 | ||
106 | You can also use it in raw form from the root namespace for better control. | |
107 | Using this form also allows for the use of arbitrarily complex queries, | |
108 | including joins. Instead of being objects, rows are provided as C<ARRAY> | |
109 | references when used in this form. | |
110 | CPANDB->iterate( | |
111 | 'select name from module order by module', | |
112 | sub { | |
113 | print $_->[0] . "\n"; | |
114 | } | |
115 | ); | |
38 | 116 | |
39 | 117 | =head2 count |
40 | 118 | |
64 | 142 | =head2 module |
65 | 143 | |
66 | 144 | if ( $object->module ) { |
67 | print "Object has been inserted\n"; | |
145 | print "Object has been inserted\\n"; | |
68 | 146 | } else { |
69 | print "Object has not been inserted\n"; | |
147 | print "Object has not been inserted\\n"; | |
70 | 148 | } |
71 | 149 | |
72 | 150 | Returns true, or throws an exception on error. |
100 | 178 | |
101 | 179 | =head1 COPYRIGHT |
102 | 180 | |
103 | Copyright 2009 Adam Kennedy. | |
181 | Copyright 2009 - 2010 Adam Kennedy. | |
104 | 182 | |
105 | 183 | This program is free software; you can redistribute |
106 | 184 | it and/or modify it under the same terms as Perl itself. |
10 | 10 | TO BE COMPLETED |
11 | 11 | |
12 | 12 | =head1 METHODS |
13 | ||
14 | =head2 base | |
15 | ||
16 | my $namespace = CPANDB::Requires->base; # Returns 'CPANDB' | |
17 | ||
18 | Normally you will only need to work directly with a table class, | |
19 | and only with one ORLite package. | |
20 | ||
21 | However, if for some reason you need to work with multiple ORLite packages | |
22 | at the same time without hardcoding the root namespace all the time, you | |
23 | can determine the root namespace from an object or table class with the | |
24 | C<base> method. | |
25 | ||
26 | =head2 table | |
27 | ||
28 | print CPANDB::Requires->table; # Returns 'requires' | |
29 | ||
30 | While you should not need the name of table for any simple operations, | |
31 | from time to time you may need it programatically. If you do need it, | |
32 | you can use the C<table> method to get the table name. | |
33 | ||
34 | =head2 load | |
35 | ||
36 | my $object = CPANDB::Requires->load( $distribution ); | |
37 | ||
38 | If your table has single column primary key, a C<load> method will be | |
39 | generated in the class. If there is no primary key, the method is not | |
40 | created. | |
41 | ||
42 | The C<load> method provides a shortcut mechanism for fetching a single | |
43 | object based on the value of the primary key. However it should only | |
44 | be used for cases where your code trusts the record to already exists. | |
45 | ||
46 | It returns a C<CPANDB::Requires> object, or throws an exception if the | |
47 | object does not exist. | |
13 | 48 | |
14 | 49 | =head2 select |
15 | 50 | |
36 | 71 | |
37 | 72 | Throws an exception on error, typically directly from the L<DBI> layer. |
38 | 73 | |
74 | =head2 iterate | |
75 | ||
76 | CPANDB::Requires->iterate( sub { | |
77 | print $_->distribution . "\n"; | |
78 | } ); | |
79 | ||
80 | The C<iterate> method enables the processing of large tables one record at | |
81 | a time without loading having to them all into memory in advance. | |
82 | ||
83 | This plays well to the strength of SQLite, allowing it to do the work of | |
84 | loading arbitrarily large stream of records from disk while retaining the | |
85 | full power of Perl when processing the records. | |
86 | ||
87 | The last argument to C<iterate> must be a subroutine reference that will be | |
88 | called for each element in the list, with the object provided in the topic | |
89 | variable C<$_>. | |
90 | ||
91 | This makes the C<iterate> code fragment above functionally equivalent to the | |
92 | following, except with an O(1) memory cost instead of O(n). | |
93 | ||
94 | foreach ( CPANDB::Requires->select ) { | |
95 | print $_->distribution . "\n"; | |
96 | } | |
97 | ||
98 | You can filter the list via SQL in the same way you can with C<select>. | |
99 | CPANDB::Requires->iterate( | |
100 | 'order by ?', 'distribution', | |
101 | sub { | |
102 | print $_->distribution . "\n"; | |
103 | } | |
104 | ); | |
105 | ||
106 | You can also use it in raw form from the root namespace for better control. | |
107 | Using this form also allows for the use of arbitrarily complex queries, | |
108 | including joins. Instead of being objects, rows are provided as C<ARRAY> | |
109 | references when used in this form. | |
110 | CPANDB->iterate( | |
111 | 'select name from requires order by distribution', | |
112 | sub { | |
113 | print $_->[0] . "\n"; | |
114 | } | |
115 | ); | |
116 | ||
39 | 117 | =head2 count |
40 | 118 | |
41 | 119 | # How many objects are in the table |
64 | 142 | =head2 distribution |
65 | 143 | |
66 | 144 | if ( $object->distribution ) { |
67 | print "Object has been inserted\n"; | |
145 | print "Object has been inserted\\n"; | |
68 | 146 | } else { |
69 | print "Object has not been inserted\n"; | |
147 | print "Object has not been inserted\\n"; | |
70 | 148 | } |
71 | 149 | |
72 | 150 | Returns true, or throws an exception on error. |
114 | 192 | |
115 | 193 | =head1 COPYRIGHT |
116 | 194 | |
117 | Copyright 2009 Adam Kennedy. | |
195 | Copyright 2009 - 2010 Adam Kennedy. | |
118 | 196 | |
119 | 197 | This program is free software; you can redistribute |
120 | 198 | it and/or modify it under the same terms as Perl itself. |
7 | 7 | use ORLite::Mirror (); |
8 | 8 | use CPANDB::Distribution (); |
9 | 9 | |
10 | our $VERSION = '0.12'; | |
10 | our $VERSION = '0.13'; | |
11 | 11 | |
12 | 12 | sub import { |
13 | 13 | my $class = shift; |
16 | 16 | # Pass through any params from above |
17 | 17 | $params->{url} ||= 'http://svn.ali.as/db/cpandb.bz2'; |
18 | 18 | $params->{maxage} ||= 24 * 60 * 60; # One day |
19 | ||
20 | # Always turn on string eval debugging if Perl is new enough | |
21 | if ( $^V > 5.008008 ) { | |
22 | $^P = $^P | 0x800; | |
23 | } | |
19 | 24 | |
20 | 25 | # Prevent double-initialisation |
21 | 26 | $class->can('orlite') or |
1 | 1 | |
2 | 2 | CPANDB - An ORLite-based ORM Database API |
3 | 3 | |
4 | =head1 SYNOPSIS | |
5 | ||
6 | TO BE COMPLETED | |
7 | ||
8 | 4 | =head1 DESCRIPTION |
9 | 5 | |
10 | TO BE COMPLETED | |
6 | B<CPANDB> is an module for accessing CPAN metadata merged from many different | |
7 | CPAN websites into a single simple object model. | |
11 | 8 | |
12 | 9 | =head1 METHODS |
13 | 10 | |
55 | 52 | The C<dbh> method returns a L<DBI::db> object, or throws an exception on |
56 | 53 | error. |
57 | 54 | |
55 | =head2 begin | |
56 | ||
57 | CPANDB->begin; | |
58 | ||
59 | The C<begin> method indicates the start of a transaction. | |
60 | ||
61 | In the same way that ORLite allows only a single connection, likewise | |
62 | it allows only a single application-wide transaction. | |
63 | ||
64 | No indication is given as to whether you are currently in a transaction | |
65 | or not, all code should be written neutrally so that it works either way | |
66 | or doesn't need to care. | |
67 | ||
68 | Returns true or throws an exception on error. | |
69 | ||
70 | =head2 rollback | |
71 | ||
72 | The C<rollback> method rolls back the current transaction. If called outside | |
73 | of a current transaction, it is accepted and treated as a null operation. | |
74 | ||
75 | Once the rollback has been completed, the database connection falls back | |
76 | into auto-commit state. If you wish to immediately start another | |
77 | transaction, you will need to issue a separate -E<gt>begin call. | |
78 | ||
79 | If a transaction exists at END-time as the process exits, it will be | |
80 | automatically rolled back. | |
81 | ||
82 | Returns true or throws an exception on error. | |
83 | ||
84 | =head2 do | |
85 | ||
86 | CPANDB->do( | |
87 | 'insert into table ( foo, bar ) values ( ?, ? )', {}, | |
88 | \$foo_value, | |
89 | \$bar_value, | |
90 | ); | |
91 | ||
92 | The C<do> method is a direct wrapper around the equivalent L<DBI> method, | |
93 | but applied to the appropriate locally-provided connection or transaction. | |
94 | ||
95 | It takes the same parameters and has the same return values and error | |
96 | behaviour. | |
97 | ||
58 | 98 | =head2 selectall_arrayref |
59 | 99 | |
60 | 100 | The C<selectall_arrayref> method is a direct wrapper around the equivalent |
130 | 170 | The C<pragma> method provides a convenient method for fetching a pragma |
131 | 171 | for a datase. See the SQLite documentation for more details. |
132 | 172 | |
173 | =head2 distribution | |
174 | ||
175 | my $dist = CPANDB->distribution('Config-Tiny'); | |
176 | ||
177 | The C<distribution> method is a convenient shortcut for direct access to | |
178 | the L<CPANDB::Distribution> object for a single named distribution. | |
179 | ||
180 | =head2 graph | |
181 | ||
182 | my $everything = CPANDB->graph; | |
183 | ||
184 | Originally created as a proof of concept for L<Graph> integration, the C<graph> | |
185 | method creates a single giant L<Graph::Directed> object representing the | |
186 | dependency structure of the entire CPAN at a distribution-to-distribution level. | |
187 | ||
188 | The graphing features of L<CPANDB> are considered optional. To use this method | |
189 | you will need to install L<Graph::Directed> yourself, and set up a dependency | |
190 | in any code that uses L<Graph> features. | |
191 | ||
133 | 192 | =head1 SUPPORT |
134 | 193 | |
135 | CPANDB is based on L<ORLite> 1.23. | |
136 | ||
137 | Documentation created by L<ORLite::Pod> 0.06. | |
194 | CPANDB is based on L<ORLite> $ORLite::VERSION. | |
195 | ||
196 | Documentation created by L<ORLite::Pod> $ORLite::Pod::VERSION. | |
138 | 197 | |
139 | 198 | For general support please see the support section of the main |
140 | 199 | project documentation. |
141 | 200 | |
142 | 201 | =head1 COPYRIGHT |
143 | 202 | |
144 | Copyright 2009 Adam Kennedy. | |
203 | Copyright 2009 - 2010 Adam Kennedy. | |
145 | 204 | |
146 | 205 | This program is free software; you can redistribute |
147 | 206 | it and/or modify it under the same terms as Perl itself. |
14 | 14 | Version 0.12 |
15 | 15 | |
16 | 16 | =cut |
17 | our $VERSION = '0.12'; | |
17 | our $VERSION = '0.13'; | |
18 | 18 | |
19 | 19 | use CPANDB (); |
20 | 20 |
109 | 109 | is( scalar(@latest), 10, 'Found the 10 latest results' ); |
110 | 110 | foreach ( @latest ) { |
111 | 111 | isa_ok( $_, 'CPANDB::Distribution' ); |
112 | is( $_->quadrant, 1, $_->distribution . ' is in quadrant 1' ); | |
112 | is( $_->quartile, 1, $_->distribution . ' is in quartile 1' ); | |
113 | 113 | } |
114 | 114 | } |
115 | 115 |
0 | #!/usr/bin/perl | |
1 | ||
2 | # Test that our META.yml file matches the current specification. | |
3 | ||
4 | use strict; | |
5 | BEGIN { | |
6 | $| = 1; | |
7 | $^W = 1; | |
8 | } | |
9 | ||
10 | my $MODULE = 'Test::CPAN::Meta 0.12'; | |
11 | ||
12 | # Don't run tests for installs | |
13 | use Test::More; | |
14 | unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { | |
15 | plan( skip_all => "Author tests not required for installation" ); | |
16 | } | |
17 | ||
18 | # Load the testing module | |
19 | eval "use $MODULE"; | |
20 | if ( $@ ) { | |
21 | $ENV{RELEASE_TESTING} | |
22 | ? die( "Failed to load required release-testing module $MODULE" ) | |
23 | : plan( skip_all => "$MODULE not available for testing" ); | |
24 | } | |
25 | ||
26 | meta_yaml_ok(); |
0 | #!/usr/bin/perl | |
1 | ||
2 | # Test that the syntax of our POD documentation is valid | |
3 | ||
4 | use strict; | |
5 | BEGIN { | |
6 | $| = 1; | |
7 | $^W = 1; | |
8 | } | |
9 | ||
10 | my @MODULES = ( | |
11 | 'Pod::Simple 3.07', | |
12 | 'Test::Pod 1.26', | |
13 | ); | |
14 | ||
15 | # Don't run tests for installs | |
16 | use Test::More; | |
17 | unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { | |
18 | plan( skip_all => "Author tests not required for installation" ); | |
19 | } | |
20 | ||
21 | # Load the testing modules | |
22 | foreach my $MODULE ( @MODULES ) { | |
23 | eval "use $MODULE"; | |
24 | if ( $@ ) { | |
25 | $ENV{RELEASE_TESTING} | |
26 | ? die( "Failed to load required release-testing module $MODULE" ) | |
27 | : plan( skip_all => "$MODULE not available for testing" ); | |
28 | } | |
29 | } | |
30 | ||
31 | all_pod_files_ok(); |
0 | #!/usr/bin/perl | |
1 | ||
2 | # Test that our declared minimum Perl version matches our syntax | |
3 | ||
4 | use strict; | |
5 | BEGIN { | |
6 | $| = 1; | |
7 | $^W = 1; | |
8 | } | |
9 | ||
10 | my @MODULES = ( | |
11 | 'Perl::MinimumVersion 1.20', | |
12 | 'Test::MinimumVersion 0.008', | |
13 | ); | |
14 | ||
15 | # Don't run tests for installs | |
16 | use Test::More; | |
17 | unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { | |
18 | plan( skip_all => "Author tests not required for installation" ); | |
19 | } | |
20 | ||
21 | # Load the testing modules | |
22 | foreach my $MODULE ( @MODULES ) { | |
23 | eval "use $MODULE"; | |
24 | if ( $@ ) { | |
25 | $ENV{RELEASE_TESTING} | |
26 | ? die( "Failed to load required release-testing module $MODULE" ) | |
27 | : plan( skip_all => "$MODULE not available for testing" ); | |
28 | } | |
29 | } | |
30 | ||
31 | all_minimum_version_from_metayml_ok(); |
0 | #!/usr/bin/perl | |
1 | ||
2 | # Test that our META.yml file matches the current specification. | |
3 | ||
4 | use strict; | |
5 | BEGIN { | |
6 | $| = 1; | |
7 | $^W = 1; | |
8 | } | |
9 | ||
10 | my $MODULE = 'Test::CPAN::Meta 0.12'; | |
11 | ||
12 | # Don't run tests for installs | |
13 | use Test::More; | |
14 | unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { | |
15 | plan( skip_all => "Author tests not required for installation" ); | |
16 | } | |
17 | ||
18 | # Load the testing module | |
19 | eval "use $MODULE"; | |
20 | if ( $@ ) { | |
21 | $ENV{RELEASE_TESTING} | |
22 | ? die( "Failed to load required release-testing module $MODULE" ) | |
23 | : plan( skip_all => "$MODULE not available for testing" ); | |
24 | } | |
25 | ||
26 | meta_yaml_ok(); |
0 | #!/usr/bin/perl | |
1 | ||
2 | # Test that our declared minimum Perl version matches our syntax | |
3 | ||
4 | use strict; | |
5 | BEGIN { | |
6 | $| = 1; | |
7 | $^W = 1; | |
8 | } | |
9 | ||
10 | my @MODULES = ( | |
11 | 'Perl::MinimumVersion 1.20', | |
12 | 'Test::MinimumVersion 0.008', | |
13 | ); | |
14 | ||
15 | # Don't run tests for installs | |
16 | use Test::More; | |
17 | unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { | |
18 | plan( skip_all => "Author tests not required for installation" ); | |
19 | } | |
20 | ||
21 | # Load the testing modules | |
22 | foreach my $MODULE ( @MODULES ) { | |
23 | eval "use $MODULE"; | |
24 | if ( $@ ) { | |
25 | $ENV{RELEASE_TESTING} | |
26 | ? die( "Failed to load required release-testing module $MODULE" ) | |
27 | : plan( skip_all => "$MODULE not available for testing" ); | |
28 | } | |
29 | } | |
30 | ||
31 | all_minimum_version_from_metayml_ok(); |
0 | #!/usr/bin/perl | |
1 | ||
2 | # Test that the syntax of our POD documentation is valid | |
3 | ||
4 | use strict; | |
5 | BEGIN { | |
6 | $| = 1; | |
7 | $^W = 1; | |
8 | } | |
9 | ||
10 | my @MODULES = ( | |
11 | 'Pod::Simple 3.07', | |
12 | 'Test::Pod 1.26', | |
13 | ); | |
14 | ||
15 | # Don't run tests for installs | |
16 | use Test::More; | |
17 | unless ( $ENV{AUTOMATED_TESTING} or $ENV{RELEASE_TESTING} ) { | |
18 | plan( skip_all => "Author tests not required for installation" ); | |
19 | } | |
20 | ||
21 | # Load the testing modules | |
22 | foreach my $MODULE ( @MODULES ) { | |
23 | eval "use $MODULE"; | |
24 | if ( $@ ) { | |
25 | $ENV{RELEASE_TESTING} | |
26 | ? die( "Failed to load required release-testing module $MODULE" ) | |
27 | : plan( skip_all => "$MODULE not available for testing" ); | |
28 | } | |
29 | } | |
30 | ||
31 | all_pod_files_ok(); |