graph_mediator 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|