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.
@@ -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