cond 0.2.1 → 0.3.0
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/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 {
|