flustered 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../lib/flustered'
3
+
4
+ Flustered::Cli.run(*ARGV)
@@ -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,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless Kernel.respond_to?(:require_relative)
4
+ module Kernel
5
+ def require_relative(path)
6
+ require File.join(File.dirname(caller[0]), path.to_str)
7
+ end
8
+ end
9
+ end
10
+
@@ -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