diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-01-31 02:13:12 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-01-31 02:13:12 +0000 |
commit | 7446bb2b9d24fa6b702fbb62d73084a32ade6f75 (patch) | |
tree | 50037edde1d3cde3aaa25e759cd39975841ca663 /README | |
download | Class-Tiny-tarball-Class-Tiny-1.001.tar.gz |
Class-Tiny-1.001HEADClass-Tiny-1.001master
Diffstat (limited to 'README')
-rw-r--r-- | README | 359 |
1 files changed, 359 insertions, 0 deletions
@@ -0,0 +1,359 @@ +NAME + Class::Tiny - Minimalist class construction + +VERSION + version 1.001 + +SYNOPSIS + In Person.pm: + + package Person; + + use Class::Tiny qw( name ); + + 1; + + In Employee.pm: + + package Employee; + use parent 'Person'; + + use Class::Tiny qw( ssn ), { + timestamp => sub { time } # attribute with default + }; + + 1; + + In example.pl: + + use Employee; + + my $obj = Employee->new( name => "Larry", ssn => "111-22-3333" ); + + # unknown attributes are ignored + my $obj = Employee->new( name => "Larry", OS => "Linux" ); + # $obj->{OS} does not exist + +DESCRIPTION + This module offers a minimalist class construction kit in around 120 + lines of code. Here is a list of features: + + * defines attributes via import arguments + + * generates read-write accessors + + * supports lazy attribute defaults + + * supports custom accessors + + * superclass provides a standard "new" constructor + + * "new" takes a hash reference or list of key/value pairs + + * "new" supports providing "BUILDARGS" to customize constructor + options + + * "new" calls "BUILD" for each class from parent to child + + * superclass provides a "DESTROY" method + + * "DESTROY" calls "DEMOLISH" for each class from child to parent + + Multiple-inheritance is possible, with superclass order determined via + mro::get_linear_isa. + + It uses no non-core modules for any recent Perl. On Perls older than + v5.10 it requires MRO::Compat. On Perls older than v5.14, it requires + Devel::GlobalDestruction. + +USAGE + Defining attributes + Define attributes as a list of import arguments: + + package Foo::Bar; + + use Class::Tiny qw( + name + id + height + weight + ); + + For each attribute, a read-write accessor is created unless a subroutine + of that name already exists: + + $obj->name; # getter + $obj->name( "John Doe" ); # setter + + Attribute names must be valid subroutine identifiers or an exception + will be thrown. + + You can specify lazy defaults by defining attributes with a hash + reference. Keys define attribute names and values are constants or code + references that will be evaluated when the attribute is first accessed + if no value has been set. The object is passed as an argument to a code + reference. + + package Foo::WithDefaults; + + use Class::Tiny qw/name id/, { + title => 'Peon', + skills => sub { [] }, + hire_date => sub { $_[0]->_build_hire_date }, + }; + + When subclassing, if multiple accessors of the same name exist in + different classes, any default (or lack of default) is determined by + standard method resolution order. + + To make your own custom accessors, just pre-declare the method name + before loading Class::Tiny: + + package Foo::Bar; + + use subs 'id'; + + use Class::Tiny qw( name id ); + + sub id { ... } + + Even if you pre-declare a method name, you must include it in the + attribute list for Class::Tiny to register it as a valid attribute. + + If you set a default for a custom accessor, your accessor will need to + retrieve the default and do something with it: + + package Foo::Bar; + + use subs 'id'; + + use Class::Tiny qw( name ), { id => sub { int(rand(2*31)) } }; + + sub id { + my $self = shift; + if (@_) { + return $self->{id} = shift; + } + elsif ( exists $self->{id} ) { + return $self->{id}; + } + else { + my $defaults = + Class::Tiny->get_all_attribute_defaults_for( ref $self ); + return $self->{id} = $defaults->{id}->(); + } + } + + Class::Tiny::Object is your base class + If your class does not already inherit from some class, then + Class::Tiny::Object will be added to your @ISA to provide "new" and + "DESTROY". + + If your class does inherit from something, then no additional + inheritance is set up. If the parent subclasses Class::Tiny::Object, + then all is well. If not, then you'll get accessors set up but no + constructor or destructor. Don't do that unless you really have a + special need for it. + + Define subclasses as normal. It's best to define them with base, parent + or superclass before defining attributes with Class::Tiny so the @ISA + array is already populated at compile-time: + + package Foo::Bar::More; + + use parent 'Foo::Bar'; + + use Class::Tiny qw( shoe_size ); + + Object construction + If your class inherits from Class::Tiny::Object (as it should if you + followed the advice above), it provides the "new" constructor for you. + + Objects can be created with attributes given as a hash reference or as a + list of key/value pairs: + + $obj = Foo::Bar->new( name => "David" ); + + $obj = Foo::Bar->new( { name => "David" } ); + + If a reference is passed as a single argument, it must be able to be + dereferenced as a hash or an exception is thrown. + + Unknown attributes in the constructor arguments will be ignored. Prior + to version 1.000, unknown attributes were an error, but this made it + harder for people to cleanly subclass Class::Tiny classes so this + feature was removed. + + You can define a "BUILDARGS" method to change how arguments to new are + handled. It will receive the constructor arguments as they were provided + and must return a hash reference of key/value pairs (or else throw an + exception). + + sub BUILDARGS { + my $class = shift; + my $name = shift || "John Doe"; + return { name => $name }; + }; + + Foo::Bar->new( "David" ); + Foo::Bar->new(); # "John Doe" + + Unknown attributes returned from "BUILDARGS" will be ignored. + + BUILD + If your class or any superclass defines a "BUILD" method, it will be + called by the constructor from the furthest parent class down to the + child class after the object has been created. + + It is passed the constructor arguments as a hash reference. The return + value is ignored. Use "BUILD" for validation, checking required + attributes or setting default values that depend on other attributes. + + sub BUILD { + my ($self, $args) = @_; + + for my $req ( qw/name age/ ) { + croak "$req attribute required" unless defined $self->$req; + } + + croak "Age must be non-negative" if $self->age < 0; + + $self->msg( "Hello " . $self->name ); + } + + The argument reference is a copy, so deleting elements won't affect data + in the original (but changes will be passed to other BUILD methods in + @ISA). + + DEMOLISH + Class::Tiny provides a "DESTROY" method. If your class or any superclass + defines a "DEMOLISH" method, they will be called from the child class to + the furthest parent class during object destruction. It is provided a + single boolean argument indicating whether Perl is in global + destruction. Return values and errors are ignored. + + sub DEMOLISH { + my ($self, $global_destruct) = @_; + $self->cleanup(); + } + + Introspection and internals + You can retrieve an unsorted list of valid attributes known to + Class::Tiny for a class and its superclasses with the + "get_all_attributes_for" class method. + + my @attrs = Class::Tiny->get_all_attributes_for("Employee"); + # returns qw/name ssn timestamp/ + + Likewise, a hash reference of all valid attributes and default values + (or code references) may be retrieved with the + "get_all_attribute_defaults_for" class method. Any attributes without a + default will be "undef". + + my $def = Class::Tiny->get_all_attribute_defaults_for("Employee"); + # returns { + # name => undef, + # ssn => undef + # timestamp => $coderef + # } + + The "import" method uses two class methods, "prepare_class" and + "create_attributes" to set up the @ISA array and attributes. Anyone + attempting to extend Class::Tiny itself should use these instead of + mocking up a call to "import". + + When the first object is created, linearized @ISA, the valid attribute + list and various subroutine references are cached for speed. Ensure that + all inheritance and methods are in place before creating objects. (You + don't want to be changing that once you create objects anyway, right?) + +RATIONALE + Why this instead of Object::Tiny or Class::Accessor or something else? + I wanted something so simple that it could potentially be used by core + Perl modules I help maintain (or hope to write), most of which either + use Class::Struct or roll-their-own OO framework each time. + + Object::Tiny and Object::Tiny::RW were close to what I wanted, but + lacking some features I deemed necessary, and their maintainers have an + even more strict philosophy against feature creep than I have. + + I also considered Class::Accessor, which has been around a long time and + is heavily used, but it, too, lacked features I wanted and did things in + ways I considered poor design. + + I looked for something else on CPAN, but after checking a dozen class + creators I realized I could implement exactly what I wanted faster than + I could search CPAN for something merely sufficient. + + In general, compared to most things on CPAN (other than Object::Tiny), + Class::Tiny is smaller in implementation and simpler in API. + + Specifically, here is how Class::Tiny ("C::T") compares to Object::Tiny + ("O::T") and Class::Accessor ("C::A"): + + FEATURE C::T O::T C::A + -------------------------------------------------------------- + attributes defined via import yes yes no + read/write accessors yes no yes + lazy attribute defaults yes no no + provides new yes yes yes + provides DESTROY yes no no + new takes either hashref or list yes no (list) no (hash) + Moo(se)-like BUILD/DEMOLISH yes no no + Moo(se)-like BUILDARGS yes no no + no extraneous methods via @ISA yes yes no + + Why this instead of Moose or Moo? + Moose and Moo are both excellent OO frameworks. Moose offers a powerful + meta-object protocol (MOP), but is slow to start up and has about 30 + non-core dependencies including XS modules. Moo is faster to start up + and has about 10 pure Perl dependencies but provides no true MOP, + relying instead on its ability to transparently upgrade Moo to Moose + when Moose's full feature set is required. + + By contrast, Class::Tiny has no MOP and has zero non-core dependencies + for Perls in the support window. It has far less code, less complexity + and no learning curve. If you don't need or can't afford what Moo or + Moose offer, this is intended to be a reasonable fallback. + + That said, Class::Tiny offers Moose-like conventions for things like + "BUILD" and "DEMOLISH" for some minimal interoperability and an easier + upgrade path. + +SUPPORT + Bugs / Feature Requests + Please report any bugs or feature requests through the issue tracker at + <https://github.com/dagolden/Class-Tiny/issues>. You will be notified + automatically of any progress on your issue. + + Source Code + This is open source software. The code repository is available for + public review and contribution under the terms of the license. + + <https://github.com/dagolden/Class-Tiny> + + git clone https://github.com/dagolden/Class-Tiny.git + +AUTHOR + David Golden <dagolden@cpan.org> + +CONTRIBUTORS + * Dagfinn Ilmari MannsÄker <ilmari@ilmari.org> + + * Gelu Lupas <gelu@devnull.ro> + + * Karen Etheridge <ether@cpan.org> + + * Matt S Trout <mstrout@cpan.org> + + * Olivier Mengué <dolmen@cpan.org> + + * Toby Inkster <tobyink@cpan.org> + +COPYRIGHT AND LICENSE + This software is Copyright (c) 2013 by David Golden. + + This is free software, licensed under: + + The Apache License, Version 2.0, January 2004 + |