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.
- data/History +37 -30
- data/MIT-LICENSE +1 -1
- data/README +92 -44
- data/bin/tap +62 -75
- data/cmd/console.rb +42 -0
- data/cmd/destroy.rb +16 -0
- data/cmd/generate.rb +16 -0
- data/cmd/run.rb +126 -0
- data/doc/Class Reference +362 -0
- data/doc/Command Reference +153 -0
- data/doc/Tutorial +237 -0
- data/lib/tap.rb +6 -45
- data/lib/tap/app.rb +126 -500
- data/lib/tap/constants.rb +2 -29
- data/lib/tap/env.rb +555 -250
- data/lib/tap/file_task.rb +60 -103
- data/lib/tap/generator/base.rb +109 -0
- data/lib/tap/generator/destroy.rb +37 -0
- data/lib/tap/generator/generate.rb +61 -0
- data/lib/tap/generator/generators/command/command_generator.rb +16 -12
- data/lib/tap/generator/generators/command/templates/command.erb +13 -19
- data/lib/tap/generator/generators/config/config_generator.rb +18 -27
- data/lib/tap/generator/generators/config/templates/doc.erb +12 -0
- data/lib/tap/generator/generators/config/templates/nodoc.erb +8 -0
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -11
- data/lib/tap/generator/generators/file_task/templates/file.txt +11 -2
- data/lib/tap/generator/generators/file_task/templates/result.yml +6 -0
- data/lib/tap/generator/generators/file_task/templates/task.erb +24 -31
- data/lib/tap/generator/generators/file_task/templates/test.erb +18 -22
- data/lib/tap/generator/generators/root/root_generator.rb +45 -31
- data/lib/tap/generator/generators/root/templates/Rakefile +64 -41
- data/lib/tap/generator/generators/root/templates/gemspec +27 -0
- data/lib/tap/generator/generators/root/templates/tapfile +8 -0
- data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -0
- data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
- data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +15 -0
- data/lib/tap/generator/generators/task/task_generator.rb +21 -28
- data/lib/tap/generator/generators/task/templates/task.erb +13 -23
- data/lib/tap/generator/generators/task/templates/test.erb +15 -18
- data/lib/tap/generator/manifest.rb +14 -0
- data/lib/tap/patches/rake/rake_test_loader.rb +0 -0
- data/lib/tap/patches/rake/testtask.rb +0 -0
- data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -0
- data/lib/tap/patches/ruby19/parsedate.rb +0 -0
- data/lib/tap/root.rb +260 -21
- data/lib/tap/support/aggregator.rb +11 -11
- data/lib/tap/support/assignments.rb +172 -0
- data/lib/tap/support/audit.rb +20 -18
- data/lib/tap/support/batchable.rb +21 -10
- data/lib/tap/support/batchable_class.rb +107 -0
- data/lib/tap/support/class_configuration.rb +154 -239
- data/lib/tap/support/command_line.rb +97 -102
- data/lib/tap/support/comment.rb +270 -0
- data/lib/tap/support/configurable.rb +86 -65
- data/lib/tap/support/configurable_class.rb +296 -0
- data/lib/tap/support/configuration.rb +122 -0
- data/lib/tap/support/constant.rb +70 -0
- data/lib/tap/support/constant_utils.rb +127 -0
- data/lib/tap/support/declarations.rb +111 -0
- data/lib/tap/support/executable.rb +30 -17
- data/lib/tap/support/executable_queue.rb +0 -0
- data/lib/tap/support/framework.rb +71 -0
- data/lib/tap/support/framework_class.rb +199 -0
- data/lib/tap/support/instance_configuration.rb +147 -0
- data/lib/tap/support/lazydoc.rb +428 -0
- data/lib/tap/support/manifest.rb +89 -0
- data/lib/tap/support/run_error.rb +0 -0
- data/lib/tap/support/shell_utils.rb +33 -9
- data/lib/tap/support/summary.rb +30 -0
- data/lib/tap/support/tdoc.rb +339 -134
- data/lib/tap/support/tdoc/tdoc_html_generator.rb +0 -0
- data/lib/tap/support/tdoc/tdoc_html_template.rb +0 -0
- data/lib/tap/support/templater.rb +180 -0
- data/lib/tap/support/validation.rb +409 -76
- data/lib/tap/support/versions.rb +5 -3
- data/lib/tap/task.rb +78 -174
- data/lib/tap/tasks/dump.rb +56 -0
- data/lib/tap/tasks/rake.rb +93 -0
- data/lib/tap/test.rb +3 -3
- data/lib/tap/test/env_vars.rb +2 -2
- data/lib/tap/test/file_methods.rb +19 -20
- data/lib/tap/test/script_methods.rb +144 -0
- data/lib/tap/test/subset_methods.rb +1 -1
- data/lib/tap/test/tap_methods.rb +28 -62
- data/lib/tap/workflow.rb +22 -39
- metadata +48 -179
- data/Basic Overview +0 -151
- data/Command Reference +0 -99
- data/Rakefile +0 -127
- data/Tutorial +0 -287
- data/lib/tap/cmd/console.rb +0 -31
- data/lib/tap/cmd/destroy.rb +0 -20
- data/lib/tap/cmd/generate.rb +0 -20
- data/lib/tap/cmd/run.rb +0 -151
- data/lib/tap/dump.rb +0 -57
- data/lib/tap/generator.rb +0 -91
- data/lib/tap/generator/generators/command/USAGE +0 -6
- data/lib/tap/generator/generators/config/USAGE +0 -21
- data/lib/tap/generator/generators/config/templates/config.erb +0 -1
- data/lib/tap/generator/generators/file_task/USAGE +0 -3
- data/lib/tap/generator/generators/file_task/templates/file.yml +0 -3
- data/lib/tap/generator/generators/generator/USAGE +0 -0
- data/lib/tap/generator/generators/generator/generator_generator.rb +0 -21
- data/lib/tap/generator/generators/generator/templates/generator.erb +0 -32
- data/lib/tap/generator/generators/generator/templates/usage.erb +0 -1
- data/lib/tap/generator/generators/root/USAGE +0 -0
- data/lib/tap/generator/generators/root/templates/ReadMe.txt +0 -0
- data/lib/tap/generator/generators/root/templates/tap.yml +0 -80
- data/lib/tap/generator/generators/task/USAGE +0 -3
- data/lib/tap/generator/generators/workflow/USAGE +0 -0
- data/lib/tap/generator/generators/workflow/templates/task.erb +0 -16
- data/lib/tap/generator/generators/workflow/templates/test.erb +0 -7
- data/lib/tap/generator/generators/workflow/workflow_generator.rb +0 -6
- data/lib/tap/generator/options.rb +0 -26
- data/lib/tap/generator/usage.rb +0 -26
- data/lib/tap/support/batchable_methods.rb +0 -34
- data/lib/tap/support/command_line_methods.rb +0 -76
- data/lib/tap/support/configurable_methods.rb +0 -224
- data/lib/tap/support/logger.rb +0 -88
- data/lib/tap/support/rake.rb +0 -43
- data/lib/tap/support/tdoc/config_attr.rb +0 -362
- data/test/app/config/another/task.yml +0 -1
- data/test/app/config/batch.yml +0 -2
- data/test/app/config/empty.yml +0 -0
- data/test/app/config/erb.yml +0 -2
- data/test/app/config/some/task.yml +0 -1
- data/test/app/config/template.yml +0 -2
- data/test/app/config/version-0.1.yml +0 -1
- data/test/app/config/version.yml +0 -1
- data/test/app/lib/app_test_task.rb +0 -3
- data/test/app_test.rb +0 -1849
- data/test/env/test_configure/recurse_a.yml +0 -2
- data/test/env/test_configure/recurse_b.yml +0 -2
- data/test/env/test_configure/tap.yml +0 -23
- data/test/env/test_load_env_config/dir/tap.yml +0 -3
- data/test/env/test_load_env_config/recurse_a.yml +0 -2
- data/test/env/test_load_env_config/recurse_b.yml +0 -2
- data/test/env/test_load_env_config/tap.yml +0 -3
- data/test/env_test.rb +0 -198
- data/test/file_task/config/batch.yml +0 -2
- data/test/file_task/config/configured.yml +0 -1
- data/test/file_task/old_file_one.txt +0 -0
- data/test/file_task/old_file_two.txt +0 -0
- data/test/file_task_test.rb +0 -1291
- data/test/root/alt_lib/alt_module.rb +0 -4
- data/test/root/file.txt +0 -0
- data/test/root/glob/one.txt +0 -0
- data/test/root/glob/two.txt +0 -0
- data/test/root/lib/absolute_alt_filepath.rb +0 -2
- data/test/root/lib/alternative_filepath.rb +0 -2
- data/test/root/lib/another_module.rb +0 -2
- data/test/root/lib/nested/some_module.rb +0 -4
- data/test/root/lib/no_module_included.rb +0 -0
- data/test/root/lib/some/module.rb +0 -4
- data/test/root/lib/some_class.rb +0 -2
- data/test/root/lib/some_module.rb +0 -3
- data/test/root/load_path/load_path_module.rb +0 -2
- data/test/root/load_path/skip_module.rb +0 -2
- data/test/root/mtime/older.txt +0 -0
- data/test/root/unload/full_path.rb +0 -2
- data/test/root/unload/loaded_by_nested.rb +0 -2
- data/test/root/unload/nested/nested_load.rb +0 -6
- data/test/root/unload/nested/nested_with_ext.rb +0 -4
- data/test/root/unload/nested/relative_path.rb +0 -4
- data/test/root/unload/older.rb +0 -2
- data/test/root/unload/unload_base.rb +0 -9
- data/test/root/versions/another.yml +0 -0
- data/test/root/versions/file-0.1.2.yml +0 -0
- data/test/root/versions/file-0.1.yml +0 -0
- data/test/root/versions/file.yml +0 -0
- data/test/root_test.rb +0 -718
- data/test/support/aggregator_test.rb +0 -99
- data/test/support/audit_test.rb +0 -445
- data/test/support/batchable_test.rb +0 -74
- data/test/support/class_configuration_test.rb +0 -331
- data/test/support/command_line_test.rb +0 -58
- data/test/support/configurable/config/configured.yml +0 -2
- data/test/support/configurable_test.rb +0 -295
- data/test/support/executable_queue_test.rb +0 -103
- data/test/support/executable_test.rb +0 -38
- data/test/support/logger_test.rb +0 -31
- data/test/support/rake_test.rb +0 -37
- data/test/support/shell_utils_test.rb +0 -24
- data/test/support/tdoc_test.rb +0 -370
- data/test/support/validation_test.rb +0 -54
- data/test/support/versions_test.rb +0 -103
- data/test/tap_test_helper.rb +0 -57
- data/test/tap_test_suite.rb +0 -7
- data/test/task/config/batch.yml +0 -2
- data/test/task/config/batched.yml +0 -2
- data/test/task/config/configured.yml +0 -1
- data/test/task/config/example.yml +0 -1
- data/test/task_base_test.rb +0 -24
- data/test/task_syntax_test.rb +0 -300
- data/test/task_test.rb +0 -320
- data/test/test/env_vars_test.rb +0 -48
- data/test/test/file_methods/test_assert_files/expected/one.txt +0 -1
- data/test/test/file_methods/test_assert_files/expected/two.txt +0 -1
- data/test/test/file_methods/test_assert_files/input/one.txt +0 -1
- data/test/test/file_methods/test_assert_files/input/two.txt +0 -1
- data/test/test/file_methods/test_assert_files_can_have_no_expected_files_if_specified/input/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_can_have_no_expected_files_if_specified/input/two.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/two.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/expected/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +0 -1
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +0 -1
- data/test/test/file_methods/test_method_glob/expected/file.yml +0 -0
- data/test/test/file_methods/test_method_glob/expected/file_1.txt +0 -0
- data/test/test/file_methods/test_method_glob/expected/file_2.txt +0 -0
- data/test/test/file_methods_doc/test_sub/expected/one.txt +0 -1
- data/test/test/file_methods_doc/test_sub/expected/two.txt +0 -1
- data/test/test/file_methods_doc/test_sub/input/one.txt +0 -1
- data/test/test/file_methods_doc/test_sub/input/two.txt +0 -1
- data/test/test/file_methods_doc_test.rb +0 -29
- data/test/test/file_methods_test.rb +0 -275
- data/test/test/subset_methods_test.rb +0 -171
- data/test/test/tap_methods/test_assert_files/expected/task/name/a.txt +0 -1
- data/test/test/tap_methods/test_assert_files/expected/task/name/b.txt +0 -1
- data/test/test/tap_methods/test_assert_files/input/a.txt +0 -1
- data/test/test/tap_methods/test_assert_files/input/b.txt +0 -1
- data/test/test/tap_methods_test.rb +0 -399
- data/test/workflow_test.rb +0 -120
- data/vendor/rails_generator.rb +0 -56
- data/vendor/rails_generator/base.rb +0 -263
- data/vendor/rails_generator/commands.rb +0 -581
- data/vendor/rails_generator/generated_attribute.rb +0 -42
- data/vendor/rails_generator/lookup.rb +0 -209
- data/vendor/rails_generator/manifest.rb +0 -53
- data/vendor/rails_generator/options.rb +0 -143
- data/vendor/rails_generator/scripts.rb +0 -83
- data/vendor/rails_generator/scripts/destroy.rb +0 -7
- data/vendor/rails_generator/scripts/generate.rb +0 -7
- data/vendor/rails_generator/scripts/update.rb +0 -12
- data/vendor/rails_generator/simple_logger.rb +0 -46
- 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
|
data/lib/tap/support/audit.rb
CHANGED
|
@@ -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
|
|
35
|
-
#
|
|
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)
|
|
41
|
-
#
|
|
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
|
|
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
|
|
66
|
-
# source, and an array of the merging values as the
|
|
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
|
-
#
|
|
124
|
-
# of
|
|
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
|
-
|
|
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.
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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
|
-
|
|
14
|
+
|
|
15
|
+
def self.included(mod)
|
|
16
|
+
mod.extend Support::BatchableClass if mod.kind_of?(Class)
|
|
17
|
+
end
|
|
10
18
|
|
|
11
|
-
# The object batch.
|
|
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
|
|
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 =
|
|
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
|