graph_mediator 0.2.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.
- data/.document +4 -0
- data/.gitignore +26 -0
- data/LICENSE +20 -0
- data/README.rdoc +136 -0
- data/Rakefile +32 -0
- data/graph_mediator.gemspec +31 -0
- data/lib/graph_mediator.rb +509 -0
- data/lib/graph_mediator/locking.rb +50 -0
- data/lib/graph_mediator/mediator.rb +260 -0
- data/lib/graph_mediator/version.rb +3 -0
- data/spec/database.rb +12 -0
- data/spec/examples/course_example_spec.rb +91 -0
- data/spec/examples/dingo_pen_example_spec.rb +288 -0
- data/spec/graph_mediator_spec.rb +500 -0
- data/spec/integration/changes_spec.rb +159 -0
- data/spec/integration/locking_tests_spec.rb +214 -0
- data/spec/integration/nesting_spec.rb +113 -0
- data/spec/integration/threads_spec.rb +59 -0
- data/spec/integration/validation_spec.rb +19 -0
- data/spec/investigation/alias_method_chain_spec.rb +170 -0
- data/spec/investigation/insert_subclass_spec.rb +122 -0
- data/spec/investigation/insert_superclass_spec.rb +131 -0
- data/spec/investigation/module_super_spec.rb +88 -0
- data/spec/investigation/self_decorating.rb +55 -0
- data/spec/mediator_spec.rb +201 -0
- data/spec/reservations/lodging.rb +4 -0
- data/spec/reservations/party.rb +4 -0
- data/spec/reservations/party_lodging.rb +4 -0
- data/spec/reservations/reservation.rb +18 -0
- data/spec/reservations/schema.rb +33 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +65 -0
- metadata +173 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe "mediated_transactions in different threads" do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
ActiveRecord::Base.establish_connection({'adapter' => 'sqlite3', 'database' => 'thread-test'})
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:all) do
|
10
|
+
ActiveRecord::Base.establish_connection({'adapter' => 'sqlite3', 'database' => ':memory:'})
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
load_traceable_callback_tester
|
15
|
+
@t = Traceable.new(:name => :gizmo)
|
16
|
+
@t.save_without_mediation!
|
17
|
+
end
|
18
|
+
|
19
|
+
after(:each) do
|
20
|
+
Object.__send__(:remove_const, :Traceable)
|
21
|
+
end
|
22
|
+
|
23
|
+
# This will produce two warnings regarding overlapping transactions
|
24
|
+
it "should be different instances" do
|
25
|
+
objectid1, objectid2 = nil, nil
|
26
|
+
mediator1, mediator2 = nil, nil
|
27
|
+
|
28
|
+
# puts 'start thread 1'
|
29
|
+
thread1 = Thread.new do
|
30
|
+
t1 = Traceable.find(@t.id)
|
31
|
+
# puts 'preparing to mediate transaction on thread 1'
|
32
|
+
mediator1 = t1.__send__(:_get_mediator)
|
33
|
+
# puts 'mediating transaction on thread 1'
|
34
|
+
Kernel.sleep(2)
|
35
|
+
# puts 'thread 1 finished'
|
36
|
+
end
|
37
|
+
|
38
|
+
# puts 'sleeping kernel 1'
|
39
|
+
Kernel.sleep(1)
|
40
|
+
|
41
|
+
# puts 'start thread 2'
|
42
|
+
thread2 = Thread.new do
|
43
|
+
t2 = Traceable.find(@t.id)
|
44
|
+
# puts 'preparing to mediate transaction on thread 2'
|
45
|
+
mediator2 = t2.__send__(:_get_mediator)
|
46
|
+
# puts 'mediating transaction on thread 2'
|
47
|
+
Kernel.sleep(1)
|
48
|
+
# puts 'thread 2 finished'
|
49
|
+
end
|
50
|
+
|
51
|
+
# puts 'finishing thread 1'
|
52
|
+
thread1.join
|
53
|
+
# puts 'finishing thread 2'
|
54
|
+
thread2.join
|
55
|
+
# pp mediator1, mediator2
|
56
|
+
mediator1.should_not equal(mediator2)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe "GraphMediator validation scenarios" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
load_traceable_callback_tester
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
Object.__send__(:remove_const, :Traceable)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should not call after_mediation if validation fails" do
|
14
|
+
t = Traceable.new
|
15
|
+
t.save.should == false
|
16
|
+
@traceables_callbacks.should == [:before]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
module AliasMethodChainSpec # namespacing
|
4
|
+
|
5
|
+
describe "alias method chain" do
|
6
|
+
|
7
|
+
module ModifiedAliasMethodChain
|
8
|
+
# From Tammo Freese's patch:
|
9
|
+
# https://rails.lighthouseapp.com/projects/8994/tickets/285-alias_method_chain-limits-extensibility
|
10
|
+
def alias_method_chain(target, feature)
|
11
|
+
punctuation = nil
|
12
|
+
with_method, without_method = "#{target}_with_#{feature}#{punctuation}", "#{target}_without_#{feature}#{punctuation}"
|
13
|
+
|
14
|
+
method_defined_here = (instance_methods(false) + private_instance_methods(false)).include?(RUBY_VERSION < '1.9' ? target.to_s : target)
|
15
|
+
unless method_defined_here
|
16
|
+
module_eval <<-EOS
|
17
|
+
def #{target}(*args, &block)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
EOS
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method without_method, target
|
24
|
+
# alias_method target, with_method
|
25
|
+
|
26
|
+
target_method_exists = (instance_methods + private_instance_methods).include?(RUBY_VERSION < '1.9' ? with_method : with_method.to_sym)
|
27
|
+
raise NameError unless target_method_exists
|
28
|
+
|
29
|
+
module_eval <<-EOS
|
30
|
+
def #{target}(*args, &block)
|
31
|
+
self.__send__(:'#{with_method}', *args, &block)
|
32
|
+
end
|
33
|
+
EOS
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module BasicAliasMethodChain
|
38
|
+
def alias_method_chain(target, feature)
|
39
|
+
punctuation = nil
|
40
|
+
with_method, without_method = "#{target}_with_#{feature}#{punctuation}", "#{target}_without_#{feature}#{punctuation}"
|
41
|
+
alias_method without_method, target
|
42
|
+
alias_method target, with_method
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module Bar
|
47
|
+
def bar
|
48
|
+
'bar'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module Baz
|
53
|
+
def baz
|
54
|
+
'baz'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module BazWithLess
|
59
|
+
def self.included(base)
|
60
|
+
base.alias_method_chain :baz, :less
|
61
|
+
end
|
62
|
+
|
63
|
+
def baz_with_less
|
64
|
+
baz_without_less + ' less'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Foo
|
69
|
+
extend ModifiedAliasMethodChain
|
70
|
+
include Bar
|
71
|
+
|
72
|
+
def foo_with_more
|
73
|
+
foo_without_more + ' more'
|
74
|
+
end
|
75
|
+
|
76
|
+
def foo
|
77
|
+
'foo'
|
78
|
+
end
|
79
|
+
alias_method_chain :foo, :more
|
80
|
+
|
81
|
+
def bar_with_less
|
82
|
+
bar_without_less + ' less'
|
83
|
+
end
|
84
|
+
alias_method_chain :bar, :less
|
85
|
+
|
86
|
+
include Baz
|
87
|
+
include BazWithLess
|
88
|
+
end
|
89
|
+
|
90
|
+
class FooBasic
|
91
|
+
extend BasicAliasMethodChain
|
92
|
+
include Bar
|
93
|
+
|
94
|
+
def foo_with_more
|
95
|
+
foo_without_more + ' more'
|
96
|
+
end
|
97
|
+
|
98
|
+
def foo
|
99
|
+
'foo'
|
100
|
+
end
|
101
|
+
alias_method_chain :foo, :more
|
102
|
+
|
103
|
+
def bar_with_less
|
104
|
+
bar_without_less + ' less'
|
105
|
+
end
|
106
|
+
alias_method_chain :bar, :less
|
107
|
+
|
108
|
+
include Baz
|
109
|
+
include BazWithLess
|
110
|
+
end
|
111
|
+
|
112
|
+
it "test modified alias method chain" do
|
113
|
+
f = Foo.new
|
114
|
+
f.foo.should == 'foo more'
|
115
|
+
f.foo_without_more.should == 'foo'
|
116
|
+
f.foo_with_more.should == 'foo more'
|
117
|
+
f.bar.should == 'bar less'
|
118
|
+
f.bar_without_less.should == 'bar'
|
119
|
+
f.bar_with_less.should == 'bar less'
|
120
|
+
f.baz.should == 'baz less'
|
121
|
+
f.baz_without_less.should == 'baz'
|
122
|
+
f.baz_with_less.should == 'baz less'
|
123
|
+
Bar.class_eval do
|
124
|
+
def bar
|
125
|
+
'new bar'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
f.bar.should == 'new bar less'
|
129
|
+
f.bar_without_less.should == 'new bar'
|
130
|
+
f.bar_with_less.should == 'new bar less'
|
131
|
+
Foo.class_eval do
|
132
|
+
def baz_with_less
|
133
|
+
'lesser'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
f.baz_without_less.should == 'baz'
|
137
|
+
f.baz_with_less.should == 'lesser'
|
138
|
+
f.baz.should == 'lesser'
|
139
|
+
end
|
140
|
+
|
141
|
+
it "test basic alias method chain" do
|
142
|
+
f = FooBasic.new
|
143
|
+
f.foo.should == 'foo more'
|
144
|
+
f.foo_without_more.should == 'foo'
|
145
|
+
f.foo_with_more.should == 'foo more'
|
146
|
+
f.bar.should == 'bar less'
|
147
|
+
f.bar_without_less.should == 'bar'
|
148
|
+
f.bar_with_less.should == 'bar less'
|
149
|
+
Bar.class_eval do
|
150
|
+
def bar
|
151
|
+
'new bar'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
# no change
|
155
|
+
f.bar.should == 'bar less'
|
156
|
+
f.bar_without_less.should == 'bar'
|
157
|
+
f.bar_with_less.should == 'bar less'
|
158
|
+
Foo.class_eval do
|
159
|
+
def baz_with_less
|
160
|
+
raise
|
161
|
+
end
|
162
|
+
end
|
163
|
+
# no error
|
164
|
+
f.baz_without_less.should == 'baz'
|
165
|
+
f.baz_with_less.should == 'baz less'
|
166
|
+
f.baz.should == 'baz less'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
require 'investigation/self_decorating'
|
4
|
+
|
5
|
+
module DecoratingSubclassSpec # namespacing
|
6
|
+
|
7
|
+
describe "Decorating by extending object eigenclass" do
|
8
|
+
|
9
|
+
module Other
|
10
|
+
|
11
|
+
def dingo
|
12
|
+
super
|
13
|
+
end
|
14
|
+
# super fails in dingo_without_other (see above)
|
15
|
+
alias_method :dingo_without_other, :dingo
|
16
|
+
|
17
|
+
def dingo
|
18
|
+
super + " other"
|
19
|
+
end
|
20
|
+
|
21
|
+
def bat
|
22
|
+
'bat'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class SuperClass
|
27
|
+
def dingo
|
28
|
+
'dingo'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def reload_bar
|
33
|
+
Object.send(:remove_const, :Bar) if Object.const_defined?(:Bar)
|
34
|
+
instance_eval <<EOS
|
35
|
+
module ::Bar
|
36
|
+
def bar
|
37
|
+
'modular bar'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
EOS
|
41
|
+
end
|
42
|
+
|
43
|
+
class SubClass < SuperClass; end
|
44
|
+
|
45
|
+
before(:each) do
|
46
|
+
reload_bar
|
47
|
+
end
|
48
|
+
|
49
|
+
after(:all) do
|
50
|
+
Object.__send__(:remove_const, :Bar)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should extend Foo::Secret" do
|
54
|
+
f = SelfDecorating.new
|
55
|
+
f.foo.should == 'foo'
|
56
|
+
end
|
57
|
+
|
58
|
+
context "with a new SelfDecorating" do
|
59
|
+
|
60
|
+
before(:each) do
|
61
|
+
load('investigation/self_decorating.rb')
|
62
|
+
end
|
63
|
+
|
64
|
+
after(:each) do
|
65
|
+
Object.send(:remove_const, :SelfDecorating)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be able to decorate methods in base after they are defined" do
|
69
|
+
SelfDecorating.send(:define_method, :bar) { 'bar' }
|
70
|
+
SelfDecorating.decorate :bar
|
71
|
+
f = SelfDecorating.new
|
72
|
+
f.bar.should == 'bar with secret'
|
73
|
+
f.bar_without_secret.should == 'bar'
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should be able to decorate methods in Secret before they are defined" do
|
77
|
+
SelfDecorating.decorate :bar
|
78
|
+
SelfDecorating.send(:define_method, :bar) { 'bar' }
|
79
|
+
f = SelfDecorating.new
|
80
|
+
f.bar.should == 'bar with secret'
|
81
|
+
f.bar_without_secret.should == 'bar'
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should not interfere with overrides in superclasses" do
|
85
|
+
SelfDecorating.class_eval { include Bar }
|
86
|
+
SelfDecorating.decorate :bar
|
87
|
+
f = SelfDecorating.new
|
88
|
+
f.bar.should == 'modular bar with secret'
|
89
|
+
f.bar_without_secret.should == 'modular bar'
|
90
|
+
Bar.class_eval { def bar; 'new bar'; end }
|
91
|
+
f.bar_without_secret.should == 'new bar'
|
92
|
+
f.bar.should == 'new bar with secret'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should not interfere with overrides in the base class" do
|
96
|
+
SelfDecorating.class_eval do
|
97
|
+
include Bar
|
98
|
+
def bar
|
99
|
+
"locally " + super
|
100
|
+
end
|
101
|
+
end
|
102
|
+
SelfDecorating.decorate :bar
|
103
|
+
f = SelfDecorating.new
|
104
|
+
f.bar.should == 'locally modular bar with secret'
|
105
|
+
f.bar_without_secret.should == 'locally modular bar'
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should test overriding superclass methods in a module" do
|
111
|
+
s = SubClass.new
|
112
|
+
s.dingo.should == 'dingo'
|
113
|
+
SubClass.send(:include, Other)
|
114
|
+
s.dingo.should == 'dingo other'
|
115
|
+
# 1.8 bug - aliased method that calls super in a module
|
116
|
+
# http://redmine.ruby-lang.org/issues/show/734
|
117
|
+
lambda { s.dingo_without_other }.should raise_error(NoMethodError)
|
118
|
+
s.bat.should == 'bat'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
module InsertingSuperClassSpec # namespacing
|
4
|
+
|
5
|
+
describe "insert superclass" do
|
6
|
+
|
7
|
+
module Decorator
|
8
|
+
def decorate(*methods)
|
9
|
+
methods.each do |m|
|
10
|
+
alias_method "#{m}_without_decoration", m
|
11
|
+
define_method(m) do |*args,&block|
|
12
|
+
super + " decorated"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def reload_foo
|
19
|
+
[:Bar, :Foo, :SubFoo].each { |c| Object.send(:remove_const, c) if Object.const_defined?(c) }
|
20
|
+
instance_eval <<EOS
|
21
|
+
module ::Bar
|
22
|
+
def second; 'bar second'; end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Baz
|
26
|
+
def super_method
|
27
|
+
'super'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class ::Foo
|
32
|
+
extend Decorator
|
33
|
+
include Bar
|
34
|
+
include Baz
|
35
|
+
module DecorateMe
|
36
|
+
def first; 'first'; end
|
37
|
+
def second; super + ' overridden'; end
|
38
|
+
def third; 'third'; end
|
39
|
+
end
|
40
|
+
include DecorateMe
|
41
|
+
|
42
|
+
def local
|
43
|
+
'local'
|
44
|
+
end
|
45
|
+
|
46
|
+
decorate :first, :second, :third, :super_method, :local
|
47
|
+
|
48
|
+
def third
|
49
|
+
'broken'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class ::SubFoo < Foo
|
54
|
+
def first
|
55
|
+
'sub ' + super
|
56
|
+
end
|
57
|
+
def first_without_decoration
|
58
|
+
'sub ' + super
|
59
|
+
end
|
60
|
+
def second
|
61
|
+
'sub ' + super
|
62
|
+
end
|
63
|
+
def second_without_decoration
|
64
|
+
'sub ' + super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
EOS
|
68
|
+
end
|
69
|
+
|
70
|
+
before(:each) do
|
71
|
+
reload_foo
|
72
|
+
end
|
73
|
+
|
74
|
+
after(:all) do
|
75
|
+
Object.__send__(:remove_const, :Bar)
|
76
|
+
Object.__send__(:remove_const, :Foo)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should decorate the declared methods" do
|
80
|
+
f = Foo.new
|
81
|
+
f.first.should == "first decorated"
|
82
|
+
f.first_without_decoration.should == "first"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should decorate superclass methods not declared in DecorateMe" do
|
86
|
+
# the same case as the DecorateMe module
|
87
|
+
f = Foo.new
|
88
|
+
f.super_method.should == "super decorated"
|
89
|
+
f.super_method_without_decoration.should == "super"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should not interfere with overrides of superclass methods in DecorateMe" do
|
93
|
+
f = Foo.new
|
94
|
+
f.second.should == "bar second overridden decorated"
|
95
|
+
f.second_without_decoration.should == "bar second overridden"
|
96
|
+
end
|
97
|
+
|
98
|
+
it "has the issue that it raises errors attempting to decorate methods defined only in the base class" do
|
99
|
+
f = Foo.new
|
100
|
+
lambda { f.local }.should raise_error(NoMethodError) # not .should == 'local decorated'
|
101
|
+
f.local_without_decoration.should.should == 'local'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "has the issue that overrides in base class override decoration" do
|
105
|
+
f = Foo.new
|
106
|
+
f.third.should == 'broken' # not 'broken decorated'
|
107
|
+
f.third_without_decoration.should == 'third'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should not interfere with external overrides of superclasses methods" do
|
111
|
+
Bar.class_eval { def second; 'external'; end }
|
112
|
+
f = Foo.new
|
113
|
+
f.second.should == 'external overridden decorated'
|
114
|
+
f.second_without_decoration.should == 'external overridden'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should allow subclasses to override decoration" do
|
118
|
+
f = SubFoo.new
|
119
|
+
f.first.should == 'sub first decorated'
|
120
|
+
f.second.should == 'sub bar second overridden decorated'
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should allow subclasses to override methods without decoration" do
|
124
|
+
f = SubFoo.new
|
125
|
+
f.first_without_decoration.should == 'sub first'
|
126
|
+
f.second_without_decoration.should == 'sub bar second overridden'
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|