recovered ancient docs
edenc [Mon, 17 Dec 2007 18:43:38 +0000 (18:43 +0000)]
lib/Reaction/Manual.pod [new file with mode: 0644]
lib/Reaction/Manual/Cookbook.pod [new file with mode: 0644]
lib/Reaction/Manual/Example.pod [new file with mode: 0644]
lib/Reaction/Manual/FAQ.pod [new file with mode: 0644]
lib/Reaction/Manual/Internals.pod [new file with mode: 0644]
lib/Reaction/Manual/Intro.pod [new file with mode: 0644]

diff --git a/lib/Reaction/Manual.pod b/lib/Reaction/Manual.pod
new file mode 100644 (file)
index 0000000..ab366cc
--- /dev/null
@@ -0,0 +1,47 @@
+=head1 NAME
+
+Reaction::Manual - The Index of The Manual
+
+=head1 DESCRIPTON
+
+Reaction is basically an extended MVC framework built upon L<Catalyst>.
+
+=head1 SECTIONS
+
+=head2 L<Reaction::Manual::Intro>
+
+=head2 L<Reaction::Manual::Example>
+
+=head2 L<Reaction::Manual::Cookbook>
+
+=head2 L<Reaction::Manual::Internals>
+
+=head2 L<Reaction::Manual::FAQ>
+
+=head1 SEE ALSO
+
+=over 
+
+=item * L<Catalyst::Manual>
+
+=item * L<DBIx::Class::Manual>
+
+=item * L<Moose>
+
+=item * L<Template::Toolkit>
+
+=back
+
+=head1 SUPPORT
+
+IRC: Join #reaction on irc.perl.org
+
+=head1 AUTHORS
+
+See L<Reaction::Class> for authors for authors.
+
+=head1 LICENSE
+
+See L<Reaction::Class> for the license.
+
+=cut
diff --git a/lib/Reaction/Manual/Cookbook.pod b/lib/Reaction/Manual/Cookbook.pod
new file mode 100644 (file)
index 0000000..e04c6ee
--- /dev/null
@@ -0,0 +1,74 @@
+=head1 NAME
+
+Reaction::Manual::Cookbook - Miscellaneous recipes
+
+=head1 RECIPES
+
+These should include some hopefully useful tips and tricks!
+
+=head2 Display
+
+These would typically go in your /root directory along with your other
+templates.
+
+=head3 Alternating listview row styles with CSS
+
+Filename: listview
+
+  [%
+  
+  PROCESS base/listview;
+  
+  row_block = 'listview_row_fancy';
+  
+  BLOCK listview_row_fancy;
+  
+    IF loop.count % 2 == 1;
+      attrs.class = 'dark';
+    ELSE;
+      attrs.class = 'light';
+    END;
+  
+    INCLUDE listview_row;
+  
+  END;
+  
+  %]
+
+=head3 Displaying heading on action forms
+
+Filename: form_base
+
+  [%
+  
+  PROCESS base/form_base;
+  
+  main_block = 'form_base_control_fancy';
+  
+  BLOCK form_base_control_fancy;
+  
+    action_class = self.action.meta.name.split('::').pop;
+    '<h3>'; action_class.split('(?=[A-Z])').join(' '); '</h3>';
+    INCLUDE form_base_control;
+  
+  END;
+  
+  %]
+
+=head2 Controllers
+
+Things
+
+=head2 Models
+
+Stuff
+
+=head1 AUTHORS
+
+See L<Reaction::Class> for authors.
+
+=head1 LICENSE
+
+See L<Reaction::Class> for the license.
+
+=cut
diff --git a/lib/Reaction/Manual/Example.pod b/lib/Reaction/Manual/Example.pod
new file mode 100644 (file)
index 0000000..02a55fe
--- /dev/null
@@ -0,0 +1,304 @@
+=head1 NAME
+
+Reaction::Manual::Example - Simple Reaction example
+
+=head1 DESCRIPTION
+
+This tutorial will guide you through the process of setting up and testing a
+very basic CRUD application based on the database from
+L<DBIx::Class::Manual::Example>.
+
+You need at least a fairly basic understanding of L<DBIx::Class::Schema> for
+this example to have value for you.
+
+=head2 Installation
+
+Install L<DBIx::Class> via CPAN.
+
+Install Reaction from http://code2.0beta.co.uk/reaction/svn via SVN or SVK.
+
+Set up the database as mentioned in L<DBIx::Class::Manual::Example>. Don't do
+any of the DBIx::Class related stuff, only the SQLite database.
+
+=head2 Create the application
+
+  catalyst.pl Test::Reaction 
+  cd Test-Reaction
+  script/test_reaction_create.pl Model Test::Reaction DBIC::Schema Test::Reaction::DB
+
+Also, remember to include Catalyst::Plugin::I18N in your plugin list, like
+this:
+
+  use Catalyst qw/-Debug ConfigLoader Static::Simple I18N/;
+
+=head2 Set up DBIx::Class::Schema
+
+In addition to the normal DBIC stuff, you need to moosify your DBIC classes.
+
+Change directory back from db to the directory app:
+
+  cd lib/Test/Reaction
+  mkdir DB
+
+Then, create the following DBIx::Class::Schema classes:
+
+DB.pm:
+    
+  package Test::Reaction::DB;
+
+  use base 'DBIx::Class::Schema';
+  
+  __PACKAGE__->load_classes;
+  
+  1;
+
+DB/Artist.pm:
+
+  package Test::Reaction::DB::Artist;
+  
+  use base 'DBIx::Class';
+  use Reaction::Class;
+  
+  has 'artistid' => ( isa => 'Int', is => 'ro', required => 1 );
+  has 'name' => ( isa => 'NonEmptySimpleStr', is => 'rw', required => 1 );
+  
+  sub display_name {
+      my $self = shift;
+      return $self->name;
+  }
+  
+  __PACKAGE__->load_components(qw/PK::Auto Core/);
+  __PACKAGE__->table('artist');
+  __PACKAGE__->add_columns(qw/ artistid name /);
+  __PACKAGE__->set_primary_key('artistid');
+  __PACKAGE__->has_many( 'cds' => 'Test::Reaction::DB::Cd' );
+  
+  1;
+
+DB/Cd.pm:
+
+  package Test::Reaction::DB::Cd;
+
+  use base 'DBIx::Class';
+  use Reaction::Class;
+  
+  has 'cdid' => ( isa => 'Int', is => 'ro', required => 1 );
+  has 'artist' =>
+      ( isa => 'Test::Reaction::DB::Artist', is => 'rw', required => 1 );
+  has 'title' => ( isa => 'NonEmptySimpleStr', is => 'rw', required => 1 );
+  
+  sub display_name {
+      my $self = shift;
+      return $self->title;
+  }
+  
+  __PACKAGE__->load_components(qw/PK::Auto Core/);
+  __PACKAGE__->table('cd');
+  __PACKAGE__->add_columns(qw/ cdid artist title/);
+  __PACKAGE__->set_primary_key('cdid');
+  __PACKAGE__->belongs_to( 'artist' => 'Test::Reaction::DB::Artist' );
+  __PACKAGE__->has_many( 'tracks' => 'Test::Reaction::DB::Track' );
+  
+  1;
+
+DB/Track.pm:
+
+  package Test::Reaction::DB::Track;
+  
+  use base 'DBIx::Class';
+  use Reaction::Class;
+  
+  has 'trackid' => ( isa => 'Int', is => 'ro', required => 1 );
+  has 'cd'    => ( isa => 'Test::Reaction::DB::Cd', is => 'rw', required => 1 );
+  has 'title' => ( isa => 'NonEmptySimpleStr',      is => 'rw', required => 1 );
+  
+  __PACKAGE__->load_components(qw/PK::Auto Core/);
+  __PACKAGE__->table('track');
+  __PACKAGE__->add_columns(qw/ trackid cd title/);
+  __PACKAGE__->set_primary_key('trackid');
+  __PACKAGE__->belongs_to( 'cd' => 'Test::Reaction::DB::Cd' );
+  
+  1;
+
+=head3 Reaction attributes
+
+See L<Reaction::Types::Core>
+
+=head3 The rest
+
+Reaction will use I<sub display_name> for displaying when there is a 1:Many or
+Many:Many relation. It will return a suitable text representation.
+
+=head2 Models
+
+=head3 Create Test::Reaction::Model::Action
+
+Still in lib/Test/Reaction, create 
+
+Model/Action.pm:
+
+  package Test::Reaction::Model::Action;
+  
+  use Reaction::Class;
+  
+  use Test::Reaction::DB;
+  
+  use aliased 'Reaction::InterfaceModel::Action::DBIC::ActionReflector';
+  
+  my $r = ActionReflector->new;
+  
+  $r->reflect_actions_for( 'Test::Reaction::DB::Artist' => __PACKAGE__ );
+  $r->reflect_actions_for( 'Test::Reaction::DB::Cd'     => __PACKAGE__ );
+  $r->reflect_actions_for( 'Test::Reaction::DB::Track'  => __PACKAGE__ );
+  
+  1;
+
+=head2 Controllers
+
+Reaction controllers inherit from Reaction::UI::CRUDController, like this:
+
+Controller/Artist.pm
+
+  package Test::Reaction::Controller::Artist;
+  
+  use strict;
+  use warnings;
+  use base 'Reaction::UI::CRUDController';
+  use Reaction::Class;
+  
+  __PACKAGE__->config(
+    model_base => 'Test::Reaction',
+    model_name => 'Artist',
+    action => { base => { Chained => '/base', PathPart => 'artist' } }
+  );
+  
+  1;
+
+Controller/Cd.pm
+
+  package Test::Reaction::Controller::Cd;
+  
+  use strict;
+  use warnings;
+  use base 'Reaction::UI::CRUDController';
+  use Reaction::Class;
+  
+  __PACKAGE__->config(
+    model_base => 'Test::Reaction',
+    model_name => 'Cd',
+    action => { base => { Chained => '/base', PathPart => 'cd' } }
+  );
+  
+  1;
+
+Controller/Track.pm
+
+  package Test::Reaction::Controller::Track;
+  
+  use strict;
+  use warnings;
+  use base 'Reaction::UI::CRUDController';
+  use Reaction::Class;
+  
+  __PACKAGE__->config(
+    model_base => 'Test::Reaction',
+    model_name => 'Track',
+    action => { base => { Chained => '/base', PathPart => 'track' } }
+  );
+  
+  1;
+
+Finally, change Controller/Root.pm to
+
+  package Test::Reaction::Controller::Root;
+  
+  use strict;
+  use warnings;
+  use base 'Reaction::UI::RootController';
+  use Reaction::Class;
+  
+  use aliased 'Reaction::UI::ViewPort';
+  use aliased 'Reaction::UI::ViewPort::ListView';
+  use aliased 'Reaction::UI::ViewPort::ActionForm';
+  
+  __PACKAGE__->config->{namespace} = '';
+  
+  sub base :Chained('/') :PathPart('') :CaptureArgs(0) {
+    my ($self, $c) = @_;
+  
+    $self->push_viewport(ViewPort, layout => 'xhtml');
+  }
+  
+  sub root :Chained('base') :PathPart('') :Args(0) {
+    my ($self, $c) = @_;
+  
+    $self->push_viewport(ViewPort, layout => 'index');
+  }
+  
+  1;
+
+=head2 View
+
+View/XHTML.pm looks like this
+
+  package Test::Reaction::View::XHTML;
+  
+  use Reaction::Class;
+  
+  extends 'Reaction::UI::Renderer::XHTML';
+  
+  1;
+
+This is all the perly stuff. Now return to the base Test-Reaction directory and
+create root/index:
+
+  [%
+  
+  main_block = 'index';
+  
+  BLOCK index;
+  
+  %]<p><a href="[% ctx.uri_for('/artist') %]">artist</a></p>
+  <p><a href="[% ctx.uri_for('/cd') %]">cd</a></p>
+  <p><a href="[% ctx.uri_for('/track') %]">track</a></p>[%
+  
+  END;
+  
+  %]
+
+=head2 Running
+
+Now all that remains is to tell catalyst about the root and the model. Let
+test_reaction.yml look like this:
+
+ ---
+ name: Test::Reaction
+ Controller::Root:
+     view_name:  'XHTML'
+     window_title: 'Reaction Test App'
+ Model::Test::Reaction:
+     schema_class: 'Test::Reaction::DB'
+     connect_info:
+         - 'dbi:SQLite:dbname=database/example.db'
+
+The finals step for this example is to link to Reaction's templates:
+
+ ln -s <path to reaction install directory>/root/base/ root/base
+
+At last you're now ready to run the server
+
+  script/test_reaction_server.pl
+
+=head1 Notes
+
+=head1 TODO
+
+=head1 AUTHORS
+
+See L<Reaction::Class> for authors.
+
+=head1 LICENSE
+
+See L<Reaction::Class> for the license.
+
+=cut
diff --git a/lib/Reaction/Manual/FAQ.pod b/lib/Reaction/Manual/FAQ.pod
new file mode 100644 (file)
index 0000000..96f20fd
--- /dev/null
@@ -0,0 +1,101 @@
+=head1 NAME
+
+Reaction::Manual::FAQ
+
+=head2 INTRODUCTION
+
+=head3 What is Reaction?
+
+Reaction is an MVCish framework that is designed with two goals in mind:
+"don't repeat yourself" and "components rule."
+
+=head3 How is it different from other MVC frameworks?
+
+Reaction is more flexible and abstract. Web development is only a specialized
+set of what Reaction is designed to provide - the inner classes are general
+enough to be used in many different environments and for solving non-web
+problems.
+
+It is planned to go a lot further than just the web - we want to develop GUIs
+and CLIs as easily and painlessly as possible, using Reaction. How about
+writing your web application and instantly getting a CLI to go with it? That's
+only part of the flexibility we have in mind.
+
+=head3 How is it different from Catalyst?
+
+Catalyst is MVC-based whereas Reaction splits the Model into 2 parts: The
+"Domain Model" and the "Interface Model." Web development is only a sample of
+what Reaction can do - but it already comes bundled with the basic components
+that you would have to program in Catalyst. At the moment, Reaction runs on
+Catalyst for web development.
+
+=head3 What's a Domain?
+
+A domain is the field where an abstraction makes sense. For example, to build
+a web site a programmer may come up with an abstraction of a User, Products,
+User roles, etc. These concepts are just one particular implementation of all
+the possible abstractions for that web site -- the set of all these possible
+abstractions make up the Domain.
+
+=head3 What's a Domain Model?
+
+A Domain Model is an actual computational model of an abstraction. In most
+cases these models are business-based, as in the set of objects that make up
+the representation for a particular domain, such as Users, Products, User
+Roles, etc.
+
+=head3 What's an Interface Model?
+
+A well defined model for the common operations involved in a particular mode
+of interaction with the domain. In other words, it's a layer around the Domain
+Model that provides interaction with it. One example would be an authorization
+procedure for different views of the same data, based on user's credentials.
+
+=head3 I'm lost! What does "Model" mean?
+
+The term "model" can mean two things: "model as in Computer Model" and "Model
+as in MVC". For this document, the former will be written as just "Model"
+whereas the latter will be referred to as "Model as in MVC."
+
+=head3 Haven't I seen these definitions elsewhere?
+Yes, similar terms have been used in Java-land and Smalltalk-ville. Note that
+for the sake of simplicity we are not giving rigorous (and more complex)
+definitions.
+
+=head3 What's a View?
+
+=head3 What's a Viewport?
+
+ListView and ActionForm are subclasses of ViewPort.
+
+=head3 What's a Focus Stack?
+
+=head3 What are Tangents?
+
+=head3 Can I have a pony?
+
+=head2 USING REACTION
+
+=head3 Where do I put my HTML?
+
+Packages involved
+ ComponentUI
+ ComponentUI::Controller::Bar
+ ComponentUI::Controller::Baz
+ ComponentUI::Controller::Foo
+ ComponentUI::Controller::Root
+ ComponentUI::Model::TestDB
+ ComponentUI::Model::Action
+ ComponentUI::View::XHTML
+
+CRUD    
+
+=head1 AUTHORS
+
+See L<Reaction::Class> for authors.
+
+=head1 LICENSE
+
+See L<Reaction::Class> for the license.
+
+=cut
diff --git a/lib/Reaction/Manual/Internals.pod b/lib/Reaction/Manual/Internals.pod
new file mode 100644 (file)
index 0000000..720608c
--- /dev/null
@@ -0,0 +1,270 @@
+=head1 NAME
+
+Reaction::Manual::Internals
+
+=head2 Hacking on Reaction
+
+=head3 What is a component?
+
+=head3 What component types are there?
+
+=head3 How do I create a new component?
+
+=head3 How does it work with a database?
+
+=head3 What about Moose?
+
+L<Moose>
+
+=head3 Type system
+
+=head3 What Perl modules should I be familiar with, in order to hack on Reaction's
+internals?
+
+=over
+
+=item L<Moose>
+
+A complete modern object system for Perl 5.
+
+=item L<aliased>
+
+Use shorter package names, i.e., "X::Y::Z" as "Z".
+
+=item L<Catalyst>
+
+The MVC application framework Reaction uses.
+
+=over
+
+=item * L<Catalyst::Controller::BindLex>
+
+=item * L<Catalyst::Model::DBIC::Schema>
+
+=item * L<Catalyst::Plugin::ConfigLoader> 
+
+=item * L<Catalyst::Plugin::I18N>
+
+=item * L<Catalyst::Plugin::Static::Simple>
+
+=item * L<Catalyst::View::TT>
+
+=back
+
+=item TT
+
+Template Toolkit
+
+=item L<Config::General> 
+
+Generic config file module.
+
+=item L<DBIx::Class> 
+
+Object/Relational mapper.
+
+=item L<DateTime>
+
+=item L<DateTime::Format::MySQL>
+
+=item L<Digest::MD5>
+
+=item L<Email::MIME>
+
+=item L<Email::MIME::Creator>
+
+=item L<Email::Send>
+
+=item L<Email::Valid>
+
+=item L<SQL::Translator>
+
+=item L<Test::Class>
+
+=item L<Test::Memory::Cycle>
+
+=item L<Time::ParseDate>
+
+=back
+
+=head3 Packages involved
+
+=over
+
+=item L<Reaction::Class>
+
+Utility class, sets up to export a few methods that return parameters for use
+within Moose's C<has> (as new parameters) in other packages. It also C<use>s
+Moose itself.
+
+The methods it injects are:
+
+=over
+
+=item set_or_lazy_build($field_name)
+
+The attribute is required, if not provided beforehand the build_${name} method
+will be called on the object when the attribute's getter is first called. If
+the method does not exist, or returns undef, an error will be thrown.
+
+=item set_or_lazy_fail()
+
+The attribute is required, if not provided beforehand the 'lazy' parameter of
+Moose will make it fail.
+
+=item trigger_adopt()
+
+Calls adopt_${type} after the attribute value is set to $type.
+
+=item register_inc_entry()
+
+Will mark the calling package as already included, using %INC.
+
+=back
+
+=item Reaction::InterfaceModel::Action
+
+=item Reaction::InterfaceModel::Action::DBIC::ResultSet::Create;
+
+=item Reaction::InterfaceModel::Action::DBIC::ActionReflector;
+
+A method "adaptor" that creates the needed objects to support CRUD DBIC
+actions. In the future the code could be moved to a class higher in the
+hierarchy and only contain the operations to adapt.
+
+Sample run:
+
+Reaction::InterfaceModel::Action::DBIC::ActionReflector->reflect_actions_for(
+Reaction::InterfaceModel::Action::DBIC::ActionReflector=HASH(0x93cb2f0) 
+RTest::TestDB::Foo 
+ComponentUI::Model::Action
+)
+
+Generates and evaluates:
+
+package ComponentUI::Model::Action::DeleteFoo;
+use Reaction::Class;
+extends 'Reaction::InterfaceModel::Action::DBIC::Result::Delete';
+package ComponentUI::Model::Action::UpdateFoo;
+use Reaction::Class;
+extends 'Reaction::InterfaceModel::Action::DBIC::Result::Update';
+has 'baz_list' => (isa => 'ArrayRef', is => 'rw', set_or_lazy_fail('baz_list'), default => sub { [] }, valid_values => sub {
+$_[0]->target_model
+->result_source
+->related_source('links_to_baz_list')
+->related_source('baz')
+->resultset;
+});
+has 'last_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('last_name'));
+has 'first_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('first_name'));
+package ComponentUI::Model::Action::CreateFoo;
+use Reaction::Class;
+extends 'Reaction::InterfaceModel::Action::DBIC::ResultSet::Create';
+has 'baz_list' => (isa => 'ArrayRef', is => 'rw', set_or_lazy_fail('baz_list'), default => sub { [] }, valid_values => sub {
+$_[0]->target_model
+->result_source
+->related_source('links_to_baz_list')
+->related_source('baz')
+->resultset;
+});
+has 'last_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('last_name'));
+has 'first_name' => (isa => 'NonEmptySimpleStr', is => 'rw', set_or_lazy_fail('first_name'));
+
+=item Reaction::InterfaceModel::Action::DBIC::Result::Delete
+
+=item Reaction::InterfaceModel::Action::DBIC::Result::Update
+
+=item Reaction::InterfaceModel::Action::DBIC::User::ResetPassword
+
+=item Reaction::InterfaceModel::Action::DBIC::User::Role::SetPassword
+
+=item Reaction::InterfaceModel::Action::DBIC::User::ChangePassword
+
+=item Reaction::InterfaceModel::Action::User::ResetPassword
+
+=item Reaction::InterfaceModel::Action::User::ChangePassword
+
+=item Reaction::InterfaceModel::Action::User::SetPassword
+
+=item Reaction::Meta::InterfaceModel::Action::ParameterAttribute
+
+=item Reaction::Meta::InterfaceModel::Action::Class
+
+=item Reaction::Types::Email
+
+=item Reaction::Types::Core
+
+=item Reaction::Types::DateTime
+
+=item Reaction::Types::File
+
+=item Reaction::Types::DBIC
+
+=item Reaction::UI::ViewPort::ListView
+
+=item Reaction::UI::ViewPort::Field::Text
+
+=item Reaction::UI::ViewPort::Field::ChooseMany
+
+=item Reaction::UI::ViewPort::Field::String
+
+=item Reaction::UI::ViewPort::Field::Number
+
+=item Reaction::UI::ViewPort::Field::HiddenArray
+
+=item Reaction::UI::ViewPort::Field::DateTime
+
+=item Reaction::UI::ViewPort::Field::File
+
+=item Reaction::UI::ViewPort::Field::ChooseOne
+
+=item Reaction::UI::ViewPort::Field::Password
+
+=item Reaction::UI::ViewPort::ActionForm
+
+=item Reaction::UI::ViewPort::Field
+
+=item Reaction::UI::FocusStack
+
+=item Reaction::UI::RootController
+
+=item Reaction::UI::Window
+
+=item Reaction::UI::Renderer::XHTML
+
+=item Reaction::UI::ViewPort
+
+=item Reaction::UI::CRUDController
+
+=item Reaction::UI::Controller
+
+=back
+
+=head3 Remarks about POD
+
+Don't use C<=over N>. POD assumes that the indent level is 4 if you leave
+it out. Most POD renderers ignore your indent level anyway.
+
+=head2 UNSORTED
+
+Packages involved
+
+t/lib/Rtest/TestDB*: TestDB DBIC declarations.
+t/lib/RTest/TestDB.pm: does DBIC populate for t/.
+t/lib/RTest/UI/ XXX
+
+Reaction::Test::WithDB;
+Reaction::Test;
+Reaction::Test::Mock::Context;
+Reaction::Test::Mock::Request;
+Reaction::Test::Mock::Response;
+
+=head1 AUTHORS
+
+See L<Reaction::Class> for authors.
+
+=head1 LICENSE
+
+See L<Reaction::Class> for the license.
+
+=cut
diff --git a/lib/Reaction/Manual/Intro.pod b/lib/Reaction/Manual/Intro.pod
new file mode 100644 (file)
index 0000000..73d3846
--- /dev/null
@@ -0,0 +1,62 @@
+=head1 NAME
+
+Reaction::Manual::Intro - Introduction to Reaction
+
+=head1 INTRODUCTION
+
+Reaction is basically an extended MVC:
+
+=over
+
+=item Domain Model 
+
+DBIC schema, etc.
+
+=item Interface Model 
+
+Model::DBIC::Schema and Action classes.
+
+=item Controller 
+
+Mediation and navigation.
+
+=item ViewPort
+
+View logic and event handling encapsulation.
+
+=item Renderer 
+
+View:: classes, handed viewports.
+
+=back
+
+=head1 THE REACTION WAY
+
+The idea is you separate your domain model, which encapsulates the domain
+itself from your interface model, which is a model of how a particular app or
+class of apps interact with that domain and provides objects/methods to
+encapsulate the common operations it does.
+
+=head2 Basic usage
+
+XXX TODO
+
+=head1 SEE ALSO
+
+=over 
+
+=item * L<Reaction::Manual::Cookbook>
+
+=item * L<Reaction::Manual::FAQ>
+
+=back
+
+=head1 AUTHORS
+
+See L<Reaction::Class> for authors.
+
+=head1 LICENSE
+
+See L<Reaction::Class> for the license.
+
+=cut