Created
June 15, 2011 16:22
-
-
Save thinkerbot/1027463 to your computer and use it in GitHub Desktop.
Illustration of rake/pull/24
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export RUBYOPT='-rpatch' | |
echo '------------ part 1 ------------' | |
rake standard_echo[a,b] | |
# got: a b | |
rake standard_echo['a,b',c] | |
# got: a b | |
rake -- cmd_echo a b | |
# got: a b | |
rake -- cmd_echo 'a,b' c | |
# got: a b | |
echo '------------ part 2 ------------' | |
rake standard_one MESSAGE=hello standard_two MESSAGE=goodbye | |
# goodbye | |
# goodbye | |
rake -- cmd_one -m hello -- cmd_two -m goodbye | |
# hello | |
# goodbye |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'rake' | |
require 'optparse' | |
module Rake | |
class CommandTask < Task | |
def parser | |
@parser ||= OptionParser.new do |opts| | |
opts.on_tail("-h", "--help", "Display this help message.") do | |
puts opts | |
exit | |
end | |
end | |
end | |
def invoke(*args) | |
parser.parse!(args) | |
super(*args) | |
end | |
def invoke_with_call_chain(*args) | |
super | |
reenable | |
end | |
def reenable | |
@config = nil | |
super | |
end | |
def config | |
@configs ||= default_config.dup | |
end | |
def default_config | |
@default_config ||= {} | |
end | |
def [](key) | |
config[key.to_sym] | |
end | |
def method_missing(sym, *args, &block) | |
sym = sym.to_sym | |
config.has_key?(sym) ? config[sym] : super | |
end | |
def set_arg_names(args) | |
while options = parse_options(args.last) | |
set_options(options) | |
args.pop | |
end | |
@arg_names = args.map { |a| a.to_sym } | |
parser.banner = "Usage: rake -- #{name} [options] #{@arg_names.join(' ')}" | |
@arg_names | |
end | |
def parse_options(obj) | |
case obj | |
when Array then [obj] | |
when String then parse_options_string(obj) | |
else nil | |
end | |
end | |
def parse_options_string(string) | |
string = string.strip | |
return nil unless string[0] == ?- | |
string.split(/\s*\n\s*/).collect do |str| | |
flags, desc = str.split(':', 2) | |
flags = flags.split(',').collect! {|arg| arg.strip } | |
key = guess_key(flags) | |
default = flags.last =~ /\s+\[(.*)\]/ ? guess_default($1) : guess_bool_default(flags) | |
[key, default] + flags + [desc.to_s.strip] | |
end | |
end | |
def guess_key(flags) | |
keys = flags.collect do |flag| | |
case flag.split(' ').first | |
when /\A-([^-])\z/ then $1 | |
when /\A--\[no-\](.*)\z/ then $1 | |
when /\A--(.*)\z/ then $1 | |
else nil | |
end | |
end | |
keys.compact.sort_by {|key| key.length }.last | |
end | |
def guess_default(str) | |
case str | |
when /\A(\d+)\z/ then str.to_i | |
when /\A(\d+\.\d+)\z/ then str.to_f | |
else str | |
end | |
end | |
def guess_bool_default(flags) | |
flags.any? {|flag| flag =~ /\A--\[no-\]/ ? true : false } | |
end | |
def set_options(options) | |
options.each do |(key, default, *option)| | |
default = false if default.nil? | |
option = guess_option(key, default) if option.empty? | |
default_config[key.to_sym] = default | |
parser.on(*option) do |value| | |
config[key.to_sym] = parse_config_value(default, value) | |
end | |
end | |
end | |
def guess_option(key, default) | |
n = key.to_s.length | |
case default | |
when false | |
n == 1 ? ["-#{key}"] : ["--#{key}"] | |
when true | |
["--[no-]#{key}"] | |
else | |
n == 1 ? ["-#{key} [#{key.to_s.upcase}]"] : ["--#{key} [#{key.to_s.upcase}]"] | |
end | |
end | |
def parse_config_value(default, value) | |
case default | |
when String then value.to_s | |
when Integer then value.to_i | |
when Float then value.to_f | |
else value | |
end | |
end | |
end | |
end | |
module Rake | |
module DSL | |
def cmd(*args, &block) | |
# Removed to skip depracation warning... | |
# unless args.last.kind_of?(Hash) | |
# args << {:needs => []} | |
# end | |
Rake::CommandTask.define_task(*args, &block) | |
end | |
end | |
end | |
module Rake | |
class Application | |
def format_task_string(args) | |
"#{args.shift}[#{args.join(',')}]" | |
end | |
# Read and handle the command line options. | |
def handle_options | |
options.rakelib = ['rakelib'] | |
OptionParser.new do |opts| | |
opts.banner = "rake [-f rakefile] {options} targets..." | |
opts.separator "" | |
opts.separator "Options are ..." | |
opts.on_tail("-h", "--help", "-H", "Display this help message.") do | |
puts opts | |
exit | |
end | |
standard_rake_options.each { |args| opts.on(*args) } | |
opts.on_tail("--", "Turn on arg syntax ('-- a b c' => 'a[b,c]')") do | |
# restores option break to ARGV if found, allowing arg syntax | |
throw :terminate, "--" | |
end | |
opts.environment('RAKEOPT') | |
end.parse! | |
# If class namespaces are requested, set the global options | |
# according to the values in the options structure. | |
if options.classic_namespace | |
$show_tasks = options.show_tasks | |
$show_prereqs = options.show_prereqs | |
$trace = options.trace | |
$dryrun = options.dryrun | |
$silent = options.silent | |
end | |
end | |
# Collect the list of tasks on the command line. If no tasks are | |
# given, return a list containing only the default task. | |
# Environmental assignments are processed at this time as well. | |
def collect_tasks | |
@top_level_tasks = [] | |
current = nil | |
ARGV.each do |arg| | |
case arg | |
when '--' | |
if current && !current.empty? | |
@top_level_tasks << format_task_string(current) | |
end | |
current = [] | |
when /^(\w+)=(.*)$/ | |
ENV[$1] = $2 | |
else | |
if current | |
current << arg | |
else | |
@top_level_tasks << arg unless arg =~ /^-/ | |
end | |
end | |
end | |
if current && !current.empty? | |
@top_level_tasks << format_task_string(current) | |
end | |
@top_level_tasks.push("default") if @top_level_tasks.size == 0 | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# To run, export RUBYOPT so that it applies the patch before invoking rake: | |
# | |
# export RUBYOPT='-rpatch' | |
# rake -h | |
# rake -T | |
# rake -- cmd_echo a b | |
# | |
# | |
# Part 1 | |
# | |
task :standard_echo, :a, :b do |t, args| | |
message = ENV['MESSAGE'] || 'got' | |
puts "#{message}: #{args.a} #{args.b}" | |
end | |
cmd :cmd_echo, :a, :b, %{ | |
-m,--message [got] : A message | |
} do |config, args| | |
puts "#{config.message}: #{args.a} #{args.b}" | |
end | |
# | |
# Part 2 | |
# | |
task :standard_one do | |
puts(ENV['MESSAGE'] || 'got') | |
end | |
task :standard_two do | |
puts(ENV['MESSAGE'] || 'got') | |
end | |
cmd :cmd_one, %{ | |
-m,--message [got] : A message | |
} do |config, args| | |
puts config.message | |
end | |
cmd :cmd_two, %{ | |
-m,--message [got] : A message | |
} do |config, args| | |
puts config.message | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@richmeyers for the most part I agree with your opinion but I should clarify that the '--' syntax does nothing to fix the escape issues. Commas cannot be specified using either syntax. Here are some examples - see this [gist](https://gist.github.com/1027463) to run these yourself: | |
```bash | |
# [Rakefile] | |
# task :standard_echo, :a, :b do |t, args| | |
# message = ENV['MESSAGE'] || 'got' | |
# puts "#{message}: #{args.a} #{args.b}" | |
# end | |
# | |
# cmd :cmd_echo, :a, :b, %{ | |
# -m,--message [got] : A message | |
# } do |config, args| | |
# puts "#{config.message}: #{args.a} #{args.b}" | |
# end | |
rake standard_echo[a,b] | |
# got: a b | |
rake standard_echo['a,b',c] | |
# got: a b | |
rake -- cmd_echo a b | |
# got: a b | |
rake -- cmd_echo 'a,b' c | |
# got: a b | |
``` | |
To answer your question, one of the benefits of per-task options is that you can specify different options for different tasks. This is not possible with the ENV syntax, or at least opens you up to collisions because ENV is global. Sometimes you do want global options; this proposal provides per-task options when you don't. | |
```bash | |
# [Rakefile (continued)] | |
# task :standard_one do | |
# puts(ENV['MESSAGE'] || 'got') | |
# end | |
# task :standard_two do | |
# puts(ENV['MESSAGE'] || 'got') | |
# end | |
# | |
# cmd :cmd_one, %{ | |
# -m,--message [got] : A message | |
# } do |config, args| | |
# puts config.message | |
# end | |
# cmd :cmd_two, %{ | |
# -m,--message [got] : A message | |
# } do |config, args| | |
# puts config.message | |
# end | |
rake standard_one MESSAGE=hello standard_two MESSAGE=goodbye | |
# goodbye | |
# goodbye | |
rake -- cmd_one -m hello -- cmd_two -m goodbye | |
# hello | |
# goodbye | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment