flustered 0.1.1
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/bin/flustered +4 -0
- data/lib/flustered.rb +17 -0
- data/lib/flustered/adapters.rb +0 -0
- data/lib/flustered/adapters/minitest.rb +61 -0
- data/lib/flustered/cli.rb +30 -0
- data/lib/flustered/compatibility.rb +10 -0
- data/lib/flustered/core.rb +38 -0
- data/lib/flustered/extensions.rb +23 -0
- data/lib/flustered/vendored_systemu.rb +357 -0
- data/lib/flustered/vendored_trollop.rb +782 -0
- data/lib/flustered/version.rb +3 -0
- metadata +113 -0
data/bin/flustered
ADDED
data/lib/flustered.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Locate bundled gems in vendor/.
|
2
|
+
#load_paths += Dir[File.join(File.dirname(__FILE__), '..', '/vendor/gems/**"].map do |dir|
|
3
|
+
# File.directory?(lib = "#{dir}/lib") ? lib : dir
|
4
|
+
#end
|
5
|
+
|
6
|
+
# TODO: remove dependency on bundler, and locate the bundled gems manually.
|
7
|
+
require 'bundler/setup'
|
8
|
+
|
9
|
+
require 'flustered/extensions'
|
10
|
+
require 'flustered/version'
|
11
|
+
require 'flustered/cli'
|
12
|
+
require 'flustered/core'
|
13
|
+
require 'flustered/adapters'
|
14
|
+
|
15
|
+
module Flustered
|
16
|
+
# Your code goes here...
|
17
|
+
end
|
File without changes
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/unit'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
def suppress_autorun
|
7
|
+
Class.new(MiniTest::Unit) do
|
8
|
+
# A warning is generated when class instance variables are modified from
|
9
|
+
# anonymous classes. Need to use class_variable_set, which is public in
|
10
|
+
# 1.9 and private in 1.8.
|
11
|
+
# See http://sequel.heroku.com/2010/06/17/ruby-192-compatibility/
|
12
|
+
#
|
13
|
+
self.send :class_variable_set, :@@installed_at_exit, true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
suppress_autorun
|
18
|
+
|
19
|
+
require 'test/unit'
|
20
|
+
|
21
|
+
def get_doc name
|
22
|
+
require 'yard'
|
23
|
+
require 'stringio'
|
24
|
+
|
25
|
+
YARD::CLI::YRI::DEFAULT_SEARCH_PATHS.push('.flustered.yardoc')
|
26
|
+
yri = YARD::CLI::YRI.new
|
27
|
+
|
28
|
+
out = StringIO.new
|
29
|
+
$stdout = out
|
30
|
+
hasdoc = yri.send(:find_object, name) != nil
|
31
|
+
YARD::CLI::YRI.new.run('--no-pager', name) if hasdoc
|
32
|
+
ensure
|
33
|
+
$stdout = STDOUT
|
34
|
+
|
35
|
+
out.read
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
name = 'math'
|
41
|
+
require_relative "#{name}/#{name}"
|
42
|
+
|
43
|
+
# Instead of exit, look for EOF!
|
44
|
+
Command = Struct.new(:command, :timeout) do
|
45
|
+
end
|
46
|
+
|
47
|
+
data = JSON.parse(STDIN.read)
|
48
|
+
c = Command.new(data['command'], data['timeout'])
|
49
|
+
|
50
|
+
Test::Unit::TestCase.test_suites.each do |s|
|
51
|
+
s.test_methods.each do |t|
|
52
|
+
p "#{s} : #{t}"
|
53
|
+
doc = get_doc "#{s}##{t}"
|
54
|
+
p doc if doc
|
55
|
+
instance = s.new t
|
56
|
+
runner = MiniTest::Unit.new
|
57
|
+
result = instance.run(runner)
|
58
|
+
p result
|
59
|
+
runner.instance_eval { p @report } unless result == '.'
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'flustered/vendored_trollop'
|
2
|
+
require 'flustered/core'
|
3
|
+
|
4
|
+
module Flustered
|
5
|
+
class Cli
|
6
|
+
@@version = Flustered::VERSION + ' (c) Spencer Charles'
|
7
|
+
@@parser = Trollop::options do
|
8
|
+
|
9
|
+
banner "Flustered " + @@version
|
10
|
+
banner <<-TEXT
|
11
|
+
Flustered is a test toolkit that hooks your unit tests up with a REST API.
|
12
|
+
Usage: flustered [options]
|
13
|
+
TEXT
|
14
|
+
|
15
|
+
version @@version
|
16
|
+
|
17
|
+
opt :sample, 'A stupid sample option'
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.run(*args)
|
21
|
+
Trollop::with_standard_exception_handling @@parser do
|
22
|
+
o = @@parser.parse args
|
23
|
+
end
|
24
|
+
# Trollop::die "Must specify some arg TBD" if args.empty?
|
25
|
+
|
26
|
+
Flustered::Core.run
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'innate'
|
2
|
+
|
3
|
+
module Flustered
|
4
|
+
class Core
|
5
|
+
include Innate::Node
|
6
|
+
layout 'default'
|
7
|
+
provide :html, :engine => :haml
|
8
|
+
|
9
|
+
def css(name, options={})
|
10
|
+
options[:rel] ||= 'stylesheet'
|
11
|
+
options[:type] ||= 'text/css'
|
12
|
+
options[:media] ||= 'screen'
|
13
|
+
|
14
|
+
tag = %Q{<link rel="%s" type="%s" media="%s" href="style/css/%s.css"/>}
|
15
|
+
tag = %Q{<!--[if #{options[:where]}]>#{tag}<![endif]-->} if options[:where]
|
16
|
+
|
17
|
+
tag % [options[:rel], options[:type], options[:media], name]
|
18
|
+
end
|
19
|
+
|
20
|
+
def js(name, type='text/javascript')
|
21
|
+
tag = %Q{<script type="%s" src="style/js/%s.js"></script>}
|
22
|
+
tag % [type, name]
|
23
|
+
end
|
24
|
+
|
25
|
+
def index
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run
|
29
|
+
root=File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'app'))
|
30
|
+
Innate.options[:roots] << root
|
31
|
+
Innate.middleware! :dev do |m|
|
32
|
+
m.innate
|
33
|
+
end
|
34
|
+
Innate.start :root => root, :mode => :dev
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'innate'
|
2
|
+
|
3
|
+
require 'haml/util'
|
4
|
+
require 'haml/engine'
|
5
|
+
|
6
|
+
module Innate
|
7
|
+
module View
|
8
|
+
module Haml
|
9
|
+
|
10
|
+
# Shamelessly excerpted from Ramaze.
|
11
|
+
def self.call(action, string)
|
12
|
+
haml = View.compile(string) do |s|
|
13
|
+
::Haml::Engine.new(s, action.options)
|
14
|
+
end
|
15
|
+
html = haml.to_html(action.instance, action.variables)
|
16
|
+
return html, 'text/html'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
register 'Innate::View::Haml', :haml
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,357 @@
|
|
1
|
+
# vim: ts=2:sw=2:sts=2:et:fdm=marker
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'socket'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'rbconfig'
|
6
|
+
require 'thread'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
class Object
|
10
|
+
def systemu(*a, &b) SystemUniversal.new(*a, &b).systemu end
|
11
|
+
end
|
12
|
+
|
13
|
+
class SystemUniversal
|
14
|
+
#
|
15
|
+
# constants
|
16
|
+
#
|
17
|
+
SystemUniversal::VERSION = '2.2.0' unless SystemUniversal.send(:const_defined?, :VERSION)
|
18
|
+
def SystemUniversal.version() SystemUniversal::VERSION end
|
19
|
+
def version() SystemUniversal::VERSION end
|
20
|
+
#
|
21
|
+
# class methods
|
22
|
+
#
|
23
|
+
|
24
|
+
@host = Socket.gethostname
|
25
|
+
@ppid = Process.ppid
|
26
|
+
@pid = Process.pid
|
27
|
+
@turd = ENV['SYSTEMU_TURD']
|
28
|
+
|
29
|
+
c = ::Config::CONFIG
|
30
|
+
ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
|
31
|
+
@ruby = if system('%s -e 42' % ruby)
|
32
|
+
ruby
|
33
|
+
else
|
34
|
+
system('%s -e 42' % 'ruby') ? 'ruby' : warn('no ruby in PATH/CONFIG')
|
35
|
+
end
|
36
|
+
|
37
|
+
class << SystemUniversal
|
38
|
+
%w( host ppid pid ruby turd ).each{|a| attr_accessor a}
|
39
|
+
|
40
|
+
def quote(*words)
|
41
|
+
words.map{|word| word.inspect}.join(' ')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# instance methods
|
47
|
+
#
|
48
|
+
|
49
|
+
def initialize argv, opts = {}, &block
|
50
|
+
getopt = getopts opts
|
51
|
+
|
52
|
+
@argv = argv
|
53
|
+
@block = block
|
54
|
+
|
55
|
+
@stdin = getopt[ ['stdin', 'in', '0', 0] ]
|
56
|
+
@stdout = getopt[ ['stdout', 'out', '1', 1] ]
|
57
|
+
@stderr = getopt[ ['stderr', 'err', '2', 2] ]
|
58
|
+
@env = getopt[ 'env' ]
|
59
|
+
@cwd = getopt[ 'cwd' ]
|
60
|
+
|
61
|
+
@host = getopt[ 'host', self.class.host ]
|
62
|
+
@ppid = getopt[ 'ppid', self.class.ppid ]
|
63
|
+
@pid = getopt[ 'pid', self.class.pid ]
|
64
|
+
@ruby = getopt[ 'ruby', self.class.ruby ]
|
65
|
+
end
|
66
|
+
|
67
|
+
def systemu
|
68
|
+
tmpdir do |tmp|
|
69
|
+
c = child_setup tmp
|
70
|
+
status = nil
|
71
|
+
|
72
|
+
begin
|
73
|
+
thread = nil
|
74
|
+
|
75
|
+
quietly{
|
76
|
+
IO.popen "#{ quote(@ruby) } #{ quote(c['program']) }", 'r+' do |pipe|
|
77
|
+
line = pipe.gets
|
78
|
+
case line
|
79
|
+
when %r/^pid: \d+$/
|
80
|
+
cid = Integer line[%r/\d+/]
|
81
|
+
else
|
82
|
+
begin
|
83
|
+
buf = pipe.read
|
84
|
+
buf = "#{ line }#{ buf }"
|
85
|
+
e = Marshal.load buf
|
86
|
+
raise unless Exception === e
|
87
|
+
raise e
|
88
|
+
rescue
|
89
|
+
raise "wtf?\n#{ buf }\n"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
thread = new_thread cid, @block if @block
|
93
|
+
pipe.read rescue nil
|
94
|
+
end
|
95
|
+
}
|
96
|
+
status = $?
|
97
|
+
ensure
|
98
|
+
if thread
|
99
|
+
begin
|
100
|
+
class << status
|
101
|
+
attr 'thread'
|
102
|
+
end
|
103
|
+
status.instance_eval{ @thread = thread }
|
104
|
+
rescue
|
105
|
+
42
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
if @stdout or @stderr
|
111
|
+
open(c['stdout']){|f| relay f => @stdout} if @stdout
|
112
|
+
open(c['stderr']){|f| relay f => @stderr} if @stderr
|
113
|
+
status
|
114
|
+
else
|
115
|
+
[status, IO.read(c['stdout']), IO.read(c['stderr'])]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def quote *args, &block
|
121
|
+
SystemUniversal.quote(*args, &block)
|
122
|
+
end
|
123
|
+
|
124
|
+
def new_thread cid, block
|
125
|
+
q = Queue.new
|
126
|
+
Thread.new(cid) do |cid|
|
127
|
+
current = Thread.current
|
128
|
+
current.abort_on_exception = true
|
129
|
+
q.push current
|
130
|
+
block.call cid
|
131
|
+
end
|
132
|
+
q.pop
|
133
|
+
end
|
134
|
+
|
135
|
+
def child_setup tmp
|
136
|
+
stdin = File.expand_path(File.join(tmp, 'stdin'))
|
137
|
+
stdout = File.expand_path(File.join(tmp, 'stdout'))
|
138
|
+
stderr = File.expand_path(File.join(tmp, 'stderr'))
|
139
|
+
program = File.expand_path(File.join(tmp, 'program'))
|
140
|
+
config = File.expand_path(File.join(tmp, 'config'))
|
141
|
+
|
142
|
+
if @stdin
|
143
|
+
open(stdin, 'w'){|f| relay @stdin => f}
|
144
|
+
else
|
145
|
+
FileUtils.touch stdin
|
146
|
+
end
|
147
|
+
FileUtils.touch stdout
|
148
|
+
FileUtils.touch stderr
|
149
|
+
|
150
|
+
c = {}
|
151
|
+
c['argv'] = @argv
|
152
|
+
c['env'] = @env
|
153
|
+
c['cwd'] = @cwd
|
154
|
+
c['stdin'] = stdin
|
155
|
+
c['stdout'] = stdout
|
156
|
+
c['stderr'] = stderr
|
157
|
+
c['program'] = program
|
158
|
+
open(config, 'w'){|f| YAML.dump c, f}
|
159
|
+
|
160
|
+
open(program, 'w'){|f| f.write child_program(config)}
|
161
|
+
|
162
|
+
c
|
163
|
+
end
|
164
|
+
|
165
|
+
def quietly
|
166
|
+
v = $VERBOSE
|
167
|
+
$VERBOSE = nil
|
168
|
+
yield
|
169
|
+
ensure
|
170
|
+
$VERBOSE = v
|
171
|
+
end
|
172
|
+
|
173
|
+
def child_program config
|
174
|
+
<<-program
|
175
|
+
PIPE = STDOUT.dup
|
176
|
+
begin
|
177
|
+
require 'yaml'
|
178
|
+
|
179
|
+
config = YAML.load(IO.read('#{ config }'))
|
180
|
+
|
181
|
+
argv = config['argv']
|
182
|
+
env = config['env']
|
183
|
+
cwd = config['cwd']
|
184
|
+
stdin = config['stdin']
|
185
|
+
stdout = config['stdout']
|
186
|
+
stderr = config['stderr']
|
187
|
+
|
188
|
+
Dir.chdir cwd if cwd
|
189
|
+
env.each{|k,v| ENV[k.to_s] = v.to_s} if env
|
190
|
+
|
191
|
+
STDIN.reopen stdin
|
192
|
+
STDOUT.reopen stdout
|
193
|
+
STDERR.reopen stderr
|
194
|
+
|
195
|
+
PIPE.puts "pid: \#{ Process.pid }"
|
196
|
+
PIPE.flush ### the process is ready yo!
|
197
|
+
PIPE.close
|
198
|
+
|
199
|
+
exec *argv
|
200
|
+
rescue Exception => e
|
201
|
+
PIPE.write Marshal.dump(e) rescue nil
|
202
|
+
exit 42
|
203
|
+
end
|
204
|
+
program
|
205
|
+
end
|
206
|
+
|
207
|
+
def relay srcdst
|
208
|
+
src, dst, ignored = srcdst.to_a.first
|
209
|
+
if src.respond_to? 'read'
|
210
|
+
while((buf = src.read(8192))); dst << buf; end
|
211
|
+
else
|
212
|
+
if src.respond_to?(:each_line)
|
213
|
+
src.each_line{|buf| dst << buf}
|
214
|
+
else
|
215
|
+
src.each{|buf| dst << buf}
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def tmpdir d = Dir.tmpdir, max = 42, &b
|
221
|
+
i = -1 and loop{
|
222
|
+
i += 1
|
223
|
+
|
224
|
+
tmp = File.join d, "systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"
|
225
|
+
|
226
|
+
begin
|
227
|
+
Dir.mkdir tmp
|
228
|
+
rescue Errno::EEXIST
|
229
|
+
raise if i >= max
|
230
|
+
next
|
231
|
+
end
|
232
|
+
|
233
|
+
break(
|
234
|
+
if b
|
235
|
+
begin
|
236
|
+
b.call tmp
|
237
|
+
ensure
|
238
|
+
FileUtils.rm_rf tmp unless SystemU.turd
|
239
|
+
end
|
240
|
+
else
|
241
|
+
tmp
|
242
|
+
end
|
243
|
+
)
|
244
|
+
}
|
245
|
+
end
|
246
|
+
|
247
|
+
def getopts opts = {}
|
248
|
+
lambda do |*args|
|
249
|
+
keys, default, ignored = args
|
250
|
+
catch(:opt) do
|
251
|
+
[keys].flatten.each do |key|
|
252
|
+
[key, key.to_s, key.to_s.intern].each do |key|
|
253
|
+
throw :opt, opts[key] if opts.has_key?(key)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
default
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# some monkeypatching for JRuby
|
263
|
+
if defined? JRUBY_VERSION
|
264
|
+
require 'jruby'
|
265
|
+
import org.jruby.RubyProcess
|
266
|
+
|
267
|
+
class SystemUniversal
|
268
|
+
def systemu
|
269
|
+
split_argv = JRuby::PathHelper.smart_split_command @argv
|
270
|
+
process = java.lang.Runtime.runtime.exec split_argv.to_java(:string)
|
271
|
+
|
272
|
+
stdout, stderr = [process.input_stream, process.error_stream].map do |stream|
|
273
|
+
StreamReader.new(stream)
|
274
|
+
end
|
275
|
+
|
276
|
+
exit_code = process.wait_for
|
277
|
+
[
|
278
|
+
RubyProcess::RubyStatus.new_process_status(JRuby.runtime, exit_code),
|
279
|
+
stdout.join,
|
280
|
+
stderr.join
|
281
|
+
]
|
282
|
+
end
|
283
|
+
|
284
|
+
class StreamReader
|
285
|
+
def initialize(stream)
|
286
|
+
@data = ""
|
287
|
+
@thread = Thread.new do
|
288
|
+
reader = java.io.BufferedReader.new java.io.InputStreamReader.new(stream)
|
289
|
+
|
290
|
+
while line = reader.read_line
|
291
|
+
@data << line << "\n"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def join
|
297
|
+
@thread.join
|
298
|
+
@data
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
|
306
|
+
SystemU = SystemUniversal unless defined? SystemU
|
307
|
+
Systemu = SystemUniversal unless defined? Systemu
|
308
|
+
|
309
|
+
|
310
|
+
|
311
|
+
|
312
|
+
|
313
|
+
|
314
|
+
|
315
|
+
|
316
|
+
|
317
|
+
|
318
|
+
|
319
|
+
|
320
|
+
|
321
|
+
if $0 == __FILE__
|
322
|
+
#
|
323
|
+
# date
|
324
|
+
#
|
325
|
+
date = %q( ruby -e" t = Time.now; STDOUT.puts t; STDERR.puts t " )
|
326
|
+
|
327
|
+
status, stdout, stderr = systemu date
|
328
|
+
p [status, stdout, stderr]
|
329
|
+
|
330
|
+
status = systemu date, 1=>(stdout = '')
|
331
|
+
p [status, stdout]
|
332
|
+
|
333
|
+
status = systemu date, 2=>(stderr = '')
|
334
|
+
p [status, stderr]
|
335
|
+
#
|
336
|
+
# sleep
|
337
|
+
#
|
338
|
+
sleep = %q( ruby -e" p(sleep(1)) " )
|
339
|
+
status, stdout, stderr = systemu sleep
|
340
|
+
p [status, stdout, stderr]
|
341
|
+
|
342
|
+
sleep = %q( ruby -e" p(sleep(42)) " )
|
343
|
+
status, stdout, stderr = systemu(sleep){|cid| Process.kill 9, cid}
|
344
|
+
p [status, stdout, stderr]
|
345
|
+
#
|
346
|
+
# env
|
347
|
+
#
|
348
|
+
env = %q( ruby -e" p ENV['A'] " )
|
349
|
+
status, stdout, stderr = systemu env, :env => {'A' => 42}
|
350
|
+
p [status, stdout, stderr]
|
351
|
+
#
|
352
|
+
# cwd
|
353
|
+
#
|
354
|
+
env = %q( ruby -e" p Dir.pwd " )
|
355
|
+
status, stdout, stderr = systemu env, :cwd => Dir.tmpdir
|
356
|
+
p [status, stdout, stderr]
|
357
|
+
end
|