Merge 'DBIx-Class-current' into 'trunk'
Matt S Trout [Sun, 17 Jun 2007 19:27:08 +0000 (19:27 +0000)]
0.08000 release commit

Changes
Makefile.PL
lib/DBIx/Class.pm
lib/DBIx/Class/AccessorGroup.pm [new file with mode: 0644]
lib/DBIx/Class/Schema.pm
lib/DBIx/Class/Schema/Versioned.pm
lib/DBIx/Class/Serialize/Storable.pm [new file with mode: 0644]
t/03podcoverage.t

diff --git a/Changes b/Changes
index f5f80ad..47a3f59 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,6 @@
 Revision history for DBIx::Class
 
+0.08000 2007-06-17 18:06:12
         - Fixed DBIC_TRACE debug filehandles to set ->autoflush(1)
         - Fixed circular dbh<->storage in HandleError with weakref
 
@@ -72,7 +73,7 @@ Revision history for DBIx::Class
         - add support to Ordered for multiple ordering columns
         - mark DB.pm and compose_connection as deprecated
         - switch tests to compose_namespace
-        - ResltClass::HashRefInflator added
+        - ResultClass::HashRefInflator added
         - Changed row and rs objects to not have direct handle to a source,
           instead a (schema,source_name) tuple of type ResultSourceHandle
 
index 00e5c25..a3375b6 100644 (file)
@@ -1,4 +1,4 @@
-use inc::Module::Install 0.64;
+use inc::Module::Install 0.67;
 
 name     'DBIx-Class';
 all_from 'lib/DBIx/Class.pm';
index be108a4..d4fbada 100644 (file)
@@ -18,7 +18,7 @@ sub component_base_class { 'DBIx::Class' }
 # i.e. first release of 0.XX *must* be 0.XX000. This avoids fBSD ports
 # brain damage and presumably various other packaging systems too
 
-$VERSION = '0.07999_06';
+$VERSION = '0.08000';
 
 sub MODIFY_CODE_ATTRIBUTES {
   my ($class,$code,@attrs) = @_;
diff --git a/lib/DBIx/Class/AccessorGroup.pm b/lib/DBIx/Class/AccessorGroup.pm
new file mode 100644 (file)
index 0000000..56bcf1b
--- /dev/null
@@ -0,0 +1,342 @@
+package DBIx::Class::AccessorGroup;
+
+use strict;
+use warnings;
+
+use Carp::Clan qw/^DBIx::Class/;
+
+=head1 NAME
+
+DBIx::Class::AccessorGroup -  Lets you build groups of accessors
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+This class lets you build groups of accessors that will call different
+getters and setters.
+
+=head1 METHODS
+
+=head2 mk_group_accessors
+
+=over 4
+
+=item Arguments: $group, @fieldspec
+
+Returns: none
+
+=back
+
+Creates a set of accessors in a given group.
+
+$group is the name of the accessor group for the generated accessors; they
+will call get_$group($field) on get and set_$group($field, $value) on set.
+
+@fieldspec is a list of field/accessor names; if a fieldspec is a scalar
+this is used as both field and accessor name, if a listref it is expected to
+be of the form [ $accessor, $field ].
+
+=cut
+
+sub mk_group_accessors {
+  my ($self, $group, @fields) = @_;
+
+  $self->_mk_group_accessors('make_group_accessor', $group, @fields);
+  return;
+}
+
+
+{
+    no strict 'refs';
+    no warnings 'redefine';
+
+    sub _mk_group_accessors {
+        my($self, $maker, $group, @fields) = @_;
+        my $class = ref $self || $self;
+
+        # So we don't have to do lots of lookups inside the loop.
+        $maker = $self->can($maker) unless ref $maker;
+
+        foreach my $field (@fields) {
+            if( $field eq 'DESTROY' ) {
+                carp("Having a data accessor named DESTROY  in ".
+                             "'$class' is unwise.");
+            }
+
+            my $name = $field;
+
+            ($name, $field) = @$field if ref $field;
+
+            my $accessor = $self->$maker($group, $field);
+            my $alias = "_${name}_accessor";
+
+            #warn "$class $group $field $alias";
+
+            *{$class."\:\:$name"}  = $accessor;
+              #unless defined &{$class."\:\:$field"}
+
+            *{$class."\:\:$alias"}  = $accessor;
+              #unless defined &{$class."\:\:$alias"}
+        }
+    }
+}
+
+=head2 mk_group_ro_accessors
+
+=over 4
+
+=item Arguments: $group, @fieldspec
+
+Returns: none
+
+=back
+
+Creates a set of read only accessors in a given group. Identical to
+<L:/mk_group_accessors> but accessors will throw an error if passed a value
+rather than setting the value.
+
+=cut
+
+sub mk_group_ro_accessors {
+    my($self, $group, @fields) = @_;
+
+    $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
+}
+
+=head2 mk_group_wo_accessors
+
+=over 4
+
+=item Arguments: $group, @fieldspec
+
+Returns: none
+
+=back
+
+Creates a set of write only accessors in a given group. Identical to
+<L:/mk_group_accessors> but accessors will throw an error if not passed a
+value rather than getting the value.
+
+=cut
+
+sub mk_group_wo_accessors {
+    my($self, $group, @fields) = @_;
+
+    $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
+}
+
+=head2 make_group_accessor
+
+=over 4
+
+=item Arguments: $group, $field
+
+Returns: $sub (\CODE)
+
+=back
+
+Returns a single accessor in a given group; called by mk_group_accessors
+for each entry in @fieldspec.
+
+=cut
+
+sub make_group_accessor {
+    my ($class, $group, $field) = @_;
+
+    my $set = "set_$group";
+    my $get = "get_$group";
+
+    # Build a closure around $field.
+    return sub {
+        my $self = shift;
+
+        if(@_) {
+            return $self->$set($field, @_);
+        }
+        else {
+            return $self->$get($field);
+        }
+    };
+}
+
+=head2 make_group_ro_accessor
+
+=over 4
+
+=item Arguments: $group, $field
+
+Returns: $sub (\CODE)
+
+=back
+
+Returns a single read-only accessor in a given group; called by
+mk_group_ro_accessors for each entry in @fieldspec.
+
+=cut
+
+sub make_group_ro_accessor {
+    my($class, $group, $field) = @_;
+
+    my $get = "get_$group";
+
+    return sub {
+        my $self = shift;
+
+        if(@_) {
+            my $caller = caller;
+            croak("'$caller' cannot alter the value of '$field' on ".
+                        "objects of class '$class'");
+        }
+        else {
+            return $self->$get($field);
+        }
+    };
+}
+
+=head2 make_group_wo_accessor
+
+=over 4
+
+=item Arguments: $group, $field
+
+Returns: $sub (\CODE)
+
+=back
+
+Returns a single write-only accessor in a given group; called by
+mk_group_wo_accessors for each entry in @fieldspec.
+
+=cut
+
+sub make_group_wo_accessor {
+    my($class, $group, $field) = @_;
+
+    my $set = "set_$group";
+
+    return sub {
+        my $self = shift;
+
+        unless (@_) {
+            my $caller = caller;
+            croak("'$caller' cannot access the value of '$field' on ".
+                        "objects of class '$class'");
+        }
+        else {
+            return $self->$set($field, @_);
+        }
+    };
+}
+
+=head2 get_simple
+
+=over 4
+
+=item Arguments: $field
+
+Returns: $value
+
+=back
+
+Simple getter for hash-based objects which returns the value for the field
+name passed as an argument.
+
+=cut
+
+sub get_simple {
+  my ($self, $get) = @_;
+  return $self->{$get};
+}
+
+=head2 set_simple
+
+=over 4
+
+=item Arguments: $field, $new_value
+
+Returns: $new_value
+
+=back
+
+Simple setter for hash-based objects which sets and then returns the value
+for the field name passed as an argument.
+
+=cut
+
+sub set_simple {
+  my ($self, $set, $val) = @_;
+  return $self->{$set} = $val;
+}
+
+=head2 get_component_class
+
+=over 4
+
+=item Arguments: $name
+
+Returns: $component_class
+
+=back
+
+Returns the class name for a component; returns an object key if called on
+an object, or attempts to return classdata referenced by _$name if called
+on a class.
+
+=cut
+
+sub get_component_class {
+  my ($self, $get) = @_;
+  if (ref $self) {
+      return $self->{$get};
+  } else {
+      $get = "_$get";
+      return $self->can($get) ? $self->$get : undef;
+  }
+}
+
+=head2 set_component_class
+
+=over 4
+
+=item Arguments: $name, $new_component_class
+
+Returns: $new_component_class
+
+=back
+
+Sets a component class name; attempts to require the class before setting
+but does not error if unable to do so. Sets an object key of the given name
+if called or an object or classdata called _$name if called on a class.
+
+=cut
+
+sub set_component_class {
+  my ($self, $set, $val) = @_;
+  eval "require $val";
+  if ($@) {
+      my $val_path = $val;
+      $val_path =~ s{::}{/}g;
+      carp $@ unless $@ =~ /^Can't locate $val_path\.pm/;
+  }
+  if (ref $self) {
+      return $self->{$set} = $val;
+  } else {
+      $set = "_$set";
+      return $self->can($set) ?
+        $self->$set($val) :
+        $self->mk_classdata($set => $val);
+  }
+}
+
+1;
+
+=head1 AUTHORS
+
+Matt S. Trout <mst@shadowcatsystems.co.uk>
+
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself.
+
+=cut
+
index e7064df..99b7f28 100644 (file)
@@ -679,7 +679,6 @@ sub connection {
   my $storage = $storage_class->new($self);
   $storage->connect_info(\@info);
   $self->storage($storage);
-  $self->on_connect() if($self->can('on_connect'));
   return $self;
 }
 
index dd297ff..ea662b3 100644 (file)
@@ -60,7 +60,7 @@ sub schema_version {
   return $version;
 }
 
-sub on_connect
+sub _on_connect
 {
     my ($self) = @_;
     my $vschema = DBIx::Class::Version->connect(@{$self->storage->connect_info()});
diff --git a/lib/DBIx/Class/Serialize/Storable.pm b/lib/DBIx/Class/Serialize/Storable.pm
new file mode 100644 (file)
index 0000000..7ccd2b0
--- /dev/null
@@ -0,0 +1,68 @@
+package DBIx::Class::Serialize::Storable;
+use strict;
+use warnings;
+use Storable;
+
+sub STORABLE_freeze {
+    my ($self,$cloning) = @_;
+    my $to_serialize = { %$self };
+    delete $to_serialize->{result_source};
+    return (Storable::freeze($to_serialize));
+}
+
+sub STORABLE_thaw {
+    my ($self,$cloning,$serialized) = @_;
+    %$self = %{ Storable::thaw($serialized) };
+    $self->result_source($self->result_source_instance)
+      if $self->can('result_source_instance');
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+    DBIx::Class::Serialize::Storable - hooks for Storable freeze/thaw
+
+=head1 SYNOPSIS
+
+    # in a table class definition
+    __PACKAGE__->load_components(qw/Serialize::Storable/);
+
+    # meanwhile, in a nearby piece of code
+    my $cd = $schema->resultset('CD')->find(12);
+    # if the cache uses Storable, this will work automatically
+    $cache->set($cd->ID, $cd);
+
+=head1 DESCRIPTION
+
+This component adds hooks for Storable so that row objects can be
+serialized. It assumes that your row object class (C<result_class>) is
+the same as your table class, which is the normal situation.
+
+=head1 HOOKS
+
+The following hooks are defined for L<Storable> - see the
+documentation for L<Storable/Hooks> for detailed information on these
+hooks.
+
+=head2 STORABLE_freeze
+
+The serializing hook, called on the object during serialization. It
+can be inherited, or defined in the class itself, like any other
+method.
+
+=head2 STORABLE_thaw
+
+The deserializing hook called on the object during deserialization.
+
+=head1 AUTHORS
+
+David Kamholz <dkamholz@cpan.org>
+
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself.
+
+=cut
index 2530be2..106fece 100644 (file)
@@ -70,6 +70,18 @@ my $exceptions = {
     'DBIx::Class::Storage::DBI::mysql'                  => { skip => 1 },
     'SQL::Translator::Parser::DBIx::Class'              => { skip => 1 },
     'SQL::Translator::Producer::DBIx::Class::File'      => { skip => 1 },
+
+# skipped because the synopsis covers it clearly
+
+    'DBIx::Class::InflateColumn::File'                  => { skip => 1 },
+
+# skipped because two methods may not need to be public
+
+    'DBIx::Class::Schema::Versioned' => { ignore => [ qw(on_connect exists) ] },
+
+# must kill authors.
+
+    'DBIx::Class::Storage::DBI::Replication' => { skip => 1 },
 };
 
 foreach my $module (@modules) {