Catalyst-Model-DBIC-Schema-0.66/000755 000766 000024 00000000000 14461412703 016450 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/inc/000755 000766 000024 00000000000 14461412703 017221 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/README000644 000766 000024 00000040150 14461412670 017333 0ustar00gknopstaff000000 000000 NAME Catalyst::Model::DBIC::Schema - DBIx::Class::Schema Model Class SYNOPSIS First, prepare your database schema using DBIx::Class, see Catalyst::Helper::Model::DBIC::Schema for how to generate a DBIx::Class::Schema from your database using the Helper script, and DBIx::Class::Schema::Loader::Base. A typical usage of the helper script would be: script/myapp_create.pl model FilmDB DBIC::Schema MyApp::Schema::FilmDB \ create=static dbi:mysql:filmdb dbusername dbpass \ quote_names=1 If you are unfamiliar with DBIx::Class, see DBIx::Class::Manual::Intro first. These examples assume that you already have a schema called "MyApp::Schema::FilmDB", which defines some Result classes for tables in "MyApp::Schema::FilmDB::Result::Actor" and "MyApp::Schema::FilmDB::Result::Film". Either created by the helper script (as shown above) or manually. The helper also creates a Model in "lib/MyApp/Model/FilmDB.pm", if you already have a schema you can create just the Model using: script/myapp_create.pl model FilmDB DBIC::Schema MyApp::Schema::FilmDB dbi:mysql:filmdb dbusername dbpass The connect_info is optional and will be hardcoded into the Model if provided. It's better to configure it in your Catalyst config file, which will also override any hardcoded config, see "connect_info" for examples. Now you have a working Model which accesses your separate DBIC Schema. This can be used/accessed in the normal Catalyst manner, via "$c->model()": my $db_model = $c->model('FilmDB'); # a Catalyst::Model my $dbic = $c->model('FilmDB')->schema; # the actual DBIC object There is also a shortcut, which returns a DBIx::Class::ResultSet directly, instead of a Catalyst::Model: my $rs = $c->model('FilmDB::Actor'); See DBIx::Class::ResultSet to find out more about which methods can be called on ResultSets. You can also define your own ResultSet methods to encapsulate the database/business logic of your applications. These go into, for example, "lib/MyApp/Schema/FilmDB/ResultSet/Actor.pm". The class must inherit from DBIx::Class::ResultSet and is automatically loaded. Then call your methods like any other DBIx::Class::ResultSet method: $c->model('FilmDB::Actor')->SAG_members Some examples: # to access schema methods directly: $c->model('FilmDB')->schema->source(...); # to access the source object, resultset, and class: $c->model('FilmDB')->source(...); $c->model('FilmDB')->resultset(...); $c->model('FilmDB')->class(...); # For resultsets, there's an even quicker shortcut: $c->model('FilmDB::Actor') # is the same as $c->model('FilmDB')->resultset('Actor') # To get the composed schema for making new connections: my $newconn = $c->model('FilmDB')->composed_schema->connect(...); # Or the same thing via a convenience shortcut: my $newconn = $c->model('FilmDB')->connect(...); # or, if your schema works on different storage drivers: my $newconn = $c->model('FilmDB')->composed_schema->clone(); $newconn->storage_type('::LDAP'); $newconn->connection(...); # and again, a convenience shortcut my $newconn = $c->model('FilmDB')->clone(); $newconn->storage_type('::LDAP'); $newconn->connection(...); To set up authentication, see "Setting up DBIC authentication" below. DESCRIPTION This is a Catalyst Model for DBIx::Class::Schema-based Models. See the documentation for Catalyst::Helper::Model::DBIC::Schema for information on generating these Models via Helper scripts. When your Catalyst app starts up, a thin Model layer is created as an interface to your DBIC Schema. It should be clearly noted that the model object returned by "$c->model('FilmDB')" is NOT itself a DBIC schema or resultset object, but merely a wrapper proving methods to access the underlying schema. In addition to this model class, a shortcut class is generated for each source in the schema, allowing easy and direct access to a resultset of the corresponding type. These generated classes are even thinner than the model class, providing no public methods but simply hooking into Catalyst's model() accessor via the ACCEPT_CONTEXT mechanism. The complete contents of each generated class is roughly equivalent to the following: package MyApp::Model::FilmDB::Actor sub ACCEPT_CONTEXT { my ($self, $c) = @_; $c->model('FilmDB')->resultset('Actor'); } In short, there are three techniques available for obtaining a DBIC resultset object: # the long way my $rs = $c->model('FilmDB')->schema->resultset('Actor'); # using the shortcut method on the model object my $rs = $c->model('FilmDB')->resultset('Actor'); # using the generated class directly my $rs = $c->model('FilmDB::Actor'); In order to add methods to a DBIC resultset, you cannot simply add them to the source (row, table) definition class; you must define a separate custom resultset class. This is just a matter of making a "lib/MyApp/Schema/ResultSet/Actor.pm" class that inherits from DBIx::Class::ResultSet, if you are using "load_namespaces" in DBIx::Class::Schema, the default for helper script generated schemas. See "Predefined searches" in DBIx::Class::Manual::Cookbook for information on definining your own DBIx::Class::ResultSet classes for use with "load_classes" in DBIx::Class::Schema, the old default. CONFIG PARAMETERS schema_class This is the classname of your DBIx::Class::Schema Schema. It needs to be findable in @INC, but it does not need to be inside the "Catalyst::Model::" namespace. This parameter is required. connect_info This is a hashref or arrayref of connection parameters, which are specific to your "storage_type" (see your storage type documentation for more details). If you only need one parameter (e.g. the DSN), you can just pass a string. This is not required if "schema_class" already has connection information defined inside itself (which isn't highly recommended, but can be done.) For DBIx::Class::Storage::DBI, which is the only supported "storage_type" in DBIx::Class at the time of this writing, the parameters are your dsn, username, password, and connect options hashref. See "connect_info" in DBIx::Class::Storage::DBI for a detailed explanation of the arguments supported. Examples: connect_info => { dsn => 'dbi:Pg:dbname=mypgdb', user => 'postgres', password => '' } connect_info => { dsn => 'dbi:SQLite:dbname=foo.db', on_connect_do => [ 'PRAGMA synchronous = OFF', ] } connect_info => { dsn => 'dbi:Pg:dbname=mypgdb', user => 'postgres', password => '', pg_enable_utf8 => 1, on_connect_do => [ 'some SQL statement', 'another SQL statement', ], } Or using Config::General: schema_class MyApp::Schema::FilmDB traits Caching dsn dbi:Pg:dbname=mypgdb user postgres password "" auto_savepoint 1 quote_names 1 on_connect_do some SQL statement on_connect_do another SQL statement user_defined_schema_accessor foo or schema_class MyApp::Schema::FilmDB connect_info dbi:SQLite:dbname=foo.db Or using YAML: Model::MyDB: schema_class: MyDB traits: Caching connect_info: dsn: dbi:Oracle:mydb user: mtfnpy password: mypass LongReadLen: 1000000 LongTruncOk: 1 on_connect_call: 'datetime_setup' quote_names: 1 The old arrayref style with hashrefs for DBI then DBIx::Class options is also supported: connect_info => [ 'dbi:Pg:dbname=mypgdb', 'postgres', '', { pg_enable_utf8 => 1, }, { auto_savepoint => 1, on_connect_do => [ 'some SQL statement', 'another SQL statement', ], } ] traits Array of Traits to apply to the instance. Traits are Moose::Roles. They are relative to the "MyApp::TraitFor::Model::DBIC::Schema::", then the "Catalyst::TraitFor::Model::DBIC::Schema::" namespaces, unless prefixed with "+" in which case they are taken to be a fully qualified name. E.g.: traits Caching traits +MyApp::TraitFor::Model::Foo A new instance is created at application time, so any consumed required attributes, coercions and modifiers will work. Traits are applied at "COMPONENT" in Catalyst::Component time using CatalystX::Component::Traits. "ref $self" will be an anon class if any traits are applied, "$self->_original_class_name" will be the original class. When writing a Trait, interesting points to modify are "BUILD", "setup" and "ACCEPT_CONTEXT". Traits that come with the distribution: Catalyst::TraitFor::Model::DBIC::Schema::Caching Catalyst::TraitFor::Model::DBIC::Schema::Replicated Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy Catalyst::TraitFor::Model::DBIC::Schema::PerRequestSchema compose_namespaces This model calls "compose_namespace" in DBIx::Class::Schema by default to install classes into the model namespaces. You can turn that off by setting this attribute to false. Default is true. install_model_shortcuts If you don't want shortcut models so you can do e.g. "$c->model('DB::Book')" set this attribute to false, Default is true. storage_type Allows the use of a different "storage_type" than what is set in your "schema_class" (which in turn defaults to "::DBI" if not set in current DBIx::Class). Completely optional, and probably unnecessary for most people until other storage backends become available for DBIx::Class. ATTRIBUTES The keys you pass in the model configuration are available as attributes. Other attributes available: connect_info Your connect_info args normalized to hashref form (with dsn/user/password.) See "connect_info" in DBIx::Class::Storage::DBI for more info on the hashref form of "connect_info". model_name The model name Catalyst uses to resolve this model, the part after "::Model::" or "::M::" in your class name. E.g. if your class name is "MyApp::Model::DB" the "model_name" will be "DB". _default_cursor_class What to reset your "cursor_class" in DBIx::Class::Storage::DBI to if a custom one doesn't work out. Defaults to DBIx::Class::Storage::DBI::Cursor. ATTRIBUTES FROM MooseX::Traits::Pluggable _original_class_name The class name of your model before any "traits" are applied. E.g. "MyApp::Model::DB". _traits Unresolved arrayref of traits passed in the config. _resolved_traits Traits you used resolved to full class names. CONFIGURING YOUR SCHEMA AND RESULTSETS See the documentation for Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy for instructions on how to pass config values from your Catalyst config to your DBIx::Class::Schema and/or DBIx::Class::ResultSet classes. METHODS new Instantiates the Model based on the above-documented ->config parameters. The only required parameter is "schema_class". "connect_info" is required in the case that "schema_class" does not already have connection information defined for it. schema Accessor which returns the connected schema being used by the this model. There are direct shortcuts on the model class itself for schema->resultset, schema->source, and schema->class. composed_schema Accessor which returns the composed schema, which has no connection info, which was used in constructing the "schema". Useful for creating new connections based on the same schema/model. There are direct shortcuts from the model object for composed_schema->clone and composed_schema->connect If "compose_namespaces" is not true, "composed_schema" is equivalent to "$model->schema_class->clone". clone Shortcut for ->composed_schema->clone connect Shortcut for ->composed_schema->connect source Shortcut for ->schema->source class Shortcut for ->schema->class resultset Shortcut for ->schema->resultset txn_do Shortcut for ->schema->txn_do txn_scope_guard Shortcut for ->schema->txn_scope_guard storage Provides an accessor for the connected schema's storage object. See DBIx::Class::Storage and DBIx::Class::Storage::DBI. setup Called at "BUILD" time before configuration, but after "connect_info" is set. To do something after configuuration use "after BUILD =>". Receives a hashref of args passed to "BUILD". ACCEPT_CONTEXT Point of extension for doing things at "$c->model" time with context, returns the model instance, see "ACCEPT_CONTEXT" in Catalyst::Manual::Intro for more information. ENVIRONMENT CMDS_NO_SOURCES Set this variable if you will be using schemas with no sources (Result classes) to disable the warning. The warning is there because having no Result classes is usually a mistake. Setting up DBIC authentication You can set this up with Catalyst::Authentication::Store::DBIx::Class in MyApp.pm: package MyApp; use Catalyst qw/... Authentication .../; ... __PACKAGE__->config('Plugin::Authentication' => { default_realm => 'members', members => { credential => { class => 'Password', password_field => 'password', password_type => 'hashed' password_hash_type => 'SHA-256' }, store => { class => 'DBIx::Class', user_model => 'DB::User', role_relation => 'roles', role_field => 'rolename', } } }); METHOD PROXYING The automatic proxying to the underlying DBIx::Class::Schema has been removed as of version 0.34, to enable this feature add "SchemaProxy" to "traits". See Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy. SEE ALSO General Catalyst Stuff: Catalyst::Manual, Catalyst::Test, Catalyst::Request, Catalyst::Response, Catalyst::Helper, Catalyst, Stuff related to DBIC and this Model style: DBIx::Class, DBIx::Class::Schema, DBIx::Class::Schema::Loader, Catalyst::Helper::Model::DBIC::Schema, CatalystX::Component::Traits, MooseX::Traits::Pluggable Traits: Catalyst::TraitFor::Model::DBIC::Schema::Caching, Catalyst::TraitFor::Model::DBIC::Schema::Replicated, Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy, Catalyst::TraitFor::Model::DBIC::Schema::PerRequestSchema, Catalyst::TraitFor::Model::DBIC::Schema::QueryLog AUTHOR Brandon L Black "blblack at gmail.com" CONTRIBUTORS caelum: Rafael Kitover "rkitover at cpan.org" dandv: Dan Dascalescu "dandv at cpan.org" bluefeet: Aran Deltac "bluefeet@cpan.org" t0m: Tomas Doran "bobtfish@bobtfish.net" osfameron: "osfameron@cpan.org" ozum: Ozum Eldogan "ozum@ozum.net" Pavel I. Shaydo "zwon@trinitum.org" SineSwiper: Brendan Byrd COPYRIGHT Copyright (c) 2006 - 2010 the Catalyst::Model::DBIC::Schema "AUTHOR" and "CONTRIBUTORS" as listed above. LICENSE This program is free software. You can redistribute it and/or modify it under the same terms as Perl itself. Catalyst-Model-DBIC-Schema-0.66/PaxHeader/Changes000644 000766 000024 00000000210 14461412361 021705 xustar00gknopstaff000000 000000 30 mtime=1690703089.973061614 57 LIBARCHIVE.xattr.com.apple.provenance=AQAAq1dlpUhBqgg 49 SCHILY.xattr.com.apple.provenance=«We„HAȘ Catalyst-Model-DBIC-Schema-0.66/Changes000644 000766 000024 00000023453 14461412361 017752 0ustar00gknopstaff000000 000000 Revision history for Perl extension Catalyst::Model::DBIC::Schema 0.66 2023-07-30 07:45:00 - fix Makefile.PL to work properly in newer perls without . in @INC - update repository link in metadata - fix version requirement in test module - fix link in Pod - work around hack in Catalyst-Runtime 5.90080 0.65 2014-08-04 11:00:00 - Make compose_namespaces and install model shortcuts optional 0.64 2014-07-22 23:00:00 - Fix Replicated trait that got busted when someone assumed Module::Runtime was a drop in replacement for Class::MOP::load_class 0.63 2014-05-05 22:56:43 - Make MooseX::MarkAsMethods a hard prerequisite (RT#94923) - Fix t/08helper.t with Data::Dumper >= 2.151 (RT#94599) 0.62 2014-01-06 12:32:27 - Don't ship MYMETA.* files (RT#91808) - Stop using deprecated Class::MOP::load_module 0.61 2013-06-19 12:48:34 - Fix test failure caused by hash randomisation in perl 5.17 (RT#82917) 0.60 2012-06-12 16:27:00 - Add per_request_schema hook to PerRequestSchema trait and docs - Additional paranoia in types as it's possible for loading code to clobber $_ 0.59 2011-11-01 11:20:46 - update helper deps for new loader 0.58 2011-10-25 19:19:43 - remove ->make_immutable from the PerRequestSchema trait 0.57 2011-10-22 16:01:45 - add POD for PerRequestSchema trait 0.56 2011-10-22 15:34:59 - add PerRequestSchema trait (t0m) 0.55 Fri Sep 16 08:55:53 UTC 2011 - add DBD::SQLite to test_requires (RT#70357) 0.54 Fri Aug 5 11:29:00 EDT 2011 - Changed t/08helper.t to skip if required features are not installed. - tweaked the Makefile.PL to support these changes 0.53 Wed Aug 3 03:45:07 UTC 2011 - check loader args after connect_info against loader methods and remove them from connect_info 0.52 Thu Jul 28 22:07:38 UTC 2011 - fix a bug in loader args reading after connect_info (skip structs) 0.51 Wed Jul 27 20:57:47 UTC 2011 - warn when helper finds no tables - accept loader args after connect_info 0.50 Fri May 20 22:45:07 UTC 2011 - change repository link to the new git repo - get t/05testapp.t to run on Win32 0.49 Wed May 11 06:03:50 UTC 2011 - make sure storage_type class is loaded before ->isa check in Replicated trait (RT#65791) - fix regex stringification test for perl 5.14 (RT#68098) - update connect_info POD (RT#66010) 0.48 Thu Dec 9 21:08:33 UTC 2010 - fix usage of Try::Tiny in helper 0.47 Wed Dec 8 22:21:06 UTC 2010 - fix loader version check 0.46 Wed Dec 8 13:35:28 UTC 2010 - make use_moose detection more robust 0.45 Wed Dec 8 12:05:58 UTC 2010 - fix bug where non-result files were picked up for Moose check 0.44 Tue Dec 7 03:50:48 UTC 2010 - do not upgrade non-Moose schemas to use_moose=1 (RT#60558) - added col_collision_map => 'column_%s' as default loader option (will take effect on release of loader 0.07003) 0.43 Sun Jul 25 01:00:34 UTC 2010 - add dep for MooseX::NonMoose for the use_moose=1 option 0.42 Sat Jul 24 23:14:27 UTC 2010 - add use_moose=1 to loader options by default for create=static 0.41 Wed Apr 28 08:42:13 EDT 2010 - allow configuring ResultSets using the SchemaProxy trait 0.40 Wed Feb 3 23:12:16 EST 2010 - fix Replicated trait deps 0.39 Mon Feb 1 10:08:51 EST 2010 - better 'on_connect_do' parsing in Helper 0.38 Fri Jan 15 06:41:24 EST 2010 - re-add the 'storage' proxy method 0.37 Thu Jan 14 10:20:43 EST 2010 - support single replicant hashref from config 0.36 Thu Jan 14 09:21:10 EST 2010 - upgrading a schema to use_namespaces=1 will also turn on components=InflateColumn::DateTime (the default.) 0.35 Sun Dec 27 04:50:53 EST 2009 - forgot to edit Changes on last upload 0.34 Sun Dec 27 03:49:34 EST 2009 - move schema proxying into SchemaProxy trait which is off by default 0.33 Sat Dec 26 08:04:49 EST 2009 - fix test failure in 05testapp.t when env var not set (RT#53101) 0.32 Wed Dec 23 01:22:06 EST 2009 - Move documentation on setting up authentication into its own section for clarity. - Other misc documentation enhancements to make the docs more clear about the important things to know. - Convert Authentication Plugin configuration example to new style. - Support Coderefs in loader options for helper (patch from Ozum Eldogan ozum@ozum.net) 0.31 Sun Oct 18 18:50:00 BST 2009 - update for copyright info 0.30 Sun Oct 18 01:35:36 EDT 2009 - change no sources error to a warning (with a way to turn it off) - write connect_info to Model without a create= option as well 0.29 Mon Sep 7 15:31:29 EDT 2009 - support for coderef connect_info's 0.28 Thu Aug 27 08:14:05 EDT 2009 - autobox issues in dep chain, bump CX::Component::Traits dep (caelum) 0.27 Wed Aug 26 09:09:44 EDT 2009 - remove autobox usage due to reports of strange errors (caelum) - make schema a delegate for model, config too (caelum) 0.26 Wed Jul 29 16:16:09 PDT 2009 - fix loading connect_info from schema-defined connection (bluefeet, RT 48084) - detect wrong case for "dbi:" DSN part in DBIC helper (caelum) - Fix missing dep on Catalyst::Helper that made tests fail (wintrmute, RT 47449) 0.25 Fri Jun 19 08:35:38 PDT 2009 - fix dep on Tie::IxHash that made tests fail - add more attributes to ::Replicated trait - fixed infinte loop in helper if SQLite connect_info has only a DSN (dandv, RT #47101) 0.24 Tue Jun 16 06:18:58 PDT 2009 - Add tests for issues with Class::C3 which are caused to applications which use new Catalyst but old DBIC, and have use Class::C3 in the MyApp class (t0m) - die on empty schema - create=dynamic deprecation warning - helper passes loader opts to dynamic schemas - conversion to Moose - cursor caching support (via Catalyst::TraitFor::Model::DBIC::Schema::Caching) - ::Storage::Replicated support (via ::Replicated trait) - switch to hashref connect_info for DBIC 8100 - better helper option parsing, with support for more options - more tests 0.23 Sun Mar 8 20:30:02 GMT 2009 - Kill a couple of warnings (one due to MRO::Compat) 0.22 Tue Mar 3 15:54:19 UTC 2009 - Fix oddly formatted error message. - Doc patch to clarify generated classes - Switch to use_namespaces and InflateColumn::DateTime for create=static by default, with backcompat - Switch to MRO::Compat from NEXT - Add support for extra Schema::Loader options such as db_schema and components 0.21 Fri Aug 22 00:26:05 UTC 2008 - doc fix (RT #31848) - connection_info can be just the DSN instead of an arrayref 0.20 Wed May 23, 2007 - Fix for rt.cpan.org #22426 - Switch to Module::Install - Assorted small pod and cleanliness fixes - Some requirements bumped to the latest maint releases of the same major feature release 0.18 Tue Aug 8 04:34:42 UTC 2006 - Version bump for public release, no functional change 0.17_01 Thu Jul 27 01:06:13 UTC 2006 - Updated for DBIC 0.07 0.16 Thu Jul 6 13:28:45 UTC 2006 - Bugfix for create=static and connect_info coderef snippets - Be more verbose when connection_info is not set. 0.15 Tue Jun 6 01:33:57 UTC 2006 - Fixed a serious bug in create=static usage - Re-arranged output generation so that the more likely failure to generate Schemas via create= will cause the helper to abort before generating the Model class itself 0.14 Mon Jun 5 23:34:35 UTC 2006 - Helpers merged, helper syntax changed - Everything updated for Schema::Loader 0.03001 support, including what amounts to using Loader in one-shot mode to generate a manual Schema with matching Model. - fixed stupid typo in docs 0.13 Wed Apr 26 2006 - noted support via mailing lists 0.12 Tue Apr 25 2006 - SYNOPSIS improved substantially to help newbies get started 0.11 Sun Mar 26 17:22:31 UTC 2006 - Removed on_connect_do config setting (it was only out in public for 4 days...). - Support for on_connect_do and sql_maker options as part of connect_info 0.10 Wed Mar 22 07:06:02 UTC 2006 - Added on_connect_do config setting - Added convenience method for ->schema->storage from paulm 0.08 Tue Feb 28 00:04:16 UTC 2006 - Bumped D::C::Schema::Loader recommendation to 0.02003 (should have been done last release) - Removed the ->require stuff added in 0.07, it doesn't do what it is supposed to do. For now, users can layer at the Schema::Loader level rather than at Model. 0.07 Sun Feb 19 21:50:18 UTC 2006 - bugfix for ::SchemaLoader::Foo password argument, and switch to connect_info argument of new Schema::Loader - Added ->require for source classes, so that you can layer in lib/MyApp/Model/Foo/Bar.pm on top of the generated MyApp::Model::Foo::Bar. 0.06 Sat Feb 18 19:05:17 UTC 2006 - Fix simple pod-related bug introduced in last rev - Added optional test that uses the helpers 0.05 Fri Feb 17 20:52:21 UTC 2006 - Stop showing the template pod in pod tools and cpan, per Gavin's email. - Bump DBIx::Class pre-req to 0.05006, to prevent likely but subtle issues under mod_perl engines. 0.04 Mon Feb 13 04:22:49 UTC 2006 - First public release Catalyst-Model-DBIC-Schema-0.66/MANIFEST000644 000766 000024 00000002176 14461412673 017615 0ustar00gknopstaff000000 000000 .gitignore Changes inc/Module/AutoInstall.pm inc/Module/Install.pm inc/Module/Install/AutoInstall.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/Catalyst/Helper/Model/DBIC/Schema.pm lib/Catalyst/Model/DBIC/Schema.pm lib/Catalyst/Model/DBIC/Schema/Types.pm lib/Catalyst/TraitFor/Model/DBIC/Schema/Caching.pm lib/Catalyst/TraitFor/Model/DBIC/Schema/PerRequestSchema.pm lib/Catalyst/TraitFor/Model/DBIC/Schema/Replicated.pm lib/Catalyst/TraitFor/Model/DBIC/Schema/SchemaProxy.pm Makefile.PL MANIFEST This list of files META.yml README t/01use.t t/02pod.t t/05testapp.t t/06c3_issues.t t/07connect_info.t t/08helper.t t/09schema_options.t t/10literal_sql_through_accessor.t t/lib/AnotherSchemaClass.pm t/lib/AnotherSchemaClass/Result/User.pm t/lib/AnotherSchemaClass/ResultSet/User.pm t/lib/ASchemaClass.pm t/lib/ASchemaClass/User.pm t/lib/TestAppC3Fail.pm t/lib/TestAppC3Fail/Model/DB.pm t/lib/TestAppC3Fail/Schema/DB.pm t/lib/TestAppC3Fail/Schema/DB/User.pm Catalyst-Model-DBIC-Schema-0.66/t/000755 000766 000024 00000000000 14461412703 016713 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/META.yml000644 000766 000024 00000002352 14461412670 017726 0ustar00gknopstaff000000 000000 --- abstract: 'DBIx::Class::Schema Model Class' author: - 'Brandon L Black C' build_requires: DBD::SQLite: 0 ExtUtils::MakeMaker: 6.59 Storable: 0 Test::Exception: 0 Test::More: '0.94' Test::Requires: 0 configure_requires: ExtUtils::MakeMaker: 6.59 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.21' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Catalyst-Model-DBIC-Schema no_index: directory: - inc - t requires: Carp::Clan: 0 Catalyst::Component::InstancePerContext: 0 Catalyst::Devel: '1.0' Catalyst::Runtime: '5.80005' CatalystX::Component::Traits: '0.14' DBIx::Class: '0.08114' DBIx::Class::Cursor::Cached: 0 DBIx::Class::Schema::Loader: '0.04005' Hash::Merge: 0 List::MoreUtils: 0 Module::Runtime: '0.012' Moose: '1.12' MooseX::MarkAsMethods: '0.13' MooseX::NonMoose: '0.16' MooseX::Types: 0 MooseX::Types::LoadableClass: 0.009 Tie::IxHash: 0 Try::Tiny: 0 namespace::autoclean: 0.09 namespace::clean: 0 perl: 5.8.1 resources: license: http://dev.perl.org/licenses/ repository: https://github.com/perl-catalyst/Catalyst-Model-DBIC-Schema.git version: '0.66' Catalyst-Model-DBIC-Schema-0.66/.gitignore000644 000766 000024 00000000203 14461407424 020437 0ustar00gknopstaff000000 000000 META.yml MYMETA.json MYMETA.yml Makefile README blib/ inc/ MANIFEST MANIFEST.bak pm_to_blib Catalyst-Model-DBIC-Schema-* *~ .#* *# Catalyst-Model-DBIC-Schema-0.66/lib/000755 000766 000024 00000000000 14461412703 017216 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/PaxHeader/Makefile.PL000644 000766 000024 00000000210 14461411171 022362 xustar00gknopstaff000000 000000 30 mtime=1690702457.256913088 57 LIBARCHIVE.xattr.com.apple.provenance=AQAAq1dlpUhBqgg 49 SCHILY.xattr.com.apple.provenance=«We„HAȘ Catalyst-Model-DBIC-Schema-0.66/Makefile.PL000644 000766 000024 00000003027 14461411171 020422 0ustar00gknopstaff000000 000000 use lib '.'; use inc::Module::Install 0.91; name 'Catalyst-Model-DBIC-Schema'; perl_version 5.008001; all_from 'lib/Catalyst/Model/DBIC/Schema.pm'; requires 'DBIx::Class' => '0.08114'; requires 'Catalyst::Runtime' => '5.80005'; requires 'CatalystX::Component::Traits' => '0.14'; requires 'Moose' => '1.12'; requires 'MooseX::MarkAsMethods' => '0.13'; requires 'MooseX::Types'; requires 'MooseX::Types::LoadableClass' => 0.009; requires 'Module::Runtime' => '0.012'; requires 'namespace::autoclean' => 0.09; requires 'Carp::Clan'; requires 'List::MoreUtils'; requires 'Tie::IxHash'; requires 'Try::Tiny'; requires 'Catalyst::Component::InstancePerContext'; test_requires 'Test::More' => '0.94'; test_requires 'Test::Exception'; test_requires 'Storable'; test_requires 'Test::Requires'; test_requires 'DBD::SQLite'; feature 'Catalyst::Helper support', -default => 0, 'Catalyst::Devel' => '1.0', 'DBIx::Class::Schema::Loader' => '0.04005', 'MooseX::NonMoose' => '0.16', ; feature 'Caching support', -default => 0, 'DBIx::Class::Cursor::Cached' => 0; feature 'Replication support', -default => 0, 'namespace::clean' => 0, 'Hash::Merge' => 0; if(-e 'MANIFEST.SKIP') { system("pod2text lib/Catalyst/Model/DBIC/Schema.pm > README"); } realclean_files 'README'; auto_provides; auto_install; resources repository => 'https://github.com/perl-catalyst/Catalyst-Model-DBIC-Schema.git'; WriteAll; Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/000755 000766 000024 00000000000 14461412703 021002 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Helper/000755 000766 000024 00000000000 14461412703 022221 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/000755 000766 000024 00000000000 14461412703 022534 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Model/000755 000766 000024 00000000000 14461412703 022042 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Model/DBIC/000755 000766 000024 00000000000 14461412703 022543 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Model/DBIC/PaxHeader/Schema.pm000644 000766 000024 00000000210 14461412230 026236 xustar00gknopstaff000000 000000 30 mtime=1690703000.508535087 57 LIBARCHIVE.xattr.com.apple.provenance=AQAAq1dlpUhBqgg 49 SCHILY.xattr.com.apple.provenance=«We„HAȘ Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Model/DBIC/Schema.pm000644 000766 000024 00000050114 14461412230 024275 0ustar00gknopstaff000000 000000 package Catalyst::Model::DBIC::Schema; use Moose; use mro 'c3'; extends 'Catalyst::Model'; with 'CatalystX::Component::Traits'; our $VERSION = '0.66'; $VERSION =~ tr/_//d; use namespace::autoclean; use Carp::Clan '^Catalyst::Model::DBIC::Schema'; use Data::Dumper; use DBIx::Class (); use Module::Runtime qw/use_module/; use Catalyst::Model::DBIC::Schema::Types qw/ConnectInfo SchemaClass Schema/; use MooseX::Types::Moose qw/Str Bool/; use MooseX::Types::LoadableClass qw/LoadableClass/; =head1 NAME Catalyst::Model::DBIC::Schema - DBIx::Class::Schema Model Class =head1 SYNOPSIS First, prepare your database schema using L, see L for how to generate a L from your database using the Helper script, and L. A typical usage of the helper script would be: script/myapp_create.pl model FilmDB DBIC::Schema MyApp::Schema::FilmDB \ create=static dbi:mysql:filmdb dbusername dbpass \ quote_names=1 If you are unfamiliar with L, see L first. These examples assume that you already have a schema called C, which defines some Result classes for tables in C and C. Either created by the helper script (as shown above) or manually. The helper also creates a Model in C, if you already have a schema you can create just the Model using: script/myapp_create.pl model FilmDB DBIC::Schema MyApp::Schema::FilmDB dbi:mysql:filmdb dbusername dbpass The connect_info is optional and will be hardcoded into the Model if provided. It's better to configure it in your L config file, which will also override any hardcoded config, see L for examples. Now you have a working Model which accesses your separate DBIC Schema. This can be used/accessed in the normal Catalyst manner, via C<< $c->model() >>: my $db_model = $c->model('FilmDB'); # a Catalyst::Model my $dbic = $c->model('FilmDB')->schema; # the actual DBIC object There is also a shortcut, which returns a L directly, instead of a L: my $rs = $c->model('FilmDB::Actor'); See L to find out more about which methods can be called on ResultSets. You can also define your own ResultSet methods to encapsulate the database/business logic of your applications. These go into, for example, C. The class must inherit from L and is automatically loaded. Then call your methods like any other L method: $c->model('FilmDB::Actor')->SAG_members =head2 Some examples: # to access schema methods directly: $c->model('FilmDB')->schema->source(...); # to access the source object, resultset, and class: $c->model('FilmDB')->source(...); $c->model('FilmDB')->resultset(...); $c->model('FilmDB')->class(...); # For resultsets, there's an even quicker shortcut: $c->model('FilmDB::Actor') # is the same as $c->model('FilmDB')->resultset('Actor') # To get the composed schema for making new connections: my $newconn = $c->model('FilmDB')->composed_schema->connect(...); # Or the same thing via a convenience shortcut: my $newconn = $c->model('FilmDB')->connect(...); # or, if your schema works on different storage drivers: my $newconn = $c->model('FilmDB')->composed_schema->clone(); $newconn->storage_type('::LDAP'); $newconn->connection(...); # and again, a convenience shortcut my $newconn = $c->model('FilmDB')->clone(); $newconn->storage_type('::LDAP'); $newconn->connection(...); To set up authentication, see L below. =head1 DESCRIPTION This is a Catalyst Model for L-based Models. See the documentation for L for information on generating these Models via Helper scripts. When your Catalyst app starts up, a thin Model layer is created as an interface to your DBIC Schema. It should be clearly noted that the model object returned by C<< $c->model('FilmDB') >> is NOT itself a DBIC schema or resultset object, but merely a wrapper proving L to access the underlying schema. In addition to this model class, a shortcut class is generated for each source in the schema, allowing easy and direct access to a resultset of the corresponding type. These generated classes are even thinner than the model class, providing no public methods but simply hooking into Catalyst's model() accessor via the L mechanism. The complete contents of each generated class is roughly equivalent to the following: package MyApp::Model::FilmDB::Actor sub ACCEPT_CONTEXT { my ($self, $c) = @_; $c->model('FilmDB')->resultset('Actor'); } In short, there are three techniques available for obtaining a DBIC resultset object: # the long way my $rs = $c->model('FilmDB')->schema->resultset('Actor'); # using the shortcut method on the model object my $rs = $c->model('FilmDB')->resultset('Actor'); # using the generated class directly my $rs = $c->model('FilmDB::Actor'); In order to add methods to a DBIC resultset, you cannot simply add them to the source (row, table) definition class; you must define a separate custom resultset class. This is just a matter of making a C class that inherits from L, if you are using L, the default for helper script generated schemas. See L for information on definining your own L classes for use with L, the old default. =head1 CONFIG PARAMETERS =head2 schema_class This is the classname of your L Schema. It needs to be findable in C<@INC>, but it does not need to be inside the C namespace. This parameter is required. =head2 connect_info This is a hashref or arrayref of connection parameters, which are specific to your C (see your storage type documentation for more details). If you only need one parameter (e.g. the DSN), you can just pass a string. This is not required if C already has connection information defined inside itself (which isn't highly recommended, but can be done.) For L, which is the only supported C in L at the time of this writing, the parameters are your dsn, username, password, and connect options hashref. See L for a detailed explanation of the arguments supported. Examples: connect_info => { dsn => 'dbi:Pg:dbname=mypgdb', user => 'postgres', password => '' } connect_info => { dsn => 'dbi:SQLite:dbname=foo.db', on_connect_do => [ 'PRAGMA synchronous = OFF', ] } connect_info => { dsn => 'dbi:Pg:dbname=mypgdb', user => 'postgres', password => '', pg_enable_utf8 => 1, on_connect_do => [ 'some SQL statement', 'another SQL statement', ], } Or using L: schema_class MyApp::Schema::FilmDB traits Caching dsn dbi:Pg:dbname=mypgdb user postgres password "" auto_savepoint 1 quote_names 1 on_connect_do some SQL statement on_connect_do another SQL statement user_defined_schema_accessor foo or schema_class MyApp::Schema::FilmDB connect_info dbi:SQLite:dbname=foo.db Or using L: Model::MyDB: schema_class: MyDB traits: Caching connect_info: dsn: dbi:Oracle:mydb user: mtfnpy password: mypass LongReadLen: 1000000 LongTruncOk: 1 on_connect_call: 'datetime_setup' quote_names: 1 The old arrayref style with hashrefs for L then L options is also supported: connect_info => [ 'dbi:Pg:dbname=mypgdb', 'postgres', '', { pg_enable_utf8 => 1, }, { auto_savepoint => 1, on_connect_do => [ 'some SQL statement', 'another SQL statement', ], } ] =head2 traits Array of Traits to apply to the instance. Traits are Ls. They are relative to the C<< MyApp::TraitFor::Model::DBIC::Schema:: >>, then the C<< Catalyst::TraitFor::Model::DBIC::Schema:: >> namespaces, unless prefixed with C<+> in which case they are taken to be a fully qualified name. E.g.: traits Caching traits +MyApp::TraitFor::Model::Foo A new instance is created at application time, so any consumed required attributes, coercions and modifiers will work. Traits are applied at L time using L. C will be an anon class if any traits are applied, C<< $self->_original_class_name >> will be the original class. When writing a Trait, interesting points to modify are C, L and L. Traits that come with the distribution: =over 4 =item L =item L =item L =item L =back =head2 compose_namespaces This model calls L by default to install classes into the model namespaces. You can turn that off by setting this attribute to false. Default is true. =head2 install_model_shortcuts If you don't want shortcut models so you can do e.g. C<< $c->model('DB::Book') >> set this attribute to false, Default is true. =head2 storage_type Allows the use of a different C than what is set in your C (which in turn defaults to C<::DBI> if not set in current L). Completely optional, and probably unnecessary for most people until other storage backends become available for L. =head1 ATTRIBUTES The keys you pass in the model configuration are available as attributes. Other attributes available: =head2 connect_info Your connect_info args normalized to hashref form (with dsn/user/password.) See L for more info on the hashref form of L. =head2 model_name The model name L uses to resolve this model, the part after C<::Model::> or C<::M::> in your class name. E.g. if your class name is C the L will be C. =head2 _default_cursor_class What to reset your L to if a custom one doesn't work out. Defaults to L. =head1 ATTRIBUTES FROM L =head2 _original_class_name The class name of your model before any L are applied. E.g. C. =head2 _traits Unresolved arrayref of traits passed in the config. =head2 _resolved_traits Traits you used resolved to full class names. =head1 CONFIGURING YOUR SCHEMA AND RESULTSETS See the documentation for L for instructions on how to pass config values from your L config to your L and/or L classes. =head1 METHODS =head2 new Instantiates the Model based on the above-documented ->config parameters. The only required parameter is C. C is required in the case that C does not already have connection information defined for it. =head2 schema Accessor which returns the connected schema being used by the this model. There are direct shortcuts on the model class itself for schema->resultset, schema->source, and schema->class. =head2 composed_schema Accessor which returns the composed schema, which has no connection info, which was used in constructing the L. Useful for creating new connections based on the same schema/model. There are direct shortcuts from the model object for composed_schema->clone and composed_schema->connect If L is not true, L is equivalent to C<< $model->schema_class->clone >>. =head2 clone Shortcut for ->composed_schema->clone =head2 connect Shortcut for ->composed_schema->connect =head2 source Shortcut for ->schema->source =head2 class Shortcut for ->schema->class =head2 resultset Shortcut for ->schema->resultset =head2 txn_do Shortcut for ->schema->txn_do =head2 txn_scope_guard Shortcut for ->schema->txn_scope_guard =head2 storage Provides an accessor for the connected schema's storage object. See L and L. =cut has schema_class => ( is => 'ro', isa => SchemaClass, required => 1 ); has compose_namespaces => (is => 'ro', isa => Bool, default => 1 ); has install_model_shortcuts => (is => 'ro', isa => Bool, default => 1 ); has storage_type => (is => 'rw', isa => Str); has connect_info => (is => 'rw', isa => ConnectInfo, coerce => 1); has model_name => ( is => 'ro', isa => Str, required => 1, lazy_build => 1, ); has _default_cursor_class => ( is => 'ro', isa => LoadableClass, default => 'DBIx::Class::Storage::DBI::Cursor', ); has schema => (is => 'rw', isa => Schema); my $app_class; before COMPONENT => sub { $app_class = ref $_[1] || $_[1]; }; sub app_class { $app_class } sub BUILD { my ($self, $args) = @_; my $class = $self->_original_class_name; my $schema_class = $self->schema_class; if( !$self->connect_info ) { if($schema_class->storage && $schema_class->storage->connect_info) { $self->connect_info($schema_class->storage->connect_info); } else { die "Either ->config->{connect_info} must be defined for $class" . " or $schema_class must have connect info defined on it." . " Here's what we got:\n" . Dumper($args); } } if (exists $self->connect_info->{cursor_class}) { eval { use_module($self->connect_info->{cursor_class}) } or croak "invalid connect_info: Cannot load your cursor_class" . " ".$self->connect_info->{cursor_class}.": $@"; } $self->setup($args); my $is_installed = defined $self->composed_schema; if (not $is_installed) { $self->composed_schema($self->compose_namespaces ? $schema_class->compose_namespace($class) : $schema_class->clone ); } $self->schema($self->composed_schema->clone) unless $self->schema; $self->schema->storage_type($self->storage_type) if $self->storage_type; $self->schema->connection($self->connect_info); if ((not $is_installed) && $self->install_model_shortcuts) { $self->_install_rs_models; } } sub clone { shift->composed_schema->clone(@_); } sub connect { shift->composed_schema->connect(@_); } # some proxy methods, see also SchemaProxy sub resultset { shift->schema->resultset(@_); } sub txn_do { shift->schema->txn_do(@_); } sub txn_scope_guard { shift->schema->txn_scope_guard(@_); } sub storage { shift->schema->storage(@_); } =head2 setup Called at C time before configuration, but after L is set. To do something after configuuration use C<< after BUILD => >>. Receives a hashref of args passed to C. =cut sub setup { 1 } =head2 ACCEPT_CONTEXT Point of extension for doing things at C<< $c->model >> time with context, returns the model instance, see L for more information. =cut sub ACCEPT_CONTEXT { shift } sub _install_rs_models { my $self = shift; my $class = $self->_original_class_name; no strict 'refs'; my @sources = $self->schema->sources; unless (@sources) { warn <<'EOF' unless $ENV{CMDS_NO_SOURCES}; ******************************* WARNING *************************************** * No sources found (did you forget to define your tables?) * * * * To turn off this warning, set the CMDS_NO_SOURCES environment variable. * ******************************************************************************* EOF } foreach my $moniker (@sources) { my $classname = "${class}::$moniker"; *{"${classname}::ACCEPT_CONTEXT"} = sub { shift; shift->model($self->model_name)->resultset($moniker); } } } sub _reset_cursor_class { my $self = shift; if ($self->storage->can('cursor_class')) { $self->storage->cursor_class($self->_default_cursor_class) if $self->storage->cursor_class ne $self->_default_cursor_class; } } { my %COMPOSED_CACHE; sub composed_schema { my $self = shift; my $class = $self->_original_class_name; my $store = \$COMPOSED_CACHE{$class}{$self->schema_class}; $$store = shift if @_; return $$store } } sub _build_model_name { my $self = shift; my $class = $self->_original_class_name; (my $model_name = $class) =~ s/^[\w:]+::(?:Model|M):://; return $model_name; } __PACKAGE__->meta->make_immutable; =head1 ENVIRONMENT =over 4 =item CMDS_NO_SOURCES Set this variable if you will be using schemas with no sources (Result classes) to disable the warning. The warning is there because having no Result classes is usually a mistake. =back =head1 Setting up DBIC authentication You can set this up with L in MyApp.pm: package MyApp; use Catalyst qw/... Authentication .../; ... __PACKAGE__->config('Plugin::Authentication' => { default_realm => 'members', members => { credential => { class => 'Password', password_field => 'password', password_type => 'hashed' password_hash_type => 'SHA-256' }, store => { class => 'DBIx::Class', user_model => 'DB::User', role_relation => 'roles', role_field => 'rolename', } } }); =head1 METHOD PROXYING The automatic proxying to the underlying L has been removed as of version C<0.34>, to enable this feature add C to L. See L. =head1 SEE ALSO General Catalyst Stuff: L, L, L, L, L, L, Stuff related to DBIC and this Model style: L, L, L, L, L, L Traits: L, L, L, L, L =head1 AUTHOR Brandon L Black C =head1 CONTRIBUTORS caelum: Rafael Kitover C dandv: Dan Dascalescu C bluefeet: Aran Deltac C t0m: Tomas Doran C osfameron: C ozum: Ozum Eldogan C Pavel I. Shaydo C SineSwiper: Brendan Byrd =head1 COPYRIGHT Copyright (c) 2006 - 2010 the Catalyst::Model::DBIC::Schema L and L as listed above. =head1 LICENSE This program is free software. You can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # vim:sts=4 sw=4 et tw=80: Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Model/DBIC/Schema/000755 000766 000024 00000000000 14461412703 023743 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Model/DBIC/Schema/Types.pm000644 000766 000024 00000007133 14461407424 025415 0ustar00gknopstaff000000 000000 package # hide from PAUSE Catalyst::Model::DBIC::Schema::Types; use MooseX::Types -declare => [qw/ ConnectInfo ConnectInfos Replicants SchemaClass CreateOption Schema LoadedClass /]; use Carp::Clan '^Catalyst::Model::DBIC::Schema'; use MooseX::Types::Moose qw/ArrayRef HashRef CodeRef Str ClassName/; use MooseX::Types::LoadableClass qw/LoadableClass/; use Scalar::Util 'reftype'; use List::MoreUtils 'all'; use Module::Runtime; use namespace::clean -except => 'meta'; # So I restored the custom Type LoadedClass because 'LoadableClass' doesn't really # exactly do the same thing, which busted the Replication trait. Please don't # "clean this up" -JNAP subtype LoadedClass, as ClassName; coerce LoadedClass, from Str, # N.B. deliberate paranoia against $_ clobbering below via { my $classname = $_; Module::Runtime::use_module($classname); $classname }; subtype SchemaClass, as LoadableClass, where { $_->isa('DBIx::Class::Schema') }; class_type Schema, { class => 'DBIx::Class::Schema' }; subtype ConnectInfo, as HashRef, where { exists $_->{dsn} || exists $_->{dbh_maker} }, message { 'Does not look like a valid connect_info' }; coerce ConnectInfo, from Str, via(\&_coerce_connect_info_from_str), from ArrayRef, via(\&_coerce_connect_info_from_arrayref), from CodeRef, via { +{ dbh_maker => $_ } }, ; # { connect_info => [ ... ] } coercion would be nice, but no chained coercions # yet. # Also no coercion from base type (yet,) but in Moose git already. # from HashRef, # via { $_->{connect_info} }, subtype ConnectInfos, as ArrayRef[ConnectInfo], message { "Not a valid array of connect_info's" }; coerce ConnectInfos, from Str, via { [ _coerce_connect_info_from_str() ] }, from CodeRef, via { [ +{ dbh_maker => $_ } ] }, from HashRef, via { [ $_ ] }, from ArrayRef, via { [ map { !ref $_ ? _coerce_connect_info_from_str() : reftype $_ eq 'HASH' ? $_ : reftype $_ eq 'CODE' ? +{ dbh_maker => $_ } : reftype $_ eq 'ARRAY' ? _coerce_connect_info_from_arrayref() : croak 'invalid connect_info' } @$_ ] }; # Helper stuff subtype CreateOption, as Str, where { /^(?:static|dynamic)\z/ }, message { "Invalid create option, must be one of 'static' or 'dynamic'" }; sub _coerce_connect_info_from_arrayref { my %connect_info; # make a copy $_ = [ @$_ ]; my $slurp_hashes = sub { for my $i (0..1) { my $extra = shift @$_; last unless $extra; croak "invalid connect_info" unless ref $extra && reftype $extra eq 'HASH'; %connect_info = (%connect_info, %$extra); } }; if (!ref $_->[0]) { # array style $connect_info{dsn} = shift @$_; $connect_info{user} = shift @$_ if !ref $_->[0]; $connect_info{password} = shift @$_ if !ref $_->[0]; $slurp_hashes->(); croak "invalid connect_info" if @$_; } elsif (ref $_->[0] && reftype $_->[0] eq 'CODE') { $connect_info{dbh_maker} = shift @$_; $slurp_hashes->(); croak "invalid connect_info" if @$_; } elsif (@$_ == 1 && ref $_->[0] && reftype $_->[0] eq 'HASH') { return $_->[0]; } else { croak "invalid connect_info"; } unless ($connect_info{dbh_maker}) { for my $key (qw/user password/) { $connect_info{$key} = '' if not defined $connect_info{$key}; } } \%connect_info; } sub _coerce_connect_info_from_str { +{ dsn => $_, user => '', password => '' } } 1; Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/Model/000755 000766 000024 00000000000 14461412703 023574 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/Model/DBIC/000755 000766 000024 00000000000 14461412703 024275 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/Model/DBIC/Schema/000755 000766 000024 00000000000 14461412703 025475 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/Model/DBIC/Schema/Replicated.pm000644 000766 000024 00000010723 14461407424 030116 0ustar00gknopstaff000000 000000 package Catalyst::TraitFor::Model::DBIC::Schema::Replicated; ## WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ## If you make changes to this code and don't actually go and test it ## on a real replicated environment I will rip you an new hole. The ## test suite DOES NOT properly test this. --JNAP use namespace::autoclean; use Moose::Role; use Carp::Clan '^Catalyst::Model::DBIC::Schema'; use Catalyst::Model::DBIC::Schema::Types qw/ConnectInfos LoadedClass/; use MooseX::Types::Moose qw/Str HashRef/; use Module::Runtime; =head1 NAME Catalyst::TraitFor::Model::DBIC::Schema::Replicated - Replicated storage support for L =head1 SYNOPSiS __PACKAGE__->config({ traits => ['Replicated'] connect_info => ['dbi:mysql:master', 'user', 'pass'], replicants => [ ['dbi:mysql:slave1', 'user', 'pass'], ['dbi:mysql:slave2', 'user', 'pass'], ['dbi:mysql:slave3', 'user', 'pass'], ], balancer_args => { master_read_weight => 0.3 } }); =head1 DESCRIPTION Sets your storage_type to L and connects replicants provided in config. See that module for supported resultset attributes. The default L is C<::Random>. Sets the L to C<1> by default, meaning that you have the same chance of reading from master as you do from replicants. Set to C<0> to turn off reads from master. =head1 CONFIG PARAMETERS =head2 replicants Array of connect_info settings for every replicant. The following can be set via L, or as their own parameters. If set via separate parameters, they will override the settings in C. =head2 pool_type See L. =head2 pool_args See L. =head2 balancer_type See L. =head2 balancer_args See L. =cut has replicants => ( is => 'ro', isa => ConnectInfos, coerce => 1, required => 1 ); # If you change LoadedClass with LoadableClass I will rip you a new hole, # it doesn't work exactly the same - JNAP has pool_type => (is => 'ro', isa => LoadedClass); has pool_args => (is => 'ro', isa => HashRef); has balancer_type => (is => 'ro', isa => Str); has balancer_args => (is => 'ro', isa => HashRef); after setup => sub { my $self = shift; # check storage_type compatibility (if configured) if (my $storage_type = $self->storage_type) { my $class = $storage_type =~ /^::/ ? "DBIx::Class::Storage$storage_type" : $storage_type; # For some odd reason if you try to use 'use_module' as an export # the code breaks. I guess something odd about MR and all these # runtime loaded crazy trait code. Please don't "tidy the code up" -JNAP Module::Runtime::use_module($class); croak "This storage_type cannot be used with replication" unless $class->isa('DBIx::Class::Storage::DBI::Replicated'); } else { $self->storage_type('::DBI::Replicated'); } my $connect_info = $self->connect_info; $connect_info->{pool_type} = $self->pool_type if $self->pool_type; $connect_info->{pool_args} = $self->pool_args if $self->pool_args; $connect_info->{balancer_type} = $self->balancer_type || $connect_info->{balancer_type} || '::Random'; $connect_info->{balancer_args} = $self->balancer_args || $connect_info->{balancer_args} || {}; $connect_info->{balancer_args}{master_read_weight} = 1 unless exists $connect_info->{balancer_args}{master_read_weight}; }; sub BUILD {} after BUILD => sub { my $self = shift; $self->storage->connect_replicants(map [ $_ ], @{ $self->replicants }); }; =head1 SEE ALSO L, L, L, L =head1 AUTHOR See L and L. =head1 COPYRIGHT See L. =head1 LICENSE This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/Model/DBIC/Schema/SchemaProxy.pm000644 000766 000024 00000012053 14461407424 030302 0ustar00gknopstaff000000 000000 package Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy; use namespace::autoclean; use Moose::Role; use Carp::Clan '^Catalyst::Model::DBIC::Schema'; use Catalyst::Model::DBIC::Schema::Types 'Schema'; =head1 NAME Catalyst::TraitFor::Model::DBIC::Schema::SchemaProxy - Proxy Schema Methods and Options from Model =head1 DESCRIPTION Allows you to call your L methods directly on the Model instance, and passes config options to your L and L attributes at C time. Methods and attributes local to your C take precedence over L or L methods and attributes. =head1 CREATING SCHEMA CONFIG ATTRIBUTES To create attributes in your C, use either Moose or L, which is inherited from by all L classes automatically. E.g.: __PACKAGE__->mk_group_accessors(simple => qw/ config_key1 config_key2 ... /); Or with L: use Moose; has config_key1 => (is => 'rw', default => 'default_value'); This code can be added after the md5sum on L generated schemas. At app startup, any non-local options will be passed to these accessors, and can be accessed as usual via C<< $schema->config_key1 >>. These config values go into your C block, along with normal config values. =head1 CREATING RESULTSET CONFIG ATTRIBUTES You can create classdata on L classes to hold values from L config. The code for this looks something like this: package MySchema::ResultSet::Foo; use base 'DBIx::Class::ResultSet'; __PACKAGE__->mk_group_accessors(inherited => qw/ rs_config_key1 rs_config_key2 ... /); __PACKAGE__->rs_config_key1('default_value'); Or, if you prefer L: package MySchema::ResultSet::Foo; use Moose; use MooseX::NonMoose; use MooseX::ClassAttribute; extends 'DBIx::Class::ResultSet'; sub BUILDARGS { $_[2] } # important class_has rs_config_key1 => (is => 'rw', default => 'default_value'); ... __PACKAGE__->meta->make_immutable; 1; In your catalyst config, use the generated Model name as the config key, e.g.: strict_passwords 1 =cut after setup => sub { my ($self, $args) = @_; my $schema = $self->schema; my $was_mutable = $self->meta->is_mutable; $self->meta->make_mutable; $self->meta->add_attribute('schema', is => 'rw', isa => Schema, handles => $self->_delegates # this removes the attribute too ); $self->meta->make_immutable unless $was_mutable; $self->schema($schema) if $schema; }; after BUILD => sub { my ($self, $args) = @_; $self->_pass_options_to_schema($args); for my $source ($self->schema->sources) { my $config_key = 'Model::' . $self->model_name . '::' . $source; my $config = $self->app_class->config->{$config_key}; next unless $config; $self->_pass_options_to_resultset($source, $config); } }; sub _delegates { my $self = shift; my $schema_meta = Class::MOP::Class->initialize($self->schema_class); my @schema_methods = $schema_meta->get_all_method_names; # combine with any already added by other schemas my @handles = eval { @{ $self->meta->find_attribute_by_name('schema')->handles } }; # now kill the attribute, otherwise add_attribute in BUILD will not do the right # thing (it clears the handles for some reason.) May be a Moose bug. eval { $self->meta->remove_attribute('schema') }; my %schema_methods; @schema_methods{ @schema_methods, @handles } = (); @schema_methods = keys %schema_methods; my @my_methods = $self->meta->get_all_method_names; my %my_methods; @my_methods{@my_methods} = (); my @delegates; for my $method (@schema_methods) { push @delegates, $method unless exists $my_methods{$method}; } return \@delegates; } sub _pass_options_to_schema { my ($self, $args) = @_; my @attributes = map { $_->init_arg || () } $self->meta->get_all_attributes; my %attributes; @attributes{@attributes} = (); for my $opt (keys %$args) { if (not exists $attributes{$opt}) { next unless $self->schema->can($opt); $self->schema->$opt($args->{$opt}); } } } sub _pass_options_to_resultset { my ($self, $source, $args) = @_; for my $opt (keys %$args) { my $rs_class = $self->schema->source($source)->resultset_class; next unless $rs_class->can($opt); $rs_class->$opt($args->{$opt}); } } =head1 SEE ALSO L, L =head1 AUTHOR See L and L. =head1 COPYRIGHT See L. =head1 LICENSE This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/Model/DBIC/Schema/Caching.pm000644 000766 000024 00000006044 14461407424 027377 0ustar00gknopstaff000000 000000 package Catalyst::TraitFor::Model::DBIC::Schema::Caching; use namespace::autoclean; use Moose::Role; use Carp::Clan '^Catalyst::Model::DBIC::Schema'; use MooseX::Types::Moose 'Int'; use Module::Runtime 'use_module'; =head1 NAME Catalyst::TraitFor::Model::DBIC::Schema::Caching - Query caching support for Catalyst::Model::DBIC::Schema =head1 SYNOPSIS __PACKAGE__->config({ traits => ['Caching'], connect_info => ['dbi:mysql:db', 'user', 'pass'], }); $c->model('DB::Table')->search({ foo => 'bar' }, { cache_for => 18000 }); =head1 DESCRIPTION Enable caching support using L and L. In order for this to work, L must be configured and loaded. A possible configuration would look like this: class Cache::FastMmap unlink_on_exit 1 share_file /tmp/myapp_share Then in your queries, set the C ResultSet attribute to the number of seconds you want the query results to be cached for, eg.: $c->model('DB::Table')->search({ foo => 'bar' }, { cache_for => 18000 }); =head1 CONFIG PARAMETERS =head2 caching Turn caching on or off, you can use: $c->model('DB')->caching(0); =cut has caching => (is => 'rw', isa => Int, default => 1); after setup => sub { my $self = shift; return if !$self->caching; $self->caching(0); my $cursor_class = $self->connect_info->{cursor_class} || 'DBIx::Class::Cursor::Cached'; unless (eval { use_module($cursor_class) }) { carp "Caching disabled, cannot load cursor class" . " $cursor_class: $@"; return; } unless ($cursor_class->can('clear_cache')) { carp "Caching disabled, cursor_class $cursor_class does not" . " support it."; return; } $self->connect_info->{cursor_class} = $cursor_class; $self->caching(1); }; before ACCEPT_CONTEXT => sub { my ($self, $c) = @_; return $self unless $self->caching; unless ($c->can('cache') && ref $c->cache) { $c->log->warn("DBIx::Class cursor caching disabled, you don't seem to" . " have a working Cache plugin."); $self->caching(0); $self->_reset_cursor_class; return $self; } if (ref $self->schema->default_resultset_attributes) { $self->schema->default_resultset_attributes->{cache_object} = $c->cache; } else { $self->schema->default_resultset_attributes({ cache_object => $c->cache }); } }; =head1 SEE ALSO L, L, L, L, L =head1 AUTHOR See L and L. =head1 COPYRIGHT See L. =head1 LICENSE This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/TraitFor/Model/DBIC/Schema/PerRequestSchema.pm000644 000766 000024 00000004026 14461407424 031261 0ustar00gknopstaff000000 000000 package Catalyst::TraitFor::Model::DBIC::Schema::PerRequestSchema; use Moose::Role; use MooseX::MarkAsMethods autoclean => 1; with 'Catalyst::Component::InstancePerContext'; =head1 NAME Catalyst::TraitFor::Model::DBIC::Schema::PerRequestSchema - Clone the schema with attributes for each requests =head1 SYNOPSIS __PACKAGE__->config({ traits => ['PerRequestSchema'], }); sub per_request_schema_attributes { my ($self, $c) = @_; return (restricting_object => $c->user->obj); } ### OR ### sub per_request_schema { my ($self, $c) = @_; return $self->schema->schema_method($c->user->obj) } =head1 DESCRIPTION Clones the schema for each new request with the attributes retrieved from your C method, which you must implement. This method is passed the context. Alternatively, you could also override the C method if you need access to the schema clone and/or need to separate out the Model/Schema methods. (See examples above and the defaults in the code.) =cut sub build_per_context_instance { my ( $self, $ctx ) = @_; return $self unless blessed($ctx); my $new = bless {%$self}, ref $self; $new->schema($new->per_request_schema($ctx)); return $new; } # Thanks to Matt Trout for this idea sub per_request_schema { my ($self, $c) = @_; return $self->schema->clone($self->per_request_schema_attributes($c)); } ### TODO: This should probably be more elegant ### sub per_request_schema_attributes { confess "Either per_request_schema_attributes needs to be created, or per_request_schema needs to be overridden!"; } =head1 SEE ALSO L, L =head1 AUTHOR See L and L. =head1 COPYRIGHT See L. =head1 LICENSE This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Helper/Model/000755 000766 000024 00000000000 14461412703 023261 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Helper/Model/DBIC/000755 000766 000024 00000000000 14461412703 023762 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Helper/Model/DBIC/PaxHeader/Schema.pm000644 000766 000024 00000000210 14461412240 027456 xustar00gknopstaff000000 000000 30 mtime=1690703008.254656629 57 LIBARCHIVE.xattr.com.apple.provenance=AQAAq1dlpUhBqgg 49 SCHILY.xattr.com.apple.provenance=«We„HAȘ Catalyst-Model-DBIC-Schema-0.66/lib/Catalyst/Helper/Model/DBIC/Schema.pm000644 000766 000024 00000050157 14461412240 025524 0ustar00gknopstaff000000 000000 package Catalyst::Helper::Model::DBIC::Schema; use namespace::autoclean; use Moose; no warnings 'uninitialized'; our $VERSION = '0.66'; $VERSION =~ tr/_//d; use Carp; use Tie::IxHash (); use Data::Dumper (); use List::Util 'first'; use MooseX::Types::Moose qw/Str HashRef Bool ArrayRef/; use Catalyst::Model::DBIC::Schema::Types 'CreateOption'; use List::MoreUtils 'firstidx'; use Scalar::Util 'looks_like_number'; use File::Find 'finddepth'; use Try::Tiny; use Cwd 'getcwd'; use Module::Runtime 'use_module'; =head1 NAME Catalyst::Helper::Model::DBIC::Schema - Helper for DBIC Schema Models =head1 SYNOPSIS script/create.pl model CatalystModelName DBIC::Schema MyApp::SchemaClass \ [ create=dynamic | create=static ] [ traits=trait1,trait2... ] \ [ Schema::Loader opts ] [ dsn user pass ] \ [ other connect_info args ] =head1 DESCRIPTION Helper for the DBIC Schema Models. =head2 Arguments: C is the short name for the Catalyst Model class being generated (i.e. callable with C<$c-Emodel('CatalystModelName')>). C is the fully qualified classname of your Schema, which might or might not yet exist. Note that you should have a good reason to create this under a new global namespace, otherwise use an existing top level namespace for your schema class. C instructs this Helper to generate the named Schema class for you, basing it on L (which means the table information will always be dynamically loaded at runtime from the database). C instructs this Helper to generate the named Schema class for you, using L in "one shot" mode to create a standard, manually-defined L setup, based on what the Loader sees in your database at this moment. A Schema/Model pair generated this way will not require L at runtime, and will not automatically adapt itself to changes in your database structure. You can edit the generated classes by hand to refine them. C is the list of traits to apply to the model, see L for details. C are documented in L and some examples are given in L below. C arguments are the same as what L expects, and are storage_type-specific. They are documented in L. For DBI-based storage, these arguments are the dsn, username, password, and connect options, respectively. These are optional for existing Schemas, but required if you use either of the C options. username and password can be omitted for C dsns. Use of either of the C options requires L. =head1 TYPICAL EXAMPLES Use DBIx::Class::Schema::Loader to create a static DBIx::Class::Schema, and a Model which references it: script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass create=static dbi:mysql:foodb myuname mypass Same, with extra connect_info args user and pass can be omitted for sqlite, since they are always empty script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass create=static dbi:SQLite:foo.db \ AutoCommit=1 cursor_class=DBIx::Class::Cursor::Cached \ on_connect_do='["select 1", "select 2"]' quote_names=1 B In C the above example would be: script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass create=static dbi:SQLite:foo.db \ AutoCommit=1 cursor_class=DBIx::Class::Cursor::Cached \ on_connect_do="[\"select 1\", \"select 2\"]" quote_names=1 Same, but with extra Schema::Loader args (separate multiple values by commas): script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass create=static db_schema=foodb components=Foo,Bar \ exclude='^(wibble|wobble)$' moniker_map='{ foo => "FOO" }' \ dbi:Pg:dbname=foodb myuname mypass Coderefs are also supported: script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass create=static \ inflect_singular='sub { $_[0] =~ /\A(.+?)(_id)?\z/; $1 }' \ moniker_map='sub { join(q{}, map ucfirst, split(/[\W_]+/, lc $_[0])); }' \ dbi:mysql:foodb myuname mypass See L for a list of options Create a dynamic DBIx::Class::Schema::Loader-based Schema, and a Model which references it (B): script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass create=dynamic dbi:mysql:foodb myuname mypass Reference an existing Schema of any kind, and provide some connection information for ->config: script/myapp_create.pl model CatalystModelName DBIC::Schema \ MyApp::SchemaClass dbi:mysql:foodb myuname mypass Same, but don't supply connect information yet (you'll need to do this in your app config, or [not recommended] in the schema itself). script/myapp_create.pl model ModelName DBIC::Schema My::SchemaClass =cut has helper => (is => 'ro', isa => 'Catalyst::Helper', required => 1); has create => (is => 'rw', isa => CreateOption); has args => (is => 'ro', isa => ArrayRef); has traits => (is => 'rw', isa => ArrayRef); has schema_class => (is => 'ro', isa => Str, required => 1); has loader_args => (is => 'rw', isa => HashRef); has connect_info => (is => 'rw', isa => HashRef); has old_schema => (is => 'rw', isa => Bool, lazy_build => 1); has is_moose_schema => (is => 'rw', isa => Bool, lazy_build => 1); has result_namespace => (is => 'rw', isa => Str, lazy_build => 1); has components => (is => 'rw', isa => ArrayRef); =head1 METHODS =head2 mk_compclass This is called by L with the commandline args to generate the files. =cut sub mk_compclass { my ($package, $helper, $schema_class, @args) = @_; my $self = $package->new( helper => $helper, schema_class => $schema_class, args => \@args ); $self->run; } sub BUILD { my $self = shift; my $helper = $self->helper; my @args = @{ $self->args || [] }; $helper->{schema_class} = $self->schema_class; @args = $self->_cleanup_args(\@args); my ($traits_idx, $traits); if (($traits_idx = firstidx { ($traits) = /^traits=(\S*)\z/ } @args) != -1) { my @traits = split /,/ => $traits; $self->traits(\@traits); $helper->{traits} = '[' .(join ',' => map { qq{'$_'} } @traits) .']'; splice @args, $traits_idx, 1, (); } if ($args[0] && $args[0] =~ /^create=(\S*)\z/) { $self->create($1); shift @args; if (@args) { $self->_parse_loader_args(\@args); $helper->{loader_args} = $self->_build_helper_loader_args; } } my $dbi_dsn_part; if (first { ($dbi_dsn_part) = /^(dbi):/i } @args) { die qq{DSN must start with 'dbi:' not '$dbi_dsn_part' (case matters!)} if $dbi_dsn_part ne 'dbi'; $helper->{setup_connect_info} = 1; $helper->{connect_info} = $self->_build_helper_connect_info(\@args); $self->_parse_connect_info(\@args); } $helper->{generator} = ref $self; $helper->{generator_version} = $VERSION; } =head2 run Can be called on an instance to generate the files. =cut sub run { my $self = shift; if ($self->create eq 'dynamic') { $self->_print_dynamic_deprecation_warning; $self->_gen_dynamic_schema; } elsif ($self->create eq 'static') { $self->_gen_static_schema; } $self->_gen_model; } sub _parse_loader_args { my ($self, $args) = @_; my %loader_args = $self->_read_loader_args($args); while (my ($key, $val) = each %loader_args) { next if $key =~ /^(?:components|constraint|exclude)\z/; $loader_args{$key} = $self->_eval($val); die "syntax error for loader args key '$key' with value '$val': $@" if $@; } my @components = $self->_build_loader_components( delete $loader_args{components}, $loader_args{use_namespaces}, ); $self->components(\@components); for my $re_opt (qw/constraint exclude/) { $loader_args{$re_opt} = qr/$loader_args{$re_opt}/ if exists $loader_args{$re_opt}; } tie my %result, 'Tie::IxHash'; %result = ( relationships => 1, use_moose => $self->is_moose_schema ? 1 : 0, col_collision_map => 'column_%s', (!$self->old_schema ? ( use_namespaces => 1 ) : ()), (@components ? ( components => \@components ) : ()), (%loader_args ? %loader_args : ()), ); $self->loader_args(\%result); wantarray ? %result : \%result; } sub _read_loader_args { my ($self, $args) = @_; my %loader_args; while (@$args && $args->[0] !~ /^dbi:/i) { my ($key, $val) = split /=/, shift(@$args), 2; if ($self->_is_struct($val)) { $loader_args{$key} = $val; } elsif ((my @vals = split /,/ => $val) > 1) { $loader_args{$key} = \@vals; } else { $loader_args{$key} = $val; } } # Use args after connect_info as loader args as well, because people always # get the order confused. my $i = 1; if ($args->[0] =~ /sqlite/i) { $i++ if $args->[$i] eq ''; $i++ if $args->[$i] eq ''; } else { $i += 2; } my $have_loader = try { use_module('DBIx::Class::Schema::Loader::Base'); 1; }; if ($have_loader) { while (defined $args->[$i]) { $i++ while $self->_is_struct($args->[$i]); last if not defined $args->[$i]; my ($key, $val) = split /=/, $args->[$i], 2; if (not DBIx::Class::Schema::Loader::Base->can($key)) { $i++; next; } if ($self->_is_struct($val)) { $loader_args{$key} = $val; } elsif ((my @vals = split /,/ => $val) > 1) { $loader_args{$key} = \@vals; } else { $loader_args{$key} = $val; } splice @$args, $i, 1; } } wantarray ? %loader_args : \%loader_args; } sub _build_helper_loader_args { my $self = shift; my $args = $self->loader_args; tie my %loader_args, 'Tie::IxHash'; while (my ($arg, $val) = each %$args) { if (ref $val) { $loader_args{$arg} = $self->_data_struct_to_string($val); } else { $loader_args{$arg} = qq{'$val'}; } } \%loader_args } sub _build_loader_components { my ($self, $components, $use_namespaces) = @_; my @components = $self->old_schema && (not $use_namespaces) ? () : ('InflateColumn::DateTime'); if ($components) { $components = [ $components ] if !ref $components; push @components, @$components; } wantarray ? @components : \@components; } sub _build_helper_connect_info { my ($self, $connect_info) = @_; my @connect_info = @$connect_info; my ($dsn, $user, $password) = $self->_get_dsn_user_pass(\@connect_info); tie my %helper_connect_info, 'Tie::IxHash'; %helper_connect_info = ( dsn => qq{'$dsn'}, user => qq{'$user'}, password => qq{'$password'} ); for (@connect_info) { if (/^\s*{.*}\s*\z/) { my $hash = $self->_eval($_); die "Syntax errorr in connect_info hash: $_: $@" if $@; my %hash = %$hash; for my $key (keys %hash) { my $val = $hash{$key}; if (ref $val) { $val = $self->_data_struct_to_string($val); } else { $val = $self->_quote($val); } $helper_connect_info{$key} = $val; } next; } my ($key, $val) = split /=/, $_, 2; if ($key eq 'quote_char') { $helper_connect_info{$key} = length($val) == 1 ? $self->_quote($val) : $self->_data_struct_to_string([split //, $val]); } else { $helper_connect_info{$key} = $self->_quote_unless_struct($val); } } \%helper_connect_info } sub _build_old_schema { my $self = shift; return $self->result_namespace eq '' ? 1 : 0; } sub _build_is_moose_schema { my $self = shift; my @schema_parts = split '::', $self->schema_class; my $result_dir = File::Spec->catfile( $self->helper->{base}, 'lib', @schema_parts, $self->result_namespace ); # assume yes for new schemas return 1 if not -d $result_dir; my $uses_moose = 1; my $cwd = getcwd; try { finddepth(sub { return if $File::Find::name !~ /\.pm\z/; open my $fh, '<', $File::Find::name or die "Could not open $File::Find::name: $!"; my $code = do { local $/; <$fh> }; close $fh; $uses_moose = 0 if $code !~ /\nuse Moose;\n/; die; }, $result_dir); }; chdir $cwd; return $uses_moose; } sub _build_result_namespace { my $self = shift; my @schema_parts = split '::', $self->schema_class; my $schema_pm = File::Spec->catfile($self->helper->{base}, 'lib', @schema_parts) . '.pm'; if (not -f $schema_pm) { eval { use_module('DBIx::Class::Schema::Loader') }; return 'Result' if $@; return (try { DBIx::Class::Schema::Loader->VERSION('0.05') }) ? 'Result' : ''; } open my $fh, '<', $schema_pm or die "Could not open $schema_pm: $!"; my $code = do { local $/; <$fh> }; close $fh; my ($result_namespace) = $code =~ /result_namespace => '([^']+)'/; return $result_namespace if $result_namespace; return '' if $code =~ /->load_classes/; return 'Result'; } sub _data_struct_to_string { my ($self, $data) = @_; local $Data::Dumper::Terse = 1; local $Data::Dumper::Quotekeys = 0; local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Indent = 0; local $Data::Dumper::Useqq = 1; return Data::Dumper->Dump([$data]); } sub _get_dsn_user_pass { my ($self, $connect_info) = @_; my $dsn = shift @$connect_info; my ($user, $password); if ($dsn =~ /sqlite/i) { ($user, $password) = ('', ''); shift @$connect_info while @$connect_info and $connect_info->[0] eq ''; } else { ($user, $password) = splice @$connect_info, 0, 2; } ($dsn, $user, $password) } sub _parse_connect_info { my ($self, $connect_info) = @_; my @connect_info = @$connect_info; my ($dsn, $user, $password) = $self->_get_dsn_user_pass(\@connect_info); tie my %connect_info, 'Tie::IxHash'; @connect_info{qw/dsn user password/} = ($dsn, $user, $password); for (@connect_info) { if (/^\s*{.*}\s*\z/) { my $hash = $self->_eval($_); die "Syntax errorr in connect_info hash: $_: $@" if $@; %connect_info = (%connect_info, %$hash); next; } my ($key, $val) = split /=/, $_, 2; if ($key eq 'quote_char') { $connect_info{$key} = length($val) == 1 ? $val : [split //, $val]; } elsif ($key =~ /^(?:name_sep|limit_dialect)\z/) { $connect_info{$key} = $val; } else { $connect_info{$key} = $self->_eval($val); } die "syntax error for connect_info key '$key' with value '$val': $@" if $@; } $self->connect_info(\%connect_info); \%connect_info } sub _is_struct { my ($self, $val) = @_; return $val =~ /^\s*(?:sub|[[{])/; } sub _quote { my ($self, $val) = @_; return 'q{'.$val.'}'; } sub _quote_unless_struct { my ($self, $val) = @_; $val = $self->_quote($val) if not $self->_is_struct($val); return $val; } sub _eval { my ($self, $code) = @_; return $code if looks_like_number $code; return $code if not $self->_is_struct($code); return eval "{no strict; $code}"; } sub _gen_dynamic_schema { my $self = shift; my $helper = $self->helper; my @schema_parts = split(/\:\:/, $self->schema_class); my $schema_file_part = pop @schema_parts; my $schema_dir = File::Spec->catfile( $helper->{base}, 'lib', @schema_parts ); my $schema_file = File::Spec->catfile( $schema_dir, $schema_file_part . '.pm' ); $helper->mk_dir($schema_dir); $helper->render_file('schemaclass', $schema_file); } sub _gen_static_schema { my $self = shift; die "cannot load schema without connect info" unless $self->connect_info; my $helper = $self->helper; my $schema_dir = File::Spec->catfile($helper->{base}, 'lib'); try { use_module('DBIx::Class::Schema::Loader') } catch { die "Cannot load DBIx::Class::Schema::Loader: $_"; }; DBIx::Class::Schema::Loader->import( "dump_to_dir:$schema_dir", 'make_schema_at' ); make_schema_at( $self->schema_class, $self->loader_args, [$self->connect_info] ); require lib; lib->import($schema_dir); use_module($self->schema_class); my @sources = $self->schema_class->sources; if (not @sources) { warn <<'EOF'; WARNING: No tables found, did you forget to specify db_schema? EOF } } sub _gen_model { my $self = shift; my $helper = $self->helper; $helper->render_file('compclass', $helper->{file} ); } sub _print_dynamic_deprecation_warning { warn <); exit 0 if $response =~ /^n(o)?\z/; } sub _cleanup_args { my ($self, $args) = @_; # remove blanks, ie. someoned doing foo \ bar my @res = grep !/^\s+\z/, @$args; # remove leading whitespace, ie. foo \ bar s/^\s*// for @res; @res } =head1 SEE ALSO General Catalyst Stuff: L, L, L, L, L, L, Stuff related to DBIC and this Model style: L, L, L, L =head1 AUTHOR See L and L. =head1 COPYRIGHT See L. =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; __DATA__ =begin pod_to_ignore __schemaclass__ package [% schema_class %]; use strict; use base qw/DBIx::Class::Schema::Loader/; __PACKAGE__->loader_options( [%- FOREACH key = loader_args.keys %] [% key %] => [% loader_args.${key} %], [%- END -%] ); =head1 NAME [% schema_class %] - L class =head1 SYNOPSIS See L<[% app %]> =head1 DESCRIPTION Dynamic L schema for use in L<[% class %]> =head1 GENERATED BY [% generator %] - [% generator_version %] =head1 AUTHOR [% author.replace(',+$', '') %] =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; __compclass__ package [% class %]; use strict; use base 'Catalyst::Model::DBIC::Schema'; __PACKAGE__->config( schema_class => '[% schema_class %]', [% IF traits %]traits => [% traits %],[% END %] [% IF setup_connect_info %]connect_info => { [%- FOREACH key = connect_info.keys %] [% key %] => [% connect_info.${key} %], [%- END -%] }[% END %] ); =head1 NAME [% class %] - Catalyst DBIC Schema Model =head1 SYNOPSIS See L<[% app %]> =head1 DESCRIPTION L Model using schema L<[% schema_class %]> =head1 GENERATED BY [% generator %] - [% generator_version %] =head1 AUTHOR [% author.replace(',+$', '') %] =head1 LICENSE This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; __END__ # vim:sts=4 sw=4: Catalyst-Model-DBIC-Schema-0.66/t/02pod.t000644 000766 000024 00000000277 14461407424 020036 0ustar00gknopstaff000000 000000 use Test::More; eval "use Test::Pod 1.14"; plan skip_all => 'Test::Pod 1.14 required' if $@; plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD}; all_pod_files_ok(); Catalyst-Model-DBIC-Schema-0.66/t/01use.t000644 000766 000024 00000000224 14461407424 020037 0ustar00gknopstaff000000 000000 use strict; use Test::More tests => 2; BEGIN { use_ok('Catalyst::Model::DBIC::Schema') } BEGIN { use_ok('Catalyst::Helper::Model::DBIC::Schema') } Catalyst-Model-DBIC-Schema-0.66/t/07connect_info.t000644 000766 000024 00000006051 14461407424 021721 0ustar00gknopstaff000000 000000 use strict; use warnings; use FindBin '$Bin'; use lib "$Bin/lib"; use Test::More; use Test::Exception; use Catalyst::Model::DBIC::Schema; use ASchemaClass; # execise the connect_info coercion my $coderef = sub {}; my @tests = ( ['dbi:SQLite:foo.db', '', ''], { dsn => 'dbi:SQLite:foo.db', user => '', password => '' }, ['dbi:SQLite:foo.db', ''], { dsn => 'dbi:SQLite:foo.db', user => '', password => '' }, ['dbi:SQLite:foo.db'], { dsn => 'dbi:SQLite:foo.db', user => '', password => '' }, 'dbi:SQLite:foo.db', { dsn => 'dbi:SQLite:foo.db', user => '', password => '' }, ['dbi:Pg:dbname=foo', 'user', 'pass', { pg_enable_utf8 => 1, auto_savepoint => 1 }], { dsn => 'dbi:Pg:dbname=foo', user => 'user', password => 'pass', pg_enable_utf8 => 1, auto_savepoint => 1 }, ['dbi:Pg:dbname=foo', 'user', 'pass', { pg_enable_utf8 => 1 }, { auto_savepoint => 1 }], { dsn => 'dbi:Pg:dbname=foo', user => 'user', password => 'pass', pg_enable_utf8 => 1, auto_savepoint => 1 }, [ { dsn => 'dbi:Pg:dbname=foo', user => 'user', password => 'pass', pg_enable_utf8 => 1, auto_savepoint => 1 } ], { dsn => 'dbi:Pg:dbname=foo', user => 'user', password => 'pass', pg_enable_utf8 => 1, auto_savepoint => 1 }, [$coderef, { pg_enable_utf8 => 1, auto_savepoint => 1 }], { dbh_maker => $coderef, pg_enable_utf8 => 1, auto_savepoint => 1 }, ); my @invalid = ( { foo => 'bar' }, [ { foo => 'bar' } ], ['dbi:Pg:dbname=foo', 'user', 'pass', { pg_enable_utf8 => 1 }, { AutoCommit => 1 }, { auto_savepoint => 1 }], ); # ignore redefined warnings, and uninitialized warnings from old # ::Storage::DBI::Replicated local $SIG{__WARN__} = sub { $_[0] !~ /(?:redefined|uninitialized)/i && warn @_ }; for (my $i = 0; $i < @tests; $i += 2) { my $m = instance( connect_info => $tests[$i] ); is_deeply $m->connect_info, $tests[$i+1], 'connect_info coerced correctly'; } throws_ok { instance(connect_info => $_) } qr/valid connect_info/i, 'invalid connect_info throws exception' for @invalid; # try as ConnectInfos (e.g.: replicants) my @replicants = map $tests[$_], grep $_ % 2 == 0, 0..$#tests; { package TryConnectInfos; use Moose; use Catalyst::Model::DBIC::Schema::Types 'ConnectInfos'; has replicants => (is => 'ro', isa => ConnectInfos, coerce => 1); } my $m = TryConnectInfos->new( replicants => \@replicants ); lives_and { is_deeply(TryConnectInfos->new(replicants => $tests[1])->replicants, [ $tests[1] ]) } 'single replicant hashref coerces correctly'; is_deeply $m->replicants, [ map $tests[$_], grep $_ % 2, 0 .. $#tests ], 'replicant connect_infos coerced correctly'; { ASchemaClass->connection( @{$tests[0]} ); my $m = instance(); is_deeply $m->connect_info, $tests[1], 'connect_info coerced correctly when defining connection in the schema class'; } done_testing; sub instance { Catalyst::Model::DBIC::Schema->new({ schema_class => 'ASchemaClass', @_ }) } Catalyst-Model-DBIC-Schema-0.66/t/10literal_sql_through_accessor.t000644 000766 000024 00000002366 14461407424 025211 0ustar00gknopstaff000000 000000 use strict; use warnings; use Test::More; use Test::Exception; use FindBin; use lib "$FindBin::Bin/lib"; use File::Spec::Functions 'catfile'; use DBI; my $test_dir = $FindBin::Bin; my $db = catfile($test_dir, 'testdb.db'); my $dbh = DBI->connect("dbi:SQLite:$db", '', '', { RaiseError => 1, PrintError => 0 }); $dbh->do(<<'EOF'); create table users ( id integer primary key, first_name varchar(100), middle_name varchar(100), last_name varchar(100), email_address varchar(100) ) EOF $dbh->disconnect; my $model = instance(); my $rs = $model->resultset('User'); my $row = $rs->create({ first_name => 'Foo', last_name => 'Bar' }); $row->first_name(\['last_name']); lives_ok { $row->update; } 'update survived'; $row->discard_changes; is $row->first_name, 'Bar', 'row updated with literal SQL through accessor'; done_testing; sub instance { MyApp::Model::DB->COMPONENT('MyApp', { schema_class => 'ASchemaClass', connect_info => ["dbi:SQLite:$db", '', ''], @_, }) } { package MyApp; use Catalyst; } { package MyApp::Model::DB; use base 'Catalyst::Model::DBIC::Schema'; } END { $model->storage->disconnect if $model; unlink $db or die "Could not delete $db: $!"; } Catalyst-Model-DBIC-Schema-0.66/t/09schema_options.t000644 000766 000024 00000002366 14461407424 022277 0ustar00gknopstaff000000 000000 use strict; use warnings; use FindBin '$Bin'; use lib "$Bin/lib"; use Test::More; use Test::Exception; use Catalyst::Model::DBIC::Schema; use ASchemaClass; use AnotherSchemaClass; # reusing the same app for 2 models, gets a redefined warning $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /redefined/ }; ok((my $m = instance(a_schema_option => 'mtfnpy')), 'instance'); is $m->schema->a_schema_option, 'mtfnpy', 'option was passed from config'; lives_ok { $m->a_schema_option('pass the crack pipe') } 'delegate called'; is $m->schema->a_schema_option, 'pass the crack pipe', 'delegation works'; ok(($m = instance(schema_class => 'AnotherSchemaClass')), 'instance'); is $m->resultset('User')->rs_config_option, 'configured rs value', 'ResultSet option passed from config'; done_testing; sub instance { MyApp::Model::DB->COMPONENT('MyApp', { traits => 'SchemaProxy', schema_class => 'ASchemaClass', connect_info => ['dbi:SQLite:foo.db', '', ''], @_, }) } BEGIN { package MyApp; use Catalyst; __PACKAGE__->config({ 'Model::DB::User' => { rs_config_option => 'configured rs value', }, }); } { package MyApp::Model::DB; use base 'Catalyst::Model::DBIC::Schema'; } Catalyst-Model-DBIC-Schema-0.66/t/05testapp.t000644 000766 000024 00000015104 14461407424 020732 0ustar00gknopstaff000000 000000 use strict; use Test::More; use FindBin; use File::Spec::Functions qw/catfile catdir/; use File::Find; use Config; use DBI; use IPC::Open3 'open3'; plan skip_all => 'Enable this optional test with $ENV{C_M_DBIC_SCHEMA_TESTAPP}' unless $ENV{C_M_DBIC_SCHEMA_TESTAPP}; my $test_params = [ [ 'TestSchema', 'DBIC::Schema', '' ], [ 'TestSchemaDSN', 'DBIC::Schema', qw/fakedsn fakeuser fakepass/, '{ AutoCommit => 1 }' ], [ 'TestSchemaDSN', 'DBIC::Schema', 'create=static', 'traits=Caching', q|moniker_map={ roles => 'ROLE' }|, 'constraint=^users\z', 'dbi:SQLite:testdb.db' ], [ 'TestSchemaDSN', 'DBIC::Schema', 'create=static', 'traits=Caching', q|moniker_map={ roles => 'ROLE' }|, 'constraint=^users\z', 'dbi:SQLite:testdb.db', '', '', q|on_connect_do=['select 1', 'select 2']| ], [ 'TestSchemaDSN', 'DBIC::Schema', 'create=static', 'traits=Caching', q|moniker_map={ roles => 'ROLE' }|, 'dbi:SQLite:testdb.db', q|on_connect_do=['select 1', 'select 2']| ], [ 'TestSchemaDSN', 'DBIC::Schema', 'create=static', 'traits=Caching', 'inflect_singular=sub { $_[0] =~ /\A(.+?)(_id)?\z/; $1 }', q{moniker_map=sub { return join('', map ucfirst, split(/[\W_]+/, lc $_[0])); }}, 'dbi:SQLite:testdb.db' ], ]; my $test_dir = $FindBin::Bin; my $blib_dir = catdir ($test_dir, '..', 'blib', 'lib'); my $cat_dir = catdir ($test_dir, 'TestApp'); my $catlib_dir = catdir ($cat_dir, 'lib'); my $schema_dir = catdir ($catlib_dir, 'TestSchemaDSN'); my $creator = catfile($cat_dir, 'script', 'testapp_create.pl'); my $model_dir = catdir ($catlib_dir, 'TestApp', 'Model'); my $db = catfile($cat_dir, 'testdb.db'); my $catalyst_pl; foreach my $bin (split /(?:$Config{path_sep}|:)/, $ENV{PATH}) { my $file = catfile($bin, 'catalyst.pl'); if (-f $file) { $catalyst_pl = $file; last; } } plan skip_all => 'catalyst.pl not found' unless $catalyst_pl; chdir($test_dir); silent_exec("$^X $catalyst_pl TestApp"); chdir($cat_dir); # create test db my $dbh = DBI->connect("dbi:SQLite:$db", '', '', { RaiseError => 1, PrintError => 0 }); $dbh->do(<<'EOF'); CREATE TABLE users ( id INTEGER PRIMARY KEY, username TEXT, password TEXT, email_address TEXT, first_name TEXT, last_name TEXT, active INTEGER ); EOF $dbh->do(<<'EOF'); CREATE TABLE roles ( id INTEGER PRIMARY KEY, role TEXT ); EOF $dbh->disconnect; foreach my $tparam (@$test_params) { my ($model, $helper, @args) = @$tparam; cleanup_schema(); silent_exec($^X, "-I$blib_dir", $creator, 'model', $model, $helper, $model, @args); my $model_path = catfile($model_dir, $model . '.pm'); ok( -f $model_path, "$model_path is a file" ); my $compile_rv = silent_exec($^X, "-I$blib_dir", "-I$catlib_dir", "-c", $model_path); ok($compile_rv == 0, "perl -c $model_path"); if (grep /create=static/, @args) { my @result_files = result_files(); if (grep /constraint/, @args) { is scalar @result_files, 1, 'constraint works'; } else { is scalar @result_files, 2, 'correct number of tables'; } for my $file (@result_files) { my $code = code_for($file); like $code, qr/use Moose;\n/, 'use_moose enabled'; like $code, qr/__PACKAGE__->meta->make_immutable;\n/, 'use_moose enabled'; } } } # Test that use_moose=1 is not applied to existing non-moose schemas (RT#60558) { cleanup_schema(); silent_exec($^X, "-I$blib_dir", $creator, 'model', 'TestSchemaDSN', 'DBIC::Schema', 'TestSchemaDSN', 'create=static', 'use_moose=0', 'dbi:SQLite:testdb.db' ); my @result_files = result_files(); for my $file (@result_files) { my $code = code_for($file); unlike $code, qr/use Moose;\n/, 'non use_moose=1 schema'; unlike $code, qr/__PACKAGE__->meta->make_immutable;\n/, 'non use_moose=1 schema'; } silent_exec($^X, "-I$blib_dir", $creator, 'model', 'TestSchemaDSN', 'DBIC::Schema', 'TestSchemaDSN', 'create=static', 'dbi:SQLite:testdb.db' ); for my $file (@result_files) { my $code = code_for($file); unlike $code, qr/use Moose;\n/, 'non use_moose=1 schema not upgraded to use_moose=1'; unlike $code, qr/__PACKAGE__->meta->make_immutable;\n/, 'non use_moose=1 schema not upgraded to use_moose=1'; } } # Test that a moose schema is not detected as a non-moose schema due to an # errant file. { cleanup_schema(); silent_exec($^X, "-I$blib_dir", $creator, 'model', 'TestSchemaDSN', 'DBIC::Schema', 'TestSchemaDSN', 'create=static', 'dbi:SQLite:testdb.db' ); mkdir "$schema_dir/.svn"; open my $fh, '>', "$schema_dir/.svn/foo" or die "Could not open $schema_dir/.svn/foo for writing: $!"; print $fh "gargle\n"; close $fh; mkdir "$schema_dir/Result/.svn"; open $fh, '>', "$schema_dir/Result/.svn/foo" or die "Could not open $schema_dir/Result/.svn/foo for writing: $!"; print $fh "hlagh\n"; close $fh; silent_exec($^X, "-I$blib_dir", $creator, 'model', 'TestSchemaDSN', 'DBIC::Schema', 'TestSchemaDSN', 'create=static', 'dbi:SQLite:testdb.db' ); for my $file (result_files()) { my $code = code_for($file); like $code, qr/use Moose;\n/, 'use_moose detection not confused by version control files'; like $code, qr/__PACKAGE__->meta->make_immutable;\n/, 'use_moose detection not confused by version control files'; } } done_testing; sub rm_rf { my $name = $File::Find::name; if(-d $name) { rmdir $name or warn "Cannot rmdir $name: $!" } else { unlink $name or die "Cannot unlink $name: $!" } } sub cleanup_schema { return unless -d $schema_dir; finddepth({ wanted => \&rm_rf, no_chdir => 1 }, $schema_dir); unlink "${schema_dir}.pm"; } sub code_for { my $file = shift; open my $fh, '<', $file; my $code = do { local $/; <$fh> }; close $fh; return $code; } sub result_files { my $result_dir = catfile($schema_dir, 'Result'); my @results; opendir my $dir, $result_dir or die "Could not open $result_dir: $!"; while (my $file = readdir $dir) { next unless $file =~ /\.pm\z/; push @results, catfile($result_dir, $file); } closedir $dir; return @results; } sub silent_exec { local *NULL; open NULL, '+<', File::Spec->devnull; my $pid = open3('<&NULL', '>&NULL', '>&NULL', @_); waitpid $pid, 0; return $?; } END { if ($ENV{C_M_DBIC_SCHEMA_TESTAPP}) { chdir($test_dir); finddepth({ wanted => \&rm_rf, no_chdir => 1 }, $cat_dir); } } # vim:sts=3 sw=3 et tw=80: Catalyst-Model-DBIC-Schema-0.66/t/08helper.t000644 000766 000024 00000014306 14461407424 020537 0ustar00gknopstaff000000 000000 use strict; use warnings; use FindBin '$Bin'; use lib "$Bin/lib"; use Test::More; use Test::Exception; use Catalyst::Helper::Model::DBIC::Schema; use Storable 'dclone'; use Data::Dumper; use Test::Requires qw(Catalyst::Helper DBIx::Class::Schema::Loader); my $helper = Catalyst::Helper->new; $helper->{base} = $Bin; my $static = 'create=static'; my $dynamic = 'create=dynamic'; my $sqlite = 'dbi:SQLite:myapp.db'; my $pg = 'dbi:Pg:dbname=foo'; my $on_connect_do = 'on_connect_do=["select 1", "select 2"]'; my $quote_char = 'quote_char="'; my $name_sep = 'name_sep=.'; my $i; $i = instance(schema_class => 'ASchemaClass'); is $i->old_schema, 1, '->load_classes detected correctly'; throws_ok { $i = instance(args => [$static, 'DbI:SQLite:myapp.db']) } qr/case matters/i, "wrong case for 'dbi:' DSN part"; $i = instance(args => ['traits=Caching']); is_deeply $i->traits, ['Caching'], 'one trait'; is $i->helper->{traits}, "['Caching']", 'one trait as string'; $i = instance(args => ['traits=Caching,Replicated']); is_deeply $i->traits, ['Caching', 'Replicated'], 'two traits'; is $i->helper->{traits}, "['Caching','Replicated']", 'two traits as string'; $i = instance(args => [$static]); is $i->create, 'static', 'create=static'; $i = instance(args => [$static, q{moniker_map={ authors => "AUTHORS", books => "BOOKS" }}] ); is_deeply $i->loader_args->{moniker_map}, { authors => 'AUTHORS', books => 'BOOKS' }, 'loader hash arg'; is $i->helper->{loader_args}{moniker_map}, q{{authors => "AUTHORS",books => "BOOKS"}}, 'loader hash arg as string'; $i = instance(args => [$static, q{foo=["bar","baz"]}]); is_deeply $i->loader_args->{foo}, ['bar', 'baz'], 'loader array arg'; is $i->helper->{loader_args}{foo}, q{["bar","baz"]}, 'loader array arg as string'; $i = instance(args => [$static, q{components=TimeStamp}]); is_deeply $i->components, ['InflateColumn::DateTime', 'TimeStamp'], 'extra component'; is $i->helper->{loader_args}{components}, q{["InflateColumn::DateTime","TimeStamp"]}, 'components as string'; $i = instance( schema_class => 'ASchemaClass', args => [$static, q{components=TimeStamp}] ); is_deeply $i->components, ['TimeStamp'], 'extra component with ->load_classes'; $i = instance(args => [$static, q{components=TimeStamp,Foo}]); is_deeply $i->components, ['InflateColumn::DateTime', 'TimeStamp', 'Foo'], 'two extra components'; # Different versions of perl and Data::Dumper serialise regexes differently my ($flagstart, $flagend, $postflag) = Dumper(qr//) =~ m{qr/(.*?)(\)?)/([a-z]*)}; $i = instance(args => [$static, q{constraint=^(foo|bar)$}]); is $i->loader_args->{constraint}, qr/^(foo|bar)$/, 'constraint loader arg'; is $i->helper->{loader_args}{constraint}, qq{qr/$flagstart^(foo|bar)\$$flagend/$postflag}, 'constraint loader arg as string'; $i = instance(args => [$static, q{exclude=^(foo|bar)$}]); is $i->loader_args->{exclude}, qr/^(foo|bar)$/, 'exclude loader arg'; $i = instance(args => [$static, q{db_schema=foo;bar::baz/quux}]); is $i->loader_args->{db_schema}, q{foo;bar::baz/quux}, 'simple value loader arg'; $i = instance(args => [ $static, 'components=TimeStamp', $sqlite, $on_connect_do, $quote_char, $name_sep ]); is_deeply $i->components, ['InflateColumn::DateTime', 'TimeStamp'], 'extra component'; is $i->connect_info->{dsn}, $sqlite, 'connect_info dsn'; is $i->connect_info->{user}, '', 'sqlite omitted user'; is $i->connect_info->{password}, '', 'sqlite omitted password'; is_deeply $i->connect_info->{on_connect_do}, ['select 1', 'select 2'], 'connect_info data struct'; is $i->helper->{connect_info}{on_connect_do}, q{["select 1", "select 2"]}, 'connect_info data struct as string'; is $i->connect_info->{quote_char}, '"', 'connect_info quote_char'; is $i->helper->{connect_info}{quote_char}, 'q{"}', 'connect_info quote_char as string'; is $i->connect_info->{name_sep}, '.', 'connect_info name_sep'; is $i->helper->{connect_info}{name_sep}, 'q{.}', 'connect_info name_sep as string'; $i = instance(args => [ $static, $sqlite, 'on_connect_do=PRAGMA foreign_keys = ON' ]); is $i->connect_info->{on_connect_do}, 'PRAGMA foreign_keys = ON', 'on_connect_do string'; is $i->helper->{connect_info}{on_connect_do}, 'q{PRAGMA foreign_keys = ON}', 'on_connect_do string as string'; $i = instance(args => [ $static, 'components=TimeStamp', $sqlite, '', $on_connect_do, $quote_char, $name_sep ]); is $i->connect_info->{dsn}, $sqlite, 'connect_info dsn'; is $i->connect_info->{user}, '', 'sqlite user'; is $i->connect_info->{password}, '', 'sqlite omitted password'; $i = instance(args => [ $static, 'components=TimeStamp', $pg, 'user', 'pass', $on_connect_do, $quote_char, $name_sep ]); is $i->connect_info->{dsn}, $pg, 'connect_info dsn'; is $i->connect_info->{user}, 'user', 'user'; is $i->connect_info->{password}, 'pass', 'password'; $i = instance(args => [ $static, $pg, 'user', 'pass', 'quote_char=[]', $name_sep ]); is_deeply $i->connect_info->{quote_char}, ['[', ']'], '2 character quote_char'; is $i->helper->{connect_info}{quote_char}, '["[","]"]', '2 character quote_char as string'; $i = instance(args => [ $static, 'components=TimeStamp', $sqlite, $on_connect_do, $quote_char, $name_sep, '{ auto_savepoint => 1, AutoCommit => 0 }' ]); is $i->connect_info->{auto_savepoint}, 1, 'connect_info arg from extra hash'; is $i->connect_info->{AutoCommit}, 0, 'connect_info arg from extra hash'; is $i->helper->{connect_info}{auto_savepoint}, 'q{1}', 'connect_info arg from extra hash as string'; is $i->helper->{connect_info}{AutoCommit}, 'q{0}', 'connect_info arg from extra hash as string'; $i = instance(args => [ $static, 'components=TimeStamp', $sqlite, $on_connect_do, $quote_char, $name_sep, 'auto_savepoint=1', 'AutoCommit=0', 'db_schema=myschema', ]); is $i->loader_args->{db_schema}, 'myschema', 'loader arg after connect_info'; ok ((not exists $i->helper->{connect_info}{db_schema}), 'loader args removed from connect_info'); done_testing; sub instance { Catalyst::Helper::Model::DBIC::Schema->new( schema_class => 'AnotherSchemaClass', helper => dclone($helper), args => ['create=static'], @_ ) } Catalyst-Model-DBIC-Schema-0.66/t/lib/000755 000766 000024 00000000000 14461412703 017461 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/06c3_issues.t000644 000766 000024 00000000462 14461407424 021154 0ustar00gknopstaff000000 000000 use strict; use warnings; use FindBin qw/$Bin/; use lib "$Bin/lib"; use Test::More tests => 1; # This fails for me on 5.8.8 with the following module versions: # # Class:C3 0.21 # Class::C3::Componentised 1.0005 # DBIx::Class 0.08013 (0.08099_05 works) use TestAppC3Fail; Catalyst-Model-DBIC-Schema-0.66/t/lib/PaxHeader/TestAppC3Fail.pm000644 000766 000024 00000000210 14461410560 024322 xustar00gknopstaff000000 000000 30 mtime=1690702192.148650891 57 LIBARCHIVE.xattr.com.apple.provenance=AQAAq1dlpUhBqgg 49 SCHILY.xattr.com.apple.provenance=«We„HAȘ Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail.pm000644 000766 000024 00000001146 14461410560 022362 0ustar00gknopstaff000000 000000 package TestAppC3Fail; use strict; use warnings; use Class::C3; # This causes the fail, saying use MRO::Compat is fine.. our $VERSION = '0.0001'; use Catalyst::Runtime 5.70; use Catalyst; __PACKAGE__->config( name => 'TestAppC3Fail', ); my @keys = sort keys( %{ __PACKAGE__->config } ); __PACKAGE__->setup; my @new_keys = sort # Ignore key added by horrid hack in Catalyst::Runtime 5.90080 grep { $_ ne '__configured_from_psgi_middleware'} keys( %{ __PACKAGE__->config } ); use Test::More; is_deeply(\@new_keys, \@keys, 'Config keys correct') or diag explain [\@keys, \@new_keys]; 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/ASchemaClass/000755 000766 000024 00000000000 14461412703 021750 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/ASchemaClass.pm000644 000766 000024 00000000210 14461407424 022303 0ustar00gknopstaff000000 000000 package ASchemaClass; use base 'DBIx::Class::Schema'; __PACKAGE__->load_classes; use Moose; has a_schema_option => (is => 'rw'); 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/AnotherSchemaClass.pm000644 000766 000024 00000000140 14461407424 023525 0ustar00gknopstaff000000 000000 package AnotherSchemaClass; use base 'DBIx::Class::Schema'; __PACKAGE__->load_namespaces; 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail/000755 000766 000024 00000000000 14461412703 022023 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/AnotherSchemaClass/000755 000766 000024 00000000000 14461412703 023170 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/AnotherSchemaClass/ResultSet/000755 000766 000024 00000000000 14461412703 025122 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/AnotherSchemaClass/Result/000755 000766 000024 00000000000 14461412703 024446 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/AnotherSchemaClass/Result/User.pm000644 000766 000024 00000001117 14461407424 025726 0ustar00gknopstaff000000 000000 package AnotherSchemaClass::Result::User; use strict; use warnings; use base 'DBIx::Class::Core'; __PACKAGE__->table("users"); __PACKAGE__->add_columns( "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, "first_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "middle_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "last_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "email_address", { data_type => "varchar", is_nullable => 1, size => 100 }, ); __PACKAGE__->set_primary_key("id"); 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/AnotherSchemaClass/ResultSet/User.pm000644 000766 000024 00000000272 14461407424 026403 0ustar00gknopstaff000000 000000 package AnotherSchemaClass::ResultSet::User; use strict; use warnings; use base 'DBIx::Class::ResultSet'; __PACKAGE__->mk_group_accessors(inherited => qw/ rs_config_option /); 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail/Schema/000755 000766 000024 00000000000 14461412703 023223 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail/Model/000755 000766 000024 00000000000 14461412703 023063 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail/Model/DB.pm000644 000766 000024 00000000355 14461407424 023715 0ustar00gknopstaff000000 000000 package TestAppC3Fail::Model::DB; use strict; use warnings; use base 'Catalyst::Model::DBIC::Schema'; __PACKAGE__->config( schema_class => 'TestAppC3Fail::Schema::DB', connect_info => [ 'DBI:SQLite:dbname=foo', '', '' ], ); 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail/Schema/DB/000755 000766 000024 00000000000 14461412703 023510 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail/Schema/DB.pm000644 000766 000024 00000000200 14461407424 024042 0ustar00gknopstaff000000 000000 package TestAppC3Fail::Schema::DB; use strict; use warnings; use base 'DBIx::Class::Schema'; __PACKAGE__->load_classes; 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/TestAppC3Fail/Schema/DB/User.pm000644 000766 000024 00000001116 14461407424 024767 0ustar00gknopstaff000000 000000 package TestAppC3Fail::Schema::DB::User; use strict; use warnings; use base 'DBIx::Class::Core'; __PACKAGE__->table("users"); __PACKAGE__->add_columns( "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, "first_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "middle_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "last_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "email_address", { data_type => "varchar", is_nullable => 1, size => 100 }, ); __PACKAGE__->set_primary_key("id"); 1; Catalyst-Model-DBIC-Schema-0.66/t/lib/ASchemaClass/User.pm000644 000766 000024 00000001101 14461407424 023221 0ustar00gknopstaff000000 000000 package ASchemaClass::User; use strict; use warnings; use base 'DBIx::Class::Core'; __PACKAGE__->table("users"); __PACKAGE__->add_columns( "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, "first_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "middle_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "last_name", { data_type => "varchar", is_nullable => 1, size => 100 }, "email_address", { data_type => "varchar", is_nullable => 1, size => 100 }, ); __PACKAGE__->set_primary_key("id"); 1; Catalyst-Model-DBIC-Schema-0.66/inc/Module/000755 000766 000024 00000000000 14461412703 020446 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/000755 000766 000024 00000000000 14461412703 022054 5ustar00gknopstaff000000 000000 Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install.pm000644 000766 000024 00000027145 14461412667 022434 0ustar00gknopstaff000000 000000 #line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.006; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.21'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::getcwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::getcwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $base_path = VMS::Filespec::unixify($base_path) if $^O eq 'VMS'; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( {no_chdir => 1, wanted => sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($File::Find::name); my $in_pod = 0; foreach ( split /\n/, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }}, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. Catalyst-Model-DBIC-Schema-0.66/inc/Module/AutoInstall.pm000644 000766 000024 00000062311 14461412670 023251 0ustar00gknopstaff000000 000000 #line 1 package Module::AutoInstall; use strict; use Cwd (); use File::Spec (); use ExtUtils::MakeMaker (); use vars qw{$VERSION}; BEGIN { $VERSION = '1.21'; } # special map on pre-defined feature sets my %FeatureMap = ( '' => 'Core Features', # XXX: deprecated '-core' => 'Core Features', ); # various lexical flags my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $InstallDepsTarget, $HasCPANPLUS ); my ( $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly, $AllDeps, $UpgradeDeps ); my ( $PostambleActions, $PostambleActionsNoTest, $PostambleActionsUpgradeDeps, $PostambleActionsUpgradeDepsNoTest, $PostambleActionsListDeps, $PostambleActionsListAllDeps, $PostambleUsed, $NoTest); # See if it's a testing or non-interactive session _accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); _init(); sub _accept_default { $AcceptDefault = shift; } sub _installdeps_target { $InstallDepsTarget = shift; } sub missing_modules { return @Missing; } sub do_install { __PACKAGE__->install( [ $Config ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) : () ], @Missing, ); } # initialize various flags, and/or perform install sub _init { foreach my $arg ( @ARGV, split( /[\s\t]+/, $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' ) ) { if ( $arg =~ /^--config=(.*)$/ ) { $Config = [ split( ',', $1 ) ]; } elsif ( $arg =~ /^--installdeps=(.*)$/ ) { __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--upgradedeps=(.*)$/ ) { $UpgradeDeps = 1; __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--default(?:deps)?$/ ) { $AcceptDefault = 1; } elsif ( $arg =~ /^--check(?:deps)?$/ ) { $CheckOnly = 1; } elsif ( $arg =~ /^--skip(?:deps)?$/ ) { $SkipInstall = 1; } elsif ( $arg =~ /^--test(?:only)?$/ ) { $TestOnly = 1; } elsif ( $arg =~ /^--all(?:deps)?$/ ) { $AllDeps = 1; } } } # overrides MakeMaker's prompt() to automatically accept the default choice sub _prompt { goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; my ( $prompt, $default ) = @_; my $y = ( $default =~ /^[Yy]/ ); print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; print "$default\n"; return $default; } # the workhorse sub import { my $class = shift; my @args = @_ or return; my $core_all; print "*** $class version " . $class->VERSION . "\n"; print "*** Checking for Perl dependencies...\n"; my $cwd = Cwd::getcwd(); $Config = []; my $maxlen = length( ( sort { length($b) <=> length($a) } grep { /^[^\-]/ } map { ref($_) ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) : '' } map { +{@args}->{$_} } grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } )[0] ); # We want to know if we're under CPAN early to avoid prompting, but # if we aren't going to try and install anything anyway then skip the # check entirely since we don't want to have to load (and configure) # an old CPAN just for a cosmetic message $UnderCPAN = _check_lock(1) unless $SkipInstall || $InstallDepsTarget; while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { my ( @required, @tests, @skiptests ); my $default = 1; my $conflict = 0; if ( $feature =~ m/^-(\w+)$/ ) { my $option = lc($1); # check for a newer version of myself _update_to( $modules, @_ ) and return if $option eq 'version'; # sets CPAN configuration options $Config = $modules if $option eq 'config'; # promote every features to core status $core_all = ( $modules =~ /^all$/i ) and next if $option eq 'core'; next unless $option eq 'core'; } print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); unshift @$modules, -default => &{ shift(@$modules) } if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward compatibility while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { if ( $mod =~ m/^-(\w+)$/ ) { my $option = lc($1); $default = $arg if ( $option eq 'default' ); $conflict = $arg if ( $option eq 'conflict' ); @tests = @{$arg} if ( $option eq 'tests' ); @skiptests = @{$arg} if ( $option eq 'skiptests' ); next; } printf( "- %-${maxlen}s ...", $mod ); if ( $arg and $arg =~ /^\D/ ) { unshift @$modules, $arg; $arg = 0; } # XXX: check for conflicts and uninstalls(!) them. my $cur = _version_of($mod); if (_version_cmp ($cur, $arg) >= 0) { print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; push @Existing, $mod => $arg; $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { if (not defined $cur) # indeed missing { print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; } else { # no need to check $arg as _version_cmp ($cur, undef) would satisfy >= above print "too old. ($cur < $arg)\n"; } push @required, $mod => $arg; } } next unless @required; my $mandatory = ( $feature eq '-core' or $core_all ); if ( !$SkipInstall and ( $CheckOnly or ($mandatory and $UnderCPAN) or $AllDeps or $InstallDepsTarget or _prompt( qq{==> Auto-install the } . ( @required / 2 ) . ( $mandatory ? ' mandatory' : ' optional' ) . qq{ module(s) from CPAN?}, $default ? 'y' : 'n', ) =~ /^[Yy]/ ) ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } elsif ( !$SkipInstall and $default and $mandatory and _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) =~ /^[Nn]/ ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { $DisabledTests{$_} = 1 for map { glob($_) } @tests; } } if ( @Missing and not( $CheckOnly or $UnderCPAN) ) { require Config; my $make = $Config::Config{make}; if ($InstallDepsTarget) { print "*** To install dependencies type '$make installdeps' or '$make installdeps_notest'.\n"; } else { print "*** Dependencies will be installed the next time you type '$make'.\n"; } # make an educated guess of whether we'll need root permission. print " (You may need to do that as the 'root' user.)\n" if eval '$>'; } print "*** $class configuration finished.\n"; chdir $cwd; # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; return (@Existing, @Missing); } sub _running_under { my $thing = shift; print <<"END_MESSAGE"; *** Since we're running under ${thing}, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } # Check to see if we are currently running under CPAN.pm and/or CPANPLUS; # if we are, then we simply let it taking care of our dependencies sub _check_lock { return unless @Missing or @_; if ($ENV{PERL5_CPANM_IS_RUNNING}) { return _running_under('cpanminus'); } my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING}; if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { return _running_under($cpan_env ? 'CPAN' : 'CPANPLUS'); } require CPAN; if ($CPAN::VERSION > '1.89') { if ($cpan_env) { return _running_under('CPAN'); } return; # CPAN.pm new enough, don't need to check further } # last ditch attempt, this -will- configure CPAN, very sorry _load_cpan(1); # force initialize even though it's already loaded # Find the CPAN lock-file my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); return unless -f $lock; # Check the lock local *LOCK; return unless open(LOCK, $lock); if ( ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' ) { print <<'END_MESSAGE'; *** Since we're running under CPAN, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } close LOCK; return; } sub install { my $class = shift; my $i; # used below to strip leading '-' from config keys my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); my ( @modules, @installed, @modules_to_upgrade ); while (my ($pkg, $ver) = splice(@_, 0, 2)) { # grep out those already installed if (_version_cmp(_version_of($pkg), $ver) >= 0) { push @installed, $pkg; if ($UpgradeDeps) { push @modules_to_upgrade, $pkg, $ver; } } else { push @modules, $pkg, $ver; } } if ($UpgradeDeps) { push @modules, @modules_to_upgrade; @installed = (); @modules_to_upgrade = (); } return @installed unless @modules; # nothing to do return @installed if _check_lock(); # defer to the CPAN shell print "*** Installing dependencies...\n"; return unless _connected_to('cpan.org'); my %args = @config; my %failed; local *FAILED; if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { while () { chomp; $failed{$_}++ } close FAILED; my @newmod; while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { push @newmod, ( $k => $v ) unless $failed{$k}; } @modules = @newmod; } if ( _has_cpanplus() and not $ENV{PERL_AUTOINSTALL_PREFER_CPAN} ) { _install_cpanplus( \@modules, \@config ); } else { _install_cpan( \@modules, \@config ); } print "*** $class installation finished.\n"; # see if we have successfully installed them while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { print FAILED "$pkg\n"; } } close FAILED if $args{do_once}; return @installed; } sub _install_cpanplus { my @modules = @{ +shift }; my @config = _cpanplus_config( @{ +shift } ); my $installed = 0; require CPANPLUS::Backend; my $cp = CPANPLUS::Backend->new; my $conf = $cp->configure_object; return unless $conf->can('conf') # 0.05x+ with "sudo" support or _can_write($conf->_get_build('base')); # 0.04x # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $conf->get_conf('makeflags') || ''; if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { # 0.03+ uses a hashref here $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; } else { # 0.02 and below uses a scalar $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); } $conf->set_conf( makeflags => $makeflags ); $conf->set_conf( prereqs => 1 ); while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { $conf->set_conf( $key, $val ); } my $modtree = $cp->module_tree; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { print "*** Installing $pkg...\n"; MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; my $success; my $obj = $modtree->{$pkg}; if ( $obj and _version_cmp( $obj->{version}, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $cp->install( modules => [ $obj->{module} ] ); if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation cancelled.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _cpanplus_config { my @config = (); while ( @_ ) { my ($key, $value) = (shift(), shift()); if ( $key eq 'prerequisites_policy' ) { if ( $value eq 'follow' ) { $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); } elsif ( $value eq 'ask' ) { $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); } elsif ( $value eq 'ignore' ) { $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); } else { die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; } push @config, 'prereqs', $value; } elsif ( $key eq 'force' ) { push @config, $key, $value; } elsif ( $key eq 'notest' ) { push @config, 'skiptest', $value; } else { die "*** Cannot convert option $key to CPANPLUS version.\n"; } } return @config; } sub _install_cpan { my @modules = @{ +shift }; my @config = @{ +shift }; my $installed = 0; my %args; _load_cpan(); require Config; if (CPAN->VERSION < 1.80) { # no "sudo" support, probe for writableness return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) and _can_write( $Config::Config{sitelib} ); } # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $CPAN::Config->{make_install_arg} || ''; $CPAN::Config->{make_install_arg} = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); # don't show start-up info $CPAN::Config->{inhibit_startup_message} = 1; # set additional options while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { ( $args{$opt} = $arg, next ) if $opt =~ /^(?:force|notest)$/; # pseudo-option $CPAN::Config->{$opt} = $opt eq 'urllist' ? [$arg] : $arg; } if ($args{notest} && (not CPAN::Shell->can('notest'))) { die "Your version of CPAN is too old to support the 'notest' pragma"; } local $CPAN::Config->{prerequisites_policy} = 'follow'; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; print "*** Installing $pkg...\n"; my $obj = CPAN::Shell->expand( Module => $pkg ); my $success = 0; if ( $obj and _version_cmp( $obj->cpan_version, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = do { if ($args{force}) { CPAN::Shell->force( install => $pkg ) } elsif ($args{notest}) { CPAN::Shell->notest( install => $pkg ) } else { CPAN::Shell->install($pkg) } }; $rv ||= eval { $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) ->{install} if $CPAN::META; }; if ( $rv eq 'YES' ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation failed.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _has_cpanplus { return ( $HasCPANPLUS = ( $INC{'CPANPLUS/Config.pm'} or _load('CPANPLUS::Shell::Default') ) ); } # make guesses on whether we're under the CPAN installation directory sub _under_cpan { require Cwd; require File::Spec; my $cwd = File::Spec->canonpath( Cwd::getcwd() ); my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); return ( index( $cwd, $cpan ) > -1 ); } sub _update_to { my $class = __PACKAGE__; my $ver = shift; return if _version_cmp( _version_of($class), $ver ) >= 0; # no need to upgrade if ( _prompt( "==> A newer version of $class ($ver) is required. Install?", 'y' ) =~ /^[Nn]/ ) { die "*** Please install $class $ver manually.\n"; } print << "."; *** Trying to fetch it from CPAN... . # install ourselves _load($class) and return $class->import(@_) if $class->install( [], $class, $ver ); print << '.'; exit 1; *** Cannot bootstrap myself. :-( Installation terminated. . } # check if we're connected to some host, using inet_aton sub _connected_to { my $site = shift; return ( ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( qq( *** Your host cannot resolve the domain name '$site', which probably means the Internet connections are unavailable. ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/ ); } # check if a directory is writable; may create it on demand sub _can_write { my $path = shift; mkdir( $path, 0755 ) unless -e $path; return 1 if -w $path; print << "."; *** You are not allowed to write to the directory '$path'; the installation may fail due to insufficient permissions. . if ( eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( qq( ==> Should we try to re-execute the autoinstall process with 'sudo'?), ((-t STDIN) ? 'y' : 'n') ) =~ /^[Yy]/ ) { # try to bootstrap ourselves from sudo print << "."; *** Trying to re-execute the autoinstall process with 'sudo'... . my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; return unless system( 'sudo', $^X, $0, "--config=$config", "--installdeps=$missing" ); print << "."; *** The 'sudo' command exited with error! Resuming... . } return _prompt( qq( ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/; } # load a module and return the version it reports sub _load { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; local $@; return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); } # report version without loading a module sub _version_of { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; foreach my $dir ( @INC ) { next if ref $dir; my $path = File::Spec->catfile($dir, $file); next unless -e $path; require ExtUtils::MM_Unix; return ExtUtils::MM_Unix->parse_version($path); } return undef; } # Load CPAN.pm and it's configuration sub _load_cpan { return if $CPAN::VERSION and $CPAN::Config and not @_; require CPAN; # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to # CPAN::HandleConfig->load. CPAN reports that the redirection # is deprecated in a warning printed at the user. # CPAN-1.81 expects CPAN::HandleConfig->load, does not have # $CPAN::HandleConfig::VERSION but cannot handle # CPAN::Config->load # Which "versions expect CPAN::Config->load? if ( $CPAN::HandleConfig::VERSION || CPAN::HandleConfig->can('load') ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { # Older versions had the load method in Config directly CPAN::Config->load; } } # compare two versions, either use Sort::Versions or plain comparison # return values same as <=> sub _version_cmp { my ( $cur, $min ) = @_; return -1 unless defined $cur; # if 0 keep comparing return 1 unless $min; $cur =~ s/\s+$//; # check for version numbers that are not in decimal format if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { if ( ( $version::VERSION or defined( _load('version') )) and version->can('new') ) { # use version.pm if it is installed. return version->new($cur) <=> version->new($min); } elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) { # use Sort::Versions as the sorting algorithm for a.b.c versions return Sort::Versions::versioncmp( $cur, $min ); } warn "Cannot reliably compare non-decimal formatted versions.\n" . "Please install version.pm or Sort::Versions.\n"; } # plain comparison local $^W = 0; # shuts off 'not numeric' bugs return $cur <=> $min; } # nothing; this usage is deprecated. sub main::PREREQ_PM { return {}; } sub _make_args { my %args = @_; $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } if $UnderCPAN or $TestOnly; if ( $args{EXE_FILES} and -e 'MANIFEST' ) { require ExtUtils::Manifest; my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); $args{EXE_FILES} = [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; } $args{test}{TESTS} ||= 't/*.t'; $args{test}{TESTS} = join( ' ', grep { !exists( $DisabledTests{$_} ) } map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; $PostambleActions = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); my $deps_list = join( ',', @Missing, @Existing ); $PostambleActionsUpgradeDeps = "\$(PERL) $0 --config=$config --upgradedeps=$deps_list"; my $config_notest = join( ',', (UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config}), 'notest', 1 ) if $Config; $PostambleActionsNoTest = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config_notest --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); $PostambleActionsUpgradeDepsNoTest = "\$(PERL) $0 --config=$config_notest --upgradedeps=$deps_list"; $PostambleActionsListDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $Missing[$_], grep $_ % 2 == 0, 0..$#Missing); my @all = (@Missing, @Existing); $PostambleActionsListAllDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $all[$_], grep $_ % 2 == 0, 0..$#all); return %args; } # a wrapper to ExtUtils::MakeMaker::WriteMakefile sub Write { require Carp; Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; if ($CheckOnly) { print << "."; *** Makefile not written in check-only mode. . return; } my %args = _make_args(@_); no strict 'refs'; $PostambleUsed = 0; local *MY::postamble = \&postamble unless defined &MY::postamble; ExtUtils::MakeMaker::WriteMakefile(%args); print << "." unless $PostambleUsed; *** WARNING: Makefile written with customized MY::postamble() without including contents from Module::AutoInstall::postamble() -- auto installation features disabled. Please contact the author. . return 1; } sub postamble { $PostambleUsed = 1; my $fragment; $fragment .= <<"AUTO_INSTALL" if !$InstallDepsTarget; config :: installdeps \t\$(NOECHO) \$(NOOP) AUTO_INSTALL $fragment .= <<"END_MAKE"; checkdeps :: \t\$(PERL) $0 --checkdeps installdeps :: \t$PostambleActions installdeps_notest :: \t$PostambleActionsNoTest upgradedeps :: \t$PostambleActionsUpgradeDeps upgradedeps_notest :: \t$PostambleActionsUpgradeDepsNoTest listdeps :: \t$PostambleActionsListDeps listalldeps :: \t$PostambleActionsListAllDeps END_MAKE return $fragment; } 1; __END__ #line 1197 Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/Win32.pm000644 000766 000024 00000003403 14461412670 023317 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/Can.pm000644 000766 000024 00000006405 14461412670 023123 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; if ($^O eq 'VMS') { require ExtUtils::CBuilder; my $builder = ExtUtils::CBuilder->new( quiet => 1, ); return $builder->have_compiler; } my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 245 Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/Fetch.pm000644 000766 000024 00000004627 14461412670 023457 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/Makefile.pm000644 000766 000024 00000027437 14461412667 024155 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-separated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/WriteAll.pm000644 000766 000024 00000002376 14461412670 024150 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1; Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/AutoInstall.pm000644 000766 000024 00000004162 14461412670 024657 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::AutoInstall; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub AutoInstall { $_[0] } sub run { my $self = shift; $self->auto_install_now(@_); } sub write { my $self = shift; $self->auto_install(@_); } sub auto_install { my $self = shift; return if $self->{done}++; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->build_requires, $self->requires; my @config = @_; # We'll need Module::AutoInstall $self->include('Module::AutoInstall'); require Module::AutoInstall; my @features_require = Module::AutoInstall->import( (@config ? (-config => \@config) : ()), (@core ? (-core => \@core) : ()), $self->features, ); my %seen; my @requires = map @$_, map @$_, grep ref, $self->requires; while (my ($mod, $ver) = splice(@requires, 0, 2)) { $seen{$mod}{$ver}++; } my @build_requires = map @$_, map @$_, grep ref, $self->build_requires; while (my ($mod, $ver) = splice(@build_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires; while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @deduped; while (my ($mod, $ver) = splice(@features_require, 0, 2)) { push @deduped, $mod => $ver unless $seen{$mod}{$ver}++; } $self->requires(@deduped); $self->makemaker_args( Module::AutoInstall::_make_args() ); my $class = ref($self); $self->postamble( "# --- $class section:\n" . Module::AutoInstall::postamble() ); } sub installdeps_target { my ($self, @args) = @_; $self->include('Module::AutoInstall'); require Module::AutoInstall; Module::AutoInstall::_installdeps_target(1); $self->auto_install(@args); } sub auto_install_now { my $self = shift; $self->auto_install(@_); Module::AutoInstall::do_install(); } 1; Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/Include.pm000644 000766 000024 00000001015 14461412670 023775 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::Include; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub include { shift()->admin->include(@_); } sub include_deps { shift()->admin->include_deps(@_); } sub auto_include { shift()->admin->auto_include(@_); } sub auto_include_deps { shift()->admin->auto_include_deps(@_); } sub auto_include_dependent_dists { shift()->admin->auto_include_dependent_dists(@_); } 1; Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/Metadata.pm000644 000766 000024 00000043437 14461412667 024156 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) [\s|;]* /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', artistic => 'http://opensource.org/licenses/artistic-license.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, # these are not actually allowed in meta-spec v1.4 but are left here for compatibility: apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashes delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; Catalyst-Model-DBIC-Schema-0.66/inc/Module/Install/Base.pm000644 000766 000024 00000002147 14461412667 023301 0ustar00gknopstaff000000 000000 #line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.21'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159