bahuvrihi-tap 0.10.2 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/tap/workflow.rb CHANGED
@@ -76,43 +76,17 @@ module Tap
76
76
  # app.run
77
77
  # app.results(w1.exit_points, w2.exit_points)) # => [8, -8]
78
78
  #
79
- class Workflow
80
- include Support::Framework
81
-
82
- class << self
83
- protected
84
-
85
- def define(name, klass=Tap::Task, &block)
86
- instance_var = "@#{name}".to_sym
87
-
88
- define_method(name) do |*args|
89
- raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" if args.length > 1
90
-
91
- instance_name = args[0] || name
92
- instance_variable_set(instance_var, {}) unless instance_variable_defined?(instance_var)
93
- instance_variable_get(instance_var)[instance_name] ||= task(instance_name, klass, &block)
94
- end
95
-
96
- define_method("#{name}=") do |input|
97
- input = {name => input} unless input.kind_of?(Hash)
98
- instance_variable_set(instance_var, input)
99
- end
100
- end
101
- end
79
+ class Workflow < Task
102
80
 
103
81
  # The entry point for self.
104
82
  attr_accessor :entry_point
105
83
 
106
84
  # The exit point for self.
107
85
  attr_accessor :exit_point
108
-
109
- # The task block provided during initialization.
110
- attr_reader :task_block
111
-
86
+
112
87
  # Creates a new Task with the specified attributes.
113
88
  def initialize(config={}, name=nil, app=App.instance, &task_block)
114
- super(config, name, app)
115
- @task_block = (task_block == nil ? default_task_block : task_block)
89
+ super
116
90
  initialize_workflow
117
91
  end
118
92
 
@@ -157,32 +131,22 @@ module Tap
157
131
  # the number of inputs required by all the entry points;
158
132
  # if the entry points have different input requirements, they
159
133
  # have to be enqued separately.
160
- def enq(*inputs)
134
+ def unbatched_enq(*inputs)
161
135
  entry_points.each do |task|
162
136
  app.enq(task, *inputs)
163
137
  end
164
138
  end
165
-
166
- batch_function :enq
167
-
139
+
168
140
  # Sets the on_complete_block for all exit points for self and
169
141
  # self.batch. Use unbatched_on_complete to set the on_complete_block
170
142
  # for just self.exit_points.
171
- def on_complete(override=false, &block)
143
+ def unbatched_on_complete(override=false, &block)
172
144
  exit_points.each do |task|
173
145
  task.on_complete(override, &block)
174
146
  end
175
147
  self
176
148
  end
177
-
178
- batch_function(:on_complete) {}
179
-
180
- def task(name, klass=Tap::Task, &block)
181
- configs = config[name] || {}
182
- raise ArgumentError, "config '#{name}' is not a hash" unless configs.kind_of?(Hash)
183
- klass.new(configs, name, &block)
184
- end
185
-
149
+
186
150
  # The workflow definition method. By default workflow
187
151
  # simply calls the task_block. In subclasses, workflow
188
152
  # should be overridden to provide the workflow definition.
@@ -190,11 +154,8 @@ module Tap
190
154
  task_block.call(self) if task_block
191
155
  end
192
156
 
193
- protected
194
-
195
- # Hook to set a default task block. By default, nil.
196
- def default_task_block
197
- nil
157
+ def process(*inputs)
158
+ enq(*inputs)
198
159
  end
199
160
  end
200
161
  end
data/template/404.erb ADDED
@@ -0,0 +1,12 @@
1
+ <html>
2
+ <body>
3
+ <p>
4
+ # 404 error<br/>
5
+ # Could not handle request:
6
+ </p>
7
+ <code><pre>
8
+ <%= cgi.to_yaml %>
9
+ <%= rack.to_yaml %>
10
+ </pre></code>
11
+ </body>
12
+ </html>
@@ -0,0 +1,41 @@
1
+ <html>
2
+ <head>
3
+ <title>Tap::Manifest</title>
4
+ </head>
5
+ <body>
6
+ <h1><a href="<%= Tap::WEBSITE %>">Tap (<ins>T</ins>ask <ins>Ap</ins>plication) <%= Tap::VERSION %> </a></h1>
7
+
8
+ <% server.manifest(:envs, true).minimize.each do |(env_key, env)|
9
+ cgi_manifest = env.manifest(:cgis, true).minimize
10
+ task_manifest = env.manifest(:tasks, true).minimize
11
+ next if cgi_manifest.empty? && task_manifest.empty? %>
12
+ <h2><%= env_key %></h2>
13
+
14
+ <% unless cgi_manifest.empty? %>
15
+ <ul>
16
+ <% cgi_manifest.each do |(cgi_key, path)|
17
+ lazydoc = Tap::Support::Lazydoc[path]
18
+ lazydoc.resolve
19
+ summary = lazydoc.default_attributes['summary']
20
+ %>
21
+ <li><a href="<%= cgi_key %>"><%= cgi_key %></a>: <%= summary %></li>
22
+ <% end %>
23
+ </ul>
24
+ <% end %>
25
+
26
+ <% unless task_manifest.empty? %>
27
+ <ul>
28
+ <% task_manifest.each do |(task_key, const)|
29
+ lazydoc = Tap::Support::Lazydoc[const.require_path]
30
+ lazydoc.resolve
31
+ summary = lazydoc[const.name]['manifest'].subject
32
+ %>
33
+ <li><a href="run?task=<%= task_key %>"><%= const.name %></a> <%= summary %></li>
34
+ <% end %>
35
+ </ul>
36
+ <% end %>
37
+ <% end %>
38
+
39
+ <a href="index?refresh=true">Refresh</a>
40
+ </body>
41
+ </html>
@@ -0,0 +1,93 @@
1
+ require 'strscan'
2
+
3
+ class UrlEncodedPairParser < StringScanner #:nodoc:
4
+ attr_reader :top, :parent, :result
5
+
6
+ def initialize(pairs = [])
7
+ super('')
8
+ @result = {}
9
+ pairs.each { |key, value| parse(key, value) }
10
+ end
11
+
12
+ KEY_REGEXP = %r{([^\[\]=&]+)}
13
+ BRACKETED_KEY_REGEXP = %r{\[([^\[\]=&]+)\]}
14
+
15
+ # Parse the query string
16
+ def parse(key, value)
17
+ self.string = key
18
+ @top, @parent = result, nil
19
+
20
+ # First scan the bare key
21
+ key = scan(KEY_REGEXP) or return
22
+ key = post_key_check(key)
23
+
24
+ # Then scan as many nestings as present
25
+ until eos?
26
+ r = scan(BRACKETED_KEY_REGEXP) or return
27
+ key = self[1]
28
+ key = post_key_check(key)
29
+ end
30
+
31
+ bind(key, value)
32
+ end
33
+
34
+ private
35
+ # After we see a key, we must look ahead to determine our next action. Cases:
36
+ #
37
+ # [] follows the key. Then the value must be an array.
38
+ # = follows the key. (A value comes next)
39
+ # & or the end of string follows the key. Then the key is a flag.
40
+ # otherwise, a hash follows the key.
41
+ def post_key_check(key)
42
+ if scan(/\[\]/) # a[b][] indicates that b is an array
43
+ container(key, Array)
44
+ nil
45
+ elsif check(/\[[^\]]/) # a[b] indicates that a is a hash
46
+ container(key, Hash)
47
+ nil
48
+ else # End of key? We do nothing.
49
+ key
50
+ end
51
+ end
52
+
53
+ # Add a container to the stack.
54
+ def container(key, klass)
55
+ type_conflict! klass, top[key] if top.is_a?(Hash) && top.key?(key) && ! top[key].is_a?(klass)
56
+ value = bind(key, klass.new)
57
+ type_conflict! klass, value unless value.is_a?(klass)
58
+ push(value)
59
+ end
60
+
61
+ # Push a value onto the 'stack', which is actually only the top 2 items.
62
+ def push(value)
63
+ @parent, @top = @top, value
64
+ end
65
+
66
+ # Bind a key (which may be nil for items in an array) to the provided value.
67
+ def bind(key, value)
68
+ if top.is_a? Array
69
+ if key
70
+ if top[-1].is_a?(Hash) && ! top[-1].key?(key)
71
+ top[-1][key] = value
72
+ else
73
+ top << {key => value}#.with_indifferent_access
74
+ push top.last
75
+ end
76
+ else
77
+ top << value
78
+ end
79
+ elsif top.is_a? Hash
80
+ key = CGI.unescape(key)
81
+ parent << (@top = {}) if top.key?(key) && parent.is_a?(Array)
82
+ return top[key] ||= value
83
+ else
84
+ raise ArgumentError, "Don't know what to do: top is #{top.inspect}"
85
+ end
86
+
87
+ return value
88
+ end
89
+
90
+ def type_conflict!(klass, value)
91
+ raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value."
92
+ end
93
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bahuvrihi-tap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.2
4
+ version: 0.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Chiang
@@ -30,11 +30,13 @@ files:
30
30
  - README
31
31
  - MIT-LICENSE
32
32
  - History
33
+ - cgi/run.rb
33
34
  - cmd/console.rb
34
35
  - cmd/destroy.rb
35
36
  - cmd/generate.rb
36
37
  - cmd/manifest.rb
37
38
  - cmd/run.rb
39
+ - cmd/server.rb
38
40
  - doc/Tutorial
39
41
  - doc/Class Reference
40
42
  - doc/Command Reference
@@ -85,7 +87,6 @@ files:
85
87
  - lib/tap/support/batchable_class.rb
86
88
  - lib/tap/support/class_configuration.rb
87
89
  - lib/tap/support/command_line.rb
88
- - lib/tap/support/command_line/parser.rb
89
90
  - lib/tap/support/comment.rb
90
91
  - lib/tap/support/configurable.rb
91
92
  - lib/tap/support/configurable_class.rb
@@ -95,14 +96,16 @@ files:
95
96
  - lib/tap/support/declarations.rb
96
97
  - lib/tap/support/executable.rb
97
98
  - lib/tap/support/executable_queue.rb
98
- - lib/tap/support/framework.rb
99
- - lib/tap/support/framework_class.rb
100
99
  - lib/tap/support/gems/rake.rb
100
+ - lib/tap/support/gems/rack.rb
101
101
  - lib/tap/support/gems.rb
102
102
  - lib/tap/support/instance_configuration.rb
103
103
  - lib/tap/support/lazy_attributes.rb
104
104
  - lib/tap/support/lazydoc.rb
105
105
  - lib/tap/support/manifest.rb
106
+ - lib/tap/support/parsers/base.rb
107
+ - lib/tap/support/parsers/command_line.rb
108
+ - lib/tap/support/parsers/server.rb
106
109
  - lib/tap/support/run_error.rb
107
110
  - lib/tap/support/shell_utils.rb
108
111
  - lib/tap/support/tdoc.rb
@@ -127,6 +130,9 @@ files:
127
130
  - lib/tap/test.rb
128
131
  - lib/tap/workflow.rb
129
132
  - lib/tap.rb
133
+ - template/404.erb
134
+ - template/index.erb
135
+ - vendor/url_encoded_pair_parser.rb
130
136
  has_rdoc: true
131
137
  homepage: http://tap.rubyforge.org
132
138
  post_install_message:
@@ -1,121 +0,0 @@
1
- module Tap
2
- module Support
3
- module CommandLine
4
- class Parser
5
- class << self
6
- def parse_sequence(str, count=0)
7
- seq = []
8
- seq << count if str[0] == ?:
9
- str.split(/:+/).each do |n|
10
- seq << n.to_i unless n.empty?
11
- end
12
- seq << count + 1 if str[-1] == ?:
13
- seq
14
- end
15
-
16
- def bracket_regexp(l, r)
17
- /\A--(\d*)#{Regexp.escape(l)}([\d,]*)#{Regexp.escape(r)}\z/
18
- end
19
-
20
- def parse_bracket(lead, str, count=0)
21
- bracket = []
22
- str.split(/,+/).each do |n|
23
- bracket << n.to_i unless n.empty?
24
- end
25
-
26
- [lead.empty? ? count : lead.to_i, bracket]
27
- end
28
-
29
- # Parses the input string as YAML, if the string matches the YAML document
30
- # specifier (ie it begins with "---\s*\n"). Otherwise returns the string.
31
- #
32
- # str = {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
33
- # Tap::Script.parse_yaml(str) # => {'key' => 'value'}
34
- # Tap::Script.parse_yaml("str") # => "str"
35
- def parse_yaml(str)
36
- str =~ /\A---\s*\n/ ? YAML.load(str) : str
37
- end
38
-
39
- def shift_arg(argv)
40
- index = nil
41
- argv.each_with_index do |arg, i|
42
- if arg !~ /\A-/
43
- index = i
44
- break
45
- end
46
- end
47
- index == nil ? nil : argv.delete_at(index)
48
- end
49
- end
50
-
51
- ROUND = /\A--(\+(\d+)|\+*)\z/
52
- SEQUENCE = /\A--(\d*(:\d*)+)\z/
53
- FORK = bracket_regexp("[", "]")
54
- MERGE = bracket_regexp("{", "}")
55
- SYNC_MERGE = bracket_regexp("(", ")")
56
- INVALID = /\A--(\z|[^A-Za-z])/
57
-
58
- attr_reader :rounds
59
- attr_reader :sequences
60
- attr_reader :forks
61
- attr_reader :merges
62
- attr_reader :sync_merges
63
-
64
- def initialize(argv)
65
- @sequences = []
66
- @forks = []
67
- @merges = []
68
- @sync_merges = []
69
-
70
- current = []
71
- current_round = []
72
- count = 0
73
- @rounds = [current_round]
74
-
75
- argv.each do |arg|
76
- unless arg =~ INVALID
77
- current << arg
78
- next
79
- end
80
-
81
- # for peformance split to match
82
- # most arguments just once.
83
- current_round << current unless current.empty?
84
- current = []
85
-
86
- case arg
87
- when ROUND
88
- current_round = (@rounds[$2 ? $2.to_i : $1.length] ||= [])
89
- when SEQUENCE
90
- @sequences << Parser.parse_sequence($1, count)
91
- when FORK
92
- @forks << Parser.parse_bracket($1, $2, count)
93
- when MERGE
94
- @merges << Parser.parse_bracket($1, $2, count)
95
- when SYNC_MERGE
96
- @sync_merges << Parser.parse_bracket($1, $2, count)
97
- else
98
- raise ArgumentError, "invalid argument: #{arg}"
99
- end
100
-
101
- count += 1
102
- end
103
-
104
- current_round << current unless current.empty?
105
- @rounds.delete_if {|round| round.nil? || round.empty? }
106
- end
107
-
108
- def targets
109
- targets = []
110
- sequences.each {|sequence| targets.concat(sequence[1..-1]) }
111
- forks.each {|fork| targets.concat(fork[1]) }
112
- targets.concat merges.collect {|target, sources| target }
113
- targets.concat sync_merges.collect {|target, sources| target }
114
-
115
- targets.uniq.sort
116
- end
117
-
118
- end
119
- end
120
- end
121
- end
@@ -1,83 +0,0 @@
1
- require 'tap/support/batchable'
2
- require 'tap/support/executable'
3
- require 'tap/support/framework_class'
4
-
5
- module Tap
6
- module Support
7
-
8
- # Framework encapsulates the basic framework functionality (batching,
9
- # configuration, documentation, etc) used by Task and Workflow. Note
10
- # that Framework does NOT encapsulate the functionality needed to
11
- # make a class useful in workflows, such as enq and on_complete.
12
- module Framework
13
- include Batchable
14
- include Configurable
15
-
16
- def self.included(mod)
17
- mod.extend Support::BatchableClass
18
- mod.extend Support::ConfigurableClass
19
- mod.extend Support::FrameworkClass
20
- mod.lazy_attr :manifest
21
- mod.lazy_attr :args
22
- end
23
-
24
- # The application used to load config_file templates
25
- # (and hence, to initialize batched objects).
26
- attr_reader :app
27
-
28
- # The name of self.
29
- #--
30
- # Currently names may be any object. Audit makes use of name
31
- # via to_s, as does app when figuring configuration filepaths.
32
- attr_accessor :name
33
-
34
- # Initializes a new instance and associated batch objects. Batch
35
- # objects will be initialized for each configuration template
36
- # specified by app.each_config_template(config_file) where
37
- # config_file = app.config_filepath(name).
38
- def initialize(config={}, name=nil, app=App.instance)
39
- super()
40
- @app = app
41
- @name = name || self.class.default_name
42
-
43
- case config
44
- when InstanceConfiguration
45
- @config = config
46
- config.bind(self)
47
- else
48
- initialize_config(config)
49
- end
50
- end
51
-
52
- # Creates a new batched object and adds the object to batch. The batched object
53
- # will be a duplicate of the current object but with a new name and/or
54
- # configurations.
55
- def initialize_batch_obj(overrides={}, name=nil)
56
- obj = super().reconfigure(overrides)
57
- obj.name = name if name
58
- obj
59
- end
60
-
61
- # Logs the inputs to the application logger (via app.log)
62
- def log(action, msg="", level=Logger::INFO)
63
- # TODO - add a task identifier?
64
- app.log(action, msg, level)
65
- end
66
-
67
- # Raises a TerminateError if app.state == State::TERMINATE.
68
- # check_terminate may be called at any time to provide a
69
- # breakpoint in long-running processes.
70
- def check_terminate
71
- if app.state == App::State::TERMINATE
72
- raise App::TerminateError.new
73
- end
74
- end
75
-
76
- # Returns self.name
77
- def to_s
78
- name.to_s
79
- end
80
-
81
- end
82
- end
83
- end