rbbt-util 5.1.0 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.rdoc +2 -2
- data/bin/rbbt +45 -0
- data/bin/rbbt_dangling_locks.rb +9 -0
- data/bin/rbbt_monitor.rb +12 -10
- data/bin/run_workflow.rb +80 -18
- data/lib/rbbt.rb +1 -1
- data/lib/rbbt/annotations.rb +1 -19
- data/lib/rbbt/annotations/annotated_array.rb +23 -0
- data/lib/rbbt/fix_width_table.rb +2 -2
- data/lib/rbbt/persist.rb +13 -5
- data/lib/rbbt/persist/tsv.rb +2 -0
- data/lib/rbbt/resource.rb +4 -4
- data/lib/rbbt/resource/path.rb +35 -10
- data/lib/rbbt/resource/util.rb +54 -47
- data/lib/rbbt/tsv.rb +17 -15
- data/lib/rbbt/tsv/accessor.rb +35 -37
- data/lib/rbbt/tsv/excel.rb +3 -1
- data/lib/rbbt/tsv/manipulate.rb +27 -4
- data/lib/rbbt/tsv/parser.rb +13 -7
- data/lib/rbbt/util/R.rb +11 -1
- data/lib/rbbt/util/misc.rb +182 -26
- data/lib/rbbt/util/named_array.rb +14 -7
- data/lib/rbbt/util/open.rb +2 -1
- data/lib/rbbt/util/tmpfile.rb +16 -1
- data/lib/rbbt/workflow.rb +63 -101
- data/lib/rbbt/workflow/accessor.rb +19 -9
- data/lib/rbbt/workflow/annotate.rb +33 -64
- data/lib/rbbt/workflow/definition.rb +71 -0
- data/lib/rbbt/workflow/soap.rb +15 -5
- data/lib/rbbt/workflow/step.rb +57 -8
- data/lib/rbbt/workflow/usage.rb +72 -0
- data/share/lib/R/util.R +12 -0
- data/share/rbbt_commands/conf/web_user/add +26 -0
- data/share/rbbt_commands/conf/web_user/list +9 -0
- data/share/rbbt_commands/conf/web_user/remove +18 -0
- data/share/rbbt_commands/workflow/remote/add +11 -0
- data/share/rbbt_commands/workflow/remote/list +9 -0
- data/share/rbbt_commands/workflow/remote/remove +9 -0
- data/share/rbbt_commands/workflow/task +181 -0
- data/test/rbbt/test_resource.rb +2 -1
- data/test/rbbt/test_workflow.rb +13 -0
- data/test/rbbt/tsv/test_manipulate.rb +18 -0
- data/test/rbbt/util/test_misc.rb +19 -39
- data/test/rbbt/util/test_tmpfile.rb +8 -0
- data/test/rbbt/workflow/test_soap.rb +2 -0
- metadata +31 -2
@@ -8,35 +8,42 @@ module NamedArray
|
|
8
8
|
attr_accessor :fields
|
9
9
|
attr_accessor :key
|
10
10
|
attr_accessor :entity_options
|
11
|
+
attr_accessor :entity_templates
|
11
12
|
|
12
|
-
def
|
13
|
+
def entity_templates
|
14
|
+
@entity_templates ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.setup(array, fields, key = nil, entity_options = nil, entity_templates = nil)
|
13
18
|
array.extend NamedArray unless NamedArray === array
|
14
19
|
array.fields = fields
|
15
20
|
array.key = key
|
16
|
-
array.entity_options = entity_options
|
21
|
+
array.entity_options = entity_options unless entity_options.nil?
|
22
|
+
array.entity_templates = entity_templates unless entity_templates.nil?
|
17
23
|
array
|
18
24
|
end
|
19
25
|
|
20
26
|
def prepare_entity(entity, field, options = {})
|
21
27
|
return entity if entity.nil?
|
22
28
|
return entity unless defined? Entity
|
23
|
-
|
24
|
-
|
29
|
+
template = entity_templates[field]
|
30
|
+
entity_templates ||= {}
|
31
|
+
if template
|
25
32
|
entity = template.annotate(entity.frozen? ? entity.dup : entity)
|
26
33
|
entity.extend AnnotatedArray if Array === entity
|
27
34
|
entity
|
28
35
|
else
|
29
|
-
if
|
36
|
+
if entity_templates.include? field
|
30
37
|
entity
|
31
38
|
else
|
32
39
|
template = Misc.prepare_entity("TEMPLATE", field, options)
|
33
40
|
if Annotated === template
|
34
|
-
|
41
|
+
entity_templates[field] = template
|
35
42
|
entity = template.annotate(entity.frozen? ? entity.dup : entity)
|
36
43
|
entity.extend AnnotatedArray if Array === entity
|
37
44
|
entity
|
38
45
|
else
|
39
|
-
|
46
|
+
entity_templates[field] = nil
|
40
47
|
entity
|
41
48
|
end
|
42
49
|
end
|
data/lib/rbbt/util/open.rb
CHANGED
@@ -180,6 +180,7 @@ module Open
|
|
180
180
|
end
|
181
181
|
|
182
182
|
def self.open(url, options = {})
|
183
|
+
return url if IO === url
|
183
184
|
options = Misc.add_defaults options, :noz => false, :mode => 'r'
|
184
185
|
|
185
186
|
mode = Misc.process_options options, :mode
|
@@ -283,7 +284,7 @@ module Open
|
|
283
284
|
f.flock(File::LOCK_UN)
|
284
285
|
end
|
285
286
|
rescue Exception
|
286
|
-
FileUtils.
|
287
|
+
FileUtils.rm_rf file if File.exists? file
|
287
288
|
raise $!
|
288
289
|
end
|
289
290
|
content.close
|
data/lib/rbbt/util/tmpfile.rb
CHANGED
@@ -28,8 +28,11 @@ module TmpFile
|
|
28
28
|
File.join(TMPDIR, random_name(s,max))
|
29
29
|
end
|
30
30
|
|
31
|
-
def self.with_file(content = nil, erase = true)
|
31
|
+
def self.with_file(content = nil, erase = true, options = {})
|
32
32
|
tmpfile = tmp_file
|
33
|
+
if options[:extension]
|
34
|
+
tmpfile += ".#{options[:extension]}"
|
35
|
+
end
|
33
36
|
|
34
37
|
File.open(tmpfile, 'w') do |f| f.write content end if content != nil
|
35
38
|
|
@@ -39,4 +42,16 @@ module TmpFile
|
|
39
42
|
|
40
43
|
result
|
41
44
|
end
|
45
|
+
|
46
|
+
def self.with_dir(erase = true, options = {})
|
47
|
+
tmpdir = tmp_file
|
48
|
+
|
49
|
+
FileUtils.mkdir_p tmpdir
|
50
|
+
|
51
|
+
result = yield(tmpdir)
|
52
|
+
|
53
|
+
FileUtils.rm_rf tmpdir if File.exists?(tmpdir) and erase
|
54
|
+
|
55
|
+
result
|
56
|
+
end
|
42
57
|
end
|
data/lib/rbbt/workflow.rb
CHANGED
@@ -1,14 +1,33 @@
|
|
1
|
+
require 'rbbt/workflow/definition'
|
1
2
|
require 'rbbt/workflow/task'
|
2
3
|
require 'rbbt/workflow/step'
|
3
|
-
require 'rbbt/workflow/annotate'
|
4
4
|
require 'rbbt/workflow/accessor'
|
5
5
|
|
6
6
|
module Workflow
|
7
|
+
def self.resolve_locals(inputs)
|
8
|
+
inputs.each do |name, value|
|
9
|
+
if value =~ /^local:(.*?):(.*)/ or
|
10
|
+
(Array === value and value.length == 1 and value.first =~ /^local:(.*?):(.*)/) or
|
11
|
+
(TSV === value and value.size == 1 and value.keys.first =~ /^local:(.*?):(.*)/)
|
12
|
+
task_name = $1
|
13
|
+
jobname = $2
|
14
|
+
value = load_id(File.join(task_name, jobname)).load
|
15
|
+
end
|
16
|
+
inputs[name] = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#{{{ WORKFLOW MANAGEMENT
|
7
21
|
class << self
|
8
22
|
attr_accessor :workflows
|
9
23
|
end
|
10
24
|
self.workflows = []
|
11
25
|
|
26
|
+
def self.extended(base)
|
27
|
+
self.workflows << base
|
28
|
+
base.libdir = Path.caller_lib_dir.tap{|p| p.resource = base}
|
29
|
+
end
|
30
|
+
|
12
31
|
def self.require_remote_workflow(wf_name, url)
|
13
32
|
require 'rbbt/workflow/rest/client'
|
14
33
|
eval "Object::#{wf_name} = RbbtRestClient.new '#{ url }', '#{wf_name}'"
|
@@ -95,10 +114,10 @@ module Workflow
|
|
95
114
|
rescue Exception
|
96
115
|
Log.debug $!.message
|
97
116
|
Log.debug $!.backtrace.first
|
98
|
-
raise "Workflow not found: #{ wf_name }" if wf_name == Misc.
|
99
|
-
Log.debug "Trying with humanized: '#{Misc.
|
117
|
+
raise "Workflow not found: #{ wf_name }" if wf_name == Misc.snake_case(wf_name)
|
118
|
+
Log.debug "Trying with humanized: '#{Misc.snake_case wf_name}'"
|
100
119
|
begin
|
101
|
-
require_local_workflow(Misc.
|
120
|
+
require_local_workflow(Misc.snake_case(wf_name))
|
102
121
|
rescue Exception
|
103
122
|
Log.debug $!.message
|
104
123
|
raise "Workflow not found: #{ wf_name }"
|
@@ -106,121 +125,65 @@ module Workflow
|
|
106
125
|
end
|
107
126
|
end
|
108
127
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
attr_accessor :libdir, :workdir, :tasks, :task_dependencies, :task_description, :dependencies, :asynchronous_exports, :synchronous_exports, :exec_exports, :last_task
|
114
|
-
|
115
|
-
alias prev_workflow_extended extended if methods.include? "extended"
|
116
|
-
|
117
|
-
def extended(object)
|
118
|
-
self.send(:prev_workflow_extended, object) if methods.include? "prev_workflow_extended"
|
119
|
-
object.extend Workflow unless Workflow === object
|
120
|
-
|
121
|
-
object.tasks.merge! self.tasks
|
122
|
-
object.task_dependencies.merge! self.task_dependencies
|
123
|
-
end
|
124
|
-
|
125
|
-
def dependencies
|
126
|
-
i = @dependencies; @dependencies = []; i
|
127
|
-
end
|
128
|
-
|
129
|
-
def task_dependencies
|
130
|
-
IndiferentHash.setup(@task_dependencies || {})
|
131
|
-
end
|
132
|
-
|
133
|
-
def tasks
|
134
|
-
IndiferentHash.setup(@tasks || {})
|
135
|
-
end
|
136
|
-
end
|
128
|
+
attr_accessor :libdir, :workdir
|
129
|
+
attr_accessor :helpers, :tasks
|
130
|
+
attr_accessor :task_dependencies, :task_description, :last_task
|
131
|
+
attr_accessor :asynchronous_exports, :synchronous_exports, :exec_exports
|
137
132
|
|
138
|
-
|
139
|
-
base.workdir = Rbbt.var.jobs.find
|
140
|
-
else
|
141
|
-
base.workdir = Path.setup('var/jobs')
|
142
|
-
end
|
143
|
-
base.tasks = {}
|
144
|
-
base.dependencies = []
|
145
|
-
base.task_dependencies = {}
|
146
|
-
base.task_description = {}
|
147
|
-
base.asynchronous_exports = []
|
148
|
-
base.synchronous_exports = []
|
149
|
-
base.exec_exports = []
|
150
|
-
base.libdir = Path.caller_lib_dir
|
151
|
-
end
|
152
|
-
self.workflows << base
|
153
|
-
end
|
133
|
+
#{{{ ATTR DEFAULTS
|
154
134
|
|
155
|
-
|
135
|
+
def workdir
|
136
|
+
@workdir ||= if defined? Rbbt
|
137
|
+
Rbbt.var.jobs[self].find
|
138
|
+
else
|
139
|
+
Path.setup('var/jobs')
|
140
|
+
end
|
141
|
+
end
|
156
142
|
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
else
|
162
|
-
result_type = :marshal
|
163
|
-
end
|
143
|
+
def libdir
|
144
|
+
@libdir = Path.caller_lib_dir if @libdir.nil?
|
145
|
+
@libdir
|
146
|
+
end
|
164
147
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
result_type = result_type
|
170
|
-
annotations = {
|
171
|
-
:name => name,
|
172
|
-
:inputs => inputs,
|
173
|
-
:description => description,
|
174
|
-
:input_types => input_types,
|
175
|
-
:result_type => Array == result_type ? result_type.to_sym : result_type,
|
176
|
-
:input_defaults => input_defaults,
|
177
|
-
:input_descriptions => input_descriptions,
|
178
|
-
:input_options => input_options,
|
179
|
-
:result_description => result_description
|
180
|
-
}
|
181
|
-
|
182
|
-
task = Task.setup(annotations, &block)
|
148
|
+
def helpers
|
149
|
+
@helpers ||= {}
|
150
|
+
end
|
183
151
|
|
184
|
-
|
185
|
-
@tasks
|
186
|
-
@task_dependencies[name] = dependencies
|
152
|
+
def tasks
|
153
|
+
@tasks ||= {}
|
187
154
|
end
|
188
155
|
|
189
|
-
def
|
190
|
-
@
|
156
|
+
def task_dependencies
|
157
|
+
@task_dependencies ||= {}
|
191
158
|
end
|
192
159
|
|
193
|
-
def
|
194
|
-
@
|
160
|
+
def task_description
|
161
|
+
@task_description ||= {}
|
195
162
|
end
|
196
163
|
|
197
|
-
def
|
198
|
-
@
|
164
|
+
def asynchronous_exports
|
165
|
+
@asynchronous_exports ||= []
|
199
166
|
end
|
200
167
|
|
201
|
-
|
168
|
+
def synchronous_exports
|
169
|
+
@synchronous_exports ||= []
|
170
|
+
end
|
202
171
|
|
203
|
-
def
|
204
|
-
|
205
|
-
if value =~ /^local:(.*?):(.*)/ or
|
206
|
-
(Array === value and value.length == 1 and value.first =~ /^local:(.*?):(.*)/) or
|
207
|
-
(TSV === value and value.size == 1 and value.keys.first =~ /^local:(.*?):(.*)/)
|
208
|
-
task_name = $1
|
209
|
-
jobname = $2
|
210
|
-
value = load_id(File.join(task_name, jobname)).load
|
211
|
-
end
|
212
|
-
inputs[name] = value
|
213
|
-
end
|
172
|
+
def exec_exports
|
173
|
+
@exec_exports ||= []
|
214
174
|
end
|
215
175
|
|
176
|
+
# {{{ JOB MANAGEMENT
|
177
|
+
|
216
178
|
def job(taskname, jobname = nil, inputs = {})
|
179
|
+
taskname = taskname.to_sym
|
217
180
|
jobname = "Default" if jobname.nil? or jobname.empty?
|
218
181
|
task = tasks[taskname]
|
219
182
|
raise "Task not found: #{ taskname }" if task.nil?
|
220
183
|
|
221
184
|
IndiferentHash.setup(inputs)
|
222
185
|
|
223
|
-
resolve_locals(inputs)
|
186
|
+
Workflow.resolve_locals(inputs)
|
224
187
|
|
225
188
|
dependencies = real_dependencies(task, jobname, inputs, task_dependencies[taskname] || [])
|
226
189
|
|
@@ -230,9 +193,8 @@ module Workflow
|
|
230
193
|
|
231
194
|
step = Step.new step_path, task, input_values, dependencies
|
232
195
|
|
233
|
-
helpers
|
234
|
-
|
235
|
-
helpers.each do |name, block|
|
196
|
+
helpers.each do |name, block|
|
197
|
+
(class << step; self; end).instance_eval do
|
236
198
|
define_method name, &block
|
237
199
|
end
|
238
200
|
end
|
@@ -242,13 +204,13 @@ module Workflow
|
|
242
204
|
|
243
205
|
def load_step(path)
|
244
206
|
task = task_for path
|
245
|
-
Step.new path, tasks[task]
|
207
|
+
Step.new path, tasks[task.to_sym]
|
246
208
|
end
|
247
209
|
|
248
210
|
def load_id(id)
|
249
211
|
path = File.join(workdir, id)
|
250
212
|
task = task_for path
|
251
|
-
step = Step.new path, tasks[task]
|
213
|
+
step = Step.new path, tasks[task.to_sym]
|
252
214
|
if step.info.include? :dependencies
|
253
215
|
step.dependencies = step.info[:dependencies].collect do |task, job|
|
254
216
|
load_id(File.join(task.to_s, job))
|
@@ -11,6 +11,10 @@ class Step
|
|
11
11
|
name.sub(/(.*)_.*/, '\1')
|
12
12
|
end
|
13
13
|
|
14
|
+
def task_name
|
15
|
+
@task_name ||= task.name
|
16
|
+
end
|
17
|
+
|
14
18
|
# {{{ INFO
|
15
19
|
|
16
20
|
def info_file
|
@@ -71,8 +75,13 @@ class Step
|
|
71
75
|
end
|
72
76
|
|
73
77
|
def done?
|
74
|
-
|
75
|
-
|
78
|
+
path.exists?
|
79
|
+
end
|
80
|
+
|
81
|
+
def running?
|
82
|
+
return nil if not File.exists? info_file
|
83
|
+
return nil if info[:pid].nil?
|
84
|
+
return Misc.pid_exists? info[:pid]
|
76
85
|
end
|
77
86
|
|
78
87
|
def error?
|
@@ -166,6 +175,7 @@ module Workflow
|
|
166
175
|
end
|
167
176
|
|
168
177
|
def task_info(name)
|
178
|
+
name = name.to_sym
|
169
179
|
task = tasks[name]
|
170
180
|
description = task.description
|
171
181
|
result_description = task.result_description
|
@@ -187,7 +197,7 @@ module Workflow
|
|
187
197
|
end
|
188
198
|
|
189
199
|
|
190
|
-
dependencies =
|
200
|
+
dependencies = task_dependencies[name].select{|dep| String === dep or Symbol === dep}
|
191
201
|
{ :id => File.join(self.to_s, name.to_s),
|
192
202
|
:description => description,
|
193
203
|
:export => export,
|
@@ -213,23 +223,23 @@ module Workflow
|
|
213
223
|
end
|
214
224
|
|
215
225
|
def rec_inputs(taskname)
|
216
|
-
[taskname].concat(rec_dependencies(taskname)).inject([]){|acc, tn| acc.concat tasks[tn].inputs}
|
226
|
+
[taskname].concat(rec_dependencies(taskname)).inject([]){|acc, tn| acc.concat tasks[tn.to_sym].inputs}
|
217
227
|
end
|
218
228
|
|
219
229
|
def rec_input_defaults(taskname)
|
220
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn].input_defaults}
|
230
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_defaults}
|
221
231
|
end
|
222
232
|
|
223
233
|
def rec_input_types(taskname)
|
224
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn].input_types}
|
234
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_types}
|
225
235
|
end
|
226
236
|
|
227
237
|
def rec_input_descriptions(taskname)
|
228
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn].input_descriptions}
|
238
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_descriptions}
|
229
239
|
end
|
230
240
|
|
231
241
|
def rec_input_options(taskname)
|
232
|
-
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn].input_options}
|
242
|
+
[taskname].concat(rec_dependencies(taskname)).inject({}){|acc, tn| acc.merge tasks[tn.to_sym].input_options}
|
233
243
|
end
|
234
244
|
|
235
245
|
|
@@ -240,7 +250,7 @@ module Workflow
|
|
240
250
|
when Step === dependency
|
241
251
|
dependency
|
242
252
|
when Symbol === dependency
|
243
|
-
job
|
253
|
+
job(dependency, jobname, inputs)
|
244
254
|
when Proc === dependency
|
245
255
|
dependency.call jobname, inputs
|
246
256
|
end
|
@@ -1,79 +1,48 @@
|
|
1
1
|
module AnnotatedModule
|
2
|
-
def self.extended(base)
|
3
|
-
if not base.respond_to? :inputs
|
4
|
-
class << base
|
5
|
-
attr_accessor :description, :inputs, :input_types, :input_descriptions, :input_defaults, :input_options, :result_description, :helpers
|
6
2
|
|
7
|
-
|
8
|
-
|
3
|
+
def self.add_consummable_annotation(target, *annotations)
|
4
|
+
if annotations.length == 1 and Hash === annotations.first
|
5
|
+
annotations.first.each do |annotation, default|
|
6
|
+
target.send(:attr_accessor, annotation)
|
7
|
+
target.send(:define_method, "consume_#{annotation}") do
|
8
|
+
value = instance_variable_get("@#{annotation}") || default.dup
|
9
|
+
instance_variable_set("@#{annotation}", default.dup)
|
10
|
+
value
|
9
11
|
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def input_descriptions
|
20
|
-
i = @input_descriptions; @input_descriptions = {}; i
|
21
|
-
end
|
22
|
-
|
23
|
-
def input_defaults
|
24
|
-
i = @input_defaults; @input_defaults = {}; i
|
25
|
-
end
|
26
|
-
|
27
|
-
def input_options
|
28
|
-
i = @input_options; @input_options = {}; i
|
29
|
-
end
|
30
|
-
|
31
|
-
def description
|
32
|
-
i = @description; @description = ""; i
|
33
|
-
end
|
34
|
-
|
35
|
-
def result_description
|
36
|
-
i = @result_description; @result_description = nil; i
|
12
|
+
end
|
13
|
+
else
|
14
|
+
annotations.each do |annotation|
|
15
|
+
target.send(:attr_accessor, annotation)
|
16
|
+
target.send(:define_method, "consume_#{annotation}") do
|
17
|
+
value = instance_variable_get("@#{annotation}")
|
18
|
+
instance_variable_set("@#{annotation}", nil)
|
37
19
|
end
|
38
20
|
end
|
39
|
-
|
40
|
-
base.description = ""
|
41
|
-
base.inputs = []
|
42
|
-
base.input_types = {}
|
43
|
-
base.input_descriptions = {}
|
44
|
-
base.input_defaults = {}
|
45
|
-
base.input_options = {}
|
46
|
-
base.helpers = {}
|
47
|
-
|
48
21
|
end
|
49
22
|
end
|
50
23
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
def desc(description)
|
60
|
-
@description = description
|
61
|
-
end
|
62
|
-
|
63
|
-
def dep(*dependencies, &block)
|
64
|
-
dependencies << block if block_given?
|
65
|
-
@dependencies.concat dependencies
|
66
|
-
end
|
24
|
+
add_consummable_annotation(self,
|
25
|
+
:description => "",
|
26
|
+
:inputs => [],
|
27
|
+
:input_types => {},
|
28
|
+
:input_descriptions => {},
|
29
|
+
:input_defaults => {},
|
30
|
+
:input_options => {})
|
67
31
|
|
68
32
|
def input(name, type = nil, desc = nil, default = nil, options = nil)
|
69
33
|
name = name.to_sym
|
70
34
|
type = type.to_sym
|
71
|
-
|
72
|
-
@
|
35
|
+
|
36
|
+
@inputs = [] if @inputs.nil?
|
37
|
+
@input_types = {} if @input_types.nil?
|
38
|
+
@input_descriptions = {} if @input_descriptions.nil?
|
39
|
+
@input_defaults = {} if @input_defaults.nil?
|
40
|
+
@input_options = {} if @input_options.nil?
|
41
|
+
|
42
|
+
@inputs << name
|
43
|
+
@input_types[name] = type unless type.nil?
|
73
44
|
@input_descriptions[name] = desc unless desc.nil?
|
74
|
-
@input_defaults[name]
|
75
|
-
@input_options[name]
|
45
|
+
@input_defaults[name] = default unless default.nil?
|
46
|
+
@input_options[name] = options unless options.nil?
|
76
47
|
end
|
77
48
|
end
|
78
|
-
|
79
|
-
|