Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/drnic/rubigen

Generator framework for your own Ruby framework
https://github.com/drnic/rubigen

Last synced: 3 days ago
JSON representation

Generator framework for your own Ruby framework

Awesome Lists containing this project

README

        

= 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