rbbt-util 3.2.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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