rbbt-util 3.2.1 → 4.0.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 (85) hide show
  1. data/README.rdoc +65 -0
  2. data/bin/run_workflow.rb +142 -69
  3. data/lib/rbbt-util.rb +3 -3
  4. data/lib/rbbt.rb +12 -3
  5. data/lib/rbbt/annotations.rb +215 -0
  6. data/lib/rbbt/{util/fix_width_table.rb → fix_width_table.rb} +17 -13
  7. data/lib/rbbt/persist.rb +164 -0
  8. data/lib/rbbt/persist/tsv.rb +135 -0
  9. data/lib/rbbt/resource.rb +100 -0
  10. data/lib/rbbt/resource/path.rb +180 -0
  11. data/lib/rbbt/resource/rake.rb +48 -0
  12. data/lib/rbbt/resource/util.rb +111 -0
  13. data/lib/rbbt/resource/with_key.rb +28 -0
  14. data/lib/rbbt/tsv.rb +134 -0
  15. data/lib/rbbt/tsv/accessor.rb +345 -0
  16. data/lib/rbbt/tsv/attach.rb +183 -0
  17. data/lib/rbbt/tsv/attach/util.rb +277 -0
  18. data/lib/rbbt/{util/tsv/filters.rb → tsv/filter.rb} +76 -37
  19. data/lib/rbbt/tsv/index.rb +453 -0
  20. data/lib/rbbt/tsv/manipulate.rb +361 -0
  21. data/lib/rbbt/tsv/parser.rb +231 -0
  22. data/lib/rbbt/tsv/serializers.rb +79 -0
  23. data/lib/rbbt/tsv/util.rb +67 -0
  24. data/lib/rbbt/util/R.rb +3 -3
  25. data/lib/rbbt/util/chain_methods.rb +64 -0
  26. data/lib/rbbt/util/cmd.rb +17 -13
  27. data/lib/rbbt/util/excel2tsv.rb +4 -3
  28. data/lib/rbbt/util/log.rb +1 -0
  29. data/lib/rbbt/util/misc.rb +296 -285
  30. data/lib/rbbt/util/open.rb +9 -2
  31. data/lib/rbbt/util/persistence.rb +1 -1
  32. data/lib/rbbt/util/task/job.rb +3 -1
  33. data/lib/rbbt/workflow.rb +193 -0
  34. data/lib/rbbt/workflow/accessor.rb +249 -0
  35. data/lib/rbbt/workflow/annotate.rb +60 -0
  36. data/lib/rbbt/workflow/soap.rb +100 -0
  37. data/lib/rbbt/workflow/step.rb +102 -0
  38. data/lib/rbbt/workflow/task.rb +76 -0
  39. data/test/rbbt/resource/test_path.rb +12 -0
  40. data/test/rbbt/test_annotations.rb +106 -0
  41. data/test/rbbt/{util/test_fix_width_table.rb → test_fix_width_table.rb} +8 -9
  42. data/test/rbbt/test_resource.rb +66 -0
  43. data/test/rbbt/test_tsv.rb +332 -0
  44. data/test/rbbt/test_workflow.rb +102 -0
  45. data/test/rbbt/tsv/test_accessor.rb +163 -0
  46. data/test/rbbt/{util/tsv → tsv}/test_attach.rb +86 -43
  47. data/test/rbbt/{util/tsv/test_filters.rb → tsv/test_filter.rb} +31 -13
  48. data/test/rbbt/tsv/test_index.rb +284 -0
  49. data/test/rbbt/{util/tsv → tsv}/test_manipulate.rb +35 -105
  50. data/test/rbbt/util/test_R.rb +1 -1
  51. data/test/rbbt/util/test_chain_methods.rb +22 -0
  52. data/test/rbbt/util/test_filecache.rb +0 -1
  53. data/test/rbbt/util/test_misc.rb +97 -79
  54. data/test/rbbt/util/test_open.rb +1 -0
  55. data/test/rbbt/util/test_tmpfile.rb +1 -1
  56. data/test/rbbt/workflow/test_soap.rb +103 -0
  57. data/test/rbbt/workflow/test_step.rb +142 -0
  58. data/test/rbbt/workflow/test_task.rb +84 -0
  59. data/test/test_helper.rb +7 -7
  60. metadata +80 -54
  61. data/lib/rbbt/util/rake.rb +0 -176
  62. data/lib/rbbt/util/resource.rb +0 -355
  63. data/lib/rbbt/util/task.rb +0 -183
  64. data/lib/rbbt/util/tc_hash.rb +0 -324
  65. data/lib/rbbt/util/tsv.rb +0 -236
  66. data/lib/rbbt/util/tsv/accessor.rb +0 -312
  67. data/lib/rbbt/util/tsv/attach.rb +0 -416
  68. data/lib/rbbt/util/tsv/index.rb +0 -419
  69. data/lib/rbbt/util/tsv/manipulate.rb +0 -300
  70. data/lib/rbbt/util/tsv/misc.rb +0 -41
  71. data/lib/rbbt/util/tsv/parse.rb +0 -324
  72. data/lib/rbbt/util/tsv/resource.rb +0 -88
  73. data/lib/rbbt/util/workflow.rb +0 -135
  74. data/lib/rbbt/util/workflow/soap.rb +0 -116
  75. data/test/rbbt/util/test_persistence.rb +0 -201
  76. data/test/rbbt/util/test_rake.rb +0 -54
  77. data/test/rbbt/util/test_resource.rb +0 -77
  78. data/test/rbbt/util/test_task.rb +0 -133
  79. data/test/rbbt/util/test_tc_hash.rb +0 -144
  80. data/test/rbbt/util/test_tsv.rb +0 -221
  81. data/test/rbbt/util/test_workflow.rb +0 -135
  82. data/test/rbbt/util/tsv/test_accessor.rb +0 -150
  83. data/test/rbbt/util/tsv/test_index.rb +0 -241
  84. data/test/rbbt/util/tsv/test_parse.rb +0 -87
  85. data/test/rbbt/util/tsv/test_resource.rb +0 -9
@@ -0,0 +1,60 @@
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
6
+
7
+ def description
8
+ i = @description; @description = ""; i
9
+ end
10
+
11
+ def inputs
12
+ i = @inputs; @inputs = []; i
13
+ end
14
+
15
+ def input_types
16
+ i = @input_types; @input_types = {}; i
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 description
28
+ i = @description; @description = ""; i
29
+ end
30
+ end
31
+
32
+ base.description = ""
33
+ base.inputs = []
34
+ base.input_types = {}
35
+ base.input_descriptions = {}
36
+ base.input_defaults = {}
37
+
38
+ end
39
+ end
40
+
41
+ def desc(description)
42
+ @description = description
43
+ end
44
+
45
+ def dep(*dependencies, &block)
46
+ dependencies << block if block_given?
47
+ @dependencies.concat dependencies
48
+ end
49
+
50
+ def input(name, type = nil, desc = nil, default = nil)
51
+ name = name.to_sym
52
+ type = type.to_sym
53
+ @inputs << name
54
+ @input_types[name] = type unless type.nil?
55
+ @input_descriptions[name] = desc unless desc.nil?
56
+ @input_defaults[name] = default unless default.nil?
57
+ end
58
+ end
59
+
60
+
@@ -0,0 +1,100 @@
1
+ require 'base64'
2
+ require 'simplews'
3
+
4
+ class WorkflowSOAP < SimpleWS
5
+ attr_accessor :workflow
6
+ def job(jobid)
7
+ workdir = @workflow.workdir
8
+ if workdir.respond_to? :find
9
+ workdir_find = workdir.find
10
+ else
11
+ workdir_find = workdir
12
+ end
13
+
14
+ @workflow.load(File.join(workdir_find, jobid))
15
+ end
16
+
17
+ def initialize(workflow, *args)
18
+ super(workflow.to_s,*args)
19
+ @workflow = workflow
20
+ @workflow.synchronous_exports.each do |name| synchronous name end
21
+ @workflow.asynchronous_exports.each do |name| asynchronous name end
22
+
23
+ desc "Job management: Check the status of a job"
24
+ param_desc :jobid => "Job identifier", :return => "Status code. Special status codes are: 'done' and 'error'"
25
+ serve :status, [:jobid], :jobid => :string, :return => :string do |jobid|
26
+ (job(jobid).status || :queued).to_s
27
+ end
28
+
29
+ desc "Job management: Return an array with the messages issued by the job"
30
+ param_desc :jobid => "Job identifier", :return => "Array with message strings"
31
+ serve :messages, ['jobid'], :job => :string, :return => :array do |jobid|
32
+ job(jobid).messages || []
33
+ end
34
+
35
+ desc "Job management: Return a YAML string containing arbitrary information set up by the job"
36
+ param_desc :jobid => "Job identifier", :return => "Hash with arbitrary values in YAML format"
37
+ serve :info, ['jobid'], :jobid => :string, :return => :string do |jobid|
38
+ job(jobid).info.to_yaml
39
+ end
40
+
41
+ desc "Job management: Abort the job"
42
+ param_desc :jobid => "Job identifier"
43
+ serve :abort, %w(jobid), :jobid => :string, :return => false do |jobid|
44
+ job(jobid).abort
45
+ end
46
+
47
+ desc "Job management: Check if the job is done. Could have finished successfully, with error, or have been aborted"
48
+ param_desc :jobid => "Job identifier", :return => "True if the job has status 'done', 'error' or 'aborted'"
49
+ serve :done, %w(jobid), :jobid => :string, :return => :boolean do |jobid|
50
+ [:done, :error, :aborted].include?((job(jobid).status || :queued).to_sym)
51
+ end
52
+
53
+ desc "Job management: Check if the job has finished with error. The last message is the error message"
54
+ param_desc :jobid => "Job identifier", :return => "True if the job has status 'error'"
55
+ serve :error, %w(jobid), :jobid => :string, :return => :boolean do |jobid|
56
+ job(jobid).status.to_sym == :error
57
+ end
58
+
59
+ desc "Job management: Load job result as string "
60
+ param_desc :jobid => "Job identifier", :return => "String containing the result of the job"
61
+ serve :load_string, %w(jobid), :jobid => :string, :return => :string do |jobid|
62
+ job(jobid).load.to_s
63
+ end
64
+ end
65
+
66
+ def synchronous(*tasknames)
67
+ tasknames.each do |name|
68
+ task = @workflow.tasks[name]
69
+ desc @workflow.task_description[name] if @workflow.task_description.include? name
70
+
71
+ rec_inputs = @workflow.rec_inputs name
72
+ rec_input_descriptions= @workflow.rec_input_descriptions name
73
+ rec_input_types= @workflow.rec_input_types name
74
+
75
+ param_desc rec_input_descriptions
76
+ serve name, rec_inputs, rec_input_types, &task
77
+ end
78
+ end
79
+
80
+ def asynchronous(*tasknames)
81
+ tasknames.each do |name|
82
+ task = @workflow.tasks[name]
83
+ desc @workflow.task_description[name] if @workflow.task_description.include? name
84
+
85
+ rec_inputs = @workflow.rec_inputs name
86
+ rec_input_descriptions= @workflow.rec_input_descriptions name
87
+ rec_input_types= @workflow.rec_input_types name
88
+
89
+ param_desc rec_input_descriptions.merge(:suggested_name => "Suggested Name", :return => "Job identifier")
90
+ serve name, [:suggested_name] + rec_inputs, rec_input_types.merge(:suggested_name => :string, :return => :string) do |jobname, *inputs|
91
+ inputs = Hash[*@workflow.rec_inputs(name).zip(inputs).flatten]
92
+
93
+ step = @workflow.job(name, jobname, inputs)
94
+ step.fork
95
+ @workflow.id_for step.path
96
+ end
97
+ end
98
+ end
99
+ end
100
+
@@ -0,0 +1,102 @@
1
+ require 'rbbt/persist'
2
+ require 'rbbt/persist/tsv'
3
+ require 'rbbt/util/log'
4
+ require 'rbbt/workflow/accessor'
5
+
6
+ class Step
7
+ attr_accessor :path, :task, :inputs, :dependencies
8
+ attr_accessor :pid
9
+
10
+ class Aborted < Exception; end
11
+
12
+ def initialize(path, task = nil, inputs = nil, dependencies = nil)
13
+ @path = path
14
+ @task = task
15
+ @dependencies = case
16
+ when dependencies.nil?
17
+ []
18
+ when Array === dependencies
19
+ dependencies
20
+ else
21
+ [dependencies]
22
+ end
23
+ @inputs = inputs || []
24
+ end
25
+
26
+ def exec
27
+ @task.exec_in self, *@inputs
28
+ end
29
+
30
+ def join
31
+ if @pid.nil?
32
+ while not done? do
33
+ Log.debug "Waiting: #{info[:step]}"
34
+ sleep 5
35
+ end
36
+ else
37
+ Process.waitpid @pid
38
+ @pid = nil
39
+ end
40
+ self
41
+ end
42
+
43
+ def run
44
+ Persist.persist "Job", @task.result_type, :file => @path, :check => rec_dependencies.collect{|dependency| dependency.path}.uniq do
45
+ log task.name, "Starting task: #{ name }"
46
+ set_info :dependencies, @dependencies.collect{|dep| [dep.task.name, dep.name]}
47
+ @dependencies.each{|dependency| dependency.run}
48
+ set_info :status, :start
49
+ set_info :inputs, Misc.zip2hash(task.inputs, @inputs) unless task.inputs.nil?
50
+ res = exec
51
+ set_info :status, :done
52
+ res
53
+ end
54
+ end
55
+
56
+ def fork
57
+ raise "Can not fork: Step is waiting for proces #{@pid} to finish" if not @pid.nil?
58
+ @pid = Process.fork do
59
+ begin
60
+ trap(:INT) { raise Step::Aborted.new "INT signal recieved" }
61
+ run
62
+ rescue Exception
63
+ log(:error, "#{$!.class}: #{$!.message}")
64
+ end
65
+ end
66
+ set_info :pid, @pid
67
+ self
68
+ end
69
+
70
+ def abort
71
+ if @pid.nil?
72
+ false
73
+ else
74
+ Process.kill("INT", @pid)
75
+ true
76
+ end
77
+ end
78
+
79
+ def load
80
+ raise "Can not load: Step is waiting for proces #{@pid} to finish" if not done?
81
+ Persist.persist "Job", @task.result_type, :file => @path, :check => rec_dependencies.collect{|dependency| dependency.path} do
82
+ exec
83
+ end
84
+ end
85
+
86
+ def clean
87
+ if File.exists?(path) or File.exists?(info_file)
88
+ begin
89
+ FileUtils.rm info_file
90
+ FileUtils.rm path
91
+ FileUtils.rm_rf files_dir
92
+ end
93
+ end
94
+ end
95
+
96
+ def rec_dependencies
97
+ @dependencies.collect{|step| step.rec_dependencies}.flatten.concat @dependencies
98
+ end
99
+ def step(name)
100
+ rec_dependencies.select{|step| step.task.name.to_sym == name.to_sym}.first
101
+ end
102
+ end
@@ -0,0 +1,76 @@
1
+ require 'rbbt/util/misc'
2
+ require 'rbbt/persist'
3
+
4
+ module Task
5
+ attr_accessor :inputs, :input_types, :result_type, :input_defaults, :input_descriptions, :description, :name
6
+
7
+ def self.setup(options = {}, &block)
8
+ block.extend Task
9
+ options = IndiferentHash.setup options
10
+ block.singleton_methods.
11
+ select{|method| method.to_s[-1] != "="[0]}.each{|method|
12
+ if block.respond_to?(method + "=") and options.include? method.to_sym
13
+ block.send(method + '=', options[method.to_sym])
14
+ end
15
+ }
16
+ block
17
+ end
18
+
19
+ def parse_description
20
+ if description =~ /\n\n/
21
+ short_description, rest = description.match(/(.*?)\n\n(.*)/).values_at 1, 2
22
+ else
23
+ short_description = description
24
+ rest = nil
25
+ end
26
+
27
+ if rest.nil?
28
+ long_description = ""
29
+ end
30
+ end
31
+
32
+ def param_options
33
+ end
34
+
35
+ def take_input_values(input_values)
36
+ return [] if @inputs.nil?
37
+ values = []
38
+ @inputs.each do |input|
39
+ value = input_values[input] ||
40
+ IndiferentHash.setup(@input_defaults || {})[input]
41
+ values << value
42
+ end
43
+ values
44
+ end
45
+
46
+ def exec(*args)
47
+ case
48
+ when (args.length == 1 and not inputs.nil? and inputs.length > 1 and Hash === args.first)
49
+ self.call *take_input_values(IndiferentHash.setup(args.first))
50
+ else
51
+ self.call *args
52
+ end
53
+ end
54
+
55
+ def exec_in(object, *args)
56
+ case
57
+ when (args.length == 1 and not inputs.nil? and inputs.length > 1 and Hash === args.first)
58
+ object.instance_exec *IndiferentHash.setup(args.first).values_at(*inputs), &self
59
+ else
60
+ object.instance_exec *args, &self
61
+ end
62
+ end
63
+
64
+ def persist_exec(filename, *args)
65
+ Persist.persist "Task", @persistence_type, :file => filename do
66
+ exec *args
67
+ end
68
+ end
69
+
70
+ def persist_exec_in(filename, *args)
71
+ Persist.persist "Task", @persistence_type, :file => filename do
72
+ exec_in *args
73
+ end
74
+ end
75
+
76
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../../test_helper')
2
+ require 'rbbt/resource/path'
3
+ require 'rbbt/util/tmpfile'
4
+ require 'test/unit'
5
+
6
+ class TestTSV < Test::Unit::TestCase
7
+
8
+ def test_prev
9
+ path = Path.setup "/tmp"
10
+ assert_equal "/tmp/bar/foo", path.foo("bar")
11
+ end
12
+ end
@@ -0,0 +1,106 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+ require 'rbbt/annotations'
3
+ require 'rbbt/util/tmpfile'
4
+ require 'test/unit'
5
+
6
+ module AnnotatedString
7
+ extend Annotation
8
+ self.annotation :annotation_str
9
+
10
+ def add_annot
11
+ self + annotation_str
12
+ end
13
+ end
14
+
15
+ module AnnotatedString2
16
+ extend Annotation
17
+ include AnnotatedString
18
+ self.annotation :annotation_str2
19
+ end
20
+
21
+ class TestAnnotations < Test::Unit::TestCase
22
+
23
+ def test_annotated_string
24
+ assert_equal %w(annotation_str), AnnotatedString.annotations.collect{|a| a.to_s}
25
+ end
26
+
27
+ def test_string
28
+ str = "string"
29
+ annotation_str = "Annotation String"
30
+ AnnotatedString.setup(str, annotation_str)
31
+ assert_equal [AnnotatedString], str.annotation_types
32
+ assert_equal annotation_str, str.annotation_str
33
+ end
34
+
35
+ def test_array
36
+ ary = ["string"]
37
+ annotation_str = "Annotation String"
38
+ AnnotatedArray.setup_chain(ary)
39
+ AnnotatedString.setup(ary, annotation_str)
40
+ assert_equal [AnnotatedString], ary.annotation_types
41
+ assert_equal annotation_str, ary.annotation_str
42
+ assert_equal annotation_str, ary[0].annotation_str
43
+ end
44
+
45
+ def test_info
46
+ ary = ["string"]
47
+ annotation_str = "Annotation String"
48
+ AnnotatedString.setup(ary, annotation_str)
49
+ assert_equal({:annotation_str => annotation_str, :annotation_types => [AnnotatedString]}, ary.info)
50
+ end
51
+
52
+ def test_load
53
+ str = "string"
54
+ annotation_str = "Annotation String"
55
+ info = {:annotation_str => annotation_str, :annotation_types => [AnnotatedString]}
56
+
57
+ Annotated.load(str, info)
58
+ assert_equal annotation_str, str.annotation_str
59
+ end
60
+
61
+ def test_tsv
62
+ str1 = "string1"
63
+ annotation_str1 = "Annotation String 1"
64
+ str2 = "string2"
65
+ annotation_str2 = "Annotation String 2"
66
+ AnnotatedString.setup(str1, annotation_str1)
67
+ AnnotatedString.setup(str2, annotation_str2)
68
+ assert_equal str1, Annotated.tsv([str1, str2], :all)[str1.id]["literal"]
69
+ assert_equal annotation_str1, Annotated.tsv([str1, str2], :annotation_str, :JSON)[str1.id]["annotation_str"]
70
+ end
71
+
72
+ def test_literal
73
+ str = "string"
74
+ annotation_str = "Annotation String"
75
+ AnnotatedString.setup(str, annotation_str)
76
+ assert_equal ["string"], str.tsv_values("literal")
77
+ end
78
+
79
+ def test_load_tsv
80
+ str1 = "string1"
81
+ annotation_str1 = "Annotation String 1"
82
+ str2 = "string2"
83
+ annotation_str2 = "Annotation String 2"
84
+ AnnotatedString.setup(str1, annotation_str1)
85
+ AnnotatedString.setup(str2, annotation_str2)
86
+ assert_equal annotation_str1, Annotated.load_tsv(Annotated.tsv([str1, str2], :all)).sort.first.annotation_str
87
+ assert_equal str1, Annotated.load_tsv(Annotated.tsv([str1, str2], :literal, :JSON)).sort.first
88
+ end
89
+
90
+ def test_inheritance
91
+ str = "string1"
92
+ annotation_str1 = "Annotation String 1"
93
+ annotation_str2 = "Annotation String 2"
94
+ assert_equal [AnnotatedString], AnnotatedString2.inheritance
95
+ AnnotatedString2.setup(str, annotation_str1, annotation_str2)
96
+ assert_equal annotation_str1, str.annotation_str
97
+ assert_equal annotation_str2, str.annotation_str2
98
+ end
99
+
100
+ def test_annotation_methods
101
+ str = "string"
102
+ annotation_str = "Annotation String"
103
+ AnnotatedString.setup(str, annotation_str)
104
+ assert_equal str + annotation_str, str.add_annot
105
+ end
106
+ end