File: README.rdoc

# README.rdoc

Path: | README.rdoc
Last Update: | Thu Apr 01 17:20:42 -0600 2010

# RubiGen - Ruby Generator Framework

- drnic.github.com/rubigen

## DESCRIPTION:

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

## 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 (`RAILS_ROOT`), 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.

### Thanks go to…

Jeremy Kemper wrote the original Rails Generator, which is 95% of the basis of RubiGen. He‘s awesome.

## Installation

RubiGen is only required at development time, and normally isn‘t required at deployment time (unless your application uses it to generate files at runtime).

On your development machine:

        sudo gem install rubigen

## Usage

RubiGen comes with a stand-alone executable to allow you to invoke generators:

For example, to run the rails’ `model` generator:

        rubigen rails model Person name:string

would replace the normal

        script/generate model Person name:string

RubiGen has been traditionally integrated into another project, such as `rails`, `newgem` or `camping`, rather than be used on its own.

These frameworks might use RubiGen for two reasons:

1. To generate an initial stub for developers, e.g. `rails` generated a stub to write a Rails application. `newgem` generates a stub to write a RubyGem. BTW - RubiGen has a builtin application `ruby_app` which generates a bare-bones Ruby application stub (lib, test, and script folders, plus a Rakefile, and a script/generate script)
2. To generate components within their development areas, e.g. Rails had its `script/generate` 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:

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

# Creating generators

There are two types of generators:

1. 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 `rails` stub for new Rails applications) for your framework users.
2. 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.

## Creating an Application Generator for your Framework

Without RubiGen, to give your users a head start and create a stub for them, you will copiously use `mkdir_p` and `File.open`. 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 `newgem` script, which I am dubiously responsible for… :P).

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

These are the `newgem` 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 `bin/newgem` script is very simple, and looks like:

        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')

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

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

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

All the generator work is performed within `yourgem_generator.rb`. A stub for it will be:

        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

Easy peasy.

## Creating a Component Generator for your Framework

[Validate]