Wednesday, December 19, 2007

Generate Merb Plugins and Generators

As part of my effort to port over restful_authentication I'm at the point where I want to start making a merb plugin gem out of it. This will of course include some generators for merb and datamapper. Later I'll add the Active Record generators. This is super simple thanx to Rubigen

Just today I went to start and found the merb plugin generator wasn't able to generate generators. Now just to move on from that fairly circular sentence, a quick call to DrNic and he had it sorted pretty quickly. The end result is, that as of today, you'll need to install merb from trunk to follow this. That or wait until merb 0.5.0 is released officially.

Generate a Merb Plugin

Merb comes with an option to build the skeleton of a plugin inside the merb command.
$ merb -P merbful_authentication
create
create lib/merbful_authentication
create spec
create Rakefile
create README
create LICENSE
create TODO
create spec/spec_helper.rb
create spec/merbful_authentication_spec.rb
create lib/merbful_authentication.rb
create lib/merbful_authentication/merbtasks.rb
dependency install_rubigen_scripts
create script
create script/generate
create script/destroy
As you can see it's very simple to generate a merb plugin. You could call rake gem in that directory and it will build the gem for you automatically.

From here it's just like any other gem. When you add new files, be sure to add them to the gemspec in the Rakefile.

For the specific case of merbful_authentication, I want to have a generator that is available for all merb projects, and also generators with the relevant code for datamapper, activerecord, and sequel. This is a pretty important way to help support merb's ORM agnosticness.

Merb makes use of rubigen scopes. All merb projects have the merb scope and in your app when you select which orm to use via use_orm the ORM scope is selected automatically. The available scopes in a merb application at the moment are

  • merb

  • merb_default - (used when no orm is selected)

  • datamapper

  • sequel

  • activerecord

  • rspec

  • test_unit

The merb scope is available in all merb projects, with the others available as selected. By default the rspec library is the testing scope that is available.

How to Use Scopes?

When you make your generators, you should apply a scope to them. What this does is allows your gem to behave itself according to the configuration the user has setup. The way I'll setup the generators structure in merbful_authentication will be:

  • merb_generators
    • authentication_generator


  • datamapper_generators
    • authentication_model_generator


  • activerecord_generators
    • authentication_model_generator


  • rspec_generators
    • authentication_testing_generator


  • test_unit_generators
    • authentication_testing_generator


The final names that I end up with might be different, but this is the general structure I will use.

Why this is useful, is that the merb generators are always available, so we can always call the authentication generator in a merb app. This in turn will have a dependency on the authentication_model generator. This is where the magic happens. So if the app has:

Scope : datamapper
The authentication_model generator defined in datamapper_generators will be active and therefore used.

Scope : activerecord
The authentication_model generator defined in activerecord_generators will be active and used instead

This is the way merb generators support the different syntaxes of models and controllers when you use script/generate resource or similar. The testing frameworks will work the same way.

How to Generate a Generator with Scope

To generate your generator with the required scope, it is really simple. In the root directory of your generated plugin:
$ ruby script/generate component_generator authentication merb
create merb_generators/authentication/templates
create test
create merb_generators/authentication/authentication_generator.rb
create test/test_authentication_generator.rb
create test/test_generator_helper.rb
create merb_generators/authentication/USAGE
There are also a whole heap of instructions on what to do next that are put up on the screen.

This will generate the authentication generator in the merb scope. See the documentation for rubigen to see how to use your shiny new generator. It's pretty much the same that you'd do for rails.

So then to make the datamapper generator
ruby script/generate component_generator authentication_model datamapper
I don't want this to show in the list of available generators when you run ruby script/generate so I will delete the USAGE file to prevent it showing up in that list.

Inside the merbful_authentication.rb (your_plugin.rb) file is the place to put your hook script. Similar to the init.rb file in rails plugins.

A note about plugins in general for merb. To mixin behavior to views and controllers you would include into and extend:

Views:- Merb::ViewContext (class)

Controllers:-

  • All controllers - Merb::AbstractController

  • Just web controllers - Merb::Controller (or Application)

  • Just Part controllers - Merb::PartController

  • Just Mail controllers - Merb::MailController

Ok now get out there and make some cool plugins for Merb! :)