rom 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +81 -0
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile +12 -8
  6. data/Guardfile +17 -11
  7. data/README.md +7 -7
  8. data/Rakefile +29 -0
  9. data/lib/rom.rb +9 -66
  10. data/lib/rom/adapter.rb +45 -12
  11. data/lib/rom/adapter/memory.rb +0 -4
  12. data/lib/rom/adapter/memory/commands.rb +0 -10
  13. data/lib/rom/adapter/memory/dataset.rb +18 -6
  14. data/lib/rom/adapter/memory/storage.rb +0 -3
  15. data/lib/rom/command_registry.rb +24 -43
  16. data/lib/rom/commands.rb +5 -6
  17. data/lib/rom/commands/create.rb +5 -5
  18. data/lib/rom/commands/delete.rb +8 -6
  19. data/lib/rom/commands/result.rb +82 -0
  20. data/lib/rom/commands/update.rb +5 -4
  21. data/lib/rom/commands/with_options.rb +1 -4
  22. data/lib/rom/config.rb +70 -0
  23. data/lib/rom/env.rb +11 -3
  24. data/lib/rom/global.rb +107 -0
  25. data/lib/rom/header.rb +122 -89
  26. data/lib/rom/header/attribute.rb +148 -0
  27. data/lib/rom/mapper.rb +46 -67
  28. data/lib/rom/mapper_builder.rb +20 -73
  29. data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
  30. data/lib/rom/mapper_builder/model_dsl.rb +29 -0
  31. data/lib/rom/mapper_registry.rb +21 -0
  32. data/lib/rom/model_builder.rb +11 -17
  33. data/lib/rom/processor.rb +28 -0
  34. data/lib/rom/processor/transproc.rb +105 -0
  35. data/lib/rom/reader.rb +81 -21
  36. data/lib/rom/reader_builder.rb +14 -4
  37. data/lib/rom/relation.rb +19 -5
  38. data/lib/rom/relation_builder.rb +20 -6
  39. data/lib/rom/repository.rb +0 -2
  40. data/lib/rom/setup.rb +156 -0
  41. data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
  42. data/lib/rom/setup/command_dsl.rb +46 -0
  43. data/lib/rom/setup/finalize.rb +125 -0
  44. data/lib/rom/setup/mapper_dsl.rb +19 -0
  45. data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
  46. data/lib/rom/setup/schema_dsl.rb +33 -0
  47. data/lib/rom/support/registry.rb +10 -6
  48. data/lib/rom/version.rb +1 -1
  49. data/rom.gemspec +3 -1
  50. data/spec/integration/adapters/extending_relations_spec.rb +0 -2
  51. data/spec/integration/commands/create_spec.rb +2 -9
  52. data/spec/integration/commands/delete_spec.rb +4 -5
  53. data/spec/integration/commands/error_handling_spec.rb +4 -3
  54. data/spec/integration/commands/update_spec.rb +3 -8
  55. data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
  56. data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
  57. data/spec/integration/mappers/embedded_spec.rb +82 -0
  58. data/spec/integration/mappers/group_spec.rb +170 -0
  59. data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
  60. data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
  61. data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
  62. data/spec/integration/mappers/wrap_spec.rb +162 -0
  63. data/spec/integration/multi_repo_spec.rb +64 -0
  64. data/spec/integration/relations/reading_spec.rb +12 -8
  65. data/spec/integration/relations/registry_dsl_spec.rb +1 -3
  66. data/spec/integration/schema_spec.rb +10 -0
  67. data/spec/integration/setup_spec.rb +57 -6
  68. data/spec/spec_helper.rb +2 -1
  69. data/spec/unit/config_spec.rb +60 -0
  70. data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
  71. data/spec/unit/rom/adapter_spec.rb +31 -11
  72. data/spec/unit/rom/header_spec.rb +60 -16
  73. data/spec/unit/rom/mapper_builder_spec.rb +311 -0
  74. data/spec/unit/rom/mapper_registry_spec.rb +25 -0
  75. data/spec/unit/rom/mapper_spec.rb +4 -5
  76. data/spec/unit/rom/model_builder_spec.rb +15 -13
  77. data/spec/unit/rom/processor/transproc_spec.rb +331 -0
  78. data/spec/unit/rom/reader_spec.rb +73 -0
  79. data/spec/unit/rom/registry_spec.rb +38 -0
  80. data/spec/unit/rom/relation_spec.rb +0 -1
  81. data/spec/unit/rom/setup_spec.rb +55 -0
  82. data/spec/unit/rom_spec.rb +14 -0
  83. metadata +62 -22
  84. data/Gemfile.devtools +0 -71
  85. data/lib/rom/boot.rb +0 -197
  86. data/lib/rom/boot/command_dsl.rb +0 -48
  87. data/lib/rom/boot/dsl.rb +0 -37
  88. data/lib/rom/boot/mapper_dsl.rb +0 -23
  89. data/lib/rom/boot/schema_dsl.rb +0 -27
  90. data/lib/rom/ra.rb +0 -172
  91. data/lib/rom/ra/operation/group.rb +0 -47
  92. data/lib/rom/ra/operation/join.rb +0 -39
  93. data/lib/rom/ra/operation/wrap.rb +0 -45
  94. data/lib/rom/transformer.rb +0 -77
  95. data/spec/integration/ra/group_spec.rb +0 -46
  96. data/spec/integration/ra/join_spec.rb +0 -50
  97. data/spec/integration/ra/wrap_spec.rb +0 -37
  98. data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
  99. data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
  100. data/spec/unit/rom/transformer_spec.rb +0 -41
@@ -1,6 +1,5 @@
1
1
  module ROM
2
- class Boot
3
-
2
+ class Setup
4
3
  class RelationDSL
5
4
  attr_reader :schema, :relations
6
5
 
@@ -16,8 +15,6 @@ module ROM
16
15
  def call
17
16
  relations
18
17
  end
19
-
20
18
  end
21
-
22
19
  end
23
20
  end
@@ -0,0 +1,33 @@
1
+ require 'rom/setup/base_relation_dsl'
2
+
3
+ module ROM
4
+ class Setup
5
+ # @private
6
+ class SchemaDSL
7
+ attr_reader :env, :schema
8
+
9
+ # @api private
10
+ def initialize(env, schema, &block)
11
+ @env = env
12
+ @schema = schema
13
+ initialize_schema
14
+ instance_exec(&block)
15
+ end
16
+
17
+ # @api public
18
+ def base_relation(name, &block)
19
+ dsl = BaseRelationDSL.new(env, name, &block)
20
+ schema[dsl.repository] << dsl.call
21
+ end
22
+
23
+ private
24
+
25
+ # @api private
26
+ def initialize_schema
27
+ env.repositories.each_value do |repository|
28
+ schema[repository] ||= []
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,14 +1,20 @@
1
1
  module ROM
2
-
3
2
  # @api private
4
3
  class Registry
5
4
  include Enumerable
6
5
  include Equalizer.new(:elements)
7
6
 
8
- attr_reader :elements
7
+ class ElementNotFoundError < KeyError
8
+ def initialize(key, name)
9
+ super("#{key.inspect} doesn't exist in #{name} registry")
10
+ end
11
+ end
12
+
13
+ attr_reader :elements, :name
9
14
 
10
15
  def initialize(elements = {})
11
16
  @elements = elements
17
+ @name = self.class.name
12
18
  end
13
19
 
14
20
  def each(&block)
@@ -16,8 +22,8 @@ module ROM
16
22
  elements.each(&block)
17
23
  end
18
24
 
19
- def [](name)
20
- elements.fetch(name)
25
+ def [](key)
26
+ elements.fetch(key) { raise ElementNotFoundError.new(key, name) }
21
27
  end
22
28
 
23
29
  def respond_to_missing?(name, include_private = false)
@@ -33,7 +39,5 @@ module ROM
33
39
  super
34
40
  end
35
41
  end
36
-
37
42
  end
38
-
39
43
  end
@@ -1,3 +1,3 @@
1
1
  module ROM
2
- VERSION = '0.4.2'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
6
6
  gem.name = 'rom'
7
7
  gem.summary = 'Ruby Object Mapper'
8
8
  gem.description = 'Persistence and mapping toolkit for Ruby'
9
- gem.authors = 'Piotr Solnica',
9
+ gem.author = 'Piotr Solnica'
10
10
  gem.email = 'piotr.solnica@gmail.com'
11
11
  gem.homepage = 'http://rom-rb.org'
12
12
  gem.require_paths = ['lib']
@@ -16,6 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.license = 'MIT'
17
17
 
18
18
  gem.add_runtime_dependency 'addressable', '~> 2.3'
19
+ gem.add_runtime_dependency 'transproc', '~> 0.1'
19
20
  gem.add_runtime_dependency 'equalizer', '~> 0.0', '>= 0.0.9'
20
21
  gem.add_runtime_dependency 'concord', '~> 0.1', '>= 0.1.4'
21
22
  gem.add_runtime_dependency 'charlatan', '~> 0.1', '>= 0.1'
@@ -23,5 +24,6 @@ Gem::Specification.new do |gem|
23
24
 
24
25
  gem.add_development_dependency 'rake', '~> 10.3'
25
26
  gem.add_development_dependency 'rspec-core', '~> 3.1'
27
+ gem.add_development_dependency 'rspec-mocks', '~> 3.1'
26
28
  gem.add_development_dependency 'rspec-expectations', '~> 3.1'
27
29
  end
@@ -23,8 +23,6 @@ describe "Adapter" do
23
23
  end
24
24
  end
25
25
  end
26
-
27
- ROM::Adapter.register(self)
28
26
  end
29
27
  end
30
28
  end
@@ -29,7 +29,6 @@ describe 'Commands / Create' do
29
29
  setup.commands(:tasks) do
30
30
  define(:create)
31
31
  end
32
-
33
32
  end
34
33
 
35
34
  it 'inserts user on successful validation' do
@@ -47,7 +46,8 @@ describe 'Commands / Create' do
47
46
  }
48
47
  }
49
48
 
50
- expect(result).to match_array([{ name: 'Piotr', title: 'Finish command-api' }])
49
+ expect(result)
50
+ .to match_array([{ name: 'Piotr', title: 'Finish command-api' }])
51
51
  end
52
52
 
53
53
  it 'returns validation object with errors on failed validation' do
@@ -59,14 +59,11 @@ describe 'Commands / Create' do
59
59
  end
60
60
 
61
61
  describe '"result" option' do
62
-
63
62
  it 'returns a single tuple when set to :one' do
64
63
  setup.commands(:users) do
65
-
66
64
  define(:create_one, type: :create) do
67
65
  result :one
68
66
  end
69
-
70
67
  end
71
68
 
72
69
  tuple = { name: 'Piotr', email: 'piotr@solnic.eu' }
@@ -80,17 +77,13 @@ describe 'Commands / Create' do
80
77
 
81
78
  it 'allows only valid result types' do
82
79
  expect {
83
-
84
80
  setup.commands(:users) do
85
81
  define(:create_one, type: :create) do
86
82
  result :invalid_type
87
83
  end
88
84
  end
89
85
  setup.finalize
90
-
91
86
  }.to raise_error(ROM::InvalidOptionError)
92
87
  end
93
-
94
88
  end
95
-
96
89
  end
@@ -27,13 +27,13 @@ describe 'Commands / Delete' do
27
27
  end
28
28
 
29
29
  it 'deletes tuples matching restriction' do
30
- result = users.try { delete(:by_name, 'Joe').call }
30
+ result = users.try { delete(:by_name, 'Joe') }
31
31
 
32
32
  expect(result).to match_array([{ name: 'Joe', email: 'joe@doe.org' }])
33
33
  end
34
34
 
35
35
  it 'returns untouched relation if there are no tuples to delete' do
36
- result = users.try { delete(:by_name, 'Not here').call }
36
+ result = users.try { delete(:by_name, 'Not here') }
37
37
 
38
38
  expect(result).to match_array([])
39
39
  end
@@ -45,12 +45,12 @@ describe 'Commands / Delete' do
45
45
  end
46
46
  end
47
47
 
48
- result = users.try { delete_one(:by_name, 'Jane').call }
48
+ result = users.try { delete_one(:by_name, 'Jane') }
49
49
 
50
50
  expect(result.value).to eql(name: 'Jane', email: 'jane@doe.org')
51
51
  end
52
52
 
53
- it 'raises error when result is set to :one and relation contains more tuples' do
53
+ it 'raises when result is set to :one and relation contains more tuples' do
54
54
  setup.commands(:users) do
55
55
  define(:delete) do
56
56
  result :one
@@ -66,5 +66,4 @@ describe 'Commands / Delete' do
66
66
  { name: 'Joe', email: 'joe@doe.org' }
67
67
  ])
68
68
  end
69
-
70
69
  end
@@ -12,12 +12,13 @@ describe 'Commands / Error handling' do
12
12
 
13
13
  it 'rescues from ROM::CommandError' do
14
14
  result = false
15
- expect(users.try { raise ROM::CommandError } >-> test { result = true }).
16
- to be_instance_of(ROM::Result::Failure)
15
+ expect(users.try { raise ROM::CommandError } >-> _test { result = true })
16
+ .to be_instance_of(ROM::Commands::Result::Failure)
17
17
  expect(result).to be(false)
18
18
  end
19
19
 
20
20
  it 'raises other errors' do
21
- expect { users.try { raise ArgumentError, 'test' } }.to raise_error(ArgumentError, 'test')
21
+ expect { users.try { raise ArgumentError, 'test' } }
22
+ .to raise_error(ArgumentError, 'test')
22
23
  end
23
24
  end
@@ -31,7 +31,6 @@ describe 'Commands / Update' do
31
31
  validator UserValidator
32
32
  end
33
33
  end
34
-
35
34
  end
36
35
 
37
36
  it 'update tuples on successful validation' do
@@ -39,7 +38,8 @@ describe 'Commands / Update' do
39
38
  update(:all, name: 'Jane').set(email: 'jane.doe@test.com')
40
39
  }
41
40
 
42
- expect(result).to match_array([{ name: 'Jane', email: 'jane.doe@test.com' }])
41
+ expect(result)
42
+ .to match_array([{ name: 'Jane', email: 'jane.doe@test.com' }])
43
43
  end
44
44
 
45
45
  it 'returns validation object with errors on failed validation' do
@@ -54,7 +54,6 @@ describe 'Commands / Update' do
54
54
  end
55
55
 
56
56
  describe '"result" option' do
57
-
58
57
  it 'returns a single tuple when set to :one' do
59
58
  setup.commands(:users) do
60
59
  define(:update_one, type: :update) do
@@ -69,7 +68,7 @@ describe 'Commands / Update' do
69
68
  expect(result.value).to eql(name: 'Jane', email: 'jane.doe@test.com')
70
69
  end
71
70
 
72
- it 'raises error when there is more than one tuple and result is set to :one' do
71
+ it 'raises when there is more than one tuple and result is set to :one' do
73
72
  setup.commands(:users) do
74
73
  define(:update_one, type: :update) do
75
74
  result :one
@@ -90,17 +89,13 @@ describe 'Commands / Update' do
90
89
 
91
90
  it 'allows only valid result types' do
92
91
  expect {
93
-
94
92
  setup.commands(:users) do
95
93
  define(:create_one, type: :create) do
96
94
  result :invalid_type
97
95
  end
98
96
  end
99
97
  setup.finalize
100
-
101
98
  }.to raise_error(ROM::InvalidOptionError)
102
99
  end
103
-
104
100
  end
105
-
106
101
  end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mappers / deeply embedded tuples' do
4
+ let(:setup) { ROM.setup('memory://test') }
5
+ let(:rom) { setup.finalize }
6
+
7
+ it 'allows mapping embedded tuples' do
8
+ setup.schema do
9
+ base_relation(:users) do
10
+ repository :default
11
+ attribute 'name'
12
+ attribute 'tasks'
13
+ end
14
+ end
15
+
16
+ setup.relation(:users)
17
+
18
+ setup.mappers do
19
+ define(:users) do
20
+ model name: 'User'
21
+
22
+ attribute :name, from: 'name'
23
+
24
+ embedded :tasks, from: 'tasks' do
25
+ attribute :title, from: 'title'
26
+
27
+ embedded :priority, from: 'priority', type: :hash do
28
+ attribute :value, from: 'value'
29
+ attribute :desc, from: 'desc'
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ rom.schema.users << {
36
+ 'name' => 'Jane',
37
+ 'tasks' => [
38
+ { 'title' => 'Task One', 'priority' => { 'value' => 1, 'desc' => 'high' } },
39
+ { 'title' => 'Task Two', 'priority' => { 'value' => 3, 'desc' => 'low' } }
40
+ ]
41
+ }
42
+
43
+ jane = rom.read(:users).to_a.first
44
+
45
+ expect(jane.name).to eql('Jane')
46
+
47
+ expect(jane.tasks).to eql([
48
+ { title: 'Task One', priority: { value: 1, desc: 'high' } },
49
+ { title: 'Task Two', priority: { value: 3, desc: 'low' } }
50
+ ])
51
+ end
52
+ end
@@ -101,125 +101,9 @@ describe 'Mapper definition DSL' do
101
101
  end
102
102
  end
103
103
 
104
- describe 'grouped relation mapper' do
105
- before do
106
- setup.relation(:tasks)
107
-
108
- setup.relation(:users) do
109
- include ROM::RA
110
-
111
- def with_tasks
112
- join(tasks)
113
- end
114
- end
115
-
116
- setup.mappers do
117
- define(:users) do
118
- model name: 'User'
119
-
120
- attribute :name
121
- attribute :email
122
- end
123
- end
124
- end
125
-
126
- it 'allows defining grouped attributes via options hash' do
127
- setup.mappers do
128
- define(:with_tasks, parent: :users) do
129
- model name: 'UserWithTasks'
130
-
131
- attribute :name
132
- attribute :email
133
-
134
- group tasks: [:title, :priority]
135
- end
136
- end
137
-
138
- rom = setup.finalize
139
-
140
- UserWithTasks.send(:include, Equalizer.new(:name, :email, :tasks))
141
-
142
- jane = rom.read(:users).with_tasks.to_a.last
143
-
144
- expect(jane).to eql(
145
- UserWithTasks.new(
146
- name: 'Jane',
147
- email: 'jane@doe.org',
148
- tasks: [{ title: 'be cool', priority: 2 }]
149
- )
150
- )
151
- end
152
-
153
- it 'allows defining grouped attributes via block' do
154
- setup.mappers do
155
- define(:with_tasks, parent: :users) do
156
- model name: 'UserWithTasks'
157
-
158
- attribute :name
159
- attribute :email
160
-
161
- group :tasks do
162
- attribute :title
163
- attribute :priority
164
- end
165
- end
166
- end
167
-
168
- rom = setup.finalize
169
-
170
- UserWithTasks.send(:include, Equalizer.new(:name, :email, :tasks))
171
-
172
- jane = rom.read(:users).with_tasks.to_a.last
173
-
174
- expect(jane).to eql(
175
- UserWithTasks.new(
176
- name: 'Jane',
177
- email: 'jane@doe.org',
178
- tasks: [{ title: 'be cool', priority: 2 }]
179
- )
180
- )
181
- end
182
-
183
- it 'allows defining grouped attributes mapped to a model via block' do
184
- setup.mappers do
185
- define(:with_tasks, parent: :users) do
186
- model name: 'UserWithTasks'
187
-
188
- attribute :name
189
- attribute :email
190
-
191
- group :tasks do
192
- model name: 'Task'
193
-
194
- attribute :title
195
- attribute :priority
196
- end
197
- end
198
- end
199
-
200
- rom = setup.finalize
201
-
202
- UserWithTasks.send(:include, Equalizer.new(:name, :email, :tasks))
203
- Task.send(:include, Equalizer.new(:title, :priority))
204
-
205
- jane = rom.read(:users).with_tasks.to_a.last
206
-
207
- expect(jane).to eql(
208
- UserWithTasks.new(
209
- name: 'Jane',
210
- email: 'jane@doe.org',
211
- tasks: [Task.new(title: 'be cool', priority: 2)]
212
- )
213
- )
214
- end
215
-
216
- end
217
-
218
104
  describe 'wrapped relation mapper' do
219
105
  before do
220
106
  setup.relation(:tasks) do
221
- include ROM::RA
222
-
223
107
  def with_user
224
108
  join(users)
225
109
  end
@@ -323,7 +207,5 @@ describe 'Mapper definition DSL' do
323
207
  )
324
208
  )
325
209
  end
326
-
327
210
  end
328
-
329
211
  end