cond 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.rdoc +12 -0
- data/MANIFEST +39 -0
- data/{README → README.rdoc} +23 -28
- data/Rakefile +23 -180
- data/devel/jumpstart.rb +970 -0
- data/install.rb +2 -3
- data/lib/cond.rb +38 -453
- data/lib/cond/code_section.rb +51 -0
- data/lib/cond/cond.rb +159 -0
- data/lib/cond/defaults.rb +73 -0
- data/lib/cond/dsl.rb +2 -0
- data/lib/cond/dsl_definition.rb +74 -0
- data/lib/cond/error.rb +17 -0
- data/lib/cond/handler.rb +10 -0
- data/lib/cond/handling_section.rb +12 -0
- data/lib/cond/kernel_raise.rb +59 -0
- data/lib/cond/message_proc.rb +15 -0
- data/lib/cond/restart.rb +10 -0
- data/lib/cond/restartable_section.rb +12 -0
- data/lib/cond/symbol_generator.rb +41 -0
- data/lib/cond/thread_local.rb +71 -0
- data/lib/cond/wrapping.rb +45 -0
- data/readmes/restarts.rb +1 -2
- data/readmes/seibel_pcl.rb +1 -2
- data/{examples/bad_example.rb → spec/bad_spec.rb} +2 -2
- data/spec/basic_spec.rb +2 -2
- data/{examples/calc_example.rb → spec/calc_spec.rb} +2 -2
- data/spec/{common.rb → cond_spec_base.rb} +3 -20
- data/spec/error_spec.rb +2 -2
- data/spec/leave_again_spec.rb +10 -10
- data/spec/matching_spec.rb +1 -1
- data/spec/raise_spec.rb +1 -1
- data/spec/readme_spec.rb +10 -0
- data/spec/reraise_spec.rb +2 -2
- data/{examples/restarts_example.rb → spec/restarts_spec.rb} +7 -4
- data/{examples/seibel_example.rb → spec/seibel_spec.rb} +4 -6
- data/spec/symbols_spec.rb +2 -2
- data/spec/thread_local_spec.rb +8 -8
- data/spec/wrapping_spec.rb +2 -2
- metadata +110 -42
- data/cond.gemspec +0 -37
- data/examples/readme_example.rb +0 -27
- data/lib/cond/cond_private/defaults.rb +0 -78
- data/lib/cond/cond_private/symbol_generator.rb +0 -45
- data/lib/cond/cond_private/thread_local.rb +0 -77
- data/spec/specs_spec.rb +0 -16
- data/support/quix/ruby.rb +0 -51
- data/support/quix/simple_installer.rb +0 -88
data/lib/cond/restart.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
module Cond
|
3
|
+
module SymbolGenerator
|
4
|
+
@count = 'a'
|
5
|
+
@mutex = Mutex.new
|
6
|
+
@recycled = []
|
7
|
+
@object_id_to_sym_list = Hash.new
|
8
|
+
@finalizer = lambda { |id|
|
9
|
+
recycle(@object_id_to_sym_list.delete(id))
|
10
|
+
}
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def gensym
|
14
|
+
@mutex.synchronize {
|
15
|
+
if @recycled.empty?
|
16
|
+
@count.succ!
|
17
|
+
:"|#{@count}"
|
18
|
+
else
|
19
|
+
@recycled.shift
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def recycle(syms)
|
25
|
+
@mutex.synchronize {
|
26
|
+
@recycled.concat(syms)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def track(object, *syms)
|
31
|
+
@mutex.synchronize {
|
32
|
+
@object_id_to_sym_list[object.object_id] = syms.flatten
|
33
|
+
ObjectSpace.define_finalizer(object, @finalizer)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
define_method :gensym, &method(:gensym)
|
39
|
+
private :gensym
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
module Cond
|
3
|
+
#
|
4
|
+
# Thread-local variable.
|
5
|
+
#
|
6
|
+
class ThreadLocal
|
7
|
+
include SymbolGenerator
|
8
|
+
|
9
|
+
#
|
10
|
+
# If +value+ is called before +value=+ then the result of
|
11
|
+
# &default is used.
|
12
|
+
#
|
13
|
+
# &default normally creates a new object, otherwise the returned
|
14
|
+
# object will be shared across threads.
|
15
|
+
#
|
16
|
+
def initialize(&default)
|
17
|
+
@name = gensym
|
18
|
+
@accessed = gensym
|
19
|
+
@default = default
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Reset to just-initialized state for all threads.
|
24
|
+
#
|
25
|
+
def clear(&default)
|
26
|
+
Thread.exclusive {
|
27
|
+
@default = default
|
28
|
+
Thread.list.each { |thread|
|
29
|
+
thread[@accessed] = nil
|
30
|
+
thread[@name] = nil
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def value
|
36
|
+
unless Thread.current[@accessed]
|
37
|
+
if @default
|
38
|
+
Thread.current[@name] = @default.call
|
39
|
+
end
|
40
|
+
Thread.current[@accessed] = true
|
41
|
+
end
|
42
|
+
Thread.current[@name]
|
43
|
+
end
|
44
|
+
|
45
|
+
def value=(value)
|
46
|
+
Thread.current[@accessed] = true
|
47
|
+
Thread.current[@name] = value
|
48
|
+
end
|
49
|
+
|
50
|
+
class << self
|
51
|
+
def accessor_module(name, subclass = self, &block)
|
52
|
+
var = subclass.new(&block)
|
53
|
+
Module.new {
|
54
|
+
define_method(name) {
|
55
|
+
var.value
|
56
|
+
}
|
57
|
+
define_method("#{name}=") { |value|
|
58
|
+
var.value = value
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def reader_module(name, subclass = self, &block)
|
64
|
+
accessor_module(name, subclass, &block).instance_eval {
|
65
|
+
remove_method "#{name}="
|
66
|
+
self
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module Cond
|
3
|
+
module Wrapping
|
4
|
+
#
|
5
|
+
# Allow handlers to be called from C code by wrapping a method with
|
6
|
+
# begin/rescue. Returns the aliased name of the original method.
|
7
|
+
#
|
8
|
+
# See the README.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# Cond.wrap_instance_method(Fixnum, :/)
|
13
|
+
#
|
14
|
+
def wrap_instance_method(mod, method)
|
15
|
+
original = "cond_original_#{mod.inspect}_#{method.inspect}"
|
16
|
+
# TODO: jettison 1.8.6, remove eval and use |&block|
|
17
|
+
mod.module_eval <<-eval_end
|
18
|
+
alias_method :'#{original}', :'#{method}'
|
19
|
+
def #{method}(*args, &block)
|
20
|
+
begin
|
21
|
+
send(:'#{original}', *args, &block)
|
22
|
+
rescue Exception => e
|
23
|
+
raise e
|
24
|
+
end
|
25
|
+
end
|
26
|
+
eval_end
|
27
|
+
original
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Allow handlers to be called from C code by wrapping a method with
|
32
|
+
# begin/rescue. Returns the aliased name of the original method.
|
33
|
+
#
|
34
|
+
# See the README.
|
35
|
+
#
|
36
|
+
# Example:
|
37
|
+
#
|
38
|
+
# Cond.wrap_singleton_method(IO, :read)
|
39
|
+
#
|
40
|
+
def wrap_singleton_method(mod, method)
|
41
|
+
singleton_class = class << mod ; self ; end
|
42
|
+
wrap_instance_method(singleton_class, method)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/readmes/restarts.rb
CHANGED
data/readmes/seibel_pcl.rb
CHANGED
@@ -13,9 +13,8 @@ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
|
13
13
|
##########################################################
|
14
14
|
# setup
|
15
15
|
|
16
|
-
require 'cond'
|
16
|
+
require 'cond/dsl'
|
17
17
|
require 'time'
|
18
|
-
include Cond
|
19
18
|
|
20
19
|
class MalformedLogEntryError < StandardError
|
21
20
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__) +
|
1
|
+
require File.dirname(__FILE__) + '/cond_spec_base'
|
2
2
|
|
3
3
|
#
|
4
4
|
# This is a bad example because a handler should re-raise if no
|
@@ -6,7 +6,7 @@ require File.dirname(__FILE__) + "/../spec/common"
|
|
6
6
|
# 'raise' gets executed. But for fun let's see what it looks like.
|
7
7
|
#
|
8
8
|
|
9
|
-
|
9
|
+
require 'cond/dsl'
|
10
10
|
|
11
11
|
module BadExample
|
12
12
|
A, B = (1..2).map { Class.new RuntimeError }
|
data/spec/basic_spec.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require File.dirname(__FILE__) +
|
1
|
+
require File.dirname(__FILE__) + '/cond_spec_base'
|
2
2
|
|
3
3
|
class ExampleError < RuntimeError
|
4
4
|
end
|
5
5
|
|
6
|
-
|
6
|
+
require 'cond/dsl'
|
7
7
|
|
8
8
|
describe "basic handler/restart functionality" do
|
9
9
|
it "should work using the raw form" do
|
@@ -1,31 +1,14 @@
|
|
1
1
|
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
2
|
-
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../
|
2
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../devel"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
begin
|
7
|
-
require 'spec'
|
8
|
-
rescue LoadError
|
9
|
-
require 'rubygems'
|
10
|
-
require 'spec'
|
11
|
-
end
|
4
|
+
require 'rubygems'
|
5
|
+
require 'spec/autorun'
|
12
6
|
|
13
7
|
# NOTE: In jruby this must come after require 'rubygems'
|
14
8
|
require 'cond'
|
15
9
|
|
16
|
-
require 'pathname'
|
17
10
|
require 'stringio'
|
18
11
|
|
19
|
-
def pipe_to_ruby(code)
|
20
|
-
require 'quix/ruby'
|
21
|
-
IO.popen(%{"#{Quix::Ruby::EXECUTABLE}"}, "r+") { |pipe|
|
22
|
-
pipe.puts code
|
23
|
-
pipe.flush
|
24
|
-
pipe.close_write
|
25
|
-
pipe.read
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
12
|
def capture(input_string)
|
30
13
|
previous = [
|
31
14
|
$stdout, $stdin, Cond.defaults.stream_out, Cond.defaults.stream_in
|
data/spec/error_spec.rb
CHANGED
data/spec/leave_again_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require File.dirname(__FILE__) +
|
1
|
+
require File.dirname(__FILE__) + '/cond_spec_base'
|
2
2
|
|
3
|
-
|
3
|
+
require 'cond/dsl'
|
4
4
|
|
5
5
|
[:handling, :restartable].each { |keyword|
|
6
6
|
describe "arguments to 'leave' have semantics of 'return'" do
|
@@ -36,10 +36,10 @@ include Cond
|
|
36
36
|
send(keyword) do |*args|
|
37
37
|
@memo.push :visit
|
38
38
|
if @memo.size == 2
|
39
|
-
args.should
|
39
|
+
args.should eql([])
|
40
40
|
again
|
41
41
|
elsif @memo.size == 3
|
42
|
-
args.should
|
42
|
+
args.should eql([])
|
43
43
|
leave
|
44
44
|
end
|
45
45
|
again
|
@@ -49,10 +49,10 @@ include Cond
|
|
49
49
|
send(keyword) do |*args|
|
50
50
|
@memo.push :visit
|
51
51
|
if @memo.size == 2
|
52
|
-
args.should
|
52
|
+
args.should eql([3])
|
53
53
|
again
|
54
54
|
elsif @memo.size == 3
|
55
|
-
args.should
|
55
|
+
args.should eql([])
|
56
56
|
leave
|
57
57
|
end
|
58
58
|
again 3
|
@@ -62,10 +62,10 @@ include Cond
|
|
62
62
|
send(keyword) do |*args|
|
63
63
|
@memo.push :visit
|
64
64
|
if @memo.size == 2
|
65
|
-
args.should
|
65
|
+
args.should eql([4, 5])
|
66
66
|
again
|
67
67
|
elsif @memo.size == 3
|
68
|
-
args.should
|
68
|
+
args.should eql([])
|
69
69
|
leave
|
70
70
|
end
|
71
71
|
again 4, 5
|
@@ -75,10 +75,10 @@ include Cond
|
|
75
75
|
send(keyword) do |*args|
|
76
76
|
@memo.push :visit
|
77
77
|
if @memo.size == 2
|
78
|
-
args.should
|
78
|
+
args.should eql([6, 7])
|
79
79
|
again
|
80
80
|
elsif @memo.size == 3
|
81
|
-
args.should
|
81
|
+
args.should eql([])
|
82
82
|
leave
|
83
83
|
end
|
84
84
|
again [6, 7]
|
data/spec/matching_spec.rb
CHANGED
data/spec/raise_spec.rb
CHANGED
data/spec/readme_spec.rb
ADDED
data/spec/reraise_spec.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
-
|
2
|
-
require here + "/../spec/common"
|
1
|
+
require File.dirname(__FILE__) + '/cond_spec_base'
|
3
2
|
|
4
|
-
|
3
|
+
require 'jumpstart'
|
4
|
+
|
5
|
+
RESTARTS_FILE = File.dirname(__FILE__) + '/../readmes/restarts.rb'
|
5
6
|
|
6
7
|
def run_restarts(input_string)
|
7
8
|
capture(input_string) {
|
8
|
-
|
9
|
+
Jumpstart::Ruby.no_warnings {
|
10
|
+
load RESTARTS_FILE
|
11
|
+
}
|
9
12
|
}
|
10
13
|
end
|
11
14
|
|
@@ -1,11 +1,9 @@
|
|
1
|
-
|
2
|
-
require
|
1
|
+
require File.dirname(__FILE__) + '/cond_spec_base'
|
2
|
+
require 'cond/dsl'
|
3
3
|
|
4
|
-
seibel_file =
|
4
|
+
seibel_file = File.dirname(__FILE__) + "/../readmes/seibel_pcl.rb"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
if RUBY_VERSION > "1.8.6"
|
6
|
+
if RUBY_VERSION >= "1.8.7"
|
9
7
|
describe seibel_file do
|
10
8
|
it "should run" do
|
11
9
|
lambda {
|