rbbt-util 4.1.0 → 4.2.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/bin/run_workflow.rb +4 -1
- data/lib/rbbt/annotations.rb +138 -53
- data/lib/rbbt/persist.rb +30 -12
- data/lib/rbbt/persist/tsv.rb +1 -1
- data/lib/rbbt/resource/path.rb +1 -1
- data/lib/rbbt/tsv.rb +7 -1
- data/lib/rbbt/tsv/accessor.rb +21 -16
- data/lib/rbbt/tsv/attach/util.rb +1 -10
- data/lib/rbbt/tsv/manipulate.rb +21 -3
- data/lib/rbbt/tsv/parser.rb +24 -5
- data/lib/rbbt/tsv/util.rb +1 -1
- data/lib/rbbt/util/chain_methods.rb +12 -23
- data/lib/rbbt/util/misc.rb +133 -144
- data/lib/rbbt/util/named_array.rb +113 -0
- data/lib/rbbt/util/open.rb +17 -10
- data/lib/rbbt/workflow/accessor.rb +9 -1
- data/lib/rbbt/workflow/step.rb +9 -7
- data/share/lib/R/util.R +28 -6
- data/test/rbbt/test_annotations.rb +16 -2
- data/test/rbbt/test_persist.rb +37 -1
- data/test/rbbt/test_tsv.rb +12 -0
- data/test/rbbt/tsv/test_attach.rb +1 -1
- data/test/rbbt/util/test_chain_methods.rb +1 -1
- data/test/rbbt/util/test_misc.rb +10 -0
- metadata +5 -4
data/bin/run_workflow.rb
CHANGED
@@ -92,12 +92,15 @@ if options[:server]
|
|
92
92
|
require 'compass'
|
93
93
|
|
94
94
|
Workflow.require_workflow workflow
|
95
|
-
WorkflowREST.add_workflows Workflow.workflows
|
95
|
+
WorkflowREST.add_workflows *Workflow.workflows
|
96
96
|
|
97
97
|
WorkflowREST.setup
|
98
98
|
|
99
99
|
Sinatra::Application.port = options[:port] || 4567
|
100
100
|
Sinatra::Application.run = true
|
101
|
+
if File.exists? workflow
|
102
|
+
Sinatra::Application.views = File.join(File.dirname(workflow), 'www/views')
|
103
|
+
end
|
101
104
|
|
102
105
|
else
|
103
106
|
|
data/lib/rbbt/annotations.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
require 'rbbt/util/misc'
|
1
2
|
require 'rbbt/util/chain_methods'
|
3
|
+
|
2
4
|
require 'json'
|
3
5
|
module Annotated
|
4
6
|
attr_accessor :annotation_types
|
5
7
|
attr_accessor :context
|
6
8
|
attr_accessor :container
|
9
|
+
attr_accessor :container_index
|
7
10
|
|
8
11
|
def self.extended(base)
|
9
12
|
base.annotation_types ||= []
|
@@ -30,53 +33,83 @@ module Annotated
|
|
30
33
|
|
31
34
|
def self.load(object, info)
|
32
35
|
annotation_types = info[:annotation_types]
|
36
|
+
annotation_types = annotation_types.split("+") if String === annotation_types
|
37
|
+
|
33
38
|
annotation_types.each do |mod|
|
34
39
|
mod = Misc.string2const(mod) if String === mod
|
35
|
-
mod.
|
40
|
+
mod.setup(object, *info.values_at(*mod.all_annotations))
|
36
41
|
end
|
37
42
|
|
38
43
|
object
|
39
44
|
end
|
40
45
|
|
41
46
|
def tsv_values(*fields)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
if Array === self and (not AnnotatedArray === self or self.double_array)
|
48
|
+
Misc.zip_fields(self.compact.collect{|e| e.tsv_values(fields)})
|
49
|
+
else
|
50
|
+
fields = fields.flatten
|
51
|
+
info = self.info
|
52
|
+
values = []
|
53
|
+
|
54
|
+
fields.each do |field|
|
55
|
+
values << case
|
56
|
+
when Proc === field
|
57
|
+
field.call(self)
|
58
|
+
when field == "JSON"
|
59
|
+
info.to_json
|
60
|
+
when field == "annotation_types"
|
61
|
+
annotation_types.collect{|t| t.to_s} * "+"
|
62
|
+
when field == "literal array"
|
63
|
+
(self * "|").gsub(/\n|\t/, ' ')
|
64
|
+
when field == "literal"
|
65
|
+
self.gsub(/\n|\t/, ' ')
|
66
|
+
when info.include?(field.to_sym)
|
67
|
+
info.delete(field.to_sym)
|
68
|
+
when self.respond_to?(field)
|
69
|
+
self.send(field)
|
70
|
+
end
|
55
71
|
end
|
72
|
+
|
73
|
+
values
|
56
74
|
end
|
57
|
-
values
|
58
75
|
end
|
59
76
|
|
60
77
|
def self.load_tsv_values(id, values, *fields)
|
61
78
|
fields = fields.flatten
|
62
79
|
info = {}
|
63
80
|
literal_pos = fields.index "literal"
|
81
|
+
literal_array_pos = fields.index "literal array"
|
64
82
|
|
65
|
-
object =
|
66
|
-
|
83
|
+
object = case
|
84
|
+
when literal_pos
|
85
|
+
values[literal_pos]
|
86
|
+
when literal_array_pos
|
87
|
+
values[literal_array_pos].split("|").extend AnnotatedArray
|
67
88
|
else
|
68
|
-
|
69
|
-
v = v.first if Array === v
|
70
|
-
v
|
89
|
+
id.dup
|
71
90
|
end
|
72
91
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
92
|
+
if Array === values
|
93
|
+
Misc.zip_fields(values).collect do |list|
|
94
|
+
fields.each_with_index do |field,i|
|
95
|
+
if field == "JSON"
|
96
|
+
JSON.parse(list[i]).each do |key, value|
|
97
|
+
info[key.to_sym] = value
|
98
|
+
end
|
99
|
+
else
|
100
|
+
info[field.to_sym] = list[i]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
else
|
105
|
+
fields.each_with_index do |field,i|
|
106
|
+
if field == "JSON"
|
107
|
+
JSON.parse(values[i]).each do |key, value|
|
108
|
+
info[key.to_sym] = value
|
109
|
+
end
|
110
|
+
else
|
111
|
+
info[field.to_sym] = values[i]
|
77
112
|
end
|
78
|
-
else
|
79
|
-
info[field.to_sym] = values[i]
|
80
113
|
end
|
81
114
|
end
|
82
115
|
|
@@ -84,44 +117,71 @@ module Annotated
|
|
84
117
|
end
|
85
118
|
|
86
119
|
def self.tsv(annotations, *fields)
|
120
|
+
return nil if annotations.nil?
|
87
121
|
fields = case
|
88
122
|
when ((fields.compact.empty?) and not annotations.empty?)
|
89
|
-
fields = annotations.first.annotations
|
123
|
+
fields = AnnotatedArray === annotations ? annotations.annotations : annotations.first.annotations
|
90
124
|
fields << :annotation_types
|
91
125
|
when (fields == [:literal] and not annotations.empty?)
|
92
|
-
fields = annotations.first.annotations
|
93
126
|
fields << :literal
|
94
127
|
when (fields == [:all] and not annotations.empty?)
|
95
|
-
fields = [:annotation_types] + annotations.first.annotations
|
128
|
+
fields = [:annotation_types] + (Annotated === annotations ? annotations.annotations : annotations.first.annotations)
|
96
129
|
fields << :literal
|
97
130
|
else
|
98
131
|
fields.flatten
|
99
132
|
end
|
133
|
+
|
100
134
|
fields = fields.collect{|f| f.to_s}
|
101
135
|
|
102
|
-
|
136
|
+
fields = fields.collect{|f| ((f == "literal" and AnnotatedArray === annotations) ? "literal array" : f)}
|
103
137
|
|
104
|
-
|
105
|
-
|
138
|
+
case
|
139
|
+
when (Annotated === annotations and not annotations.double_array)
|
140
|
+
tsv = TSV.setup({}, :key_field => "Single", :fields => fields, :type => :list, :unnamed => true)
|
141
|
+
tsv[annotations.id] = annotations.tsv_values(*fields)
|
142
|
+
when Array === annotations
|
143
|
+
tsv = TSV.setup({}, :key_field => "ID", :fields => fields, :type => :list, :unnamed => true)
|
144
|
+
annotations.compact.each do |annotation|
|
145
|
+
tsv[annotation.id] = annotation.tsv_values(*fields)
|
146
|
+
end
|
147
|
+
else
|
148
|
+
raise "Annotations need to be an Array to create TSV"
|
106
149
|
end
|
107
150
|
|
108
151
|
tsv
|
109
152
|
end
|
110
153
|
|
111
154
|
def self.load_tsv(tsv)
|
112
|
-
tsv.
|
113
|
-
|
155
|
+
tsv.with_unnamed do
|
156
|
+
annotated_entities = tsv.collect do |id, values|
|
157
|
+
Annotated.load_tsv_values(id, values, tsv.fields)
|
158
|
+
end
|
159
|
+
|
160
|
+
if tsv.key_field == "Single"
|
161
|
+
annotated_entities.first
|
162
|
+
else
|
163
|
+
annotated_entities[0].annotate annotated_entities unless annotated_entities.empty?
|
164
|
+
end
|
114
165
|
end
|
115
166
|
end
|
116
167
|
|
117
168
|
def make_list
|
118
169
|
new = [self]
|
119
170
|
annotation_types.each do |mod|
|
120
|
-
mod.setup(new, *info.values_at(*mod.
|
171
|
+
mod.setup(new, *info.values_at(*mod.all_annotations))
|
121
172
|
end
|
122
173
|
new.context = self.context
|
123
174
|
new
|
124
175
|
end
|
176
|
+
|
177
|
+
def annotate(object)
|
178
|
+
annotation_types.each do |mod|
|
179
|
+
mod.setup(object, *info.values_at(*mod.annotations))
|
180
|
+
end
|
181
|
+
object.context = self.context
|
182
|
+
object.container = self.container
|
183
|
+
object
|
184
|
+
end
|
125
185
|
end
|
126
186
|
|
127
187
|
|
@@ -145,12 +205,12 @@ module Annotation
|
|
145
205
|
|
146
206
|
def self.extended(object)
|
147
207
|
self.send(:prev_annotation_extended, object)
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
208
|
+
object.extend Annotated unless Annotated == object
|
209
|
+
if not object.annotation_types.include? self
|
210
|
+
object.annotation_types.concat self.inheritance
|
211
|
+
object.annotation_types << self
|
212
|
+
object.annotation_types.uniq!
|
213
|
+
end
|
154
214
|
end
|
155
215
|
|
156
216
|
def self.included(base)
|
@@ -166,7 +226,7 @@ module Annotation
|
|
166
226
|
end
|
167
227
|
|
168
228
|
def update_annotations
|
169
|
-
@all_annotations = all_inheritance.inject([]){|acc,mod| acc.concat mod.
|
229
|
+
@all_annotations = all_inheritance.inject([]){|acc,mod| acc.concat mod.all_annotations}.concat(@annotations)
|
170
230
|
end
|
171
231
|
|
172
232
|
def annotation(*values)
|
@@ -179,14 +239,14 @@ module Annotation
|
|
179
239
|
end
|
180
240
|
|
181
241
|
def setup_info(object, info)
|
182
|
-
object.extend self
|
242
|
+
object.extend self unless self === object
|
183
243
|
all_annotations.each do |annotation|
|
184
244
|
object.send(annotation.to_s + '=', info[annotation])
|
185
245
|
end
|
186
246
|
end
|
187
247
|
|
188
248
|
def setup(object, *values)
|
189
|
-
object.extend self
|
249
|
+
object.extend self unless self === object
|
190
250
|
|
191
251
|
inputs = Misc.positional2hash(all_annotations, *values)
|
192
252
|
inputs.each do |name, value|
|
@@ -195,29 +255,47 @@ module Annotation
|
|
195
255
|
|
196
256
|
object
|
197
257
|
end
|
258
|
+
|
198
259
|
end
|
199
260
|
|
200
261
|
module AnnotatedArray
|
201
262
|
extend ChainMethods
|
202
263
|
self.chain_prefix = :annotated_array
|
203
264
|
|
265
|
+
def double_array
|
266
|
+
AnnotatedArray === self.first
|
267
|
+
end
|
268
|
+
|
269
|
+
def annotated_array_first
|
270
|
+
self[0]
|
271
|
+
end
|
272
|
+
|
273
|
+
def annotated_array_last
|
274
|
+
self[-1]
|
275
|
+
end
|
276
|
+
|
204
277
|
def annotated_array_get_brackets(pos)
|
205
278
|
value = annotated_array_clean_get_brackets(pos)
|
206
279
|
annotation_types.each do |mod|
|
207
|
-
mod.setup(value, *info.values_at(*mod.
|
280
|
+
mod.setup(value, *info.values_at(*mod.all_annotations))
|
208
281
|
end
|
209
282
|
value.context = self.context
|
210
283
|
value.container = self
|
284
|
+
value.container_index = pos
|
211
285
|
value
|
212
286
|
end
|
213
287
|
|
214
288
|
def annotated_array_each
|
289
|
+
i = 0
|
215
290
|
annotated_array_clean_each do |value|
|
291
|
+
value = value.dup if value.frozen?
|
216
292
|
annotation_types.each do |mod|
|
217
293
|
mod.setup(value, info)
|
218
294
|
end
|
219
295
|
value.context = self.context
|
220
296
|
value.container = self
|
297
|
+
value.container_index = i
|
298
|
+
i += 1
|
221
299
|
yield value
|
222
300
|
end
|
223
301
|
end
|
@@ -237,7 +315,7 @@ module AnnotatedArray
|
|
237
315
|
annotated_array_each do |value|
|
238
316
|
res << value if yield(value)
|
239
317
|
end
|
240
|
-
|
318
|
+
|
241
319
|
annotation_types.each do |mod|
|
242
320
|
mod.setup(res, *info.values_at(*mod.annotations))
|
243
321
|
end
|
@@ -252,7 +330,7 @@ module AnnotatedArray
|
|
252
330
|
annotated_array_each do |value|
|
253
331
|
res << value unless yield(value)
|
254
332
|
end
|
255
|
-
|
333
|
+
|
256
334
|
annotation_types.each do |mod|
|
257
335
|
mod.setup(res, *info.values_at(*mod.annotations))
|
258
336
|
end
|
@@ -265,7 +343,7 @@ module AnnotatedArray
|
|
265
343
|
def annotated_array_subset(list)
|
266
344
|
value = (self & list)
|
267
345
|
annotation_types.each do |mod|
|
268
|
-
mod.setup(value, *info.values_at(*mod.
|
346
|
+
mod.setup(value, *info.values_at(*mod.all_annotations))
|
269
347
|
end
|
270
348
|
value.context = self.context
|
271
349
|
value.container = self.container
|
@@ -282,6 +360,18 @@ module AnnotatedArray
|
|
282
360
|
value
|
283
361
|
end
|
284
362
|
|
363
|
+
def annotated_array_compact
|
364
|
+
value = self.annotated_array_clean_compact
|
365
|
+
|
366
|
+
annotation_types.each do |mod|
|
367
|
+
mod.setup(value, *info.values_at(*mod.annotations))
|
368
|
+
end
|
369
|
+
|
370
|
+
value.context = self.context
|
371
|
+
value.container = self.container
|
372
|
+
value
|
373
|
+
end
|
374
|
+
|
285
375
|
def annotated_array_uniq
|
286
376
|
value = self.annotated_array_clean_uniq
|
287
377
|
|
@@ -353,11 +443,6 @@ module AnnotatedArray
|
|
353
443
|
value << e if method.shift
|
354
444
|
end
|
355
445
|
|
356
|
-
#annotation_types.each do |mod|
|
357
|
-
# mod.setup(value, *info.values_at(*mod.annotations))
|
358
|
-
#end
|
359
|
-
#value.context = self.context
|
360
|
-
#value.container = self.container
|
361
446
|
value
|
362
447
|
end
|
363
448
|
end
|
data/lib/rbbt/persist.rb
CHANGED
@@ -10,6 +10,8 @@ module Persist
|
|
10
10
|
CACHEDIR="/tmp/tsv_persistent_cache"
|
11
11
|
FileUtils.mkdir CACHEDIR unless File.exist? CACHEDIR
|
12
12
|
|
13
|
+
MEMORY = {}
|
14
|
+
|
13
15
|
def self.cachedir=(cachedir)
|
14
16
|
CACHEDIR.replace cachedir
|
15
17
|
FileUtils.mkdir_p CACHEDIR unless File.exist? CACHEDIR
|
@@ -62,7 +64,11 @@ module Persist
|
|
62
64
|
persistence_dir = Misc.process_options(persist_options, :dir) || CACHEDIR
|
63
65
|
|
64
66
|
filename = perfile.gsub(/\s/,'_').gsub(/\//,'>')
|
65
|
-
|
67
|
+
clean_options = options
|
68
|
+
clean_options.delete :unnamed
|
69
|
+
clean_options.delete "unnamed"
|
70
|
+
|
71
|
+
options_md5 = Misc.hash2md5 clean_options
|
66
72
|
filename << ":" << options_md5 unless options_md5.empty?
|
67
73
|
|
68
74
|
File.join(persistence_dir, filename)
|
@@ -75,6 +81,8 @@ module Persist
|
|
75
81
|
nil
|
76
82
|
when :boolean
|
77
83
|
TRUE_STRINGS.include? Open.read(path).chomp.strip
|
84
|
+
when :annotations
|
85
|
+
Annotated.load_tsv TSV.open(path)
|
78
86
|
when :tsv
|
79
87
|
TSV.open(path)
|
80
88
|
when :marshal_tsv
|
@@ -104,7 +112,7 @@ module Persist
|
|
104
112
|
|
105
113
|
def self.save_file(path, type, content)
|
106
114
|
|
107
|
-
return if
|
115
|
+
return if content.nil?
|
108
116
|
|
109
117
|
case (type || "nil").to_sym
|
110
118
|
when :nil
|
@@ -116,6 +124,8 @@ module Persist
|
|
116
124
|
Open.write(path, content.file.read)
|
117
125
|
when :tsv
|
118
126
|
Open.write(path, content.to_s)
|
127
|
+
when :annotations
|
128
|
+
Open.write(path, Annotated.tsv(content, :all).to_s)
|
119
129
|
when :string, :text
|
120
130
|
Open.write(path, content)
|
121
131
|
when :array
|
@@ -140,19 +150,27 @@ module Persist
|
|
140
150
|
def self.persist(name, type = nil, persist_options = {})
|
141
151
|
type ||= :marshal
|
142
152
|
persist_options = Misc.add_defaults persist_options, :persist => true
|
153
|
+
other_options = Misc.process_options persist_options, :other
|
143
154
|
|
144
155
|
if persist_options[:persist]
|
145
|
-
path = persistence_path(name, persist_options)
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
156
|
+
path = persistence_path(name, persist_options, other_options || {})
|
157
|
+
|
158
|
+
case type
|
159
|
+
when :memory
|
160
|
+
Persist::MEMORY[path] ||= yield
|
161
|
+
else
|
162
|
+
Misc.lock(path) do
|
163
|
+
if is_persisted?(path, persist_options)
|
164
|
+
Log.debug "Persist up-to-date: #{ path } - #{persist_options.inspect[0..100]}"
|
165
|
+
return nil if persist_options[:no_load]
|
166
|
+
return load_file(path, type)
|
167
|
+
else
|
168
|
+
Log.debug "Persist create: #{ path } - #{persist_options.inspect[0..100]}"
|
169
|
+
end
|
170
|
+
res = yield
|
171
|
+
save_file(path, type, res)
|
172
|
+
res
|
152
173
|
end
|
153
|
-
res = yield
|
154
|
-
save_file(path, type, res)
|
155
|
-
res
|
156
174
|
end
|
157
175
|
else
|
158
176
|
yield
|