bahuvrihi-tap 0.10.4 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/bin/rap +112 -0
  2. data/bin/tap +21 -10
  3. data/cmd/destroy.rb +1 -1
  4. data/cmd/generate.rb +1 -1
  5. data/cmd/run.rb +4 -48
  6. data/cmd/server.rb +3 -1
  7. data/lib/tap/constants.rb +1 -1
  8. data/lib/tap/env.rb +37 -39
  9. data/lib/tap/exe.rb +59 -29
  10. data/lib/tap/generator/base.rb +1 -1
  11. data/lib/tap/generator/generators/config/templates/doc.erb +1 -1
  12. data/lib/tap/generator/generators/file_task/templates/test.erb +1 -1
  13. data/lib/tap/generator/generators/root/templates/README +0 -0
  14. data/lib/tap/generator/generators/root/templates/gemspec +3 -4
  15. data/lib/tap/generator/generators/root/templates/tapfile +3 -3
  16. data/lib/tap/parser.rb +35 -0
  17. data/lib/tap/patches/optparse/summarize.rb +62 -0
  18. data/lib/tap/root.rb +24 -18
  19. data/lib/tap/support/class_configuration.rb +1 -1
  20. data/lib/tap/support/configurable_class.rb +3 -1
  21. data/lib/tap/support/configuration.rb +19 -0
  22. data/lib/tap/support/constant.rb +14 -2
  23. data/lib/tap/support/declarations.rb +33 -39
  24. data/lib/tap/support/dependable.rb +21 -2
  25. data/lib/tap/support/gems.rb +4 -30
  26. data/lib/tap/support/gems/rack.rb +14 -11
  27. data/lib/tap/support/lazy_attributes.rb +1 -1
  28. data/lib/tap/support/lazydoc.rb +257 -340
  29. data/lib/tap/support/lazydoc/comment.rb +499 -0
  30. data/lib/tap/support/lazydoc/config.rb +17 -0
  31. data/lib/tap/support/lazydoc/declaration.rb +20 -0
  32. data/lib/tap/support/lazydoc/document.rb +118 -0
  33. data/lib/tap/support/lazydoc/method.rb +24 -0
  34. data/lib/tap/support/manifest.rb +33 -4
  35. data/lib/tap/support/validation.rb +56 -0
  36. data/lib/tap/task.rb +46 -44
  37. data/lib/tap/tasks/dump.rb +15 -10
  38. data/lib/tap/tasks/load.rb +25 -0
  39. data/lib/tap/tasks/rake.rb +2 -2
  40. data/lib/tap/test.rb +55 -36
  41. data/lib/tap/test/file_methods.rb +204 -178
  42. data/lib/tap/test/file_methods_class.rb +4 -18
  43. data/lib/tap/test/script_methods.rb +76 -90
  44. data/lib/tap/test/script_methods/regexp_escape.rb +92 -0
  45. data/lib/tap/test/script_methods/script_test.rb +4 -2
  46. data/lib/tap/test/subset_methods.rb +46 -49
  47. data/lib/tap/test/subset_methods_class.rb +17 -54
  48. data/lib/tap/test/tap_methods.rb +1 -5
  49. data/lib/tap/test/utils.rb +142 -32
  50. metadata +12 -3
  51. data/lib/tap/support/command_line.rb +0 -55
  52. data/lib/tap/support/comment.rb +0 -270
@@ -0,0 +1,17 @@
1
+ module Tap
2
+ module Support
3
+ module Lazydoc
4
+ class Config < Comment
5
+ def empty?
6
+ to_str.empty?
7
+ end
8
+
9
+ def to_str
10
+ # currently removes the :no_default: document modifier
11
+ # which is used during generation of TDoc
12
+ subject.to_s =~ /#\s*(:no_default:)?\s*(.*)$/ ? $2.strip : ""
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module Tap
2
+ module Support
3
+ module Lazydoc
4
+ class Declaration < Comment
5
+ def resolve(lines)
6
+ super
7
+
8
+ @subject = case
9
+ when content.empty? || content[0][0].to_s !~ /^::desc(.*)/ then ""
10
+ else
11
+ content[0].shift
12
+ $1.strip
13
+ end
14
+
15
+ self
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,118 @@
1
+ require 'tap/support/lazydoc/comment'
2
+
3
+ module Tap
4
+ module Support
5
+ module Lazydoc
6
+ class Document
7
+ # The source file for self, used during resolve.
8
+ attr_reader :source_file
9
+
10
+ # An array of Comment objects identifying lines
11
+ # resolved or to-be-resolved for self.
12
+ attr_reader :comments
13
+
14
+ # A hash of (const_name, attributes) pairs tracking the constant
15
+ # attributes resolved or to-be-resolved for self. Attributes
16
+ # are hashes of (key, comment) pairs.
17
+ attr_reader :const_attrs
18
+
19
+ # The default constant name used when no constant name
20
+ # is specified for a constant attribute.
21
+ attr_reader :default_const_name
22
+
23
+ # Flag indicating whether or not self has been resolved.
24
+ attr_accessor :resolved
25
+
26
+ def initialize(source_file=nil, default_const_name='')
27
+ self.source_file = source_file
28
+ @default_const_name = default_const_name
29
+ @comments = []
30
+ @const_attrs = {}
31
+ @resolved = false
32
+ self.reset
33
+ end
34
+
35
+ # Resets self by clearing const_attrs, comments, and setting
36
+ # resolved to false. Generally NOT recommended as this
37
+ # clears any work you've done registering lines; to simply
38
+ # allow resolve to re-scan a document, manually set
39
+ # resolved to false.
40
+ def reset
41
+ @const_attrs.clear
42
+ @comments.clear
43
+ @resolved = false
44
+ self
45
+ end
46
+
47
+ # Sets the source file for self. Expands the source file path if necessary.
48
+ def source_file=(source_file)
49
+ @source_file = source_file == nil ? nil : File.expand_path(source_file)
50
+ end
51
+
52
+ # Sets the default_const_name for self. Any const_attrs assigned to
53
+ # the previous default_const_name will be removed from const_attrs
54
+ # and merged with any const_attrs already assigned to the new
55
+ # default_const_name.
56
+ def default_const_name=(const_name)
57
+ self[const_name].merge!(const_attrs.delete(@default_const_name) || {})
58
+ @default_const_name = const_name
59
+ end
60
+
61
+ # Returns the attributes for the specified const_name.
62
+ def [](const_name)
63
+ const_attrs[const_name] ||= {}
64
+ end
65
+
66
+ # Register the specified line number to self. Returns a
67
+ # comment_class instance corresponding to the line.
68
+ def register(line_number, comment_class=Comment)
69
+ comment = comments.find {|c| c.class == comment_class && c.line_number == line_number }
70
+
71
+ if comment == nil
72
+ comment = comment_class.new(line_number)
73
+ comments << comment
74
+ end
75
+
76
+ comment
77
+ end
78
+
79
+ def register_method(method, comment_class=Comment)
80
+ register(/^\s*def\s+#{method}(\W|$)/, comment_class)
81
+ end
82
+
83
+ def resolve(str=nil)
84
+ return(false) if resolved
85
+
86
+ str = File.read(source_file) if str == nil
87
+ Lazydoc.parse(str) do |const_name, key, comment|
88
+ const_name = default_const_name if const_name.empty?
89
+ self[const_name][key] = comment
90
+ end
91
+
92
+ unless comments.empty?
93
+ lines = str.split(/\r?\n/)
94
+ comments.each do |comment|
95
+ comment.resolve(lines)
96
+ end
97
+ end
98
+
99
+ @resolved = true
100
+ end
101
+
102
+ def to_hash
103
+ const_hash = {}
104
+ const_attrs.each_pair do |const_name, attributes|
105
+ next if attributes.empty?
106
+
107
+ attr_hash = {}
108
+ attributes.each_pair do |key, comment|
109
+ attr_hash[key] = (block_given? ? yield(comment) : comment)
110
+ end
111
+ const_hash[const_name] = attr_hash
112
+ end
113
+ const_hash
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,24 @@
1
+ module Tap
2
+ module Support
3
+ module Lazydoc
4
+ class Method < Comment
5
+ def resolve(lines)
6
+ super
7
+ @subject =~ /def \w+(\((.*?)\))?/
8
+
9
+ args = $2.to_s.split(',').collect do |arg|
10
+ arg = arg.strip.upcase
11
+ case arg
12
+ when /^&/ then nil
13
+ when /^\*/ then arg[1..-1] + "..."
14
+ else arg
15
+ end
16
+ end
17
+
18
+ @subject = args.join(', ')
19
+ self
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -40,6 +40,8 @@ module Tap
40
40
  entries.empty?
41
41
  end
42
42
 
43
+ # Sets the search_paths for self. Setting search_paths
44
+ # clears all entries and puts search_path_index to zero.
43
45
  def search_paths=(search_paths)
44
46
  @entries = []
45
47
  @search_paths = search_paths
@@ -94,9 +96,9 @@ module Tap
94
96
  new_entry
95
97
  end
96
98
 
97
- # Iterates over each (key, value) entry in self, dynamically identifying entries
98
- # from search_paths if necessary. New entries are identifed using the each_for
99
- # method.
99
+ # Iterates over each (key, value) entry in self, dynamically
100
+ # identifying entries from search_paths if necessary. New
101
+ # entries are identifed using the each_for method.
100
102
  def each
101
103
  entries.each do |key, path|
102
104
  yield(key, path)
@@ -134,7 +136,34 @@ module Tap
134
136
  entries.collect {|path, value| [hash[path], value] }
135
137
  end
136
138
 
137
- protected
139
+ # Returns the first [key, value] entry where the key mini-matches
140
+ # the input pattern, or nil if no matching entry is found. This
141
+ # method identifies new entries as in each, as needed.
142
+ #
143
+ # See Tap::Root.minimal_match? for details on mini-matching.
144
+ def [](pattern)
145
+ each do |key, value|
146
+ return [key, value] if Root.minimal_match?(key, pattern)
147
+ end
148
+ nil
149
+ end
150
+
151
+ def inspect
152
+ lines = ["", "search paths:"]
153
+ search_paths.each_with_index do |path, index|
154
+ indent = (index == search_path_index ? "* " : " ")
155
+ lines << (indent + path.inspect)
156
+ end
157
+
158
+ lines << ""
159
+ lines << "mini-entries:"
160
+ minimize.each do |mini, value|
161
+ lines << " #{mini}: #{value.inspect}"
162
+ end
163
+ lines << ""
164
+
165
+ "#{self.class}:#{object_id} #{lines.join("\n")}"
166
+ end
138
167
 
139
168
  # Raised when multiple paths are assigned to the same manifest key.
140
169
  class ManifestConflict < StandardError
@@ -405,6 +405,62 @@ module Tap
405
405
  end
406
406
  RANGE_OR_NIL = range_or_nil_block
407
407
 
408
+ # Returns a block that checks the input is a Time. String inputs are
409
+ # loaded using Time.parse and then converted into times. Parsed times
410
+ # are local unless specified otherwise.
411
+ #
412
+ # time.class # => Proc
413
+ #
414
+ # now = Time.now
415
+ # time.call(now) # => now
416
+ #
417
+ # time.call('2008-08-08 20:00:00.00 +08:00').getutc.strftime('%Y/%m/%d %H:%M:%S')
418
+ # # => '2008/08/08 12:00:00'
419
+ #
420
+ # time.call('2008-08-08').strftime('%Y/%m/%d %H:%M:%S')
421
+ # # => '2008/08/08 00:00:00'
422
+ #
423
+ # time.call(1) # => ValidationError
424
+ # time.call(nil) # => ValidationError
425
+ #
426
+ # Warning: Time.parse will parse a valid time (Time.now)
427
+ # even when no time is specified:
428
+ #
429
+ # time.call('str').strftime('%Y/%m/%d %H:%M:%S')
430
+ # # => Time.now.strftime('%Y/%m/%d %H:%M:%S')
431
+ #
432
+ def time()
433
+ # adding this here is a compromise to lazy-load the parse
434
+ # method (autoload doesn't work since Time already exists)
435
+ require 'time' unless Time.respond_to?(:parse)
436
+ TIME
437
+ end
438
+
439
+ TIME = lambda do |input|
440
+ input = Time.parse(input) if input.kind_of?(String)
441
+ validate(input, [Time])
442
+ end
443
+
444
+ # Same as time but allows nil:
445
+ #
446
+ # time_or_nil.call('~') # => nil
447
+ # time_or_nil.call(nil) # => nil
448
+ def time_or_nil()
449
+ # adding this check is a compromise to autoload the parse
450
+ # method (autoload doesn't work since Time already exists)
451
+ require 'time' unless Time.respond_to?(:parse)
452
+ TIME_OR_NIL
453
+ end
454
+
455
+ TIME_OR_NIL = lambda do |input|
456
+ input = case input
457
+ when nil, '~' then nil
458
+ when String then Time.parse(input)
459
+ else input
460
+ end
461
+
462
+ validate(input, [Time, nil])
463
+ end
408
464
  end
409
465
  end
410
466
  end
data/lib/tap/task.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'tap/support/batchable'
2
2
  require 'tap/support/executable'
3
- require 'tap/support/command_line'
3
+ require 'tap/support/lazydoc/method'
4
+ autoload(:OptionParser, 'optparse')
4
5
 
5
6
  module Tap
6
7
 
@@ -214,52 +215,32 @@ module Tap
214
215
  subclass.define_configurations(configs)
215
216
  subclass.define_dependencies(dependencies)
216
217
  subclass.define_process(block) if block_given?
217
-
218
- #
219
- # Register documentation
220
- #
221
- const_name = subclass.to_s
222
- caller.each_with_index do |line, index|
223
- case line
224
- when /\/tap\/support\/declarations.rb/ then next
225
- when Support::Lazydoc::CALLER_REGEXP
226
- subclass.source_file = File.expand_path($1)
227
- lzd = subclass.lazydoc(false)
228
- lzd[const_name, false]['manifest'] = lzd.register($3.to_i - 1)
229
- break
230
- end
231
- end
232
-
233
- arity = options[:arity] || (block_given? ? block.arity : -1)
234
- comment = Support::Comment.new
235
- comment.subject = case
236
- when arity > 0
237
- Array.new(arity, "INPUT").join(' ')
238
- when arity < 0
239
- array = Array.new(-1 * arity - 1, "INPUT")
240
- array << "INPUTS..."
241
- array.join(' ')
242
- else ""
243
- end
244
- subclass.lazydoc(false)[const_name, false]['args'] ||= comment
245
-
246
- subclass.default_name = const_name.underscore
218
+ subclass.default_name = subclass.to_s.underscore
247
219
  subclass
248
220
  end
249
221
 
250
- def instantiate(argv, app=Tap::App.instance) # => instance, argv
222
+ # Parses the argv into an instance of self and an array of arguments (implicitly
223
+ # to be enqued to the instance and run by app). Yields a help string to the
224
+ # block when the argv indicates 'help'.
225
+ #
226
+ def parse(argv=ARGV, app=Tap::App.instance, &block) # :yields: help_str
227
+ parse!(argv.dup, &block)
228
+ end
229
+
230
+ # Same as parse, but removes switches destructively.
231
+ def parse!(argv=ARGV, app=Tap::App.instance) # :yields: help_str
251
232
  opts = OptionParser.new
252
233
 
253
234
  # Add configurations
254
- config = {}
235
+ argv_config = {}
255
236
  unless configurations.empty?
256
237
  opts.separator ""
257
238
  opts.separator "configurations:"
258
239
  end
259
240
 
260
- configurations.each do |receiver, key, configuration|
261
- opts.on(*Support::CommandLine.configv(configuration)) do |value|
262
- config[key] = value
241
+ configurations.each do |receiver, key, config|
242
+ opts.on(*config.to_optparse_argv) do |value|
243
+ argv_config[key] = value
263
244
  end
264
245
  end
265
246
 
@@ -269,8 +250,12 @@ module Tap
269
250
 
270
251
  opts.on_tail("-h", "--help", "Print this help") do
271
252
  opts.banner = "#{help}usage: tap run -- #{to_s.underscore} #{args.subject}"
272
- puts opts
273
- exit
253
+ if block_given?
254
+ yield(opts.to_s)
255
+ else
256
+ puts opts
257
+ exit
258
+ end
274
259
  end
275
260
 
276
261
  # Add option for name
@@ -295,26 +280,42 @@ module Tap
295
280
  use_args << obj
296
281
  end
297
282
  end
298
-
283
+
284
+ # parse the argv
299
285
  opts.parse!(argv)
286
+
287
+ # build and reconfigure the instance and any associated
288
+ # batch objects as specified in the file configurations
300
289
  obj = new({}, name, app)
301
-
302
290
  path_configs = load_config(app.config_filepath(name))
303
291
  if path_configs.kind_of?(Array)
304
292
  path_configs.each_with_index do |path_config, i|
305
- obj.initialize_batch_obj(path_config, "#{name}_#{i}") unless i == 0
293
+ next if i == 0
294
+ batch_obj = obj.initialize_batch_obj(path_config, "#{name}_#{i}")
295
+ batch_obj.reconfigure(argv_config)
306
296
  end
307
297
  path_configs = path_configs[0]
308
298
  end
309
-
299
+ obj.reconfigure(path_configs).reconfigure(argv_config)
300
+
301
+ # recollect arguments
310
302
  argv = (argv + use_args).collect {|str| str =~ /\A---\s*\n/ ? YAML.load(str) : str }
311
303
 
312
- [obj.reconfigure(path_configs).reconfigure(config), argv]
304
+ [obj, argv]
305
+ end
306
+
307
+ def execute(argv=ARGV)
308
+ instance, args = parse(ARGV) do |help|
309
+ puts help
310
+ exit
311
+ end
312
+
313
+ instance.execute(*args)
313
314
  end
314
315
 
315
316
  def lazydoc(resolve=true)
316
317
  lazydoc = super(false)
317
- lazydoc.register_method_pattern('args', :process) unless lazydoc.resolved?
318
+ lazydoc[self.to_s]['args'] ||= lazydoc.register_method(:process, Support::Lazydoc::Method)
318
319
  super
319
320
  end
320
321
 
@@ -615,5 +616,6 @@ module Tap
615
616
  raise ArgumentError, "config '#{name}' is not a hash" unless configs.kind_of?(Hash)
616
617
  klass.new(configs, name, &block)
617
618
  end
619
+
618
620
  end
619
621
  end