forkoff 1.1.1 → 1.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.
- checksums.yaml +15 -0
- data/Rakefile +394 -0
- data/forkoff.gemspec +22 -8
- data/lib/forkoff.rb +67 -72
- data/test/{forkoff.rb → forkoff_test.rb} +21 -1
- metadata +28 -39
- data/rakefile +0 -223
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjVlNmM0YmE4MDhmOTkyZDliOTM5YzhlMWQ3OGIzODE5MTFhODE5NQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MmFmZmUzYTA1ODZhYjZlZWZkYThkYTJhMjRhMmJkNzU1M2FjNDQyNg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MTYxYzkyODZkODlmZTU4YzkxNmZiZTA2M2FmOTZhNjZjMDc0NDdlNDBiYWJi
|
10
|
+
ODdhNGEzY2UyZjFlNjI1YzM0YjU0OTM2OTMwMWIxMTU5NWI1YTBhYTRmMjJk
|
11
|
+
OTczZmVhNjIzZDVlZDczMzc0ZjY3MGNjYTBkODY5NjNkOTg3ZDk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MDBmNGMxYWYyMTE4OTBiOTY2ODlkODAyYmI0Yjg3NWYxZjYyZTczZThkZWJh
|
14
|
+
Y2U4ZTY5Y2FmNDUxODYyMTBmYjIzNDViMWQ0ZDExMmQ3NDg2ZjEwNmExOWEw
|
15
|
+
ODdiNTAwYWM3MzcxYTNlM2FlMDRjYWY2NWI0Njc4MzhiMGIxM2Y=
|
data/Rakefile
ADDED
@@ -0,0 +1,394 @@
|
|
1
|
+
This.rubyforge_project = 'codeforpeople'
|
2
|
+
This.author = "Ara T. Howard"
|
3
|
+
This.email = "ara.t.howard@gmail.com"
|
4
|
+
This.homepage = "https://github.com/ahoward/#{ This.lib }"
|
5
|
+
|
6
|
+
task :license do
|
7
|
+
open('LICENSE', 'w'){|fd| fd.puts "Ruby"}
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default do
|
11
|
+
puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
|
12
|
+
end
|
13
|
+
|
14
|
+
task :test do
|
15
|
+
run_tests!
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :test do
|
19
|
+
task(:unit){ run_tests!(:unit) }
|
20
|
+
task(:functional){ run_tests!(:functional) }
|
21
|
+
task(:integration){ run_tests!(:integration) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_tests!(which = nil)
|
25
|
+
which ||= '**'
|
26
|
+
test_dir = File.join(This.dir, "test")
|
27
|
+
test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
|
28
|
+
test_rbs = Dir.glob(test_glob).sort
|
29
|
+
|
30
|
+
div = ('=' * 119)
|
31
|
+
line = ('-' * 119)
|
32
|
+
|
33
|
+
test_rbs.each_with_index do |test_rb, index|
|
34
|
+
testno = index + 1
|
35
|
+
command = "#{ This.ruby } -w -I ./lib -I ./test/lib #{ test_rb }"
|
36
|
+
|
37
|
+
puts
|
38
|
+
say(div, :color => :cyan, :bold => true)
|
39
|
+
say("@#{ testno } => ", :bold => true, :method => :print)
|
40
|
+
say(command, :color => :cyan, :bold => true)
|
41
|
+
say(line, :color => :cyan, :bold => true)
|
42
|
+
|
43
|
+
system(command)
|
44
|
+
|
45
|
+
say(line, :color => :cyan, :bold => true)
|
46
|
+
|
47
|
+
status = $?.exitstatus
|
48
|
+
|
49
|
+
if status.zero?
|
50
|
+
say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
|
51
|
+
say("SUCCESS", :color => :green, :bold => true)
|
52
|
+
else
|
53
|
+
say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
|
54
|
+
say("FAILURE", :color => :red, :bold => true)
|
55
|
+
end
|
56
|
+
say(line, :color => :cyan, :bold => true)
|
57
|
+
|
58
|
+
exit(status) unless status.zero?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
task :gemspec do
|
64
|
+
ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
|
65
|
+
ignore_directories = ['pkg']
|
66
|
+
ignore_files = ['test/log']
|
67
|
+
|
68
|
+
shiteless =
|
69
|
+
lambda do |list|
|
70
|
+
list.delete_if do |entry|
|
71
|
+
next unless test(?e, entry)
|
72
|
+
extension = File.basename(entry).split(%r/[.]/).last
|
73
|
+
ignore_extensions.any?{|ext| ext === extension}
|
74
|
+
end
|
75
|
+
list.delete_if do |entry|
|
76
|
+
next unless test(?d, entry)
|
77
|
+
dirname = File.expand_path(entry)
|
78
|
+
ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
|
79
|
+
end
|
80
|
+
list.delete_if do |entry|
|
81
|
+
next unless test(?f, entry)
|
82
|
+
filename = File.expand_path(entry)
|
83
|
+
ignore_files.any?{|file| File.expand_path(file) == filename}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
lib = This.lib
|
88
|
+
object = This.object
|
89
|
+
version = This.version
|
90
|
+
files = shiteless[Dir::glob("**/**")]
|
91
|
+
executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
|
92
|
+
#has_rdoc = true #File.exist?('doc')
|
93
|
+
test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
|
94
|
+
summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
|
95
|
+
description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
|
96
|
+
license = object.respond_to?(:license) ? object.license : "Ruby"
|
97
|
+
|
98
|
+
if This.extensions.nil?
|
99
|
+
This.extensions = []
|
100
|
+
extensions = This.extensions
|
101
|
+
%w( Makefile configure extconf.rb ).each do |ext|
|
102
|
+
extensions << ext if File.exists?(ext)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
extensions = [extensions].flatten.compact
|
106
|
+
|
107
|
+
if This.dependencies.nil?
|
108
|
+
dependencies = []
|
109
|
+
else
|
110
|
+
case This.dependencies
|
111
|
+
when Hash
|
112
|
+
dependencies = This.dependencies.values
|
113
|
+
when Array
|
114
|
+
dependencies = This.dependencies
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
template =
|
119
|
+
if test(?e, 'gemspec.erb')
|
120
|
+
Template{ IO.read('gemspec.erb') }
|
121
|
+
else
|
122
|
+
Template {
|
123
|
+
<<-__
|
124
|
+
## <%= lib %>.gemspec
|
125
|
+
#
|
126
|
+
|
127
|
+
Gem::Specification::new do |spec|
|
128
|
+
spec.name = <%= lib.inspect %>
|
129
|
+
spec.version = <%= version.inspect %>
|
130
|
+
spec.platform = Gem::Platform::RUBY
|
131
|
+
spec.summary = <%= lib.inspect %>
|
132
|
+
spec.description = <%= description.inspect %>
|
133
|
+
spec.license = <%= license.inspect %>
|
134
|
+
|
135
|
+
spec.files =\n<%= files.sort.pretty_inspect %>
|
136
|
+
spec.executables = <%= executables.inspect %>
|
137
|
+
|
138
|
+
spec.require_path = "lib"
|
139
|
+
|
140
|
+
spec.test_files = <%= test_files.inspect %>
|
141
|
+
|
142
|
+
<% dependencies.each do |lib_version| %>
|
143
|
+
spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
|
144
|
+
<% end %>
|
145
|
+
|
146
|
+
spec.extensions.push(*<%= extensions.inspect %>)
|
147
|
+
|
148
|
+
spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
|
149
|
+
spec.author = <%= This.author.inspect %>
|
150
|
+
spec.email = <%= This.email.inspect %>
|
151
|
+
spec.homepage = <%= This.homepage.inspect %>
|
152
|
+
end
|
153
|
+
__
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
Fu.mkdir_p(This.pkgdir)
|
158
|
+
gemspec = "#{ lib }.gemspec"
|
159
|
+
open(gemspec, "w"){|fd| fd.puts(template)}
|
160
|
+
This.gemspec = gemspec
|
161
|
+
end
|
162
|
+
|
163
|
+
task :gem => [:clean, :gemspec] do
|
164
|
+
Fu.mkdir_p(This.pkgdir)
|
165
|
+
before = Dir['*.gem']
|
166
|
+
cmd = "gem build #{ This.gemspec }"
|
167
|
+
`#{ cmd }`
|
168
|
+
after = Dir['*.gem']
|
169
|
+
gem = ((after - before).first || after.first) or abort('no gem!')
|
170
|
+
Fu.mv(gem, This.pkgdir)
|
171
|
+
This.gem = File.join(This.pkgdir, File.basename(gem))
|
172
|
+
end
|
173
|
+
|
174
|
+
task :readme do
|
175
|
+
samples = ''
|
176
|
+
prompt = '~ > '
|
177
|
+
lib = This.lib
|
178
|
+
version = This.version
|
179
|
+
|
180
|
+
Dir['sample*/*'].sort.each do |sample|
|
181
|
+
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
182
|
+
|
183
|
+
cmd = "cat #{ sample }"
|
184
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
185
|
+
samples << Util.indent(`#{ cmd }`, 4) << "\n"
|
186
|
+
|
187
|
+
cmd = "ruby #{ sample }"
|
188
|
+
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
189
|
+
|
190
|
+
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
|
191
|
+
samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
|
192
|
+
end
|
193
|
+
|
194
|
+
template =
|
195
|
+
if test(?e, 'README.erb')
|
196
|
+
Template{ IO.read('README.erb') }
|
197
|
+
else
|
198
|
+
Template {
|
199
|
+
<<-__
|
200
|
+
NAME
|
201
|
+
#{ lib }
|
202
|
+
|
203
|
+
DESCRIPTION
|
204
|
+
|
205
|
+
INSTALL
|
206
|
+
gem install #{ lib }
|
207
|
+
|
208
|
+
SAMPLES
|
209
|
+
#{ samples }
|
210
|
+
__
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
open("README", "w"){|fd| fd.puts template}
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
task :clean do
|
219
|
+
Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
task :release => [:clean, :gemspec, :gem] do
|
224
|
+
gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
|
225
|
+
raise "which one? : #{ gems.inspect }" if gems.size > 1
|
226
|
+
raise "no gems?" if gems.size < 1
|
227
|
+
|
228
|
+
cmd = "gem push #{ This.gem }"
|
229
|
+
puts cmd
|
230
|
+
puts
|
231
|
+
system(cmd)
|
232
|
+
abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
|
233
|
+
|
234
|
+
cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
|
235
|
+
puts cmd
|
236
|
+
puts
|
237
|
+
system(cmd)
|
238
|
+
abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
BEGIN {
|
246
|
+
# support for this rakefile
|
247
|
+
#
|
248
|
+
$VERBOSE = nil
|
249
|
+
|
250
|
+
require 'ostruct'
|
251
|
+
require 'erb'
|
252
|
+
require 'fileutils'
|
253
|
+
require 'rbconfig'
|
254
|
+
require 'pp'
|
255
|
+
|
256
|
+
# fu shortcut
|
257
|
+
#
|
258
|
+
Fu = FileUtils
|
259
|
+
|
260
|
+
# cache a bunch of stuff about this rakefile/environment
|
261
|
+
#
|
262
|
+
This = OpenStruct.new
|
263
|
+
|
264
|
+
This.file = File.expand_path(__FILE__)
|
265
|
+
This.dir = File.dirname(This.file)
|
266
|
+
This.pkgdir = File.join(This.dir, 'pkg')
|
267
|
+
|
268
|
+
# grok lib
|
269
|
+
#
|
270
|
+
lib = ENV['LIB']
|
271
|
+
unless lib
|
272
|
+
lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
|
273
|
+
end
|
274
|
+
This.lib = lib
|
275
|
+
|
276
|
+
# grok version
|
277
|
+
#
|
278
|
+
version = ENV['VERSION']
|
279
|
+
unless version
|
280
|
+
require "./lib/#{ This.lib }"
|
281
|
+
This.name = lib.capitalize
|
282
|
+
This.object = eval(This.name)
|
283
|
+
version = This.object.send(:version)
|
284
|
+
end
|
285
|
+
This.version = version
|
286
|
+
|
287
|
+
# see if dependencies are export by the module
|
288
|
+
#
|
289
|
+
if This.object.respond_to?(:dependencies)
|
290
|
+
This.dependencies = This.object.dependencies
|
291
|
+
end
|
292
|
+
|
293
|
+
# we need to know the name of the lib an it's version
|
294
|
+
#
|
295
|
+
abort('no lib') unless This.lib
|
296
|
+
abort('no version') unless This.version
|
297
|
+
|
298
|
+
# discover full path to this ruby executable
|
299
|
+
#
|
300
|
+
c = Config::CONFIG
|
301
|
+
bindir = c["bindir"] || c['BINDIR']
|
302
|
+
ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
|
303
|
+
ruby_ext = c['EXEEXT'] || ''
|
304
|
+
ruby = File.join(bindir, (ruby_install_name + ruby_ext))
|
305
|
+
This.ruby = ruby
|
306
|
+
|
307
|
+
# some utils
|
308
|
+
#
|
309
|
+
module Util
|
310
|
+
def indent(s, n = 2)
|
311
|
+
s = unindent(s)
|
312
|
+
ws = ' ' * n
|
313
|
+
s.gsub(%r/^/, ws)
|
314
|
+
end
|
315
|
+
|
316
|
+
def unindent(s)
|
317
|
+
indent = nil
|
318
|
+
s.each_line do |line|
|
319
|
+
next if line =~ %r/^\s*$/
|
320
|
+
indent = line[%r/^\s*/] and break
|
321
|
+
end
|
322
|
+
indent ? s.gsub(%r/^#{ indent }/, "") : s
|
323
|
+
end
|
324
|
+
extend self
|
325
|
+
end
|
326
|
+
|
327
|
+
# template support
|
328
|
+
#
|
329
|
+
class Template
|
330
|
+
def initialize(&block)
|
331
|
+
@block = block
|
332
|
+
@template = block.call.to_s
|
333
|
+
end
|
334
|
+
def expand(b=nil)
|
335
|
+
ERB.new(Util.unindent(@template)).result((b||@block).binding)
|
336
|
+
end
|
337
|
+
alias_method 'to_s', 'expand'
|
338
|
+
end
|
339
|
+
def Template(*args, &block) Template.new(*args, &block) end
|
340
|
+
|
341
|
+
# colored console output support
|
342
|
+
#
|
343
|
+
This.ansi = {
|
344
|
+
:clear => "\e[0m",
|
345
|
+
:reset => "\e[0m",
|
346
|
+
:erase_line => "\e[K",
|
347
|
+
:erase_char => "\e[P",
|
348
|
+
:bold => "\e[1m",
|
349
|
+
:dark => "\e[2m",
|
350
|
+
:underline => "\e[4m",
|
351
|
+
:underscore => "\e[4m",
|
352
|
+
:blink => "\e[5m",
|
353
|
+
:reverse => "\e[7m",
|
354
|
+
:concealed => "\e[8m",
|
355
|
+
:black => "\e[30m",
|
356
|
+
:red => "\e[31m",
|
357
|
+
:green => "\e[32m",
|
358
|
+
:yellow => "\e[33m",
|
359
|
+
:blue => "\e[34m",
|
360
|
+
:magenta => "\e[35m",
|
361
|
+
:cyan => "\e[36m",
|
362
|
+
:white => "\e[37m",
|
363
|
+
:on_black => "\e[40m",
|
364
|
+
:on_red => "\e[41m",
|
365
|
+
:on_green => "\e[42m",
|
366
|
+
:on_yellow => "\e[43m",
|
367
|
+
:on_blue => "\e[44m",
|
368
|
+
:on_magenta => "\e[45m",
|
369
|
+
:on_cyan => "\e[46m",
|
370
|
+
:on_white => "\e[47m"
|
371
|
+
}
|
372
|
+
def say(phrase, *args)
|
373
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
374
|
+
options[:color] = args.shift.to_s.to_sym unless args.empty?
|
375
|
+
keys = options.keys
|
376
|
+
keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
|
377
|
+
|
378
|
+
color = options[:color]
|
379
|
+
bold = options.has_key?(:bold)
|
380
|
+
|
381
|
+
parts = [phrase]
|
382
|
+
parts.unshift(This.ansi[color]) if color
|
383
|
+
parts.unshift(This.ansi[:bold]) if bold
|
384
|
+
parts.push(This.ansi[:clear]) if parts.size > 1
|
385
|
+
|
386
|
+
method = options[:method] || :puts
|
387
|
+
|
388
|
+
Kernel.send(method, parts.join)
|
389
|
+
end
|
390
|
+
|
391
|
+
# always run out of the project dir
|
392
|
+
#
|
393
|
+
Dir.chdir(This.dir)
|
394
|
+
}
|
data/forkoff.gemspec
CHANGED
@@ -3,25 +3,39 @@
|
|
3
3
|
|
4
4
|
Gem::Specification::new do |spec|
|
5
5
|
spec.name = "forkoff"
|
6
|
-
spec.
|
7
|
-
spec.version = "1.1.1"
|
6
|
+
spec.version = "1.2.0"
|
8
7
|
spec.platform = Gem::Platform::RUBY
|
9
8
|
spec.summary = "forkoff"
|
9
|
+
spec.description = "description: forkoff kicks the ass"
|
10
|
+
spec.license = "Ruby"
|
11
|
+
|
12
|
+
spec.files =
|
13
|
+
["README",
|
14
|
+
"Rakefile",
|
15
|
+
"forkoff.gemspec",
|
16
|
+
"lib",
|
17
|
+
"lib/forkoff.rb",
|
18
|
+
"readme.erb",
|
19
|
+
"samples",
|
20
|
+
"samples/a.rb",
|
21
|
+
"samples/b.rb",
|
22
|
+
"samples/c.rb",
|
23
|
+
"samples/d.rb",
|
24
|
+
"test",
|
25
|
+
"test/forkoff_test.rb"]
|
10
26
|
|
11
|
-
spec.files = ["forkoff.gemspec", "lib", "lib/forkoff.rb", "rakefile", "README", "readme.erb", "samples", "samples/a.rb", "samples/b.rb", "samples/c.rb", "samples/d.rb", "test", "test/forkoff.rb"]
|
12
27
|
spec.executables = []
|
13
28
|
|
14
29
|
spec.require_path = "lib"
|
15
30
|
|
16
|
-
spec.
|
17
|
-
|
18
|
-
|
19
|
-
#spec.add_dependency 'fattr'
|
31
|
+
spec.test_files = nil
|
32
|
+
|
33
|
+
|
20
34
|
|
21
35
|
spec.extensions.push(*[])
|
22
36
|
|
23
37
|
spec.rubyforge_project = "codeforpeople"
|
24
38
|
spec.author = "Ara T. Howard"
|
25
39
|
spec.email = "ara.t.howard@gmail.com"
|
26
|
-
spec.homepage = "
|
40
|
+
spec.homepage = "https://github.com/ahoward/forkoff"
|
27
41
|
end
|
data/lib/forkoff.rb
CHANGED
@@ -2,11 +2,7 @@ require 'thread'
|
|
2
2
|
|
3
3
|
module Forkoff
|
4
4
|
def version
|
5
|
-
'1.
|
6
|
-
end
|
7
|
-
|
8
|
-
def done
|
9
|
-
@done ||= Object.new
|
5
|
+
'1.2.0'
|
10
6
|
end
|
11
7
|
|
12
8
|
def default
|
@@ -76,7 +72,7 @@ module Forkoff
|
|
76
72
|
end
|
77
73
|
end
|
78
74
|
|
79
|
-
def pipe_result
|
75
|
+
def pipe_result arg, &block
|
80
76
|
r, w = IO.pipe
|
81
77
|
pid = fork
|
82
78
|
|
@@ -84,13 +80,13 @@ module Forkoff
|
|
84
80
|
r.close
|
85
81
|
result =
|
86
82
|
begin
|
87
|
-
block.call(
|
83
|
+
block.call(arg)
|
88
84
|
rescue Object => e
|
89
85
|
e
|
90
86
|
end
|
91
87
|
w.write( Marshal.dump( result ) )
|
92
88
|
w.close
|
93
|
-
exit
|
89
|
+
exit!
|
94
90
|
end
|
95
91
|
|
96
92
|
w.close
|
@@ -104,19 +100,19 @@ module Forkoff
|
|
104
100
|
return result
|
105
101
|
end
|
106
102
|
|
107
|
-
def file_result
|
103
|
+
def file_result arg, &block
|
108
104
|
tmpfile do |fd|
|
109
105
|
pid = fork
|
110
106
|
|
111
107
|
unless pid
|
112
108
|
result =
|
113
109
|
begin
|
114
|
-
block.call(
|
110
|
+
block.call(arg)
|
115
111
|
rescue Object => e
|
116
112
|
e
|
117
113
|
end
|
118
114
|
fd.write( Marshal.dump( result ) )
|
119
|
-
exit
|
115
|
+
exit!
|
120
116
|
end
|
121
117
|
|
122
118
|
Process.waitpid pid
|
@@ -130,85 +126,84 @@ module Forkoff
|
|
130
126
|
class Error < ::StandardError; end
|
131
127
|
|
132
128
|
extend self
|
129
|
+
|
130
|
+
STRATEGIES = Hash.new do |h, key|
|
131
|
+
strategy = key.to_s.strip.downcase.to_sym
|
132
|
+
raise ArgumentError, "strategy=#{ strategy.class }(#{ strategy.inspect })" unless h.has_key?(strategy)
|
133
|
+
h[key] = h[strategy]
|
134
|
+
end
|
135
|
+
|
136
|
+
STRATEGIES.merge!(
|
137
|
+
:pipe => :pipe_result,
|
138
|
+
:file => :file_result
|
139
|
+
)
|
140
|
+
|
133
141
|
end
|
134
142
|
|
135
143
|
module Enumerable
|
136
144
|
def forkoff options = {}, &block
|
145
|
+
#
|
137
146
|
options = { 'processes' => Integer(options) } unless Hash === options
|
138
147
|
n = Integer( options['processes'] || options[:processes] || Forkoff.default['processes'] )
|
139
|
-
strategy = options['strategy'] || options[:strategy] ||
|
148
|
+
strategy = options['strategy'] || options[:strategy] || :pipe
|
149
|
+
strategy_method = Forkoff::STRATEGIES[strategy]
|
140
150
|
q = SizedQueue.new(n)
|
141
|
-
|
142
|
-
|
143
|
-
#
|
144
|
-
# consumers
|
145
|
-
#
|
146
|
-
consumers = []
|
147
|
-
|
148
|
-
n.times do |i|
|
149
|
-
thread =
|
150
|
-
Thread.new do
|
151
|
-
Thread.current.abort_on_exception = true
|
152
|
-
|
153
|
-
loop do
|
154
|
-
value = q.pop
|
155
|
-
break if value == Forkoff.done
|
156
|
-
args, index = value
|
157
|
-
|
158
|
-
result =
|
159
|
-
case strategy.to_s.strip.downcase
|
160
|
-
when 'pipe'
|
161
|
-
Forkoff.pipe_result(*args, &block)
|
162
|
-
when 'file'
|
163
|
-
Forkoff.file_result(*args, &block)
|
164
|
-
else
|
165
|
-
raise ArgumentError, "strategy=#{ strategy.class }(#{ strategy.inspect })"
|
166
|
-
end
|
167
|
-
|
168
|
-
results[i].push( [result, index] )
|
169
|
-
end
|
170
|
-
|
171
|
-
results[i].push( Forkoff.done )
|
172
|
-
end
|
173
|
-
|
174
|
-
consumers << thread
|
175
|
-
end
|
151
|
+
result_sets = Array.new(n){ [] }
|
176
152
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
153
|
+
# consumers
|
154
|
+
#
|
155
|
+
consumers =
|
156
|
+
result_sets.map do |set|
|
181
157
|
Thread.new do
|
182
158
|
Thread.current.abort_on_exception = true
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
159
|
+
|
160
|
+
loop do
|
161
|
+
arg, index = q.pop
|
162
|
+
break if index.nil?
|
163
|
+
result = Forkoff.send( strategy_method, arg, &block )
|
164
|
+
|
165
|
+
set.push [result, index]
|
188
166
|
end
|
167
|
+
|
168
|
+
set.push( :done )
|
189
169
|
end
|
170
|
+
end
|
190
171
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
172
|
+
# producers
|
173
|
+
#
|
174
|
+
producer =
|
175
|
+
Thread.new do
|
176
|
+
Thread.current.abort_on_exception = true
|
177
|
+
each_with_index do |arg, i|
|
178
|
+
q.push [arg, i]
|
179
|
+
end
|
180
|
+
n.times do |i|
|
181
|
+
q.push( :done )
|
182
|
+
end
|
196
183
|
end
|
197
184
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
185
|
+
# wait for all consumers to complete
|
186
|
+
#
|
187
|
+
consumers.each do |t|
|
188
|
+
t.value
|
189
|
+
end
|
202
190
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
191
|
+
# wait for the producer to complete
|
192
|
+
#
|
193
|
+
producer.value
|
194
|
+
|
195
|
+
# gather results
|
196
|
+
#
|
197
|
+
returned = []
|
198
|
+
|
199
|
+
result_sets.each do |set|
|
200
|
+
set.each do |result, index|
|
201
|
+
break if index.nil?
|
202
|
+
returned[index] = result
|
209
203
|
end
|
204
|
+
end
|
210
205
|
|
211
|
-
|
206
|
+
returned
|
212
207
|
end
|
213
208
|
|
214
209
|
alias_method 'forkoff!', 'forkoff'
|
@@ -23,7 +23,7 @@ class T < Test::Unit::TestCase
|
|
23
23
|
n = 4
|
24
24
|
strategies = :forkoff, :each
|
25
25
|
|
26
|
-
|
26
|
+
n.times do
|
27
27
|
result = {}
|
28
28
|
|
29
29
|
strategies.each do |strategy|
|
@@ -50,5 +50,25 @@ class T < Test::Unit::TestCase
|
|
50
50
|
assert elapsed < 2
|
51
51
|
end
|
52
52
|
|
53
|
+
def test_hash
|
54
|
+
received = []
|
55
|
+
sent = [{:foo => :bar, 1=>2}, {:baz => 42}]
|
56
|
+
received = sent.forkoff do |h|
|
57
|
+
h
|
58
|
+
end
|
59
|
+
assert_equal sent, received
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_multi_argument
|
63
|
+
sent = [[1,2,3], [4, 5, 6]]
|
64
|
+
received = sent.forkoff do |a, b, c|
|
65
|
+
[a, b, c]
|
66
|
+
end
|
67
|
+
assert_equal sent, received
|
68
|
+
received = sent.forkoff do |arr|
|
69
|
+
arr
|
70
|
+
end
|
71
|
+
assert_equal sent, received
|
72
|
+
end
|
53
73
|
|
54
74
|
end
|
metadata
CHANGED
@@ -1,64 +1,53 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: forkoff
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
6
|
+
authors:
|
7
7
|
- Ara T. Howard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
|
12
|
-
date: 2009-10-12 00:00:00 -06:00
|
13
|
-
default_executable:
|
11
|
+
date: 2014-03-14 00:00:00.000000000 Z
|
14
12
|
dependencies: []
|
15
|
-
|
16
|
-
description: brain-dead simple parallel processing for ruby
|
13
|
+
description: ! 'description: forkoff kicks the ass'
|
17
14
|
email: ara.t.howard@gmail.com
|
18
15
|
executables: []
|
19
|
-
|
20
16
|
extensions: []
|
21
|
-
|
22
17
|
extra_rdoc_files: []
|
23
|
-
|
24
|
-
|
18
|
+
files:
|
19
|
+
- README
|
20
|
+
- Rakefile
|
25
21
|
- forkoff.gemspec
|
26
22
|
- lib/forkoff.rb
|
27
|
-
- rakefile
|
28
|
-
- README
|
29
23
|
- readme.erb
|
30
24
|
- samples/a.rb
|
31
25
|
- samples/b.rb
|
32
26
|
- samples/c.rb
|
33
27
|
- samples/d.rb
|
34
|
-
- test/
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
28
|
+
- test/forkoff_test.rb
|
29
|
+
homepage: https://github.com/ahoward/forkoff
|
30
|
+
licenses:
|
31
|
+
- Ruby
|
32
|
+
metadata: {}
|
39
33
|
post_install_message:
|
40
34
|
rdoc_options: []
|
41
|
-
|
42
|
-
require_paths:
|
35
|
+
require_paths:
|
43
36
|
- lib
|
44
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- -
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version:
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
version: "0"
|
55
|
-
version:
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
56
47
|
requirements: []
|
57
|
-
|
58
48
|
rubyforge_project: codeforpeople
|
59
|
-
rubygems_version:
|
49
|
+
rubygems_version: 2.0.3
|
60
50
|
signing_key:
|
61
|
-
specification_version:
|
51
|
+
specification_version: 4
|
62
52
|
summary: forkoff
|
63
|
-
test_files:
|
64
|
-
- test/forkoff.rb
|
53
|
+
test_files: []
|
data/rakefile
DELETED
@@ -1,223 +0,0 @@
|
|
1
|
-
|
2
|
-
This.rubyforge_project = 'codeforpeople'
|
3
|
-
This.author = "Ara T. Howard"
|
4
|
-
This.email = "ara.t.howard@gmail.com"
|
5
|
-
This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
|
6
|
-
|
7
|
-
|
8
|
-
task :default do
|
9
|
-
puts(Rake::Task.tasks.map{|task| task.name} - ['default'])
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
task :gemspec do
|
14
|
-
ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
|
15
|
-
ignore_directories = 'pkg'
|
16
|
-
|
17
|
-
shiteless =
|
18
|
-
lambda do |list|
|
19
|
-
list.delete_if do |entry|
|
20
|
-
next unless test(?e, entry)
|
21
|
-
extension = File.basename(entry).split(%r/[.]/).last
|
22
|
-
ignore_extensions.any?{|ext| ext === extension}
|
23
|
-
end
|
24
|
-
list.delete_if do |entry|
|
25
|
-
next unless test(?d, entry)
|
26
|
-
dirname = File.expand_path(entry)
|
27
|
-
ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
lib = This.lib
|
32
|
-
version = This.version
|
33
|
-
files = shiteless[Dir::glob("**/**")]
|
34
|
-
executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
|
35
|
-
has_rdoc = true #File.exist?('doc')
|
36
|
-
test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
|
37
|
-
|
38
|
-
extensions = This.extensions
|
39
|
-
if extensions.nil?
|
40
|
-
%w( Makefile configure extconf.rb ).each do |ext|
|
41
|
-
extensions << ext if File.exists?(ext)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
extensions = [extensions].flatten.compact
|
45
|
-
|
46
|
-
template =
|
47
|
-
if test(?e, 'gemspec.erb')
|
48
|
-
Template{ IO.read('gemspec.erb') }
|
49
|
-
else
|
50
|
-
Template {
|
51
|
-
<<-__
|
52
|
-
## #{ lib }.gemspec
|
53
|
-
#
|
54
|
-
|
55
|
-
Gem::Specification::new do |spec|
|
56
|
-
spec.name = #{ lib.inspect }
|
57
|
-
spec.description = 'brain-dead simple parallel processing for ruby'
|
58
|
-
spec.version = #{ version.inspect }
|
59
|
-
spec.platform = Gem::Platform::RUBY
|
60
|
-
spec.summary = #{ lib.inspect }
|
61
|
-
|
62
|
-
spec.files = #{ files.inspect }
|
63
|
-
spec.executables = #{ executables.inspect }
|
64
|
-
|
65
|
-
spec.require_path = "lib"
|
66
|
-
|
67
|
-
spec.has_rdoc = #{ has_rdoc.inspect }
|
68
|
-
spec.test_files = #{ test_files.inspect }
|
69
|
-
#spec.add_dependency 'lib', '>= version'
|
70
|
-
#spec.add_dependency 'fattr'
|
71
|
-
|
72
|
-
spec.extensions.push(*#{ extensions.inspect })
|
73
|
-
|
74
|
-
spec.rubyforge_project = #{ This.rubyforge_project.inspect }
|
75
|
-
spec.author = #{ This.author.inspect }
|
76
|
-
spec.email = #{ This.email.inspect }
|
77
|
-
spec.homepage = #{ This.homepage.inspect }
|
78
|
-
end
|
79
|
-
__
|
80
|
-
}
|
81
|
-
end
|
82
|
-
|
83
|
-
open("#{ lib }.gemspec", "w"){|fd| fd.puts template}
|
84
|
-
This.gemspec = "#{ lib }.gemspec"
|
85
|
-
end
|
86
|
-
|
87
|
-
task :gem => [:clean, :gemspec] do
|
88
|
-
Fu.mkdir_p This.pkgdir
|
89
|
-
before = Dir['*.gem']
|
90
|
-
cmd = "gem build #{ This.gemspec }"
|
91
|
-
`#{ cmd }`
|
92
|
-
after = Dir['*.gem']
|
93
|
-
gem = ((after - before).first || after.first) or abort('no gem!')
|
94
|
-
Fu.mv gem, This.pkgdir
|
95
|
-
This.gem = File.basename(gem)
|
96
|
-
end
|
97
|
-
|
98
|
-
task :readme do
|
99
|
-
samples = ''
|
100
|
-
prompt = '~ > '
|
101
|
-
lib = This.lib
|
102
|
-
version = This.version
|
103
|
-
|
104
|
-
Dir['sample*/*'].sort.each do |sample|
|
105
|
-
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
106
|
-
|
107
|
-
cmd = "cat #{ sample }"
|
108
|
-
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
109
|
-
samples << Util.indent(`#{ cmd }`, 4) << "\n"
|
110
|
-
|
111
|
-
cmd = "ruby #{ sample }"
|
112
|
-
samples << Util.indent(prompt + cmd, 2) << "\n\n"
|
113
|
-
|
114
|
-
cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib #{ sample })'"
|
115
|
-
samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
|
116
|
-
end
|
117
|
-
|
118
|
-
template =
|
119
|
-
if test(?e, 'readme.erb')
|
120
|
-
Template{ IO.read('readme.erb') }
|
121
|
-
else
|
122
|
-
Template {
|
123
|
-
<<-__
|
124
|
-
NAME
|
125
|
-
#{ lib }
|
126
|
-
|
127
|
-
DESCRIPTION
|
128
|
-
|
129
|
-
INSTALL
|
130
|
-
gem install #{ lib }
|
131
|
-
|
132
|
-
SAMPLES
|
133
|
-
#{ samples }
|
134
|
-
__
|
135
|
-
}
|
136
|
-
end
|
137
|
-
|
138
|
-
open("README", "w"){|fd| fd.puts template}
|
139
|
-
end
|
140
|
-
|
141
|
-
|
142
|
-
task :clean do
|
143
|
-
Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
|
144
|
-
end
|
145
|
-
|
146
|
-
|
147
|
-
task :release => [:clean, :gemspec, :gem] do
|
148
|
-
gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
|
149
|
-
raise "which one? : #{ gems.inspect }" if gems.size > 1
|
150
|
-
raise "no gems?" if gems.size < 1
|
151
|
-
cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.pkgdir }/#{ This.gem }"
|
152
|
-
puts cmd
|
153
|
-
system cmd
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
BEGIN {
|
161
|
-
$VERBOSE = nil
|
162
|
-
|
163
|
-
require 'ostruct'
|
164
|
-
require 'erb'
|
165
|
-
require 'fileutils'
|
166
|
-
|
167
|
-
Fu = FileUtils
|
168
|
-
|
169
|
-
This = OpenStruct.new
|
170
|
-
|
171
|
-
This.file = File.expand_path(__FILE__)
|
172
|
-
This.dir = File.dirname(This.file)
|
173
|
-
This.pkgdir = File.join(This.dir, 'pkg')
|
174
|
-
|
175
|
-
lib = ENV['LIB']
|
176
|
-
unless lib
|
177
|
-
lib = File.basename(Dir.pwd)
|
178
|
-
end
|
179
|
-
This.lib = lib
|
180
|
-
|
181
|
-
version = ENV['VERSION']
|
182
|
-
unless version
|
183
|
-
name = lib.capitalize
|
184
|
-
require "./lib/#{ lib }"
|
185
|
-
version = eval(name).send(:version)
|
186
|
-
end
|
187
|
-
This.version = version
|
188
|
-
|
189
|
-
abort('no lib') unless This.lib
|
190
|
-
abort('no version') unless This.version
|
191
|
-
|
192
|
-
module Util
|
193
|
-
def indent(s, n = 2)
|
194
|
-
s = unindent(s)
|
195
|
-
ws = ' ' * n
|
196
|
-
s.gsub(%r/^/, ws)
|
197
|
-
end
|
198
|
-
|
199
|
-
def unindent(s)
|
200
|
-
indent = nil
|
201
|
-
s.each do |line|
|
202
|
-
next if line =~ %r/^\s*$/
|
203
|
-
indent = line[%r/^\s*/] and break
|
204
|
-
end
|
205
|
-
indent ? s.gsub(%r/^#{ indent }/, "") : s
|
206
|
-
end
|
207
|
-
extend self
|
208
|
-
end
|
209
|
-
|
210
|
-
class Template
|
211
|
-
def initialize(&block)
|
212
|
-
@block = block
|
213
|
-
@template = block.call.to_s
|
214
|
-
end
|
215
|
-
def expand(b=nil)
|
216
|
-
ERB.new(Util.unindent(@template)).result(b||@block)
|
217
|
-
end
|
218
|
-
alias_method 'to_s', 'expand'
|
219
|
-
end
|
220
|
-
def Template(*args, &block) Template.new(*args, &block) end
|
221
|
-
|
222
|
-
Dir.chdir(This.dir)
|
223
|
-
}
|