detroit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.ruby +45 -0
- data/COPYING.rdoc +19 -0
- data/EXAMPLE.md +188 -0
- data/GPL3.txt +675 -0
- data/HISTORY.rdoc +14 -0
- data/README.rdoc +139 -0
- data/bin/detroit +9 -0
- data/lib/detroit.rb +67 -0
- data/lib/detroit.yml +45 -0
- data/lib/detroit/application.rb +427 -0
- data/lib/detroit/assembly.rb +80 -0
- data/lib/detroit/config.rb +197 -0
- data/lib/detroit/control.rb +124 -0
- data/lib/detroit/core_ext.rb +139 -0
- data/lib/detroit/custom.rb +65 -0
- data/lib/detroit/dsl.rb +55 -0
- data/lib/detroit/schedule.rb +187 -0
- data/lib/detroit/service.rb +188 -0
- data/lib/detroit/standard_assembly.rb +52 -0
- data/lib/detroit/tool.rb +216 -0
- data/lib/detroit/tool/core_ext.rb +3 -0
- data/lib/detroit/tool/core_ext/facets.rb +11 -0
- data/lib/detroit/tool/core_ext/filetest.rb +29 -0
- data/lib/detroit/tool/core_ext/shell_extensions.rb +7 -0
- data/lib/detroit/tool/core_ext/to_actual_filename.rb +19 -0
- data/lib/detroit/tool/core_ext/to_console.rb +97 -0
- data/lib/detroit/tool/core_ext/to_list.rb +29 -0
- data/lib/detroit/tool/core_ext/to_yamlfrag.rb +9 -0
- data/lib/detroit/tool/core_ext/unfold_paragraphs.rb +27 -0
- data/lib/detroit/tool/email_utils.rb +288 -0
- data/lib/detroit/tool/project_utils.rb +41 -0
- data/lib/detroit/tool/shell_utils.rb +235 -0
- data/qed/01_schedule/02_initialize.md +57 -0
- data/qed/99_plugins/rdoc/rdoc-plugin.rdoc +22 -0
- data/qed/99_plugins/rdoc/sample/Syckfile +6 -0
- data/qed/99_plugins/rdoc/sample/lib/sandbox/.xxx +1 -0
- data/qed/99_plugins/rdoc/sample/lib/sandbox/hello.rb +5 -0
- data/qed/99_plugins/rdoc/sample/lib/sandbox/xxx.rb +6 -0
- data/qed/99_plugins/rdoc/sample/lib/xxx/bye.rb +4 -0
- data/qed/99_plugins/rdoc/sample/meta/name +1 -0
- data/qed/99_plugins/rdoc/sample/meta/version +1 -0
- data/qed/samples/example_project/.ruby +0 -0
- data/qed/samples/example_project/Schedule +9 -0
- data/qed/samples/example_project/lib/foo/.xxx +1 -0
- data/qed/samples/example_project/lib/foo/hello.rb +7 -0
- data/qed/samples/example_project/lib/foo/xxx.rb +6 -0
- data/qed/samples/example_project/lib/foo/xxx/bye.rb +4 -0
- data/qed/samples/example_project/meta/name +1 -0
- data/qed/samples/example_project/meta/version +1 -0
- data/qed/samples/example_schedule.rb +57 -0
- metadata +139 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
module Detroit
|
2
|
+
|
3
|
+
# All assemblies and tracks have a maintenance sub-track.
|
4
|
+
# For this reason stop names `reset`, `clean` and `purge`
|
5
|
+
# are reserved names and MUST not be used as stop names
|
6
|
+
# in defining custom lines.
|
7
|
+
MAINTENANCE_TRACK = [:reset, :clean, :purge]
|
8
|
+
|
9
|
+
# Returns Hash of name and Circuit instance pairs.
|
10
|
+
def self.assemblies
|
11
|
+
@assemblies ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Define a new assembly.
|
15
|
+
def self.assembly(name, &block)
|
16
|
+
assemblies[name.to_sym] = Assembly.new(name, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# The Assembly class encapsulates an *assembly system* which consists of
|
20
|
+
# a set of interrelated assembly lines, or tracks.
|
21
|
+
class Assembly
|
22
|
+
|
23
|
+
# Name of the assembly system.
|
24
|
+
attr :name
|
25
|
+
|
26
|
+
# Returns a Hash of track names mapped to list of stops.
|
27
|
+
attr :lines
|
28
|
+
|
29
|
+
# Lines are also called `tracks`.
|
30
|
+
alias_method :tracks, :lines
|
31
|
+
|
32
|
+
# Create a new instance.
|
33
|
+
def initialize(name, &block)
|
34
|
+
@name = name.to_sym
|
35
|
+
@lines = {:maintenance => MAINTENANCE_TRACK}
|
36
|
+
instance_eval(&block) if block
|
37
|
+
end
|
38
|
+
|
39
|
+
# Define an assembly line.
|
40
|
+
def line(name, *stops)
|
41
|
+
if stops.empty?
|
42
|
+
@lines[name.to_sym]
|
43
|
+
else
|
44
|
+
@lines[name.to_sym] = stops.map{ |s| s.to_sym }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Lines are also called tracks.
|
49
|
+
alias_method :track, :line
|
50
|
+
|
51
|
+
# Lookup track by name and (optional) stop. If the stop belongs
|
52
|
+
# to the maintenance sub-track then the maintenance sub-track will
|
53
|
+
# be returned instead of the track itself.
|
54
|
+
#
|
55
|
+
# The Application class uses this to simplify track lookup.
|
56
|
+
def get_track(name, stop=nil)
|
57
|
+
name = name.to_sym
|
58
|
+
if stop
|
59
|
+
stop = stop.to_sym
|
60
|
+
if MAINTENANCE_TRACK.include?(stop.to_sym)
|
61
|
+
track = MAINTENANCE_TRACK
|
62
|
+
else
|
63
|
+
track = tracks[name]
|
64
|
+
raise "Unknown track `#{name}'." unless track
|
65
|
+
unless track.include?(stop)
|
66
|
+
raise "Unknown stop `#{stop}` for track `#{name}'."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
else
|
70
|
+
track = tracks[name]
|
71
|
+
end
|
72
|
+
track
|
73
|
+
end
|
74
|
+
|
75
|
+
# Did I mention that `line` and `track` are synonyms?
|
76
|
+
alias_method :get_line, :get_track
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
module Detroit
|
2
|
+
|
3
|
+
# Detroit configuration. Configuration comes from a main +Routine+
|
4
|
+
# and/or +.routine+ files.
|
5
|
+
class Config
|
6
|
+
#instance_methods.each{ |m| private m unless /^__/ =~ m.to_s }
|
7
|
+
|
8
|
+
# Configuration directory name (most likely a hidden "dot" directory).
|
9
|
+
DIRECTORY = "detroit"
|
10
|
+
|
11
|
+
# File identifier used to find a project's Schedule(s).
|
12
|
+
FILE_EXTENSION = "schedule"
|
13
|
+
|
14
|
+
# Current POM::Project object.
|
15
|
+
#attr :project
|
16
|
+
|
17
|
+
# The list of a project's routine files.
|
18
|
+
#
|
19
|
+
# @return [Array<String>] routine files
|
20
|
+
attr :schedules
|
21
|
+
|
22
|
+
# Service configurations from Schedule or *.schedule files.
|
23
|
+
#
|
24
|
+
# @return [Hash] service settings
|
25
|
+
attr :services
|
26
|
+
|
27
|
+
# Service defaults. This is a mapping of service names to
|
28
|
+
# default settings. Very useful for when using the same
|
29
|
+
# service more than once.
|
30
|
+
#
|
31
|
+
# @return [Hash] default settings
|
32
|
+
attr :defaults
|
33
|
+
|
34
|
+
#
|
35
|
+
def initialize(schedule_files=nil)
|
36
|
+
if schedule_files && !schedule_files.empty?
|
37
|
+
@schedule_filenames = schedule_files
|
38
|
+
else
|
39
|
+
@schedule_filenames = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
@schedules = {}
|
43
|
+
@services = {}
|
44
|
+
@defaults = {}
|
45
|
+
|
46
|
+
@loaded_plugins = {}
|
47
|
+
|
48
|
+
load_plugins
|
49
|
+
load_defaults
|
50
|
+
load_schedules
|
51
|
+
end
|
52
|
+
|
53
|
+
#--
|
54
|
+
# TODO: Use this, or pass in via initialize?
|
55
|
+
#++
|
56
|
+
def project
|
57
|
+
Detroit.project
|
58
|
+
end
|
59
|
+
|
60
|
+
# Load a plugin.
|
61
|
+
def load_plugin(name)
|
62
|
+
@loaded_plugins[name] ||= (
|
63
|
+
require "detroit-#{name}"
|
64
|
+
name
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Pre-load plugins using `.detroit/plugins.rb`.
|
69
|
+
def load_plugins
|
70
|
+
if file = project.root.glob('{.,}#{DIRECTORY}/plugins{,.rb}').first
|
71
|
+
require file
|
72
|
+
else
|
73
|
+
self.defaults = {}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Load defaults from `.detroit/defaults.yml`.
|
78
|
+
def load_defaults
|
79
|
+
if file = project.root.glob('{.,}#{DIRECTORY}/defaults{,.yml,.yaml}').first
|
80
|
+
self.defaults = YAML.load(File.new(file))
|
81
|
+
else
|
82
|
+
self.defaults = {}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
def load_schedules
|
88
|
+
schedule_filenames.each do |file|
|
89
|
+
load_schedule_file(file)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
def load_schedule_file(file)
|
95
|
+
@schedules[file] = Schedule.load(File.new(file))
|
96
|
+
@services.merge!(schedules[file].services)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Set defaults.
|
100
|
+
def defaults=(hash)
|
101
|
+
@defaults = hash.to_h
|
102
|
+
end
|
103
|
+
|
104
|
+
# If a `Schedule` or `.schedule` file exists, then it is returned. Otherwise
|
105
|
+
# all `*.schedule` files are loaded. To load `*.schedule` files from another
|
106
|
+
# directory add the directory to config options file.
|
107
|
+
def schedule_filenames
|
108
|
+
@schedule_filenames ||= (
|
109
|
+
files = []
|
110
|
+
## match 'Schedule' or '.schedule' file
|
111
|
+
files = project.root.glob("{,.,*.}#{FILE_EXTENSION}{,.rb,.yml,.yaml}", :casefold)
|
112
|
+
## only files
|
113
|
+
files = files.select{ |f| File.file?(f) }
|
114
|
+
##
|
115
|
+
if files.empty?
|
116
|
+
## match '.detroit/*.schedule' or 'detroit/*.schedule'
|
117
|
+
files += project.root.glob("{,.}#{DIRECTORY}/*.#{FILE_EXTENSION}", :casefold)
|
118
|
+
## match 'task/*.schedule' (OLD SCHOOL)
|
119
|
+
files += project.root.glob("{task,tasks}/*.#{FILE_EXTENSION}", :casefold)
|
120
|
+
## only files
|
121
|
+
files = files.select{ |f| File.file?(f) }
|
122
|
+
end
|
123
|
+
files
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
def each(&block)
|
129
|
+
services.each(&block)
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
def size
|
134
|
+
services.size
|
135
|
+
end
|
136
|
+
|
137
|
+
=begin
|
138
|
+
# If using a `Routine` file and want to import antoher file then use
|
139
|
+
# `import:` entry.
|
140
|
+
def load_detroit_file(file)
|
141
|
+
#@dir = File.dirname(file)
|
142
|
+
|
143
|
+
schedules[file] =
|
144
|
+
|
145
|
+
# TODO: can we just read the first line of the file and go from there?
|
146
|
+
#text = File.read(file).strip
|
147
|
+
|
148
|
+
## if yaml vs. ruby file
|
149
|
+
#if (/\A---/ =~ text || /\.(yml|yaml)$/ =~ File.extname(file))
|
150
|
+
# #data = parse_detroit_file_yaml(text, file)
|
151
|
+
# YAML.load(text)
|
152
|
+
#else
|
153
|
+
# data = parse_detroit_file_ruby(text, file)
|
154
|
+
#end
|
155
|
+
|
156
|
+
## extract defaults
|
157
|
+
#if defaults = data.delete('defaults')
|
158
|
+
# @defaults.merge!(defaults)
|
159
|
+
#end
|
160
|
+
|
161
|
+
## import other files
|
162
|
+
#if import = data.delete('import')
|
163
|
+
# [import].flatten.each do |glob|
|
164
|
+
# routine(glob)
|
165
|
+
# end
|
166
|
+
#end
|
167
|
+
|
168
|
+
## require plugins
|
169
|
+
#if plugins = data.delete('plugins')
|
170
|
+
# [plugins].flatten.each do |file|
|
171
|
+
# require file
|
172
|
+
# end
|
173
|
+
#end
|
174
|
+
|
175
|
+
#@services.update(data)
|
176
|
+
end
|
177
|
+
=end
|
178
|
+
|
179
|
+
## Parse a YAML-based routine.
|
180
|
+
#def parse_detroit_file_yaml(text, file)
|
181
|
+
# YAMLParser.parse(self, text, file)
|
182
|
+
#end
|
183
|
+
|
184
|
+
## Parse a Ruby-based routine.
|
185
|
+
#def parse_detroit_file_ruby(text, file)
|
186
|
+
# RubyParser.parse(self, text, file)
|
187
|
+
#end
|
188
|
+
|
189
|
+
## TODO: Should the +dir+ be relative to the file or project.root?
|
190
|
+
#def routine(glob)
|
191
|
+
# pattern = File.join(@dir, glob)
|
192
|
+
# Dir[pattern].each{ |f| load_detroit_file(f) }
|
193
|
+
#end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Detroit
|
2
|
+
|
3
|
+
# The control module is a function module that extends
|
4
|
+
# the toplevel Detroit namespace module.
|
5
|
+
module Control
|
6
|
+
|
7
|
+
# Location of standard plugins.
|
8
|
+
#PLUGIN_DIRECTORY = File.dirname(__FILE__) + '/plugins'
|
9
|
+
|
10
|
+
# Returns Array of standard plugin file names.
|
11
|
+
#def standard_plugins
|
12
|
+
# Dir[PLUGIN_DIRECTORY + '/*.rb']
|
13
|
+
#end
|
14
|
+
|
15
|
+
# Universal acccess to the current project.
|
16
|
+
#
|
17
|
+
# TODO: Is Control#project being used?
|
18
|
+
def project
|
19
|
+
@project ||= POM::Project.find
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns Application given options.
|
23
|
+
def application(options={})
|
24
|
+
Application.new(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Run the command line interface.
|
28
|
+
def cli(*argv)
|
29
|
+
cli_options = {
|
30
|
+
:schedules => [],
|
31
|
+
:trace=>nil, :trial=>nil, :debug=>nil, :quiet=>nil, :verbose=>nil,
|
32
|
+
:force=>nil, :multitask=>nil, :skip=>[]
|
33
|
+
}
|
34
|
+
|
35
|
+
cli_usage(cli_options).parse!(argv)
|
36
|
+
|
37
|
+
#if /\.schedule$/ =~ argv[0]
|
38
|
+
# job = argv[1]
|
39
|
+
# begin
|
40
|
+
# application(cli_options).runscript(argv[0], job)
|
41
|
+
# rescue => error
|
42
|
+
# $stderr.puts error.message
|
43
|
+
# exit -1
|
44
|
+
# end
|
45
|
+
#else
|
46
|
+
begin
|
47
|
+
application(cli_options).start(*argv)
|
48
|
+
rescue => error
|
49
|
+
if $DEBUG
|
50
|
+
raise error
|
51
|
+
else
|
52
|
+
$stderr.puts error.message
|
53
|
+
exit -1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
#end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns an instance of OptionParser.
|
60
|
+
def cli_usage(options)
|
61
|
+
@usage ||= (
|
62
|
+
OptionParser.new do |usage|
|
63
|
+
usage.banner = "Usage: detroit [<track>:]<stop> [options]"
|
64
|
+
usage.on('-m', '--multitask', "Run work elements in parallel.") do
|
65
|
+
options[:multitask] = true
|
66
|
+
end
|
67
|
+
usage.on('-S', '--skip [SERVICE]', 'Skip a service.') do |skip|
|
68
|
+
options[:skip] << skip
|
69
|
+
end
|
70
|
+
|
71
|
+
usage.on('-a', '--assembly=NAME', "Select assembly. Default is `standard'.") do |assembly|
|
72
|
+
options[:assembly] = assembly
|
73
|
+
end
|
74
|
+
usage.on('-s', '--schedule [FILE]', 'Use specific schedule file(s).') do |file|
|
75
|
+
options[:schedules] << file
|
76
|
+
end
|
77
|
+
|
78
|
+
usage.on('-F', '--force', "Force operations.") do
|
79
|
+
options[:force] = true
|
80
|
+
end
|
81
|
+
usage.on('--trace', "Run in TRACE mode.") do
|
82
|
+
#$TRACE = true
|
83
|
+
options[:trace] = true
|
84
|
+
end
|
85
|
+
usage.on('--trial', "Run in TRIAL mode (no disk writes).") do
|
86
|
+
#$TRIAL = true
|
87
|
+
options[:trial] = true
|
88
|
+
end
|
89
|
+
# TODO: do we really need verbose?
|
90
|
+
usage.on('--verbose', "Provided extra output.") do
|
91
|
+
options[:verbose] = true
|
92
|
+
end
|
93
|
+
usage.on('-q', '--quiet', "Run silently.") do
|
94
|
+
options[:quiet] = true
|
95
|
+
end
|
96
|
+
|
97
|
+
usage.on('-I=PATH', "Add directory to $LOAD_PATH") do |dirs|
|
98
|
+
dirs.to_list.each do |dir|
|
99
|
+
$LOAD_PATH.unshift(dir)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
usage.on('--debug', "Run with $DEBUG set to true.") do
|
103
|
+
$DEBUG = true
|
104
|
+
options[:debug] = true # DEPRECATE?
|
105
|
+
end
|
106
|
+
usage.on('--warn', "Run with $VERBOSE set to true.") do
|
107
|
+
$VERBOSE = true # wish this were called $WARN
|
108
|
+
end
|
109
|
+
usage.on_tail('--help', "Display this help message.") do
|
110
|
+
puts usage
|
111
|
+
exit
|
112
|
+
end
|
113
|
+
usage.on_tail('--config', "Produce a configuration template.") do
|
114
|
+
puts application.config_template.to_yaml
|
115
|
+
exit
|
116
|
+
end
|
117
|
+
end
|
118
|
+
)
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
extend Control
|
124
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
#__DIR__ = File.dirname(__FILE__)
|
2
|
+
|
3
|
+
#Dir[File.join(__DIR__, 'core_ext', '*.rb')].each do |file|
|
4
|
+
# require file
|
5
|
+
#end
|
6
|
+
|
7
|
+
#require 'facets'
|
8
|
+
require 'facets/to_hash'
|
9
|
+
require 'facets/module/basename'
|
10
|
+
require 'facets/module/alias_accessor'
|
11
|
+
require 'facets/pathname'
|
12
|
+
#require 'facets/boolean'
|
13
|
+
|
14
|
+
class Array
|
15
|
+
|
16
|
+
def to_list
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class NilClass
|
23
|
+
|
24
|
+
def to_list
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class String
|
31
|
+
|
32
|
+
# Helper method for cleaning list options.
|
33
|
+
# This will split the option on ':' or ';'
|
34
|
+
# if it is a string, rather than an array.
|
35
|
+
# And it will make sure there are no nil elements.
|
36
|
+
|
37
|
+
def to_list
|
38
|
+
split(/[:;,\n]/).map{ |s| s.strip }
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# TODO: Replace these with facets/shellwords !!!
|
44
|
+
|
45
|
+
# TODO: Belongs in Redtools, no?
|
46
|
+
|
47
|
+
#
|
48
|
+
class Array #:nodoc:
|
49
|
+
|
50
|
+
# Convert an array into commandline parameters.
|
51
|
+
# The array is accepted in the format of Ruby
|
52
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
53
|
+
|
54
|
+
def to_console
|
55
|
+
#flags = (Hash===last ? pop : {})
|
56
|
+
#flags = flags.to_console
|
57
|
+
#flags + ' ' + join(" ")
|
58
|
+
to_argv.join(' ')
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO: DEPRECATE
|
62
|
+
alias_method :to_params, :to_console
|
63
|
+
|
64
|
+
#
|
65
|
+
def to_argv
|
66
|
+
flags = (Hash===last ? pop : {})
|
67
|
+
flags = flags.to_argv
|
68
|
+
flags + self
|
69
|
+
end
|
70
|
+
|
71
|
+
# def to_console
|
72
|
+
# flags = (Hash===last ? pop : {})
|
73
|
+
# flags = flags.collect do |f,v|
|
74
|
+
# m = f.to_s.size == 1 ? '-' : '--'
|
75
|
+
# case v
|
76
|
+
# when Array
|
77
|
+
# v.collect{ |e| "#{m}#{f} '#{e}'" }.join(' ')
|
78
|
+
# when true
|
79
|
+
# "#{m}#{f}"
|
80
|
+
# when false, nil
|
81
|
+
# ''
|
82
|
+
# else
|
83
|
+
# "#{m}#{f} '#{v}'"
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
# return (flags + self).join(" ")
|
87
|
+
# end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
class Hash
|
92
|
+
|
93
|
+
# Convert a Hash into command line arguments.
|
94
|
+
# The array is accepted in the format of Ruby
|
95
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
96
|
+
def to_console
|
97
|
+
to_argv.join(' ')
|
98
|
+
end
|
99
|
+
|
100
|
+
# Convert a Hash into command line parameters.
|
101
|
+
# The array is accepted in the format of Ruby
|
102
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
103
|
+
def to_argv
|
104
|
+
flags = map do |f,v|
|
105
|
+
m = f.to_s.size == 1 ? '-' : '--'
|
106
|
+
case v
|
107
|
+
when Array
|
108
|
+
v.collect{ |e| "#{m}#{f}='#{e}'" }.join(' ')
|
109
|
+
when true
|
110
|
+
"#{m}#{f}"
|
111
|
+
when false, nil
|
112
|
+
''
|
113
|
+
else
|
114
|
+
"#{m}#{f}='#{v}'"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Turn a hash into arguments.
|
120
|
+
#
|
121
|
+
# h = { :list => [1,2], :base => "HI" }
|
122
|
+
# h.argumentize #=> [ [], { :list => [1,2], :base => "HI" } ]
|
123
|
+
# h.argumentize(:list) #=> [ [1,2], { :base => "HI" } ]
|
124
|
+
#
|
125
|
+
def argumentize(args_field=nil)
|
126
|
+
config = dup
|
127
|
+
if args_field
|
128
|
+
args = [config.delete(args_field)].flatten.compact
|
129
|
+
else
|
130
|
+
args = []
|
131
|
+
end
|
132
|
+
args << config
|
133
|
+
return args
|
134
|
+
end
|
135
|
+
|
136
|
+
alias_method :command_vector, :argumentize
|
137
|
+
|
138
|
+
end
|
139
|
+
|