bahuvrihi-tap 0.10.7 → 0.10.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/MIT-LICENSE +0 -2
  2. data/README +20 -31
  3. data/bin/rap +18 -8
  4. data/cgi/run.rb +47 -37
  5. data/cmd/console.rb +1 -1
  6. data/cmd/destroy.rb +3 -3
  7. data/cmd/generate.rb +3 -3
  8. data/cmd/manifest.rb +61 -53
  9. data/cmd/run.rb +1 -1
  10. data/doc/Class Reference +119 -110
  11. data/doc/Command Reference +76 -123
  12. data/doc/Syntax Reference +290 -0
  13. data/doc/Tutorial +307 -237
  14. data/lib/tap.rb +1 -12
  15. data/lib/tap/app.rb +46 -71
  16. data/lib/tap/constants.rb +1 -1
  17. data/lib/tap/declarations.rb +110 -100
  18. data/lib/tap/env.rb +141 -173
  19. data/lib/tap/exe.rb +5 -5
  20. data/lib/tap/file_task.rb +2 -2
  21. data/lib/tap/generator/base.rb +0 -4
  22. data/lib/tap/generator/destroy.rb +8 -12
  23. data/lib/tap/generator/generate.rb +19 -14
  24. data/lib/tap/generator/generators/command/command_generator.rb +1 -1
  25. data/lib/tap/generator/generators/config/config_generator.rb +3 -3
  26. data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
  27. data/lib/tap/generator/generators/generator/generator_generator.rb +27 -0
  28. data/lib/tap/generator/generators/generator/templates/task.erb +27 -0
  29. data/lib/tap/generator/generators/root/root_generator.rb +12 -12
  30. data/lib/tap/generator/generators/root/templates/Rakefile +1 -2
  31. data/lib/tap/generator/generators/root/templates/tapfile +11 -8
  32. data/lib/tap/generator/generators/task/task_generator.rb +1 -3
  33. data/lib/tap/generator/generators/task/templates/test.erb +1 -3
  34. data/lib/tap/root.rb +4 -2
  35. data/lib/tap/support/aggregator.rb +16 -3
  36. data/lib/tap/support/assignments.rb +10 -9
  37. data/lib/tap/support/audit.rb +58 -62
  38. data/lib/tap/support/class_configuration.rb +32 -43
  39. data/lib/tap/support/combinator.rb +7 -7
  40. data/lib/tap/support/configurable.rb +13 -14
  41. data/lib/tap/support/configurable_class.rb +6 -30
  42. data/lib/tap/support/configuration.rb +36 -9
  43. data/lib/tap/support/constant.rb +75 -13
  44. data/lib/tap/support/constant_manifest.rb +115 -0
  45. data/lib/tap/support/dependencies.rb +27 -67
  46. data/lib/tap/support/dependency.rb +44 -0
  47. data/lib/tap/support/executable.rb +78 -109
  48. data/lib/tap/support/executable_queue.rb +1 -1
  49. data/lib/tap/support/gems.rb +6 -0
  50. data/lib/tap/support/gems/rack.rb +197 -84
  51. data/lib/tap/support/instance_configuration.rb +29 -3
  52. data/lib/tap/support/intern.rb +46 -0
  53. data/lib/tap/support/join.rb +67 -11
  54. data/lib/tap/support/joins.rb +2 -0
  55. data/lib/tap/support/joins/fork.rb +1 -0
  56. data/lib/tap/support/joins/merge.rb +3 -1
  57. data/lib/tap/support/joins/sequence.rb +2 -2
  58. data/lib/tap/support/joins/switch.rb +3 -1
  59. data/lib/tap/support/joins/sync_merge.rb +6 -0
  60. data/lib/tap/support/lazy_attributes.rb +16 -1
  61. data/lib/tap/support/lazydoc.rb +21 -21
  62. data/lib/tap/support/lazydoc/comment.rb +59 -55
  63. data/lib/tap/support/lazydoc/definition.rb +36 -0
  64. data/lib/tap/support/lazydoc/document.rb +37 -13
  65. data/lib/tap/support/manifest.rb +120 -131
  66. data/lib/tap/support/minimap.rb +90 -0
  67. data/lib/tap/support/node.rb +4 -6
  68. data/lib/tap/support/parser.rb +63 -6
  69. data/lib/tap/support/schema.rb +11 -2
  70. data/lib/tap/support/shell_utils.rb +3 -5
  71. data/lib/tap/support/string_ext.rb +60 -0
  72. data/lib/tap/support/tdoc.rb +2 -2
  73. data/lib/tap/support/templater.rb +29 -15
  74. data/lib/tap/support/validation.rb +22 -11
  75. data/lib/tap/task.rb +155 -156
  76. data/lib/tap/tasks/load.rb +95 -8
  77. data/lib/tap/test/extensions.rb +2 -1
  78. data/lib/tap/test/script_tester.rb +7 -1
  79. data/template/index.erb +39 -32
  80. metadata +13 -13
  81. data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +0 -15
  82. data/lib/tap/patches/rake/rake_test_loader.rb +0 -8
  83. data/lib/tap/patches/rake/testtask.rb +0 -57
  84. data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -51
  85. data/lib/tap/patches/ruby19/parsedate.rb +0 -16
  86. data/lib/tap/spec.rb +0 -42
  87. data/lib/tap/spec/adapter.rb +0 -25
  88. data/lib/tap/spec/inheritable_class_test_root.rb +0 -9
  89. data/lib/tap/support/constant_utils.rb +0 -127
  90. data/lib/tap/support/summary.rb +0 -30
@@ -0,0 +1,36 @@
1
+ module Tap
2
+ module Support
3
+ module Lazydoc
4
+ class Definition < Comment
5
+ attr_accessor :subclass
6
+
7
+ def configurations(fragment_sep=" ", line_sep="\n", strip=true)
8
+ lines = []
9
+ subclass.configurations.each do |receiver, key, config|
10
+ desc = config.desc
11
+ case desc
12
+ when Definition
13
+ lines << "# #{desc.subclass}"
14
+ lines.concat desc.original_to_s(fragment_sep, nil, strip).collect {|line| "# #{line}"}
15
+ lines << "#{key}:"
16
+ lines.concat desc.configurations(fragment_sep).collect {|line| " #{line}"}
17
+ else
18
+ lines << "# #{desc}"
19
+ lines << "#{key}: #{config.default}"
20
+ lines << ""
21
+ end
22
+ end
23
+
24
+ lines
25
+ end
26
+
27
+ alias original_to_s to_s
28
+
29
+ def to_s(fragment_sep=" ", line_sep="\n", strip=true)
30
+ lines = [original_to_s(fragment_sep, line_sep, strip)] + configurations(fragment_sep)
31
+ line_sep ? lines.join(line_sep) : lines
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -3,24 +3,38 @@ require 'tap/support/lazydoc/comment'
3
3
  module Tap
4
4
  module Support
5
5
  module Lazydoc
6
+
7
+ # A Document tracks constant attributes and code comments for a particular
8
+ # source file. Documents may be assigned a default_const_name to be used
9
+ # when a constant attribute does not specify a constant.
10
+ #
11
+ # # KeyWithConst::key value a
12
+ # # ::key value b
13
+ #
14
+ # doc = Document.new(__FILE__, 'DefaultConst')
15
+ # doc.resolve
16
+ # doc['KeyWithConst']['key'].value # => 'value a'
17
+ # doc['DefaultConst']['key'].value # => 'value b'
18
+ #
6
19
  class Document
7
- # The source file for self, used during resolve.
20
+
21
+ # The source file for self, used during resolve
8
22
  attr_reader :source_file
9
23
 
10
24
  # An array of Comment objects identifying lines
11
- # resolved or to-be-resolved for self.
25
+ # resolved or to-be-resolved
12
26
  attr_reader :comments
13
27
 
14
- # A hash of (const_name, attributes) pairs tracking the constant
28
+ # A hash of [const_name, attributes] pairs tracking the constant
15
29
  # attributes resolved or to-be-resolved for self. Attributes
16
- # are hashes of (key, comment) pairs.
30
+ # are hashes of [key, comment] pairs.
17
31
  attr_reader :const_attrs
18
32
 
19
33
  # The default constant name used when no constant name
20
- # is specified for a constant attribute.
34
+ # is specified for a constant attribute
21
35
  attr_reader :default_const_name
22
36
 
23
- # Flag indicating whether or not self has been resolved.
37
+ # Flag indicating whether or not self has been resolved
24
38
  attr_accessor :resolved
25
39
 
26
40
  def initialize(source_file=nil, default_const_name='')
@@ -50,9 +64,8 @@ module Tap
50
64
  end
51
65
 
52
66
  # 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.
67
+ # the previous default will be removed and merged with those already
68
+ # assigned to the new default.
56
69
  def default_const_name=(const_name)
57
70
  self[const_name].merge!(const_attrs.delete(@default_const_name) || {})
58
71
  @default_const_name = const_name
@@ -72,9 +85,12 @@ module Tap
72
85
  end
73
86
  names
74
87
  end
75
-
76
- # Register the specified line number to self. Returns a
77
- # comment_class instance corresponding to the line.
88
+
89
+ # Register the specified line number to self. Register
90
+ # may take an integer or a regexp for late-evaluation.
91
+ # See Comment#resolve for more details.
92
+ #
93
+ # Returns a comment_class instance corresponding to the line.
78
94
  def register(line_number, comment_class=Comment)
79
95
  comment = comments.find {|c| c.class == comment_class && c.line_number == line_number }
80
96
 
@@ -85,11 +101,19 @@ module Tap
85
101
 
86
102
  comment
87
103
  end
88
-
104
+
105
+ # Registers a regexp matching methods by the specified
106
+ # name.
89
107
  def register_method(method, comment_class=Comment)
90
108
  register(/^\s*def\s+#{method}(\W|$)/, comment_class)
91
109
  end
92
110
 
111
+ # Scans str for constant attributes and adds them to to self. Code
112
+ # comments are also resolved against str. If no str is specified,
113
+ # the contents of source_file are used instead.
114
+ #
115
+ # Resolve does nothing if resolved == true. Returns true if str
116
+ # was resolved, or false otherwise.
93
117
  def resolve(str=nil)
94
118
  return(false) if resolved
95
119
 
@@ -1,180 +1,169 @@
1
- require 'tap/root'
1
+ require 'tap/support/minimap'
2
2
 
3
3
  module Tap
4
4
  module Support
5
+
6
+ # Stores an array of paths and makes them available for lookup by
7
+ # minipath. Manifests may be bound to a Tap::Env, allowing searches
8
+ # across a full environment (including nested environments).
9
+ #
10
+ # Manifest has a number of hooks used by subclasses like
11
+ # ConstantManifest to lazily add entries as needed.
5
12
  class Manifest
6
13
  class << self
7
- def normalize(key)
8
- key.to_s.downcase.gsub(/\s/, "_").delete(":")
14
+
15
+ # Interns a new manifest, overriding the minikey
16
+ # method with the block (the minikey method converts
17
+ # entries to the path used during minimap and
18
+ # minimatch lookup, see Minimap).
19
+ def intern(*args, &block)
20
+ instance = new(*args)
21
+ if block_given?
22
+ instance.extend Support::Intern(:minikey)
23
+ instance.minikey_block = block
24
+ end
25
+ instance
9
26
  end
10
27
  end
11
28
 
12
29
  include Enumerable
30
+ include Minimap
13
31
 
14
- # An array of (key, value) entries in self.
15
- attr_reader :entries
32
+ # Matches a compound manifest search key. After the match,
33
+ # if the key is compound then:
34
+ #
35
+ # $1:: env_key
36
+ # $4:: key
37
+ #
38
+ # If the key is not compound, $4 is nil and $1 is the key.
39
+ SEARCH_REGEXP = /^(([A-z]:)?.*?)(:(.*))?$/
16
40
 
17
- # An array of search_paths to identify entries.
18
- attr_reader :search_paths
41
+ # An array entries in self.
42
+ attr_reader :entries
19
43
 
20
- # The index of the search_path that will be searched
21
- # next when building the manifest.
22
- attr_reader :search_path_index
44
+ # The bound Tap::Env, or nil.
45
+ attr_reader :env
23
46
 
24
- def initialize(search_paths)
25
- self.search_paths = search_paths
26
- end
47
+ # The reader on Tap::Env accessing manifests of the
48
+ # same type as self. reader is set during bind.
49
+ attr_reader :reader
27
50
 
28
- # Returns an array of the entries keys.
29
- def keys
30
- entries.collect {|(key, value)| key }
51
+ # Initializes a new, unbound Manifest.
52
+ def initialize(entries=[])
53
+ @entries = entries
54
+ @env = nil
55
+ @reader = nil
31
56
  end
32
57
 
33
- # Returns an array of the entries values.
34
- def values
35
- entries.collect {|(key, value)| value }
36
- end
37
-
38
- # True if entries are empty.
39
- def empty?
40
- entries.empty?
58
+ # Binds self to an env and reader. The manifests returned by env.reader
59
+ # will be used during traversal methods like search. Raises an error if
60
+ # env does not respond to reader; returns self.
61
+ def bind(env, reader)
62
+ if env == nil
63
+ raise ArgumentError, "env may not be nil"
64
+ end
65
+
66
+ unless env.respond_to?(reader)
67
+ raise ArgumentError, "env does not respond to #{reader}"
68
+ end
69
+
70
+ @env = env
71
+ @reader = reader
72
+ self
41
73
  end
42
74
 
43
- # Sets the search_paths for self. Setting search_paths
44
- # clears all entries and puts search_path_index to zero.
45
- def search_paths=(search_paths)
46
- @entries = []
47
- @search_paths = search_paths
48
- @search_path_index = 0
75
+ # Unbinds self from env. Returns self.
76
+ def unbind
77
+ @env = nil
78
+ @reader = nil
79
+ self
49
80
  end
50
81
 
51
- # Clears entries and sets the search_path_index to zero.
52
- def reset
53
- @entries.clear
54
- @search_path_index = 0
82
+ # True if the env and reader have been set.
83
+ def bound?
84
+ @env != nil && @reader != nil
55
85
  end
56
86
 
57
- # Builds the manifest, identifying all entries from search_paths.
58
- # Returns self.
87
+ # A hook for dynamically building entries. By default build simply
88
+ # returns self
59
89
  def build
60
- each {|k, v|} unless built?
61
90
  self
62
91
  end
63
92
 
64
- # True if all search paths have been checked for entries
65
- # (ie search_path_index == search_paths.length).
93
+ # A hook to flag when self is built. By default built? returns true.
66
94
  def built?
67
- @search_path_index == search_paths.length
95
+ true
68
96
  end
69
97
 
70
- # Abstract method which should return each (key, value) entry
71
- # for a given search path. Raises a NotImplementedError
72
- # if left not implemented.
73
- def entries_for(search_path)
74
- [[search_path, search_path]]
98
+ # A hook to reset a build. By default reset simply returns self.
99
+ def reset
100
+ self
75
101
  end
76
102
 
77
- # Adds the (key, value) pair to entries and returns the new entry.
78
- # Checks that entries does not already assign key a conflicting value;
79
- # raises an error if this is the case, or returns the existing entry.
80
- #
81
- # Keys are normalized using Manifest.normalize before storing.
82
- def store(key, value)
83
- key = Manifest.normalize(key)
84
- existing = entries.find {|(k, v)| key == k }
85
-
86
- if existing
87
- if existing[1] != value
88
- raise ManifestConflict.new(key, value, existing[1])
89
- else
90
- return existing
91
- end
92
- end
93
-
94
- new_entry = [key, value]
95
- entries << new_entry
96
- new_entry
103
+ # True if entries are empty.
104
+ def empty?
105
+ entries.empty?
97
106
  end
98
107
 
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.
108
+ # Iterates over each entry entry in self.
102
109
  def each
103
- entries.each do |key, path|
104
- yield(key, path)
105
- end
106
-
107
- unless built?
108
- n_to_skip = @search_path_index
109
- search_paths.each do |search_path|
110
- # advance to the current search path
111
- if n_to_skip > 0
112
- n_to_skip -= 1
113
- next
114
- end
115
- @search_path_index += 1
116
-
117
- # collect new entries and yield afterwards to ensure
118
- # that all entries for the search_path get stored
119
- new_entries = entries_for(*search_path)
120
- next if new_entries == nil
121
-
122
- new_entries.each {|(key, value)| store(key, value) }
123
- new_entries.each {|(key, value)| yield(key, value) }
124
- end
125
- end
110
+ entries.each {|entry| yield(entry) }
126
111
  end
127
112
 
128
- # Returns an array of (mini_key, value) pairs, matching
129
- # entries by index.
130
- def minimize
131
- hash = {}
132
- Tap::Root.minimize(keys) do |path, mini_path|
133
- hash[path] = mini_path
134
- end
135
-
136
- entries.collect {|path, value| [hash[path], value] }
113
+ # Alias for Minimap#minimatch.
114
+ def [](key)
115
+ minimatch(key)
137
116
  end
138
117
 
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.
118
+ # Search across env.each for the first entry minimatching key.
119
+ # A single env can be specified by using a compound key like
120
+ # 'env_key:key'. Returns nil if no matching entry is found.
142
121
  #
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)
122
+ # Search raises an error unless bound?
123
+ def search(key)
124
+ raise "cannot search unless bound" unless bound?
125
+
126
+ key =~ SEARCH_REGEXP
127
+ envs = if $4 != nil
128
+ # compound key, match for env
129
+ key = $4
130
+ [env.minimatch($1)].compact
131
+ else
132
+ # not a compound key, search all
133
+ # envs by iterating env itself
134
+ env
156
135
  end
157
136
 
158
- lines << ""
159
- lines << "mini-entries:"
160
- minimize.each do |mini, value|
161
- lines << " #{mini}: #{value.inspect}"
137
+ # traverse envs looking for the first
138
+ # manifest entry matching key
139
+ envs.each do |env|
140
+ if result = env.send(reader).minimatch(key)
141
+ return result
142
+ end
162
143
  end
163
- lines << ""
164
144
 
165
- "#{self.class}:#{object_id} #{lines.join("\n")}"
145
+ nil
166
146
  end
167
-
168
- # Raised when multiple paths are assigned to the same manifest key.
169
- class ManifestConflict < StandardError
170
- attr_reader :key, :value, :existing
147
+
148
+ def inspect(traverse=true)
149
+ if traverse && bound?
150
+ lines = []
151
+ env.each do |env|
152
+ manifest = env.send(reader).build
153
+ next if manifest.empty?
154
+
155
+ lines << "== #{env.root.root}"
156
+ manifest.minimap.each do |mini, value|
157
+ lines << " #{mini}: #{value.inspect}"
158
+ end
159
+ end
160
+ return lines.join("\n")
161
+ end
171
162
 
172
- def initialize(key, value, existing)
173
- @key = key
174
- @value = value
175
- @existing = existing
176
- super("attempted to store '%s': %s\nbut already was\n%s" % [key, value, existing])
163
+ lines = minimap.collect do |mini, value|
164
+ " #{mini}: #{value.inspect}"
177
165
  end
166
+ "#{self.class}:#{object_id} (#{bound? ? env.root.root : ''})\n#{lines.join("\n")}"
178
167
  end
179
168
  end
180
169
  end
@@ -0,0 +1,90 @@
1
+ require 'tap/root'
2
+
3
+ module Tap
4
+ module Support
5
+
6
+ # Minimap adds minimization and search methods to an array of paths (see
7
+ # Tap::Root.minimize and Tap::Root.minimal_match?).
8
+ #
9
+ # paths = %w{
10
+ # path/to/file-0.1.0.txt
11
+ # path/to/file-0.2.0.txt
12
+ # path/to/another_file.txt
13
+ # }
14
+ # paths.extend Minimap
15
+ #
16
+ # paths.minimatch('file') # => 'path/to/file-0.1.0.txt'
17
+ # paths.minimatch('file-0.2.0') # => 'path/to/file-0.2.0.txt'
18
+ # paths.minimatch('another_file') # => 'path/to/another_file.txt'
19
+ #
20
+ # More generally, Minimap may extend any object responding to each.
21
+ # Override the minikey method to convert objects into paths.
22
+ #
23
+ # class ConstantMap < Array
24
+ # include Minimap
25
+ #
26
+ # def minikey(const)
27
+ # const.underscore
28
+ # end
29
+ # end
30
+ #
31
+ # constants = ConstantMap[Tap::Support::Minimap Tap::Root]
32
+ # constants.minimatch('root') # => Tap::Root
33
+ # constants.minimatch('minimap') # => Tap::Support::Minimap
34
+ #
35
+ module Minimap
36
+
37
+ # Provides a minimized map of the entries using keys provided minikey.
38
+ #
39
+ # paths = %w{
40
+ # path/to/file-0.1.0.txt
41
+ # path/to/file-0.2.0.txt
42
+ # path/to/another_file.txt
43
+ # }.extend Minimap
44
+ #
45
+ # paths.minimap
46
+ # # => [
47
+ # # ['file-0.1.0', 'path/to/file-0.1.0.txt'],
48
+ # # ['file-0.2.0', 'path/to/file-0.2.0.txt'],
49
+ # # ['another_file','path/to/another_file.txt']]
50
+ #
51
+ def minimap
52
+ hash = {}
53
+ map = []
54
+ each {|entry| map << (hash[minikey(entry)] = [entry]) }
55
+ Tap::Root.minimize(hash.keys) do |key, mini_key|
56
+ hash[key].unshift mini_key
57
+ end
58
+
59
+ map
60
+ end
61
+
62
+ # Returns the first entry whose minikey mini-matches the input, or nil if
63
+ # no such entry exists.
64
+ #
65
+ # paths = %w{
66
+ # path/to/file-0.1.0.txt
67
+ # path/to/file-0.2.0.txt
68
+ # path/to/another_file.txt
69
+ # }.extend Minimap
70
+ #
71
+ # paths.minimatch('file-0.2.0') # => 'path/to/file-0.2.0.txt'
72
+ # paths.minimatch('file-0.3.0') # => nil
73
+ #
74
+ def minimatch(key)
75
+ each do |entry|
76
+ return entry if Tap::Root.minimal_match?(minikey(entry), key)
77
+ end
78
+ nil
79
+ end
80
+
81
+ protected
82
+
83
+ # A hook to convert a non-path entry into a path for minimap and
84
+ # minimatch. Returns the entry by default.
85
+ def minikey(entry)
86
+ entry
87
+ end
88
+ end
89
+ end
90
+ end