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.
- data/MIT-LICENSE +0 -2
- data/README +20 -31
- data/bin/rap +18 -8
- data/cgi/run.rb +47 -37
- data/cmd/console.rb +1 -1
- data/cmd/destroy.rb +3 -3
- data/cmd/generate.rb +3 -3
- data/cmd/manifest.rb +61 -53
- data/cmd/run.rb +1 -1
- data/doc/Class Reference +119 -110
- data/doc/Command Reference +76 -123
- data/doc/Syntax Reference +290 -0
- data/doc/Tutorial +307 -237
- data/lib/tap.rb +1 -12
- data/lib/tap/app.rb +46 -71
- data/lib/tap/constants.rb +1 -1
- data/lib/tap/declarations.rb +110 -100
- data/lib/tap/env.rb +141 -173
- data/lib/tap/exe.rb +5 -5
- data/lib/tap/file_task.rb +2 -2
- data/lib/tap/generator/base.rb +0 -4
- data/lib/tap/generator/destroy.rb +8 -12
- data/lib/tap/generator/generate.rb +19 -14
- data/lib/tap/generator/generators/command/command_generator.rb +1 -1
- data/lib/tap/generator/generators/config/config_generator.rb +3 -3
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
- data/lib/tap/generator/generators/generator/generator_generator.rb +27 -0
- data/lib/tap/generator/generators/generator/templates/task.erb +27 -0
- data/lib/tap/generator/generators/root/root_generator.rb +12 -12
- data/lib/tap/generator/generators/root/templates/Rakefile +1 -2
- data/lib/tap/generator/generators/root/templates/tapfile +11 -8
- data/lib/tap/generator/generators/task/task_generator.rb +1 -3
- data/lib/tap/generator/generators/task/templates/test.erb +1 -3
- data/lib/tap/root.rb +4 -2
- data/lib/tap/support/aggregator.rb +16 -3
- data/lib/tap/support/assignments.rb +10 -9
- data/lib/tap/support/audit.rb +58 -62
- data/lib/tap/support/class_configuration.rb +32 -43
- data/lib/tap/support/combinator.rb +7 -7
- data/lib/tap/support/configurable.rb +13 -14
- data/lib/tap/support/configurable_class.rb +6 -30
- data/lib/tap/support/configuration.rb +36 -9
- data/lib/tap/support/constant.rb +75 -13
- data/lib/tap/support/constant_manifest.rb +115 -0
- data/lib/tap/support/dependencies.rb +27 -67
- data/lib/tap/support/dependency.rb +44 -0
- data/lib/tap/support/executable.rb +78 -109
- data/lib/tap/support/executable_queue.rb +1 -1
- data/lib/tap/support/gems.rb +6 -0
- data/lib/tap/support/gems/rack.rb +197 -84
- data/lib/tap/support/instance_configuration.rb +29 -3
- data/lib/tap/support/intern.rb +46 -0
- data/lib/tap/support/join.rb +67 -11
- data/lib/tap/support/joins.rb +2 -0
- data/lib/tap/support/joins/fork.rb +1 -0
- data/lib/tap/support/joins/merge.rb +3 -1
- data/lib/tap/support/joins/sequence.rb +2 -2
- data/lib/tap/support/joins/switch.rb +3 -1
- data/lib/tap/support/joins/sync_merge.rb +6 -0
- data/lib/tap/support/lazy_attributes.rb +16 -1
- data/lib/tap/support/lazydoc.rb +21 -21
- data/lib/tap/support/lazydoc/comment.rb +59 -55
- data/lib/tap/support/lazydoc/definition.rb +36 -0
- data/lib/tap/support/lazydoc/document.rb +37 -13
- data/lib/tap/support/manifest.rb +120 -131
- data/lib/tap/support/minimap.rb +90 -0
- data/lib/tap/support/node.rb +4 -6
- data/lib/tap/support/parser.rb +63 -6
- data/lib/tap/support/schema.rb +11 -2
- data/lib/tap/support/shell_utils.rb +3 -5
- data/lib/tap/support/string_ext.rb +60 -0
- data/lib/tap/support/tdoc.rb +2 -2
- data/lib/tap/support/templater.rb +29 -15
- data/lib/tap/support/validation.rb +22 -11
- data/lib/tap/task.rb +155 -156
- data/lib/tap/tasks/load.rb +95 -8
- data/lib/tap/test/extensions.rb +2 -1
- data/lib/tap/test/script_tester.rb +7 -1
- data/template/index.erb +39 -32
- metadata +13 -13
- data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +0 -15
- data/lib/tap/patches/rake/rake_test_loader.rb +0 -8
- data/lib/tap/patches/rake/testtask.rb +0 -57
- data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -51
- data/lib/tap/patches/ruby19/parsedate.rb +0 -16
- data/lib/tap/spec.rb +0 -42
- data/lib/tap/spec/adapter.rb +0 -25
- data/lib/tap/spec/inheritable_class_test_root.rb +0 -9
- data/lib/tap/support/constant_utils.rb +0 -127
- data/lib/tap/support/summary.rb +0 -30
@@ -21,18 +21,14 @@ module Tap
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def file(target, options={})
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
log_relative :
|
32
|
-
file_task.added_files << File.expand_path(target)
|
33
|
-
file_task.rm(target) unless pretend
|
34
|
-
else
|
35
|
-
log_relative :missing, target
|
24
|
+
target = File.expand_path(target, target_dir)
|
25
|
+
|
26
|
+
if File.exists?(target)
|
27
|
+
log_relative :rm, target
|
28
|
+
file_task.added_files << File.expand_path(target)
|
29
|
+
file_task.rm(target) unless pretend
|
30
|
+
else
|
31
|
+
log_relative :missing, target
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
@@ -16,31 +16,36 @@ module Tap
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def file(target, options={})
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def prepare(target, options={})
|
19
|
+
def file(target, options={})
|
20
|
+
source_file = Tempfile.new('generate')
|
21
|
+
yield(source_file) if block_given?
|
22
|
+
source_file.close
|
23
|
+
|
24
|
+
source = source_file.path
|
26
25
|
target = File.expand_path(target, target_dir)
|
27
26
|
|
28
|
-
case
|
27
|
+
copy_file = case
|
29
28
|
when !File.exists?(target)
|
30
29
|
log_relative :create, target
|
31
|
-
|
30
|
+
true
|
31
|
+
when FileUtils.cmp(source, target)
|
32
|
+
log_relative :exists, target
|
33
|
+
false
|
32
34
|
when force_file_collision?(target)
|
33
35
|
log_relative :force, target
|
36
|
+
true
|
34
37
|
else
|
35
38
|
log_relative :skip, target
|
36
|
-
|
39
|
+
false
|
37
40
|
end
|
38
41
|
|
39
|
-
|
42
|
+
if copy_file && !pretend
|
40
43
|
file_task.prepare(target)
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
44
|
+
FileUtils.mv(source, target)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
44
49
|
|
45
50
|
# Ask the user interactively whether to force collision.
|
46
51
|
def force_file_collision?(target)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Tap::Generator::Generators
|
2
2
|
|
3
|
-
#
|
3
|
+
# Tap::Generator::Generators::CommandGenerator::generator a new tap command
|
4
4
|
#
|
5
5
|
# Generates a new tap command under the cmd directory. The
|
6
6
|
# new command can be run from the command line using:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Tap::Generator::Generators
|
2
2
|
|
3
|
-
#
|
3
|
+
# Tap::Generator::Generators::ConfigGenerator::generator a config file for a task
|
4
4
|
#
|
5
5
|
# Generates a new config file for a task. The configurations, defaults,
|
6
6
|
# and documentation is determined from the task source file.
|
@@ -13,12 +13,12 @@ module Tap::Generator::Generators
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def manifest(m, name, config_name=name)
|
16
|
-
const = env.search(
|
16
|
+
const = env.tasks.search(name) or raise "unknown task: #{name}"
|
17
17
|
task_class = const.constantize or raise "unknown task: #{name}"
|
18
18
|
|
19
19
|
m.directory app['config']
|
20
20
|
m.file app.filepath('config', config_name + '.yml') do |file|
|
21
|
-
task_class.configurations.
|
21
|
+
task_class.configurations.inspect((doc ? :doc : :nodoc), file)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -2,7 +2,7 @@ require 'tap/generator/generators/task/task_generator'
|
|
2
2
|
|
3
3
|
module Tap::Generator::Generators
|
4
4
|
|
5
|
-
#
|
5
|
+
# Tap::Generator::Generators::FileTaskGenerator::generator a file_task and test
|
6
6
|
#
|
7
7
|
# Generates a new Tap::FileTask and associated test files.
|
8
8
|
class FileTaskGenerator < TaskGenerator
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Tap::Generator::Generators
|
2
|
+
|
3
|
+
# Tap::Generator::Generators::GeneratorGenerator::generator a generator task and test
|
4
|
+
#
|
5
|
+
# Generates a new generator.
|
6
|
+
class GeneratorGenerator < Tap::Generator::Base
|
7
|
+
|
8
|
+
def manifest(m, const_name)
|
9
|
+
const = Constant.new(const_name.camelize)
|
10
|
+
dir= File.join('lib', const.path)
|
11
|
+
|
12
|
+
# make the directory
|
13
|
+
m.directory app.filepath(dir)
|
14
|
+
|
15
|
+
# make the generator
|
16
|
+
m.template app.filepath(dir, const.basename + '_generator.rb'), "task.erb", :const => const
|
17
|
+
|
18
|
+
# make the templates directory
|
19
|
+
m.directory app.filepath(dir, 'templates')
|
20
|
+
m.file app.filepath(dir, 'templates', 'template_file.erb') do |file|
|
21
|
+
file.puts "# A sample template file."
|
22
|
+
file.puts "key: <%= key %>"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<% redirect do |target| %># <%= const.name %>::generator <replace with manifest summary>
|
2
|
+
# <replace with command line description>
|
3
|
+
|
4
|
+
# <%= const.const_name %> Documentation
|
5
|
+
class <%= const.const_name %> < Tap::Generator::Base
|
6
|
+
|
7
|
+
config :key, 'value' # a sample config
|
8
|
+
|
9
|
+
# The generator will receive the inputs on the command line, and
|
10
|
+
# m, a Manifest object that records the actions of this method.
|
11
|
+
def manifest(m, *inputs)
|
12
|
+
|
13
|
+
# make a directory
|
14
|
+
# m.directory path
|
15
|
+
|
16
|
+
# make a file
|
17
|
+
# m.file path do |file|
|
18
|
+
# file << contents
|
19
|
+
# end
|
20
|
+
|
21
|
+
# template a file in the templates directory using ERB.
|
22
|
+
# The (key, value) pairs will be available in the
|
23
|
+
# template as local variables.
|
24
|
+
m.template "<%= const.const_name.underscore %>_file.txt", "template_file.erb", :key => 'value'
|
25
|
+
|
26
|
+
end
|
27
|
+
end <% module_nest(const.nesting, ' ') { target } end %>
|
@@ -2,17 +2,17 @@ require 'tap/root'
|
|
2
2
|
|
3
3
|
module Tap::Generator::Generators
|
4
4
|
|
5
|
-
#
|
5
|
+
# Tap::Generator::Generators::RootGenerator::generator a basic tap directory structure
|
6
6
|
#
|
7
7
|
# Generates a tap root directory structure. Use the switches to
|
8
|
-
# generate a
|
8
|
+
# generate a Tapfile and/or a tap config file:
|
9
9
|
#
|
10
10
|
# root
|
11
11
|
# |- Rakefile
|
12
12
|
# |- lib
|
13
13
|
# |- sample.gemspec
|
14
14
|
# |- tap.yml
|
15
|
-
# |-
|
15
|
+
# |- Tapfile
|
16
16
|
# `- test
|
17
17
|
# |- tap_test_helper.rb
|
18
18
|
# |- tap_test_suite.rb
|
@@ -20,8 +20,8 @@ module Tap::Generator::Generators
|
|
20
20
|
#
|
21
21
|
class RootGenerator < Tap::Generator::Base
|
22
22
|
|
23
|
-
config :config_file,
|
24
|
-
config :tapfile, false, &c.switch
|
23
|
+
config :config_file, true, &c.switch # create a tap.yml file
|
24
|
+
config :tapfile, false, &c.switch # create a tapfile
|
25
25
|
|
26
26
|
# ::args ROOT, PROJECT_NAME=basename(ROOT)
|
27
27
|
def manifest(m, root, project_name=nil)
|
@@ -35,26 +35,26 @@ module Tap::Generator::Generators
|
|
35
35
|
case
|
36
36
|
when File.directory?(source)
|
37
37
|
m.directory r[target]
|
38
|
+
next
|
38
39
|
when target == 'gemspec'
|
39
40
|
m.template r[project_name + '.gemspec'], source, :project_name => project_name, :tapfile => tapfile, :config_file => config_file
|
40
|
-
|
41
|
+
next
|
42
|
+
when target =~ /tapfile/i
|
41
43
|
next unless tapfile
|
42
|
-
target = (target == 'tapfile' ? r['tapfile.rb'] : r[target])
|
43
|
-
m.template target, source, :project_name => project_name
|
44
|
-
else
|
45
|
-
m.template r[target], source, :project_name => project_name
|
46
44
|
end
|
45
|
+
|
46
|
+
m.template r[target], source, :project_name => project_name
|
47
47
|
end
|
48
48
|
|
49
49
|
m.file(r['tap.yml']) do |file|
|
50
|
-
Tap::App.configurations.
|
50
|
+
Tap::App.configurations.inspect(:doc, file) do |templater|
|
51
51
|
next unless templater.receiver == Tap::Root
|
52
52
|
|
53
53
|
templater.configurations.each do |(key, config)|
|
54
54
|
config.default = nil if key.to_s == 'root'
|
55
55
|
end
|
56
56
|
end
|
57
|
-
Tap::Env.configurations.
|
57
|
+
Tap::Env.configurations.inspect(:doc, file)
|
58
58
|
end if config_file
|
59
59
|
end
|
60
60
|
end
|
@@ -4,7 +4,6 @@ require 'rake/rdoctask'
|
|
4
4
|
require 'rake/gempackagetask'
|
5
5
|
|
6
6
|
require 'tap/constants'
|
7
|
-
require 'tap/patches/rake/testtask.rb'
|
8
7
|
|
9
8
|
#
|
10
9
|
# Gem specification
|
@@ -36,7 +35,7 @@ task :print_manifest do
|
|
36
35
|
# included already (marking by the absence
|
37
36
|
# of a label)
|
38
37
|
Dir.glob("**/*").each do |file|
|
39
|
-
next if file =~ /^(rdoc|pkg)/ || File.directory?(file)
|
38
|
+
next if file =~ /^(rdoc|pkg|backup)/ || File.directory?(file)
|
40
39
|
|
41
40
|
path = File.expand_path(file)
|
42
41
|
files[path] = ["", file] unless files.has_key?(path)
|
@@ -1,8 +1,11 @@
|
|
1
|
-
require 'tap'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
require 'tap/declarations'
|
2
|
+
|
3
|
+
module <%= project_name.camelize %>
|
4
|
+
extend Tap::Declarations
|
5
|
+
|
6
|
+
# ::desc your basic goodnight moon task
|
7
|
+
# Says goodnight with a configurable message.
|
8
|
+
task(:goodnight, :obj, :message => 'goodnight') do |task, args|
|
9
|
+
puts "#{task.message} #{args.obj}"
|
10
|
+
end
|
11
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Tap::Generator::Generators
|
2
2
|
|
3
|
-
#
|
3
|
+
# Tap::Generator::Generators::TaskGenerator::generator a task and test
|
4
4
|
#
|
5
5
|
# Generates a new Tap::Task and an associated test file.
|
6
6
|
class TaskGenerator < Tap::Generator::Base
|
@@ -19,8 +19,6 @@ module Tap::Generator::Generators
|
|
19
19
|
m.directory File.dirname(test_path)
|
20
20
|
m.template test_path, "test.erb", :const => const
|
21
21
|
end
|
22
|
-
|
23
|
-
const
|
24
22
|
end
|
25
23
|
|
26
24
|
end
|
@@ -12,9 +12,7 @@ class <%= const.name %>Test < Test::Unit::TestCase
|
|
12
12
|
assert_equal "goodnight moon", task.process("moon")
|
13
13
|
|
14
14
|
# a more complex test
|
15
|
-
task.
|
16
|
-
app.run
|
17
|
-
|
15
|
+
task.execute("moon")
|
18
16
|
assert_equal ["goodnight moon"], app.results(task)
|
19
17
|
assert_audit_equal ExpAudit[[nil, "moon"], [task, "goodnight moon"]], app._results(task)[0]
|
20
18
|
end
|
data/lib/tap/root.rb
CHANGED
@@ -126,11 +126,13 @@ module Tap
|
|
126
126
|
# mkdir is specified. chdir raises an error for non-existant
|
127
127
|
# directories, as well as non-directory inputs.
|
128
128
|
def chdir(dir, mkdir=false, &block)
|
129
|
+
dir = File.expand_path(dir)
|
130
|
+
|
129
131
|
unless File.directory?(dir)
|
130
132
|
if !File.exists?(dir) && mkdir
|
131
133
|
FileUtils.mkdir_p(dir)
|
132
134
|
else
|
133
|
-
raise "not a directory: #{dir}"
|
135
|
+
raise ArgumentError, "not a directory: #{dir}"
|
134
136
|
end
|
135
137
|
end
|
136
138
|
|
@@ -264,7 +266,7 @@ module Tap
|
|
264
266
|
end.compact
|
265
267
|
end
|
266
268
|
end
|
267
|
-
|
269
|
+
|
268
270
|
# Returns true if the mini_path matches path. Matching logic
|
269
271
|
# reverses that of minimize:
|
270
272
|
# * a match occurs when path ends with mini_path
|
@@ -2,9 +2,22 @@ module Tap
|
|
2
2
|
module Support
|
3
3
|
|
4
4
|
# Aggregator allows thread-safe collection of Audits, organized
|
5
|
-
# by Audit#_current_source.
|
5
|
+
# by Audit#_current_source.
|
6
|
+
#
|
7
|
+
# a = Audit.new
|
8
|
+
# a._record(:src, 'a')
|
9
|
+
#
|
10
|
+
# b = Audit.new
|
11
|
+
# b._record(:src, 'b')
|
12
|
+
#
|
13
|
+
# agg = Aggregator.new
|
14
|
+
# agg.store(a)
|
15
|
+
# agg.store(b)
|
16
|
+
# agg.retrieve(:src) # => [a, b]
|
17
|
+
#
|
6
18
|
class Aggregator < Monitor
|
7
|
-
|
19
|
+
|
20
|
+
# Creates a new Aggregator.
|
8
21
|
def initialize
|
9
22
|
super
|
10
23
|
clear
|
@@ -35,7 +48,7 @@ module Tap
|
|
35
48
|
synchronize { hash[source] }
|
36
49
|
end
|
37
50
|
|
38
|
-
# Retreives all audits for the input sources, joined
|
51
|
+
# Retreives all audits for the input sources, joined as an array.
|
39
52
|
def retrieve_all(*sources)
|
40
53
|
synchronize do
|
41
54
|
sources.collect {|src| hash[src] }.flatten.compact
|
@@ -5,14 +5,12 @@ module Tap
|
|
5
5
|
# which values are assigned to a particular key. A value may only
|
6
6
|
# be assigned to one key at a time.
|
7
7
|
#
|
8
|
-
# Assignments tracks the order
|
8
|
+
# Assignments tracks the order of key declaration, and the
|
9
9
|
# order in which values are assigned to a key. This behavior is
|
10
|
-
# used by ClassConfiguration to track the order
|
11
|
-
#
|
10
|
+
# used by ClassConfiguration to track the order of configurations
|
11
|
+
# in a class; the order, in turn, is used in the formation
|
12
12
|
# of config files, command line documentation, etc.
|
13
13
|
#
|
14
|
-
# === Example
|
15
|
-
#
|
16
14
|
# a = Assignments.new
|
17
15
|
# a.assign(:one, 'one')
|
18
16
|
# a.assign(:two, 'two')
|
@@ -35,6 +33,9 @@ module Tap
|
|
35
33
|
class Assignments
|
36
34
|
include Enumerable
|
37
35
|
|
36
|
+
# Generates a new Assignments using the parent array of
|
37
|
+
# [key, values] pairs. Uses parent.array if parent is
|
38
|
+
# an Assignments, or [] if parent is nil.
|
38
39
|
def initialize(parent=nil)
|
39
40
|
existing_array = case parent
|
40
41
|
when Assignments then parent.array
|
@@ -139,7 +140,7 @@ module Tap
|
|
139
140
|
nil
|
140
141
|
end
|
141
142
|
|
142
|
-
# Yields each key, value pair in the order in which
|
143
|
+
# Yields each [key, value] pair in the order in which
|
143
144
|
# the keys were declared. Keys with no values are
|
144
145
|
# skipped.
|
145
146
|
def each
|
@@ -148,7 +149,7 @@ module Tap
|
|
148
149
|
end
|
149
150
|
end
|
150
151
|
|
151
|
-
# Yields each key, values pair in the order in which
|
152
|
+
# Yields each [key, values] pair in the order in which
|
152
153
|
# the keys were declared.
|
153
154
|
def each_pair
|
154
155
|
array.each do |key, values|
|
@@ -156,7 +157,7 @@ module Tap
|
|
156
157
|
end
|
157
158
|
end
|
158
159
|
|
159
|
-
# Returns
|
160
|
+
# Returns self as an array
|
160
161
|
def to_a
|
161
162
|
array.collect {|key, values| [key, values.dup] }
|
162
163
|
end
|
@@ -164,7 +165,7 @@ module Tap
|
|
164
165
|
protected
|
165
166
|
|
166
167
|
# An array of [key, values] arrays tracking the
|
167
|
-
#
|
168
|
+
# order in which values are assigned.
|
168
169
|
attr_reader :array
|
169
170
|
|
170
171
|
end
|
data/lib/tap/support/audit.rb
CHANGED
@@ -3,43 +3,41 @@ module Tap
|
|
3
3
|
|
4
4
|
# Marks the merge of multiple Audit trails
|
5
5
|
class AuditMerge < Array
|
6
|
+
|
7
|
+
# True if another is an AuditMerge and passes Array#==
|
6
8
|
def ==(another)
|
7
9
|
another.kind_of?(AuditMerge) && super
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
|
-
# Marks a split in an Audit trail
|
12
|
-
class AuditSplit
|
13
|
-
attr_reader :block
|
14
|
-
def initialize(block) @block = block end
|
15
|
-
|
16
|
-
def ==(another)
|
17
|
-
another.kind_of?(AuditSplit) && another.block == block
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
13
|
# Marks the expansion of an Audit trail
|
22
|
-
class
|
14
|
+
class AuditIterate
|
23
15
|
attr_reader :index
|
24
16
|
def initialize(index) @index = index end
|
25
|
-
|
17
|
+
|
18
|
+
# True if another is an AuditIterate with the same index.
|
26
19
|
def ==(another)
|
27
|
-
another.kind_of?(
|
20
|
+
another.kind_of?(AuditIterate) && another.index == index
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a string like '_iterate(<index>)'.
|
24
|
+
def to_s
|
25
|
+
"_iterate(#{index})"
|
28
26
|
end
|
29
27
|
end
|
30
28
|
|
31
|
-
# Audit provides a way to track the values (inputs and results) passed
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
29
|
+
# Audit provides a way to track the values (inputs and results) passed among
|
30
|
+
# tasks or, more generally, any Executable. Audits allow you to track inputs
|
31
|
+
# as they make their way through a workflow, and have great utility in
|
32
|
+
# debugging and record keeping.
|
35
33
|
#
|
36
|
-
# During execution, the
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
34
|
+
# During execution, the inputs to a task are used to initialize an Audit.
|
35
|
+
# These inputs are the original value of the audit and mark the begining
|
36
|
+
# of an audit trail; every task adds to the trail by recording it's result
|
37
|
+
# and itself as the 'source' of the result.
|
40
38
|
#
|
41
|
-
#
|
42
|
-
#
|
39
|
+
# Audits can take any object as a source, so for illustration lets use some
|
40
|
+
# symbols:
|
43
41
|
#
|
44
42
|
# # initialize a new audit
|
45
43
|
# a = Audit.new(1, nil)
|
@@ -48,8 +46,8 @@ module Tap
|
|
48
46
|
# a._record(:A, 2)
|
49
47
|
# a._record(:B, 3)
|
50
48
|
#
|
51
|
-
# Now you can pull up the source and value trails, as well as
|
52
|
-
#
|
49
|
+
# Now you can pull up the source and value trails, as well as the current
|
50
|
+
# and original values:
|
53
51
|
#
|
54
52
|
# a._source_trail # => [nil, :A, :B]
|
55
53
|
# a._value_trail # => [1, 2, 3]
|
@@ -60,9 +58,9 @@ module Tap
|
|
60
58
|
# a._current # => 3
|
61
59
|
# a._current_source # => :B
|
62
60
|
#
|
63
|
-
# Merges are supported by using an array of the
|
64
|
-
# an AuditMerge) as the source, and an array of the
|
65
|
-
#
|
61
|
+
# Merges are supported by using an array of the merged trails (actually
|
62
|
+
# an AuditMerge) as the source, and an array of the merged values as the
|
63
|
+
# original value.
|
66
64
|
#
|
67
65
|
# b = Audit.new(10, nil)
|
68
66
|
# b._record(:C, 11)
|
@@ -81,9 +79,9 @@ module Tap
|
|
81
79
|
# c._value_trail # => [ [[1,2,3], [10, 11, 12]], "a string value", {'a' => 'hash value'}, ['an', 'array', 'value']]
|
82
80
|
#
|
83
81
|
# Audit supports forks by duplicating the source and value trails. Forks
|
84
|
-
# can be developed independently.
|
85
|
-
#
|
86
|
-
#
|
82
|
+
# can be developed independently. Audits are also forked during a merge;
|
83
|
+
# notice the additional record in 'a' doesn't change the source trail for
|
84
|
+
# 'c':
|
87
85
|
#
|
88
86
|
# a1 = a._fork
|
89
87
|
#
|
@@ -99,23 +97,23 @@ module Tap
|
|
99
97
|
# to help gain access, as well as a printing method to visualize the
|
100
98
|
# audit trail:
|
101
99
|
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
# o-[
|
105
|
-
# o-[
|
106
|
-
#
|
107
|
-
# |
|
108
|
-
# | o-[
|
109
|
-
# | o-[
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
100
|
+
# c._to_s
|
101
|
+
# # =>
|
102
|
+
# # o-[] 1
|
103
|
+
# # o-[A] 2
|
104
|
+
# # o-[B] 3
|
105
|
+
# # |
|
106
|
+
# # | o-[] 10
|
107
|
+
# # | o-[C] 11
|
108
|
+
# # | o-[D] 12
|
109
|
+
# # | |
|
110
|
+
# # `-`-o-[E] "a string value"
|
111
|
+
# # o-[F] {"a"=>"hash value"}
|
112
|
+
# # o-[G] ["an", "array", "value"]
|
114
113
|
#
|
115
114
|
# In practice, tasks are recored as sources. Thus source trails can be used
|
116
115
|
# to access task configurations and other information that may be useful
|
117
|
-
# when creating reports or making workflow decisions
|
118
|
-
# error after looping to a given task too many times).
|
116
|
+
# when creating reports or making workflow decisions.
|
119
117
|
#
|
120
118
|
#--
|
121
119
|
# TODO:
|
@@ -141,9 +139,9 @@ module Tap
|
|
141
139
|
class << self
|
142
140
|
|
143
141
|
# Creates a new Audit by merging the input audits. The value of the new
|
144
|
-
# Audit will be an array of the _current values of the
|
145
|
-
# will be an AuditMerge whose values are forks of the
|
146
|
-
# sources
|
142
|
+
# Audit will be an array of the _current values of the inputs. The source
|
143
|
+
# will be an AuditMerge whose values are forks of the inputs. Non-Audit
|
144
|
+
# sources may be provided; they are initialized to Audits before merging.
|
147
145
|
#
|
148
146
|
# a = Audit.new
|
149
147
|
# a._record(:a, 'a')
|
@@ -179,9 +177,9 @@ module Tap
|
|
179
177
|
# An array of the values in self
|
180
178
|
attr_reader :_values
|
181
179
|
|
182
|
-
# An arbitrary
|
183
|
-
# provided to Audit.new. (nil
|
184
|
-
#
|
180
|
+
# An arbitrary object used to identify when no inputs have been
|
181
|
+
# provided to Audit.new. (nil cannot be used since nil is a valid
|
182
|
+
# initial value)
|
185
183
|
AUDIT_NIL = Object.new
|
186
184
|
|
187
185
|
# A new audit takes a value and/or source. A nil source is typically given
|
@@ -268,7 +266,7 @@ module Tap
|
|
268
266
|
end
|
269
267
|
|
270
268
|
# Produces a new Audit with duplicate sources and values, suitable for
|
271
|
-
#
|
269
|
+
# independent development.
|
272
270
|
def _fork
|
273
271
|
a = Audit.new
|
274
272
|
a._sources = _sources.dup
|
@@ -276,18 +274,16 @@ module Tap
|
|
276
274
|
a
|
277
275
|
end
|
278
276
|
|
279
|
-
#
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
#
|
285
|
-
|
286
|
-
# does not respond to each.
|
287
|
-
def _expand
|
277
|
+
# Produces a fork of self for each item in the current value (_current).
|
278
|
+
# Iterate is useful for developing each item of (say) an array along
|
279
|
+
# different paths.
|
280
|
+
#
|
281
|
+
# Records the next value of each fork as [item, AuditIterate.new(<index of item>)].
|
282
|
+
# Raises an error if _current does not respond to each.
|
283
|
+
def _iterate
|
288
284
|
expanded = []
|
289
285
|
_current.each do |value|
|
290
|
-
expanded << _fork._record(
|
286
|
+
expanded << _fork._record(AuditIterate.new(expanded.length), value)
|
291
287
|
end
|
292
288
|
expanded
|
293
289
|
end
|