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 +14 -0
- data/MIT-LICENSE +17 -18
- data/README +2 -5
- data/lib/tap/joins/gate.rb +87 -0
- data/lib/tap/middlewares/profiler.rb +72 -0
- data/lib/tap/tasks/dump/csv.rb +2 -2
- data/lib/tap/tasks/load/csv.rb +4 -4
- data/lib/tap/tasks/load/yaml.rb +1 -27
- data/lib/tap/tasks/null.rb +27 -0
- data/lib/tap/tasks/stream.rb +64 -0
- data/lib/tap/tasks/stream/yaml.rb +49 -0
- data/lib/tap/tasks/version.rb +9 -0
- metadata +15 -8
- data/lib/tap/tasks/prompt.rb +0 -42
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
|
-
|
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
|
-
|
13
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
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
|
-
|
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
|
data/lib/tap/tasks/dump/csv.rb
CHANGED
@@ -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.
|
data/lib/tap/tasks/load/csv.rb
CHANGED
@@ -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)
|
data/lib/tap/tasks/load/yaml.rb
CHANGED
@@ -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
|
-
|
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
|
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.
|
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-
|
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.
|
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.
|
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/
|
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
|
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.
|
91
|
+
rubygems_version: 1.3.5
|
85
92
|
signing_key:
|
86
|
-
specification_version:
|
93
|
+
specification_version: 3
|
87
94
|
summary: A set of standard Tap tasks
|
88
95
|
test_files: []
|
89
96
|
|
data/lib/tap/tasks/prompt.rb
DELETED
@@ -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
|