tap 0.8.0 → 0.9.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.
Files changed (185) hide show
  1. data/Basic Overview +151 -0
  2. data/Command Reference +99 -0
  3. data/History +24 -0
  4. data/MIT-LICENSE +1 -1
  5. data/README +29 -57
  6. data/Rakefile +30 -37
  7. data/Tutorial +243 -191
  8. data/bin/tap +66 -35
  9. data/lib/tap.rb +47 -29
  10. data/lib/tap/app.rb +700 -342
  11. data/lib/tap/{script → cmd}/console.rb +0 -0
  12. data/lib/tap/{script → cmd}/destroy.rb +0 -0
  13. data/lib/tap/{script → cmd}/generate.rb +0 -0
  14. data/lib/tap/cmd/run.rb +156 -0
  15. data/lib/tap/constants.rb +4 -0
  16. data/lib/tap/dump.rb +57 -0
  17. data/lib/tap/env.rb +316 -0
  18. data/lib/tap/file_task.rb +106 -109
  19. data/lib/tap/generator.rb +4 -1
  20. data/lib/tap/generator/generators/command/USAGE +6 -0
  21. data/lib/tap/generator/generators/command/command_generator.rb +17 -0
  22. data/lib/tap/generator/generators/{script/templates/script.erb → command/templates/command.erb} +10 -10
  23. data/lib/tap/generator/generators/config/USAGE +21 -0
  24. data/lib/tap/generator/generators/config/config_generator.rb +17 -7
  25. data/lib/tap/generator/generators/file_task/USAGE +3 -0
  26. data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -0
  27. data/lib/tap/generator/generators/file_task/templates/file.txt +2 -0
  28. data/lib/tap/generator/generators/file_task/templates/file.yml +3 -0
  29. data/lib/tap/generator/generators/file_task/templates/task.erb +26 -20
  30. data/lib/tap/generator/generators/file_task/templates/test.erb +20 -10
  31. data/lib/tap/generator/generators/generator/generator_generator.rb +1 -1
  32. data/lib/tap/generator/generators/generator/templates/generator.erb +21 -12
  33. data/lib/tap/generator/generators/root/templates/Rakefile +33 -24
  34. data/lib/tap/generator/generators/root/templates/tap.yml +28 -31
  35. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +1 -0
  36. data/lib/tap/generator/generators/task/USAGE +3 -0
  37. data/lib/tap/generator/generators/task/task_generator.rb +18 -5
  38. data/lib/tap/generator/generators/task/templates/task.erb +7 -12
  39. data/lib/tap/generator/generators/task/templates/test.erb +10 -11
  40. data/lib/tap/generator/generators/workflow/templates/task.erb +1 -1
  41. data/lib/tap/generator/generators/workflow/templates/test.erb +1 -1
  42. data/lib/tap/patches/rake/rake_test_loader.rb +8 -0
  43. data/lib/tap/patches/rake/testtask.rb +55 -0
  44. data/lib/tap/patches/ruby19/backtrace_filter.rb +51 -0
  45. data/lib/tap/patches/ruby19/parsedate.rb +16 -0
  46. data/lib/tap/root.rb +172 -67
  47. data/lib/tap/script.rb +70 -336
  48. data/lib/tap/support/aggregator.rb +55 -0
  49. data/lib/tap/support/audit.rb +281 -280
  50. data/lib/tap/support/batchable.rb +59 -0
  51. data/lib/tap/support/class_configuration.rb +279 -0
  52. data/lib/tap/support/configurable.rb +92 -0
  53. data/lib/tap/support/configurable_methods.rb +296 -0
  54. data/lib/tap/support/executable.rb +98 -0
  55. data/lib/tap/support/executable_queue.rb +82 -0
  56. data/lib/tap/support/logger.rb +9 -15
  57. data/lib/tap/support/rake.rb +43 -54
  58. data/lib/tap/support/run_error.rb +32 -13
  59. data/lib/tap/support/shell_utils.rb +47 -0
  60. data/lib/tap/support/tdoc.rb +9 -8
  61. data/lib/tap/support/tdoc/config_attr.rb +40 -16
  62. data/lib/tap/support/validation.rb +77 -0
  63. data/lib/tap/support/versions.rb +36 -36
  64. data/lib/tap/task.rb +276 -482
  65. data/lib/tap/test.rb +20 -261
  66. data/lib/tap/test/env_vars.rb +7 -5
  67. data/lib/tap/test/file_methods.rb +126 -121
  68. data/lib/tap/test/subset_methods.rb +86 -45
  69. data/lib/tap/test/tap_methods.rb +271 -0
  70. data/lib/tap/workflow.rb +174 -46
  71. data/test/app/config/another/task.yml +1 -0
  72. data/test/app/config/erb.yml +2 -1
  73. data/test/app/config/some/task.yml +1 -0
  74. data/test/app/config/template.yml +2 -6
  75. data/test/app_test.rb +1241 -1008
  76. data/test/env/test_configure/recurse_a.yml +2 -0
  77. data/test/env/test_configure/recurse_b.yml +2 -0
  78. data/test/env/test_configure/tap.yml +23 -0
  79. data/test/env/test_load_env_config/dir/tap.yml +3 -0
  80. data/test/env/test_load_env_config/recurse_a.yml +2 -0
  81. data/test/env/test_load_env_config/recurse_b.yml +2 -0
  82. data/test/env/test_load_env_config/tap.yml +3 -0
  83. data/test/env_test.rb +198 -0
  84. data/test/file_task_test.rb +70 -53
  85. data/{lib/tap/generator/generators/package/USAGE → test/root/file.txt} +0 -0
  86. data/test/root_test.rb +621 -454
  87. data/test/script_test.rb +38 -174
  88. data/test/support/aggregator_test.rb +99 -0
  89. data/test/support/audit_test.rb +409 -416
  90. data/test/support/batchable_test.rb +74 -0
  91. data/test/support/{task_configuration_test.rb → class_configuration_test.rb} +106 -47
  92. data/test/{task/config/overriding.yml → support/configurable/config/configured.yml} +0 -0
  93. data/test/support/configurable_test.rb +295 -0
  94. data/test/support/executable_queue_test.rb +103 -0
  95. data/test/support/executable_test.rb +38 -0
  96. data/test/support/logger_test.rb +17 -17
  97. data/test/support/rake_test.rb +4 -2
  98. data/test/support/shell_utils_test.rb +24 -0
  99. data/test/support/tdoc_test.rb +265 -258
  100. data/test/support/validation_test.rb +54 -0
  101. data/test/support/versions_test.rb +38 -38
  102. data/test/tap_test_helper.rb +19 -5
  103. data/test/tap_test_suite.rb +5 -2
  104. data/test/task_base_test.rb +13 -104
  105. data/test/task_syntax_test.rb +300 -0
  106. data/test/task_test.rb +258 -381
  107. data/test/test/env_vars_test.rb +40 -40
  108. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/one.txt +0 -0
  109. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/two.txt +0 -0
  110. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/one.txt +0 -0
  111. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/two.txt +0 -0
  112. data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/one.txt +0 -0
  113. data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/two.txt +0 -0
  114. data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +1 -0
  115. data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_different_content}/expected/two.txt +0 -0
  116. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +1 -0
  117. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +1 -0
  118. data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_missing_expected_file}/expected/one.txt +0 -0
  119. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +1 -0
  120. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +1 -0
  121. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +1 -0
  122. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +1 -0
  123. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +1 -0
  124. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +1 -0
  125. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +1 -0
  126. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +1 -0
  127. data/test/test/file_methods_doc/test_sub/expected/one.txt +1 -0
  128. data/test/test/file_methods_doc/test_sub/expected/two.txt +1 -0
  129. data/test/test/file_methods_doc/test_sub/input/one.txt +1 -0
  130. data/test/test/file_methods_doc/test_sub/input/two.txt +1 -0
  131. data/test/test/file_methods_doc_test.rb +29 -0
  132. data/test/test/file_methods_test.rb +214 -143
  133. data/test/test/subset_methods_test.rb +111 -115
  134. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/a.txt +0 -0
  135. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/b.txt +0 -0
  136. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/a.txt +0 -0
  137. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/b.txt +0 -0
  138. data/test/test/tap_methods_test.rb +399 -0
  139. data/test/workflow_test.rb +101 -91
  140. metadata +86 -70
  141. data/lib/tap/generator/generators/package/package_generator.rb +0 -38
  142. data/lib/tap/generator/generators/package/templates/package.erb +0 -186
  143. data/lib/tap/generator/generators/script/USAGE +0 -0
  144. data/lib/tap/generator/generators/script/script_generator.rb +0 -17
  145. data/lib/tap/script/run.rb +0 -154
  146. data/lib/tap/support/batch_queue.rb +0 -162
  147. data/lib/tap/support/combinator.rb +0 -114
  148. data/lib/tap/support/task_configuration.rb +0 -169
  149. data/lib/tap/support/template.rb +0 -81
  150. data/lib/tap/support/templater.rb +0 -155
  151. data/lib/tap/version.rb +0 -4
  152. data/test/app/config/addition_template.yml +0 -6
  153. data/test/app_class_test.rb +0 -33
  154. data/test/check/binding_eval.rb +0 -23
  155. data/test/check/define_method_check.rb +0 -22
  156. data/test/check/dependencies_check.rb +0 -175
  157. data/test/check/inheritance_check.rb +0 -22
  158. data/test/support/batch_queue_test.rb +0 -320
  159. data/test/support/combinator_test.rb +0 -249
  160. data/test/support/template_test.rb +0 -122
  161. data/test/support/templater/erb.txt +0 -2
  162. data/test/support/templater/erb.yml +0 -2
  163. data/test/support/templater/somefile.txt +0 -2
  164. data/test/support/templater_test.rb +0 -192
  165. data/test/task/config/template.yml +0 -4
  166. data/test/task_class_test.rb +0 -170
  167. data/test/task_execute_test.rb +0 -262
  168. data/test/test/file_methods/test_assert_expected/expected/file.txt +0 -1
  169. data/test/test/file_methods/test_assert_expected/expected/folder/file.txt +0 -1
  170. data/test/test/file_methods/test_assert_expected/input/file.txt +0 -1
  171. data/test/test/file_methods/test_assert_expected/input/folder/file.txt +0 -1
  172. data/test/test/file_methods/test_assert_files_exist/input/input_1.txt +0 -0
  173. data/test/test/file_methods/test_assert_files_exist/input/input_2.txt +0 -0
  174. data/test/test/file_methods/test_file_compare/expected/output_1.txt +0 -3
  175. data/test/test/file_methods/test_file_compare/expected/output_2.txt +0 -1
  176. data/test/test/file_methods/test_file_compare/input/input_1.txt +0 -3
  177. data/test/test/file_methods/test_file_compare/input/input_2.txt +0 -3
  178. data/test/test/file_methods/test_infer_glob/expected/file.yml +0 -0
  179. data/test/test/file_methods/test_infer_glob/expected/file_1.txt +0 -0
  180. data/test/test/file_methods/test_infer_glob/expected/file_2.txt +0 -0
  181. data/test/test/file_methods/test_yml_compare/expected/output_1.yml +0 -6
  182. data/test/test/file_methods/test_yml_compare/expected/output_2.yml +0 -6
  183. data/test/test/file_methods/test_yml_compare/input/input_1.yml +0 -4
  184. data/test/test/file_methods/test_yml_compare/input/input_2.yml +0 -4
  185. data/test/test_test.rb +0 -373
@@ -1,362 +1,96 @@
1
1
  require 'getoptlong'
2
- require 'singleton'
3
2
  autoload(:PP, "pp")
4
3
 
5
4
  module Tap
6
- module Support
7
- autoload(:TDoc, 'tap/support/tdoc')
8
- end
9
-
10
5
  # == UNDER CONSTRUCTION
11
- class ScriptConfig < OpenStruct
12
- class << self
13
- def defaults
14
- {:gems => [],
15
- :load_once_paths => [],
16
- :load_paths => ["lib"],
17
- :script_paths => ["script"]}
18
- end
19
-
20
- def spec_filepath(dir=nil)
21
- dir == nil ? "tapspec.yml" : File.join(dir, "tapspec.yml")
22
- end
23
- end
24
-
25
- def initialize(config={}, app=Tap::App.instance)
26
- super(
27
- :gemspecs => [],
28
- :load_once_paths => [],
29
- :load_paths => [],
30
- :script_paths => [])
31
-
32
- config = ScriptConfig.defaults.merge(config)
33
- resolve_paths(config, app)
34
- collect_gem_paths(config)
35
-
36
- # add additional configurations
37
- config.each_pair do |key, value|
38
- next if self.respond_to?(key)
39
- self.send("#{key}=", value)
40
- end
41
-
42
- self.load_once_paths.uniq!
43
- self.load_paths.uniq!
44
- self.script_paths.uniq!
45
- end
6
+ #
7
+ # Script is a mixed bag of methods encapsulating many scripting
8
+ # functions like handling options and assembling usage information.
9
+ module Script
10
+ module_function
46
11
 
47
- def scripts
48
- scripts = {}
49
- self.script_paths.each do |dir|
50
- Dir.glob(File.expand_path(File.join(dir, "**/*.rb"))).each do |file|
51
- script = Tap::App.relative_filepath(dir, file).chomp(".rb")
52
- raise "script name confict: #{script}" if scripts.include?(script)
53
- scripts[script] = file
54
- end
55
- end
56
-
57
- # allow gem scripts to overrride default scripts
58
- # (hence do this second)
59
- script_dir = File.expand_path(File.join( File.dirname(__FILE__), "script"))
60
- Dir.glob( script_dir + "/**/*.rb" ).each do |file|
61
- script = Tap::App.relative_filepath(script_dir, file).chomp(".rb")
62
- scripts[script] = file unless scripts.include?(script)
63
- end
64
-
65
- scripts
12
+ # Parses the input string as YAML, if the string matches the YAML document
13
+ # specifier (ie it begins with "---\s*\n"). Otherwise returns the string.
14
+ #
15
+ # str = {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
16
+ # Tap::Script.parse_yaml(str) # => {'key' => 'value'}
17
+ # Tap::Script.parse_yaml("str") # => "str"
18
+ def parse_yaml(str)
19
+ str =~ /\A---\s*\n/ ? YAML.load(str) : str
66
20
  end
67
21
 
68
- protected
69
-
70
- # Resolve configuration paths, :load_paths, :load_once_paths, :script_paths,
71
- # to full paths using the provided app, or by expanding the paths relative to
72
- # the full_gem_path of the provided gemspec.
73
- def resolve_paths(config, app_or_gemspec) # :nodoc:
74
- # resolve and collect paths
75
- [:load_paths, :load_once_paths, :script_paths].each do |key|
76
- paths = arrayify(config[key])
77
-
78
- paths.collect! do |path|
79
- case app_or_gemspec
80
- when Tap::App
81
- app_or_gemspec.filepath(path)
82
- when Gem::Specification
83
- expanded = File.expand_path(path, app_or_gemspec.full_gem_path)
84
- unless expanded.index(app_or_gemspec.full_gem_path) == 0
85
- raise "'#{path}' for '#{app_or_gemspec.name}' resolves to a non-gem directory"
86
- end
87
- expanded
88
- end
22
+ def split_argv(argv)
23
+ current = []
24
+ current_split = []
25
+ splits = [current_split]
26
+
27
+ argv.each do |arg|
28
+ if arg =~ /\A-{2}(\+*)\z/
29
+ current_split << current unless current.empty?
30
+ current = []
31
+ current_split = (splits[$1.length] ||= [])
32
+ else
33
+ current << arg
89
34
  end
90
-
91
- self.send(key).concat(paths)
92
- end
35
+ end
36
+
37
+ current_split << current unless current.empty?
38
+ splits.delete_if {|split| split.nil? || split.empty? }
39
+ splits
93
40
  end
94
-
95
- # Recursively collects paths from the gems specfied in config[:gems],
96
- # using tap specification file for the gem as determined by
97
- # ScriptConfig#spec_filepath
98
- def collect_gem_paths(config) # :nodoc:
99
- arrayify(config[:gems]).each do |string|
100
- # figure the version of the gem, by default >= 0.0.0
101
- string =~ /^([^<=>]*)(.*)$/
102
- gem_name, version = $1, $2
103
- version = ">= 0.0.0" if version.empty?
104
-
105
- # load the gem and get the spec
106
- gem(gem_name, version)
107
- spec = Gem.loaded_specs[gem_name]
108
41
 
109
- # prevent an infinite loop...
110
- next if self.gemspecs.include?(spec)
111
- self.gemspecs << spec
112
-
113
- # load gem config from the spec, if possible,
114
- # otherwise use the defaults for the gem
115
- tap_spec_file = ScriptConfig.spec_filepath(spec.full_gem_path)
116
- gem_config = if File.exists?(tap_spec_file)
117
- YAML.load_file(tap_spec_file).symbolize_keys
118
- else
119
- ScriptConfig.defaults
42
+ def next_arg(argv)
43
+ index = nil
44
+ argv.each_with_index do |arg, i|
45
+ if arg !~ /\A-/
46
+ index = i
47
+ break
120
48
  end
121
-
122
- resolve_paths(gem_config, spec)
123
- collect_gem_paths(gem_config)
124
49
  end
50
+ index == nil ? nil : argv.delete_at(index)
125
51
  end
126
52
 
127
- def arrayify(obj) # :nodoc:
128
- case obj
129
- when nil then []
130
- when Array then obj
131
- else
132
- obj.to_s.strip.empty? ? [] : [obj]
53
+ # Handles options using GetoptLong, and passes each option and
54
+ # value in ARGV to the block.
55
+ #
56
+ #--
57
+ # expect [long, <short>, type, desc]
58
+ #++
59
+ def handle_options(*options)
60
+ options = options.collect do |opt|
61
+ opt = opt[0..-2]
62
+ opt.compact
63
+ end
64
+
65
+ opts = GetoptLong.new(*options)
66
+ opts.quiet = true
67
+ opts.each do |opt, value|
68
+ yield(opt, value)
133
69
  end
134
70
  end
135
- end
136
-
137
- # == UNDER CONSTRUCTION
138
- #
139
- # Script is a mixed bag of methods encapsulating many scripting
140
- # functions like reconfiguring an application, handling options
141
- # and assembling usage information.
142
- class Script
143
71
 
144
- class << self
145
- def config_filepath(dir=nil)
146
- dir == nil ? "tap.yml" : File.join(dir, "tap.yml")
147
- end
148
-
149
- def read_config(config_file)
150
- config = if File.exists?(config_file)
151
- config_str = ERB.new( File.read(config_file) ).result
152
- config = config_str.empty? ? {} : YAML.load(config_str)
153
- config == false ? {} : config
154
- else
155
- {}
156
- end
157
-
158
- unless config.kind_of?(Hash)
159
- raise "cannot parse file contents into a hash using YAML: #{config_file}"
160
- end
161
-
162
- config.symbolize_keys
163
- end
164
-
165
- def split_arguments(argv, separator_regexp=/^-{2}$/)
166
- splits = []
167
- current = []
168
- argv.each do |arg|
169
- if arg =~ separator_regexp
170
- splits << current unless current.empty?
171
- current = []
172
- else
173
- current << arg
174
- end
175
- end
176
- splits << current unless current.empty?
177
- splits
178
- end
179
-
180
- def next_arg(argv)
181
- index = nil
182
- argv.each_with_index do |arg, i|
183
- if arg !~ /^-/
184
- index = i
185
- break
186
- end
187
- end
188
- index == nil ? nil : argv.delete_at(index)
189
- end
190
-
191
- def usage(program_file, *sections)
192
- options = sections.last.kind_of?(Hash) ? sections.pop : {}
193
- options = {:keep_headers => true}.merge(options)
194
- comment = Support::TDoc.usage(program_file, sections, options[:keep_headers])
195
- comment.rstrip + "\n"
196
- end
197
-
198
- def usage_options(opts)
199
- opt_lines = ["Options:\n"]
200
- opts.each do |long, short, mode, desc|
201
- short = short == nil ? " " : "(#{short})"
202
- opt_lines << " %-25s %s %s" % [long, short, desc]
203
- end
204
- opt_lines.join("\n")
205
- end
206
-
207
- # Handles options using GetoptLong, and passes each option and
208
- # value in ARGV to the block.
209
- #
210
- #--
211
- # expect [long, <short>, type, desc]
212
- #++
213
- def handle_options(*options)
214
- options = options.collect do |opt|
215
- opt = opt[0..-2]
216
- opt.compact
217
- end
218
-
219
- opts = GetoptLong.new(*options)
220
- opts.each do |opt, value|
221
- yield(opt, value)
222
- end
223
- end
224
-
225
- def handle_task_options(task)
226
- return task.handle_options if task.respond_to?(:handle_options)
227
-
228
- config = {}
229
- opt_map = {}
230
- opts = task.class.configurations.collect do |declaration_class, key, value, attributes|
231
- long, short, opt_type, desc = config_to_opt(key, value, attributes)
232
- opt_map[long] = key
233
- [long, short, opt_type, desc]
234
- end
235
- opts << ['--help', '-h', GetoptLong::NO_ARGUMENT, "Print this help."]
236
-
237
- handle_options(*opts) do |opt, value|
238
- case opt
239
- when '--help'
240
- class_doc = Tap::Support::TDoc[task.class]
241
- if class_doc == nil
242
- puts "could not find help for '#{task.class}'"
243
- exit
244
- end
245
-
246
- sections = class_doc.comment_sections(/Description|Usage/i, true)
247
- opt_lines = opts.collect do |long, short, opt_type, desc|
248
- key = opt_map[long]
249
- default = PP.singleline_pp(task.class.configurations.default[key], "")
250
- config_attr = class_doc.find_configuration_named(key.to_s)
251
-
252
- short = "(#{short})" unless short.to_s.empty?
253
- if desc == nil && config_attr != nil
254
- desc = config_attr.desc + " (#{default})"
255
- end
256
-
257
- " %-25s %-5s %s" % [long, short, desc]
258
- end
259
-
260
- puts %Q{#{task.class.to_s}
261
- #{sections["Description"]}
262
-
263
- Usage:
264
- #{sections["Usage"]}
265
-
266
- Options:
267
- #{opt_lines.join("\n")}}
268
- exit
269
-
270
- else
271
- key = opt_map[opt]
272
- config[key] = YAML.load(value)
273
- end
274
- end
275
-
276
- # reconfigure task
277
- task.batch.each do |t|
278
- t.config = config
279
- end
280
- end
281
-
282
- protected
283
-
284
- def config_to_opt(key, value, attributes)
285
- attributes = {
286
- :long => key,
287
- :short => nil,
288
- :opt_type => GetoptLong::REQUIRED_ARGUMENT,
289
- :desc => nil
290
- }.merge(attributes)
291
-
292
- long = attributes[:long]
293
- attributes[:long] = "--#{long}" unless long =~ /^-{2}/
294
-
295
- short = attributes[:short].to_s
296
- attributes[:short] = "-#{short}" unless short.empty? || short =~ /^-/
297
-
298
- [attributes[:long], attributes[:short], attributes[:opt_type], attributes[:desc]]
299
- end
300
- end
301
-
302
- include Singleton
303
-
304
- attr_accessor :config
305
-
306
- def reset
307
- self.config = nil
72
+ def usage(program_file, *sections)
73
+ options = sections.last.kind_of?(Hash) ? sections.pop : {}
74
+ options = {:keep_headers => true}.merge(options)
75
+ comment = Support::TDoc.usage(program_file, sections, options[:keep_headers])
76
+ comment.rstrip + "\n"
308
77
  end
309
-
310
- # Configures the app with the input configurations.
311
- def configure_app(app_config={}, app=Tap::App.instance)
312
- app_config = app_config ? app_config.symbolize_keys : {}
313
78
 
314
- # partition script_config from config
315
- script_config = ScriptConfig.defaults
316
- script_config_keys = script_config.keys
317
- app_config.delete_if do |key, value|
318
- if script_config_keys.include?(key)
319
- script_config[key] = value
320
- true
321
- else
322
- false
323
- end
324
- end
325
-
326
- # reconfigure the current app with remaining keys
327
- # this must be done first so load paths can be
328
- # resolved using the most current app config
329
- app.reconfigure(app_config) do |key, value|
330
- # collect unknown options
331
- script_config[key] = value
332
- end
333
-
334
- # define the config, using the newly configured app
335
- self.config = ScriptConfig.new(script_config, app)
79
+ def usage_options(opts)
80
+ opt_lines = []
81
+ opts.each do |long, short, mode, desc|
336
82
 
337
- # add load paths to system load paths
338
- # echos Rail::Initializer.set_load_path
339
- tap_gem_dir = File.expand_path(File.dirname(__FILE__) + "/..")
340
- config.load_paths.unshift(tap_gem_dir)
341
- config.load_paths.reverse_each do |dir|
342
- $LOAD_PATH.unshift(dir) #if File.directory?(dir)
343
- end
344
- $LOAD_PATH.uniq!
345
-
346
- # set Dependencies load paths and freeze setting of load_paths
347
- # echos Rail::Initializer.set_autoload_paths
348
- Dependencies.load_once_paths = config.load_once_paths
349
- Dependencies.load_paths = config.load_paths
83
+ if desc.kind_of?(Class) && desc.include?(Tap::Support::Configurable)
84
+ key = desc.configurations.opt_map(long)
85
+ default = PP.singleline_pp(desc.configurations.default[key], "")
86
+ config_attr = desc.tdoc.find_configuration_named(key.to_s)
87
+ desc = config_attr.desc
88
+ end
350
89
 
351
- extra = Dependencies.load_once_paths - Dependencies.load_paths
352
- unless extra.empty?
353
- raise(
354
- "load_once_paths must be a subset of the load_paths.\n" +
355
- "Extra items in load_once_paths: #{extra * ','}")
90
+ short = short == nil ? " " : "(#{short})"
91
+ opt_lines << " %-25s %s %s" % [long, short, desc]
356
92
  end
357
-
358
- config
93
+ opt_lines.join("\n")
359
94
  end
360
-
361
95
  end
362
96
  end
@@ -0,0 +1,55 @@
1
+ module Tap
2
+ module Support
3
+
4
+ # Aggregator allows thread-safe collection of Audits, organized
5
+ # by Audit#_current_source.
6
+ class Aggregator < Monitor
7
+
8
+ def initialize
9
+ super
10
+ clear
11
+ end
12
+
13
+ # Clears self of all audits.
14
+ def clear
15
+ synchronize { self.hash = Hash.new }
16
+ end
17
+
18
+ # The total number of audits recorded in self.
19
+ def size
20
+ synchronize { hash.values.inject(0) {|sum, array| sum + array.length} }
21
+ end
22
+
23
+ # True if size == 0
24
+ def empty?
25
+ synchronize { hash.empty? }
26
+ end
27
+
28
+ # Stores the Audit according to _result._current_source
29
+ def store(_result)
30
+ synchronize { (hash[_result._current_source] ||= []) << _result }
31
+ end
32
+
33
+ # Retreives all aggregated audits for the specified source.
34
+ def retrieve(source)
35
+ synchronize { hash[source] }
36
+ end
37
+
38
+ # Retreives all audits for the input sources, joined into an array.
39
+ def retrieve_all(*sources)
40
+ synchronize do
41
+ sources.collect {|src| hash[src] }.flatten.compact
42
+ end
43
+ end
44
+
45
+ # Converts self to a hash of (source, audits) pairs.
46
+ def to_hash
47
+ hash.dup
48
+ end
49
+
50
+ protected
51
+
52
+ attr_accessor :hash
53
+ end
54
+ end
55
+ end