tap 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History +9 -0
- data/README +1 -0
- data/bin/tap +7 -45
- data/cmd/manifest.rb +94 -0
- data/cmd/run.rb +1 -1
- data/lib/tap.rb +0 -5
- data/lib/tap/constants.rb +1 -1
- data/lib/tap/env.rb +195 -187
- data/lib/tap/exe.rb +63 -0
- data/lib/tap/file_task.rb +33 -8
- data/lib/tap/generator/base.rb +7 -28
- data/lib/tap/generator/generators/root/root_generator.rb +21 -15
- data/lib/tap/generator/generators/root/templates/Rakefile +1 -1
- data/lib/tap/generator/generators/root/templates/gemspec +2 -1
- data/lib/tap/patches/rake/testtask.rb +2 -0
- data/lib/tap/support/class_configuration.rb +5 -6
- data/lib/tap/support/configurable_class.rb +15 -18
- data/lib/tap/support/configuration.rb +8 -6
- data/lib/tap/support/declarations.rb +2 -2
- data/lib/tap/support/framework.rb +14 -2
- data/lib/tap/support/framework_class.rb +13 -32
- data/lib/tap/support/gems.rb +63 -0
- data/lib/tap/support/gems/rake.rb +90 -0
- data/lib/tap/support/instance_configuration.rb +8 -8
- data/lib/tap/support/lazy_attributes.rb +30 -0
- data/lib/tap/support/lazydoc.rb +65 -33
- data/lib/tap/support/manifest.rb +117 -54
- data/lib/tap/tasks/rake.rb +1 -0
- data/lib/tap/test/script_methods.rb +34 -71
- data/lib/tap/test/script_methods/script_test.rb +98 -0
- data/lib/tap/test/tap_methods.rb +1 -5
- data/lib/tap/workflow.rb +47 -34
- metadata +8 -2
@@ -8,9 +8,9 @@ module Tap
|
|
8
8
|
|
9
9
|
# Returns the default name for the class: to_s.underscore
|
10
10
|
attr_accessor :default_name
|
11
|
-
|
11
|
+
|
12
12
|
def self.extended(base)
|
13
|
-
caller.
|
13
|
+
caller.each do |line|
|
14
14
|
case line
|
15
15
|
when /\/framework.rb/ then next
|
16
16
|
when /^(([A-z]:)?[^:]+):(\d+)/
|
@@ -66,7 +66,8 @@ module Tap
|
|
66
66
|
when /\/tap\/support\/declarations.rb/ then next
|
67
67
|
when /^(([A-z]:)?[^:]+):(\d+)/
|
68
68
|
subclass.source_file = File.expand_path($1)
|
69
|
-
|
69
|
+
lzd = subclass.lazydoc(false)
|
70
|
+
lzd[const_name, false]['manifest'] = lzd.register($3.to_i - 1)
|
70
71
|
break
|
71
72
|
end
|
72
73
|
end
|
@@ -82,13 +83,14 @@ module Tap
|
|
82
83
|
array.join(' ')
|
83
84
|
else ""
|
84
85
|
end
|
85
|
-
subclass.lazydoc[const_name, false]['args'] ||= comment
|
86
|
+
subclass.lazydoc(false)[const_name, false]['args'] ||= comment
|
86
87
|
|
87
88
|
# Set the subclass constant
|
88
89
|
current.const_set(subclass_const, subclass)
|
89
90
|
end
|
90
91
|
|
91
|
-
DEFAULT_HELP_TEMPLATE = %Q{
|
92
|
+
DEFAULT_HELP_TEMPLATE = %Q{<% manifest = task_class.manifest %>
|
93
|
+
<%= task_class %><%= manifest.subject.to_s.strip.empty? ? '' : ' -- ' %><%= manifest.subject %>
|
92
94
|
|
93
95
|
<% unless manifest.empty? %>
|
94
96
|
<%= '-' * 80 %>
|
@@ -122,8 +124,6 @@ module Tap
|
|
122
124
|
opts.separator "options:"
|
123
125
|
|
124
126
|
opts.on_tail("-h", "--help", "Print this help") do
|
125
|
-
args = lazydoc(true)[to_s]['args'] || Tap::Support::Comment.new
|
126
|
-
|
127
127
|
opts.banner = "#{help}usage: tap run -- #{to_s.underscore} #{args.subject}"
|
128
128
|
puts opts
|
129
129
|
exit
|
@@ -166,33 +166,14 @@ module Tap
|
|
166
166
|
[obj.reconfigure(path_configs).reconfigure(config), argv + use_args]
|
167
167
|
end
|
168
168
|
|
169
|
-
def lazydoc(resolve=
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
comment.subject = match[2].to_s.split(',').collect do |arg|
|
174
|
-
arg = arg.strip.upcase
|
175
|
-
case arg
|
176
|
-
when /^&/ then nil
|
177
|
-
when /^\*/ then arg[1..-1] + "..."
|
178
|
-
else arg
|
179
|
-
end
|
180
|
-
end.join(', ')
|
181
|
-
|
182
|
-
lazydoc.default_attributes['args'] ||= comment
|
183
|
-
end
|
184
|
-
|
185
|
-
super(true)
|
186
|
-
else
|
187
|
-
super(false)
|
188
|
-
end
|
169
|
+
def lazydoc(resolve=true)
|
170
|
+
lazydoc = super(false)
|
171
|
+
lazydoc.register_method_pattern('args', :process) unless lazydoc.resolved?
|
172
|
+
super
|
189
173
|
end
|
190
|
-
|
174
|
+
|
191
175
|
def help
|
192
|
-
Tap::Support::Templater.new(DEFAULT_HELP_TEMPLATE,
|
193
|
-
:task_class => self,
|
194
|
-
:manifest => lazydoc(true)[to_s]['manifest'] || Tap::Support::Comment.new
|
195
|
-
).build
|
176
|
+
Tap::Support::Templater.new(DEFAULT_HELP_TEMPLATE, :task_class => self).build
|
196
177
|
end
|
197
178
|
end
|
198
179
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
autoload(:Gem, 'rubygems')
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Support
|
5
|
+
module Gems
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Finds the home directory for the user (method taken from Rubygems).
|
9
|
+
def find_home
|
10
|
+
['HOME', 'USERPROFILE'].each do |homekey|
|
11
|
+
return ENV[homekey] if ENV[homekey]
|
12
|
+
end
|
13
|
+
|
14
|
+
if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
|
15
|
+
return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}"
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
File.expand_path("~")
|
20
|
+
rescue
|
21
|
+
if File::ALT_SEPARATOR then
|
22
|
+
"C:/"
|
23
|
+
else
|
24
|
+
"/"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# The home directory for the user.
|
30
|
+
def user_home
|
31
|
+
@user_home ||= find_home
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the gemspec for the specified gem. A gem version
|
35
|
+
# can be specified in the name, like 'gem >= 1.2'. The gem
|
36
|
+
# will be activated using +gem+ if necessary.
|
37
|
+
def gemspec(gem_name)
|
38
|
+
return gem_name if gem_name.kind_of?(Gem::Specification)
|
39
|
+
|
40
|
+
# figure the version of the gem, by default >= 0.0.0
|
41
|
+
gem_name.to_s =~ /^([^<=>]*)(.*)$/
|
42
|
+
name, version = $1.strip, $2
|
43
|
+
version = ">= 0.0.0" if version.empty?
|
44
|
+
|
45
|
+
return nil if name.empty?
|
46
|
+
|
47
|
+
# load the gem and get the spec
|
48
|
+
gem(name, version)
|
49
|
+
Gem.loaded_specs[name]
|
50
|
+
end
|
51
|
+
|
52
|
+
def select_gems(latest=true)
|
53
|
+
index = latest ?
|
54
|
+
Gem.source_index.latest_specs :
|
55
|
+
Gem.source_index.gems.collect {|(name, spec)| spec }
|
56
|
+
|
57
|
+
index.select do |spec|
|
58
|
+
yield(spec)
|
59
|
+
end.sort
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'tap'
|
3
|
+
|
4
|
+
module Tap
|
5
|
+
module Support
|
6
|
+
module Gems
|
7
|
+
class RakeManifest < Support::Manifest
|
8
|
+
def initialize(env)
|
9
|
+
@env = env
|
10
|
+
rake = ::Rake.application
|
11
|
+
super(rake.have_rakefile(env.root.root) ? [rake.instance_variable_get(:@rakefile)] : [])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Rake
|
16
|
+
|
17
|
+
def self.extended(base)
|
18
|
+
Tap::Env.instance_for(Dir.pwd).activate unless Tap::Env.instance
|
19
|
+
base.env = Tap::Env.instance
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :env
|
23
|
+
|
24
|
+
def collect_tasks
|
25
|
+
ARGV.collect! do |arg|
|
26
|
+
next(arg) unless arg =~ /^:([a-z_\d]+):(.*)$/
|
27
|
+
env_pattern = $1
|
28
|
+
rake_task = $2
|
29
|
+
|
30
|
+
next(arg) unless entry = env.find(:envs, env_pattern, false)
|
31
|
+
|
32
|
+
mini_path, env = entry
|
33
|
+
root_path = env.root.root
|
34
|
+
|
35
|
+
if have_rakefile(root_path)
|
36
|
+
# load sequence echos that in raw_load_rakefile
|
37
|
+
puts "(in #{root_path})" unless options.silent
|
38
|
+
current_global_rakefile = $rakefile
|
39
|
+
$rakefile = @rakefile
|
40
|
+
|
41
|
+
namespaces = Tap::Root.split(mini_path, false).delete_if do |segment|
|
42
|
+
segment.empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
#if @rakefile != ''
|
46
|
+
eval nest_namespace(%Q{load "#{File.join(root_path, @rakefile)}"}, namespaces.dup)
|
47
|
+
#end
|
48
|
+
|
49
|
+
$rakefile = current_global_rakefile
|
50
|
+
@rakefile = nil
|
51
|
+
|
52
|
+
namespaces << rake_task
|
53
|
+
namespaces.join(":")
|
54
|
+
else
|
55
|
+
fail "No Rakefile found for '#{env_pattern}' (looking for: #{@rakefiles.join(', ')})"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
def have_rakefile(indir=nil)
|
63
|
+
return super() if indir == nil
|
64
|
+
Tap::Root.indir(indir) { super() }
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
NAMESPACE_STR = %Q{
|
70
|
+
namespace(:'%s') do
|
71
|
+
%s
|
72
|
+
end
|
73
|
+
}.strip
|
74
|
+
|
75
|
+
def nest_namespace(nest_str, namespaces)
|
76
|
+
return nest_str if namespaces.empty?
|
77
|
+
|
78
|
+
NAMESPACE_STR % [
|
79
|
+
namespaces.shift,
|
80
|
+
namespaces.empty? ? nest_str : nest_namespace(nest_str, namespaces)
|
81
|
+
]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
Rake.application.extend Tap::Support::Gems::Rake
|
89
|
+
Tap::Env.manifests[:rakefiles] = Tap::Support::RakeManifest
|
90
|
+
|
@@ -41,9 +41,9 @@ module Tap
|
|
41
41
|
# The ClassConfiguration specifying config keys
|
42
42
|
attr_reader :class_config
|
43
43
|
|
44
|
-
def initialize(class_config, receiver=nil)
|
44
|
+
def initialize(class_config, receiver=nil, store={})
|
45
45
|
@receiver = receiver
|
46
|
-
@store =
|
46
|
+
@store = store
|
47
47
|
@class_config = class_config
|
48
48
|
end
|
49
49
|
|
@@ -54,7 +54,7 @@ module Tap
|
|
54
54
|
raise ArgumentError.new("receiver cannot be nil") if receiver == nil
|
55
55
|
|
56
56
|
class_config.each_pair do |key, config|
|
57
|
-
receiver.send(config.writer, store.delete(key))
|
57
|
+
receiver.send(config.writer, store.delete(key)) if config.writer
|
58
58
|
end
|
59
59
|
@receiver = receiver
|
60
60
|
|
@@ -70,7 +70,7 @@ module Tap
|
|
70
70
|
# are stored in store. Returns the unbound receiver.
|
71
71
|
def unbind
|
72
72
|
class_config.each_pair do |key, config|
|
73
|
-
store[key] = receiver.send(config.reader)
|
73
|
+
store[key] = receiver.send(config.reader) if config.reader
|
74
74
|
end
|
75
75
|
r = receiver
|
76
76
|
@receiver = nil
|
@@ -92,7 +92,7 @@ module Tap
|
|
92
92
|
def []=(key, value)
|
93
93
|
case
|
94
94
|
when bound? && config = class_config.map[key.to_sym]
|
95
|
-
receiver.send(config.writer, value)
|
95
|
+
config.writer ? receiver.send(config.writer, value) : store[key] = value
|
96
96
|
else store[key] = value
|
97
97
|
end
|
98
98
|
end
|
@@ -103,7 +103,7 @@ module Tap
|
|
103
103
|
def [](key)
|
104
104
|
case
|
105
105
|
when bound? && config = class_config.map[key.to_sym]
|
106
|
-
receiver.send(config.reader)
|
106
|
+
config.reader ? receiver.send(config.reader) : store[key]
|
107
107
|
else store[key]
|
108
108
|
end
|
109
109
|
end
|
@@ -116,7 +116,7 @@ module Tap
|
|
116
116
|
# Calls block once for each key-value pair stored in self.
|
117
117
|
def each_pair # :yields: key, value
|
118
118
|
class_config.each_pair do |key, config|
|
119
|
-
yield(key, receiver.send(config.reader))
|
119
|
+
yield(key, receiver.send(config.reader)) if config.reader
|
120
120
|
end if bound?
|
121
121
|
|
122
122
|
store.each_pair do |key, value|
|
@@ -126,7 +126,7 @@ module Tap
|
|
126
126
|
|
127
127
|
# Equal if the to_hash values of self and another are equal.
|
128
128
|
def ==(another)
|
129
|
-
to_hash == another.to_hash
|
129
|
+
another.respond_to?(:to_hash) && to_hash == another.to_hash
|
130
130
|
end
|
131
131
|
|
132
132
|
# Returns self as a hash.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'tap/support/lazydoc'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Support
|
5
|
+
module LazyAttributes
|
6
|
+
|
7
|
+
# The source_file for self. Must be set independently.
|
8
|
+
attr_accessor :source_file
|
9
|
+
|
10
|
+
# Returns the lazydoc for source_file
|
11
|
+
def lazydoc(resolve=true)
|
12
|
+
lazydoc = Lazydoc[source_file]
|
13
|
+
lazydoc.resolve if resolve
|
14
|
+
lazydoc
|
15
|
+
end
|
16
|
+
|
17
|
+
# Creates a lazy attribute reader for the specified attribute.
|
18
|
+
def lazy_attr(key, attribute=key)
|
19
|
+
instance_eval %Q{def #{key}; @#{key} ||= get_lazy_attr('#{attribute}'); end}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def get_lazy_attr(attribute)
|
25
|
+
lazydoc[self.to_s][attribute] || (lazydoc.attributes(self.to_s)[attribute] = Tap::Support::Comment.new)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/tap/support/lazydoc.rb
CHANGED
@@ -10,8 +10,7 @@ module Tap
|
|
10
10
|
#
|
11
11
|
# Constant attributes are designated the same as constants in Ruby, but with
|
12
12
|
# an extra 'key' constant that must consist of only lowercase letters and/or
|
13
|
-
# underscores.
|
14
|
-
# outside of comments.
|
13
|
+
# underscores. Attributes are only parsed from comment lines.
|
15
14
|
#
|
16
15
|
# When Lazydoc finds an attribute it parses a Comment value where the subject
|
17
16
|
# is the remainder of the line, and comment lines are parsed down until a
|
@@ -49,6 +48,8 @@ module Tap
|
|
49
48
|
# # Const::Name::not_parsed
|
50
49
|
# # :::+
|
51
50
|
#
|
51
|
+
# Const::Name::not_parsed
|
52
|
+
#
|
52
53
|
# # Const::Name::parsed subject
|
53
54
|
# }
|
54
55
|
#
|
@@ -127,10 +128,10 @@ module Tap
|
|
127
128
|
# $3:: key
|
128
129
|
# $4:: end flag
|
129
130
|
#
|
130
|
-
ATTRIBUTE_REGEXP = /(
|
131
|
-
|
132
|
-
# A regexp matching constants
|
133
|
-
CONSTANT_REGEXP =
|
131
|
+
ATTRIBUTE_REGEXP = /([A-Z][A-z]*(::[A-Z][A-z]*)*)?::([a-z_]+)(-?)/
|
132
|
+
|
133
|
+
# A regexp matching constants from the ATTRIBUTE_REGEXP leader
|
134
|
+
CONSTANT_REGEXP = /#.*?([A-Z][A-z]*(::[A-Z][A-z]*)*)?$/
|
134
135
|
|
135
136
|
class << self
|
136
137
|
|
@@ -159,7 +160,7 @@ module Tap
|
|
159
160
|
end
|
160
161
|
|
161
162
|
# Resolves all lazydocs which include the specified code comments.
|
162
|
-
def
|
163
|
+
def resolve_comments(code_comments)
|
163
164
|
registry.each do |doc|
|
164
165
|
next if (code_comments & doc.code_comments).empty?
|
165
166
|
doc.resolve
|
@@ -185,14 +186,16 @@ module Tap
|
|
185
186
|
# and <tt>:+</tt>.
|
186
187
|
#
|
187
188
|
# str = %Q{
|
188
|
-
# Const::Name::key value
|
189
|
-
# ::alt alt_value
|
189
|
+
# # Const::Name::key value
|
190
|
+
# # ::alt alt_value
|
191
|
+
# #
|
192
|
+
# # Ignored::Attribute::not_matched value
|
193
|
+
# # :::-
|
194
|
+
# # Also::Ignored::key value
|
195
|
+
# # :::+
|
196
|
+
# # Another::key another value
|
190
197
|
#
|
191
|
-
# Ignored::
|
192
|
-
# :::-
|
193
|
-
# Also::Ignored::key value
|
194
|
-
# :::+
|
195
|
-
# Another::key another value
|
198
|
+
# Ignored::key value
|
196
199
|
# }
|
197
200
|
#
|
198
201
|
# results = []
|
@@ -213,17 +216,17 @@ module Tap
|
|
213
216
|
when String then StringScanner.new(str)
|
214
217
|
else raise TypeError, "can't convert #{str.class} into StringScanner or String"
|
215
218
|
end
|
216
|
-
|
217
|
-
regexp =
|
219
|
+
|
220
|
+
regexp = /^(.*?)::(:-|#{key})/
|
218
221
|
while !scanner.eos?
|
219
|
-
break if scanner.skip_until(
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
scanner.
|
222
|
+
break if scanner.skip_until(regexp) == nil
|
223
|
+
|
224
|
+
if scanner[2] == ":-"
|
225
|
+
scanner.skip_until(/:::\+/)
|
226
|
+
else
|
227
|
+
next unless scanner[1] =~ CONSTANT_REGEXP
|
228
|
+
key = scanner[2]
|
229
|
+
yield($1.to_s, key, scanner.matched.strip) if scanner.scan(/[ \r\t].*$|$/)
|
227
230
|
end
|
228
231
|
end
|
229
232
|
|
@@ -267,9 +270,9 @@ module Tap
|
|
267
270
|
|
268
271
|
scan(scanner, '[a-z_]+') do |const_name, key, value|
|
269
272
|
comment = Comment.parse(scanner, false) do |line|
|
270
|
-
if line =~
|
273
|
+
if line =~ ATTRIBUTE_REGEXP
|
271
274
|
# rewind to capture the next attribute unless an end is specified.
|
272
|
-
scanner.unscan unless
|
275
|
+
scanner.unscan unless $4 == '-' && $3 == key && $1.to_s == const_name
|
273
276
|
true
|
274
277
|
else false
|
275
278
|
end
|
@@ -294,10 +297,13 @@ module Tap
|
|
294
297
|
# attributes resolved or to-be-resolved for self. Attributes
|
295
298
|
# are hashes of (key, comment) pairs.
|
296
299
|
attr_reader :const_attrs
|
297
|
-
|
300
|
+
|
301
|
+
attr_reader :patterns
|
302
|
+
|
298
303
|
def initialize(source_file=nil)
|
299
304
|
self.source_file = source_file
|
300
305
|
@code_comments = []
|
306
|
+
@patterns = {}
|
301
307
|
@const_attrs = {}
|
302
308
|
@resolved = false
|
303
309
|
end
|
@@ -364,6 +370,25 @@ module Tap
|
|
364
370
|
comment
|
365
371
|
end
|
366
372
|
|
373
|
+
def register_pattern(key, regexp, &block) # :yields: comment, match
|
374
|
+
patterns[key] = [regexp, block]
|
375
|
+
end
|
376
|
+
|
377
|
+
def register_method_pattern(key, method, range=0..-1)
|
378
|
+
register_pattern(key, /^\s*def\s+#{method}(\((.*?)\))?/) do |comment, match|
|
379
|
+
args = match[2].to_s.split(',').collect do |arg|
|
380
|
+
arg = arg.strip.upcase
|
381
|
+
case arg
|
382
|
+
when /^&/ then nil
|
383
|
+
when /^\*/ then arg[1..-1] + "..."
|
384
|
+
else arg
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
comment.subject = args[range].join(', ')
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
367
392
|
# Returns true if the code_comments for source_file are frozen.
|
368
393
|
def resolved?
|
369
394
|
@resolved
|
@@ -371,7 +396,7 @@ module Tap
|
|
371
396
|
|
372
397
|
attr_writer :resolved
|
373
398
|
|
374
|
-
def resolve(str=nil
|
399
|
+
def resolve(str=nil)
|
375
400
|
return(false) if resolved?
|
376
401
|
|
377
402
|
if str == nil
|
@@ -384,11 +409,18 @@ module Tap
|
|
384
409
|
end
|
385
410
|
|
386
411
|
lines = str.split(/\r?\n/)
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
412
|
+
|
413
|
+
patterns.each_pair do |key, (regexp, block)|
|
414
|
+
next if default_attributes.has_key?(key)
|
415
|
+
|
416
|
+
lines.each_with_index do |line, line_number|
|
417
|
+
next unless line =~ regexp
|
418
|
+
|
419
|
+
comment = register(line_number)
|
420
|
+
default_attributes[key] = comment
|
421
|
+
break if block.call(comment, $~)
|
422
|
+
end
|
423
|
+
end unless patterns.empty?
|
392
424
|
|
393
425
|
code_comments.collect! do |comment|
|
394
426
|
line_number = comment.line_number
|