rom-session 0.1.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 (53) hide show
  1. data/.gitignore +9 -0
  2. data/.rspec +2 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +22 -0
  6. data/Gemfile +30 -0
  7. data/Gemfile.devtools +55 -0
  8. data/Guardfile +19 -0
  9. data/LICENSE +20 -0
  10. data/README.md +21 -0
  11. data/Rakefile +4 -0
  12. data/config/devtools.yml +2 -0
  13. data/config/flay.yml +3 -0
  14. data/config/flog.yml +2 -0
  15. data/config/mutant.yml +3 -0
  16. data/config/reek.yml +96 -0
  17. data/config/rubocop.yml +45 -0
  18. data/lib/rom-session.rb +43 -0
  19. data/lib/rom/session.rb +62 -0
  20. data/lib/rom/session/environment.rb +66 -0
  21. data/lib/rom/session/identity_map.rb +43 -0
  22. data/lib/rom/session/mapper.rb +43 -0
  23. data/lib/rom/session/relation.rb +126 -0
  24. data/lib/rom/session/state.rb +50 -0
  25. data/lib/rom/session/state/created.rb +22 -0
  26. data/lib/rom/session/state/deleted.rb +25 -0
  27. data/lib/rom/session/state/persisted.rb +29 -0
  28. data/lib/rom/session/state/transient.rb +20 -0
  29. data/lib/rom/session/state/updated.rb +29 -0
  30. data/lib/rom/session/tracker.rb +69 -0
  31. data/lib/rom/session/version.rb +9 -0
  32. data/lib/rom/support/proxy.rb +50 -0
  33. data/rom-session.gemspec +24 -0
  34. data/spec/integration/session_spec.rb +71 -0
  35. data/spec/rcov.opts +7 -0
  36. data/spec/shared/unit/environment_context.rb +11 -0
  37. data/spec/shared/unit/relation_context.rb +18 -0
  38. data/spec/spec_helper.rb +70 -0
  39. data/spec/unit/rom/session/class_methods/start_spec.rb +23 -0
  40. data/spec/unit/rom/session/clean_predicate_spec.rb +21 -0
  41. data/spec/unit/rom/session/environment/element_reader_spec.rb +13 -0
  42. data/spec/unit/rom/session/flush_spec.rb +58 -0
  43. data/spec/unit/rom/session/mapper/load_spec.rb +44 -0
  44. data/spec/unit/rom/session/relation/delete_spec.rb +28 -0
  45. data/spec/unit/rom/session/relation/dirty_predicate_spec.rb +38 -0
  46. data/spec/unit/rom/session/relation/identity_spec.rb +11 -0
  47. data/spec/unit/rom/session/relation/new_spec.rb +50 -0
  48. data/spec/unit/rom/session/relation/save_spec.rb +50 -0
  49. data/spec/unit/rom/session/relation/state_spec.rb +26 -0
  50. data/spec/unit/rom/session/relation/track_spec.rb +23 -0
  51. data/spec/unit/rom/session/relation/tracking_predicate_spec.rb +23 -0
  52. data/spec/unit/rom/session/state_spec.rb +79 -0
  53. metadata +167 -0
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Mapper, '#load' do
6
+ subject { object.load(tuple) }
7
+
8
+ let(:object) { described_class.new(mapper, tracker, im) }
9
+
10
+ let(:mapper) { fake(:mapper) { ROM::Mapper } }
11
+
12
+ let(:tuple) { Hash[id: 1, name: 'Jane'] }
13
+ let(:user) { model.new(tuple) }
14
+ let(:model) { mock_model(:id, :name) }
15
+ let(:im) { Session::IdentityMap.build }
16
+ let(:tracker) { Session::Tracker.new }
17
+
18
+ before do
19
+ stub(mapper).identity_from_tuple(tuple) { 1 }
20
+ end
21
+
22
+ context 'when IM does not include the loaded object' do
23
+ it 'loads the object' do
24
+ stub(mapper).load(tuple) { user }
25
+ expect(subject).to be(user)
26
+ mapper.should have_received.load(tuple)
27
+ end
28
+
29
+ it 'stores persisted state in the tracker' do
30
+ expect(tracker.fetch(subject)).to be_persisted
31
+ end
32
+ end
33
+
34
+ context 'when IM includes the loaded object' do
35
+ before do
36
+ im.store(1, user, tuple)
37
+ end
38
+
39
+ it 'returns already loaded object' do
40
+ expect(subject).to be(user)
41
+ mapper.should_not have_received.load(tuple)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#delete' do
6
+ subject { users.delete(user) }
7
+
8
+ include_context 'Session::Relation'
9
+
10
+ let(:state) { subject.state(user) }
11
+
12
+ context 'with a persisted object' do
13
+ it_behaves_like 'a command method'
14
+
15
+ specify { expect(state).to be_deleted }
16
+ end
17
+
18
+ context 'with a transient object' do
19
+ let(:user) { users.new }
20
+
21
+ specify do
22
+ expect { subject }.to raise_error(
23
+ Session::State::TransitionError,
24
+ 'cannot delete object with ROM::Session::State::Transient state'
25
+ )
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#dirty?' do
6
+ subject { users.dirty?(user) }
7
+
8
+ include_context 'Session::Relation'
9
+
10
+ context 'with a transient object' do
11
+ let(:user) { users.new }
12
+
13
+ it { should be(true) }
14
+ end
15
+
16
+ context 'when persisted object was changed' do
17
+ before do
18
+ user.name = 'John Doe'
19
+ end
20
+
21
+ it { should be(true) }
22
+ end
23
+
24
+ context 'when persisted object was not changed' do
25
+ it { should be(false) }
26
+ end
27
+
28
+ context 'when object is not tracked' do
29
+ let(:user) { model.new(id: 3, name: 'Unknown') }
30
+
31
+ specify do
32
+ expect { subject }.to raise_error(
33
+ Session::ObjectNotTrackedError,
34
+ "Tracker doesn't include #{user.inspect}"
35
+ )
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#save' do
6
+ subject { object.identity(user) }
7
+
8
+ include_context 'Session::Relation'
9
+
10
+ it { should eq([user.id]) }
11
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#new' do
6
+ share_examples_for 'a new tracked object' do
7
+ it { should be_instance_of(model) }
8
+
9
+ it 'sets state to transient' do
10
+ expect(object.state(subject)).to be_transient
11
+ end
12
+
13
+ it 'auto-tracks the new object' do
14
+ expect(object.tracking?(subject)).to be_true
15
+ end
16
+ end
17
+
18
+ include_context 'Session::Relation'
19
+
20
+ let(:attributes) { Hash[id: 1, name: 'Jane'] }
21
+
22
+ context 'with attributes' do
23
+ subject { users.new(attributes) }
24
+
25
+ it { should eq(model.new(attributes)) }
26
+
27
+ it_behaves_like 'a new tracked object'
28
+ end
29
+
30
+ context 'with attributes and block' do
31
+ subject { users.new(attributes, &block) }
32
+
33
+ let(:model) {
34
+ Class.new {
35
+ attr_reader :attributes
36
+
37
+ def initialize(attributes, &block)
38
+ @attributes = attributes
39
+ yield(attributes)
40
+ end
41
+ }
42
+ }
43
+
44
+ let(:block) { proc { |attributes| attributes[:test] = true } }
45
+
46
+ its(:attributes) { should eq(attributes.merge(test: true)) }
47
+
48
+ it_behaves_like 'a new tracked object'
49
+ end
50
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#save' do
6
+ subject { object.save(user) }
7
+
8
+ include_context 'Session::Relation'
9
+
10
+ let(:state) { subject.state(user) }
11
+
12
+ context 'when an object is transient' do
13
+ let(:user) { users.new(id: 3, name: 'John') }
14
+
15
+ it_behaves_like 'a command method'
16
+
17
+ specify { state.should be_created }
18
+ end
19
+
20
+ context 'when an object is persisted' do
21
+ context 'when not dirty' do
22
+ it_behaves_like 'a command method'
23
+
24
+ specify { state.should be_persisted }
25
+ end
26
+
27
+ context 'when dirty' do
28
+ before do
29
+ user.name = 'John Doe'
30
+ end
31
+
32
+ it_behaves_like 'a command method'
33
+
34
+ specify { state.should be_updated }
35
+ end
36
+ end
37
+
38
+ context 'when an object is deleted' do
39
+ before do
40
+ object.delete(user)
41
+ end
42
+
43
+ specify do
44
+ expect { subject }.to raise_error(
45
+ Session::State::TransitionError,
46
+ 'cannot save object with ROM::Session::State::Deleted state'
47
+ )
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#state' do
6
+ subject { users.state(user) }
7
+
8
+ include_context 'Session::Relation'
9
+
10
+ context 'when object is tracked' do
11
+ it { should be_kind_of(Session::State) }
12
+
13
+ its(:object) { should be(user) }
14
+ end
15
+
16
+ context 'when object is not tracked' do
17
+ let(:user) { model.new }
18
+
19
+ specify do
20
+ expect { subject }.to raise_error(
21
+ Session::ObjectNotTrackedError,
22
+ "Tracker doesn't include #{user.inspect}"
23
+ )
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#track' do
6
+ subject { users.track(user) }
7
+
8
+ include_context 'Session::Relation'
9
+
10
+ let(:user) { model.new(id: 3, name: 'John') }
11
+
12
+ before do
13
+ users.track(user)
14
+ end
15
+
16
+ it_behaves_like 'a command method'
17
+
18
+ it { should be(subject) }
19
+
20
+ it 'starts tracking the object' do
21
+ expect(users.tracking?(user)).to be_true
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::Relation, '#tracking?' do
6
+ subject { users.tracking?(user) }
7
+
8
+ include_context 'Session::Relation'
9
+
10
+ let(:user) { model.new(id: 3, name: 'John') }
11
+
12
+ context 'when the object is being tracked' do
13
+ before do
14
+ users.track(user)
15
+ end
16
+
17
+ it { should be(true) }
18
+ end
19
+
20
+ context 'when the object is not being tracked' do
21
+ it { should be(false) }
22
+ end
23
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Session::State do
6
+ fake(:object)
7
+ fake(:mapper)
8
+ fake(:relation)
9
+
10
+ describe '#transient?' do
11
+ context 'with transient state' do
12
+ subject { Session::State::Transient.new(object, mapper) }
13
+
14
+ it { should be_transient }
15
+ end
16
+
17
+ context 'with a non-transient state' do
18
+ subject { Session::State::Persisted.new(object, mapper) }
19
+
20
+ it { should_not be_transient }
21
+ end
22
+ end
23
+
24
+ describe '#persisted?' do
25
+ context 'with a persisted state' do
26
+ subject { Session::State::Persisted.new(object, mapper) }
27
+
28
+ it { should be_persisted }
29
+ end
30
+
31
+ context 'with a non-persisted state' do
32
+ subject { Session::State::Transient.new(object, mapper) }
33
+
34
+ it { should_not be_persisted }
35
+ end
36
+ end
37
+
38
+ describe '#created?' do
39
+ context 'with a created state' do
40
+ subject { Session::State::Created.new(object, mapper, relation) }
41
+
42
+ it { should be_created }
43
+ end
44
+
45
+ context 'with a non-created state' do
46
+ subject { Session::State::Transient.new(object, mapper) }
47
+
48
+ it { should_not be_created }
49
+ end
50
+ end
51
+
52
+ describe '#updated?' do
53
+ context 'with an updated state' do
54
+ subject { Session::State::Updated.new(object, [], relation) }
55
+
56
+ it { should be_updated }
57
+ end
58
+
59
+ context 'with a non-updated state' do
60
+ subject { Session::State::Transient.new(object, mapper) }
61
+
62
+ it { should_not be_updated }
63
+ end
64
+ end
65
+
66
+ describe '#deleted?' do
67
+ context 'with a deleted state' do
68
+ subject { Session::State::Deleted.new(object, relation) }
69
+
70
+ it { should be_deleted }
71
+ end
72
+
73
+ context 'with a non-updated state' do
74
+ subject { Session::State::Transient.new(object, mapper) }
75
+
76
+ it { should_not be_deleted }
77
+ end
78
+ end
79
+ end
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rom-session
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Markus Schirp
9
+ - Piotr Solnica
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-08-23 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: adamantium
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '0.1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '0.1'
31
+ - !ruby/object:Gem::Dependency
32
+ name: equalizer
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 0.0.7
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 0.0.7
47
+ - !ruby/object:Gem::Dependency
48
+ name: abstract_type
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.6
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 0.0.6
63
+ - !ruby/object:Gem::Dependency
64
+ name: concord
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: 0.1.4
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 0.1.4
79
+ description: Session for ROM
80
+ email:
81
+ - mbj@schirp-dso.com
82
+ - piotr.solnica@gmail.com
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files:
86
+ - README.md
87
+ - LICENSE
88
+ files:
89
+ - .gitignore
90
+ - .rspec
91
+ - .ruby-gemset
92
+ - .ruby-version
93
+ - .travis.yml
94
+ - Gemfile
95
+ - Gemfile.devtools
96
+ - Guardfile
97
+ - LICENSE
98
+ - README.md
99
+ - Rakefile
100
+ - config/devtools.yml
101
+ - config/flay.yml
102
+ - config/flog.yml
103
+ - config/mutant.yml
104
+ - config/reek.yml
105
+ - config/rubocop.yml
106
+ - lib/rom-session.rb
107
+ - lib/rom/session.rb
108
+ - lib/rom/session/environment.rb
109
+ - lib/rom/session/identity_map.rb
110
+ - lib/rom/session/mapper.rb
111
+ - lib/rom/session/relation.rb
112
+ - lib/rom/session/state.rb
113
+ - lib/rom/session/state/created.rb
114
+ - lib/rom/session/state/deleted.rb
115
+ - lib/rom/session/state/persisted.rb
116
+ - lib/rom/session/state/transient.rb
117
+ - lib/rom/session/state/updated.rb
118
+ - lib/rom/session/tracker.rb
119
+ - lib/rom/session/version.rb
120
+ - lib/rom/support/proxy.rb
121
+ - rom-session.gemspec
122
+ - spec/integration/session_spec.rb
123
+ - spec/rcov.opts
124
+ - spec/shared/unit/environment_context.rb
125
+ - spec/shared/unit/relation_context.rb
126
+ - spec/spec_helper.rb
127
+ - spec/unit/rom/session/class_methods/start_spec.rb
128
+ - spec/unit/rom/session/clean_predicate_spec.rb
129
+ - spec/unit/rom/session/environment/element_reader_spec.rb
130
+ - spec/unit/rom/session/flush_spec.rb
131
+ - spec/unit/rom/session/mapper/load_spec.rb
132
+ - spec/unit/rom/session/relation/delete_spec.rb
133
+ - spec/unit/rom/session/relation/dirty_predicate_spec.rb
134
+ - spec/unit/rom/session/relation/identity_spec.rb
135
+ - spec/unit/rom/session/relation/new_spec.rb
136
+ - spec/unit/rom/session/relation/save_spec.rb
137
+ - spec/unit/rom/session/relation/state_spec.rb
138
+ - spec/unit/rom/session/relation/track_spec.rb
139
+ - spec/unit/rom/session/relation/tracking_predicate_spec.rb
140
+ - spec/unit/rom/session/state_spec.rb
141
+ homepage: http://rom-rb.org
142
+ licenses:
143
+ - MIT
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ none: false
150
+ requirements:
151
+ - - ! '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubyforge_project:
162
+ rubygems_version: 1.8.23
163
+ signing_key:
164
+ specification_version: 3
165
+ summary: Session for ROM
166
+ test_files: []
167
+ has_rdoc: