tap 0.9.1 → 0.10.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 (244) hide show
  1. data/History +37 -30
  2. data/MIT-LICENSE +1 -1
  3. data/README +92 -44
  4. data/bin/tap +62 -75
  5. data/cmd/console.rb +42 -0
  6. data/cmd/destroy.rb +16 -0
  7. data/cmd/generate.rb +16 -0
  8. data/cmd/run.rb +126 -0
  9. data/doc/Class Reference +362 -0
  10. data/doc/Command Reference +153 -0
  11. data/doc/Tutorial +237 -0
  12. data/lib/tap.rb +6 -45
  13. data/lib/tap/app.rb +126 -500
  14. data/lib/tap/constants.rb +2 -29
  15. data/lib/tap/env.rb +555 -250
  16. data/lib/tap/file_task.rb +60 -103
  17. data/lib/tap/generator/base.rb +109 -0
  18. data/lib/tap/generator/destroy.rb +37 -0
  19. data/lib/tap/generator/generate.rb +61 -0
  20. data/lib/tap/generator/generators/command/command_generator.rb +16 -12
  21. data/lib/tap/generator/generators/command/templates/command.erb +13 -19
  22. data/lib/tap/generator/generators/config/config_generator.rb +18 -27
  23. data/lib/tap/generator/generators/config/templates/doc.erb +12 -0
  24. data/lib/tap/generator/generators/config/templates/nodoc.erb +8 -0
  25. data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -11
  26. data/lib/tap/generator/generators/file_task/templates/file.txt +11 -2
  27. data/lib/tap/generator/generators/file_task/templates/result.yml +6 -0
  28. data/lib/tap/generator/generators/file_task/templates/task.erb +24 -31
  29. data/lib/tap/generator/generators/file_task/templates/test.erb +18 -22
  30. data/lib/tap/generator/generators/root/root_generator.rb +45 -31
  31. data/lib/tap/generator/generators/root/templates/Rakefile +64 -41
  32. data/lib/tap/generator/generators/root/templates/gemspec +27 -0
  33. data/lib/tap/generator/generators/root/templates/tapfile +8 -0
  34. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -0
  35. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
  36. data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +15 -0
  37. data/lib/tap/generator/generators/task/task_generator.rb +21 -28
  38. data/lib/tap/generator/generators/task/templates/task.erb +13 -23
  39. data/lib/tap/generator/generators/task/templates/test.erb +15 -18
  40. data/lib/tap/generator/manifest.rb +14 -0
  41. data/lib/tap/patches/rake/rake_test_loader.rb +0 -0
  42. data/lib/tap/patches/rake/testtask.rb +0 -0
  43. data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -0
  44. data/lib/tap/patches/ruby19/parsedate.rb +0 -0
  45. data/lib/tap/root.rb +260 -21
  46. data/lib/tap/support/aggregator.rb +11 -11
  47. data/lib/tap/support/assignments.rb +172 -0
  48. data/lib/tap/support/audit.rb +20 -18
  49. data/lib/tap/support/batchable.rb +21 -10
  50. data/lib/tap/support/batchable_class.rb +107 -0
  51. data/lib/tap/support/class_configuration.rb +154 -239
  52. data/lib/tap/support/command_line.rb +97 -102
  53. data/lib/tap/support/comment.rb +270 -0
  54. data/lib/tap/support/configurable.rb +86 -65
  55. data/lib/tap/support/configurable_class.rb +296 -0
  56. data/lib/tap/support/configuration.rb +122 -0
  57. data/lib/tap/support/constant.rb +70 -0
  58. data/lib/tap/support/constant_utils.rb +127 -0
  59. data/lib/tap/support/declarations.rb +111 -0
  60. data/lib/tap/support/executable.rb +30 -17
  61. data/lib/tap/support/executable_queue.rb +0 -0
  62. data/lib/tap/support/framework.rb +71 -0
  63. data/lib/tap/support/framework_class.rb +199 -0
  64. data/lib/tap/support/instance_configuration.rb +147 -0
  65. data/lib/tap/support/lazydoc.rb +428 -0
  66. data/lib/tap/support/manifest.rb +89 -0
  67. data/lib/tap/support/run_error.rb +0 -0
  68. data/lib/tap/support/shell_utils.rb +33 -9
  69. data/lib/tap/support/summary.rb +30 -0
  70. data/lib/tap/support/tdoc.rb +339 -134
  71. data/lib/tap/support/tdoc/tdoc_html_generator.rb +0 -0
  72. data/lib/tap/support/tdoc/tdoc_html_template.rb +0 -0
  73. data/lib/tap/support/templater.rb +180 -0
  74. data/lib/tap/support/validation.rb +409 -76
  75. data/lib/tap/support/versions.rb +5 -3
  76. data/lib/tap/task.rb +78 -174
  77. data/lib/tap/tasks/dump.rb +56 -0
  78. data/lib/tap/tasks/rake.rb +93 -0
  79. data/lib/tap/test.rb +3 -3
  80. data/lib/tap/test/env_vars.rb +2 -2
  81. data/lib/tap/test/file_methods.rb +19 -20
  82. data/lib/tap/test/script_methods.rb +144 -0
  83. data/lib/tap/test/subset_methods.rb +1 -1
  84. data/lib/tap/test/tap_methods.rb +28 -62
  85. data/lib/tap/workflow.rb +22 -39
  86. metadata +48 -179
  87. data/Basic Overview +0 -151
  88. data/Command Reference +0 -99
  89. data/Rakefile +0 -127
  90. data/Tutorial +0 -287
  91. data/lib/tap/cmd/console.rb +0 -31
  92. data/lib/tap/cmd/destroy.rb +0 -20
  93. data/lib/tap/cmd/generate.rb +0 -20
  94. data/lib/tap/cmd/run.rb +0 -151
  95. data/lib/tap/dump.rb +0 -57
  96. data/lib/tap/generator.rb +0 -91
  97. data/lib/tap/generator/generators/command/USAGE +0 -6
  98. data/lib/tap/generator/generators/config/USAGE +0 -21
  99. data/lib/tap/generator/generators/config/templates/config.erb +0 -1
  100. data/lib/tap/generator/generators/file_task/USAGE +0 -3
  101. data/lib/tap/generator/generators/file_task/templates/file.yml +0 -3
  102. data/lib/tap/generator/generators/generator/USAGE +0 -0
  103. data/lib/tap/generator/generators/generator/generator_generator.rb +0 -21
  104. data/lib/tap/generator/generators/generator/templates/generator.erb +0 -32
  105. data/lib/tap/generator/generators/generator/templates/usage.erb +0 -1
  106. data/lib/tap/generator/generators/root/USAGE +0 -0
  107. data/lib/tap/generator/generators/root/templates/ReadMe.txt +0 -0
  108. data/lib/tap/generator/generators/root/templates/tap.yml +0 -80
  109. data/lib/tap/generator/generators/task/USAGE +0 -3
  110. data/lib/tap/generator/generators/workflow/USAGE +0 -0
  111. data/lib/tap/generator/generators/workflow/templates/task.erb +0 -16
  112. data/lib/tap/generator/generators/workflow/templates/test.erb +0 -7
  113. data/lib/tap/generator/generators/workflow/workflow_generator.rb +0 -6
  114. data/lib/tap/generator/options.rb +0 -26
  115. data/lib/tap/generator/usage.rb +0 -26
  116. data/lib/tap/support/batchable_methods.rb +0 -34
  117. data/lib/tap/support/command_line_methods.rb +0 -76
  118. data/lib/tap/support/configurable_methods.rb +0 -224
  119. data/lib/tap/support/logger.rb +0 -88
  120. data/lib/tap/support/rake.rb +0 -43
  121. data/lib/tap/support/tdoc/config_attr.rb +0 -362
  122. data/test/app/config/another/task.yml +0 -1
  123. data/test/app/config/batch.yml +0 -2
  124. data/test/app/config/empty.yml +0 -0
  125. data/test/app/config/erb.yml +0 -2
  126. data/test/app/config/some/task.yml +0 -1
  127. data/test/app/config/template.yml +0 -2
  128. data/test/app/config/version-0.1.yml +0 -1
  129. data/test/app/config/version.yml +0 -1
  130. data/test/app/lib/app_test_task.rb +0 -3
  131. data/test/app_test.rb +0 -1849
  132. data/test/env/test_configure/recurse_a.yml +0 -2
  133. data/test/env/test_configure/recurse_b.yml +0 -2
  134. data/test/env/test_configure/tap.yml +0 -23
  135. data/test/env/test_load_env_config/dir/tap.yml +0 -3
  136. data/test/env/test_load_env_config/recurse_a.yml +0 -2
  137. data/test/env/test_load_env_config/recurse_b.yml +0 -2
  138. data/test/env/test_load_env_config/tap.yml +0 -3
  139. data/test/env_test.rb +0 -198
  140. data/test/file_task/config/batch.yml +0 -2
  141. data/test/file_task/config/configured.yml +0 -1
  142. data/test/file_task/old_file_one.txt +0 -0
  143. data/test/file_task/old_file_two.txt +0 -0
  144. data/test/file_task_test.rb +0 -1291
  145. data/test/root/alt_lib/alt_module.rb +0 -4
  146. data/test/root/file.txt +0 -0
  147. data/test/root/glob/one.txt +0 -0
  148. data/test/root/glob/two.txt +0 -0
  149. data/test/root/lib/absolute_alt_filepath.rb +0 -2
  150. data/test/root/lib/alternative_filepath.rb +0 -2
  151. data/test/root/lib/another_module.rb +0 -2
  152. data/test/root/lib/nested/some_module.rb +0 -4
  153. data/test/root/lib/no_module_included.rb +0 -0
  154. data/test/root/lib/some/module.rb +0 -4
  155. data/test/root/lib/some_class.rb +0 -2
  156. data/test/root/lib/some_module.rb +0 -3
  157. data/test/root/load_path/load_path_module.rb +0 -2
  158. data/test/root/load_path/skip_module.rb +0 -2
  159. data/test/root/mtime/older.txt +0 -0
  160. data/test/root/unload/full_path.rb +0 -2
  161. data/test/root/unload/loaded_by_nested.rb +0 -2
  162. data/test/root/unload/nested/nested_load.rb +0 -6
  163. data/test/root/unload/nested/nested_with_ext.rb +0 -4
  164. data/test/root/unload/nested/relative_path.rb +0 -4
  165. data/test/root/unload/older.rb +0 -2
  166. data/test/root/unload/unload_base.rb +0 -9
  167. data/test/root/versions/another.yml +0 -0
  168. data/test/root/versions/file-0.1.2.yml +0 -0
  169. data/test/root/versions/file-0.1.yml +0 -0
  170. data/test/root/versions/file.yml +0 -0
  171. data/test/root_test.rb +0 -718
  172. data/test/support/aggregator_test.rb +0 -99
  173. data/test/support/audit_test.rb +0 -445
  174. data/test/support/batchable_test.rb +0 -74
  175. data/test/support/class_configuration_test.rb +0 -331
  176. data/test/support/command_line_test.rb +0 -58
  177. data/test/support/configurable/config/configured.yml +0 -2
  178. data/test/support/configurable_test.rb +0 -295
  179. data/test/support/executable_queue_test.rb +0 -103
  180. data/test/support/executable_test.rb +0 -38
  181. data/test/support/logger_test.rb +0 -31
  182. data/test/support/rake_test.rb +0 -37
  183. data/test/support/shell_utils_test.rb +0 -24
  184. data/test/support/tdoc_test.rb +0 -370
  185. data/test/support/validation_test.rb +0 -54
  186. data/test/support/versions_test.rb +0 -103
  187. data/test/tap_test_helper.rb +0 -57
  188. data/test/tap_test_suite.rb +0 -7
  189. data/test/task/config/batch.yml +0 -2
  190. data/test/task/config/batched.yml +0 -2
  191. data/test/task/config/configured.yml +0 -1
  192. data/test/task/config/example.yml +0 -1
  193. data/test/task_base_test.rb +0 -24
  194. data/test/task_syntax_test.rb +0 -300
  195. data/test/task_test.rb +0 -320
  196. data/test/test/env_vars_test.rb +0 -48
  197. data/test/test/file_methods/test_assert_files/expected/one.txt +0 -1
  198. data/test/test/file_methods/test_assert_files/expected/two.txt +0 -1
  199. data/test/test/file_methods/test_assert_files/input/one.txt +0 -1
  200. data/test/test/file_methods/test_assert_files/input/two.txt +0 -1
  201. data/test/test/file_methods/test_assert_files_can_have_no_expected_files_if_specified/input/one.txt +0 -1
  202. data/test/test/file_methods/test_assert_files_can_have_no_expected_files_if_specified/input/two.txt +0 -1
  203. data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +0 -1
  204. data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/two.txt +0 -1
  205. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +0 -1
  206. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +0 -1
  207. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/expected/one.txt +0 -1
  208. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +0 -1
  209. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +0 -1
  210. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +0 -1
  211. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +0 -1
  212. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +0 -1
  213. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +0 -1
  214. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +0 -1
  215. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +0 -1
  216. data/test/test/file_methods/test_method_glob/expected/file.yml +0 -0
  217. data/test/test/file_methods/test_method_glob/expected/file_1.txt +0 -0
  218. data/test/test/file_methods/test_method_glob/expected/file_2.txt +0 -0
  219. data/test/test/file_methods_doc/test_sub/expected/one.txt +0 -1
  220. data/test/test/file_methods_doc/test_sub/expected/two.txt +0 -1
  221. data/test/test/file_methods_doc/test_sub/input/one.txt +0 -1
  222. data/test/test/file_methods_doc/test_sub/input/two.txt +0 -1
  223. data/test/test/file_methods_doc_test.rb +0 -29
  224. data/test/test/file_methods_test.rb +0 -275
  225. data/test/test/subset_methods_test.rb +0 -171
  226. data/test/test/tap_methods/test_assert_files/expected/task/name/a.txt +0 -1
  227. data/test/test/tap_methods/test_assert_files/expected/task/name/b.txt +0 -1
  228. data/test/test/tap_methods/test_assert_files/input/a.txt +0 -1
  229. data/test/test/tap_methods/test_assert_files/input/b.txt +0 -1
  230. data/test/test/tap_methods_test.rb +0 -399
  231. data/test/workflow_test.rb +0 -120
  232. data/vendor/rails_generator.rb +0 -56
  233. data/vendor/rails_generator/base.rb +0 -263
  234. data/vendor/rails_generator/commands.rb +0 -581
  235. data/vendor/rails_generator/generated_attribute.rb +0 -42
  236. data/vendor/rails_generator/lookup.rb +0 -209
  237. data/vendor/rails_generator/manifest.rb +0 -53
  238. data/vendor/rails_generator/options.rb +0 -143
  239. data/vendor/rails_generator/scripts.rb +0 -83
  240. data/vendor/rails_generator/scripts/destroy.rb +0 -7
  241. data/vendor/rails_generator/scripts/generate.rb +0 -7
  242. data/vendor/rails_generator/scripts/update.rb +0 -12
  243. data/vendor/rails_generator/simple_logger.rb +0 -46
  244. data/vendor/rails_generator/spec.rb +0 -44
@@ -1,7 +1,7 @@
1
1
  module Tap
2
- module Support
3
-
4
- # Aggregator allows thread-safe collection of Audits, organized
2
+ module Support
3
+
4
+ # Aggregator allows thread-safe collection of Audits, organized
5
5
  # by Audit#_current_source.
6
6
  class Aggregator < Monitor
7
7
 
@@ -9,39 +9,39 @@ module Tap
9
9
  super
10
10
  clear
11
11
  end
12
-
12
+
13
13
  # Clears self of all audits.
14
14
  def clear
15
15
  synchronize { self.hash = Hash.new }
16
16
  end
17
-
17
+
18
18
  # The total number of audits recorded in self.
19
19
  def size
20
20
  synchronize { hash.values.inject(0) {|sum, array| sum + array.length} }
21
21
  end
22
-
22
+
23
23
  # True if size == 0
24
24
  def empty?
25
25
  synchronize { hash.empty? }
26
26
  end
27
-
27
+
28
28
  # Stores the Audit according to _result._current_source
29
29
  def store(_result)
30
30
  synchronize { (hash[_result._current_source] ||= []) << _result }
31
31
  end
32
-
32
+
33
33
  # Retreives all aggregated audits for the specified source.
34
34
  def retrieve(source)
35
35
  synchronize { hash[source] }
36
36
  end
37
-
37
+
38
38
  # Retreives all audits for the input sources, joined into an array.
39
39
  def retrieve_all(*sources)
40
40
  synchronize do
41
41
  sources.collect {|src| hash[src] }.flatten.compact
42
42
  end
43
43
  end
44
-
44
+
45
45
  # Converts self to a hash of (source, audits) pairs.
46
46
  def to_hash
47
47
  hash.dup
@@ -49,7 +49,7 @@ module Tap
49
49
 
50
50
  protected
51
51
 
52
- attr_accessor :hash
52
+ attr_accessor :hash # :nodoc:
53
53
  end
54
54
  end
55
55
  end
@@ -0,0 +1,172 @@
1
+ module Tap
2
+ module Support
3
+
4
+ # Assignments defines an array of [key, values] pairs that tracks
5
+ # which values are assigned to a particular key. A value may only
6
+ # be assigned to one key at a time.
7
+ #
8
+ # Assignments tracks the order in which keys are declared, and the
9
+ # order in which values are assigned to a key. This behavior is
10
+ # used by ClassConfiguration to track the order in which configurations
11
+ # are assigned to a class; the order, in turn, is used in the formation
12
+ # of config files, command line documentation, etc.
13
+ #
14
+ # === Example
15
+ #
16
+ # a = Assignments.new
17
+ # a.assign(:one, 'one')
18
+ # a.assign(:two, 'two')
19
+ # a.assign(:one, 'ONE')
20
+ # a.to_a # => [[:one, ['one', 'ONE']], [:two, ['two']]]
21
+ #
22
+ # b = Assignments.new(a)
23
+ # b.to_a # => [[:one, ['one', 'ONE']], [:two, ['two']]]
24
+ #
25
+ # b.unassign('one')
26
+ # b.assign(:one, 1)
27
+ # b.to_a # => [[:one, ['ONE', 1]], [:two, ['two']]]
28
+ # a.to_a # => [[:one, ['one', 'ONE']], [:two, ['two']]]
29
+ #
30
+ #--
31
+ # TODO:
32
+ # Assignments may be optimizable... check if an alternate internal
33
+ # storage can be made faster or to take up less memory. Not that
34
+ # that much can be gained period...
35
+ class Assignments
36
+ include Enumerable
37
+
38
+ def initialize(parent=nil)
39
+ existing_array = case parent
40
+ when Assignments then parent.array
41
+ when Array then parent
42
+ when nil then []
43
+ else
44
+ raise ArgumentError.new("cannot convert #{parent.class} to Assignments, Array, or nil")
45
+ end
46
+
47
+ @array = []
48
+ existing_array.each do |key, values|
49
+ assign(key, *values)
50
+ end
51
+ end
52
+
53
+ # Adds the key to the declarations.
54
+ def declare(key)
55
+ array << [key, []] unless declared?(key)
56
+ end
57
+
58
+ # Removes all values for the specified key and
59
+ # removes the key from declarations.
60
+ def undeclare(key)
61
+ array.delete_if {|k, values| k == key}
62
+ end
63
+
64
+ # Returns true if the key is declared.
65
+ def declared?(key)
66
+ array.each do |k, values|
67
+ return true if k == key
68
+ end
69
+ false
70
+ end
71
+
72
+ # Returns an array of all the declared keys
73
+ def declarations
74
+ array.collect {|key, values| key }
75
+ end
76
+
77
+ # Assigns the specified values to the key. The key will
78
+ # be declared, if necessary. Raises an error if the key
79
+ # is nil.
80
+ def assign(key, *values)
81
+ raise ArgumentError.new("nil keys are not allowed") if key == nil
82
+
83
+ # partition the input values into existing and new
84
+ # values, then check for conflicts.
85
+ current_values = self.values
86
+ existing_values, new_values = values.partition {|value| current_values.include?(value) }
87
+
88
+ conflicts = []
89
+ existing_values.collect do |value|
90
+ current_key = key_for(value)
91
+ if current_key != key
92
+ conflicts << "#{value} (#{key}) already assigned to #{current_key}"
93
+ end
94
+ end
95
+
96
+ unless conflicts.empty?
97
+ raise ArgumentError.new(conflicts.join("\n"))
98
+ end
99
+
100
+ declare(key)
101
+ values_for(key).concat new_values
102
+ end
103
+
104
+ # Removes the specified value.
105
+ def unassign(value)
106
+ array.each do |key, values|
107
+ values.delete(value)
108
+ end
109
+ end
110
+
111
+ # Returns true if the value has been assigned to a key.
112
+ def assigned?(value)
113
+ array.each do |key, values|
114
+ return true if values.include?(value)
115
+ end
116
+ false
117
+ end
118
+
119
+ # Returns the ordered values as an array
120
+ def values
121
+ array.collect {|key, values| values}.flatten
122
+ end
123
+
124
+ # Returns the key for the specified value, or nil
125
+ # if the value is unassigned.
126
+ def key_for(value)
127
+ array.each do |key, values|
128
+ return key if values.include?(value)
129
+ end
130
+ nil
131
+ end
132
+
133
+ # Returns the values for the specified key, or nil if
134
+ # the key cannot be found.
135
+ def values_for(key)
136
+ array.each do |k, values|
137
+ return values if k == key
138
+ end
139
+ nil
140
+ end
141
+
142
+ # Yields each key, value pair in the order in which
143
+ # the keys were declared. Keys with no values are
144
+ # skipped.
145
+ def each
146
+ array.each do |key, values|
147
+ values.each {|value| yield(key, value) }
148
+ end
149
+ end
150
+
151
+ # Yields each key, values pair in the order in which
152
+ # the keys were declared.
153
+ def each_pair
154
+ array.each do |key, values|
155
+ yield(key, values)
156
+ end
157
+ end
158
+
159
+ # Returns the [key, values] as an array
160
+ def to_a
161
+ array.collect {|key, values| [key, values.dup] }
162
+ end
163
+
164
+ protected
165
+
166
+ # An array of [key, values] arrays tracking the
167
+ # key and order in which values were assigned.
168
+ attr_reader :array
169
+
170
+ end
171
+ end
172
+ end
@@ -1,3 +1,5 @@
1
+ autoload(:PP, 'pp')
2
+
1
3
  module Tap
2
4
  module Support
3
5
 
@@ -28,17 +30,15 @@ module Tap
28
30
  end
29
31
  end
30
32
 
31
- # == Overview
32
- #
33
33
  # Audit provides a way to track the values (inputs and results) passed
34
- # among tasks. Audits allow you to track inputs as they make their
35
- # way through a workflow, and have a great deal of importance for
36
- # debugging and record keeping.
34
+ # among tasks or, more generally, any Executable method. Audits allow
35
+ # you to track inputs as they make their way through a workflow, and
36
+ # have great utility in debugging and record keeping.
37
37
  #
38
38
  # During execution, the group of inputs for a task are used to initialize
39
39
  # an Audit. These inputs mark the begining of an audit trail; every
40
- # task that processes them (including the first) records it's result in
41
- # the trail with the task as the 'source' of the result.
40
+ # task that processes them (including the first) adds to the trail by
41
+ # recording it's result using itself as the 'source' of the result.
42
42
  #
43
43
  # Since Audits are meant to be fairly general structures, they can take
44
44
  # any object as a source, so for illustration lets use some symbols:
@@ -50,7 +50,7 @@ module Tap
50
50
  # a._record(:A, 2)
51
51
  # a._record(:B, 3)
52
52
  #
53
- # Now you can pull up the trails of sources and values, as well as
53
+ # Now you can pull up the source and value trails, as well as
54
54
  # information like the current and original values:
55
55
  #
56
56
  # a._source_trail # => [nil, :A, :B]
@@ -62,8 +62,9 @@ module Tap
62
62
  # a._current # => 3
63
63
  # a._current_source # => :B
64
64
  #
65
- # Merges are supported by using an array of the merging trails as the
66
- # source, and an array of the merging values as the initial value.
65
+ # Merges are supported by using an array of the merging trails (internally
66
+ # an AuditMerge) as the source, and an array of the merging values as the
67
+ # initial value.
67
68
  #
68
69
  # b = Audit.new(10, nil)
69
70
  # b._record(:C, 11)
@@ -84,7 +85,7 @@ module Tap
84
85
  # Audit supports forks by duplicating the source and value trails. Forks
85
86
  # can be developed independently. Importantly, Audits are forked during
86
87
  # a merge; notice the additional record in +a+ doesn't change the source
87
- # trail for +c+
88
+ # trail for +c+:
88
89
  #
89
90
  # a1 = a._fork
90
91
  #
@@ -120,9 +121,8 @@ module Tap
120
121
  #
121
122
  #--
122
123
  # TODO:
123
- # Create an AuditMerge class to mark merges (don't use arrays). Track nesting level
124
- # of ams; see if you can hook this into _to_s process to make extraction/presentation
125
- # of audits more managable.
124
+ # Track nesting level of ams; see if you can hook this into the _to_s process to make
125
+ # extraction/presentation of audits more managable.
126
126
  #
127
127
  # Create a FirstLastArray to minimize the audit data collected. Allow different audit
128
128
  # modes:
@@ -140,8 +140,6 @@ module Tap
140
140
  # `-----`-----`-o-[j] j5
141
141
  #
142
142
  class Audit
143
- autoload(:PP, 'pp')
144
-
145
143
  class << self
146
144
 
147
145
  # Creates a new Audit by merging the input audits. The value of the new
@@ -177,7 +175,11 @@ module Tap
177
175
  end
178
176
  end
179
177
 
180
- attr_reader :_sources, :_values
178
+ # An array of the sources in self
179
+ attr_reader :_sources
180
+
181
+ # An array of the values in self
182
+ attr_reader :_values
181
183
 
182
184
  # An arbitrary constant used to identify when no inputs have been
183
185
  # provided to Audit.new. (nil itself cannot be used as nil is a
@@ -378,7 +380,7 @@ module Tap
378
380
 
379
381
  protected
380
382
 
381
- attr_writer :_sources, :_values
383
+ attr_writer :_sources, :_values # :nodoc:
382
384
 
383
385
  private
384
386
 
@@ -1,16 +1,28 @@
1
+ require 'tap/support/batchable_class'
2
+
1
3
  module Tap
2
4
  module Support
3
5
 
4
6
  # Batchable encapsulates the methods used to support batching
5
- # of tasks. See the 'Batches' section in the Tap::Task
6
- # documentation for more details on how Batchable works in
7
- # practice.
7
+ # of tasks. Classes including Batchable should call <tt>super</tt>
8
+ # during initialization to initialize batch, or they should
9
+ # initialize batch themselves.
10
+ #
11
+ # See the 'Batches' section in the Tap::Task documentation for
12
+ # details on how Batchable works in practice.
8
13
  module Batchable
9
- extend Support::BatchableMethods
14
+
15
+ def self.included(mod)
16
+ mod.extend Support::BatchableClass if mod.kind_of?(Class)
17
+ end
10
18
 
11
- # The object batch. (must be initializd by classes that
12
- # include Batchable)
19
+ # The object batch.
13
20
  attr_reader :batch
21
+
22
+ def initialize(batch=[])
23
+ @batch = batch
24
+ @batch << self
25
+ end
14
26
 
15
27
  # Returns true if the batch size is greater than one
16
28
  # (the one being self).
@@ -21,13 +33,12 @@ module Tap
21
33
  # Returns the index of the self in batch.
22
34
  def batch_index
23
35
  batch.index(self)
24
- end
36
+ end
25
37
 
26
38
  # Initializes a new batch object and adds the object to batch.
27
- # The object will be self if batch is empty (ie for the first
28
- # call) or a duplicate of self if not.
39
+ # The object will be a duplicate of self.
29
40
  def initialize_batch_obj
30
- obj = (batch.empty? ? self : self.dup)
41
+ obj = self.dup
31
42
  batch << obj
32
43
  obj
33
44
  end
@@ -0,0 +1,107 @@
1
+ module Tap
2
+ module Support
3
+
4
+ # BatchableClass encapsulates class methods related to Batchable.
5
+ module BatchableClass
6
+
7
+ # Merges the batches for the specified objects. All objects
8
+ # sharing the individual object batches will be affected, even
9
+ # if they are not listed explicitly as an input.
10
+ #
11
+ # t1 = Tap::Task.new
12
+ # t2 = Tap::Task.new
13
+ # t3 = t2.initialize_batch_obj
14
+ #
15
+ # Tap::Task.batch(t1, t2)
16
+ # t3.batch # => [t1,t2,t3]
17
+ #
18
+ # Returns the new batch.
19
+ def batch(*batchables)
20
+ merged = []
21
+ batches = batchables.collect {|batchable| batchable.batch }.uniq
22
+ batches.each do |batch|
23
+ merged.concat(batch)
24
+ batch.clear
25
+ end
26
+ merged.uniq!
27
+ batches.each {|batch| batch.concat(merged) }
28
+ merged
29
+ end
30
+
31
+ protected
32
+
33
+ # Redefines the specified method(s) as batched methods. The existing method
34
+ # is renamed as <tt>unbatched_method</tt> and <tt>method</tt> redefined to
35
+ # call <tt>unbatched_method</tt> on each object in the batch.
36
+ #
37
+ # def process(one, two)
38
+ # ...
39
+ # end
40
+ # batch_function(:process)
41
+ #
42
+ # Is equivalent to:
43
+ #
44
+ # def unbatched_process(one, two)
45
+ # ...
46
+ # end
47
+ #
48
+ # def process(one, two)
49
+ # batch.each do |t|
50
+ # t.unbatched_process(one, two)
51
+ # end
52
+ # self
53
+ # end
54
+ #
55
+ # The batched method will accept/pass as many arguments as are defined for
56
+ # the unbatched method. Splats are supported, and blocks are supported too
57
+ # by passing a block to batch_function:
58
+ #
59
+ # def process(arg, *args, &block)
60
+ # ...
61
+ # end
62
+ # batch_function(:process) {}
63
+ #
64
+ # Is equivalent to:
65
+ #
66
+ # def unbatched_process(arg, *args, &block)
67
+ # ...
68
+ # end
69
+ #
70
+ # def process(*args, &block)
71
+ # batch.each do |t|
72
+ # t.unbatched_process(*args, &block)
73
+ # end
74
+ # self
75
+ # end
76
+ #
77
+ # Obviously there are limitations to batch_function, most notably batching
78
+ # functions with default values. In these cases, batch functionality
79
+ # must be implemented manually.
80
+ def batch_function(*methods)
81
+ methods.each do |method_name|
82
+ unbatched_method = "unbatched_#{method_name}"
83
+ if method_defined?(unbatched_method)
84
+ raise "unbatched method already defined: #{unbatched_method}"
85
+ end
86
+
87
+ arity = instance_method(method_name).arity
88
+ args = case
89
+ when arity < 0 then "*args"
90
+ else Array.new(arity) {|index| "arg#{index}" }.join(", ")
91
+ end
92
+ args += ", &block" if block_given?
93
+
94
+ class_eval %Q{
95
+ alias #{unbatched_method} #{method_name}
96
+ def #{method_name}(#{args})
97
+ batch.each do |t|
98
+ t.#{unbatched_method}(#{args})
99
+ end
100
+ self
101
+ end
102
+ }
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end