tap-tasks 0.5.0 → 0.7.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/History +4 -0
- data/MIT-LICENSE +1 -1
- data/README +2 -4
- data/lib/tap/tasks/console.rb +43 -0
- data/lib/tap/tasks/dump/csv.rb +15 -5
- data/lib/tap/tasks/dump/inspect.rb +2 -5
- data/lib/tap/tasks/dump/yaml.rb +1 -1
- data/lib/tap/tasks/error.rb +16 -0
- data/lib/tap/tasks/glob.rb +2 -2
- data/lib/tap/tasks/insert.rb +89 -0
- data/lib/tap/tasks/load/csv.rb +15 -4
- data/lib/tap/tasks/load/yaml.rb +1 -1
- data/lib/tap/tasks/null.rb +2 -3
- data/lib/tap/tasks/sleep.rb +17 -0
- data/lib/tap/tasks/stream/yaml.rb +1 -1
- data/lib/tap/tasks/version.rb +1 -1
- data/tap-tasks.gemspec +50 -0
- metadata +38 -21
- data/lib/tap/joins/gate.rb +0 -87
- data/lib/tap/middlewares/profiler.rb +0 -72
- data/lib/tap/tasks/stream.rb +0 -64
data/History
CHANGED
data/MIT-LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Copyright (c) 2009, Regents of the University of Colorado.
|
2
2
|
|
3
|
-
Copyright (c) 2009, Simon Chiang.
|
3
|
+
Copyright (c) 2009-2010, Simon Chiang.
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README
CHANGED
@@ -7,9 +7,7 @@ A set of standard Tap tasks.
|
|
7
7
|
== Description
|
8
8
|
|
9
9
|
A standard library of utility tasks, for example tasks to dump/load results as
|
10
|
-
{YAML}[http://www.yaml.org/]
|
11
|
-
is a part of the {Tap-Suite}[http://tap.rubyforge.org/tap-suite]. Check out
|
12
|
-
these links for documentation, development, and bug tracking.
|
10
|
+
{YAML}[http://www.yaml.org/] or CSV.
|
13
11
|
|
14
12
|
* Website[http://tap.rubyforge.org]
|
15
13
|
* Github[http://github.com/bahuvrihi/tap/tree/master]
|
@@ -19,7 +17,7 @@ these links for documentation, development, and bug tracking.
|
|
19
17
|
|
20
18
|
Usage is the same as for any tasks.
|
21
19
|
|
22
|
-
% tap
|
20
|
+
% tap load/yaml "{key: value}" -: inspect
|
23
21
|
{"key" => "value"}
|
24
22
|
|
25
23
|
== Installation
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'tap/task'
|
2
|
+
require 'tap/declarations'
|
3
|
+
require 'irb'
|
4
|
+
|
5
|
+
# http://www.ruby-forum.com/topic/182335
|
6
|
+
class IRB::Irb
|
7
|
+
alias initialize_orig initialize
|
8
|
+
def initialize(workspace = nil, *args)
|
9
|
+
default = IRB.conf[:DEFAULT_OBJECT]
|
10
|
+
workspace ||= IRB::WorkSpace.new(default) if default
|
11
|
+
initialize_orig(workspace, *args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Tap
|
16
|
+
module Tasks
|
17
|
+
# :startdoc::task start an irb session
|
18
|
+
#
|
19
|
+
# Console allows interaction with tap via IRB. Starts an IRB sssion with
|
20
|
+
# the same context as a tapfile (a Tap::Declarations::Context). Only one
|
21
|
+
# console can be running at time.
|
22
|
+
#
|
23
|
+
class Console < Tap::Task
|
24
|
+
# Handles a bug in IRB that causes exit to throw :IRB_EXIT
|
25
|
+
# and consequentially make a warning message, even on a
|
26
|
+
# clean exit. This module resets exit to the original
|
27
|
+
# aliased method.
|
28
|
+
module CleanExit # :nodoc:
|
29
|
+
def exit(ret = 0)
|
30
|
+
__exit__(ret)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def process
|
35
|
+
raise "console already running" if IRB.conf[:DEFAULT_OBJECT]
|
36
|
+
IRB.conf[:DEFAULT_OBJECT] = Declarations::Context.new(app, "console")
|
37
|
+
IRB.start
|
38
|
+
IRB.conf[:DEFAULT_OBJECT] = nil
|
39
|
+
IRB.CurrentContext.extend CleanExit
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/tap/tasks/dump/csv.rb
CHANGED
@@ -11,18 +11,28 @@ module Tap
|
|
11
11
|
# into a single line of csv, ie multiple dumps build the csv results.
|
12
12
|
# Non-array objects are converted to arrays using to_ary.
|
13
13
|
#
|
14
|
-
# % tap
|
14
|
+
# % tap load/yaml '["a", "b", "c"]' -: dump/csv
|
15
15
|
# a,b,c
|
16
16
|
#
|
17
17
|
class Csv < Dump
|
18
18
|
|
19
19
|
config :col_sep, ",", :short => :c, &c.string # The column separator (",")
|
20
|
-
config :row_sep,
|
20
|
+
config :row_sep, $/, :short => :r, &c.string # The row separator ("\n")
|
21
21
|
|
22
|
-
# Dumps the data to io as CSV. Data is converted to an array using
|
23
|
-
# to_ary.
|
24
22
|
def dump(data, io)
|
25
|
-
io <<
|
23
|
+
io << generate_line(data.to_ary)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
if RUBY_VERSION >= '1.9'
|
29
|
+
def generate_line(data)
|
30
|
+
CSV.generate_line(data, :col_sep => col_sep, :row_sep => row_sep)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
def generate_line(data)
|
34
|
+
CSV.generate_line(data, col_sep) + row_sep
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
end
|
@@ -10,15 +10,12 @@ module Tap
|
|
10
10
|
# method can be specified for inspection using the inspect_method
|
11
11
|
# config.
|
12
12
|
#
|
13
|
-
# % tap
|
13
|
+
# % tap load/yaml "{key: value}" -: inspect
|
14
14
|
# {"key"=>"value"}
|
15
15
|
#
|
16
|
-
# % tap run -- load string --: inspect -m length
|
17
|
-
# 6
|
18
|
-
#
|
19
16
|
class Inspect < Dump
|
20
17
|
|
21
|
-
config :inspect_method, 'inspect', :short => :m # The inspection method
|
18
|
+
config :inspect_method, 'inspect', :long => :method, :short => :m # The inspection method
|
22
19
|
|
23
20
|
# Dumps the object to io using obj.inspect
|
24
21
|
def dump(obj, io)
|
data/lib/tap/tasks/dump/yaml.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'tap/task'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Tasks
|
5
|
+
# :startdoc::task raises an error
|
6
|
+
#
|
7
|
+
# Error raises a Runtime error when called. The input specifies the
|
8
|
+
# error message.
|
9
|
+
#
|
10
|
+
class Error < Tap::Task
|
11
|
+
def process(msg=nil)
|
12
|
+
raise msg
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/tap/tasks/glob.rb
CHANGED
@@ -7,7 +7,7 @@ module Tap
|
|
7
7
|
# Globs the input patterns for matching patterns. Matching files are
|
8
8
|
# returned as an array.
|
9
9
|
#
|
10
|
-
# % tap
|
10
|
+
# % tap glob * -: dump/yaml
|
11
11
|
#
|
12
12
|
# A variety of filters are available as configurations.
|
13
13
|
#
|
@@ -20,7 +20,7 @@ module Tap
|
|
20
20
|
#
|
21
21
|
# To glob within the task and not the command line, quote the glob.
|
22
22
|
#
|
23
|
-
# % tap
|
23
|
+
# % tap glob '*' -: dump/yaml
|
24
24
|
#
|
25
25
|
class Glob < Tap::Task
|
26
26
|
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'tap/task'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Tasks
|
5
|
+
# :startdoc::task insert into an array
|
6
|
+
#
|
7
|
+
# Insert supports a common workflow pattern of inserting variable
|
8
|
+
# arguments into an otherwise static array.
|
9
|
+
#
|
10
|
+
# % tap load moon -: insert goodnight %0 -: inspect
|
11
|
+
# ["goodnight", "moon"]
|
12
|
+
#
|
13
|
+
# The percent serves as a placeholder identifying the index of the
|
14
|
+
# argument that will be inserted. Unlike most tasks, command-line
|
15
|
+
# arguments provided to insert define the insertion template rather than
|
16
|
+
# inputs (ie they cannot be enqued or executed with -- or -!) so typically
|
17
|
+
# inserts are used with joins or signals.
|
18
|
+
#
|
19
|
+
# % tap insert goodnight %0 -: inspect -/enq 0 moon
|
20
|
+
# ["goodnight", "moon"]
|
21
|
+
#
|
22
|
+
# Arguments can be used more than once, as indicated. The default value
|
23
|
+
# will be used if the argument value at the given index is nil.
|
24
|
+
#
|
25
|
+
# % tap load a -: insert %0 %0 %1 -: inspect
|
26
|
+
# ["a", "a", nil]
|
27
|
+
#
|
28
|
+
class Insert < Tap::Task
|
29
|
+
class << self
|
30
|
+
def parse(argv=ARGV, app=Tap::App.current)
|
31
|
+
super(argv, app, &nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse!(argv=ARGV, app=Tap::App.current)
|
35
|
+
super(argv, app, &nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
def build(spec={}, app=Tap::App.current)
|
39
|
+
new(spec['template'], spec['config'], app)
|
40
|
+
end
|
41
|
+
|
42
|
+
def convert_to_spec(parser, args)
|
43
|
+
template = args.dup
|
44
|
+
args.clear
|
45
|
+
|
46
|
+
{
|
47
|
+
'config' => parser.nested_config,
|
48
|
+
'template' => template
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
config :placeholder, '%', :short => :p, &c.string # argument placeholder
|
54
|
+
config :default, nil # default insert value
|
55
|
+
|
56
|
+
attr_reader :template
|
57
|
+
|
58
|
+
def initialize(template, config={}, app=Tap::App.current)
|
59
|
+
super(config, app)
|
60
|
+
@template = template
|
61
|
+
@map = {}
|
62
|
+
|
63
|
+
plength = placeholder.length
|
64
|
+
template.each_with_index do |arg, index|
|
65
|
+
if arg.index(placeholder) == 0
|
66
|
+
@map[index] = arg[plength, arg.length - plength].to_i
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def process(*args)
|
72
|
+
result = template.dup
|
73
|
+
|
74
|
+
@map.each_pair do |insert_idx, arg_idx|
|
75
|
+
value = args[arg_idx]
|
76
|
+
result[insert_idx] = value.nil? ? default : value
|
77
|
+
end
|
78
|
+
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_spec
|
83
|
+
spec = super
|
84
|
+
spec['template'] = template
|
85
|
+
spec
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/tap/tasks/load/csv.rb
CHANGED
@@ -10,7 +10,7 @@ module Tap
|
|
10
10
|
# Load CSV data as an array of arrays, selecting the specified rows and
|
11
11
|
# columns.
|
12
12
|
#
|
13
|
-
# % tap
|
13
|
+
# % tap load/csv 'a,b,c.d,e,f' --row-sep '.' -: inspect
|
14
14
|
# [["a", "b", "c"], ["d", "e", "f"]]
|
15
15
|
#
|
16
16
|
# Note this task is quite inefficient in that it will load all data
|
@@ -22,12 +22,12 @@ module Tap
|
|
22
22
|
config :columns, nil, :short => :C, &c.range_or_nil # Specify a range of columns
|
23
23
|
config :rows, nil, :short => :R, &c.range_or_nil # Specify a range of rows
|
24
24
|
|
25
|
-
config :col_sep,
|
26
|
-
config :row_sep,
|
25
|
+
config :col_sep, ',', :short => :c, &c.string_or_nil # The column separator (",")
|
26
|
+
config :row_sep, $/, :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)
|
30
|
-
data =
|
30
|
+
data = parse(io.read)
|
31
31
|
|
32
32
|
if rows
|
33
33
|
data = data[rows]
|
@@ -42,6 +42,17 @@ module Tap
|
|
42
42
|
data
|
43
43
|
end
|
44
44
|
|
45
|
+
private
|
46
|
+
|
47
|
+
if RUBY_VERSION >= '1.9'
|
48
|
+
def parse(str)
|
49
|
+
CSV.parse(str, :col_sep => col_sep, :row_sep => row_sep)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
def parse(str)
|
53
|
+
CSV.parse(str, col_sep, row_sep)
|
54
|
+
end
|
55
|
+
end
|
45
56
|
end
|
46
57
|
end
|
47
58
|
end
|
data/lib/tap/tasks/load/yaml.rb
CHANGED
data/lib/tap/tasks/null.rb
CHANGED
@@ -8,11 +8,10 @@ module Tap
|
|
8
8
|
# to Null go nowhere. Null does not accept joins and will not execute
|
9
9
|
# the default app joins.
|
10
10
|
#
|
11
|
-
# % tap
|
11
|
+
# % tap load/yaml '[1, 2, 3]' -: null
|
12
12
|
#
|
13
|
-
class Null < Tap::Task
|
13
|
+
class Null < Tap::Task
|
14
14
|
def process(*args)
|
15
|
-
nil
|
16
15
|
end
|
17
16
|
|
18
17
|
def joins
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'tap/task'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Tasks
|
5
|
+
# :startdoc::task sleep
|
6
|
+
#
|
7
|
+
# Sleeps for the specified duration.
|
8
|
+
class Sleep < Tap::Task
|
9
|
+
config :duration, 1, &c.numeric # sleep duration (ms)
|
10
|
+
|
11
|
+
def call(input)
|
12
|
+
sleep duration
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/tap/tasks/version.rb
CHANGED
data/tap-tasks.gemspec
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
$:.unshift File.expand_path('../../tap/lib', __FILE__)
|
2
|
+
$:.unshift File.expand_path('../../tap-test/lib', __FILE__)
|
3
|
+
$:.unshift File.expand_path('../../tap-tasks/lib', __FILE__)
|
4
|
+
|
5
|
+
require 'tap/version'
|
6
|
+
require 'tap/test/version'
|
7
|
+
require 'tap/tasks/version'
|
8
|
+
|
9
|
+
Gem::Specification.new do |s|
|
10
|
+
s.name = 'tap-tasks'
|
11
|
+
s.version = Tap::Tasks::VERSION
|
12
|
+
s.author = 'Simon Chiang'
|
13
|
+
s.email = 'simon.a.chiang@gmail.com'
|
14
|
+
s.homepage = File.join(Tap::WEBSITE, 'tap-tasks')
|
15
|
+
s.platform = Gem::Platform::RUBY
|
16
|
+
s.summary = 'A set of standard Tap tasks'
|
17
|
+
s.require_path = 'lib'
|
18
|
+
s.rubyforge_project = 'tap'
|
19
|
+
s.add_dependency('tap', ">= #{Tap::VERSION}")
|
20
|
+
s.add_development_dependency('tap-test', ">= #{Tap::Test::VERSION}")
|
21
|
+
s.has_rdoc = true
|
22
|
+
s.rdoc_options.concat %W{--main README -S -N --title Tap-Tasks}
|
23
|
+
|
24
|
+
# list extra rdoc files here.
|
25
|
+
s.extra_rdoc_files = %W{
|
26
|
+
History
|
27
|
+
README
|
28
|
+
MIT-LICENSE
|
29
|
+
}
|
30
|
+
|
31
|
+
# list the files you want to include here. you can
|
32
|
+
# check this manifest using 'rap print_manifest'
|
33
|
+
s.files = %W{
|
34
|
+
lib/tap/tasks/insert.rb
|
35
|
+
lib/tap/tasks/console.rb
|
36
|
+
lib/tap/tasks/dump/csv.rb
|
37
|
+
lib/tap/tasks/dump/inspect.rb
|
38
|
+
lib/tap/tasks/dump/yaml.rb
|
39
|
+
lib/tap/tasks/error.rb
|
40
|
+
lib/tap/tasks/glob.rb
|
41
|
+
lib/tap/tasks/load/csv.rb
|
42
|
+
lib/tap/tasks/load/yaml.rb
|
43
|
+
lib/tap/tasks/null.rb
|
44
|
+
lib/tap/tasks/sleep.rb
|
45
|
+
lib/tap/tasks/stream/yaml.rb
|
46
|
+
lib/tap/tasks/version.rb
|
47
|
+
tap-tasks.gemspec
|
48
|
+
tap.yml
|
49
|
+
}
|
50
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tap-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 7
|
8
|
+
- 0
|
9
|
+
version: 0.7.0
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Simon Chiang
|
@@ -9,29 +14,37 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date:
|
17
|
+
date: 2010-05-02 00:00:00 -06:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: tap
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 3
|
30
|
+
- 0
|
31
|
+
version: 1.3.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
25
34
|
- !ruby/object:Gem::Dependency
|
26
35
|
name: tap-test
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
38
|
requirements:
|
31
39
|
- - ">="
|
32
40
|
- !ruby/object:Gem::Version
|
33
|
-
|
34
|
-
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
- 6
|
44
|
+
- 0
|
45
|
+
version: 0.6.0
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
35
48
|
description:
|
36
49
|
email: simon.a.chiang@gmail.com
|
37
50
|
executables: []
|
@@ -43,24 +56,26 @@ extra_rdoc_files:
|
|
43
56
|
- README
|
44
57
|
- MIT-LICENSE
|
45
58
|
files:
|
46
|
-
- lib/tap/
|
47
|
-
- lib/tap/
|
59
|
+
- lib/tap/tasks/insert.rb
|
60
|
+
- lib/tap/tasks/console.rb
|
48
61
|
- lib/tap/tasks/dump/csv.rb
|
49
62
|
- lib/tap/tasks/dump/inspect.rb
|
50
63
|
- lib/tap/tasks/dump/yaml.rb
|
51
|
-
- lib/tap/tasks/
|
64
|
+
- lib/tap/tasks/error.rb
|
65
|
+
- lib/tap/tasks/glob.rb
|
52
66
|
- lib/tap/tasks/load/csv.rb
|
67
|
+
- lib/tap/tasks/load/yaml.rb
|
53
68
|
- lib/tap/tasks/null.rb
|
54
|
-
- lib/tap/tasks/
|
55
|
-
- lib/tap/tasks/stream.rb
|
69
|
+
- lib/tap/tasks/sleep.rb
|
56
70
|
- lib/tap/tasks/stream/yaml.rb
|
57
71
|
- lib/tap/tasks/version.rb
|
72
|
+
- tap-tasks.gemspec
|
58
73
|
- tap.yml
|
59
74
|
- History
|
60
75
|
- README
|
61
76
|
- MIT-LICENSE
|
62
77
|
has_rdoc: true
|
63
|
-
homepage: http://tap.rubyforge.org/tap-tasks
|
78
|
+
homepage: http://tap.rubyforge.org/tap-tasks
|
64
79
|
licenses: []
|
65
80
|
|
66
81
|
post_install_message:
|
@@ -77,18 +92,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
77
92
|
requirements:
|
78
93
|
- - ">="
|
79
94
|
- !ruby/object:Gem::Version
|
95
|
+
segments:
|
96
|
+
- 0
|
80
97
|
version: "0"
|
81
|
-
version:
|
82
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
99
|
requirements:
|
84
100
|
- - ">="
|
85
101
|
- !ruby/object:Gem::Version
|
102
|
+
segments:
|
103
|
+
- 0
|
86
104
|
version: "0"
|
87
|
-
version:
|
88
105
|
requirements: []
|
89
106
|
|
90
107
|
rubyforge_project: tap
|
91
|
-
rubygems_version: 1.3.
|
108
|
+
rubygems_version: 1.3.6
|
92
109
|
signing_key:
|
93
110
|
specification_version: 3
|
94
111
|
summary: A set of standard Tap tasks
|
data/lib/tap/joins/gate.rb
DELETED
@@ -1,87 +0,0 @@
|
|
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
|
@@ -1,72 +0,0 @@
|
|
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
|
data/lib/tap/tasks/stream.rb
DELETED
@@ -1,64 +0,0 @@
|
|
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
|