Class Sprout::ToolTask
In: sprout/lib/sprout/tasks/tool_task.rb
Parent: Rake::FileTask

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'
  end

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.

Methods

Public Class methods

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 34
    def self.add_preprocessed_task(name)
      @@preprocessed_tasks[name] = true
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 42
    def self.clear_preprocessed_tasks
      @@preprocessed_tasks.clear
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 56
    def self.define_task(args, &block)
      t = super
      if(t.is_a?(ToolTask))
        yield t if block_given?
        t.define
        t.prepare
      end
      return t
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 38
    def self.has_preprocessed_task?(name)
      !@@preprocessed_tasks[name].nil?
    end

Public Instance methods

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 144
    def appended_args
      @appended_args
    end

Arguments to appended at the end of the command line output

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 139
    def appended_args=(args)
      @appended_args = args
    end

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

Defaults to ’/**/**/*’

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 244
    def default_file_expression
      @default_file_expression ||= '/**/**/*'
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 235
    def define
      resolve_libraries(prerequisites)
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 199
    def execute(*args)
      display_preprocess_message
      #puts ">> Executing #{File.basename(exe)} #{to_shell}"
      exe = Sprout.get_executable(gem_name, gem_path, gem_version)
      User.execute(exe, to_shell)
    end

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.

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 70
    def gem_name
      return @gem_name ||= @default_gem_name
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 74
    def gem_name=(name)
      @gem_name = name
    end

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 97
    def gem_path
      return @gem_path ||= @default_gem_path
    end

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.

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 87
    def gem_version
      return @gem_version ||= nil
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 91
    def gem_version=(version)
      @gem_version = version
    end

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 220
    def params
      @params ||= []
    end

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 226
    def prepare
      # Get each added param to inject prerequisites as necessary
      params.each do |param|
        param.prepare
      end
      # Ensure there are no duplicates in the prerequisite collection
      @prerequisites = prerequisites.uniq
    end

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 134
    def prepended_args
      @prepended_args
    end

Arguments to be prepended in front of the command line output

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 129
    def prepended_args=(args)
      @prepended_args = args
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 189
    def preprocessed_path
      @preprocessed_path ||= '.preprocessed'
    end

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 185
    def preprocessed_path=(preprocessed_path)
      @preprocessed_path = preprocessed_path
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 180
    def preprocessor
      @preprocessor
    end

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.

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 176
    def preprocessor=(preprocessor)
      @preprocessor = preprocessor
    end

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 105
    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

Create a string that represents this configured tool for shell execution

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 207
    def to_shell
      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

Protected Instance methods

add_param is the workhorse of the ToolTask. This method is used to add new shell parameters to the task. name is a symbol or string that represents the parameter that you would like to add such as :debug or :source_path. type is usually sent as a Ruby symbol and can be one of the following:

:string
Any string value
:boolean
true or false
:number
Any number
:file
Path to a file
:url
Basic URL
:path
Path to a directory
:files
Collection of files
:paths
Collection of directories
:strings
Collection of arbitrary strings
:urls
Collection of URLs

Be sure to check out the Sprout::TaskParam class to learn more about block editing the parameters.

Once parameters have been added using the add_param method, clients can set and get those parameters from the newly created task.

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 282
    def add_param(name, type, &block) # :yields: Sprout::TaskParam
      name = name.to_s

      # First ensure the named accessor doesn't yet exist...
      if(param_hash[name])
        raise ToolTaskError.new("TaskBase.add_param called with existing parameter name: #{name}")
      end

      param = create_param(type)
      param.init do |p|
        p.belongs_to = self
        p.name = name
        p.type = type
        yield p if block_given?
      end

      param_hash[name] = param
      params << param
    end

Alias an existing parameter with another name. For example, the existing parameter :source_path might be given an alias ’-sp’ as follows:

  add_param_alias(:sp, :source_path)

Alias parameters cannot be configured differently from the parameter that they alias

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 310
    def add_param_alias(name, other_param)
      if(param_hash.has_key? other_param.to_s)
        param_hash[name.to_s] = param_hash[other_param.to_s]
      else
        raise ToolTaskError.new("TaskBase.add_param_alis called with")
      end
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 336
    def clean_name(name)
      name.gsub(/=$/, '')
    end

If the provided path contains spaces, wrap it in quotes so that shell tools won‘t choke on the spaces

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 378
    def clean_path(path)
      if(path.index(' '))
        path = %{"#{path}"}
      end
      return path
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 320
    def create_param(type)
      return eval("#{type.to_s.capitalize}Param.new")
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 250
    def initialize_task
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 340
    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]

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

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 324
    def param_hash
      @param_hash ||= {}
    end

Iterate over all prerequisites looking for any that are a LibraryTask. Concrete ToolTask implementations should override resolve_library in order to add the library sources or binaries appropriately.

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 362
    def resolve_libraries(prerequisites)
      prerequisites.each do |prereq|
        instance = Rake::application[prereq]
        if(instance.is_a?(LibraryTask))
          resolve_library(instance)
        end
      end
    end

Concrete ToolTasks should override this method and add any dependent libraries appropriately

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 373
    def resolve_library(library_task)
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 328
    def respond_to?(name)
      result = super
      if(!result)
        result = param_hash.has_key? name
      end
      return result
    end

[Source]

# File sprout/lib/sprout/tasks/tool_task.rb, line 253
    def validate
      params.each do |param|
        param.validate
      end
    end

[Validate]