The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

CatalystX::Features - Merges external directories into your app

VERSION

version 0.1011

SYNOPSIS

   package MyApp;

   use Catalyst qw/
         +CatalystX::Features
         +CatalystX::Features::Lib
         +CatalystX::Features::Plugin::ConfigLoader
         +CatalystX::Features::Plugin::Static::Simple
         ...
         /;

DESCRIPTION

This module tries to make it easier to spread out outside of the main application directory, in the spirit of Eclipse features and Ruby on Rails plugins.

It's mainly useful if you're working on a large application with distinct, isolated features that are not tightly coupled with the main app and could be pulled off or eventually reused somewhere else.

It also comes handy in a large project, with many developers working on specific application parts. And, say, you wish to split the functionality in diretories, or just want to keep them out of the application core files.

USAGE

1) Create a directory under your app home named /features

   mkdir /MyApp/features/

2) Each feature home dir should be named something like:

   /MyApp/features/my.demo.feature_1.0.0

The folder name is split at the underscore _, the left part becomes the feature name, the right one, the feature version.

It can also split on a dash -, allowing the feature to be named like Feature-0.9123, which can be useful for dropping something from, say, CPAN.

The dots on the feature name are just sassy stuff. They are absolutely optional.

3) Recreate your application structure under the feature directory.

   /MyApp/features/my.demo.feature_1.0.0
      /lib
      /root
      /t

Files under /root will only be picked up by supported plugins and views. The rest will probably be ignored. Check the distribution directory for supported plugins and views.

Files under /lib will be included in @INC (if CatalystX::Features::Lib is used). That means your Controllers, Models and Views (and DBIC::Schema) will be loaded as if they were under the main directory.

4) Extend your app yourself!

Don't sit there waiting for a plugin for your favorite View to come out. Just write your own. Use the force and check the source of some of the plugins in this distribution, ie. CatalystX::Features::View::Mason.

Really, writing a "feature" enabled application is really simple. Usually you inherit from a well-known View or Plugin, then trap the initialization code (setup() or new()) and push the array of loaded features into some sort of path list.

   foreach my $feature ( $c->features->list ) {

      my $path_to_root = $feature->root;

      # make that path reach the config object for the View

      push @{  $c->config->{View::Bzerk}->{include_path} }, $path_to_root;

   }

5) Change MyApp.pm to inherit the ::Plugins and ::Views you need, then fire it up.

A debug box will be printed on startup, so you can check which version of each feature has been loaded:

   [debug] Features Loaded:
   .----------------------------------------+------------------------+----------.
   | Home                                   | Name                   | Version  |
   +----------------------------------------+------------------------+----------+
   | simple.feature_1.0.0                   | simple.feature         | 1.0.0    |
   .-----------------------------------------------------------------+----------.

RULES AND CAVEATS

Feature versions

  • If a higher version of a feature is found, that's the one to be used, the rest is ignored

  • A feature without a version is ok, it will be the highest version available. That's good for commiting to source control, where you don't want version numbers on directories.

Merging

  • Merging rules are left in the open right now. If duplicate files are found between two features, or a feature and the main app, maybe the one in the feature will have precedence. Maybe not.

  • But the idea is to give precedence to the feature, which is "rewriting" the main app.

  • On the other hand, there are cases where the main app wants to force down the rules to the features. I prefer a "stronger" feature. After all, features are app novelties, thus the precedence.

  • Check each plugin for details on how its merge is done. For instance, CatalystX::Features::Plugin::ConfigLoader will merge directly into the main app's config file, overwriting whatever comes across its path.

"Cascading"

If your feature is called myfeature, and inside there's a Controller called Test, the registered url *will not* be:

   /myfeature/test/*

But:

        /test/*

Just like if it were stowed under the main app /lib dir.

CONFIGURATION

home

Let's you set a list of directories where your features are located. It expects full paths.

   <CatalystX::Features>
      home /opt/myapp_features
      home /somewhere/else
   </CatalystX::Features>

Defaults to:

   MyApp/features

backend_class

Sets an alternative class to use as a backend. The default is CatalystX::Features::Backend.

   <CatalystX::Features>
      backend_class MyApp::Features
   </CatalystX::Features>

feature_class

Sets an alternative class to represent a single feature. The default is CatalystX::Features::Feature. This class should implement the role CatalystX::Features::Role::Feature.

   <CatalystX::Features>
      feature_class MyApp::Feature
   </CatalystX::Features>

EXAMPLES

For a simple app example, try taking a look at t/TestApp in the distribution tarball.

METHODS

$c->features

Returns the feature backend object.

$c->features->list

Returns an array of loaded features, which are instances of the CatalystX::Features::Feature class.

$c->setup

The plugin setup method. Loads features and prints the feature configuration table.

$c->features_setup

Does the dirty setup work. Called from various CatalystX::Features::Plugin::* to make sure features are loaded.

TODO

These things here, and many, many more that I can't recall right now.

  • Check dependencies among features.

  • More plugins.

  • Deploy PAR/ZIP files automatically.

  • Delayed initialization into INC

BUGS

This is running in production right now somewhere in the corporate limbo. It has behaved well... so far.

AUTHORS

    Rodrigo de Oliveira (rodrigolive), C<rodrigolive@gmail.com>

LICENSE

This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself.