scout-gear 7.3.0 → 8.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +44 -16
  3. data/Rakefile +6 -1
  4. data/VERSION +1 -1
  5. data/bin/scout +21 -7
  6. data/doc/lib/scout/path.md +35 -0
  7. data/doc/lib/scout/workflow/task.md +13 -0
  8. data/lib/rbbt-scout.rb +1 -0
  9. data/lib/scout/cmd.rb +24 -25
  10. data/lib/scout/concurrent_stream.rb +59 -39
  11. data/lib/scout/config.rb +1 -1
  12. data/lib/scout/exceptions.rb +10 -0
  13. data/lib/scout/log/color.rb +15 -12
  14. data/lib/scout/log/progress/report.rb +8 -6
  15. data/lib/scout/log/progress/util.rb +61 -54
  16. data/lib/scout/log/progress.rb +1 -1
  17. data/lib/scout/log/trap.rb +107 -0
  18. data/lib/scout/log.rb +115 -52
  19. data/lib/scout/meta_extension.rb +47 -6
  20. data/lib/scout/misc/digest.rb +12 -3
  21. data/lib/scout/misc/format.rb +24 -7
  22. data/lib/scout/misc/insist.rb +1 -1
  23. data/lib/scout/misc/monitor.rb +22 -0
  24. data/lib/scout/misc/system.rb +58 -0
  25. data/lib/scout/named_array.rb +73 -3
  26. data/lib/scout/offsite/ssh.rb +171 -0
  27. data/lib/scout/offsite/step.rb +83 -0
  28. data/lib/scout/offsite/sync.rb +55 -0
  29. data/lib/scout/offsite.rb +3 -0
  30. data/lib/scout/open/lock/lockfile.rb +587 -0
  31. data/lib/scout/open/lock.rb +9 -2
  32. data/lib/scout/open/remote.rb +16 -1
  33. data/lib/scout/open/stream.rb +146 -83
  34. data/lib/scout/open/util.rb +22 -3
  35. data/lib/scout/open.rb +5 -4
  36. data/lib/scout/path/find.rb +24 -11
  37. data/lib/scout/path/util.rb +40 -0
  38. data/lib/scout/persist/serialize.rb +19 -6
  39. data/lib/scout/persist.rb +29 -13
  40. data/lib/scout/resource/path.rb +57 -0
  41. data/lib/scout/resource/produce.rb +0 -8
  42. data/lib/scout/resource/util.rb +12 -5
  43. data/lib/scout/tmpfile.rb +7 -8
  44. data/lib/scout/tsv/attach.rb +177 -0
  45. data/lib/scout/tsv/change_id.rb +40 -0
  46. data/lib/scout/tsv/dumper.rb +74 -46
  47. data/lib/scout/tsv/index.rb +85 -87
  48. data/lib/scout/tsv/open.rb +160 -85
  49. data/lib/scout/tsv/parser.rb +142 -80
  50. data/lib/scout/tsv/path.rb +1 -2
  51. data/lib/scout/tsv/persist/adapter.rb +15 -45
  52. data/lib/scout/tsv/persist/fix_width_table.rb +3 -0
  53. data/lib/scout/tsv/persist/tokyocabinet.rb +6 -1
  54. data/lib/scout/tsv/persist.rb +4 -0
  55. data/lib/scout/tsv/stream.rb +204 -0
  56. data/lib/scout/tsv/transformer.rb +152 -0
  57. data/lib/scout/tsv/traverse.rb +96 -92
  58. data/lib/scout/tsv/util/filter.rb +9 -0
  59. data/lib/scout/tsv/util/reorder.rb +81 -0
  60. data/lib/scout/tsv/util/select.rb +78 -33
  61. data/lib/scout/tsv/util/unzip.rb +86 -0
  62. data/lib/scout/tsv/util.rb +60 -11
  63. data/lib/scout/tsv.rb +34 -4
  64. data/lib/scout/work_queue/socket.rb +6 -1
  65. data/lib/scout/work_queue/worker.rb +5 -2
  66. data/lib/scout/work_queue.rb +51 -20
  67. data/lib/scout/workflow/definition.rb +23 -3
  68. data/lib/scout/workflow/deployment/orchestrator.rb +245 -0
  69. data/lib/scout/workflow/deployment.rb +1 -0
  70. data/lib/scout/workflow/step/dependencies.rb +56 -10
  71. data/lib/scout/workflow/step/file.rb +5 -0
  72. data/lib/scout/workflow/step/info.rb +40 -7
  73. data/lib/scout/workflow/step/load.rb +1 -1
  74. data/lib/scout/workflow/step/provenance.rb +9 -7
  75. data/lib/scout/workflow/step/status.rb +43 -0
  76. data/lib/scout/workflow/step.rb +160 -49
  77. data/lib/scout/workflow/task/dependencies.rb +114 -0
  78. data/lib/scout/workflow/task/inputs.rb +40 -32
  79. data/lib/scout/workflow/task.rb +38 -102
  80. data/lib/scout/workflow/usage.rb +48 -18
  81. data/lib/scout/workflow.rb +4 -2
  82. data/lib/scout-gear.rb +2 -0
  83. data/lib/scout.rb +6 -0
  84. data/scout-gear.gemspec +52 -23
  85. data/scout_commands/doc +37 -0
  86. data/scout_commands/find +1 -0
  87. data/scout_commands/offsite +30 -0
  88. data/scout_commands/update +29 -0
  89. data/scout_commands/workflow/info +15 -3
  90. data/scout_commands/workflow/install +102 -0
  91. data/scout_commands/workflow/task +57 -9
  92. data/test/scout/offsite/test_ssh.rb +15 -0
  93. data/test/scout/offsite/test_step.rb +33 -0
  94. data/test/scout/offsite/test_sync.rb +36 -0
  95. data/test/scout/offsite/test_task.rb +0 -0
  96. data/test/scout/open/test_stream.rb +60 -58
  97. data/test/scout/path/test_find.rb +10 -1
  98. data/test/scout/resource/test_path.rb +6 -0
  99. data/test/scout/resource/test_produce.rb +15 -0
  100. data/test/scout/test_meta_extension.rb +25 -0
  101. data/test/scout/test_named_array.rb +24 -0
  102. data/test/scout/test_persist.rb +9 -2
  103. data/test/scout/test_tsv.rb +229 -2
  104. data/test/scout/test_work_queue.rb +65 -41
  105. data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
  106. data/test/scout/tsv/test_attach.rb +227 -0
  107. data/test/scout/tsv/test_change_id.rb +98 -0
  108. data/test/scout/tsv/test_dumper.rb +1 -1
  109. data/test/scout/tsv/test_index.rb +49 -3
  110. data/test/scout/tsv/test_open.rb +160 -2
  111. data/test/scout/tsv/test_parser.rb +33 -2
  112. data/test/scout/tsv/test_persist.rb +2 -0
  113. data/test/scout/tsv/test_stream.rb +200 -0
  114. data/test/scout/tsv/test_transformer.rb +120 -0
  115. data/test/scout/tsv/test_traverse.rb +88 -3
  116. data/test/scout/tsv/test_util.rb +1 -0
  117. data/test/scout/tsv/util/test_reorder.rb +94 -0
  118. data/test/scout/tsv/util/test_select.rb +25 -11
  119. data/test/scout/tsv/util/test_unzip.rb +112 -0
  120. data/test/scout/work_queue/test_socket.rb +0 -1
  121. data/test/scout/workflow/deployment/test_orchestrator.rb +272 -0
  122. data/test/scout/workflow/step/test_dependencies.rb +68 -0
  123. data/test/scout/workflow/step/test_info.rb +18 -0
  124. data/test/scout/workflow/step/test_status.rb +30 -0
  125. data/test/scout/workflow/task/test_dependencies.rb +355 -0
  126. data/test/scout/workflow/task/test_inputs.rb +67 -14
  127. data/test/scout/workflow/test_definition.rb +18 -0
  128. data/test/scout/workflow/test_documentation.rb +24 -0
  129. data/test/scout/workflow/test_step.rb +112 -3
  130. data/test/scout/workflow/test_task.rb +0 -151
  131. data/test/scout/workflow/test_usage.rb +33 -6
  132. data/test/test_scout.rb +9 -0
  133. metadata +100 -8
  134. data/scout_commands/workflow/task_old +0 -706
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scout'
4
+
5
+ $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
6
+
7
+ options = SOPT.setup <<EOF
8
+
9
+ Description of the tool
10
+
11
+ $ #{$0} [<options>] <filename> [<other|->]*
12
+
13
+ Install a workflow, or a coma separated list of workflows, from its source. If
14
+ repo is not specified then 'http://github.com/Rbbt-Workflows/' will be used. If
15
+ the workflow is already installed it will be updated. If 'all' is specified
16
+ instead of a particular workflow, all installed workflows will be updated.
17
+
18
+ You can set the environment variable SCOUT_WORKFLOW_AUTOINSTALL=true to make
19
+ workflows install automatically as required.
20
+
21
+ -h--help Print this help
22
+ EOF
23
+ if options[:help]
24
+ if defined? scout_usage
25
+ scout_usage
26
+ else
27
+ puts SOPT.doc
28
+ end
29
+ exit 0
30
+ end
31
+
32
+
33
+ workflow = ARGV[0]
34
+ base_repo = ARGV[1]
35
+
36
+ raise "No workflow specified" if workflow.nil?
37
+
38
+ workflow_dir = Scout.etc.workflow_dir.exists? ? Path.setup(Scout.etc.workflow_dir.read.strip) : Scout.workflows.find(:user)
39
+
40
+ FileUtils.mkdir_p workflow_dir unless File.exist? workflow_dir
41
+
42
+ all_workflows = workflow_dir.find.glob("*/.git").collect{|d| File.basename(File.dirname(d))}
43
+ workflows = workflow == 'all' ? all_workflows : workflow.split(",")
44
+
45
+ Misc.in_dir(workflow_dir) do
46
+ workflows.each do |workflow|
47
+ case
48
+ when File.exist?(Misc.snake_case(workflow))
49
+ Log.info "Updating: " + workflow
50
+ Misc.in_dir(Misc.snake_case(workflow)) do
51
+ `git pull`
52
+ `git submodule init`
53
+ `git submodule update`
54
+ end
55
+ when File.exist?(workflow)
56
+ Misc.in_dir(workflow) do
57
+ Log.info "Updating: " + workflow
58
+ `git pull`
59
+ `git submodule init`
60
+ `git submodule update`
61
+ end
62
+ else
63
+ Log.info "Installing: " + workflow
64
+
65
+ if base_repo.nil?
66
+ repo_base_url = Rbbt.etc.workflow_repo.exists? ? Rbbt.etc.workflow_repo.read.strip : 'https://github.com/Rbbt-Workflows/'
67
+ else
68
+ repo_base_url = base_repo
69
+ end
70
+
71
+
72
+ if repo_base_url.include?(workflow) or repo_base_url.include?(Misc.snake_case(workflow))
73
+ repo = repo_base_url
74
+ else
75
+ begin
76
+ repo = File.join(repo_base_url, workflow + '.git')
77
+ CMD.cmd("wget '#{repo}' -O /dev/null").read
78
+ rescue
79
+ Log.debug "Workflow repo does not exist, trying snake_case: #{ repo }"
80
+ begin
81
+ repo = File.join(repo_base_url, Misc.snake_case(workflow) + '.git')
82
+ CMD.cmd("wget '#{repo}' -O /dev/null").read
83
+ rescue
84
+ raise "Workflow repo does not exist: #{ repo }"
85
+ end
86
+ end
87
+ end
88
+
89
+ Log.warn "Cloning #{ repo }"
90
+ Misc.insist do
91
+ `git clone "#{repo}" #{ Misc.snake_case(workflow) }`
92
+ raise unless $?.success?
93
+ end
94
+ Log.warn "Initializing and updating submodules for #{repo}. You might be prompted for passwords."
95
+ Misc.in_dir(Misc.snake_case(workflow)) do
96
+ `git submodule init`
97
+ `git submodule update`
98
+ end
99
+ end
100
+ end
101
+ end
102
+
@@ -4,6 +4,11 @@ require 'scout'
4
4
 
5
5
  $0 = "scout #{$previous_commands.any? ? $previous_commands*" " + " " : "" }#{ File.basename(__FILE__) }" if $previous_commands
6
6
 
7
+ ENV["SCOUT_NO_STREAM"] = "true" if ARGV.include? "--nostream"
8
+ ARGV.delete '--nostream'
9
+ ENV["SCOUT_UPDATE"] = "true" if ARGV.include? "--update"
10
+ ARGV.delete '--update'
11
+
7
12
  options = SOPT.setup <<EOF
8
13
 
9
14
  Run a workflow job
@@ -11,11 +16,16 @@ Run a workflow job
11
16
  $ #{$0} [<options>] <workflow> <task>
12
17
 
13
18
  -h--help Print this help
19
+ --nostream Disable job streaming
20
+ --update Update jobs with newer dependencies
14
21
  -jn--job_name* Name to use as job identifier
22
+ -li--load_inputs* Directory with inputs files to load
15
23
  -pf--print_filepath Print the file path
16
24
  -prov--provenance Print the step provenance
17
25
  -cl--clean Clean the last step
18
26
  -rcl--recursive_clean Clean all steps
27
+ -ct--clean_task* Clean a particular task
28
+ -d--deploy* Deploy mode: serial, local, or SLURM (default 'serial')
19
29
  EOF
20
30
 
21
31
  workflow_name, task_name = ARGV
@@ -28,7 +38,11 @@ task = workflow.tasks[task_name.to_sym] if task_name
28
38
 
29
39
  options[:help] = true if task.nil?
30
40
 
31
- if options[:help]
41
+ help, provenance, clean, recursive_clean, clean_task, load_inputs, jobname, print_filepath, deploy = IndiferentHash.process_options options,
42
+ :help, :provenance, :clean, :recursive_clean, :clean_task, :load_inputs, :job_name, :print_filepath, :deploy,
43
+ :deploy => 'serial'
44
+
45
+ if help
32
46
  if defined? scout_usage
33
47
  scout_usage
34
48
  else
@@ -39,18 +53,52 @@ if options[:help]
39
53
  exit 0
40
54
  end
41
55
 
42
- job_options = task.get_SOPT(task)
43
- job = workflow.job(task_name, options[:job_name], job_options)
56
+ if load_inputs
57
+ job_inputs = workflow.tasks[task_name].load_inputs(load_inputs)
58
+ else
59
+ job_inputs = task.get_SOPT
60
+ end
44
61
 
45
- job.recursive_clean if options[:recursive_clean]
46
- job.clean if options[:clean]
62
+ job = workflow.job(task_name, jobname, job_inputs)
63
+
64
+ job.recursive_clean if recursive_clean
65
+ job.clean if clean
66
+
67
+ if clean_task
68
+ ENV["SCOUT_UPDATE"] = 'true'
69
+ clean_task.split(",").each do |clean_task|
70
+ if clean_task.include? "#"
71
+ clean_workflow, clean_task = clean_task.split("#")
72
+ end
47
73
 
48
- if options[:provenance]
74
+ job.rec_dependencies.each do |dep|
75
+ next unless dep.task_name.to_s == clean_task.to_s
76
+ next unless clean_workflow.nil? || clean_workflow == dep.workflow.to_s
77
+ dep.clean
78
+ dep.set_info :status, :cleaned
79
+ end
80
+
81
+ job.clean if job.task_name.to_s == clean_task.to_s
82
+ end
83
+ end
84
+
85
+ if provenance
49
86
  puts Step.prov_report(job)
50
87
  else
51
- job.run unless job.done?
52
-
53
- if options[:print_filepath]
88
+ case deploy
89
+ when "serial"
90
+ job.run(true)
91
+ when "local"
92
+ orchestrator = Workflow::Orchestrator.new 3, "cpus" => Misc.processors
93
+ orchestrator.process({}, job)
94
+ when "slurm"
95
+ SLURM.orchestrate(job)
96
+ else
97
+ OffsiteStep.setup(job, server: deploy, provided_inputs: job_inputs)
98
+ job.run
99
+ end unless job.done?
100
+
101
+ if print_filepath
54
102
  job.join
55
103
  path = job.path
56
104
  path = path.find if Path === path
@@ -0,0 +1,15 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestSSH < Test::Unit::TestCase
5
+ def test_marshal
6
+ return unless SSHLine.reach?
7
+
8
+ assert TrueClass === SSHLine.rbbt(:default, 'true')
9
+ end
10
+
11
+ def test_localhost
12
+ assert SSHLine.scout('localhost', 'true')
13
+ end
14
+ end
15
+
@@ -0,0 +1,33 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestOffsiteStep < Test::Unit::TestCase
5
+ def test_offsite_task
6
+ workflow_code =<<-EOF
7
+ module TestWF
8
+ extend Workflow
9
+
10
+ input :string, :string, "String", "string"
11
+ task :string => :string do |string| string end
12
+ end
13
+
14
+ TestWF.directory = Path.setup("#{tmpdir.offsite.TestWF}")
15
+ EOF
16
+
17
+ TmpFile.with_file workflow_code, :extension => 'rb' do |wffile|
18
+ wf = Workflow.require_workflow wffile
19
+
20
+ job = wf.job(:string)
21
+
22
+ sss 0
23
+ off = OffsiteStep.setup job, server: 'localhost', workflow_name: wffile
24
+
25
+ refute off.done?
26
+ assert_equal 'string', off.run
27
+
28
+ assert off.done?
29
+ assert_equal 'string', off.run
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,36 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestSync < Test::Unit::TestCase
5
+ def test_sync
6
+ TmpFile.with_path do |tmpdir|
7
+ tmpdir = Scout.tmp.tmpdir_sync
8
+ tmpdir.dir1.foo.write("FOO")
9
+ tmpdir.dir1.bar.write("BAR")
10
+
11
+ TmpFile.with_path do |tmpdir2|
12
+ Misc.in_dir tmpdir2 do
13
+ SSHLine.sync([tmpdir.dir1], map: :current)
14
+
15
+ assert tmpdir2.glob("**/*").select{|f| f.include?('foo') }.any?
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ def test_sync_dir_map
22
+ TmpFile.with_path do |tmpdir|
23
+ tmpdir = Scout.tmp.tmpdir_sync
24
+ tmpdir.dir1.foo.write("FOO")
25
+ tmpdir.dir1.bar.write("BAR")
26
+
27
+ TmpFile.with_path do |tmpdir2|
28
+ SSHLine.sync([tmpdir.dir1], map: tmpdir2)
29
+ Misc.in_dir tmpdir2 do
30
+ assert tmpdir2.glob("**/*").select{|f| f.include?('foo') }.any?
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
File without changes
@@ -334,63 +334,65 @@ row1 A B C
334
334
  assert_equal %w(## ## ## #Row row1 row2 row3), sorted.read.split("\n").collect{|l| l.split(" ").first}
335
335
  end
336
336
 
337
- # def test_collapse_stream
338
- # text=<<-EOF
339
- #row1 A B C
340
- #row1 a b c
341
- #row2 AA BB CC
342
- #row2 aa bb cc
343
- # EOF
344
- #
345
- # s = StringIO.new text
346
- # tsv = TSV.open Misc.collapse_stream(s,nil, " "), :sep => " "
347
- # assert_equal ["A", "a"], tsv["row1"][0]
348
- # assert_equal ["BB", "bb"], tsv["row2"][1]
349
- # end
350
- #
351
- # def test_collapse_sum
352
- # text=<<-EOF
353
- #row1 12
354
- #row1 4
355
- #row2 10
356
- #row2 6
357
- # EOF
358
- #
359
- # s = StringIO.new text
360
- # stream = Misc.collapse_stream(s,nil, " ") do |parts|
361
- # next nil if parts.empty?
362
- # parts.first.split("|").collect{|p| p.to_f}.inject(0){|acc,e| acc += e}.to_s
363
- # end
364
- # tsv = TSV.open stream, :sep => " "
365
- # ppp tsv.to_s
366
- # end
367
- #
368
- # def test_collapse_stream_gap
369
- # text=<<-EOF
370
- #row2 AA BB
371
- #row2 aa bb cc
372
- # EOF
373
- #
374
- # s = StringIO.new text
375
- # assert Misc.collapse_stream(s, nil, " ").read =~ /\|cc$/
376
- #
377
- # text=<<-EOF
378
- #row2 aa bb cc
379
- #row2 AA BB
380
- # EOF
381
- #
382
- # s = StringIO.new text
383
- # assert Misc.collapse_stream(s, nil, " ").read =~ /cc\|$/
384
- #
385
- # text=<<-EOF
386
- #row2 AA BB
387
- #row2 aa bb cc
388
- # EOF
389
- #
390
- # s = StringIO.new text
391
- # assert Misc.collapse_stream(s, nil, " ").read =~ /\|cc$/
392
- #
393
- # end
337
+ def test_collapse_stream
338
+ text=<<-EOF
339
+ row1 A B C
340
+ row1 a b c
341
+ row2 AA BB CC
342
+ row2 aa bb cc
343
+ EOF
344
+
345
+ s = StringIO.new text
346
+ stream = Open.collapse_stream(s, sep: " ")
347
+ txt = stream.read
348
+ assert_include txt, "A|a"
349
+ assert_include txt, "B|b"
350
+ assert_include txt, "C|c"
351
+ end
352
+
353
+
354
+ def test_collapse_sum
355
+ text=<<-EOF
356
+ row1 12
357
+ row1 4
358
+ row2 10
359
+ row2 6
360
+ EOF
361
+
362
+ s = StringIO.new text
363
+ stream = Open.collapse_stream(s, sep: " ") do |parts|
364
+ next nil if parts.empty?
365
+ parts.first.split("|").collect{|p| p.to_f}.inject(0){|acc,e| acc += e}.to_s
366
+ end
367
+ assert_include stream.read, "row1 16"
368
+ end
369
+
370
+
371
+ def test_collapse_stream_gap
372
+ text=<<-EOF
373
+ row2 AA BB
374
+ row2 aa bb cc
375
+ EOF
376
+
377
+ s = StringIO.new text
378
+ assert Open.collapse_stream(s, sep: " ").read =~ /\|cc$/
379
+
380
+ text=<<-EOF
381
+ row2 aa bb cc
382
+ row2 AA BB
383
+ EOF
384
+
385
+ s = StringIO.new text
386
+ assert Open.collapse_stream(s, sep: " ").read =~ /cc\|$/
387
+
388
+ text=<<-EOF
389
+ row2 AA BB
390
+ row2 aa bb cc
391
+ EOF
392
+
393
+ s = StringIO.new text
394
+ assert Open.collapse_stream(s, sep: " ").read =~ /\|cc$/
395
+ end
394
396
  #
395
397
  #
396
398
  # def test_paste_stream
@@ -433,7 +435,7 @@ row1 A B C
433
435
  # s = StringIO.new text
434
436
  # sorted = Misc.sort_stream(s)
435
437
  # assert_equal %w(## ## ## #Row row2 row3 row1), text.split("\n").collect{|l| l.split(" ").first}
436
- # assert_equal %w(## ## ## #Row row1 row2 row3), sorted.read.split("\n").collect{|l| l.split(" ").first}
438
+ # assert_equal %w(## ## ## #Row row1 row2 row3), sorted.read.split("\n").collect{|l| l.split(" ").first}
437
439
  # end
438
440
  #
439
441
  # def test_sort_long_stream
@@ -68,7 +68,6 @@ class TestPathFind < Test::Unit::TestCase
68
68
  p = Path.setup("/tmp/foo/bar")
69
69
  assert p.located?
70
70
  assert_equal_path p, p.find
71
-
72
71
  end
73
72
 
74
73
  def test_custom
@@ -106,5 +105,15 @@ class TestPathFind < Test::Unit::TestCase
106
105
  assert Open.exist?(tmpdir.somefile)
107
106
  end
108
107
  end
108
+
109
+ def test_with_extension
110
+ dir = tmpdir.directory[__method__]
111
+ list = %w(a b)
112
+ Misc.in_dir(dir) do
113
+ file = dir.foo
114
+ Open.write(file.set_extension('list'), list * "\n")
115
+ assert_equal list, file.list
116
+ end
117
+ end
109
118
  end
110
119
 
@@ -36,5 +36,11 @@ class TestResourcePath < Test::Unit::TestCase
36
36
  assert_include tmpfile.foo.bar.read, "TEST"
37
37
  end
38
38
  end
39
+
40
+ def test_identify
41
+ p = Scout.data.file.find(:lib)
42
+ assert p.located?
43
+ assert_equal "data/file", p.identify
44
+ end
39
45
  end
40
46
 
@@ -59,4 +59,19 @@ end
59
59
  assert_include File.open(TestResource.tmp.test.work.footest.bar.find).read, "OTHER"
60
60
  assert_include File.open(TestResource.tmp.test.work.footest.foo_bar.find).read, "OTHER"
61
61
  end
62
+
63
+ def test_produce_with_extension
64
+ dir = tmpdir.directory[__method__]
65
+ dir.pkgdir = Scout
66
+ list = %w(a b)
67
+
68
+ Scout.claim dir["foo.list"], :proc do
69
+ list
70
+ end
71
+
72
+ Misc.in_dir(dir) do
73
+ file = dir.foo
74
+ assert_equal list, file.list
75
+ end
76
+ end
62
77
  end
@@ -8,6 +8,13 @@ class TestMetaExtension < Test::Unit::TestCase
8
8
  extension_attr :code, :code2
9
9
  end
10
10
 
11
+ module ExtensionClass2
12
+ extend MetaExtension
13
+
14
+ extension_attr :code3, :code4
15
+ end
16
+
17
+
11
18
  def test_setup_annotate
12
19
  str = "String"
13
20
  ExtensionClass.setup(str, :code)
@@ -51,5 +58,23 @@ class TestMetaExtension < Test::Unit::TestCase
51
58
  assert o.extension_attr_hash.include?(:code)
52
59
  assert o.extension_attr_hash.include?(:code2)
53
60
  end
61
+
62
+ def test_twice
63
+ str = "String"
64
+
65
+ ExtensionClass.setup(str, :code2 => :code)
66
+ assert_equal :code, str.code2
67
+ assert_include str.instance_variable_get(:@extension_attrs), :code
68
+
69
+ str.extend ExtensionClass2
70
+ str.code3 = :code_alt
71
+ assert_equal :code, str.code2
72
+ assert_equal :code_alt, str.code3
73
+ assert_include str.instance_variable_get(:@extension_attrs), :code
74
+ assert_include str.instance_variable_get(:@extension_attrs), :code3
75
+
76
+ assert_include str.extension_attr_hash, :code
77
+ assert_include str.extension_attr_hash, :code3
78
+ end
54
79
  end
55
80
 
@@ -15,5 +15,29 @@ ValueB (Entity type)
15
15
  assert_equal 1, NamedArray.identify_name(names, "ValueB")
16
16
  assert_equal 1, NamedArray.identify_name(names, 1)
17
17
  end
18
+
19
+ def test_missing_field
20
+ a = NamedArray.setup([1,2], [:a, :b])
21
+ assert_equal 1, a[:a]
22
+ assert_equal nil, a[:c]
23
+ end
24
+
25
+ def test_zip_fields
26
+ a = [%w(a b), %w(1 1)]
27
+ assert_equal [%w(a 1), %w(b 1)], NamedArray.zip_fields(a)
28
+ end
29
+
30
+ def test_add_zipped
31
+ a = [%w(a b), %w(1 1)]
32
+ NamedArray.add_zipped a, [%w(c), %w(1)]
33
+ NamedArray.add_zipped a, [%w(d), %w(1)]
34
+ assert_equal [%w(a b c d), %w(1 1 1 1)], a
35
+ end
36
+
37
+ def test_method_missing
38
+ a = NamedArray.setup([1,2], [:a, :b])
39
+ assert_equal 1, a.a
40
+ assert_equal 2, a.b
41
+ end
18
42
  end
19
43
 
@@ -114,6 +114,7 @@ class TestPersist < Test::Unit::TestCase
114
114
  end
115
115
  end
116
116
  end
117
+
117
118
  if IO === io
118
119
  Open.consume_stream(io, false)
119
120
  else
@@ -137,8 +138,8 @@ class TestPersist < Test::Unit::TestCase
137
138
  Open.write(output2, io)
138
139
  end
139
140
  end
140
- Process.wait
141
- Process.wait
141
+ Process.wait pid1
142
+ Process.wait pid2
142
143
 
143
144
  assert File.exist?(output1) || File.exist?(output2)
144
145
  [pid1, pid2].zip([output2, output1]).each do |pid, found|
@@ -156,6 +157,12 @@ class TestPersist < Test::Unit::TestCase
156
157
  end
157
158
  end
158
159
 
160
+ def test_path_prefix
161
+ Persist.persist('foo', :tsv, :prefix => "TSV") do |filename|
162
+ assert File.basename(filename).start_with? "TSV"
163
+ end
164
+ end
165
+
159
166
  def __test_speed
160
167
  times = 100_000
161
168
  TmpFile.with_file do |tmpfile|