tap 0.19.0 → 1.3.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.
Files changed (66) hide show
  1. data/History +100 -45
  2. data/MIT-LICENSE +1 -1
  3. data/README +95 -51
  4. data/bin/tap +11 -57
  5. data/bin/tapexe +84 -0
  6. data/doc/API +91 -139
  7. data/doc/Configuration +93 -0
  8. data/doc/Examples/Command Line +10 -42
  9. data/doc/Examples/Tapfile +124 -0
  10. data/doc/Ruby to Ruby +87 -0
  11. data/doc/Workflow Syntax +185 -0
  12. data/lib/tap.rb +74 -5
  13. data/lib/tap/app.rb +217 -310
  14. data/lib/tap/app/api.rb +44 -23
  15. data/lib/tap/app/queue.rb +11 -12
  16. data/lib/tap/app/stack.rb +4 -4
  17. data/lib/tap/declarations.rb +200 -0
  18. data/lib/tap/declarations/context.rb +31 -0
  19. data/lib/tap/declarations/description.rb +33 -0
  20. data/lib/tap/env.rb +133 -779
  21. data/lib/tap/env/cache.rb +87 -0
  22. data/lib/tap/env/constant.rb +94 -39
  23. data/lib/tap/env/path.rb +71 -0
  24. data/lib/tap/join.rb +42 -78
  25. data/lib/tap/joins/gate.rb +85 -0
  26. data/lib/tap/joins/switch.rb +4 -2
  27. data/lib/tap/joins/sync.rb +3 -3
  28. data/lib/tap/middleware.rb +5 -5
  29. data/lib/tap/middlewares/debugger.rb +18 -58
  30. data/lib/tap/parser.rb +115 -183
  31. data/lib/tap/root.rb +162 -239
  32. data/lib/tap/signal.rb +72 -0
  33. data/lib/tap/signals.rb +20 -2
  34. data/lib/tap/signals/class_methods.rb +38 -43
  35. data/lib/tap/signals/configure.rb +19 -0
  36. data/lib/tap/signals/help.rb +5 -7
  37. data/lib/tap/signals/load.rb +49 -0
  38. data/lib/tap/signals/module_methods.rb +1 -0
  39. data/lib/tap/task.rb +46 -275
  40. data/lib/tap/tasks/dump.rb +21 -16
  41. data/lib/tap/tasks/list.rb +184 -0
  42. data/lib/tap/tasks/load.rb +4 -4
  43. data/lib/tap/tasks/prompt.rb +128 -0
  44. data/lib/tap/tasks/signal.rb +42 -0
  45. data/lib/tap/tasks/singleton.rb +35 -0
  46. data/lib/tap/tasks/stream.rb +64 -0
  47. data/lib/tap/utils.rb +83 -0
  48. data/lib/tap/version.rb +2 -2
  49. data/lib/tap/workflow.rb +124 -0
  50. data/tap.yml +0 -0
  51. metadata +59 -24
  52. data/cmd/console.rb +0 -43
  53. data/cmd/manifest.rb +0 -118
  54. data/cmd/run.rb +0 -145
  55. data/doc/Examples/Workflow +0 -40
  56. data/lib/tap/app/node.rb +0 -29
  57. data/lib/tap/env/context.rb +0 -61
  58. data/lib/tap/env/gems.rb +0 -63
  59. data/lib/tap/env/manifest.rb +0 -179
  60. data/lib/tap/env/minimap.rb +0 -308
  61. data/lib/tap/intern.rb +0 -50
  62. data/lib/tap/joins.rb +0 -9
  63. data/lib/tap/prompt.rb +0 -36
  64. data/lib/tap/root/utils.rb +0 -220
  65. data/lib/tap/root/versions.rb +0 -138
  66. data/lib/tap/signals/signal.rb +0 -68
@@ -0,0 +1,35 @@
1
+ require 'tap/task'
2
+
3
+ module Tap
4
+ module Tasks
5
+ class Singleton < Tap::Task
6
+ class << self
7
+ def cache
8
+ @cache ||= {}
9
+ end
10
+
11
+ def new(*args)
12
+ obj = super
13
+ cache[obj.signature] ||= obj
14
+ end
15
+ end
16
+
17
+ attr_reader :cache
18
+ attr_reader :signature
19
+
20
+ def initialize(config={}, app=Tap::App.current)
21
+ @signature = [config.dup, app].freeze
22
+ super(config, app)
23
+ reset
24
+ end
25
+
26
+ def call(input)
27
+ cache.has_key?(input) ? cache[input] : cache[input] = super
28
+ end
29
+
30
+ def reset
31
+ @cache = {}
32
+ end
33
+ end
34
+ end
35
+ 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.pq(self, [io])
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,83 @@
1
+ require 'tempfile'
2
+
3
+ module Tap
4
+
5
+ #
6
+ # == Windows
7
+ # MSDOS has command line length limits specific to the version of Windows being
8
+ # run (from http://www.ss64.com/nt/cmd.html):
9
+ #
10
+ # Windows NT:: 256 characters
11
+ # Windows 2000:: 2046 characters
12
+ # Windows XP:: 8190 characters
13
+ #
14
+ # Commands longer than these limits fail, usually with something like: 'the input
15
+ # line is too long'
16
+ module Utils
17
+ module_function
18
+
19
+ def shellsplit(line, comment="#")
20
+ words = []
21
+ field = ''
22
+ line.scan(/\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\s|\z)?/m) do
23
+ |word, sq, dq, esc, garbage, sep|
24
+ raise ArgumentError, "Unmatched double quote: #{line.inspect}" if garbage
25
+ break if word == comment
26
+ field << (word || sq || (dq || esc).gsub(/\\(?=.)/, ''))
27
+ if sep
28
+ words << field
29
+ field = ''
30
+ end
31
+ end
32
+ words
33
+ end
34
+
35
+ # Sets the specified ENV variables and returns the *current* env.
36
+ # If replace is true, current ENV variables are replaced; otherwise
37
+ # the new env variables are simply added to the existing set.
38
+ def set_env(env={}, replace=false)
39
+ current_env = {}
40
+ ENV.each_pair do |key, value|
41
+ current_env[key] = value
42
+ end
43
+
44
+ ENV.clear if replace
45
+
46
+ env.each_pair do |key, value|
47
+ if value.nil?
48
+ ENV.delete(key)
49
+ else
50
+ ENV[key] = value
51
+ end
52
+ end if env
53
+
54
+ current_env
55
+ end
56
+
57
+ # Sets the specified ENV variables for the duration of the block.
58
+ # If replace is true, current ENV variables are replaced; otherwise
59
+ # the new env variables are simply added to the existing set.
60
+ #
61
+ # Returns the block return.
62
+ def with_env(env={}, replace=false)
63
+ current_env = nil
64
+ begin
65
+ current_env = set_env(env, replace)
66
+ yield
67
+ ensure
68
+ if current_env
69
+ set_env(current_env, true)
70
+ end
71
+ end
72
+ end
73
+
74
+ def sh_escape(str)
75
+ str.to_s.gsub("'", "\\\\'").gsub(";", '\\;')
76
+ end
77
+
78
+ # Run the command with system and raise an error if it fails.
79
+ def sh(*cmd)
80
+ system(*cmd) or raise "Command failed with status (#{$?.exitstatus}): [#{cmd.join(' ')}]"
81
+ end
82
+ end
83
+ end
@@ -1,6 +1,6 @@
1
1
  module Tap
2
- MAJOR = 0
3
- MINOR = 19
2
+ MAJOR = 1
3
+ MINOR = 3
4
4
  TINY = 0
5
5
 
6
6
  VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
@@ -0,0 +1,124 @@
1
+ require 'tap/task'
2
+
3
+ module Tap
4
+ class Workflow < Task
5
+ class << self
6
+ protected
7
+
8
+ # Defines a task subclass with the specified configurations and process
9
+ # block. During initialization the subclass is instantiated and made
10
+ # accessible through the name method.
11
+ #
12
+ # Defined tasks may be configured during through config, or directly
13
+ # through the instance; in effect you get tasks with nested configs which
14
+ # can greatly facilitate workflows.
15
+ #
16
+ # class AddALetter < Tap::Task
17
+ # config :letter, 'a'
18
+ # def process(input); input << letter; end
19
+ # end
20
+ #
21
+ # class AlphabetSoup < Tap::Task
22
+ # define :a, AddALetter, {:letter => 'a'}
23
+ # define :b, AddALetter, {:letter => 'b'}
24
+ # define :c, AddALetter, {:letter => 'c'}
25
+ #
26
+ # def process
27
+ # sequence(a, b, c)
28
+ # [a, c]
29
+ # end
30
+ # end
31
+ #
32
+ # AlphabetSoup.new.process # => 'abc'
33
+ #
34
+ # i = AlphabetSoup.new(:a => {:letter => 'x'}, :b => {:letter => 'y'}, :c => {:letter => 'z'})
35
+ # i.process # => 'xyz'
36
+ #
37
+ # i.config[:a] = {:letter => 'p'}
38
+ # i.config[:b][:letter] = 'q'
39
+ # i.c.letter = 'r'
40
+ # i.process # => 'pqr'
41
+ #
42
+ # ==== Usage
43
+ #
44
+ # Define is basically the equivalent of:
45
+ #
46
+ # class Sample < Tap::Task
47
+ # Name = baseclass.subclass(config, &block)
48
+ #
49
+ # # accesses an instance of Name
50
+ # attr_reader :name
51
+ #
52
+ # # register name as a config, but with a
53
+ # # non-standard reader and writer
54
+ # config :name, {}, {:reader => :name_config, :writer => :name_config=}.merge(options)
55
+ #
56
+ # # reader for name.config
57
+ # def name_config; ...; end
58
+ #
59
+ # # reconfigures name with input
60
+ # def name_config=(input); ...; end
61
+ #
62
+ # def initialize(*args)
63
+ # super
64
+ # @name = Name.new(config[:name])
65
+ # end
66
+ # end
67
+ #
68
+ # Note the following:
69
+ # * define will set a constant like name.camelize
70
+ # * the block defines the process method in the subclass
71
+ # * three methods are created by define: name, name_config, name_config=
72
+ #
73
+ def define(name, baseclass=Tap::Task, configs={}, options={}, &block)
74
+ # define the subclass
75
+ subclass = Class.new(baseclass)
76
+ configs.each_pair do |key, value|
77
+ subclass.send(:config, key, value)
78
+ end
79
+
80
+ if block_given?
81
+ # prevent lazydoc registration of the process method
82
+ subclass.registered_methods.delete(:process)
83
+ subclass.send(:define_method, :process, &block)
84
+ end
85
+
86
+ # register documentation
87
+ # TODO: register subclass in documentation
88
+ options[:desc] ||= Lazydoc.register_caller(Lazydoc::Trailer, 1)
89
+
90
+ # add the configuration
91
+ nest(name, subclass, {:const_name => name.to_s.camelize}.merge!(options))
92
+ end
93
+ end
94
+
95
+ attr_reader :entry_point
96
+ attr_reader :exit_point
97
+
98
+ def initialize(config={}, app=Tap::App.current)
99
+ super
100
+ @entry_point, @exit_point = process
101
+ end
102
+
103
+ def call(input)
104
+ output = nil
105
+
106
+ if exit_point
107
+ joins = exit_point.joins
108
+
109
+ collector = lambda do |result|
110
+ output = result
111
+ joins.delete(collector)
112
+ end
113
+
114
+ joins << collector
115
+ end
116
+
117
+ if entry_point
118
+ app.exe(entry_point, input)
119
+ end
120
+
121
+ output
122
+ end
123
+ end
124
+ end
data/tap.yml ADDED
File without changes
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.0
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 3
8
+ - 0
9
+ version: 1.3.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Simon Chiang
@@ -9,19 +14,37 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-12-05 00:00:00 -07:00
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: configurable
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 7
30
+ - 0
31
+ version: 0.7.0
17
32
  type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: tap-test
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
20
38
  requirements:
21
39
  - - ">="
22
40
  - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 6
44
+ - 0
23
45
  version: 0.6.0
24
- version:
46
+ type: :development
47
+ version_requirements: *id002
25
48
  description:
26
49
  email: simon.a.chiang@gmail.com
27
50
  executables:
@@ -33,54 +56,64 @@ extra_rdoc_files:
33
56
  - MIT-LICENSE
34
57
  - History
35
58
  - doc/API
59
+ - doc/Workflow Syntax
60
+ - doc/Ruby to Ruby
36
61
  - doc/Examples/Command Line
37
- - doc/Examples/Workflow
62
+ - doc/Examples/Tapfile
63
+ - doc/Configuration
38
64
  files:
39
- - cmd/console.rb
40
- - cmd/manifest.rb
41
- - cmd/run.rb
65
+ - bin/tapexe
42
66
  - lib/tap.rb
43
67
  - lib/tap/app.rb
44
68
  - lib/tap/app/api.rb
45
- - lib/tap/app/node.rb
46
69
  - lib/tap/app/queue.rb
47
70
  - lib/tap/app/stack.rb
48
71
  - lib/tap/app/state.rb
72
+ - lib/tap/declarations.rb
73
+ - lib/tap/declarations/context.rb
74
+ - lib/tap/declarations/description.rb
49
75
  - lib/tap/env.rb
76
+ - lib/tap/env/cache.rb
50
77
  - lib/tap/env/constant.rb
51
- - lib/tap/env/context.rb
52
- - lib/tap/env/gems.rb
53
- - lib/tap/env/manifest.rb
54
- - lib/tap/env/minimap.rb
78
+ - lib/tap/env/path.rb
55
79
  - lib/tap/env/string_ext.rb
56
- - lib/tap/intern.rb
57
80
  - lib/tap/join.rb
58
- - lib/tap/joins.rb
81
+ - lib/tap/joins/gate.rb
59
82
  - lib/tap/joins/switch.rb
60
83
  - lib/tap/joins/sync.rb
61
84
  - lib/tap/middleware.rb
62
85
  - lib/tap/middlewares/debugger.rb
63
86
  - lib/tap/parser.rb
64
- - lib/tap/prompt.rb
65
87
  - lib/tap/root.rb
66
- - lib/tap/root/utils.rb
67
- - lib/tap/root/versions.rb
88
+ - lib/tap/signal.rb
68
89
  - lib/tap/signals.rb
69
90
  - lib/tap/signals/class_methods.rb
91
+ - lib/tap/signals/configure.rb
70
92
  - lib/tap/signals/help.rb
93
+ - lib/tap/signals/load.rb
71
94
  - lib/tap/signals/module_methods.rb
72
- - lib/tap/signals/signal.rb
73
95
  - lib/tap/task.rb
74
96
  - lib/tap/tasks/dump.rb
75
97
  - lib/tap/tasks/load.rb
98
+ - lib/tap/tasks/list.rb
99
+ - lib/tap/tasks/prompt.rb
100
+ - lib/tap/tasks/singleton.rb
101
+ - lib/tap/tasks/signal.rb
102
+ - lib/tap/tasks/stream.rb
76
103
  - lib/tap/templater.rb
104
+ - lib/tap/utils.rb
77
105
  - lib/tap/version.rb
106
+ - lib/tap/workflow.rb
107
+ - tap.yml
78
108
  - README
79
109
  - MIT-LICENSE
80
110
  - History
81
111
  - doc/API
112
+ - doc/Workflow Syntax
113
+ - doc/Ruby to Ruby
82
114
  - doc/Examples/Command Line
83
- - doc/Examples/Workflow
115
+ - doc/Examples/Tapfile
116
+ - doc/Configuration
84
117
  has_rdoc: true
85
118
  homepage: http://tap.rubyforge.org
86
119
  licenses: []
@@ -99,18 +132,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
132
  requirements:
100
133
  - - ">="
101
134
  - !ruby/object:Gem::Version
135
+ segments:
136
+ - 0
102
137
  version: "0"
103
- version:
104
138
  required_rubygems_version: !ruby/object:Gem::Requirement
105
139
  requirements:
106
140
  - - ">="
107
141
  - !ruby/object:Gem::Version
142
+ segments:
143
+ - 0
108
144
  version: "0"
109
- version:
110
145
  requirements: []
111
146
 
112
147
  rubyforge_project: tap
113
- rubygems_version: 1.3.5
148
+ rubygems_version: 1.3.6
114
149
  signing_key:
115
150
  specification_version: 3
116
151
  summary: A configurable, distributable workflow framework.