tap-tasks 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History CHANGED
@@ -1,3 +1,17 @@
1
+ == 0.5.0 / 2009-12-05
2
+
3
+ Updates for Tap-0.19.0
4
+
5
+ == 0.4.0
6
+
7
+ * added short options to load/dump csv
8
+ * added Gate join
9
+ * added Null task
10
+ * added Stream task for stream loading
11
+ * updated load/yaml to only load a single document
12
+ * added stream/yaml for stream loading documents
13
+ * added Profiler middleware
14
+
1
15
  == 0.3.0 / 2009-06-17
2
16
 
3
17
  * added load/dump csv tasks
data/MIT-LICENSE CHANGED
@@ -1,22 +1,21 @@
1
1
  Copyright (c) 2009, Regents of the University of Colorado.
2
2
 
3
- Permission is hereby granted, free of charge, to any person
4
- obtaining a copy of this software and associated documentation
5
- files (the "Software"), to deal in the Software without
6
- restriction, including without limitation the rights to use,
7
- copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- copies of the Software, and to permit persons to whom the
9
- Software is furnished to do so, subject to the following
10
- conditions:
3
+ Copyright (c) 2009, Simon Chiang.
11
4
 
12
- The above copyright notice and this permission notice shall be
13
- included in all copies or substantial portions of the Software.
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
14
11
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
- OTHER DEALINGS IN THE SOFTWARE.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README CHANGED
@@ -12,7 +12,6 @@ is a part of the {Tap-Suite}[http://tap.rubyforge.org/tap-suite]. Check out
12
12
  these links for documentation, development, and bug tracking.
13
13
 
14
14
  * Website[http://tap.rubyforge.org]
15
- * Lighthouse[http://bahuvrihi.lighthouseapp.com/projects/9908-tap-task-application/tickets]
16
15
  * Github[http://github.com/bahuvrihi/tap/tree/master]
17
16
  * {Google Group}[http://groups.google.com/group/ruby-on-tap]
18
17
 
@@ -25,13 +24,11 @@ Usage is the same as for any tasks.
25
24
 
26
25
  == Installation
27
26
 
28
- Tap-Tasks is available as a gem on RubyForge[http://rubyforge.org/projects/tap]. Use:
27
+ Tap-Tasks is available as a gem on Gemcutter[http://gemcutter.org/gems/tap-tasks].
29
28
 
30
29
  % gem install tap-tasks
31
30
 
32
31
  == Info
33
32
 
34
- Copyright (c) 2009, Regents of the University of Colorado.
35
- Developer:: {Simon Chiang}[http://bahuvrihi.wordpress.com], {Biomolecular Structure Program}[http://biomol.uchsc.edu/], {Hansen Lab}[http://hsc-proteomics.uchsc.edu/hansenlab/]
36
- Support:: CU Denver School of Medicine Deans Academic Enrichment Fund
33
+ Developer:: {Simon Chiang}[http://bahuvrihi.wordpress.com]
37
34
  License:: {MIT-Style}[link:files/MIT-LICENSE.html]
@@ -0,0 +1,87 @@
1
+ require 'tap/join'
2
+
3
+ module Tap
4
+ module Joins
5
+
6
+ # :startdoc::join collects results before the join
7
+ #
8
+ # Similar to a synchronized merge, but collects all results regardless of
9
+ # where they come from. Gates enque themselves when called as a join, and
10
+ # won't let results pass until they get run as a node.
11
+ #
12
+ # % tap run -- load a -- load b -- inspect --[0,1][2].gate
13
+ # ["a", "b"]
14
+ #
15
+ # Gates are useful in conjunction with iteration where a single task may
16
+ # feed multiple results to a single join; in this case a sync merge doesn't
17
+ # produce the desired behavior of collecting the results.
18
+ #
19
+ # % tap run -- load/yaml "[1, 2, 3]" --:i inspect --:.gate inspect
20
+ # 1
21
+ # 2
22
+ # 3
23
+ # [1, 2, 3]
24
+ #
25
+ # % tap run -- load/yaml "[1, 2, 3]" --:i inspect --:.sync inspect
26
+ # 1
27
+ # [1]
28
+ # 2
29
+ # [2]
30
+ # 3
31
+ # [3]
32
+ #
33
+ # When a limit is specified, the gate will collect results up to the limit
34
+ # and then pass the results. Any leftover results are still passed at the
35
+ # end.
36
+ #
37
+ # % tap run -- load/yaml "[1, 2, 3]" --:i inspect -- inspect --. gate 1 2 --limit 2
38
+ # 1
39
+ # 2
40
+ # [1, 2]
41
+ # 3
42
+ # [3]
43
+ #
44
+ class Gate < Join
45
+
46
+ # An array of results collected thusfar.
47
+ attr_reader :results
48
+
49
+ config :limit, nil, :short => :l, &c.integer_or_nil # Pass results after limit
50
+
51
+ def initialize(config={}, app=Tap::App.instance)
52
+ super
53
+ @results = nil
54
+ end
55
+
56
+ def call(result)
57
+ if @results
58
+ # Results are set, so self is already enqued and collecting
59
+ # results. If the input is the collection, then it's time
60
+ # to dispatch the results and reset. Otherwise, just
61
+ # collect the input and wait.
62
+
63
+ if result == @results
64
+ @results = nil
65
+ super(result)
66
+ else
67
+ @results << result
68
+
69
+ if limit && @results.length >= limit
70
+ super(@results.dup)
71
+ @results.clear
72
+ end
73
+ end
74
+
75
+ else
76
+ # No results are set, so this is a first call and self is
77
+ # not enqued. Setup the collection.
78
+
79
+ @results = [result]
80
+ app.enq(self, @results)
81
+ end
82
+
83
+ self
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,72 @@
1
+ require 'tap/middleware'
2
+
3
+ module Tap
4
+ module Middlewares
5
+
6
+ # :startdoc::middleware profile the workflow execution time
7
+ #
8
+ #
9
+ class Profiler < Tap::Middleware
10
+
11
+ attr_reader :app_time
12
+ attr_reader :nodes
13
+ attr_reader :counts
14
+
15
+ def initialize(stack, config={})
16
+ super
17
+ reset
18
+ at_exit { app.quiet = false; app.log(:profile, "\n" + summary.join("\n")) }
19
+ end
20
+
21
+ def reset
22
+ @app_time = 0
23
+ @last = nil
24
+ @nodes = Hash.new(0)
25
+ @counts = Hash.new(0)
26
+ end
27
+
28
+ def total_time
29
+ nodes.values.inject(0) {|sum, elapsed| sum + elapsed }
30
+ end
31
+
32
+ def total_counts
33
+ counts.values.inject(0) {|sum, n| sum + n }
34
+ end
35
+
36
+ def call(node, inputs=[])
37
+ @app_time += Time.now - @last if @last
38
+
39
+ start = Time.now
40
+ result = super
41
+ elapsed = Time.now - start
42
+
43
+ nodes[node] += elapsed
44
+ counts[node] += 1
45
+
46
+ @last = Time.now
47
+ result
48
+ end
49
+
50
+ def summary
51
+ lines = []
52
+ lines << "App Time: #{app_time}s"
53
+ lines << "Node Time: #{total_time}s"
54
+ lines << "Nodes Run: #{total_counts}"
55
+ lines << "Breakdown:"
56
+
57
+ nodes_by_class = {}
58
+ nodes.each_key do |node|
59
+ (nodes_by_class[node.class.to_s] ||= []) << node
60
+ end
61
+
62
+ nodes_by_class.keys.sort.each do |node_class|
63
+ nodes_by_class[node_class].each do |node|
64
+ lines << "- #{node_class}: [#{nodes[node]}, #{counts[node]}]"
65
+ end
66
+ end
67
+
68
+ lines
69
+ end
70
+ end
71
+ end
72
+ end
@@ -16,8 +16,8 @@ module Tap
16
16
  #
17
17
  class Csv < Dump
18
18
 
19
- config :col_sep, ",", &c.string # The column separator (",")
20
- config :row_sep, "\n", &c.string # The row separator ("\n")
19
+ config :col_sep, ",", :short => :c, &c.string # The column separator (",")
20
+ config :row_sep, "\n", :short => :r, &c.string # The row separator ("\n")
21
21
 
22
22
  # Dumps the data to io as CSV. Data is converted to an array using
23
23
  # to_ary.
@@ -19,11 +19,11 @@ module Tap
19
19
  #
20
20
  class Csv < Load
21
21
 
22
- config :columns, nil, &c.range_or_nil # Specify a range of columns
23
- config :rows, nil, &c.range_or_nil # Specify a range of rows
22
+ config :columns, nil, :short => :C, &c.range_or_nil # Specify a range of columns
23
+ config :rows, nil, :short => :R, &c.range_or_nil # Specify a range of rows
24
24
 
25
- config :col_sep, nil, &c.string_or_nil # The column separator (",")
26
- config :row_sep, nil, &c.string_or_nil # The row separator ("\r\n" or "\n")
25
+ config :col_sep, nil, :short => :c, &c.string_or_nil # The column separator (",")
26
+ config :row_sep, nil, :short => :r, &c.string_or_nil # The row separator ("\r\n" or "\n")
27
27
 
28
28
  # Loads the io data as CSV, into an array of arrays.
29
29
  def load(io)
@@ -14,35 +14,9 @@ module Tap
14
14
  #
15
15
  class Yaml < Load
16
16
 
17
- config :stream, false, &c.flag # Load documents from a stream
18
-
19
17
  # Loads data from io as YAML.
20
18
  def load(io)
21
- if stream
22
- load_stream(io)
23
- else
24
- YAML.load(io)
25
- end
26
- end
27
-
28
- def load_stream(io)
29
- lines = []
30
- while !io.eof?
31
- line = io.readline
32
-
33
- if line =~ /^---/ && !lines.empty?
34
- io.pos = io.pos - line.length
35
- break
36
- else
37
- lines << line
38
- end
39
- end
40
-
41
- YAML.load(lines.join)
42
- end
43
-
44
- def complete?(io, last)
45
- !stream || io.eof?
19
+ YAML.load(io)
46
20
  end
47
21
 
48
22
  end
@@ -0,0 +1,27 @@
1
+ require 'tap/task'
2
+
3
+ module Tap
4
+ module Tasks
5
+ # :startdoc::task a dev/null task
6
+ #
7
+ # Null serves the same function as /dev/null, that is inputs directed
8
+ # to Null go nowhere. Null does not accept joins and will not execute
9
+ # the default app joins.
10
+ #
11
+ # % tap run -- load a --: null
12
+ #
13
+ class Null < Tap::Task
14
+ def process(*args)
15
+ nil
16
+ end
17
+
18
+ def joins
19
+ nil
20
+ end
21
+
22
+ def on_complete
23
+ raise "cannot be participate in joins: #{self}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ require 'tap/tasks/load'
2
+
3
+ module Tap
4
+ module Tasks
5
+
6
+ # Stream recurrently loads data from $stdin by requeing self until an
7
+ # end-of-file is reached. This behavior is useful for creating tasks
8
+ # that load a bit of data from an IO, send it into a workflow, and then
9
+ # repeat.
10
+ #
11
+ # The eof cutoff can be modified using complete? method. Streaming will
12
+ # stop when complete? returns true. For instance, this is a prompt task:
13
+ #
14
+ # class Prompt < Tap::Tasks::Stream
15
+ # config :exit_seq, "\n"
16
+ #
17
+ # def load(io)
18
+ # if io.eof?
19
+ # nil
20
+ # else
21
+ # io.readline
22
+ # end
23
+ # end
24
+ #
25
+ # def complete?(io, line)
26
+ # line == nil || line == exit_seq
27
+ # end
28
+ # end
29
+ #
30
+ class Stream < Load
31
+
32
+ # Loads data from io. Process will open the input io object, load
33
+ # a result, then check to see if the loading is complete (using the
34
+ # complete? method). Unless loading is complete, process will enque
35
+ # io to self. Process will close io when loading is complete, provided
36
+ # use_close or file is specified.
37
+ def process(io=$stdin)
38
+ io = open(io)
39
+ result = load(io)
40
+
41
+ if complete?(io, result)
42
+ if use_close || file
43
+ close(io)
44
+ end
45
+ else
46
+ reque(io)
47
+ end
48
+
49
+ result
50
+ end
51
+
52
+ # Returns true by default. Override in subclasses to allow recurrent
53
+ # loading (see process).
54
+ def complete?(io, last)
55
+ io.eof?
56
+ end
57
+
58
+ # Reques self with io to the top of the queue.
59
+ def reque(io)
60
+ app.queue.unshift(self, [io])
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,49 @@
1
+ require 'tap/tasks/stream'
2
+
3
+ module Tap
4
+ module Tasks
5
+ class Stream
6
+
7
+ # :startdoc::task streams data as YAML
8
+ #
9
+ # Stream loads data from the input IO as YAML.
10
+ #
11
+ # [example.yml]
12
+ # ---
13
+ # :sym
14
+ # ---
15
+ # - 1
16
+ # - 2
17
+ # - 3
18
+ # ---
19
+ # key: value
20
+ #
21
+ # % tap run -- stream/yaml --file example.yml --: inspect
22
+ # :sym
23
+ # [1, 2, 3]
24
+ # {"key"=>"value"}
25
+ #
26
+ class Yaml < Stream
27
+
28
+ # Streams data from io as YAML.
29
+ def load(io)
30
+ lines = []
31
+
32
+ while !io.eof?
33
+ line = io.readline
34
+
35
+ if line =~ /^---/ && !lines.empty?
36
+ io.pos = io.pos - line.length
37
+ break
38
+ else
39
+ lines << line
40
+ end
41
+ end
42
+
43
+ YAML.load(lines.join)
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,9 @@
1
+ module Tap
2
+ module Tasks
3
+ MAJOR = 0
4
+ MINOR = 5
5
+ TINY = 0
6
+
7
+ VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
8
+ end
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tap-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Chiang
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-17 00:00:00 -06:00
12
+ date: 2009-12-05 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.18.0
23
+ version: 0.19.0
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: tap-test
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.2.0
33
+ version: 0.3.0
34
34
  version:
35
35
  description:
36
36
  email: simon.a.chiang@gmail.com
@@ -43,19 +43,26 @@ extra_rdoc_files:
43
43
  - README
44
44
  - MIT-LICENSE
45
45
  files:
46
+ - lib/tap/joins/gate.rb
47
+ - lib/tap/middlewares/profiler.rb
46
48
  - lib/tap/tasks/dump/csv.rb
47
49
  - lib/tap/tasks/dump/inspect.rb
48
50
  - lib/tap/tasks/dump/yaml.rb
49
51
  - lib/tap/tasks/load/yaml.rb
50
52
  - lib/tap/tasks/load/csv.rb
53
+ - lib/tap/tasks/null.rb
51
54
  - lib/tap/tasks/glob.rb
52
- - lib/tap/tasks/prompt.rb
55
+ - lib/tap/tasks/stream.rb
56
+ - lib/tap/tasks/stream/yaml.rb
57
+ - lib/tap/tasks/version.rb
53
58
  - tap.yml
54
59
  - History
55
60
  - README
56
61
  - MIT-LICENSE
57
62
  has_rdoc: true
58
- homepage: http:/tap.rubyforge.org/tap-tasks/
63
+ homepage: http://tap.rubyforge.org/tap-tasks/
64
+ licenses: []
65
+
59
66
  post_install_message:
60
67
  rdoc_options:
61
68
  - --main
@@ -81,9 +88,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
88
  requirements: []
82
89
 
83
90
  rubyforge_project: tap
84
- rubygems_version: 1.3.1
91
+ rubygems_version: 1.3.5
85
92
  signing_key:
86
- specification_version: 2
93
+ specification_version: 3
87
94
  summary: A set of standard Tap tasks
88
95
  test_files: []
89
96
 
@@ -1,42 +0,0 @@
1
- require 'tap/tasks/load'
2
-
3
- module Tap
4
- module Tasks
5
- # :startdoc::task an input prompt
6
- #
7
- # Prompt reads lines from the input until the exit sequence is reached
8
- # or the source io is closed. This is effectively an echo:
9
- #
10
- # % tap run -- prompt --: dump
11
- # >
12
- #
13
- class Prompt < Load
14
- config :prompt, "> ", &c.string_or_nil # The prompt sequence
15
- config :exit_seq, "\n", &c.string_or_nil # The prompt exit sequence
16
- config :terminal, $stdout, &c.io_or_nil # The terminal IO
17
-
18
- configurations[:use_close].default = true
19
-
20
- def load(io)
21
- open_io(terminal) do |terminal|
22
- terminal.print prompt
23
- end if prompt
24
-
25
- if io.eof?
26
- nil
27
- else
28
- io.readline
29
- end
30
- end
31
-
32
- def complete?(io, line)
33
- line == nil || line == exit_seq
34
- end
35
-
36
- def close(io)
37
- super
38
- app.terminate
39
- end
40
- end
41
- end
42
- end