rom 0.4.2 → 0.5.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 (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