ruby_ex 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.
Files changed (108) hide show
  1. data/AUTHORS +51 -0
  2. data/ChangeLog +1763 -0
  3. data/NEWS +3 -0
  4. data/README +1 -0
  5. data/Rakefile +8 -0
  6. data/SPEC.dyn.yml +10 -0
  7. data/SPEC.gem.yml +269 -0
  8. data/SPEC.yml +36 -0
  9. data/src/abstract.rb +253 -0
  10. data/src/abstract_node.rb +85 -0
  11. data/src/algorithms.rb +12 -0
  12. data/src/algorithms/simulated_annealing.rb +142 -0
  13. data/src/ask.rb +100 -0
  14. data/src/attributed_class.rb +303 -0
  15. data/src/cache.rb +350 -0
  16. data/src/checkout.rb +12 -0
  17. data/src/choose.rb +271 -0
  18. data/src/commands.rb +20 -0
  19. data/src/commands/command.rb +492 -0
  20. data/src/commands/datas.rb +16 -0
  21. data/src/commands/datas/composite.rb +31 -0
  22. data/src/commands/datas/data.rb +65 -0
  23. data/src/commands/datas/factory.rb +69 -0
  24. data/src/commands/datas/temp.rb +26 -0
  25. data/src/commands/factory.rb +67 -0
  26. data/src/commands/helpers.rb +81 -0
  27. data/src/commands/pipe.rb +66 -0
  28. data/src/commands/runners.rb +16 -0
  29. data/src/commands/runners/exec.rb +50 -0
  30. data/src/commands/runners/fork.rb +130 -0
  31. data/src/commands/runners/runner.rb +140 -0
  32. data/src/commands/runners/system.rb +57 -0
  33. data/src/commands/seq.rb +32 -0
  34. data/src/config_file.rb +95 -0
  35. data/src/const_regexp.rb +57 -0
  36. data/src/daemon.rb +135 -0
  37. data/src/diff.rb +665 -0
  38. data/src/dlogger.rb +62 -0
  39. data/src/drb/drb_observable.rb +95 -0
  40. data/src/drb/drb_observable_pool.rb +27 -0
  41. data/src/drb/drb_service.rb +44 -0
  42. data/src/drb/drb_undumped_attributes.rb +56 -0
  43. data/src/drb/drb_undumped_indexed_object.rb +55 -0
  44. data/src/drb/insecure_protected_methods.rb +101 -0
  45. data/src/drb_ex.rb +12 -0
  46. data/src/dumpable_proc.rb +57 -0
  47. data/src/filetype.rb +229 -0
  48. data/src/generate_id.rb +44 -0
  49. data/src/histogram.rb +222 -0
  50. data/src/hookable.rb +283 -0
  51. data/src/hooker.rb +54 -0
  52. data/src/indexed_node.rb +65 -0
  53. data/src/io_marshal.rb +99 -0
  54. data/src/ioo.rb +193 -0
  55. data/src/labeled_node.rb +62 -0
  56. data/src/logger_observer.rb +24 -0
  57. data/src/md5sum.rb +70 -0
  58. data/src/module/autoload_tree.rb +65 -0
  59. data/src/module/hierarchy.rb +334 -0
  60. data/src/module/instance_method_visibility.rb +71 -0
  61. data/src/node.rb +81 -0
  62. data/src/object_monitor.rb +143 -0
  63. data/src/object_monitor_activity.rb +34 -0
  64. data/src/observable.rb +138 -0
  65. data/src/observable_pool.rb +291 -0
  66. data/src/orderedhash.rb +252 -0
  67. data/src/pp_hierarchy.rb +30 -0
  68. data/src/random_generators.rb +29 -0
  69. data/src/random_generators/random_generator.rb +33 -0
  70. data/src/random_generators/ruby.rb +25 -0
  71. data/src/ruby_ex.rb +124 -0
  72. data/src/safe_eval.rb +346 -0
  73. data/src/sendmail.rb +214 -0
  74. data/src/service_manager.rb +122 -0
  75. data/src/shuffle.rb +30 -0
  76. data/src/spring.rb +134 -0
  77. data/src/spring_set.rb +134 -0
  78. data/src/symtbl.rb +108 -0
  79. data/src/synflow.rb +474 -0
  80. data/src/thread_mutex.rb +11 -0
  81. data/src/timeout_ex.rb +79 -0
  82. data/src/trace.rb +26 -0
  83. data/src/uri/druby.rb +78 -0
  84. data/src/uri/file.rb +63 -0
  85. data/src/uri/ftp_ex.rb +36 -0
  86. data/src/uri/http_ex.rb +41 -0
  87. data/src/uri/pgsql.rb +136 -0
  88. data/src/uri/ssh.rb +87 -0
  89. data/src/uri/svn.rb +113 -0
  90. data/src/uri_ex.rb +71 -0
  91. data/src/verbose_object.rb +70 -0
  92. data/src/yaml/basenode_ext.rb +63 -0
  93. data/src/yaml/chop_header.rb +24 -0
  94. data/src/yaml/transform.rb +450 -0
  95. data/src/yaml/yregexpath.rb +76 -0
  96. data/test/algorithms/simulated_annealing_test.rb +102 -0
  97. data/test/check-pkg-ruby_ex.yml +15 -0
  98. data/test/check-ruby_ex.yml +12 -0
  99. data/test/resources/autoload_tree/A.rb +11 -0
  100. data/test/resources/autoload_tree/B.rb +10 -0
  101. data/test/resources/autoload_tree/foo/C.rb +18 -0
  102. data/test/resources/foo.txt +6 -0
  103. data/test/sanity-suite.yml +12 -0
  104. data/test/sanity/multiple-requires.yml +20 -0
  105. data/test/sanity/single-requires.yml +24 -0
  106. data/test/test-unit-setup.rb +6 -0
  107. data/test/unit-suite.yml +14 -0
  108. metadata +269 -0
@@ -0,0 +1,30 @@
1
+ # Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
2
+ # Author: Nicolas Despres <polrop@lrde.epita.fr>.
3
+ # License: Gnu General Public License.
4
+
5
+ # $LastChangedBy: polrop $
6
+ # $Id: hierarchy.rb 145 2005-01-30 14:16:14Z polrop $
7
+
8
+ require 'ruby_ex'
9
+
10
+ class Hash
11
+
12
+ # Pretty print a hash symbolizing a class hierarchy.
13
+ def pp_hierarchy(prefix=//, abstract=false)
14
+ pp_hierarchy_rec('', prefix, abstract)
15
+ end
16
+
17
+ protected
18
+ def pp_hierarchy_rec(indent, prefix, abstract)
19
+ self.each do |k, v|
20
+ k_str = k.to_s.sub(prefix, '')
21
+ if abstract and k.abstract?
22
+ puts "#{indent}/#{k_str}/"
23
+ else
24
+ puts "#{indent}#{k_str}"
25
+ end
26
+ v.pp_hierarchy_rec(indent + ' ', prefix, abstract)
27
+ end
28
+ end
29
+
30
+ end # class Hash
@@ -0,0 +1,29 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: random_generators.rb 266 2005-06-01 14:27:18Z ertai $
5
+
6
+ require 'ruby_ex'
7
+ require 'module/autoload_tree'
8
+ require 'abstract'
9
+
10
+ module RandomGenerators
11
+
12
+ autoloaded_module(__FILE__)
13
+
14
+ module_function
15
+
16
+ def default
17
+ class << self
18
+ def default
19
+ @@default
20
+ end
21
+ end
22
+ @@default = Ruby.new
23
+ end
24
+
25
+ def default= ( aClass )
26
+ @@default = aClass
27
+ end
28
+
29
+ end # module RandomGenerators
@@ -0,0 +1,33 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: random_generator.rb 258 2005-06-01 00:22:51Z ertai $
5
+
6
+ require 'random_generators'
7
+
8
+ module RandomGenerators
9
+
10
+ class RandomGenerator
11
+ abstract
12
+
13
+ def check_choose_integer ( n )
14
+ unless n.is_a? Integer
15
+ raise ArgumentError, "Need an integer (not #{n})"
16
+ end
17
+ if n <= 0
18
+ raise ArgumentError, "Need an positive value (not #{n})"
19
+ end
20
+ end
21
+
22
+ def check_choose_float ( f )
23
+ unless f.is_a? Float
24
+ raise ArgumentError, "Need a float (not #{f})"
25
+ end
26
+ if f <= 0
27
+ raise ArgumentError, "Need an positive value (not #{f})"
28
+ end
29
+ end
30
+
31
+ end # class RandomGenerator
32
+
33
+ end # module RandomGenerators
@@ -0,0 +1,25 @@
1
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
2
+ # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
3
+ # License:: GNU General Public License (GPL).
4
+ # Revision:: $Id: ruby.rb 258 2005-06-01 00:22:51Z ertai $
5
+
6
+ require 'random_generators'
7
+
8
+ module RandomGenerators
9
+
10
+ class Ruby < RandomGenerator
11
+ concrete
12
+
13
+ def choose_integer ( n )
14
+ check_choose_integer(n)
15
+ Kernel.rand(n)
16
+ end
17
+
18
+ def choose_float ( f=1.0 )
19
+ check_choose_float(f)
20
+ Kernel.rand() * f
21
+ end
22
+
23
+ end # class Ruby
24
+
25
+ end # module RandomGenerators
data/src/ruby_ex.rb ADDED
@@ -0,0 +1,124 @@
1
+ # Copyright:: Copyright (c) 2005 Nicolas Pouillard. All rights reserved.
2
+ # Author:: Nicolas Pouillard <ertai@lrde.epita.fr>.
3
+ # License:: Gnu General Public License.
4
+ # Revision:: $Id: ruby_ex.rb 266 2005-06-01 14:27:18Z ertai $
5
+
6
+ begin
7
+ require 'rubygems'
8
+ require_gem 'core_ex' # FIXME version
9
+ require 'core_ex'
10
+ rescue LoadError => ex
11
+ core_ex = @@dir.parent + 'core_ex/lib/core_ex'
12
+ if core_ex.exists? and not $".include? 'core_ex.rb'
13
+ require core_ex.to_s
14
+ else
15
+ raise ex
16
+ end
17
+ end
18
+
19
+
20
+ module DRb
21
+ end
22
+
23
+ module Algorithms
24
+ end
25
+
26
+ module RubyEx
27
+
28
+ @@dir = Pathname.new(__FILE__).dirname.expand_path
29
+ $: << @@dir.to_s
30
+
31
+ module_function
32
+
33
+ def sources
34
+ @@contents ||= Hash.new([].freeze)
35
+ %[
36
+ abstract.rb Abstract Concrete Class
37
+ abstract_node.rb AbstractNode
38
+ algorithms.rb Algorithms
39
+ attributed_class.rb AttributedClass
40
+ cache.rb Cache
41
+ config_file.rb ConfigFile
42
+ const_regexp.rb ConstRegexp
43
+ daemon.rb Daemon
44
+ diff.rb Diff
45
+ dlogger.rb DLogger
46
+ drb.rb DRb
47
+ dumpable_proc.rb DumpableProc
48
+ filetype.rb FileType
49
+ histogram.rb Histogram
50
+ hookable.rb Hookable
51
+ hooker.rb Hooker
52
+ inactive_timeout.rb InactiveTimeout
53
+ indexed_node.rb IndexedNode
54
+ ioo.rb IOO IOOTCPSocket
55
+ killall.rb KillAll
56
+ labeled_node.rb LabeledNode
57
+ node.rb Node
58
+ object_monitor.rb ObjectMonitor
59
+ object_monitor_activity.rb ObjectMonitorActivity
60
+ observable.rb Observable
61
+ observable_pool.rb ObservablePool
62
+ orderedhash.rb OrderedHash_ext OHash
63
+ pseudo_cache.rb PseudoCache
64
+ random_generators.rb RandomGenerators
65
+ timeout_ex.rb TimeoutEx
66
+ verbose_object.rb VerboseObject
67
+ spring.rb Spring
68
+ spring_set.rb SpringSet
69
+ symtbl.rb SymTbl
70
+ synflow.rb SynFlowFactory SynFlow
71
+ safe_eval.rb SafeEval
72
+ sendmail.rb Sendmail
73
+ service_manager.rb ServiceManager
74
+ test/unit/ui/yaml/testrunner.rb Test::Unit::UI::Yaml::TestRunner
75
+ # drb/session_manager.rb DRb::SessionManager
76
+ # drb/dispatcher.rb DRb::Dispatcher
77
+ ].split(/\n/).each do |line|
78
+ line.sub!(/#.*$/, '')
79
+ line.strip!
80
+ next if line =~ /^\s*$/
81
+ file, *names = line.split(/\s+/)
82
+ @@contents[@@dir + file] = names
83
+ end
84
+ @@contents.freeze
85
+
86
+ @@sources = FileList[@@dir + '**/*.rb'].exclude(/\bsession\/error.rb\b/)
87
+
88
+ class << self
89
+ def sources
90
+ @@sources
91
+ end
92
+ end
93
+ @@sources
94
+ end
95
+
96
+ def dir
97
+ @@dir
98
+ end
99
+
100
+ def each ( &block )
101
+ sources.each do |file|
102
+ block[file, @@contents[file]]
103
+ end
104
+ self
105
+ end
106
+
107
+ def autoload
108
+ each do |file, names|
109
+ names.each do |name|
110
+ name = name.split(/::/).first
111
+ Kernel.autoload(name, file.to_s)
112
+ end
113
+ end
114
+ end
115
+
116
+ def require
117
+ each { |file, names| file.require }
118
+ end
119
+
120
+ end # module RubyEx
121
+
122
+ # RubyEx.each { |*a| p a }
123
+ # RubyEx.require
124
+ # RubyEx.autoload
data/src/safe_eval.rb ADDED
@@ -0,0 +1,346 @@
1
+ # Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
2
+ # Author: Nicolas Despres <polrop@lrde.epita.fr>.
3
+ # License: Gnu General Public License.
4
+
5
+ # $LastChangedBy: ertai $
6
+ # $Id: safe_eval.rb 266 2005-06-01 14:27:18Z ertai $
7
+
8
+ require 'ruby_ex'
9
+
10
+ class SafeEval
11
+
12
+ attr_accessor :collect, :safe
13
+ attr_reader :output
14
+
15
+ def initialize(safe=3, collect=true)
16
+ @safe = safe
17
+ @collect = collect
18
+ end
19
+
20
+ def run(code_str='', binding=nil, filename='(SafeEval)', lineno=1)
21
+ binding = yield if block_given?
22
+ lineno -= 1
23
+ @output = nil
24
+ @output = [] if @collect
25
+ result = nil
26
+ code_str.strip!
27
+ return result if code_str.empty?
28
+ rd_result, wr_result = IO.pipe
29
+ open('|-') do |io|
30
+ if io.nil? then # son
31
+ status = 0
32
+ rd_result.close
33
+ set_environment
34
+ begin
35
+ code = "$SAFE = #@safe\n#{code_str}"
36
+ result = eval(code, binding, filename, lineno)
37
+ status = 0 # needed if the user change the status
38
+ rescue Exception => exception
39
+ status = 1
40
+ result = exception
41
+ ensure
42
+ Marshal.dump(result, wr_result)
43
+ wr_result.close
44
+ exit!(status)
45
+ end
46
+ else # father
47
+ wr_result.close
48
+ io.each_line { |l| @output << l.chomp } if @collect
49
+ result = Marshal.load(rd_result)
50
+ rd_result.close
51
+ Process.waitpid(io.pid)
52
+ end
53
+ end
54
+ raise result if $?.exitstatus == 1
55
+ @output = nil unless @collect
56
+ return result
57
+ end
58
+ public :run
59
+
60
+ # Can be overloaded to specify environment restriction.
61
+ def set_environment
62
+ end
63
+ protected :set_environment
64
+
65
+ end # class SafeEval
66
+
67
+
68
+ #
69
+ # Unit test suite
70
+ #
71
+ test_section __FILE__ do
72
+
73
+
74
+ class SafeEvalTest < Test::Unit::TestCase
75
+
76
+ #
77
+ # Tests
78
+ #
79
+ def test_interface
80
+ se = SafeEval.new
81
+ assert_respond_to(se, :run)
82
+ assert_respond_to(se, :output)
83
+ assert_respond_to(se, :safe)
84
+ assert_respond_to(se, :collect)
85
+ assert(se.protected_methods.include?('set_environment'),
86
+ "no protected method 'set_environment'")
87
+ end
88
+
89
+ def test_nil
90
+ se = SafeEval.new
91
+ assert_equal(nil, se.run)
92
+ assert_equal([], se.output)
93
+ end
94
+
95
+ def test_true
96
+ se = SafeEval.new
97
+ assert_equal(true, se.run('true'))
98
+ assert_equal([], se.output)
99
+ end
100
+
101
+ def test_false
102
+ se = SafeEval.new
103
+ assert_equal(false, se.run('false'))
104
+ assert_equal([], se.output)
105
+ end
106
+
107
+ def test_nil_no_collect
108
+ se = SafeEval.new(3, false)
109
+ assert_equal(nil, se.run)
110
+ assert_equal(nil, se.output)
111
+ end
112
+
113
+ def test_almost_empty_code
114
+ se = SafeEval.new
115
+ assert_equal(nil, se.run(' '))
116
+ assert_equal([], se.output)
117
+ end
118
+
119
+ def test_true_no_collect
120
+ se = SafeEval.new(3, false)
121
+ assert_equal(true, se.run('true'))
122
+ assert_equal(nil, se.output)
123
+ end
124
+
125
+ def test_binding_argument
126
+ def getBinding; a = 42; return binding; end
127
+ se = SafeEval.new
128
+ assert_equal(nil, se.run('puts a', getBinding))
129
+ assert_equal(['42'], se.output)
130
+ end
131
+
132
+ def test_binding_block
133
+ se = SafeEval.new
134
+ assert_equal(true, se.run('puts a; true') { a = 42; return binding })
135
+ assert_equal(['42'], se.output)
136
+ end
137
+
138
+ def test_binding_both
139
+ def getBinding2; a = 51; return binding; end
140
+ se = SafeEval.new
141
+ ret = se.run('puts a; true', getBinding2) { a = 42; return binding }
142
+ assert_equal(true, ret)
143
+ assert_equal(['42'], se.output)
144
+ end
145
+
146
+ def test_exception
147
+ mypid = $$
148
+ se = SafeEval.new
149
+ $tmp = 42
150
+ begin
151
+ $tmp = se.run('raise NoMethodError')
152
+ rescue NoMethodError
153
+ assert_equal(mypid, $$, "bad pid")
154
+ assert_equal(42, $tmp, "result must be nil")
155
+ assert_equal([], se.output)
156
+ ensure
157
+ assert_equal(mypid, $$, "bad pid")
158
+ end
159
+ end
160
+
161
+ def test_exception_collect
162
+ se = SafeEval.new
163
+ assert_raises(Exception) do
164
+ se.run('puts "toto"; raise Exception')
165
+ end
166
+ assert_equal(['toto'], se.output)
167
+ end
168
+
169
+ # FIXME: this test block if DRb::SessionManager test suite is executed before
170
+ # this test suite in check-ruby_ex.
171
+ # def test_exception_no_collect
172
+ # se = SafeEval.new(3, false)
173
+ # assert_raises(Exception) do
174
+ # se.run('puts "toto"; raise Exception')
175
+ # end
176
+ # assert_equal(nil, se.output)
177
+ # end
178
+
179
+ def test_require_forbidden
180
+ se = SafeEval.new
181
+ assert_raises(SecurityError) do
182
+ se.run("require 'foo'")
183
+ end
184
+ assert_equal([], se.output)
185
+ end
186
+
187
+ def test_File_chmod_forbidden
188
+ se = SafeEval.new
189
+ assert_raises(SecurityError) do
190
+ se.run("File.chmod(0755, '/tmp')")
191
+ end
192
+ assert_equal([], se.output)
193
+ end
194
+
195
+ def test_system_forbidden
196
+ se = SafeEval.new
197
+ assert_raises(SecurityError) do
198
+ se.run("system('rm /tmp/x')")
199
+ end
200
+ assert_equal([], se.output)
201
+ end
202
+
203
+ def test_system_allowed
204
+ se = SafeEval.new(2)
205
+ se.run("system(\"echo 'toto'\")")
206
+ assert_equal(['toto'], se.output)
207
+ end
208
+
209
+ def test_print
210
+ se = SafeEval.new
211
+ assert_equal(nil, se.run('print "hello"'))
212
+ assert_equal(['hello'], se.output)
213
+ end
214
+
215
+ def test_puts
216
+ se = SafeEval.new
217
+ assert_equal(nil, se.run('puts "hello"'))
218
+ assert_equal(['hello'], se.output)
219
+ end
220
+
221
+ def test_print_no_collect
222
+ se = SafeEval.new(3, false)
223
+ assert_equal(nil, se.run('print "hello"'))
224
+ assert_equal(nil, se.output)
225
+ end
226
+
227
+ def test_puts_several_lines
228
+ se = SafeEval.new
229
+ assert_equal(nil, se.run('puts "hello\nworld"'))
230
+ assert_equal(['hello', 'world'], se.output)
231
+ end
232
+
233
+ def test_syntax_error
234
+ se = SafeEval.new
235
+ assert_raises(SyntaxError) do
236
+ se.run('4syntaxerror')
237
+ end
238
+ assert_equal([], se.output)
239
+ end
240
+
241
+ def test_bad_identifier
242
+ se = SafeEval.new
243
+ assert_raises(NameError) do
244
+ se.run('bad_identifier.directory?')
245
+ end
246
+ assert_equal([], se.output)
247
+ end
248
+
249
+ def test_syntax_error_location
250
+ se = SafeEval.new
251
+ exc = assert_raises(SyntaxError) do
252
+ se.run('4syntaxerror', nil, 'toto.yml', 1)
253
+ end
254
+ expected_message = <<EOF
255
+ compile error
256
+ toto.yml:1: syntax error
257
+ 4syntaxerror
258
+ ^
259
+ EOF
260
+ expected_message.chomp!
261
+ assert_equal(expected_message, exc.message)
262
+ end
263
+
264
+ def test_syntax_error_location_several_line
265
+ code = <<EOF
266
+ puts "hello"
267
+ puts "world"
268
+ 4syntaxerror;
269
+ EOF
270
+ se = SafeEval.new
271
+ exc = assert_raises(SyntaxError) do
272
+ se.run(code, nil, 'toto.yml', 1)
273
+ end
274
+ expected_message = <<EOF
275
+ compile error
276
+ toto.yml:3: syntax error
277
+ 4syntaxerror;
278
+ ^
279
+ EOF
280
+ expected_message.chomp!
281
+ assert_equal(expected_message, exc.message)
282
+ end
283
+
284
+ def test_exit_forbidden
285
+ se = SafeEval.new(3, false)
286
+ assert_raises(SystemExit) do
287
+ se.run('exit(42)')
288
+ end
289
+ assert_equal(nil, se.output)
290
+ end
291
+
292
+ def test_exit_strong_forbidden
293
+ se = SafeEval.new
294
+ assert_raises(EOFError) do
295
+ se.run('exit!(42)')
296
+ end
297
+ assert_equal([], se.output)
298
+ end
299
+
300
+ def test_undef_me
301
+ se = SafeEval.new
302
+ assert_raises(NoMethodError) do
303
+ se.run('undef_method :run')
304
+ end
305
+ end
306
+
307
+ def test_read_my_var
308
+ se = SafeEval.new
309
+ str = 'puts code'
310
+ se.run(str)
311
+ assert_equal(str, se.output[-1])
312
+ end
313
+
314
+ def test_write_status
315
+ se = SafeEval.new
316
+ assert_equal(1, se.run('status = 1'))
317
+ end
318
+
319
+ def test_write_safe
320
+ se = SafeEval.new
321
+ assert_equal(1, se.run('@safe = 1'))
322
+ assert_equal(true, se.run('@safe == 3'))
323
+ end
324
+
325
+ def test_write_output
326
+ se = SafeEval.new
327
+ assert_equal(['foo'], se.run('@output << "foo"'))
328
+ assert_equal([], se.output)
329
+ end
330
+
331
+ def test_write_output_and_print
332
+ se = SafeEval.new
333
+ assert_equal(nil, se.run('@output << "foo"; p @output'))
334
+ assert_equal(["[\"foo\"]"], se.output)
335
+ end
336
+
337
+ def test_sleep
338
+ se = SafeEval.new
339
+ assert(se.run('sleep(1)') >= 1)
340
+ assert_equal([], se.output)
341
+ end
342
+
343
+ end # class SafeEvalTest
344
+
345
+
346
+ end