h1. rubigen

h1. Ruby Generator Framework

h2. What

A framework to allow Ruby applications to generate file/folder stubs (like the <code>rails</code> command does for Ruby on Rails, and the 'script/generate' command within a Rails application during development).

The RubyConf 2007 presentation is now "online":http://rubyconf2007.confreaks.com/d3t1p1_rubigen.html together with the theme from the A-Team.

h2. Background

RubiGen is originally extracted from Ruby on Rails (specifically the rails_generator from its railties gem).

The rails_generator was hardcoded with Rails-specific dependencies (<code>RAILS_ROOT</code>), Rails generators ('app' = Rails application; 'model' = Rails model+tests+migration), and generally assumed it was the only generator framework within the Ruby world (it was). So, any RubyGem whose name ended with '_generator' was assumed to be a generator for a Rails application.

But if you are developing an Adhearsion application, then you may want a different set of generators.
If you are developing a RubyGem, then you will want a different set of generators.

RubiGen exists to give different development environments their own generator framework.

h2. Installing

RubiGen is only required at development time, and normally isn't required at deployment time (unless your application uses it to generate files etc for its users).

On your development machine:

<pre syntax="ruby">sudo gem install rubigen</pre>

h2. Usage

RubiGen will be normally integrated into another RubyGem, such as <code>newgem</code> or <code>rails</code> or <code>camping</code>, rather than be used on its own.

These frameworks might use RubiGen for two reasons:
  
# To generate an initial stub for developers, e.g. <code>rails</code> generated a stub to write a Rails application. <code>newgem</code> generates a stub to write a RubyGem. <br/>
  BTW - RubiGen has a builtin application <code>ruby_app</code> which generates a bare-bones Ruby application stub (lib, test, and script folders, plus a Rakefile, and a script/generate script)
# To generate components within their development areas, e.g. Rails had its <code>script/generate</code> script within each Rails application, which hooked back into the rails_generator to lookup and execute generators.

So, there are two steps to integrating RubiGen into your framework:

# Use it to generate an initial stub for the developers of your framework. This would create the folders 
   (<code>lib/app</code>, <code>test</code>, <code>script</code>, <code>doc</code>, <code>log</code>, etc) and starting files (<code>Rakefile</code>, 
   <code>README.txt</code>, <code>test/test_helper.rb</code> etc). Importantly, it would generate a <code>script/generate</code> file.
   The <code>script/generate</code> file (example below) will allow developers of your framework to 
   generate components/extensions within the framework. <br />
   RubiGen allows you to restrict which generators are available. For example, within
   RubyGem development environment (as generated by <code>newgem</code>), the <code>script/generator</code>
   only shows <code>rubygem</code>-related generators. Rails could restrict <code>script/generator</code>
   to only show Rails related generators
# Your framework RubyGem (e.g. <code>newgem</code> or <code>rails</code> RubyGems) needs to add <code>rubigen</code> as a 
   dependency, so that users of your RubyGem can access the generator framework.

h1. Creating generators

There are two types of generators:

# Application Generators - used by developers of your framework to get started. 
   Generally, you will create one Application Generator for your framework.
   It generates a base stub (such as the <code>rails</code> stub for new Rails applications)
   for your framework users.
# Component Generators - used by developers to extend their application.
   You may include 1+ built-in generators with your framework.
   Developers can also write generators for your framework, and like Rails' generator
   install them in various places and have access to their via RubiGen.

h2. Creating an Application Generator for your Framework

h3. Easy way

"newgem":http://newgem.rubyforge.org/ (v0.13.0+) can generate an Application Generator
for a RubyGem.

# Create new RubyGem: <code>newgem foobar</code>
# Create generator: <code>script/generator application_generator foobar</code>
# Update tests + generator
# Install
# Run with: foobar

For more documentation, run <code>script/generator application_generator</code>

h3. DIY

Without RubiGen, to give your users a head start and create a stub for them, you will 
copiously use <code>mkdir_p</code> and <code>File.open</code>. Your script will either be primitive (only
create the bare folders and very few files) or it will be very long and unreadable
(ok, perhaps I'm just talking about the <code>newgem</code> script, which I am dubiously responsible
for... :P).

With RubiGen, you can create stubs using powerful, yet simple, syntax. Templates are
extracted into a <code>templates</code> folder, and activating the generator from a script requires
only a few lines of code.

These are the <code>newgem</code> files related to its Application Generator.

    bin/
      bin/newgem        # Appliction Generator script; Usage: newgem gemname [options]
    app_generators/
      app_generators/newgem/
        app_generators/newgem/newgem_generator.rb
        app_generators/newgem/USAGE
        app_generators/newgem/templates/
          app_generators/newgem/templates/app.rb
          app_generators/newgem/templates/History.txt
          app_generators/newgem/templates/... lots and lots of templates

The <code>bin/newgem</code> script is very simple, and looks like:

<pre syntax="ruby">
require 'rubygems'
require 'rubigen'

if %w(-v --version).include? ARGV.first
  require 'newgem/version'
  puts "#{File.basename($0)} #{Newgem::VERSION}"
  exit(0)
end

require 'rubigen/scripts/generate'
RubiGen::Base.use_application_sources!
RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'newgem')
</pre>

You can copy and paste this for your own generator script, and place it in your RubyGem's <code>bin</code> folder.
Change <code>newgem</code> to your RubyGem's name in the script above (and in all the folders listed above too)

NOTE: If you leave <code>newgem</code> there, then it will execute the <code>newgem_generator.rb</code> generator; 
as the generators are loaded from all RubyGem's having <code>/app_generators</code> folders.

So, for your RubyGem, you need to keep the <code>/app_generators</code> folder (as you are creating an 
Application Generator, not a Component Generator), but change <code>newgem</code> to <code>your gem name</code> in
all the subfolders and files. ESPECIALLY <code>newgem_generator.rb</code> -> <code>yourgem_generator.rb</code>,
as this is how the generator is discovered (via <code>RubiGen::Base.use_application_sources!</code>).

All the generator work is performed within <code>yourgem_generator.rb</code>. A stub for it will be:

<pre syntax="ruby">
require 'rbconfig'

class YourgemGenerator < RubiGen::Base
  DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
                              Config::CONFIG['ruby_install_name'])
                              
  default_options   :shebang => DEFAULT_SHEBANG,
                    :an_option => 'some_default'
  
  attr_reader :app_name, :module_name
  
  def initialize(runtime_args, runtime_options = {})
    super
    usage if args.empty?
    @destination_root = args.shift
    @app_name     = File.basename(File.expand_path(@destination_root))
    @module_name  = app_name.camelize
    extract_options
  end
    
  def manifest
    # Use /usr/bin/env if no special shebang was specified
    script_options     = { :chmod => 0755, :shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang] }
    windows            = (RUBY_PLATFORM =~ /dos|win32|cygwin/i) || (RUBY_PLATFORM =~ /(:?mswin|mingw)/)
    
    record do |m|
      # Root directory and all subdirectories.
      m.directory ''
      BASEDIRS.each { |path| m.directory path }
      
      # Root
      m.template_copy_each %w( Rakefile )
      m.file_copy_each     %w( README.txt )

      # Test helper
      m.template   "test_helper.rb",        "test/test_helper.rb"

      # Scripts
      %w( generate ).each do |file|
        m.template "script/#{file}",        "script/#{file}", script_options
        m.template "script/win_script.cmd", "script/#{file}.cmd", 
          :assigns => { :filename => file } if windows
      end
   
    end
  end

  protected
    def banner
      <<-EOS
Create a stub for #{File.basename $0} to get started.

Usage: #{File.basename $0} /path/to/your/app [options]"
EOS
    end

    def add_options!(opts)
      opts.separator ''
      opts.separator "#{File.basename $0} options:"
      opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
    end

  # Installation skeleton.  Intermediate directories are automatically
  # created so don't sweat their absence here.
  BASEDIRS = %w(
    doc
    lib
    log
    script
    test
    tmp
  )
end
</pre>

Easy peasy.

h2. Creating a Component Generator for your Framework

You can include Component Generators in RubyGems, and they will be automatially picked up
by your framework's <code>script/generate</code> script.

h3. Easy way

Use "newgem":http://newgem.rubyforge.org/, (v0.13.0+), and run:

<pre>
script/generate component_generator
</pre>

and follow the instructions.

h2. Live at RubyConf 2007

RubiGen had the 9am, Sunday timeslot at RubyConf 2007 and was "recorded for your viewing pleasure":http://rubyconf2007.confreaks.com/d3t1p1_rubigen.html.

h2. Forum

"http://groups.google.com/group/rubigen":http://groups.google.com/group/rubigen

h2. How to submit patches

Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/ and for section "8b: Submit patch to Google Groups":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups, use the Google Group above.

The source for this project is available via git. You can "browse and/or fork the source":http://github.com/drnic/rubigen/tree/master, or to clone the project locally:
  
<pre>git clone git://github.com/drnic/rubigen.git</pre>

The original Subversion repository is <code>svn://rubyforge.org/var/svn/rubigen/trunk</code> for anonymous access.

h2. Thanks go to...

"Jeremy Kemper":http://bitsweat.net/ (bitsweat) who wrote the original "Rails Generator":http://dev.rubyonrails.org.

h2. License

This code is free to use under the terms of the MIT license. 

h2. Contact

Comments are welcome. Send an email to "Dr Nic Williams":mailto:drnicwilliams@gmail.com via the "forum":http://groups.google.com/group/rubigen