The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Class::Lite - Simple base class with get/put accessors

VERSION

This document describes Class::Lite version v0.1.0

SYNOPSIS

    package Toy::Class;
    use Class::Lite qw| foo bar baz |;              # make get/put accessors
    
    package Any::Class;
    use Toy::Class;
    my $toy     = Toy::Class->new;
    $toy->init(@_);                                 # does nothing; override
    $toy->put_foo(42);
    my $answer  = $toy->get_foo;
    
    use Class::Lite;                                # no accessors

DESCRIPTION

    Nature's great masterpiece, an elephant, The only harmless great thing. -- John Donne

The hashref-based base class that does no more than it must. Your constructor and accessors are defined in a bridge package so you can override them easily.

Why?

Computer programmers are clever people who delight in evading restrictions. Create an inside-out (flyweight) class to enforce encapsulation and another fellow will hack in. The only way to win the ancient game of locksmith and lockpick is never to begin. If someone misuses your class then it's not your responsibility. Hashref-based objects are traditional, well-understood, even expected in the Perl world; tools exist with which to work with them.

Similarly, Class::Lite provides no read-only accessors. If your client developer wants to alter an attribute he will; you may as well provide a method for the purpose. You might warn against the practice by overriding the default method:

    sub put_foo {
        warn q{Please don't write to the 'foo' attribute.};
        my $self    = shift;
        return $self->SUPER::put_foo(@_);
    };

set is too similar to get in one way, not enough in another. Also set is one of those heavily overloaded words, like "love" or "data", that I prefer to avoid using at all. I say put is equally short, clearer in intent, not easily misread for get; and the first character's descender points in the opposite direction.

I eschew single-method foo() accessors.

I have long defined init() as a shortcut method to fill up a new object; but this is a blatant violation of encapsulation, no matter who does it. No more.

If accessors are defined in your calling package then you will raise a warning if you attempt to redefine them; if they are defined in Class::Lite itself then they will be available to all that inherit from it. So your accessors are defined in an intermediate "bridge" package generated at compile-time.

USE-LINE

    package Toy::Class;
    use Class::Lite qw| foo bar baz |;              # make get/put accessors
    use Class::Lite;                                # no accessors

Makes Class::Lite a base class for Toy::Class. If arguments are given then simple get and put accessors will be created in caller's namespace for each argument. The accessors do no validation.

This is probably all you need to know. Read on if you intend to do tricky stuff in a superclass.

INHERITED METHODS

import()

    Class::Lite->import(@_);
    A::Subclass->import(@_);

Called by use() as usual and does all the work. Inherited by caller so your further subclasses can also take advantage of Class::Lite features.

Since this is merely inherited you may define your own import() with impunity. If you want to have your cake and eat it, too, beware:

    package Big;
    sub import {
        my $class       = shift;
        # Do specific stuff...
        $class->SUPER::import(@_);
        return 1;
    };
    
    package Tot;
    use Big (@args);

This will not work as you expect! SUPER::import() will think Big is its caller(), which is true. So instead of making Big a parent of Tot and defining accessors for Tot; SUPER::import() will attempt to make Big a parent of itself... at which point the fatal error relieves us of further worry.

fore_import()

    package Big;
    sub fore_import {
        my $class       = shift;
        my $args        = shift;
        my $hoge        =    $args->{hoge}      // 'default'     ;
        my @accessors   = @{ $args->{accessors} // []           };
        _do_hoge{$hoge};
        return @accessors;
    };
    
    package Tot;
    use Big {
        hoge        => 'piyo',
        accessors   => [qw| chim chum choo |],
    };

To solve the difficulty previously mentioned: Leave import() untouched and do whatever you like to the use-line argument list in a redefined fore_import(). Just be sure to return a flat list of arguments so import() can do its work.

The default method does nothing and merely returns its arguments.

rear_import()

If you just have to get the last word, redefine rear_import() instead, or also. You'll be passed all the use-line arguments, not just what fore_import() returned; and your return value will be discarded.

The default method does nothing and merely returns its arguments.

NOTE that neither of these methods must be employed if all you want to do in your class is override Class::Lite::import() completely.

new()

    my $obj = My::Class->new(@_);

Blesses an anonymous hash reference into the given class which inherits from Class::Lite. Passes all its args to init().

init()

    my $obj = $old->init(@_);

This abstract method does nothing at all and returns its object. You may wish to override it in your class.

GENERATED METHODS

Accessor methods are generated for each argument on the use-line. They all do just what you'd expect. No validation is done.

    $self   = $self->put_attr($foo);
    $foo    = $self->get_attr;

Put accessors return the object. Get accessors discard any arguments.

MULTIPLE INHERITANCE

Class::Lite::import() is something of a black magic method; it tinkers in caller's package, create a bridge package (in memory), defines methods. It should probably only be called by use() or at least from within a BEGIN block; no attempt is made to define its behavior if called otherwise.

Even at compile-time there are questions raised when your class inherits from both Class::Lite and some other superclass:

    package My::Class;
    use Class::Lite qw| foo bar baz |;              # make get/put accessors
    use parent 'Big::Fat::Super';

If the other superclass is pedestrian and just defines methods for you to inherit then there's little likelihood of interaction. If the other superclass is also trying to define methods with the same names as generated accessors then who can say? So don't do that.

Diamond inheritance is a special case:

    package My::Big;
    use Class::Lite qw| big1 big2 big3 |;
    
    package My::Tot;
    # I want to inherit from My::Big but I also want Class::Lite's acc's.
    use My::Big;
    use Class::Lite qw| big3 tot1 tot2 |;

This works, regardless of which superclass is use'd first, even if the accessor lists overlap. If the My::Big superclass does funny stuff, though, all bets are off. Anybody with a use case is welcome to open an issue.

SEE ALSO

Object::Tiny, Mouse

INSTALLATION

This module is installed using Module::Build.

DIAGNOSTICS

Invalid accessor name...

You passed something horrible on the use-line. Valid arguments to import need to be quoted strings and valid Perl identifiers. If you have in your class some '-$/' attribute (which is a valid hash key) then you'll have to write your own accessors for it. You won't be able to call them, for example, get_-$/().

This error will attempt to display the offending argument but may not succeed.

Failed to generate (package)

Something evil happened while doing the heavy lifting: getting into your package, getting into the bridge package, setting up the ISA relationships, or defining requested accessors. This should not happen and isn't your fault (unless you've tried to inherit recursively). Please make a bug report.

CONFIGURATION AND ENVIRONMENT

None.

DEPENDENCIES

There are no non-core dependencies.

version 0.99
Perl extension for Version Objects

This module should work with any version of perl 5.8.8 and up. However, you may need to upgrade some core modules.

INCOMPATIBILITIES

None known.

BUGS AND LIMITATIONS

This is an early release. Reports and suggestions will be warmly welcomed.

Please report any issues to: https://github.com/Xiong/class-lite/issues.

DEVELOPMENT

This project is hosted on GitHub at: https://github.com/Xiong/class-lite.

THANKS

Adam Kennedy (ADAMK) for Object::Tiny, on which much of this module's code is based.

AUTHOR

Xiong Changnian <xiong@cpan.org>

LICENSE

Copyright (C) 2013 Xiong Changnian <xiong@cpan.org>

This library and its contents are released under Artistic License 2.0:

http://www.opensource.org/licenses/artistic-license-2.0.php