pure 0.1.0 → 0.2.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/CHANGES.rdoc +7 -0
- data/MANIFEST +44 -20
- data/README.rdoc +553 -16
- data/Rakefile +25 -2
- data/devel/jumpstart.rb +606 -253
- data/install.rb +1 -2
- data/lib/pure.rb +38 -16
- data/lib/pure/bundled_parsers.rb +4 -0
- data/lib/pure/bundled_plugin.rb +49 -0
- data/lib/pure/compiler/ruby_parser.rb +63 -0
- data/lib/pure/delegate.rb +16 -0
- data/lib/pure/driver.rb +33 -0
- data/lib/pure/dsl.rb +2 -0
- data/lib/pure/dsl_definition.rb +11 -0
- data/lib/pure/error.rb +89 -0
- data/lib/pure/extracted_functions.rb +11 -0
- data/lib/pure/extractor.rb +59 -0
- data/lib/pure/names.rb +9 -0
- data/lib/pure/native_worker.rb +27 -0
- data/lib/pure/parser/impl/base_parser.rb +21 -0
- data/lib/pure/parser/impl/internal.rb +31 -0
- data/lib/pure/parser/impl/ripper.rb +96 -0
- data/lib/pure/parser/impl/ruby_parser.rb +77 -0
- data/lib/pure/parser/internal.rb +4 -0
- data/lib/pure/parser/ripper.rb +2 -0
- data/lib/pure/parser/ruby_parser.rb +2 -0
- data/lib/pure/pure.rb +32 -0
- data/lib/pure/pure_module.rb +141 -0
- data/lib/pure/util.rb +15 -0
- data/lib/pure/version.rb +4 -0
- data/spec/compiler_ruby_parser_spec.rb +79 -0
- data/spec/compute_overrides_spec.rb +99 -0
- data/spec/compute_spec.rb +86 -0
- data/spec/compute_thread_spec.rb +29 -0
- data/spec/compute_timed_spec.rb +40 -0
- data/spec/delegate_spec.rb +141 -0
- data/spec/fstat_example.rb +26 -0
- data/spec/parser_sexp_spec.rb +100 -0
- data/spec/parser_spec.rb +18 -31
- data/spec/pure_combine_spec.rb +77 -0
- data/spec/pure_def_spec.rb +186 -0
- data/spec/pure_define_method_spec.rb +24 -0
- data/spec/pure_eval_spec.rb +18 -0
- data/spec/pure_fun_spec.rb +243 -0
- data/spec/pure_nested_spec.rb +35 -0
- data/spec/pure_parser_spec.rb +50 -0
- data/spec/pure_spec.rb +81 -0
- data/spec/pure_spec_base.rb +106 -0
- data/spec/pure_splat_spec.rb +18 -0
- data/spec/pure_two_defs_spec.rb +20 -0
- data/spec/pure_worker_spec.rb +33 -0
- data/spec/readme_spec.rb +36 -32
- data/spec/splat_spec.rb +12 -11
- data/spec/worker_spec.rb +89 -0
- metadata +157 -41
- data/devel/jumpstart/lazy_attribute.rb +0 -38
- data/devel/jumpstart/ruby.rb +0 -44
- data/devel/jumpstart/simple_installer.rb +0 -85
- data/lib/pure/pure_private/creator.rb +0 -27
- data/lib/pure/pure_private/driver.rb +0 -48
- data/lib/pure/pure_private/error.rb +0 -32
- data/lib/pure/pure_private/extractor.rb +0 -79
- data/lib/pure/pure_private/extractor_ripper.rb +0 -95
- data/lib/pure/pure_private/extractor_ruby_parser.rb +0 -47
- data/lib/pure/pure_private/function_database.rb +0 -10
- data/lib/pure/pure_private/singleton_features.rb +0 -67
- data/lib/pure/pure_private/util.rb +0 -23
- data/spec/basic_spec.rb +0 -38
- data/spec/combine_spec.rb +0 -62
- data/spec/common.rb +0 -44
- data/spec/error_spec.rb +0 -146
- data/spec/fun_spec.rb +0 -122
- data/spec/lazy_spec.rb +0 -22
- data/spec/subseqent_spec.rb +0 -42
- data/spec/timed_spec.rb +0 -30
data/Rakefile
CHANGED
@@ -1,10 +1,33 @@
|
|
1
|
-
$LOAD_PATH.unshift "devel"
|
2
1
|
|
2
|
+
$LOAD_PATH.unshift "devel"
|
3
3
|
require "jumpstart"
|
4
4
|
|
5
5
|
Jumpstart.new "pure" do |s|
|
6
6
|
s.developer("James M. Lawrence", "quixoticsycophant@gmail.com")
|
7
|
-
s.dependency("comp_tree", ">= 0.7.6")
|
8
7
|
s.rubyforge_user = "quix"
|
9
8
|
s.rubyforge_name = "purefunctional"
|
9
|
+
s.dependency("comp_tree", ">= 1.0.0")
|
10
|
+
s.dependency("ruby_parser", ">= 2.0.4")
|
11
|
+
s.extra_dev_deps = [
|
12
|
+
["ruby2ruby", ">= 1.2.2"],
|
13
|
+
["rspec", ">= 1.2.6"],
|
14
|
+
]
|
15
|
+
s.rdoc_files = %w[
|
16
|
+
lib/pure/pure.rb
|
17
|
+
lib/pure/pure_module.rb
|
18
|
+
lib/pure/dsl.rb
|
19
|
+
lib/pure/dsl_definition.rb
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
readme = "README.rdoc"
|
24
|
+
task readme do
|
25
|
+
re = %r!(The\s+default\s+worker\s+looks\s+like\s+this:).*?(?=^\S)!m
|
26
|
+
contents = File.read(readme).sub(re) { |sentence|
|
27
|
+
$1 + "\n" +
|
28
|
+
File.read("lib/pure/native_worker.rb").
|
29
|
+
gsub(%r!^!, " ").
|
30
|
+
sub(%r! \#:nodoc:!, "") + "\n"
|
31
|
+
}
|
32
|
+
File.open(readme, "w") { |f| f.print contents }
|
10
33
|
end
|
data/devel/jumpstart.rb
CHANGED
@@ -1,281 +1,544 @@
|
|
1
|
-
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
-
$LOAD_PATH.unshift File.dirname(__FILE__)
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'ostruct'
|
6
|
-
require 'rbconfig'
|
7
|
-
|
8
|
-
require 'rake/gempackagetask'
|
9
|
-
require 'rake/contrib/sshpublisher'
|
10
|
-
require 'rake/clean'
|
11
|
-
|
12
|
-
require 'rdoc/rdoc'
|
13
|
-
|
14
|
-
require 'jumpstart/ruby'
|
15
|
-
require 'jumpstart/lazy_attribute'
|
16
|
-
require 'jumpstart/simple_installer'
|
17
1
|
|
18
2
|
class Jumpstart
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
3
|
+
class SimpleInstaller
|
4
|
+
def initialize
|
5
|
+
require 'fileutils'
|
6
|
+
require 'rbconfig'
|
7
|
+
require 'find'
|
8
|
+
dest_root = Config::CONFIG["sitelibdir"]
|
9
|
+
sources = []
|
10
|
+
Find.find("./lib") { |source|
|
11
|
+
if install_file?(source)
|
12
|
+
sources << source
|
13
|
+
end
|
14
|
+
}
|
15
|
+
@spec = sources.inject(Array.new) { |acc, source|
|
16
|
+
if source == "./lib"
|
17
|
+
acc
|
18
|
+
else
|
19
|
+
dest = File.join(dest_root, source.sub(%r!\A\./lib!, ""))
|
20
|
+
|
21
|
+
install = lambda {
|
22
|
+
if File.directory?(source)
|
23
|
+
unless File.directory?(dest)
|
24
|
+
puts "mkdir #{dest}"
|
25
|
+
FileUtils.mkdir(dest)
|
26
|
+
end
|
37
27
|
else
|
38
|
-
|
28
|
+
puts "install #{source} --> #{dest}"
|
29
|
+
FileUtils.install(source, dest)
|
39
30
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
31
|
+
}
|
32
|
+
|
33
|
+
uninstall = lambda {
|
34
|
+
if File.directory?(source)
|
35
|
+
if File.directory?(dest)
|
36
|
+
puts "rmdir #{dest}"
|
37
|
+
FileUtils.rmdir(dest)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
if File.file?(dest)
|
41
|
+
puts "rm #{dest}"
|
42
|
+
FileUtils.rm(dest)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
}
|
46
|
+
|
47
|
+
acc << {
|
48
|
+
:source => source,
|
49
|
+
:dest => dest,
|
50
|
+
:install => install,
|
51
|
+
:uninstall => uninstall,
|
52
|
+
}
|
44
53
|
end
|
45
|
-
|
46
|
-
"0.0.0"
|
47
|
-
end
|
54
|
+
}
|
48
55
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
|
57
|
+
def install_file?(source)
|
58
|
+
File.directory?(source) or
|
59
|
+
(File.file?(source) and File.extname(source) == ".rb")
|
52
60
|
end
|
53
61
|
|
54
|
-
|
55
|
-
|
62
|
+
def install
|
63
|
+
@spec.each { |entry|
|
64
|
+
entry[:install].call
|
65
|
+
}
|
56
66
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
67
|
+
|
68
|
+
def uninstall
|
69
|
+
@spec.reverse.each { |entry|
|
70
|
+
entry[:uninstall].call
|
71
|
+
}
|
60
72
|
end
|
61
73
|
|
62
|
-
|
63
|
-
|
74
|
+
def run(args = ARGV)
|
75
|
+
if args.empty?
|
76
|
+
install
|
77
|
+
elsif args.size == 1 and args.first == "--uninstall"
|
78
|
+
uninstall
|
79
|
+
else
|
80
|
+
raise "unrecognized arguments: #{args.inspect}"
|
81
|
+
end
|
64
82
|
end
|
83
|
+
end
|
65
84
|
|
66
|
-
|
67
|
-
|
85
|
+
module AttrLazy
|
86
|
+
def attr_lazy(name, &block)
|
87
|
+
AttrLazy.define_reader(class << self ; self ; end, name, &block)
|
68
88
|
end
|
69
89
|
|
70
|
-
|
71
|
-
|
90
|
+
def attr_lazy_accessor(name, &block)
|
91
|
+
attr_lazy(name, &block)
|
92
|
+
AttrLazy.define_writer(class << self ; self ; end, name, &block)
|
72
93
|
end
|
73
94
|
|
74
|
-
|
75
|
-
|
76
|
-
|
95
|
+
class << self
|
96
|
+
def included(mod)
|
97
|
+
(class << mod ; self ; end).class_eval do
|
98
|
+
def attr_lazy(name, &block)
|
99
|
+
AttrLazy.define_reader(self, name, &block)
|
100
|
+
end
|
77
101
|
|
78
|
-
|
79
|
-
|
80
|
-
|
102
|
+
def attr_lazy_accessor(name, &block)
|
103
|
+
attr_lazy(name, &block)
|
104
|
+
AttrLazy.define_writer(self, name, &block)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
81
108
|
|
82
|
-
|
83
|
-
|
84
|
-
|
109
|
+
def define_evaluated_reader(instance, name, value)
|
110
|
+
(class << instance ; self ; end).class_eval do
|
111
|
+
remove_method name rescue nil
|
112
|
+
define_method name do
|
113
|
+
value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
85
117
|
|
86
|
-
|
87
|
-
|
88
|
-
|
118
|
+
def define_reader(klass, name, &block)
|
119
|
+
klass.class_eval do
|
120
|
+
remove_method name rescue nil
|
121
|
+
define_method name do
|
122
|
+
value = instance_eval(&block)
|
123
|
+
AttrLazy.define_evaluated_reader(self, name, value)
|
124
|
+
value
|
125
|
+
end
|
126
|
+
end
|
89
127
|
end
|
90
|
-
}
|
91
128
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
129
|
+
def define_writer(klass, name, &block)
|
130
|
+
klass.class_eval do
|
131
|
+
writer = "#{name}="
|
132
|
+
remove_method writer rescue nil
|
133
|
+
define_method writer do |value|
|
134
|
+
AttrLazy.define_evaluated_reader(self, name, value)
|
135
|
+
value
|
136
|
+
end
|
99
137
|
end
|
100
|
-
|
138
|
+
end
|
101
139
|
end
|
140
|
+
end
|
102
141
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
"MANIFEST"
|
109
|
-
end
|
142
|
+
module Ruby
|
143
|
+
module_function
|
144
|
+
|
145
|
+
def executable
|
146
|
+
require 'rbconfig'
|
110
147
|
|
111
|
-
|
112
|
-
|
113
|
-
|
148
|
+
name = File.join(
|
149
|
+
Config::CONFIG["bindir"],
|
150
|
+
Config::CONFIG["RUBY_INSTALL_NAME"]
|
151
|
+
)
|
152
|
+
|
153
|
+
if Config::CONFIG["host"] =~ %r!(mswin|cygwin|mingw)! and
|
154
|
+
File.basename(name) !~ %r!\.(exe|com|bat|cmd)\Z!i
|
155
|
+
name + Config::CONFIG["EXEEXT"]
|
114
156
|
else
|
115
|
-
|
157
|
+
name
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def run(*args)
|
162
|
+
cmd = [executable, *args]
|
163
|
+
unless system(*cmd)
|
164
|
+
cmd_str = cmd.map { |t| "'#{t}'" }.join(", ")
|
165
|
+
raise "system(#{cmd_str}) failed with status #{$?.exitstatus}"
|
116
166
|
end
|
117
167
|
end
|
118
168
|
|
119
|
-
|
120
|
-
|
169
|
+
def run_code_and_capture(code)
|
170
|
+
IO.popen(%{"#{executable}"}, "r+") { |pipe|
|
171
|
+
pipe.print(code)
|
172
|
+
pipe.flush
|
173
|
+
pipe.close_write
|
174
|
+
pipe.read
|
175
|
+
}
|
121
176
|
end
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
177
|
+
|
178
|
+
def run_file_and_capture(file)
|
179
|
+
unless File.file? file
|
180
|
+
raise "file does not exist: `#{file}'"
|
181
|
+
end
|
182
|
+
IO.popen(%{"#{executable}" "#{file}"}, "r") { |pipe|
|
183
|
+
pipe.read
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
def with_warnings(value = true)
|
188
|
+
previous = $VERBOSE
|
189
|
+
$VERBOSE = value
|
190
|
+
begin
|
191
|
+
yield
|
192
|
+
ensure
|
193
|
+
$VERBOSE = previous
|
128
194
|
end
|
129
195
|
end
|
196
|
+
|
197
|
+
def no_warnings(&block)
|
198
|
+
with_warnings(nil, &block)
|
199
|
+
end
|
200
|
+
end
|
130
201
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
"--title", "#{name}: #{summary}",
|
138
|
-
] + (files - rdoc_files).inject(Array.new) { |acc, file|
|
139
|
-
acc + ["--exclude", file]
|
202
|
+
module Util
|
203
|
+
module_function
|
204
|
+
|
205
|
+
def run_ruby_on_each(*files)
|
206
|
+
files.each { |file|
|
207
|
+
Ruby.run("-w", file)
|
140
208
|
}
|
141
209
|
end
|
142
210
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
Gem::Specification.new { |g|
|
162
|
-
g.has_rdoc = true
|
163
|
-
%w[
|
164
|
-
name
|
165
|
-
authors
|
166
|
-
email
|
167
|
-
summary
|
168
|
-
version
|
169
|
-
description
|
170
|
-
files
|
171
|
-
extra_rdoc_files
|
172
|
-
rdoc_options
|
173
|
-
].each { |param|
|
174
|
-
value = send(param) and (
|
175
|
-
g.send("#{param}=", value)
|
176
|
-
)
|
211
|
+
def to_camel_case(str)
|
212
|
+
str.split('_').map { |t| t.capitalize }.join
|
213
|
+
end
|
214
|
+
|
215
|
+
def write_file(file)
|
216
|
+
contents = yield
|
217
|
+
File.open(file, "wb") { |out|
|
218
|
+
out.print(contents)
|
219
|
+
}
|
220
|
+
contents
|
221
|
+
end
|
222
|
+
|
223
|
+
def replace_file(file)
|
224
|
+
old_contents = File.read(file)
|
225
|
+
new_contents = yield(old_contents)
|
226
|
+
if old_contents != new_contents
|
227
|
+
File.open(file, "wb") { |output|
|
228
|
+
output.print(new_contents)
|
177
229
|
}
|
230
|
+
end
|
231
|
+
new_contents
|
232
|
+
end
|
233
|
+
end
|
178
234
|
|
179
|
-
|
180
|
-
|
181
|
-
end
|
235
|
+
module InstanceEvalWithArgs
|
236
|
+
module_function
|
182
237
|
|
183
|
-
|
184
|
-
|
238
|
+
def with_temp_method(instance, method_name, method_block)
|
239
|
+
(class << instance ; self ; end).class_eval do
|
240
|
+
define_method(method_name, &method_block)
|
241
|
+
begin
|
242
|
+
yield method_name
|
243
|
+
ensure
|
244
|
+
remove_method(method_name)
|
185
245
|
end
|
246
|
+
end
|
247
|
+
end
|
186
248
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
extra_dev_deps.each { |dep|
|
192
|
-
g.add_development_dependency(*dep)
|
193
|
-
}
|
249
|
+
def call_temp_method(instance, method_name, *args, &method_block)
|
250
|
+
with_temp_method(instance, method_name, method_block) {
|
251
|
+
instance.send(method_name, *args)
|
194
252
|
}
|
195
253
|
end
|
196
254
|
|
197
|
-
|
198
|
-
|
255
|
+
def instance_eval_with_args(instance, *args, &block)
|
256
|
+
call_temp_method(instance, :__temp_method, *args, &block)
|
199
257
|
end
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
258
|
+
end
|
259
|
+
|
260
|
+
include AttrLazy
|
261
|
+
include Util
|
262
|
+
|
263
|
+
def initialize(project_name)
|
264
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
265
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
266
|
+
|
267
|
+
require 'rake/gempackagetask'
|
268
|
+
require 'rake/clean'
|
269
|
+
|
270
|
+
@project_name = project_name
|
271
|
+
|
272
|
+
yield self
|
273
|
+
|
274
|
+
self.class.instance_methods(false).select { |t|
|
275
|
+
t.to_s =~ %r!\Adefine_!
|
276
|
+
}.each { |method_name|
|
277
|
+
send(method_name)
|
278
|
+
}
|
279
|
+
end
|
280
|
+
|
281
|
+
class << self
|
282
|
+
alias_method :attribute, :attr_lazy_accessor
|
283
|
+
end
|
284
|
+
|
285
|
+
attribute :name do
|
286
|
+
@project_name
|
287
|
+
end
|
288
|
+
|
289
|
+
attribute :version_constant_name do
|
290
|
+
"VERSION"
|
291
|
+
end
|
292
|
+
|
293
|
+
attribute :version do
|
294
|
+
require name
|
295
|
+
mod_name = to_camel_case(name)
|
296
|
+
begin
|
297
|
+
mod = Kernel.const_get(mod_name)
|
298
|
+
if mod.constants.include?(version_constant_name)
|
299
|
+
mod.const_get(version_constant_name)
|
300
|
+
else
|
301
|
+
raise
|
210
302
|
end
|
303
|
+
rescue
|
304
|
+
"0.0.0"
|
211
305
|
end
|
306
|
+
end
|
307
|
+
|
308
|
+
attribute :rubyforge_name do
|
309
|
+
name.gsub('_', '')
|
310
|
+
end
|
311
|
+
|
312
|
+
attribute :rubyforge_user do
|
313
|
+
email.first[%r!^.*(?=@)!]
|
314
|
+
end
|
315
|
+
|
316
|
+
attribute :readme_file do
|
317
|
+
"README.rdoc"
|
318
|
+
end
|
319
|
+
|
320
|
+
attribute :history_file do
|
321
|
+
"CHANGES.rdoc"
|
322
|
+
end
|
323
|
+
|
324
|
+
attribute :doc_dir do
|
325
|
+
"documentation"
|
326
|
+
end
|
327
|
+
|
328
|
+
attribute :spec_files do
|
329
|
+
Dir["./spec/*_{spec,example}.rb"]
|
330
|
+
end
|
331
|
+
|
332
|
+
attribute :test_files do
|
333
|
+
(Dir["./test/test_*.rb"] + Dir["./test/*_test.rb"]).uniq
|
334
|
+
end
|
335
|
+
|
336
|
+
attribute :rcov_dir do
|
337
|
+
"coverage"
|
338
|
+
end
|
339
|
+
|
340
|
+
attribute :spec_output_dir do
|
341
|
+
"rspec_output"
|
342
|
+
end
|
343
|
+
|
344
|
+
attribute :spec_output_file do
|
345
|
+
"spec.html"
|
346
|
+
end
|
347
|
+
|
348
|
+
attr_lazy :spec_output do
|
349
|
+
"#{spec_output_dir}/#{spec_output_file}"
|
350
|
+
end
|
212
351
|
|
213
|
-
|
214
|
-
|
352
|
+
[:gem, :tgz].each { |ext|
|
353
|
+
attribute ext do
|
354
|
+
"pkg/#{name}-#{version}.#{ext}"
|
215
355
|
end
|
356
|
+
}
|
216
357
|
|
217
|
-
|
218
|
-
|
358
|
+
attribute :rcov_options do
|
359
|
+
# workaround for the default rspec task
|
360
|
+
Dir["*"].select { |f| File.directory? f }.inject(Array.new) { |acc, dir|
|
361
|
+
if dir == "lib"
|
362
|
+
acc
|
363
|
+
else
|
364
|
+
acc + ["--exclude", dir + "/"]
|
365
|
+
end
|
366
|
+
} + ["--text-report"]
|
367
|
+
end
|
368
|
+
|
369
|
+
attribute :readme_file do
|
370
|
+
"README.rdoc"
|
371
|
+
end
|
372
|
+
|
373
|
+
attribute :manifest_file do
|
374
|
+
"MANIFEST"
|
375
|
+
end
|
376
|
+
|
377
|
+
attribute :generated_files do
|
378
|
+
[]
|
379
|
+
end
|
380
|
+
|
381
|
+
attribute :files do
|
382
|
+
if File.exist?(manifest_file)
|
383
|
+
File.read(manifest_file).split("\n")
|
384
|
+
else
|
385
|
+
`git ls-files`.split("\n") + [manifest_file] + generated_files
|
219
386
|
end
|
387
|
+
end
|
220
388
|
|
221
|
-
|
222
|
-
|
389
|
+
attribute :rdoc_files do
|
390
|
+
Dir["lib/**/*.rb"]
|
391
|
+
end
|
392
|
+
|
393
|
+
attribute :extra_rdoc_files do
|
394
|
+
if File.exist?(readme_file)
|
395
|
+
[readme_file]
|
396
|
+
else
|
397
|
+
[]
|
223
398
|
end
|
399
|
+
end
|
224
400
|
|
225
|
-
|
226
|
-
|
401
|
+
attribute :rdoc_options do
|
402
|
+
if File.exist?(readme_file)
|
403
|
+
["--main", readme_file]
|
404
|
+
else
|
405
|
+
[]
|
406
|
+
end + [
|
407
|
+
"--title", "#{name}: #{summary}",
|
408
|
+
] + (files - rdoc_files).inject(Array.new) { |acc, file|
|
409
|
+
acc + ["--exclude", file]
|
410
|
+
}
|
411
|
+
end
|
412
|
+
|
413
|
+
attribute :browser do
|
414
|
+
require 'rbconfig'
|
415
|
+
if Config::CONFIG["host"] =~ %r!darwin!
|
416
|
+
app = %w[Firefox Safari].map { |t|
|
417
|
+
"/Applications/#{t}.app"
|
418
|
+
}.select { |t|
|
419
|
+
File.exist? t
|
420
|
+
}.first
|
421
|
+
if app
|
422
|
+
["open", app]
|
423
|
+
else
|
424
|
+
raise "need to set `browser'"
|
425
|
+
end
|
426
|
+
else
|
427
|
+
"firefox"
|
227
428
|
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
429
|
+
end
|
430
|
+
|
431
|
+
attribute :gemspec do
|
432
|
+
Gem::Specification.new { |g|
|
433
|
+
g.has_rdoc = true
|
434
|
+
%w[
|
435
|
+
name
|
436
|
+
authors
|
437
|
+
email
|
438
|
+
summary
|
439
|
+
version
|
440
|
+
description
|
441
|
+
files
|
442
|
+
extra_rdoc_files
|
443
|
+
rdoc_options
|
444
|
+
].each { |param|
|
445
|
+
value = send(param) and (
|
446
|
+
g.send("#{param}=", value)
|
447
|
+
)
|
448
|
+
}
|
449
|
+
|
450
|
+
if rubyforge_name
|
451
|
+
g.rubyforge_project = rubyforge_name
|
452
|
+
end
|
453
|
+
|
454
|
+
if url
|
455
|
+
g.homepage = url
|
240
456
|
end
|
457
|
+
|
458
|
+
extra_deps.each { |dep|
|
459
|
+
g.add_dependency(*dep)
|
460
|
+
}
|
461
|
+
|
462
|
+
extra_dev_deps.each { |dep|
|
463
|
+
g.add_development_dependency(*dep)
|
464
|
+
}
|
241
465
|
}
|
466
|
+
end
|
467
|
+
|
468
|
+
attribute :readme_contents do
|
469
|
+
File.read(readme_file) rescue "FIXME: readme_file"
|
470
|
+
end
|
471
|
+
|
472
|
+
attribute :sections do
|
473
|
+
require 'enumerator'
|
474
|
+
begin
|
475
|
+
data = readme_contents.split(%r!^==\s*(.*?)\s*$!)
|
476
|
+
pairs = data[1..-1].enum_slice(2).map { |section, contents|
|
477
|
+
[section.downcase, contents.strip]
|
478
|
+
}
|
479
|
+
Hash[*pairs.flatten]
|
480
|
+
rescue
|
481
|
+
nil
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
attribute :description_section do
|
486
|
+
"description"
|
487
|
+
end
|
488
|
+
|
489
|
+
attribute :summary_section do
|
490
|
+
"summary"
|
491
|
+
end
|
492
|
+
|
493
|
+
attribute :description_sentences do
|
494
|
+
1
|
495
|
+
end
|
242
496
|
|
243
|
-
|
497
|
+
attribute :summary_sentences do
|
498
|
+
1
|
499
|
+
end
|
500
|
+
|
501
|
+
[:summary, :description].each { |section|
|
502
|
+
attribute section do
|
244
503
|
begin
|
245
|
-
|
504
|
+
sections[send("#{section}_section")].
|
505
|
+
gsub("\n", " ").
|
506
|
+
split(%r!\.\s*!m).
|
507
|
+
first(send("#{section}_sentences")).
|
508
|
+
join(". ") << "."
|
246
509
|
rescue
|
247
|
-
"
|
510
|
+
"FIXME: #{section}"
|
248
511
|
end
|
249
512
|
end
|
513
|
+
}
|
250
514
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
[]
|
515
|
+
attribute :url do
|
516
|
+
begin
|
517
|
+
readme_contents.match(%r!^\*.*?(http://\S+)!)[1]
|
518
|
+
rescue
|
519
|
+
"http://#{rubyforge_name}.rubyforge.org"
|
257
520
|
end
|
521
|
+
end
|
258
522
|
|
259
|
-
|
523
|
+
attribute :extra_deps do
|
524
|
+
[]
|
525
|
+
end
|
260
526
|
|
261
|
-
|
262
|
-
|
263
|
-
}.each { |method_name|
|
264
|
-
send(method_name)
|
265
|
-
}
|
527
|
+
attribute :extra_dev_deps do
|
528
|
+
[]
|
266
529
|
end
|
267
530
|
|
268
|
-
|
269
|
-
|
270
|
-
self.email << email
|
531
|
+
attribute :authors do
|
532
|
+
Array.new
|
271
533
|
end
|
272
534
|
|
273
|
-
|
274
|
-
|
535
|
+
attribute :email do
|
536
|
+
Array.new
|
275
537
|
end
|
276
538
|
|
277
|
-
def email
|
278
|
-
|
539
|
+
def developer(name, email)
|
540
|
+
authors << name
|
541
|
+
self.email << email
|
279
542
|
end
|
280
543
|
|
281
544
|
def dependency(name, version)
|
@@ -301,7 +564,9 @@ class Jumpstart
|
|
301
564
|
|
302
565
|
def define_spec
|
303
566
|
unless spec_files.empty?
|
304
|
-
|
567
|
+
Ruby.no_warnings {
|
568
|
+
require 'spec/rake/spectask'
|
569
|
+
}
|
305
570
|
|
306
571
|
desc "run specs"
|
307
572
|
Spec::Rake::SpecTask.new('spec') do |t|
|
@@ -322,6 +587,8 @@ class Jumpstart
|
|
322
587
|
t.spec_opts = ["-fh:#{spec_output}"]
|
323
588
|
end
|
324
589
|
|
590
|
+
suppress_task_warnings :spec, :full_spec, :text_spec
|
591
|
+
|
325
592
|
desc "run full_spec then open browser"
|
326
593
|
task :show_spec => :full_spec do
|
327
594
|
open_browser(spec_output, rcov_dir + "/index.html")
|
@@ -335,7 +602,7 @@ class Jumpstart
|
|
335
602
|
task :prerelease => [:spec, :spec_deps]
|
336
603
|
task :default => :spec
|
337
604
|
|
338
|
-
CLEAN.include
|
605
|
+
CLEAN.include spec_output_dir
|
339
606
|
end
|
340
607
|
end
|
341
608
|
|
@@ -377,6 +644,7 @@ class Jumpstart
|
|
377
644
|
def define_doc
|
378
645
|
desc "run rdoc"
|
379
646
|
task :doc => :clean_doc do
|
647
|
+
require 'rdoc/rdoc'
|
380
648
|
args = (
|
381
649
|
gemspec.rdoc_options +
|
382
650
|
gemspec.require_paths.clone +
|
@@ -403,6 +671,7 @@ class Jumpstart
|
|
403
671
|
def define_publish
|
404
672
|
desc "upload docs"
|
405
673
|
task :publish => [:clean_doc, :doc] do
|
674
|
+
require 'rake/contrib/sshpublisher'
|
406
675
|
Rake::SshDirPublisher.new(
|
407
676
|
"#{rubyforge_user}@rubyforge.org",
|
408
677
|
"/var/www/gforge-projects/#{rubyforge_name}",
|
@@ -445,9 +714,10 @@ class Jumpstart
|
|
445
714
|
end
|
446
715
|
|
447
716
|
def debug_info(enable)
|
717
|
+
require 'find'
|
448
718
|
Find.find("lib", "test") { |path|
|
449
719
|
if path =~ %r!\.rb\Z!
|
450
|
-
|
720
|
+
replace_file(path) { |contents|
|
451
721
|
result = comment_regions(!enable, contents, "debug")
|
452
722
|
comment_lines(!enable, result, "trace")
|
453
723
|
}
|
@@ -485,13 +755,13 @@ class Jumpstart
|
|
485
755
|
task :comments do
|
486
756
|
file = "comments.txt"
|
487
757
|
write_file(file) {
|
488
|
-
Array.new
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
}
|
758
|
+
result = Array.new
|
759
|
+
(["Rakefile"] + Dir["**/*.{rb,rake}"]).each { |f|
|
760
|
+
File.read(f).scan(%r!\#[^\{].*$!) { |match|
|
761
|
+
result << match
|
493
762
|
}
|
494
|
-
}
|
763
|
+
}
|
764
|
+
result.join("\n")
|
495
765
|
}
|
496
766
|
CLEAN.include file
|
497
767
|
end
|
@@ -507,6 +777,7 @@ class Jumpstart
|
|
507
777
|
|
508
778
|
def define_ping
|
509
779
|
task :ping do
|
780
|
+
require 'rbconfig'
|
510
781
|
%w[github.com rubyforge.org].each { |server|
|
511
782
|
cmd = "ping " + (
|
512
783
|
if Config::CONFIG["host"] =~ %r!darwin!
|
@@ -548,28 +819,29 @@ class Jumpstart
|
|
548
819
|
}
|
549
820
|
end
|
550
821
|
|
551
|
-
def rubyforge(
|
552
|
-
|
553
|
-
"rubyforge",
|
554
|
-
command,
|
822
|
+
def rubyforge(mode, file, *options)
|
823
|
+
command = ["rubyforge", mode] + options + [
|
555
824
|
rubyforge_name,
|
556
825
|
rubyforge_name,
|
557
826
|
version.to_s,
|
558
|
-
file
|
559
|
-
|
827
|
+
file,
|
828
|
+
]
|
829
|
+
sh(*command)
|
560
830
|
end
|
561
831
|
|
562
832
|
def define_release
|
563
|
-
task :prerelease => [:clean, :check_directory, :ping]
|
833
|
+
task :prerelease => [:clean, :check_directory, :ping, history_file]
|
564
834
|
|
565
835
|
task :finish_release do
|
566
836
|
gem_md5, tgz_md5 = [gem, tgz].map { |file|
|
567
|
-
"#{file}.md5"
|
568
|
-
|
569
|
-
|
837
|
+
md5 = "#{file}.md5"
|
838
|
+
sh("md5sum #{file} > #{md5}")
|
839
|
+
md5
|
570
840
|
}
|
571
841
|
|
572
|
-
rubyforge(
|
842
|
+
rubyforge(
|
843
|
+
"add_release", gem, "--release_changes", history_file, "--preformatted"
|
844
|
+
)
|
573
845
|
[gem_md5, tgz, tgz_md5].each { |file|
|
574
846
|
rubyforge("add_file", file)
|
575
847
|
}
|
@@ -591,44 +863,125 @@ class Jumpstart
|
|
591
863
|
sh(*([browser].flatten + files))
|
592
864
|
end
|
593
865
|
|
594
|
-
def
|
595
|
-
|
596
|
-
|
597
|
-
|
866
|
+
def suppress_task_warnings(*task_names)
|
867
|
+
task_names.each { |task_name|
|
868
|
+
Rake::Task[task_name].actions.map! { |action|
|
869
|
+
lambda { |*args|
|
870
|
+
Ruby.no_warnings {
|
871
|
+
action.call(*args)
|
872
|
+
}
|
873
|
+
}
|
598
874
|
}
|
599
875
|
}
|
600
876
|
end
|
601
877
|
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
}
|
606
|
-
end
|
878
|
+
class << self
|
879
|
+
include Util
|
880
|
+
include InstanceEvalWithArgs
|
607
881
|
|
608
|
-
|
609
|
-
|
610
|
-
|
882
|
+
# From minitest, part of the Ruby source; by Ryan Davis.
|
883
|
+
def capture_io
|
884
|
+
require 'stringio'
|
611
885
|
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
886
|
+
orig_stdout, orig_stderr = $stdout, $stderr
|
887
|
+
captured_stdout, captured_stderr = StringIO.new, StringIO.new
|
888
|
+
$stdout, $stderr = captured_stdout, captured_stderr
|
889
|
+
|
890
|
+
yield
|
891
|
+
|
892
|
+
return captured_stdout.string, captured_stderr.string
|
893
|
+
ensure
|
894
|
+
$stdout = orig_stdout
|
895
|
+
$stderr = orig_stderr
|
896
|
+
end
|
897
|
+
|
898
|
+
def run_doc_code(code, expected, index, instance, &block)
|
899
|
+
lib = File.expand_path(File.dirname(__FILE__) + "/../lib")
|
900
|
+
header = %{
|
901
|
+
$LOAD_PATH.unshift "#{lib}"
|
902
|
+
begin
|
903
|
+
}
|
904
|
+
footer = %{
|
905
|
+
rescue Exception => __jumpstart_exception
|
906
|
+
puts "raises \#{__jumpstart_exception.class}"
|
620
907
|
end
|
621
908
|
}
|
909
|
+
final_code = header + code + footer
|
910
|
+
|
911
|
+
# Sometimes code is required to be inside a file.
|
912
|
+
actual = nil
|
913
|
+
require 'tempfile'
|
914
|
+
Tempfile.open("run-rdoc-code") { |temp_file|
|
915
|
+
temp_file.print(final_code)
|
916
|
+
temp_file.close
|
917
|
+
actual = Ruby.run_file_and_capture(temp_file.path).chomp
|
918
|
+
}
|
919
|
+
|
920
|
+
instance_eval_with_args(instance, expected, actual, index, &block)
|
921
|
+
end
|
922
|
+
|
923
|
+
def run_doc_section(file, section, instance, &block)
|
924
|
+
contents = File.read(file)
|
925
|
+
re = %r!^=+[ \t]#{Regexp.quote(section)}.*?\n(.*?)^=!m
|
926
|
+
if section_contents = contents[re, 1]
|
927
|
+
index = 0
|
928
|
+
section_contents.scan(%r!^( \S.*?)(?=(^\S|\Z))!m) { |indented, unused|
|
929
|
+
code_sections = indented.split(%r!^ \#\#\#\# output:\s*$!)
|
930
|
+
code, expected = (
|
931
|
+
case code_sections.size
|
932
|
+
when 1
|
933
|
+
[indented, indented.scan(%r!\# => (.*?)\n!).flatten.join("\n")]
|
934
|
+
when 2
|
935
|
+
code_sections
|
936
|
+
else
|
937
|
+
raise "parse error"
|
938
|
+
end
|
939
|
+
)
|
940
|
+
run_doc_code(code, expected, index, instance, &block)
|
941
|
+
index += 1
|
942
|
+
}
|
943
|
+
else
|
944
|
+
raise "couldn't find section `#{section}' of `#{file}'"
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
def doc_to_spec(file, *sections, &block)
|
949
|
+
jump = self
|
950
|
+
describe file do
|
951
|
+
sections.each { |section|
|
952
|
+
describe "section `#{section}'" do
|
953
|
+
it "should run as claimed" do
|
954
|
+
if block
|
955
|
+
jump.run_doc_section(file, section, self, &block)
|
956
|
+
else
|
957
|
+
jump.run_doc_section(file, section, self) {
|
958
|
+
|expected, actual, index|
|
959
|
+
actual.should == expected
|
960
|
+
}
|
961
|
+
end
|
962
|
+
end
|
963
|
+
end
|
964
|
+
}
|
965
|
+
end
|
622
966
|
end
|
623
|
-
end
|
624
|
-
end
|
625
967
|
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
968
|
+
def doc_to_test(file, *sections, &block)
|
969
|
+
jump = self
|
970
|
+
klass = Class.new Test::Unit::TestCase do
|
971
|
+
sections.each { |section|
|
972
|
+
define_method "test_#{file}_#{section}" do
|
973
|
+
if block
|
974
|
+
jump.run_doc_section(file, section, self, &block)
|
975
|
+
else
|
976
|
+
jump.run_doc_section(file, section, self) {
|
977
|
+
|expected, actual, index|
|
978
|
+
assert_equal expected, actual
|
979
|
+
}
|
980
|
+
end
|
981
|
+
end
|
982
|
+
}
|
983
|
+
end
|
984
|
+
Object.const_set("Test#{file}".gsub(".", ""), klass)
|
631
985
|
end
|
632
986
|
end
|
633
987
|
end
|
634
|
-
|