summaryrefslogtreecommitdiff
path: root/README
diff options
context:
space:
mode:
Diffstat (limited to 'README')
-rw-r--r--README359
1 files changed, 359 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..e3692cb
--- /dev/null
+++ b/README
@@ -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
+