Class: Sprout::ToolTask

Inherits:
Rake::FileTask
  • Object
show all
Defined in:
lib/sprout/tasks/tool_task.rb

Overview

The ToolTask provides some base functionality for any Command Line Interface (CLI) tool. It also provides support for GUI tools that you would like to expose from the Command Line (Like the Flash Player for example).

ToolTask extends Rake::FileTask, and should be thought of in the same way. Martin Fowler did a much better job of describing Rake and specifically FileTasks than I can in his (now classic) Rake article from 2005.

What this means is that most tool task instances should be named for the file that they will create. For example, an Sprout::MXMLCTask instance should be named for the SWF that it will generate.

mxmlc 'bin/SomeProject.swf' => :corelib do |t|
  t.input                     = 'src/SomeProject.as'
  t.default_size              = '800 600'
  t.namespace = "my_namespace://path\ " + File.expand_path("~/Desktop/SomeProject/build/main.xml") 
end

If you don’t put a “\ ” for the space in the “t.namespace” directive, you’ll get this: rake aborted!

ERROR

command line: Error: default arguments may not be interspersed with other options

In general, a tool task will only be executed if it’s output file (name) does not exist or if the output file is older than any file identified as a prerequisite.

Many of the compiler tasks take advantage of this feature by opting out of unnecessary compilation.

Subclasses can add and configure command line parameters by calling the protected add_param method that is implemented on this class.

Constant Summary collapse

@@preprocessed_tasks =
Hash.new

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, app) ⇒ ToolTask

:nodoc:



51
52
53
54
55
56
57
58
59
# File 'lib/sprout/tasks/tool_task.rb', line 51

def initialize(name, app) # :nodoc:
  super
  @preprocessed_path = nil
  @prepended_args    = nil
  @appended_args     = nil
  @default_gem_name  = nil
  @default_gem_path  = nil
  initialize_task
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object (protected)



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/sprout/tasks/tool_task.rb', line 368

def method_missing(name, *args)
  name = name.to_s
  cleaned = clean_name(name)
  if(!respond_to?(cleaned))
    raise NoMethodError.new("undefined method '#{name}' for #{self.class}", name)
  end
  param = param_hash[cleaned]

  matched = name =~ /=$/
  if(matched)
    param.value = args.shift
  elsif(param)
    param.value
  else
    raise ToolTaskError.new("method_missing called with undefined parameter [#{name}]")
  end
end

Class Method Details

.add_preprocessed_task(name) ⇒ Object



39
40
41
# File 'lib/sprout/tasks/tool_task.rb', line 39

def self.add_preprocessed_task(name)
  @@preprocessed_tasks[name] = true
end

.clear_preprocessed_tasksObject



47
48
49
# File 'lib/sprout/tasks/tool_task.rb', line 47

def self.clear_preprocessed_tasks
  @@preprocessed_tasks.clear
end

.define_task(args, &block) ⇒ Object



61
62
63
64
65
66
67
68
69
70
# File 'lib/sprout/tasks/tool_task.rb', line 61

def self.define_task(args, &block)
  t = super
  if(t.is_a?(ToolTask))
    t.find_and_resolve_model
    yield t if block_given?
    t.define
    t.prepare
  end
  return t
end

.has_preprocessed_task?(name) ⇒ Boolean

Returns:

  • (Boolean)


43
44
45
# File 'lib/sprout/tasks/tool_task.rb', line 43

def self.has_preprocessed_task?(name)
  !@@preprocessed_tasks[name].nil?
end

Instance Method Details

#appended_argsObject

Returns arguments that were appended at the end of the command line output



156
157
158
# File 'lib/sprout/tasks/tool_task.rb', line 156

def appended_args
  @appended_args
end

#appended_args=(args) ⇒ Object

Arguments to appended at the end of the command line output



151
152
153
# File 'lib/sprout/tasks/tool_task.rb', line 151

def appended_args=(args)
  @appended_args = args
end

#default_file_expressionObject

The default file expression to append to each PathParam in order to build file change prerequisites.

Defaults to ‘///*’



273
274
275
# File 'lib/sprout/tasks/tool_task.rb', line 273

def default_file_expression
  @default_file_expression ||= '/**/**/*'
end

#defineObject



252
253
254
# File 'lib/sprout/tasks/tool_task.rb', line 252

def define
  resolve_libraries(prerequisites)
end

#display_preprocess_messageObject

:nodoc:



205
206
207
208
209
# File 'lib/sprout/tasks/tool_task.rb', line 205

def display_preprocess_message # :nodoc:
  if(!preprocessor.nil?)
    puts ">> Preprocessed text files in: #{File.join(Dir.pwd, preprocessed_path)} with #{preprocessor}"
  end
end

#each_paramObject



107
108
109
110
111
# File 'lib/sprout/tasks/tool_task.rb', line 107

def each_param
  params.each do |param|
    yield param if block_given?
  end
end

#execute(*args) ⇒ Object



211
212
213
214
215
# File 'lib/sprout/tasks/tool_task.rb', line 211

def execute(*args)
  display_preprocess_message
  exe = Sprout.get_executable(gem_name, gem_path, gem_version)
  User.execute(exe, to_shell)
end

#find_and_resolve_modelObject

Look for a ToolTaskModel in the list of prerequisites. If found, apply any applicable params to self…



259
260
261
262
263
264
265
266
# File 'lib/sprout/tasks/tool_task.rb', line 259

def find_and_resolve_model
  prerequisites.each do |prereq|
    instance = Rake::application[prereq]
    if(instance.is_a?(ToolTaskModel))
      resolve_model(instance)
    end
  end
end

#gem_nameObject

Full name of the sprout tool gem that this tool task will use. For example, the MXMLCTask uses the sprout-flex3sdk-tool at the time of this writing, but will at some point change to use the sprout-flex3sdk-tool. You can combine this value with gem_version in order to specify exactly which gem your tool task is executing.



76
77
78
# File 'lib/sprout/tasks/tool_task.rb', line 76

def gem_name
  return @gem_name ||= @default_gem_name
end

#gem_name=(name) ⇒ Object



80
81
82
# File 'lib/sprout/tasks/tool_task.rb', line 80

def gem_name=(name)
  @gem_name = name
end

#gem_pathObject

The path inside the installed gem where an executable can be found. For the MXMLCTask, this value is ‘bin/mxmlc’.



103
104
105
# File 'lib/sprout/tasks/tool_task.rb', line 103

def gem_path
  return @gem_path ||= @default_gem_path
end

#gem_versionObject

The exact gem version that you would like the ToolTask to execute. By default this value should be nil and will download the latest version of the gem that is available unless there is a version already installed on your system.

This attribute could be an easy way to update your local gem to the latest version without leaving your build file, but it’s primary purpose is to allow you to specify very specific versions of the tools that your project depends on. This way your team can rest assured that they are all working with the same tools.



93
94
95
# File 'lib/sprout/tasks/tool_task.rb', line 93

def gem_version
  return @gem_version ||= nil
end

#gem_version=(version) ⇒ Object



97
98
99
# File 'lib/sprout/tasks/tool_task.rb', line 97

def gem_version=(version)
  @gem_version = version
end

#paramsObject

An Array of all parameters that have been added to this Tool.



233
234
235
# File 'lib/sprout/tasks/tool_task.rb', line 233

def params
  @params ||= []
end

#prepareObject

Called after initialize and define, usually subclasses should only override define.



239
240
241
242
243
244
245
# File 'lib/sprout/tasks/tool_task.rb', line 239

def prepare
  # Get each added param to inject prerequisites as necessary
  params.each do |param|
    param.prepare
  end
  prepare_prerequisites
end

#prepare_prerequisitesObject



247
248
249
250
# File 'lib/sprout/tasks/tool_task.rb', line 247

def prepare_prerequisites
  # Ensure there are no duplicates in the prerequisite collection
  @prerequisites = prerequisites.uniq
end

#prepended_argsObject

Returns arguments that were prepended in front of the command line output



146
147
148
# File 'lib/sprout/tasks/tool_task.rb', line 146

def prepended_args
  @prepended_args
end

#prepended_args=(args) ⇒ Object

Arguments to be prepended in front of the command line output



141
142
143
# File 'lib/sprout/tasks/tool_task.rb', line 141

def prepended_args=(args)
  @prepended_args = args
end

#preprocessed_pathObject



201
202
203
# File 'lib/sprout/tasks/tool_task.rb', line 201

def preprocessed_path
  @preprocessed_path ||= '.preprocessed'
end

#preprocessed_path=(preprocessed_path) ⇒ Object

Path where preprocessed files are stored. Defaults to ‘.preprocessed’



197
198
199
# File 'lib/sprout/tasks/tool_task.rb', line 197

def preprocessed_path=(preprocessed_path)
  @preprocessed_path = preprocessed_path
end

#preprocessorObject



192
193
194
# File 'lib/sprout/tasks/tool_task.rb', line 192

def preprocessor
  @preprocessor
end

#preprocessor=(preprocessor) ⇒ Object

Command line arguments to execute preprocessor. The preprocessor execution should accept text via STDIN and return its processed content via STDOUT.

In the following example, the MXMLCTask has been configured to use the C preprocessor (cpp) and place the processed output into a _preprocessed folder, instead of the hidden default folder at .preprocessed.

One side effect of the cpp tool is that it adds 2 carriage returns to the top of any processed files, so we have simply piped its output to the tail command which then strips those carriage returns from all files - which retains accurate line numbers for any compiler error messages.

mxmlc 'bin/SomeProject.swf' => :corelib do |t|
  t.input                     = 'src/SomeProject.as'
  t.default_size              = '800 600'
  t.preprocessor              = 'cpp -D__DEBUG=true -P - - | tail -c +3'
  t.preprocessed_path         = '_preprocessed'
end

Any source files found in this example project can now take advantage of any tools, macros or syntax available to CPP. For example, the __DEBUG variable is now defined and can be accessed in ActionScript source code as follows:

public static const DEBUG:Boolean = __DEBUG;

Any commandline tool identified on this attribute will be provided the content of each file on STDIN and whatever it returns to STDOUT will be written into the preprocessed_path. This means that we can take advantage of the entire posix tool chain by piping inputs and outputs from one tool to another. Whatever the last tool returns will be handed off to the concrete compiler.



188
189
190
# File 'lib/sprout/tasks/tool_task.rb', line 188

def preprocessor=(preprocessor)
  @preprocessor = preprocessor
end

#to_rdocObject

Create a string that can be turned into a file that rdoc can parse to describe the customized or generated task using param name, type and description



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/sprout/tasks/tool_task.rb', line 117

def to_rdoc
  result = ''
  parts = self.class.to_s.split('::')
  class_name = parts.pop
  module_count = 0
  while(module_name = parts.shift)
    result << "module #{module_name}\n"
    module_count += 1
  end
  
  result << "class #{class_name} < ToolTask\n"

  params.each do |param|
    result << param.to_rdoc
  end

  while((module_count -= 1) >= 0)
    result << "end\nend\n"
  end

  return result
end

#to_shellObject

Create a string that represents this configured tool for shell execution



218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/sprout/tasks/tool_task.rb', line 218

def to_shell
  return @to_shell_proc.call(self) if(!@to_shell_proc.nil?)

  result = []
  result << @prepended_args unless @prepended_args.nil?
  params.each do |param|
    if(param.visible?)
      result << param.to_shell
    end
  end
  result << @appended_args unless @appended_args.nil?
  return result.join(' ')
end