Class: Tap::Generator::Base

Inherits:
Task
  • Object
show all
Defined in:
lib/tap/generator/base.rb

Overview

:startdoc:::- Base provides the basic structure of a generator and custom generators inherit from it. Base is patterned after the Ruby on Rails generators, but obviously takes on all the advantages of Tasks.

Usage

Tap generators define a manifest method that defines what files and directories are created by the generator. Then, at execution time, a mixin with the appropriate funtion (ie Generate or Destroy) is overlaid to figure out how to roll those actions forward or backwards.

Generators are identified using the ::generator flag rather than ::task, so that generators are available to the generate/destroy commands and not run.

Typically, generators live in a directory structure like this:

root
|- lib
|   `- sample.rb
|
`- templates
    `- sample
        `- template_file.erb

Tap generators keep templates out of lib and under templates, in a directory is named after the generator class. Generators themselves take the form:

[sample.rb]
require 'tap/generator/base'

# ::generator generates a directory, and two files
#
# An extended description of the
# generator goes here...
#
class Sample < Tap::Generator::Base

  config :key, 'value'       # a sample config

  def manifest(m, *args)
    # make a directory
    m.directory('path/to/dir')

    # make a file
    m.file('path/to/file.txt') do |file|
      file << "some content"
    end

    # template a file
    m.template('path/to/result.txt', 'template_file.erb', config.to_hash)
  end
end

The arguments that a generator receives are specified by manifest (minus the ‘m’ argument which is standard) rather than process. Creating directories and files is straightforward, as above. Template renders the erb source file using attributes specified in the last argument; in the example template uses the generator configurations.

:startdoc:::+

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}, app = Tap::App.instance) ⇒ Base

Returns a new instance of Base.



97
98
99
100
101
102
# File 'lib/tap/generator/base.rb', line 97

def initialize(config={}, app=Tap::App.instance)
  super
  @prompt_in = $stdin
  @prompt_out = $stdout
  @template_dir = File.expand_path("templates/#{self.class.to_s.underscore}")
end

Instance Attribute Details

#prompt_inObject

The IO used to pull prompt inputs (default: $stdin)



92
93
94
# File 'lib/tap/generator/base.rb', line 92

def prompt_in
  @prompt_in
end

#prompt_outObject

The IO used to prompt users for input (default: $stdout)



95
96
97
# File 'lib/tap/generator/base.rb', line 95

def prompt_out
  @prompt_out
end

#template_dirObject

The generator-specific templates directory. By default: ‘templates/path/to/name’ for ‘lib/path/to/name.rb’



89
90
91
# File 'lib/tap/generator/base.rb', line 89

def template_dir
  @template_dir
end

Instance Method Details

#actionObject

Returns the action for self (ie :generate or :destroy)

Raises:

  • (NotImplementedError)


204
205
206
# File 'lib/tap/generator/base.rb', line 204

def action
  raise NotImplementedError
end

#directories(root, targets, options = {}) ⇒ Object

Makes (or destroys) the root and each of the targets, relative to root. Options are passed onto directory.



156
157
158
159
160
161
162
# File 'lib/tap/generator/base.rb', line 156

def directories(root, targets, options={})
  results = [directory(root, options)]
  targets.each do |target|
    results << directory(File.join(root, target), options)
  end
  results
end

#directory(target, options = {}) ⇒ Object

Peforms a directory action (ex generate or destroy). Must be overridden by one of the action mixins (ex Generate or Destroy).

Raises:

  • (NotImplementedError)


142
143
144
# File 'lib/tap/generator/base.rb', line 142

def directory(target, options={})
  raise NotImplementedError
end

#file(target, options = {}) ⇒ Object

Peforms a file action (ex generate or destroy). Calls to file specify input for a target by providing a block; the block recieves an IO and pushes content to it. Must be overridden by one of the action mixins (ex Generate or Destroy).

Raises:

  • (NotImplementedError)


150
151
152
# File 'lib/tap/generator/base.rb', line 150

def file(target, options={}) # :yields: io
  raise NotImplementedError
end

#iterate(actions) ⇒ Object

Peforms each of the input actions in order, and collects the results. The process method returns these results.



131
132
133
# File 'lib/tap/generator/base.rb', line 131

def iterate(actions)
  actions.collect {|action| yield(action) }
end

#log_relative(action, path) ⇒ Object

Logs the action with the relative filepath from Dir.pwd to path.



209
210
211
212
# File 'lib/tap/generator/base.rb', line 209

def log_relative(action, path)
  relative_path = Tap::Root::Utils.relative_path(Dir.pwd, path)
  log(action, relative_path || path)
end

#manifest(m, *argv) ⇒ Object

Overridden in subclasses to add actions to the input Manifest. Any arguments passed to process will be passed to manifest unchanged.

Raises:

  • (NotImplementedError)


125
126
127
# File 'lib/tap/generator/base.rb', line 125

def manifest(m, *argv)
  raise NotImplementedError
end

#on(*actions, &block) ⇒ Object

Calls the block when specified by the action for self.



195
196
197
198
199
200
201
# File 'lib/tap/generator/base.rb', line 195

def on(*actions, &block)
  if actions.include?(action)
    block.call
  else
    nil
  end
end

#path(*paths) ⇒ Object

Constructs a path relative to destination_root.



136
137
138
# File 'lib/tap/generator/base.rb', line 136

def path(*paths)
  File.expand_path(File.join(*paths), destination_root)
end

#process(*argv) ⇒ Object

Builds the manifest, then executes the actions of the manifest. Process returns the results of iterate, which normally will be an array of files and directories created (or destroyed) by self.



113
114
115
116
117
118
119
120
# File 'lib/tap/generator/base.rb', line 113

def process(*argv)
  actions = []
  manifest(Manifest.new(actions), *argv)
  
  iterate(actions) do |action, args, block|
    send(action, *args, &block)
  end
end

#set(mod) ⇒ Object



104
105
106
107
108
# File 'lib/tap/generator/base.rb', line 104

def set(mod)
  mod = app.env[mod] unless mod.class == Module
  extend(mod)
  self
end

#template(target, source, attributes = {}, options = {}) ⇒ Object

Makes (or destroys) the target by templating the source using the specified attributes. Source is expanded relative to template_dir. Options are passed onto file.



167
168
169
170
171
172
173
174
175
176
# File 'lib/tap/generator/base.rb', line 167

def template(target, source, attributes={}, options={})
  raise "no template dir is set" unless template_dir
  
  template_path = File.expand_path(source, template_dir)
  templater = Templater.new(File.read(template_path), attributes)
  
  file(target, options) do |file| 
    file << templater.build(nil, template_path)
  end
end

#template_filesObject

Yields each source file under template_dir to the block, with a target path of the source relative to template_dir.



180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/tap/generator/base.rb', line 180

def template_files
  raise "no template dir is set" unless template_dir
  
  targets = []
  Dir.glob(template_dir + "/**/*").sort.each do |source|
    next unless File.file?(source)
    
    target = Tap::Root::Utils.relative_path(template_dir, source)
    yield(source, target)
    targets << target
  end
  targets
end