1. Skip to navigation
  2. Skip to content

The ELC Community Blog

A knowledge exchange on Ruby on Rails and Agile Development


Creating new generator commands

by Daniel Lunde on November 19, 2007

Extending the built-in generator commands

The built-in generator commands will do most of what you would expect (like copy files, create directories, create a file based on a template, and generate migrations), but there are times when we need it do something a little more unique.

For instance, inserting a line (or lines) of code into a given file. In my case I needed to add a new entry into my crossdomain.xml. The following method will insert a new string either before or after a given string match.

This technique builds on the strategy that the scaffold generator uses to insert a map.resources into the routes.rb.

def file_insert(path, insert_me, sentinel, insert_before=true)
  fullpath = destination_path(path)
  content = File.read(fullpath)
  unless content.include? insert_me
    content = content.gsub /(#{Regexp.escape(sentinel)})/mi do |match|
      (insert_before) ? "#{insert_me}#{match}" : "#{match}#{insert_me}"
    end
    File.open(fullpath, 'wb') { |file| file.write(content) }
    logger.updated path
  else
    logger.identical path
  end
end

And here we make the change to the crossdomain.xml

def crossdomain()
  path = 'public/crossdomain.xml'

  domain_list =  "  <allow-access-from domain=\"#{dns_name}\" />\n"
  domain_list += "  <allow-access-from domain=\"*.#{dns_name}\" />\n"

  sentinel = '</cross-domain-policy>'

  file_insert(path, domain_list, sentinel)
end

Using those methods, updating the crossdomain.xml file is easy. And if you happen to re-run the generator with the same parameters, it reports it as identical and won't re-insert the string a second time.

Bringing it all together

So where do we put these methods? You can actually stick them in with your custom generator.

class MyCustomGenerator < Rails::Generator::NamedBase
  attr_reader :dns_name

  def initialize(runtime_args, runtime_options = {})
    super
    @dns_name = args.join.downcase
  end

  def manifest
    record do |m|
      # Add something ridiculous
      m.file_insert('public/500.html', "<h3>Ridiculous</h3>", "<body>", false)
    
      # Add crossdomain entry
      m.crossdomain
    end
  end
  
  protected
  
  # Add your custom methods here...
  def file_insert(...)
    
  def crossdomain()
end

Now if I could just write a generator to build my entire website...

Comments

Add a comment


home | services | Ruby on Rails Development | code | blog | company