= RubiGen - Ruby Generator Framework * http://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 # Application 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