Skip to content

Commit

Permalink
tasc documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkerbot committed Feb 25, 2011
1 parent e639e9b commit 9778569
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 18 deletions.
131 changes: 119 additions & 12 deletions lib/rake/config_task.rb
Expand Up @@ -3,12 +3,123 @@

module Rake
# #########################################################################
# A ConfigTask is a task that allows simple command line configurations to
# be passed to it. Configurations are parsed as options from the task args.
#
# = ConfigTask
#
# Config tasks allow the creation of tasks that can recieve simple
# configurations using command line options. The intention is to allow
# command-like tasks to be defined and used in a natural way (ie using a 'name
# --flag arg' syntax). For clarity ConfigTasks are declared using 'tasc' and
# referred to as 'tascs'.
#
# Tasc configs are declared using an options string and accessed on the tasc
# itself. Numeric types are cast to appropriate values.
#
# require 'rake'
#
# desc "welcome a thing"
# tasc :welcome, :thing, %{
# -m,--message [hello] : A welcome message
# -n [1] : Number of times to repeat
# } do |config, args|
# config.n.times do
# puts "#{config.message} #{args.thing}"
# end
# end
#
# Then from the command line, invoke after '--':
#
# % rake -- welcome world
# hello world
# % rake -- welcome --message goodnight -n 3 moon
# goodnight moon
# goodnight moon
# goodnight moon
# % rake -- welcome --help
# Usage: rake -- welcome [options] object
# -m, --message [hello] A welcome message
# -n [1] Number of times to repeat
# -h, --help Display this help message.
#
# Unlike typical tasks which only run once, tascs are reset after each run, so
# that they can be invoked multiple times:
#
# % rake -- welcome world -- welcome moon -m goodnight
# hello world
# goodnight moon
#
# Tascs may participate in dependency workflows, although it gets a little
# peculiar when other tasks depend upon the tasc. Below is an explanation.
# TL;DR; -- tascs may have dependencies, but other tasks/tascs should not depend
# upon a tasc.
#
# == Dependency Discussion
#
# Normally tasks are designed to be unaware of context (for lack of a better
# word). Once you introduce arguments/configs, then suddenly it matters when the
# arguments/configs 'get to' a task. For example:
#
# require 'rake'
#
# task(:a) { puts 'a' }
# task(:b => :a) { puts 'b' }
#
# tasc(:x, [:letter, 'x']) {|t| puts t.letter }
# tasc(:y, [:letter, 'y'], :needs => :x) {|t| puts t.letter }
#
# There is no order issue for the tasks, for which there is no context and
# therefore they can align into a one-true execution order regardless of
# declaration order.
#
# % rake a b
# a
# b
# % rake b a
# a
# b
#
# A problem arises, however with tascs that do have a context. Now it matters
# what order things get declared in. For example:
#
# % rake -- x --letter a -- y --letter b
# a
# a
# b
# % rake -- y --letter b -- x --letter a
# x
# b
# a
#
# You can see that declaration order matters for tascs in a way it does not for
# tasks. The problem is not caused directly by the decision to make tascs run
# multiple times; it's caused by the context which gets interwoven to all
# tasks/tascs via dependencies. For example, pretend tascs only executed once...
# which arguments/configurations should win in this case?
#
# % rake -- welcome world -- welcome -m goodnight
# # hello world ?
# # goodnight ?
# # goodnight world ?
#
# All of this can be avoided by only using tascs as end-points for dependency
# workflows and never as prerequisites. This is fine:
#
# require 'rake'
#
# task(:a) { print 'a' }
# task(:b => :a) { print 'b' }
# tasc(:x, [:letter, 'x'], :needs => [:b, :a]) {|t| puts t.letter }
#
# Now:
#
# % rake -- x --letter c
# abc
# % rake a b -- x --letter c
# abc
# % rake b a -- x --letter c
# abc
#
class ConfigTask < Task

# An OptionParser containing the configs for self.
def parser
@parser ||= OptionParser.new do |opts|
opts.on_tail("-h", "--help", "Display this help message.") do
Expand All @@ -21,6 +132,10 @@ def parser
def invoke(*args)
parser.parse!(args)
super(*args)
end

def invoke_with_call_chain(*args)
super
reenable
end

Expand Down Expand Up @@ -115,14 +230,6 @@ def set_options(options)
end
end

# Guess the option declaration for a config given a key and default
# value, according to the following logic:
#
# default opt
# false ['--key']
# true ['--[no-]key']
# (obj) ['--key KEY']
#
def guess_option(key, default)
n = key.to_s.length

Expand Down
12 changes: 6 additions & 6 deletions lib/rake/dsl_definition.rb
Expand Up @@ -29,7 +29,7 @@ def task(*args, &block)
#
# Example:
#
# tasc :say, :object, [:msg, 'hello'], [:n, 1] do |config, args|
# tasc :welcome, :object, [:msg, 'hello'], [:n, 1] do |config, args|
# config.n.times do
# puts "#{config.msg} #{args.object}"
# end
Expand All @@ -39,8 +39,8 @@ def task(*args, &block)
#
# Example:
#
# tasc(:say, :object,
# [:msg, 'hello', '-m', '--message', 'A message string']
# tasc(:welcome, :object,
# [:msg, 'hello', '-m', '--message', 'A welcome message']
# [:n, 1, '-n', 'Number of times to repeat']
# ) do |config, args|
# config.n.times do
Expand All @@ -55,9 +55,9 @@ def task(*args, &block)
#
# Example:
#
# tasc :say, :object, %{
# -m,--message [MSG] : A message string
# -n [1] : Number of times to repeat
# tasc :welcome, :object, %{
# -m,--message [hello] : A welcome message
# -n [1] : Number of times to repeat
# } do |config, args|
# config.n.times do
# puts "#{config.message} #{args.object}"
Expand Down

0 comments on commit 9778569

Please sign in to comment.