MooseX::Struct

MooseX::Struct - Struct-like interface for Moose Object creation

Version

Version 0.06

Synopsis

 use MooseX::Struct;

 struct 'MyClass::Foo' => (
    bar   => 'Scalar',
    baz   => 'Array',
 );
  
 my $obj = new MyClass::Foo;

 $obj->bar(44);    # sets $obj->{bar} to 44
 
 print $obj->bar;  # prints 44

 ### or

 package MyClass::Foo;
 use MooseX::Struct;

 ### This will default to the current package : 'MyClass::Foo'

 struct (
    bar   => 'Scalar',
    baz   => 'Array',
 );

 ### or create your struct at compile-time
 
 use MooseX::Struct 'MyClass::Foo' => (
    bar   => 'Scalar',
    baz   => 'Array',
 );

 ### Immutable Moose Objects

 package MyClass::Foo;
 use MooseX::Struct;

 immutable struct (
    bar   => 'Scalar',
    baz   => 'Array',
 );

Description

This module is a reimplementation of the core Class::Struct package for the Moose Object System. The original Class::Struct is a very useful package but offers little to no extensibility as soon as you outgrow its features.

For the Class::Struct users:

This is not a drop-in replacement (though for most common cases, it is a drop in replacement), it works somewhat differently and has different performance concerns.

For Moose users:

This can be used as an alternate way to create Moose objects. All exports that normally come from 'use Moose' are exported to the specified package, or the current package if none given (unless the current package is 'main').

A lot of this package passes off work to Moose and Class::MOP, so both of those should be considered good reading recommendations.

Exports

MooseX::Struct exports two functions, struct and immutable, to the caller's namespace.

immutable

immutable() is a convenience method that takes in a class name and calls CLASS->meta->make_immutable(). Since struct() returns the class name of the object it just defined, you can write out very nice looking code such as:

immutable struct 'MyClass' => ( class definition );

struct

The struct function can be passed parameters in four forms but boil down to :

struct( ['Class Name',] %hash|$hashref );

Omitting the 'Class Name' argument allows MooseX::Struct to default to the current package's namespace.

Because you do not need parantheses for predefined functions and the => is a synonym for ,, the above can be written in a more attractive way :

struct 'My::Class' => (
   attribute   => 'type',
);

Thus the following three forms are:

struct 'My::Class' => {
   attribute   => 'type',
};

struct (
   attribute   => 'type',
);

struct {
   attribute   => 'type',
};

The last two would default to the current package name.

Compile-time declaration of a struct

Like Class::Struct, MooseX::Struct allows you to specify a class at compile time by passing the appropriate definition to MooseX::Struct at import.

e.g.

use MooseX::Struct 'My::Class' => (
   attribute   => 'type',
);

Again, like Class::Struct, there is no real time savings, but you do get a more logical flow of events and it does get all of the hard work done at startup.

Attributes

Attributes all take the form of a hash key/value pair with the hash key being the name of the attribute and the default name of the accessor, and the value being a predefined type alias (see below). All attributes are read/write by default (is => 'rw'). Advanced attributes can be made by specifying a hashref of acceptible attribute specifications (see Class::MOP::Attribute) instead of a type alias, e.g.

struct 'My::Class'   => (
   foo   => 'Scalar',
   bar   => { accessor  => 'quux' }
   baz   => { is => 'ro', reader => 'get_baz', [etc] }
);

Note / Warning / Not a bug

Multiple attributes can be declared at once in an array reference while being defined within parantheses as opposed to curly brackets (i.e., as a standard array of arguments as opposed to a hash / hash reference). This is due to perl stringifying references in order to use them as hash keys and the fact that perl can't dereference them after that happens.

Types

These are used to constrain an attribute's value to a certain data type (isa => 'Type').

Types are case-insensitive for matching purposes, but you can specify a type that is not listed here and it will be passed through unchanged to Moose::Meta::Class / Class::MOP::Class. So if you are familiar with advanced types or have created your own type constraints, you can still use MooseX::Struct.

+----------------+-----------------------+
| MooseX::Struct | Moose/Class::MOP type |
+----------------+-----------------------+
|             '' | [No type constraint]  |
|              ? | [No type constraint]  |
|            any | [No type constraint]  |
|             ro | [Read Only - No Type] |
|             rw | [Read/Write - No Type]|
|              ! | Bool                  |
|              # | Num                   |
|              1 | Int                   |
|              $ | Value                 |
|             *$ | ScalarRef             |
|              @ | ArrayRef              |
|             *@ | ArrayRef              |
|              % | HashRef               |
|             *% | HashRef               |
|              & | CodeRef               |
|              * | GlobRef               |
|              w | Str                   |
|             rx | RegexpRef             |
|            int | Int                   |
|        integer | Int                   |
|         number | Num                   |
|         scalar | Value                 |
|      scalarref | ScalarRef             |
|          array | ArrayRef              |
|       arrayref | ArrayRef              |
|           hash | HashRef               |
|        hashref | HashRef               |
|           bool | Bool                  |
|        boolean | Bool                  |
|           glob | GlobRef               |
|          regex | RegexpRef             |
|         string | Str                   |
+----------------+-----------------------+

Notes

strict and warnings are imported automatically

By issuing a use MooseX::Struct, same as with useing Moose, strict and warnings are automatically imported into the calling package.

Differences from Class::Struct

The accessors that are created for each attribute are simple read / write accessors. They will attempt to assign any passed value to the attribute, and they will return the whole value on access.

# For an object 'foo' with an attribute 'bar' of type ArrayRef:

$foo->bar([1,2,3]);  # sets bar to [1,2,3]

$foo->bar;           # returns [1,2,3]

$foo->bar(0);        # Attempts to set bar to 0 and errors out because
                     # 0 is not an array reference. Class::Struct would
                     # have given you the element at index 0;

$foo->bar->[0]       # Correct

The types have been changed and extended. There are no '%' or '@' types that indicate 'Hash' and 'Array,' respectively. Both of those symbols now refer to the reference of the type.

Author

Jarrod Overson, <jsoverson at googlemail.com>

Bugs

Of course there could be bugs with use cases I hadn't thought of during testing, but most of this module's work passes off to Class::MOP or Moose, so if you find a bug, please do some testing to determine where the actual bug is occurring.

Please report any bugs or feature requests to bug-moosex-struct at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooseX-Struct. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

Support

You can find documentation for this module with the perldoc command.

perldoc MooseX::Struct

You can also look for information at:

Acknowledgements

Thanks to everyone who worked on Class::Struct for providing us a very clean interface for creating intuitive, logical data structures within perl.

And thanks to everyone who has worked on Moose for providing a somewhat complicated method of creating extremely powerful and extensible data structures within perl.

Copyright & License

Copyright 2008 Jarrod Overson, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.