gexp 0.0.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.
Files changed (42) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +1 -0
  6. data/gexp.gemspec +32 -0
  7. data/lib/gexp.rb +16 -0
  8. data/lib/gexp/command.rb +50 -0
  9. data/lib/gexp/command/object.rb +37 -0
  10. data/lib/gexp/command/stack.rb +50 -0
  11. data/lib/gexp/handler.rb +25 -0
  12. data/lib/gexp/handler/caller.rb +8 -0
  13. data/lib/gexp/handler/check.rb +9 -0
  14. data/lib/gexp/handler/check/item.rb +34 -0
  15. data/lib/gexp/handler/check/resources.rb +56 -0
  16. data/lib/gexp/handler/modify.rb +9 -0
  17. data/lib/gexp/handler/modify/resources.rb +81 -0
  18. data/lib/gexp/handler/producer.rb +61 -0
  19. data/lib/gexp/handler/transition.rb +44 -0
  20. data/lib/gexp/handler/transition/builder.rb +33 -0
  21. data/lib/gexp/mongoid.rb +4 -0
  22. data/lib/gexp/mongoid/transaction.rb +266 -0
  23. data/lib/gexp/object.rb +39 -0
  24. data/lib/gexp/receiver.rb +33 -0
  25. data/lib/gexp/state_definition.rb +4 -0
  26. data/lib/gexp/state_definition/state_machine.rb +90 -0
  27. data/lib/gexp/version.rb +3 -0
  28. data/spec/gexp/command/object_spec.rb +84 -0
  29. data/spec/gexp/command/stack_spec.rb +74 -0
  30. data/spec/gexp/command_spec.rb +59 -0
  31. data/spec/gexp/handler/check/item_spec.rb +45 -0
  32. data/spec/gexp/handler/check/resources_spec.rb +81 -0
  33. data/spec/gexp/handler/check_spec.rb +5 -0
  34. data/spec/gexp/handler/modify/resources_spec.rb +96 -0
  35. data/spec/gexp/handler/modify_spec.rb +6 -0
  36. data/spec/gexp/handler/producer_spec.rb +85 -0
  37. data/spec/gexp/handler/transition/builder_spec.rb +122 -0
  38. data/spec/gexp/handler/transition_spec.rb +14 -0
  39. data/spec/gexp/mongoid/transaction_spec.rb +210 -0
  40. data/spec/gexp/state_definition/state_machine_spec.rb +48 -0
  41. data/spec/spec_helper.rb +10 -0
  42. metadata +210 -0
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb')
3
+
4
+ describe Gexp::Handler::Check do
5
+ end
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper.rb')
3
+
4
+ describe Gexp::Handler::Modify::Resources do
5
+
6
+ before do
7
+ @user = User.new
8
+ @object = Item.new
9
+
10
+ subject.user = @user
11
+ subject.object = @object
12
+ end
13
+
14
+ context "#normilize" do
15
+
16
+ it "с положительным параметром" do
17
+ value = 100500
18
+ subject.normalize(:undefined, value).should == value
19
+ end
20
+
21
+ it "с отрицательным параметром" do
22
+ value = -3
23
+ subject.normalize(:undefined, value).should be_zero
24
+ end
25
+
26
+ end
27
+
28
+ context "#normalize_energy" do
29
+
30
+ before { @max_energy = 20 }
31
+
32
+ it "с отрицательным значением" do
33
+ value = -1
34
+ subject.normalize(:energy, value).should be_zero
35
+ end
36
+
37
+ context "Если не привышаем лимит" do
38
+ before { stub(@user).max_energy.once { @max_energy } }
39
+
40
+ it "с нормальным значением" do
41
+ value = @max_energy / 2
42
+ subject.normalize(:energy, value).should == value
43
+ end
44
+
45
+ it "с максимальным значением" do
46
+ value = @max_energy
47
+ subject.normalize(:energy, value).should == value
48
+ end
49
+
50
+ end
51
+
52
+ it "со сверх большим значением" do
53
+ stub(@user).max_energy.twice { @max_energy }
54
+ value = @max_energy + 1
55
+ subject.normalize(:energy, value).should == @max_energy
56
+ end
57
+
58
+ end
59
+
60
+ context "Изменение ресурсов" do
61
+
62
+ it "Энергия должна быть начисленна" do
63
+ @user.energy = 5
64
+ subject.process({ energy: 5 })
65
+ @user.energy.should == 10
66
+ end
67
+
68
+ it "Энергия должна списываться" do
69
+ @user.energy = 10
70
+ subject.process({ energy: -5 })
71
+ @user.energy.should == 5
72
+ end
73
+
74
+ it "Энергия должна списываться, а экспа начисляться" do
75
+ @user.energy = 10
76
+ @user.exp = 10
77
+ subject.process({ energy: -5, exp: 5 })
78
+ @user.energy.should == 5
79
+ @user.exp.should == 15
80
+ end
81
+
82
+ it "Если ресурса не хватает, полностью прерываем транзакцию" do
83
+ @user.energy = 10
84
+ @user.exp = 10
85
+
86
+ lambda {
87
+ subject.process({ exp: 5, energy: -11 })
88
+ }.should raise_error /out_of_resource\-energy/
89
+
90
+ @user.energy.should == 10
91
+ @user.exp.should == 10
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb')
3
+
4
+ describe Gexp::Handler::Modify do
5
+
6
+ end
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb')
3
+
4
+ describe Gexp::Handler::Producer do
5
+
6
+ let(:objects) do
7
+ {
8
+ object: Object.new,
9
+ provider: Object.new,
10
+ subject: Object.new,
11
+ }
12
+ end
13
+
14
+ let(:emiter) do
15
+ emiter = Gexp::Handler::Producer.new \
16
+ params,
17
+ type,
18
+ objects
19
+ end
20
+
21
+ let(:handler) do
22
+ handler = emiter.emit
23
+ end
24
+
25
+ before do
26
+ emited_class.class.should be_a_kind_of Class
27
+ end
28
+
29
+ context "Caller" do
30
+
31
+ let(:params) do
32
+ [ :object, [ :arg1, :arg2, :arg3 ] ]
33
+ end
34
+
35
+ let(:emited_class) do
36
+ Gexp::Handler::Caller
37
+ end
38
+
39
+ let(:type) do
40
+ end
41
+
42
+ it "build caller for self" do
43
+ handler.should be_a_kind_of emited_class
44
+ end
45
+
46
+ end
47
+
48
+ context "Other Handler" do
49
+
50
+ let(:params) do
51
+ [ :other, :object, { param: :value, other_param: :over_value } ]
52
+ end
53
+
54
+ let(:emited_class) do
55
+ Gexp::Handler.const_get(handler_class).const_set :Other, (Class.new do
56
+ def initialize(*args)
57
+ end
58
+ end)
59
+ end
60
+
61
+ context "Checker" do
62
+
63
+ let(:handler_class) { :Check }
64
+ let(:type) { :chekers }
65
+
66
+ it "build caller for self" do
67
+ handler.should be_a_kind_of emited_class
68
+ end
69
+
70
+ end
71
+
72
+ context "Modifier" do
73
+
74
+ let(:handler_class) { :Modify }
75
+ let(:type) { :modifiers }
76
+
77
+ it "build caller for self" do
78
+ handler.should be_a_kind_of emited_class
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,122 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper.rb')
3
+
4
+ describe Gexp::Handler::Transition::Builder do
5
+
6
+ shared_examples_for Gexp::Handler::Transition::Builder do
7
+
8
+ # let(:to) { to }
9
+
10
+ # let(:from) { from }
11
+
12
+ # let(:event) { event }
13
+
14
+ let(:transition) do
15
+ transition = Object.new
16
+ stub(transition).to_name { to }
17
+ stub(transition).from_name { from }
18
+ stub(transition).event { event }
19
+
20
+ transition
21
+ end
22
+
23
+ # let(:config) do
24
+ # config
25
+ # end
26
+
27
+ # let(:result_chekers) do
28
+ # result_chekers
29
+ # end
30
+
31
+ # let(:result_modifiers) do
32
+ # result_modifiers
33
+ # end
34
+
35
+ let(:object_param) do
36
+ object = Object.new
37
+ stub(object).config { config }
38
+ object
39
+ end
40
+
41
+ let(:subject) do
42
+ Gexp::Handler::Transition::Builder.new \
43
+ transition,
44
+ object_param,
45
+ subject_param,
46
+ provider_param
47
+ end
48
+
49
+ it "should must be given result checkers" do
50
+ subject.checkers.should == result_chekers
51
+ end
52
+
53
+ it "should must be given result modifiers" do
54
+ subject.modifiers.should == result_modifiers
55
+ end
56
+
57
+ end
58
+
59
+ context "Define handler example" do
60
+
61
+ it_behaves_like Gexp::Handler::Transition::Builder do
62
+ let(:to) { :prebuilded }
63
+ let(:from) { :created }
64
+ let(:event) { :place }
65
+ let(:config) do
66
+ {
67
+ events: {
68
+ place: {
69
+ check: [
70
+ [ :resources, :object, { wood: 5, energy: 1 } ],
71
+ [ :object, [ :place_allowed?, :not_blocked? ] ],
72
+ ],
73
+ modify: [
74
+ [ :object, [ :change_tile_type! ] ]
75
+ ]
76
+ },
77
+ sell: {
78
+ check: [
79
+ [ :object, [ :has_current_user? ] ]
80
+ ]
81
+ }
82
+ },
83
+ transitions: {
84
+ created: {
85
+ selled: { },
86
+ prebuilded: {
87
+ check: [
88
+ [ :shared_resources, :object, { 0 => 5 } ]
89
+ ],
90
+ modify: [
91
+ [ :shared_resources, :object, { 0 => 5 } ],
92
+ [ :resources, :object, { wood: -5, energy: -1 } ],
93
+ [ :shared_resources, :object, { 0 => -5 } ]
94
+ ]
95
+ }
96
+ }
97
+ }
98
+ }
99
+ end
100
+
101
+ let(:result_chekers) {
102
+ [
103
+ [ :resources, :object, { wood: 5, energy: 1 } ],
104
+ [ :object, [ :place_allowed?, :not_blocked? ] ],
105
+ [ :shared_resources, :object, { 0 => 5 } ],
106
+ ]
107
+ }
108
+ let(:result_modifiers) {
109
+ [
110
+ [ :object, [ :change_tile_type! ] ],
111
+ [ :shared_resources, :object, { 0 => 5 } ],
112
+ [ :resources, :object, { wood: -5, energy: -1 } ],
113
+ [ :shared_resources, :object, { 0 => -5 } ]
114
+ ]
115
+ }
116
+ let(:subject_param) { Object.new }
117
+ let(:provider_param) { Object.new }
118
+
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb')
3
+
4
+ describe Gexp::Handler::Transition do
5
+
6
+ shared_examples_for "construct handler" do
7
+
8
+ let(:object) { Object.new }
9
+ let(:subject) { Object.new }
10
+ let(:provider) {}
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,210 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb')
3
+
4
+ describe Gexp::Mongoid::Transaction do
5
+
6
+ context "Transactional Object" do
7
+
8
+ before do
9
+
10
+ class Foo < Gexp::Mongoid::Transaction::Base
11
+ field :name, type: String
12
+ field :quantity, type: Integer
13
+ end
14
+
15
+ class Baz < Gexp::Mongoid::Transaction::Base
16
+ field :name, type: String
17
+ field :quantity, type: Integer
18
+ end
19
+
20
+ @foo = Foo.create(name: 'foo', quantity: 0)
21
+
22
+ end
23
+
24
+ it "Проверка полей Foo#*" # TODO: нужены mongoid-rspec матчеры
25
+
26
+ context "Жизненный цикл транзакции" do
27
+
28
+ def inner_assets_for(foo, transaction)
29
+ foo.name = 'new_foo'
30
+ foo.name.should == 'new_foo'
31
+ foo._updated['name'].should == 'new_foo'
32
+ foo.attributes['name'].should == 'foo'
33
+ foo.transaction.should == transaction
34
+ foo._version.should be_zero
35
+
36
+ foo.should be_dirty_uncommited
37
+ foo.save
38
+ end
39
+
40
+ def outer_assets_for(foo)
41
+ foo.reload
42
+ foo.name.should == 'new_foo'
43
+ foo._transaction_id.should be_nil
44
+ foo._updated.should be_nil
45
+ foo._version.should_not be_zero
46
+ foo.should be_clear
47
+ end
48
+
49
+
50
+ it "Изменения без транзакции" do
51
+ @foo.reload
52
+ @foo.name = 'new_foo'
53
+ @foo.name.should == 'new_foo'
54
+ @foo._updated.should be_nil
55
+ @foo.transaction.should be_nil
56
+ @foo.save
57
+ @foo.reload
58
+ @foo.name.should == 'new_foo'
59
+ end
60
+
61
+ it "Транзакция на внутреннем новом объекте" do
62
+ foo = nil
63
+
64
+ Gexp::Mongoid::Transaction.with do |context|
65
+ foo = Foo.create(name: 'foo', quantity: 0)
66
+ inner_assets_for foo, context.transaction
67
+ end
68
+
69
+ outer_assets_for foo
70
+ end
71
+
72
+ it "Транзакция на внутреннем загруженном объекте" do
73
+
74
+ exist = Foo.create(name: 'foo', quantity: 0)
75
+ foo = nil
76
+ Gexp::Mongoid::Transaction.with do |context|
77
+ foo = Foo.find(exist)
78
+ inner_assets_for foo, context.transaction
79
+ end
80
+
81
+ outer_assets_for foo
82
+ end
83
+
84
+ it "Транзакция на внешнем новом объекте" do
85
+ foo = Foo.create(name: 'foo', quantity: 0)
86
+ Gexp::Mongoid::Transaction.with do |context|
87
+ inner_assets_for foo, context.transaction
88
+ end
89
+
90
+ outer_assets_for foo
91
+ end
92
+
93
+ it "Транзакция на внешнем загруженном объекте" do
94
+ exist = Foo.create(name: 'foo', quantity: 0)
95
+ foo = Foo.create(name: 'foo', quantity: 0)
96
+
97
+ Gexp::Mongoid::Transaction.with(foo) do |context|
98
+ foo.transaction.should == context.transaction
99
+ context.transaction.objects.include?(foo).should == true
100
+ inner_assets_for foo, context.transaction
101
+ end
102
+
103
+ outer_assets_for foo
104
+ end
105
+
106
+ end
107
+
108
+ context "Проверка признаков объекта" do
109
+
110
+ it "Чистый объект" do
111
+ @foo.should be_clear
112
+ @foo.should_not be_dirty_commited
113
+ @foo.should_not be_dirty_uncommited
114
+ end
115
+
116
+ it "Грязный закомиченный объект" do
117
+ @foo.create_update
118
+ @foo._transaction_id = '12312312asd3123'
119
+
120
+ @foo.should_not be_clear
121
+ @foo.should be_dirty_commited
122
+ @foo.should_not be_dirty_uncommited
123
+ end
124
+
125
+ it "Грязный незакомиченынй объект" do
126
+ @foo.create_update
127
+ @foo.transaction = Gexp::Mongoid::Transaction::Instance.create
128
+ @foo.should_not be_clear
129
+ @foo.should_not be_dirty_commited
130
+ @foo.should be_dirty_uncommited
131
+
132
+ Gexp::Mongoid::Transaction::Observer.finish_transaction!
133
+ end
134
+
135
+ end
136
+
137
+ context "Загрузка и запись" do
138
+
139
+ before do
140
+ @foo = Foo.create(name: 'name', quantity: 0)
141
+ @baz = Baz.create(name: 'name', quantity: 0)
142
+ end
143
+
144
+ it "чистого объекта" do
145
+ loaded = Foo.find(@foo.id)
146
+ loaded.should be_clear
147
+ end
148
+
149
+ it "В нормальном режиме" do
150
+ Gexp::Mongoid::Transaction.with do |context|
151
+ foo = Foo.find(@foo.id)
152
+ foo.name = 'new_name_foo'
153
+
154
+ baz = Baz.find(@baz.id)
155
+ baz.name = 'new_name_baz'
156
+ end
157
+
158
+ @foo.reload
159
+ @foo.name.should == 'new_name_foo'
160
+ @foo._version.should_not be_zero
161
+ @foo.should be_clear
162
+
163
+ @baz.reload
164
+ @baz.name.should == 'new_name_baz'
165
+ @baz._version.should_not be_zero
166
+ @baz.should be_clear
167
+ end
168
+
169
+ it "грязного не закоммиченного объекта с проваленной транзакцией" do
170
+ obj = @foo
171
+ lambda {
172
+ Gexp::Mongoid::Transaction.with do |context|
173
+ obj.name = 'new_name'
174
+ obj.should be_dirty_uncommited
175
+ obj.save
176
+ obj.reload
177
+ obj.name.should == 'name'
178
+ raise 'Something wrong'
179
+ end
180
+ }.should raise_error /Something wrong/
181
+
182
+ loaded = Foo.find(obj.id)
183
+ loaded.should be_clear
184
+
185
+ loaded.name.should == 'name'
186
+ end
187
+
188
+ it "грязного не закоммиченного объекта при проваленом коммите транзакции" do
189
+ lambda {
190
+ Gexp::Mongoid::Transaction.with do |context|
191
+ stub(context).end_transaction { raise 'Something wrong' }
192
+ @foo.name = 'new_name'
193
+ @foo.save
194
+ end
195
+ }.should raise_error /Something wrong/
196
+
197
+ @foo.should be_dirty
198
+ @foo.should be_dirty_commited
199
+ #mock(@foo).clear_commited!.once
200
+ mock(@foo).clear_uncommited!.never
201
+ @foo.reload
202
+ @foo.name.should == 'new_name'
203
+ @foo.should be_clear
204
+ end
205
+
206
+ end
207
+
208
+ end
209
+
210
+ end