bahuvrihi-tap 0.11.2 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/bin/rap +2 -3
  2. data/bin/tap +1 -1
  3. data/cmd/console.rb +2 -2
  4. data/cmd/manifest.rb +2 -2
  5. data/cmd/run.rb +7 -9
  6. data/cmd/server.rb +5 -5
  7. data/doc/Class Reference +17 -20
  8. data/doc/Tutorial +5 -7
  9. data/lib/tap.rb +2 -0
  10. data/lib/tap/app.rb +21 -31
  11. data/lib/tap/constants.rb +2 -2
  12. data/lib/tap/declarations.rb +85 -97
  13. data/lib/tap/declarations/declaration_task.rb +58 -0
  14. data/lib/tap/declarations/description.rb +24 -0
  15. data/lib/tap/env.rb +20 -16
  16. data/lib/tap/exe.rb +2 -2
  17. data/lib/tap/file_task.rb +224 -410
  18. data/lib/tap/generator/arguments.rb +9 -0
  19. data/lib/tap/generator/base.rb +105 -28
  20. data/lib/tap/generator/destroy.rb +29 -12
  21. data/lib/tap/generator/generate.rb +55 -39
  22. data/lib/tap/generator/generators/command/templates/command.erb +3 -3
  23. data/lib/tap/generator/generators/config/config_generator.rb +34 -3
  24. data/lib/tap/generator/generators/root/root_generator.rb +6 -9
  25. data/lib/tap/generator/generators/root/templates/Rakefile +4 -4
  26. data/lib/tap/generator/generators/task/templates/test.erb +1 -1
  27. data/lib/tap/root.rb +211 -156
  28. data/lib/tap/support/aggregator.rb +6 -9
  29. data/lib/tap/support/audit.rb +278 -357
  30. data/lib/tap/support/constant_manifest.rb +24 -21
  31. data/lib/tap/support/dependency.rb +1 -1
  32. data/lib/tap/support/executable.rb +26 -48
  33. data/lib/tap/support/join.rb +44 -19
  34. data/lib/tap/support/joins/sync_merge.rb +3 -5
  35. data/lib/tap/support/parser.rb +1 -1
  36. data/lib/tap/task.rb +195 -150
  37. data/lib/tap/tasks/dump.rb +2 -2
  38. data/lib/tap/test/extensions.rb +11 -13
  39. data/lib/tap/test/file_test.rb +71 -129
  40. data/lib/tap/test/file_test_class.rb +4 -1
  41. data/lib/tap/test/tap_test.rb +26 -154
  42. metadata +15 -22
  43. data/lib/tap/patches/optparse/summarize.rb +0 -62
  44. data/lib/tap/support/assignments.rb +0 -173
  45. data/lib/tap/support/class_configuration.rb +0 -182
  46. data/lib/tap/support/configurable.rb +0 -113
  47. data/lib/tap/support/configurable_class.rb +0 -271
  48. data/lib/tap/support/configuration.rb +0 -170
  49. data/lib/tap/support/instance_configuration.rb +0 -173
  50. data/lib/tap/support/lazydoc.rb +0 -386
  51. data/lib/tap/support/lazydoc/attributes.rb +0 -48
  52. data/lib/tap/support/lazydoc/comment.rb +0 -503
  53. data/lib/tap/support/lazydoc/config.rb +0 -17
  54. data/lib/tap/support/lazydoc/definition.rb +0 -36
  55. data/lib/tap/support/lazydoc/document.rb +0 -152
  56. data/lib/tap/support/lazydoc/method.rb +0 -24
  57. data/lib/tap/support/tdoc.rb +0 -409
  58. data/lib/tap/support/tdoc/tdoc_html_generator.rb +0 -38
  59. data/lib/tap/support/tdoc/tdoc_html_template.rb +0 -42
  60. data/lib/tap/support/validation.rb +0 -479
@@ -1,173 +0,0 @@
1
- module Tap
2
- module Support
3
-
4
- # InstanceConfiguration serves as a forwarding hash, where get and set operations
5
- # for configurations are sent to instance methods rather than to an underlying data
6
- # store.
7
- #
8
- # class Sample
9
- # attr_accessor :key
10
- # end
11
- # sample = Sample.new
12
- #
13
- # class_config = ClassConfiguration.new(Sample)
14
- # class_config.add(:key)
15
- #
16
- # config = InstanceConfiguration.new(class_config)
17
- # config.bind(sample)
18
- #
19
- # sample.key = 'value'
20
- # config[:key] # => 'value'
21
- #
22
- # config[:key] = 'another'
23
- # sample.key # => 'another'
24
- #
25
- # Non-config keys are simply stored:
26
- #
27
- # config[:not_a_key] = 'value'
28
- # config[:not_a_key] # => 'value'
29
- #
30
- # config.store # => {:not_a_key => 'value'}
31
- # config.to_hash # => {:key => 'another', :not_a_key => 'value'}
32
- #
33
- class InstanceConfiguration
34
-
35
- # The bound receiver
36
- attr_reader :receiver
37
-
38
- # The underlying data store for non-config keys
39
- attr_reader :store
40
-
41
- # The ClassConfiguration specifying config keys
42
- attr_reader :class_config
43
-
44
- def initialize(class_config, receiver=nil, store={})
45
- @receiver = receiver
46
- @store = store
47
- @class_config = class_config
48
- end
49
-
50
- # Updates self to ensure that each class_config key
51
- # has a value in self; the config.default value is
52
- # set if a value does not already exist.
53
- #
54
- # Returns self.
55
- def update(class_config=self.class_config)
56
- class_config.each_pair do |key, config|
57
- self[key] ||= config.default
58
- end
59
- self
60
- end
61
-
62
- # Binds self to the specified receiver. Mapped keys are
63
- # removed from store and sent to their writer method on
64
- # receiver.
65
- def bind(receiver)
66
- raise "already bound to: #{@receiver}" if bound?
67
- raise ArgumentError, "receiver cannot be nil" if receiver == nil
68
-
69
- class_config.each_pair do |key, config|
70
- receiver.send(config.writer, store.delete(key)) if config.writer
71
- end
72
- @receiver = receiver
73
-
74
- self
75
- end
76
-
77
- # Returns true if self is bound to a receiver
78
- def bound?
79
- receiver != nil
80
- end
81
-
82
- # Unbinds self from the specified receiver. Mapped values
83
- # are stored in store. Returns the unbound receiver.
84
- def unbind
85
- class_config.each_pair do |key, config|
86
- store[key] = receiver.send(config.reader) if config.reader
87
- end
88
- r = receiver
89
- @receiver = nil
90
-
91
- r
92
- end
93
-
94
- # Duplicates self, returning an unbound InstanceConfiguration.
95
- def dup
96
- duplicate = super()
97
- duplicate.instance_variable_set(:@receiver, nil)
98
- duplicate.instance_variable_set(:@store, @store.dup)
99
- duplicate
100
- end
101
-
102
- # Associates the value the key. If bound? and the key
103
- # is a class_config key, then the value will be forwarded
104
- # to the config.writer method on the receiver.
105
- def []=(key, value)
106
- case
107
- when bound? && config = class_config.map[key.to_sym]
108
- config.writer ? receiver.send(config.writer, value) : store[key] = value
109
- else store[key] = value
110
- end
111
- end
112
-
113
- # Retrieves the value corresponding to the key. If bound?
114
- # and the key is a class_config key, then the value is
115
- # obtained from the config.reader method on the receiver.
116
- def [](key)
117
- case
118
- when bound? && config = class_config.map[key.to_sym]
119
- config.reader ? receiver.send(config.reader) : store[key]
120
- else store[key]
121
- end
122
- end
123
-
124
- # True if the key is assigned in self.
125
- def has_key?(key)
126
- (bound? && class_config.key?(key)) || store.has_key?(key)
127
- end
128
-
129
- # Calls block once for each key-value pair stored in self.
130
- def each_pair # :yields: key, value
131
- class_config.each_pair do |key, config|
132
- yield(key, receiver.send(config.reader)) if config.reader
133
- end if bound?
134
-
135
- store.each_pair do |key, value|
136
- yield(key, value)
137
- end
138
- end
139
-
140
- # Equal if the to_hash values of self and another are equal.
141
- def ==(another)
142
- another.respond_to?(:to_hash) && to_hash == another.to_hash
143
- end
144
-
145
- # Returns self as a hash.
146
- def to_hash
147
- hash = store.dup
148
- class_config.keys.each do |key|
149
- hash[key] = self[key]
150
- end if bound?
151
- hash
152
- end
153
-
154
- def to_yaml(opts)
155
- hash = {}
156
- store.each_pair do |key, value|
157
- hash[key.to_s] = value
158
- end
159
-
160
- class_config.each_pair do |key, config|
161
- hash[key.to_s] = bound? ? self[key] : config.default
162
- end
163
-
164
- hash.to_yaml(opts)
165
- end
166
-
167
- # Overrides default inspect to show the to_hash values.
168
- def inspect
169
- "#<#{self.class}:#{object_id} to_hash=#{to_hash.inspect}>"
170
- end
171
- end
172
- end
173
- end
@@ -1,386 +0,0 @@
1
- require 'tap/support/lazydoc/document'
2
-
3
- module Tap
4
- module Support
5
-
6
- # Lazydoc lazily pulls documentation out of source files and makes it
7
- # available through Attributes. Lazydoc can find two types of
8
- # documentation, constant attributes and code comments. To illustrate,
9
- # consider the following:
10
- #
11
- # # Sample::key <value>
12
- # # This is the comment content. A content
13
- # # string can span multiple lines...
14
- # #
15
- # # code.is_allowed
16
- # # much.as_in RDoc
17
- # #
18
- # # and stops at the next non-comment
19
- # # line, the next constant attribute,
20
- # # or an end key
21
- # class Sample
22
- # extend Tap::Support::Lazydoc::Attributes
23
- # self.source_file = __FILE__
24
- #
25
- # lazy_attr :key
26
- #
27
- # # comment content for a code comment
28
- # # may similarly span multiple lines
29
- # def method_one
30
- # end
31
- # end
32
- #
33
- # When a lazy attribute is called, Lazydoc scans <tt>source_file</tt> for
34
- # the corresponding constant attribute and makes it available as a
35
- # Lazydoc::Comment.
36
- #
37
- # comment = Sample::key
38
- # comment.value
39
- # # => "<value>"
40
- #
41
- # comment.content
42
- # # => [
43
- # # ["This is the comment content. A content", "string can span multiple lines..."],
44
- # # [""],
45
- # # [" code.is_allowed"],
46
- # # [" much.as_in RDoc"],
47
- # # [""],
48
- # # ["and stops at the next non-comment", "line, the next constant attribute,", "or an end key"]]
49
- #
50
- # "\n#{'.' * 30}\n" + comment.wrap(30) + "\n#{'.' * 30}\n"
51
- # # => %q{
52
- # # ..............................
53
- # # This is the comment content.
54
- # # A content string can span
55
- # # multiple lines...
56
- # #
57
- # # code.is_allowed
58
- # # much.as_in RDoc
59
- # #
60
- # # and stops at the next
61
- # # non-comment line, the next
62
- # # constant attribute, or an end
63
- # # key
64
- # # ..............................
65
- # #}
66
- #
67
- # In addition, individual lines of code may be registered and resolved by Lazydoc:
68
- #
69
- # doc = Sample.lazydoc.reset
70
- # comment = doc.register(/method_one/)
71
- #
72
- # doc.resolve
73
- # comment.subject # => " def method_one"
74
- # comment.content # => [["comment content for a code comment", "may similarly span multiple lines"]]
75
- #
76
- # With these basics in mind, here are some details...
77
- #
78
- # === Constant Attributes
79
- # Constant attributes are like constants in Ruby, but with an extra 'key'
80
- # that must consist of only lowercase letters and/or underscores. For
81
- # example, these are constant attributes:
82
- #
83
- # # Const::Name::key
84
- # # Const::Name::key_with_underscores
85
- # # ::key
86
- #
87
- # While these are not:
88
- #
89
- # # Const::Name::Key
90
- # # Const::Name::key2
91
- # # Const::Name::k@y
92
- #
93
- # Lazydoc parses a Lazydoc::Comment for each constant attribute by using the
94
- # remainder of the line as a value (ie subject) and scanning down for content.
95
- # Scanning continues until a non-comment line, an end key, or a new attribute
96
- # is reached; the comment is then stored by constant name and key.
97
- #
98
- # str = %Q{
99
- # # Const::Name::key value for key
100
- # # comment for key
101
- # # parsed until a
102
- # # non-comment line
103
- #
104
- # # Const::Name::another value for another
105
- # # comment for another
106
- # # parsed to an end key
107
- # # Const::Name::another-
108
- # #
109
- # # ignored comment
110
- # }
111
- #
112
- # doc = Lazydoc::Document.new
113
- # doc.resolve(str)
114
- #
115
- # doc.to_hash {|comment| [comment.value, comment.to_s] }
116
- # # => {
117
- # # 'Const::Name' => {
118
- # # 'key' => ['value for key', 'comment for key parsed until a non-comment line'],
119
- # # 'another' => ['value for another', 'comment for another parsed to an end key']}
120
- # # }
121
- #
122
- # Constant attributes are only parsed from commented lines. To turn off
123
- # attribute parsing for a section of documentation, use start/stop keys:
124
- #
125
- # str = %Q{
126
- # Const::Name::not_parsed
127
- #
128
- # # :::-
129
- # # Const::Name::not_parsed
130
- # # :::+
131
- # # Const::Name::parsed value
132
- # }
133
- #
134
- # doc = Lazydoc::Document.new
135
- # doc.resolve(str)
136
- # doc.to_hash {|comment| comment.value } # => {'Const::Name' => {'parsed' => 'value'}}
137
- #
138
- # To hide attributes from RDoc, make use of the RDoc <tt>:startdoc:</tt>
139
- # document modifier like this (note that spaces are added to prevent RDoc
140
- # from hiding the example):
141
- #
142
- # # :start doc::Const::Name::one hidden in RDoc
143
- # # * This line is visible in RDoc.
144
- # # :start doc::Const::Name::one-
145
- # #
146
- # #--
147
- # # Const::Name::two
148
- # # You can hide attribute comments like this.
149
- # # Const::Name::two-
150
- # #++
151
- # #
152
- # # * This line is also visible in RDoc.
153
- #
154
- # Here is the same text, for comparison if you are reading this as RDoc:
155
- #
156
- # :startdoc::Const::Name::one hidden in RDoc
157
- # * This line is visible in RDoc.
158
- # :startdoc::Const::Name::one-
159
- #
160
- #--
161
- # Const::Name::two
162
- # You can hide attribute comments like this.
163
- # Const::Name::two-
164
- #++
165
- #
166
- # * This line is also visible in RDoc.
167
- #
168
- # As a side note, <tt>Const::Name::key</tt> is not a reference to the 'key'
169
- # constant (as that would be invalid). In *very* idiomatic ruby
170
- # <tt>Const::Name::key</tt> is equivalent to the method call
171
- # <tt>Const::Name.key</tt>.
172
- #
173
- # === Code Comments
174
- # Code comments are lines registered for parsing if and when a Lazydoc gets
175
- # resolved. Unlike constant attributes, the registered line is the comment
176
- # subject (ie value) and contents are parsed up from it (basically mimicking
177
- # the behavior of RDoc).
178
- #
179
- # str = %Q{
180
- # # comment lines for
181
- # # the method
182
- # def method
183
- # end
184
- #
185
- # # as in RDoc, the comment can be
186
- # # separated from the method
187
- #
188
- # def another_method
189
- # end
190
- # }
191
- #
192
- # doc = Lazydoc::Document.new
193
- # doc.register(3)
194
- # doc.register(9)
195
- # doc.resolve(str)
196
- #
197
- # doc.comments.collect {|comment| [comment.subject, comment.to_s] }
198
- # # => [
199
- # # ['def method', 'comment lines for the method'],
200
- # # ['def another_method', 'as in RDoc, the comment can be separated from the method']]
201
- #
202
- # Comments may be registered to specific line numbers, or with a Proc or
203
- # Regexp that will determine the line number during resolution. In the case
204
- # of a Regexp, the first matching line is used; Procs receive an array of
205
- # lines and should return the line number that should be used. See
206
- # Lazydoc::Comment#resolve for more details.
207
- #
208
- module Lazydoc
209
-
210
- # A regexp matching an attribute start or end. After a match:
211
- #
212
- # $1:: const_name
213
- # $3:: key
214
- # $4:: end flag
215
- #
216
- ATTRIBUTE_REGEXP = /([A-Z][A-z]*(::[A-Z][A-z]*)*)?::([a-z_]+)(-?)/
217
-
218
- # A regexp matching constants from the ATTRIBUTE_REGEXP leader
219
- CONSTANT_REGEXP = /#.*?([A-Z][A-z]*(::[A-Z][A-z]*)*)?$/
220
-
221
- # A regexp matching a caller line, to extract the calling file
222
- # and line number. After a match:
223
- #
224
- # $1:: file
225
- # $3:: line number (as a string, obviously)
226
- #
227
- # Note that line numbers in caller start at 1, not 0.
228
- CALLER_REGEXP = /^(([A-z]:)?[^:]+):(\d+)/
229
-
230
- module_function
231
-
232
- # A hash of (source_file, lazydoc) pairs tracking the
233
- # Lazydoc instance for the given source file.
234
- def registry
235
- @registry ||= []
236
- end
237
-
238
- # Returns the lazydoc in registry for the specified source file.
239
- # If no such lazydoc exists, one will be created for it.
240
- def [](source_file)
241
- source_file = File.expand_path(source_file.to_s)
242
- lazydoc = registry.find {|doc| doc.source_file == source_file }
243
- if lazydoc == nil
244
- lazydoc = Document.new(source_file)
245
- registry << lazydoc
246
- end
247
- lazydoc
248
- end
249
-
250
- # Register the specified line numbers to the lazydoc for source_file.
251
- # Returns a comment_class instance corresponding to the line.
252
- def register(source_file, line_number, comment_class=Comment)
253
- Lazydoc[source_file].register(line_number, comment_class)
254
- end
255
-
256
- # Resolves all lazydocs which include the specified code comments.
257
- def resolve_comments(comments)
258
- registry.each do |doc|
259
- next if (comments & doc.comments).empty?
260
- doc.resolve
261
- end
262
- end
263
-
264
- # Scans the specified file for attributes keyed by key and stores
265
- # the resulting comments in the source_file lazydoc. Returns the
266
- # lazydoc.
267
- def scan_doc(source_file, key)
268
- lazydoc = nil
269
- scan(File.read(source_file), key) do |const_name, attr_key, comment|
270
- lazydoc = self[source_file] unless lazydoc
271
- lazydoc[const_name][attr_key] = comment
272
- end
273
- lazydoc
274
- end
275
-
276
- # Scans the string or StringScanner for attributes matching the key
277
- # (keys may be patterns, they are incorporated into a regexp). Yields
278
- # each (const_name, key, value) triplet to the mandatory block and
279
- # skips regions delimited by the stop and start keys <tt>:-</tt>
280
- # and <tt>:+</tt>.
281
- #
282
- # str = %Q{
283
- # # Const::Name::key value
284
- # # ::alt alt_value
285
- # #
286
- # # Ignored::Attribute::not_matched value
287
- # # :::-
288
- # # Also::Ignored::key value
289
- # # :::+
290
- # # Another::key another value
291
- #
292
- # Ignored::key value
293
- # }
294
- #
295
- # results = []
296
- # Lazydoc.scan(str, 'key|alt') do |const_name, key, value|
297
- # results << [const_name, key, value]
298
- # end
299
- #
300
- # results
301
- # # => [
302
- # # ['Const::Name', 'key', 'value'],
303
- # # ['', 'alt', 'alt_value'],
304
- # # ['Another', 'key', 'another value']]
305
- #
306
- # Returns the StringScanner used during scanning.
307
- def scan(str, key) # :yields: const_name, key, value
308
- scanner = case str
309
- when StringScanner then str
310
- when String then StringScanner.new(str)
311
- else raise TypeError, "can't convert #{str.class} into StringScanner or String"
312
- end
313
-
314
- regexp = /^(.*?)::(:-|#{key})/
315
- while !scanner.eos?
316
- break if scanner.skip_until(regexp) == nil
317
-
318
- if scanner[2] == ":-"
319
- scanner.skip_until(/:::\+/)
320
- else
321
- next unless scanner[1] =~ CONSTANT_REGEXP
322
- key = scanner[2]
323
- yield($1.to_s, key, scanner.matched.strip) if scanner.scan(/[ \r\t].*$|$/)
324
- end
325
- end
326
-
327
- scanner
328
- end
329
-
330
- # Parses constant attributes from the string or StringScanner. Yields
331
- # each (const_name, key, comment) triplet to the mandatory block
332
- # and skips regions delimited by the stop and start keys <tt>:-</tt>
333
- # and <tt>:+</tt>.
334
- #
335
- # str = %Q{
336
- # # Const::Name::key subject for key
337
- # # comment for key
338
- #
339
- # # :::-
340
- # # Ignored::key value
341
- # # :::+
342
- #
343
- # # Ignored text before attribute ::another subject for another
344
- # # comment for another
345
- # }
346
- #
347
- # results = []
348
- # Lazydoc.parse(str) do |const_name, key, comment|
349
- # results << [const_name, key, comment.subject, comment.to_s]
350
- # end
351
- #
352
- # results
353
- # # => [
354
- # # ['Const::Name', 'key', 'subject for key', 'comment for key'],
355
- # # ['', 'another', 'subject for another', 'comment for another']]
356
- #
357
- # Returns the StringScanner used during scanning.
358
- def parse(str) # :yields: const_name, key, comment
359
- scanner = case str
360
- when StringScanner then str
361
- when String then StringScanner.new(str)
362
- else raise TypeError, "can't convert #{str.class} into StringScanner or String"
363
- end
364
-
365
- scan(scanner, '[a-z_]+') do |const_name, key, value|
366
- comment = Comment.parse(scanner, false) do |line|
367
- if line =~ ATTRIBUTE_REGEXP
368
- # rewind to capture the next attribute unless an end is specified.
369
- scanner.unscan unless $4 == '-' && $3 == key && $1.to_s == const_name
370
- true
371
- else false
372
- end
373
- end
374
- comment.subject = value
375
- yield(const_name, key, comment)
376
- end
377
- end
378
-
379
- def usage(path, cols=80)
380
- scanner = StringScanner.new(File.read(path))
381
- scanner.scan(/^#!.*?$/)
382
- Comment.parse(scanner, false).wrap(cols, 2).strip
383
- end
384
- end
385
- end
386
- end