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