cond 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/CHANGES.rdoc +12 -0
  2. data/MANIFEST +39 -0
  3. data/{README → README.rdoc} +23 -28
  4. data/Rakefile +23 -180
  5. data/devel/jumpstart.rb +970 -0
  6. data/install.rb +2 -3
  7. data/lib/cond.rb +38 -453
  8. data/lib/cond/code_section.rb +51 -0
  9. data/lib/cond/cond.rb +159 -0
  10. data/lib/cond/defaults.rb +73 -0
  11. data/lib/cond/dsl.rb +2 -0
  12. data/lib/cond/dsl_definition.rb +74 -0
  13. data/lib/cond/error.rb +17 -0
  14. data/lib/cond/handler.rb +10 -0
  15. data/lib/cond/handling_section.rb +12 -0
  16. data/lib/cond/kernel_raise.rb +59 -0
  17. data/lib/cond/message_proc.rb +15 -0
  18. data/lib/cond/restart.rb +10 -0
  19. data/lib/cond/restartable_section.rb +12 -0
  20. data/lib/cond/symbol_generator.rb +41 -0
  21. data/lib/cond/thread_local.rb +71 -0
  22. data/lib/cond/wrapping.rb +45 -0
  23. data/readmes/restarts.rb +1 -2
  24. data/readmes/seibel_pcl.rb +1 -2
  25. data/{examples/bad_example.rb → spec/bad_spec.rb} +2 -2
  26. data/spec/basic_spec.rb +2 -2
  27. data/{examples/calc_example.rb → spec/calc_spec.rb} +2 -2
  28. data/spec/{common.rb → cond_spec_base.rb} +3 -20
  29. data/spec/error_spec.rb +2 -2
  30. data/spec/leave_again_spec.rb +10 -10
  31. data/spec/matching_spec.rb +1 -1
  32. data/spec/raise_spec.rb +1 -1
  33. data/spec/readme_spec.rb +10 -0
  34. data/spec/reraise_spec.rb +2 -2
  35. data/{examples/restarts_example.rb → spec/restarts_spec.rb} +7 -4
  36. data/{examples/seibel_example.rb → spec/seibel_spec.rb} +4 -6
  37. data/spec/symbols_spec.rb +2 -2
  38. data/spec/thread_local_spec.rb +8 -8
  39. data/spec/wrapping_spec.rb +2 -2
  40. metadata +110 -42
  41. data/cond.gemspec +0 -37
  42. data/examples/readme_example.rb +0 -27
  43. data/lib/cond/cond_private/defaults.rb +0 -78
  44. data/lib/cond/cond_private/symbol_generator.rb +0 -45
  45. data/lib/cond/cond_private/thread_local.rb +0 -77
  46. data/spec/specs_spec.rb +0 -16
  47. data/support/quix/ruby.rb +0 -51
  48. data/support/quix/simple_installer.rb +0 -88
@@ -0,0 +1,15 @@
1
+
2
+ module Cond
3
+ #
4
+ # Common base for Handler and Restart. A Proc with a message.
5
+ #
6
+ class MessageProc < Proc
7
+ def initialize(message = "", &block)
8
+ @message = message
9
+ end
10
+
11
+ def message
12
+ @message
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+
2
+ module Cond
3
+ #
4
+ # A restart. Use of this class is optional: you could pass lambdas
5
+ # to Cond.with_restarts, but you'll miss the description string
6
+ # shown inside Cond.default_handler.
7
+ #
8
+ class Restart < MessageProc
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module Cond
3
+ class RestartableSection < CodeSection #:nodoc:
4
+ def initialize(&block)
5
+ super(:with_restarts, &block)
6
+ end
7
+
8
+ def restart(sym, message, &block)
9
+ Cond.restarts_stack.last[sym] = Restart.new(message, &block)
10
+ end
11
+ end
12
+ end
@@ -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
@@ -5,8 +5,7 @@ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
5
5
  #
6
6
 
7
7
  require 'pp'
8
- require 'cond'
9
- include Cond
8
+ require 'cond/dsl'
10
9
 
11
10
  class RestartableFetchError < RuntimeError
12
11
  end
@@ -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__) + "/../spec/common"
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
- include Cond
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__) + "/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
2
 
3
3
  class ExampleError < RuntimeError
4
4
  end
5
5
 
6
- include Cond
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,6 +1,6 @@
1
- require File.dirname(__FILE__) + "/../spec/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
2
 
3
- include Cond
3
+ require 'cond/dsl'
4
4
 
5
5
  class DivergedError < StandardError
6
6
  attr_reader :epsilon
@@ -1,31 +1,14 @@
1
1
  $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
2
- $LOAD_PATH.unshift File.dirname(__FILE__) + "/../support"
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + "/../devel"
3
3
 
4
- # darn rspec warnings
5
- $VERBOSE = false
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
@@ -1,6 +1,6 @@
1
- require File.dirname(__FILE__) + "/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
2
 
3
- include Cond
3
+ require 'cond/dsl'
4
4
 
5
5
  describe "error reporting" do
6
6
  it "should raise NoRestartError when restart is not found" do
@@ -1,6 +1,6 @@
1
- require File.dirname(__FILE__) + "/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
2
 
3
- include Cond
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 == [3]
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 == [4, 5]
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 == [6, 7]
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]
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + "/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
2
 
3
3
  class AnimalError < StandardError ; end
4
4
  class BirdError < AnimalError ; end
data/spec/raise_spec.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + "/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
2
 
3
3
  describe "raise replacement" do
4
4
  it "should raise" do
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
+
3
+ require "jumpstart"
4
+
5
+ Jumpstart.doc_to_spec(
6
+ "README.rdoc",
7
+ "Synopsis",
8
+ "DSL Form and Raw Form",
9
+ "Synopsis 2.0"
10
+ )
data/spec/reraise_spec.rb CHANGED
@@ -1,9 +1,9 @@
1
- require File.dirname(__FILE__) + "/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
2
 
3
3
  class ReraiseExampleError < Exception
4
4
  end
5
5
 
6
- include Cond
6
+ require 'cond/dsl'
7
7
 
8
8
  describe "re-raise" do
9
9
  it "should work work with no arguments" do
@@ -1,11 +1,14 @@
1
- here = File.dirname(__FILE__)
2
- require here + "/../spec/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
3
2
 
4
- RESTARTS_FILE = here + "/../readmes/restarts.rb"
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
- load RESTARTS_FILE
9
+ Jumpstart::Ruby.no_warnings {
10
+ load RESTARTS_FILE
11
+ }
9
12
  }
10
13
  end
11
14
 
@@ -1,11 +1,9 @@
1
- here = File.dirname(__FILE__)
2
- require here + "/../spec/common"
1
+ require File.dirname(__FILE__) + '/cond_spec_base'
2
+ require 'cond/dsl'
3
3
 
4
- seibel_file = here + "/../readmes/seibel_pcl.rb"
4
+ seibel_file = File.dirname(__FILE__) + "/../readmes/seibel_pcl.rb"
5
5
 
6
- include Cond
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 {