tap 0.12.4 → 0.17.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 (102) hide show
  1. data/History +34 -0
  2. data/README +62 -41
  3. data/bin/tap +36 -40
  4. data/cmd/console.rb +14 -6
  5. data/cmd/manifest.rb +62 -58
  6. data/cmd/run.rb +49 -31
  7. data/doc/API +84 -0
  8. data/doc/Class Reference +83 -115
  9. data/doc/Examples/Command Line +36 -0
  10. data/doc/Examples/Workflow +40 -0
  11. data/lib/tap/app.rb +293 -214
  12. data/lib/tap/app/node.rb +43 -0
  13. data/lib/tap/app/queue.rb +77 -0
  14. data/lib/tap/app/stack.rb +16 -0
  15. data/lib/tap/app/state.rb +22 -0
  16. data/lib/tap/constants.rb +2 -2
  17. data/lib/tap/env.rb +400 -314
  18. data/lib/tap/env/constant.rb +227 -0
  19. data/lib/tap/env/gems.rb +63 -0
  20. data/lib/tap/env/manifest.rb +89 -0
  21. data/lib/tap/env/minimap.rb +292 -0
  22. data/lib/tap/{support → env}/string_ext.rb +2 -2
  23. data/lib/tap/exe.rb +113 -125
  24. data/lib/tap/join.rb +175 -0
  25. data/lib/tap/joins.rb +9 -0
  26. data/lib/tap/joins/switch.rb +44 -0
  27. data/lib/tap/joins/sync.rb +99 -0
  28. data/lib/tap/root.rb +100 -491
  29. data/lib/tap/root/utils.rb +220 -0
  30. data/lib/tap/{support → root}/versions.rb +31 -29
  31. data/lib/tap/schema.rb +248 -0
  32. data/lib/tap/schema/parser.rb +413 -0
  33. data/lib/tap/schema/utils.rb +82 -0
  34. data/lib/tap/support/intern.rb +19 -6
  35. data/lib/tap/support/templater.rb +8 -3
  36. data/lib/tap/task.rb +175 -171
  37. data/lib/tap/tasks/dump.rb +58 -0
  38. data/lib/tap/tasks/load.rb +62 -0
  39. metadata +30 -73
  40. data/cmd/destroy.rb +0 -27
  41. data/cmd/generate.rb +0 -27
  42. data/doc/Command Reference +0 -105
  43. data/doc/Syntax Reference +0 -234
  44. data/doc/Tutorial +0 -348
  45. data/lib/tap/dump.rb +0 -142
  46. data/lib/tap/file_task.rb +0 -384
  47. data/lib/tap/generator/arguments.rb +0 -13
  48. data/lib/tap/generator/base.rb +0 -176
  49. data/lib/tap/generator/destroy.rb +0 -60
  50. data/lib/tap/generator/generate.rb +0 -93
  51. data/lib/tap/generator/generators/command/command_generator.rb +0 -21
  52. data/lib/tap/generator/generators/command/templates/command.erb +0 -32
  53. data/lib/tap/generator/generators/config/config_generator.rb +0 -98
  54. data/lib/tap/generator/generators/generator/generator_generator.rb +0 -37
  55. data/lib/tap/generator/generators/generator/templates/task.erb +0 -27
  56. data/lib/tap/generator/generators/generator/templates/test.erb +0 -26
  57. data/lib/tap/generator/generators/root/root_generator.rb +0 -84
  58. data/lib/tap/generator/generators/root/templates/MIT-LICENSE +0 -22
  59. data/lib/tap/generator/generators/root/templates/README +0 -14
  60. data/lib/tap/generator/generators/root/templates/Rakefile +0 -84
  61. data/lib/tap/generator/generators/root/templates/Rapfile +0 -11
  62. data/lib/tap/generator/generators/root/templates/gemspec +0 -27
  63. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -3
  64. data/lib/tap/generator/generators/task/task_generator.rb +0 -25
  65. data/lib/tap/generator/generators/task/templates/task.erb +0 -14
  66. data/lib/tap/generator/generators/task/templates/test.erb +0 -19
  67. data/lib/tap/generator/manifest.rb +0 -20
  68. data/lib/tap/generator/preview.rb +0 -69
  69. data/lib/tap/load.rb +0 -64
  70. data/lib/tap/spec.rb +0 -41
  71. data/lib/tap/support/aggregator.rb +0 -65
  72. data/lib/tap/support/audit.rb +0 -333
  73. data/lib/tap/support/constant.rb +0 -143
  74. data/lib/tap/support/constant_manifest.rb +0 -126
  75. data/lib/tap/support/dependencies.rb +0 -54
  76. data/lib/tap/support/dependency.rb +0 -44
  77. data/lib/tap/support/executable.rb +0 -198
  78. data/lib/tap/support/executable_queue.rb +0 -125
  79. data/lib/tap/support/gems.rb +0 -43
  80. data/lib/tap/support/join.rb +0 -144
  81. data/lib/tap/support/joins.rb +0 -12
  82. data/lib/tap/support/joins/switch.rb +0 -27
  83. data/lib/tap/support/joins/sync_merge.rb +0 -38
  84. data/lib/tap/support/manifest.rb +0 -171
  85. data/lib/tap/support/minimap.rb +0 -90
  86. data/lib/tap/support/node.rb +0 -176
  87. data/lib/tap/support/parser.rb +0 -450
  88. data/lib/tap/support/schema.rb +0 -385
  89. data/lib/tap/support/shell_utils.rb +0 -67
  90. data/lib/tap/test.rb +0 -77
  91. data/lib/tap/test/assertions.rb +0 -38
  92. data/lib/tap/test/env_vars.rb +0 -29
  93. data/lib/tap/test/extensions.rb +0 -73
  94. data/lib/tap/test/file_test.rb +0 -362
  95. data/lib/tap/test/file_test_class.rb +0 -15
  96. data/lib/tap/test/regexp_escape.rb +0 -87
  97. data/lib/tap/test/script_test.rb +0 -46
  98. data/lib/tap/test/script_tester.rb +0 -115
  99. data/lib/tap/test/subset_test.rb +0 -260
  100. data/lib/tap/test/subset_test_class.rb +0 -99
  101. data/lib/tap/test/tap_test.rb +0 -109
  102. data/lib/tap/test/utils.rb +0 -231
@@ -1,5 +1,5 @@
1
1
  module Tap
2
- module Support
2
+ class Env
3
3
 
4
4
  # StringExt provides two common string transformations, camelize and
5
5
  # underscore. StringExt is automatically included in String.
@@ -56,5 +56,5 @@ module Tap
56
56
  end
57
57
 
58
58
  class String # :nodoc:
59
- include Tap::Support::StringExt
59
+ include Tap::Env::StringExt
60
60
  end
data/lib/tap/exe.rb CHANGED
@@ -1,106 +1,91 @@
1
1
  require 'tap/env'
2
- require 'tap/app'
3
- require 'tap/support/schema'
2
+ require 'tap/task'
3
+ require 'tap/schema'
4
4
 
5
5
  module Tap
6
- class Exe < Env
7
- class << self
8
- def setup(argv=ARGV)
9
- if argv[-1] == '-d-'
10
- argv.pop
11
- $DEBUG = true
12
- end
13
-
14
- instantiate
6
+ module Exe
7
+
8
+ # Adapted from Gem.find_home
9
+ # def self.user_home
10
+ # ['HOME', 'USERPROFILE'].each do |homekey|
11
+ # return ENV[homekey] if ENV[homekey]
12
+ # end
13
+ #
14
+ # if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
15
+ # return "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}"
16
+ # end
17
+ #
18
+ # begin
19
+ # File.expand_path("~")
20
+ # rescue
21
+ # File::ALT_SEPARATOR ? "C:/" : "/"
22
+ # end
23
+ # end
24
+
25
+ # Setup an execution environment.
26
+ def self.setup(options={}, argv=ARGV, env=ENV)
27
+ if argv[-1] == "-d-"
28
+ argv.pop
29
+ $DEBUG = true
15
30
  end
16
31
 
17
- def instantiate(path_or_root=Dir.pwd)
18
- exe = super
19
-
20
- # add all gems if no gems are specified (Note this is VERY SLOW ~ 1/3 the overhead for tap)
21
- exe.gems = :all if !File.exists?(Tap::Env::DEFAULT_CONFIG_FILE)
22
-
23
- # add the default tap instance
24
- exe.push Env.instantiate("#{File.dirname(__FILE__)}/../..")
25
- exe
26
- end
32
+ options = {
33
+ :dir => Dir.pwd,
34
+ :config_file => CONFIG_FILE
35
+ }.merge(options)
27
36
 
28
- def load_config(path)
29
- super(GLOBAL_CONFIG_FILE).merge super(path)
30
- end
37
+ # load configurations
38
+ dir = options.delete(:dir)
39
+ config_file = options.delete(:config_file)
40
+ user_config_file = config_file ? File.join(dir, config_file) : nil
31
41
 
32
- # Adapted from Gem.find_home
33
- def user_home
34
- ['HOME', 'USERPROFILE'].each do |homekey|
35
- return ENV[homekey] if ENV[homekey]
42
+ user = Env.load_config(user_config_file)
43
+ global = {}
44
+ env.each_pair do |key, value|
45
+ if key =~ /\ATAP_(.*)\z/
46
+ global[$1.downcase] = value
36
47
  end
48
+ end
37
49
 
38
- if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
39
- return "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}"
40
- end
41
-
42
- begin
43
- File.expand_path("~")
44
- rescue
45
- File::ALT_SEPARATOR ? "C:/" : "/"
46
- end
50
+ config = {
51
+ 'root' => dir,
52
+ 'gems' => :all
53
+ }.merge(global).merge(user).merge(options)
54
+
55
+ # keys must be symbolize as they are immediately
56
+ # used to initialize the Env configs
57
+ config = config.inject({}) do |options, (key, value)|
58
+ options[key.to_sym || key] = value
59
+ options
47
60
  end
48
- end
49
-
50
- config :before, nil
51
- config :after, nil
52
-
53
- # Specify files to require when self is activated.
54
- config :requires, [], &c.array_or_nil
55
-
56
- # Specify files to load when self is activated.
57
- config :loads, [], &c.array_or_nil
58
- config :aliases, {}, &c.hash_or_nil
59
-
60
- # The global home directory
61
- GLOBAL_HOME = File.join(Exe.user_home, ".tap")
62
-
63
- # The global config file path
64
- GLOBAL_CONFIG_FILE = File.join(GLOBAL_HOME, "tap.yml")
65
-
66
- def activate
67
- if super
68
61
 
69
- # perform requires
70
- requires.each do |path|
71
- require path
72
- end
62
+ # instantiate
63
+ exe = Env.new(config, :basename => config_file).extend(Exe)
73
64
 
74
- # perform loads
75
- loads.each do |path|
76
- load path
77
- end
65
+ exe.register('command') do |env|
66
+ env.root.glob(:cmd, "**/*.rb")
78
67
  end
79
- end
80
-
81
- def handle_error(err)
82
- case
83
- when $DEBUG
84
- puts err.message
85
- puts
86
- puts err.backtrace
87
- else puts err.message
68
+
69
+ # add the tap env if necessary
70
+ unless exe.any? {|env| env.root.root == TAP_HOME }
71
+ exe.push Env.new(TAP_HOME, exe.context)
88
72
  end
73
+
74
+ exe
89
75
  end
90
76
 
91
- def execute(argv=ARGV)
92
- command = argv.shift.to_s
93
-
94
- if aliases && aliases.has_key?(command)
95
- aliases[command].reverse_each {|arg| argv.unshift(arg)}
96
- command = argv.shift
97
- end
98
-
99
- case command
77
+ # The config file path
78
+ CONFIG_FILE = "tap.yml"
79
+
80
+ # The home directory for Tap
81
+ TAP_HOME = File.expand_path("#{File.dirname(__FILE__)}/../..")
82
+
83
+ def launch(argv=ARGV)
84
+ case command = argv.shift.to_s
100
85
  when '', '--help'
101
86
  yield
102
87
  else
103
- if path = commands.search(command)
88
+ if path = seek('command', command)
104
89
  load path # run the command, if it exists
105
90
  else
106
91
  puts "Unknown command: '#{command}'"
@@ -110,61 +95,64 @@ module Tap
110
95
  end
111
96
 
112
97
  def build(schema, app=Tap::App.instance)
113
- schema.build(app) do |args|
114
- task = args.shift
115
- const = tasks.search(task)
116
-
117
- task_class = case
118
- when const then const.constantize
119
- when block_given?
120
- args.unshift(task)
121
- yield(args)
122
- else nil
98
+ schema.resolve! do |type, id, data|
99
+ klass = self[type][id]
100
+ if !klass && block_given?
101
+ klass = yield(type, id, data)
123
102
  end
124
103
 
125
- task_class or raise ArgumentError, "unknown task: #{task}"
126
- task_class.parse(args, app) do |help|
127
- puts help
128
- exit
129
- end
104
+ klass || id
130
105
  end
106
+ schema.validate!
107
+ schema.build(app)
131
108
  end
132
109
 
133
- def set_signals(app=Tap::App.instance)
110
+ def set_signals(app)
134
111
  # info signal -- Note: some systems do
135
112
  # not support the INFO signal
136
113
  # (windows, fedora, at least)
137
114
  signals = Signal.list.keys
138
- if signals.include?("INFO")
139
- Signal.trap("INFO") do
140
- puts app.info
141
- end
142
- end
115
+ Signal.trap("INFO") do
116
+ puts app.info
117
+ end if signals.include?("INFO")
143
118
 
144
119
  # interuption signal
145
- if signals.include?("INT")
146
- Signal.trap("INT") do
147
- puts " interrupted!"
148
- # prompt for decision
149
- while true
150
- print "stop, terminate, exit, or resume? (s/t/e/r):"
151
- case gets.strip
152
- when /s(top)?/i
153
- app.stop
154
- break
155
- when /t(erminate)?/i
156
- app.terminate
157
- break
158
- when /e(xit)?/i
159
- exit
160
- when /r(esume)?/i
161
- break
162
- else
163
- puts "unexpected response..."
164
- end
120
+ Signal.trap("INT") do
121
+ puts " interrupted!"
122
+ # prompt for decision
123
+ while true
124
+ print "stop, terminate, exit, or resume? (s/t/e/r):"
125
+ case gets.strip
126
+ when /s(top)?/i
127
+ app.stop
128
+ break
129
+ when /t(erminate)?/i
130
+ app.terminate
131
+ break
132
+ when /e(xit)?/i
133
+ exit
134
+ when /r(esume)?/i
135
+ break
136
+ else
137
+ puts "unexpected response..."
165
138
  end
166
139
  end
140
+ end if signals.include?("INT")
141
+ end
142
+
143
+ def run(schemas, app=Tap::App.instance, &block)
144
+ schemas = [schemas] unless schemas.kind_of?(Array)
145
+ schemas.each do |schema|
146
+ build(schema, app, &block)
147
+ end
148
+
149
+ if app.queue.empty?
150
+ raise "no nodes specified"
167
151
  end
152
+
153
+ set_signals(app)
154
+ app.run
168
155
  end
156
+
169
157
  end
170
158
  end
data/lib/tap/join.rb ADDED
@@ -0,0 +1,175 @@
1
+ require 'tap/app'
2
+ require 'tap/support/intern'
3
+
4
+ module Tap
5
+ class App
6
+ # Generates a join between the inputs and outputs.
7
+ def join(inputs, outputs, config={}, klass=Join, &block)
8
+ klass.new(config, self).join(inputs, outputs, &block)
9
+ end
10
+ end
11
+
12
+ # :startdoc::join a simple, unsyncrhonized, multi-way join
13
+ #
14
+ # Join defines an unsynchronized, multi-way join where n inputs send their
15
+ # results to m outputs. Flags can augment how the results are passed, in
16
+ # particular for array results.
17
+ #
18
+ class Join
19
+ class << self
20
+ def inherited(child) # :nodoc:
21
+ unless child.instance_variable_defined?(:@source_file)
22
+ caller[0] =~ Lazydoc::CALLER_REGEXP
23
+ child.instance_variable_set(:@source_file, File.expand_path($1))
24
+ end
25
+ super
26
+ end
27
+
28
+ # Parses the argv into an array like [inputs, outputs, instance] where
29
+ # inputs and outputs implicitly define the inputs and output for the
30
+ # instance. By default parse parses an argh then calls instantiate,
31
+ # but there is no requirement that this occurs in subclasses.
32
+ def parse(argv=ARGV, app=Tap::App.instance)
33
+ parse!(argv.dup, app)
34
+ end
35
+
36
+ # Same as parse, but removes arguments destructively.
37
+ def parse!(argv=ARGV, app=Tap::App.instance)
38
+ opts = ConfigParser.new
39
+ opts.separator "configurations:"
40
+ opts.add(configurations)
41
+
42
+ args = opts.parse!(argv, :add_defaults => false)
43
+
44
+ instantiate({
45
+ :config => opts.nested_config,
46
+ :args => args
47
+ }, app)
48
+ end
49
+
50
+ # Instantiates an instance of self and return an array like [inputs,
51
+ # outputs, instance].
52
+ def instantiate(argh, app=Tap::App.instance)
53
+ new(argh[:config] || {}, app)
54
+ end
55
+
56
+ # Instantiates a new join with the input arguments and overrides
57
+ # call with the block. The block will be called with the join
58
+ # instance and result.
59
+ #
60
+ # Simply instantiates a new join if no block is given.
61
+ def intern(config={}, app=Tap::App.instance, &block) # :yields: join, result
62
+ instance = new(config, app)
63
+ if block_given?
64
+ instance.extend Support::Intern(:call)
65
+ instance.call_block = block
66
+ end
67
+ instance
68
+ end
69
+
70
+ protected
71
+
72
+ def parse_array(obj) # :nodoc:
73
+ case obj
74
+ when nil then []
75
+ when Array then obj
76
+ else
77
+ obj.split(",").collect {|str| str.to_i }
78
+ end
79
+ end
80
+ end
81
+ include Configurable
82
+
83
+ lazy_attr :desc, 'join'
84
+
85
+ # Causes the targets to be enqued rather than executed immediately.
86
+ config :enq, false, :short => 'q', &c.flag
87
+
88
+ # Splats the result to the outputs, allowing a many-to-one join
89
+ # from the perspective of the results.
90
+ #
91
+ # # results: [1,2,3]
92
+ # # outputs: call(*inputs)
93
+ # app.execute(output, *result)
94
+ #
95
+ config :splat, false, :short => 's', &c.flag
96
+
97
+ # Iterates the results to the outputs, allowing a many-to-one join
98
+ # from the perspective of the results. Non-array results are converted
99
+ # to arrays using to_ary:
100
+ #
101
+ # # results: [1,2,3]
102
+ # # outputs: call(input)
103
+ # result.to_ary.each {|r| app.execute(output, r) }
104
+ #
105
+ # Iterate may be combined with splat:
106
+ #
107
+ # # results: [[1,2],3]
108
+ # # outputs: call(*inputs)
109
+ # result.to_ary.each {|r| app.execute(output, *r) }
110
+ #
111
+ config :iterate, false, :short => 'i', &c.flag
112
+
113
+ # The App receiving self during enq
114
+ attr_accessor :app
115
+
116
+ # An array of input nodes, or nil if the join has not been set.
117
+ attr_reader :inputs
118
+
119
+ # An array of output nodes, or nil if the join has not been set.
120
+ attr_reader :outputs
121
+
122
+ # Initializes a new join with the specified configuration.
123
+ def initialize(config={}, app=Tap::App.instance)
124
+ @app = app
125
+ @inputs = nil
126
+ @outputs = nil
127
+ initialize_config(config)
128
+ end
129
+
130
+ # Sets self as a join between the inputs and outputs.
131
+ def join(inputs, outputs)
132
+ @inputs.each do |input|
133
+ input.joins.delete(self)
134
+ end if @inputs
135
+
136
+ @inputs = inputs
137
+
138
+ inputs.each do |input|
139
+ input.joins << self
140
+ end if inputs
141
+
142
+ @outputs = outputs
143
+ self
144
+ end
145
+
146
+ # Executes the join logic for self, which by default passes the result to
147
+ # each output.
148
+ def call(result)
149
+ outputs.each do |output|
150
+ dispatch(output, result)
151
+ end
152
+ end
153
+
154
+ protected
155
+
156
+ # Dispatches the results to the node.
157
+ def dispatch(node, result) # :nodoc:
158
+ mode = enq ? :enq : :execute
159
+ if iterate
160
+ result.to_ary.each {|r| execute(mode, node, r) }
161
+ else
162
+ execute(mode, node, result)
163
+ end
164
+ end
165
+
166
+ # Executes the node with the input results.
167
+ def execute(mode, node, result) # :nodoc:
168
+ if splat
169
+ app.send(mode, node, *result)
170
+ else
171
+ app.send(mode, node, result)
172
+ end
173
+ end
174
+ end
175
+ end