rom 3.2.2 → 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dcffdcd66a5b0b8127eb767564652778c8061ca6
4
- data.tar.gz: 27f25c3fae64b26b1ab8d6643a5a7f90cb4fb633
3
+ metadata.gz: 0f727af1309d22c607fa43b3c26345749233dbef
4
+ data.tar.gz: 7a1d5142394e77da212457c8d656ca2d9d632759
5
5
  SHA512:
6
- metadata.gz: 83984e098b54e2e544b231be28aaf51157cae035c3f53f34d7509c42eb3e994796c47599feebf6a28cafcf284c64c1c6c61eeef046db7cc0216516f5d71ecbf6
7
- data.tar.gz: 0aba220bf1b4667ff29d801dca1afd457e0fca1456d60353625ca3d72aa8903186d415e2de8c412ccbb69c5993f153930d4b85acde15f096e89b0ccc85d11185
6
+ metadata.gz: 2b915a97368fd38abcaab1160d28bbc4aa5b218415fc58605fc8517d6149ca21f7ae749b383a5733e00d937b362dde5a0e61e3acfe65d98e0c847a6632982682
7
+ data.tar.gz: ca3d98f9a4446d108bc029aa6ee8da32a0185b52a6a2dd4ed007abf702fb7cf1a8d742b300db5d796ba2e141b3f90bc0608182198f7d64c3e4cfb90265d5c4a4
data/CHANGELOG.md CHANGED
@@ -1,8 +1,28 @@
1
+ # v3.2.3 2017-05-31
2
+
3
+ ## Added
4
+
5
+ * auto-registration was improved with better handling of custom namespaces (Krule)
6
+
7
+ ## Changed
8
+
9
+ * `Relation#combine` was deprecated in favor of `Relation#graph` (solnic)
10
+
11
+ [Compare v3.2.2...v3.2.3](https://github.com/rom-rb/rom/compare/v3.2.2...v3.2.3)
12
+
13
+ # v3.2.2 2017-05-05
14
+
15
+ ## Changed
16
+
17
+ * [internal] Compatibility with `dry-core` v0.3.0 (flash-gordon)
18
+
19
+ [Compare v3.2.1...v3.2.2](https://github.com/rom-rb/rom/compare/v3.2.1...v3.2.2)
20
+
1
21
  # v3.2.1 2017-05-02
2
22
 
3
23
  ## Changed
4
24
 
5
- * `ROM::Schema::Attribute` uses `Initializer` now (flash-gordon)
25
+ * [internal] `ROM::Schema::Attribute` uses `Initializer` now (flash-gordon)
6
26
 
7
27
  [Compare v3.2.0...v3.2.1](https://github.com/rom-rb/rom/compare/v3.2.0...v3.2.1)
8
28
 
data/Gemfile CHANGED
@@ -24,7 +24,7 @@ group :test do
24
24
  end
25
25
 
26
26
  group :sql do
27
- gem 'rom-sql', git: 'https://github.com/rom-rb/rom-sql.git', branch: 'master'
27
+ gem 'rom-sql', git: 'https://github.com/rom-rb/rom-sql.git', branch: 'release-1.0'
28
28
  gem 'sequel'
29
29
  gem 'jdbc-sqlite3', platforms: :jruby
30
30
  gem 'jdbc-postgres', platforms: :jruby
data/README.md CHANGED
@@ -13,6 +13,8 @@
13
13
  [![Code Climate](https://codeclimate.com/github/rom-rb/rom/badges/gpa.svg)][codeclimate]
14
14
  [![Test Coverage](https://codeclimate.com/github/rom-rb/rom/badges/coverage.svg)][codeclimate]
15
15
  [![Inline docs](http://inch-ci.org/github/rom-rb/rom.svg?branch=master&style=flat)][inchpages]
16
+ [![OpenCollective](https://opencollective.com/rom/backers/badge.svg)](#backers)
17
+ [![OpenCollective](https://opencollective.com/rom/sponsors/badge.svg)](#sponsors)
16
18
 
17
19
  Ruby Object Mapper (ROM) is a data mapping and persistence toolkit for Ruby
18
20
  with the goal to provide powerful object mapping capabilities without limiting
@@ -22,10 +24,76 @@ Learn more:
22
24
 
23
25
  * [Introduction](http://rom-rb.org/learn/introduction)
24
26
  * [Quick Start](http://rom-rb.org/learn/repositories/quick-start)
25
-
26
- ## Support Campaign
27
-
28
- You can support ROM's development via our [campaign on Bountysource](https://salt.bountysource.com/teams/rom-rb). Cheers!
27
+
28
+ ## Backers
29
+
30
+ Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/rom#backer)]
31
+
32
+ <a href="https://opencollective.com/rom/backer/0/website" target="_blank"><img src="https://opencollective.com/rom/backer/0/avatar.svg"></a>
33
+ <a href="https://opencollective.com/rom/backer/1/website" target="_blank"><img src="https://opencollective.com/rom/backer/1/avatar.svg"></a>
34
+ <a href="https://opencollective.com/rom/backer/2/website" target="_blank"><img src="https://opencollective.com/rom/backer/2/avatar.svg"></a>
35
+ <a href="https://opencollective.com/rom/backer/3/website" target="_blank"><img src="https://opencollective.com/rom/backer/3/avatar.svg"></a>
36
+ <a href="https://opencollective.com/rom/backer/4/website" target="_blank"><img src="https://opencollective.com/rom/backer/4/avatar.svg"></a>
37
+ <a href="https://opencollective.com/rom/backer/5/website" target="_blank"><img src="https://opencollective.com/rom/backer/5/avatar.svg"></a>
38
+ <a href="https://opencollective.com/rom/backer/6/website" target="_blank"><img src="https://opencollective.com/rom/backer/6/avatar.svg"></a>
39
+ <a href="https://opencollective.com/rom/backer/7/website" target="_blank"><img src="https://opencollective.com/rom/backer/7/avatar.svg"></a>
40
+ <a href="https://opencollective.com/rom/backer/8/website" target="_blank"><img src="https://opencollective.com/rom/backer/8/avatar.svg"></a>
41
+ <a href="https://opencollective.com/rom/backer/9/website" target="_blank"><img src="https://opencollective.com/rom/backer/9/avatar.svg"></a>
42
+ <a href="https://opencollective.com/rom/backer/10/website" target="_blank"><img src="https://opencollective.com/rom/backer/10/avatar.svg"></a>
43
+ <a href="https://opencollective.com/rom/backer/11/website" target="_blank"><img src="https://opencollective.com/rom/backer/11/avatar.svg"></a>
44
+ <a href="https://opencollective.com/rom/backer/12/website" target="_blank"><img src="https://opencollective.com/rom/backer/12/avatar.svg"></a>
45
+ <a href="https://opencollective.com/rom/backer/13/website" target="_blank"><img src="https://opencollective.com/rom/backer/13/avatar.svg"></a>
46
+ <a href="https://opencollective.com/rom/backer/14/website" target="_blank"><img src="https://opencollective.com/rom/backer/14/avatar.svg"></a>
47
+ <a href="https://opencollective.com/rom/backer/15/website" target="_blank"><img src="https://opencollective.com/rom/backer/15/avatar.svg"></a>
48
+ <a href="https://opencollective.com/rom/backer/16/website" target="_blank"><img src="https://opencollective.com/rom/backer/16/avatar.svg"></a>
49
+ <a href="https://opencollective.com/rom/backer/17/website" target="_blank"><img src="https://opencollective.com/rom/backer/17/avatar.svg"></a>
50
+ <a href="https://opencollective.com/rom/backer/18/website" target="_blank"><img src="https://opencollective.com/rom/backer/18/avatar.svg"></a>
51
+ <a href="https://opencollective.com/rom/backer/19/website" target="_blank"><img src="https://opencollective.com/rom/backer/19/avatar.svg"></a>
52
+ <a href="https://opencollective.com/rom/backer/20/website" target="_blank"><img src="https://opencollective.com/rom/backer/20/avatar.svg"></a>
53
+ <a href="https://opencollective.com/rom/backer/21/website" target="_blank"><img src="https://opencollective.com/rom/backer/21/avatar.svg"></a>
54
+ <a href="https://opencollective.com/rom/backer/22/website" target="_blank"><img src="https://opencollective.com/rom/backer/22/avatar.svg"></a>
55
+ <a href="https://opencollective.com/rom/backer/23/website" target="_blank"><img src="https://opencollective.com/rom/backer/23/avatar.svg"></a>
56
+ <a href="https://opencollective.com/rom/backer/24/website" target="_blank"><img src="https://opencollective.com/rom/backer/24/avatar.svg"></a>
57
+ <a href="https://opencollective.com/rom/backer/25/website" target="_blank"><img src="https://opencollective.com/rom/backer/25/avatar.svg"></a>
58
+ <a href="https://opencollective.com/rom/backer/26/website" target="_blank"><img src="https://opencollective.com/rom/backer/26/avatar.svg"></a>
59
+ <a href="https://opencollective.com/rom/backer/27/website" target="_blank"><img src="https://opencollective.com/rom/backer/27/avatar.svg"></a>
60
+ <a href="https://opencollective.com/rom/backer/28/website" target="_blank"><img src="https://opencollective.com/rom/backer/28/avatar.svg"></a>
61
+ <a href="https://opencollective.com/rom/backer/29/website" target="_blank"><img src="https://opencollective.com/rom/backer/29/avatar.svg"></a>
62
+
63
+ ## Sponsors
64
+
65
+ Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/rom#sponsor)]
66
+
67
+ <a href="https://opencollective.com/rom/sponsor/0/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/0/avatar.svg"></a>
68
+ <a href="https://opencollective.com/rom/sponsor/1/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/1/avatar.svg"></a>
69
+ <a href="https://opencollective.com/rom/sponsor/2/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/2/avatar.svg"></a>
70
+ <a href="https://opencollective.com/rom/sponsor/3/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/3/avatar.svg"></a>
71
+ <a href="https://opencollective.com/rom/sponsor/4/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/4/avatar.svg"></a>
72
+ <a href="https://opencollective.com/rom/sponsor/5/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/5/avatar.svg"></a>
73
+ <a href="https://opencollective.com/rom/sponsor/6/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/6/avatar.svg"></a>
74
+ <a href="https://opencollective.com/rom/sponsor/7/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/7/avatar.svg"></a>
75
+ <a href="https://opencollective.com/rom/sponsor/8/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/8/avatar.svg"></a>
76
+ <a href="https://opencollective.com/rom/sponsor/9/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/9/avatar.svg"></a>
77
+ <a href="https://opencollective.com/rom/sponsor/10/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/10/avatar.svg"></a>
78
+ <a href="https://opencollective.com/rom/sponsor/11/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/11/avatar.svg"></a>
79
+ <a href="https://opencollective.com/rom/sponsor/12/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/12/avatar.svg"></a>
80
+ <a href="https://opencollective.com/rom/sponsor/13/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/13/avatar.svg"></a>
81
+ <a href="https://opencollective.com/rom/sponsor/14/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/14/avatar.svg"></a>
82
+ <a href="https://opencollective.com/rom/sponsor/15/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/15/avatar.svg"></a>
83
+ <a href="https://opencollective.com/rom/sponsor/16/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/16/avatar.svg"></a>
84
+ <a href="https://opencollective.com/rom/sponsor/17/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/17/avatar.svg"></a>
85
+ <a href="https://opencollective.com/rom/sponsor/18/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/18/avatar.svg"></a>
86
+ <a href="https://opencollective.com/rom/sponsor/19/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/19/avatar.svg"></a>
87
+ <a href="https://opencollective.com/rom/sponsor/20/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/20/avatar.svg"></a>
88
+ <a href="https://opencollective.com/rom/sponsor/21/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/21/avatar.svg"></a>
89
+ <a href="https://opencollective.com/rom/sponsor/22/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/22/avatar.svg"></a>
90
+ <a href="https://opencollective.com/rom/sponsor/23/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/23/avatar.svg"></a>
91
+ <a href="https://opencollective.com/rom/sponsor/24/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/24/avatar.svg"></a>
92
+ <a href="https://opencollective.com/rom/sponsor/25/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/25/avatar.svg"></a>
93
+ <a href="https://opencollective.com/rom/sponsor/26/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/26/avatar.svg"></a>
94
+ <a href="https://opencollective.com/rom/sponsor/27/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/27/avatar.svg"></a>
95
+ <a href="https://opencollective.com/rom/sponsor/28/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/28/avatar.svg"></a>
96
+ <a href="https://opencollective.com/rom/sponsor/29/website" target="_blank"><img src="https://opencollective.com/rom/sponsor/29/avatar.svg"></a>
29
97
 
30
98
  ## Ecosystem
31
99
 
@@ -31,10 +31,10 @@ module ROM
31
31
  mod = Module.new
32
32
 
33
33
  mod.module_eval do
34
- define_method(name) do |*args|
34
+ define_method(name) do |*args, &mblock|
35
35
  response =
36
36
  if arity < 0 || arity == args.size
37
- super(*args)
37
+ super(*args, &mblock)
38
38
  else
39
39
  self.class.curried.new(self, name: name, curry_args: args, arity: arity)
40
40
  end
data/lib/rom/relation.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'dry/core/class_attributes'
2
+ require 'dry/core/deprecations'
2
3
 
3
4
  require 'rom/initializer'
4
5
  require 'rom/relation/class_interface'
@@ -41,6 +42,7 @@ module ROM
41
42
 
42
43
  extend Initializer
43
44
  extend ClassInterface
45
+ extend Dry::Core::Deprecations[:rom]
44
46
 
45
47
  extend Dry::Core::ClassAttributes
46
48
  defines :schema_class, :schema_inferrer, :schema_dsl
@@ -120,9 +122,10 @@ module ROM
120
122
  # @return [Relation::Graph]
121
123
  #
122
124
  # @api public
123
- def combine(*others)
125
+ def graph(*others)
124
126
  Graph.build(self, others)
125
127
  end
128
+ deprecate :combine, :graph
126
129
 
127
130
  # Loads relation
128
131
  #
@@ -1,3 +1,5 @@
1
+ require 'dry/core/deprecations'
2
+
1
3
  require 'rom/relation/loaded'
2
4
  require 'rom/relation/composite'
3
5
  require 'rom/relation/materializable'
@@ -24,6 +26,8 @@ module ROM
24
26
  #
25
27
  # @api public
26
28
  class Graph
29
+ extend Dry::Core::Deprecations[:rom]
30
+
27
31
  include Materializable
28
32
  include Pipeline
29
33
  include Pipeline::Proxy
@@ -82,9 +86,10 @@ module ROM
82
86
  # @return [Graph]
83
87
  #
84
88
  # @api public
85
- def combine(*others)
89
+ def graph(*others)
86
90
  self.class.new(root, nodes + others)
87
91
  end
92
+ deprecate :combine, :graph
88
93
 
89
94
  # Materialize this relation graph
90
95
  #
@@ -29,7 +29,7 @@ module ROM
29
29
  option :globs, default: -> {
30
30
  Hash[
31
31
  component_dirs.map { |component, path|
32
- [component, directory.join("#{ path }/**/*.rb")]
32
+ [component, directory.join("#{path}/**/*.rb")]
33
33
  }
34
34
  ]
35
35
  }
@@ -55,7 +55,7 @@ module ROM
55
55
  case namespace
56
56
  when String
57
57
  AutoRegistrationStrategies::CustomNamespace.new(
58
- namespace: namespace, file: file
58
+ namespace: namespace, file: file, directory: directory
59
59
  ).call
60
60
  when TrueClass
61
61
  AutoRegistrationStrategies::WithNamespace.new(
@@ -66,6 +66,7 @@ module ROM
66
66
  file: file, directory: directory, entity: component_dirs.fetch(entity)
67
67
  ).call
68
68
  end
69
+
69
70
  Dry::Core::Inflector.constantize(klass_name)
70
71
  end
71
72
  end
@@ -10,7 +10,7 @@ module ROM
10
10
 
11
11
  option :file, type: Types::Strict::String
12
12
 
13
- EXTENSION_REGEX = /\.rb\z/.freeze
13
+ EXTENSION_REGEX = /\.rb\z/
14
14
  end
15
15
  end
16
16
  end
@@ -7,17 +7,57 @@ require 'rom/setup/auto_registration_strategies/base'
7
7
  module ROM
8
8
  module AutoRegistrationStrategies
9
9
  class CustomNamespace < Base
10
+ option :directory, type: PathnameType
10
11
  option :namespace, type: Types::Strict::String
11
12
 
12
13
  def call
13
- "#{namespace}::#{Dry::Core::Inflector.camelize(filename)}"
14
+ potential = []
15
+ attempted = []
16
+
17
+ path_arr.reverse.each do |dir|
18
+ const_fragment = potential.unshift(
19
+ Dry::Core::Inflector.camelize(dir)
20
+ ).join("::")
21
+
22
+ constant = "#{namespace}::#{const_fragment}"
23
+
24
+ return constant if ns_const.const_defined?(const_fragment)
25
+
26
+ attempted << constant
27
+ end
28
+
29
+ # If we have reached this point, its means constant is not defined and
30
+ # NameError will be thrown if we attempt to camelize something like:
31
+ # `"#{namespace}::#{Dry::Core::Inflector.camelize(filename)}"`
32
+ # so we can assume naming convention was not respected in required
33
+ # file.
34
+
35
+ raise NameError, name_error_message(attempted)
14
36
  end
15
37
 
16
38
  private
17
39
 
40
+ def name_error_message(attempted)
41
+ "required file does not define expected constant name; either " \
42
+ "register your constant explicitly of try following the path" \
43
+ "naming convention like:\n\n\t- #{attempted.join("\n\t- ")}\n"
44
+ end
45
+
18
46
  def filename
19
47
  Pathname(file).basename('.rb')
20
48
  end
49
+
50
+ def ns_const
51
+ @namespace_constant ||= Dry::Core::Inflector.constantize(namespace)
52
+ end
53
+
54
+ def path_arr
55
+ file_path << filename
56
+ end
57
+
58
+ def file_path
59
+ File.dirname(file).split("/") - directory.to_s.split("/")
60
+ end
21
61
  end
22
62
  end
23
63
  end
data/lib/rom/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ROM
2
- VERSION = '3.2.2'.freeze
2
+ VERSION = '3.2.3'.freeze
3
3
  end
@@ -0,0 +1,8 @@
1
+ module My
2
+ module Namespace
3
+ module Commands
4
+ class CreateCustomer
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module My
2
+ module Namespace
3
+ module Mappers
4
+ class CustomerList
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module My
2
+ module Namespace
3
+ module Relations
4
+ class Customers
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module My
2
+ module NewNamespace
3
+ module Foo
4
+ class CreateCustomer
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module My
2
+ module NewNamespace
3
+ module Foo
4
+ class CustomerList
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module My
2
+ module NewNamespace
3
+ module Foo
4
+ class Customers
5
+ end
6
+ end
7
+ end
8
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'pathname'
2
+
1
3
  if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
2
4
  require 'yaml'
3
5
  rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
@@ -30,6 +30,10 @@ RSpec.describe ROM::AutoCurry do
30
30
  args
31
31
  end
32
32
 
33
+ def yielding_block(arg)
34
+ yield(arg)
35
+ end
36
+
33
37
  protected
34
38
 
35
39
  def leave_me_alone(foo)
@@ -39,7 +43,7 @@ RSpec.describe ROM::AutoCurry do
39
43
  end
40
44
 
41
45
  it 'registers auto-curried methods' do
42
- expect(object.class.auto_curried_methods).to eql(%i[arity_1 arity_2 arity_many])
46
+ expect(object.class.auto_curried_methods).to eql(%i[arity_1 arity_2 arity_many yielding_block])
43
47
  end
44
48
 
45
49
  it 'auto-curries method with arity == 0' do
@@ -60,4 +64,8 @@ RSpec.describe ROM::AutoCurry do
60
64
  expect(object.arity_many).to eql([])
61
65
  expect(object.arity_many(1, 2)).to eql([1, 2])
62
66
  end
67
+
68
+ it 'yields block' do
69
+ expect(object.yielding_block(1) { |arg| [arg, 2] }).to eql([1, 2])
70
+ end
63
71
  end
@@ -106,8 +106,8 @@ RSpec.describe ROM::Relation, '#combine' do
106
106
  { name: 'Jane', title: 'be cool', priority: 2 }
107
107
  ],
108
108
  tags: [
109
- { task: 'be cool', name: 'red' },
110
- { task: 'be cool', name: 'green' }
109
+ { task: 'be cool', name: 'red', user: 'Jane' },
110
+ { task: 'be cool', name: 'green', user: 'Jane' }
111
111
  ]
112
112
  }
113
113
  ]
@@ -129,8 +129,8 @@ RSpec.describe ROM::Relation, '#combine' do
129
129
  { name: 'Jane', title: 'be cool', priority: 2 }
130
130
  ],
131
131
  tags: [
132
- { task: 'be cool', name: 'red' },
133
- { task: 'be cool', name: 'green' }
132
+ { task: 'be cool', name: 'red', user: 'Jane' },
133
+ { task: 'be cool', name: 'green', user: 'Jane' }
134
134
  ]
135
135
  }
136
136
  ]
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ROM::Relation, '#graph' do
4
+ include_context 'gateway only'
5
+ include_context 'users and tasks'
6
+
7
+ let(:tags_dataset) { gateway.dataset(:tags) }
8
+
9
+ let(:users_relation) do
10
+ Class.new(ROM::Memory::Relation) do
11
+ def by_name(name)
12
+ restrict(name: name)
13
+ end
14
+ end.new(users_dataset)
15
+ end
16
+
17
+ let(:tasks_relation) do
18
+ Class.new(ROM::Memory::Relation) do
19
+ def for_users(users)
20
+ names = users.map { |user| user[:name] }
21
+ restrict { |task| names.include?(task[:name]) }
22
+ end
23
+ end.new(tasks_dataset)
24
+ end
25
+
26
+ let(:tags_relation) do
27
+ Class.new(ROM::Memory::Relation) do
28
+ attr_accessor :tasks
29
+ forward :map
30
+
31
+ def for_tasks(tasks)
32
+ titles = tasks.map { |task| task[:title] }
33
+ restrict { |tag| titles.include?(tag[:task]) }
34
+ end
35
+
36
+ def for_users(users)
37
+ user_tasks = tasks.for_users(users)
38
+
39
+ for_tasks(user_tasks).map { |tag|
40
+ tag.merge(user: user_tasks.detect { |task|
41
+ task[:title] == tag[:task]
42
+ } [:name])
43
+ }
44
+ end
45
+ end.new(tags_dataset).tap { |r| r.tasks = tasks_relation }
46
+ end
47
+
48
+ before do
49
+ tags_dataset.insert(task: 'be cool', name: 'red')
50
+ tags_dataset.insert(task: 'be cool', name: 'green')
51
+ end
52
+
53
+ let(:map_users) {
54
+ proc { |users, tasks|
55
+ users.map { |user|
56
+ user.merge(tasks: tasks.select { |task| task[:name] == user[:name] })
57
+ }
58
+ }
59
+ }
60
+
61
+ let(:map_tasks) {
62
+ proc { |(tasks, children)|
63
+ tags = children.first
64
+
65
+ tasks.map { |task|
66
+ task.merge(tags: tags.select { |tag| tag[:task] == task[:title] })
67
+ }
68
+ }
69
+ }
70
+
71
+ let(:map_user_with_tasks_and_tags) {
72
+ proc { |users, (tasks, tags)|
73
+ users.map { |user|
74
+ user_tasks = tasks.select { |task| task[:name] == user[:name] }
75
+
76
+ user_tags = tasks.flat_map { |task|
77
+ tags.select { |tag| tag[:task] == task[:title] }
78
+ }
79
+
80
+ user.merge(
81
+ tasks: user_tasks,
82
+ tags: user_tags
83
+ )
84
+ }
85
+ }
86
+ }
87
+
88
+ let(:map_user_with_tasks) {
89
+ proc { |users, children|
90
+ map_users[users, map_tasks[children.first]]
91
+ }
92
+ }
93
+
94
+ it 'raises error when composite relation is passed as a node' do
95
+ expect {
96
+ users_relation.graph(tasks_relation >> proc {})
97
+ }.to raise_error(ROM::UnsupportedRelationError)
98
+ end
99
+
100
+ it 'supports more than one eagerly-loaded relation' do
101
+ expected = [
102
+ {
103
+ name: 'Jane',
104
+ email: 'jane@doe.org',
105
+ tasks: [
106
+ { name: 'Jane', title: 'be cool', priority: 2 }
107
+ ],
108
+ tags: [
109
+ { task: 'be cool', name: 'red', user: 'Jane' },
110
+ { task: 'be cool', name: 'green', user: 'Jane' }
111
+ ]
112
+ }
113
+ ]
114
+
115
+ user_with_tasks_and_tags = users_relation.by_name('Jane')
116
+ .graph(tasks_relation.for_users, tags_relation.for_users)
117
+
118
+ result = user_with_tasks_and_tags >> map_user_with_tasks_and_tags
119
+
120
+ expect(result.to_a).to eql(expected)
121
+ end
122
+
123
+ it 'supports more than one eagerly-loaded relation via chaining' do
124
+ expected = [
125
+ {
126
+ name: 'Jane',
127
+ email: 'jane@doe.org',
128
+ tasks: [
129
+ { name: 'Jane', title: 'be cool', priority: 2 }
130
+ ],
131
+ tags: [
132
+ { task: 'be cool', name: 'red', user: 'Jane' },
133
+ { task: 'be cool', name: 'green', user: 'Jane' }
134
+ ]
135
+ }
136
+ ]
137
+
138
+ user_with_tasks_and_tags = users_relation.by_name('Jane')
139
+ .graph(tasks_relation.for_users).graph(tags_relation.for_users)
140
+
141
+ result = user_with_tasks_and_tags >> map_user_with_tasks_and_tags
142
+
143
+ expect(result).to match_array(expected)
144
+ end
145
+
146
+ it 'supports nested eager-loading' do
147
+ expected = [
148
+ {
149
+ name: 'Jane', email: 'jane@doe.org', tasks: [
150
+ { name: 'Jane', title: 'be cool', priority: 2, tags: [
151
+ { task: 'be cool', name: 'red' },
152
+ { task: 'be cool', name: 'green' }
153
+ ] }
154
+ ]
155
+ }
156
+ ]
157
+
158
+ user_with_tasks = users_relation.by_name('Jane')
159
+ .graph(tasks_relation.for_users.graph(tags_relation.for_tasks))
160
+
161
+ result = user_with_tasks >> map_user_with_tasks
162
+
163
+ expect(result).to match_array(expected)
164
+ end
165
+ end
@@ -117,34 +117,96 @@ RSpec.describe ROM::Setup, '#auto_registration' do
117
117
  end
118
118
  end
119
119
 
120
- context 'with custom namespace' do
121
- before do
122
- setup.auto_registration(
123
- SPEC_ROOT.join('fixtures/custom'),
124
- component_dirs: {
125
- relations: :relations,
126
- mappers: :mappers,
127
- commands: :commands
128
- },
129
- namespace: 'My::Namespace'
130
- )
131
- end
120
+ describe 'custom namespace' do
121
+ context 'when namespace has subnamespace' do
122
+ before do
123
+ setup.auto_registration(
124
+ SPEC_ROOT.join('fixtures/custom_namespace'),
125
+ component_dirs: {
126
+ relations: :relations,
127
+ mappers: :mappers,
128
+ commands: :commands
129
+ },
130
+ namespace: 'My::Namespace'
131
+ )
132
+ end
132
133
 
133
- describe '#relations' do
134
- it 'loads files and returns constants' do
135
- expect(setup.relation_classes).to eql([My::Namespace::Users])
134
+ describe '#relations' do
135
+ it 'loads files and returns constants' do
136
+ expect(setup.relation_classes).to eql([My::Namespace::Relations::Customers])
137
+ end
138
+ end
139
+
140
+ describe '#commands' do
141
+ it 'loads files and returns constants' do
142
+ expect(setup.command_classes).to eql([My::Namespace::Commands::CreateCustomer])
143
+ end
144
+ end
145
+
146
+ describe '#mappers' do
147
+ it 'loads files and returns constants' do
148
+ expect(setup.mapper_classes).to eql([My::Namespace::Mappers::CustomerList])
149
+ end
136
150
  end
137
151
  end
138
152
 
139
- describe '#commands' do
140
- it 'loads files and returns constants' do
141
- expect(setup.command_classes).to eql([My::Namespace::CreateUser])
153
+ context 'when namespace has wrong subnamespace' do
154
+ subject do
155
+ -> do
156
+ setup.auto_registration(
157
+ SPEC_ROOT.join('fixtures/wrong'),
158
+ component_dirs: {
159
+ relations: :relations,
160
+ mappers: :mappers,
161
+ commands: :commands
162
+ },
163
+ namespace: 'My::NewNamespace'
164
+ )
165
+ end
166
+ end
167
+
168
+ describe '#relations' do
169
+ it { is_expected.to raise_exception NameError }
170
+ end
171
+
172
+ describe '#commands' do
173
+ it { is_expected.to raise_exception NameError }
174
+ end
175
+
176
+ describe '#mappers' do
177
+ it { is_expected.to raise_exception NameError }
142
178
  end
143
179
  end
144
180
 
145
- describe '#mappers' do
146
- it 'loads files and returns constants' do
147
- expect(setup.mapper_classes).to eql([My::Namespace::UserList])
181
+ context 'when namespace does not implement subnamespace' do
182
+ before do
183
+ setup.auto_registration(
184
+ SPEC_ROOT.join('fixtures/custom'),
185
+ component_dirs: {
186
+ relations: :relations,
187
+ mappers: :mappers,
188
+ commands: :commands
189
+ },
190
+ namespace: 'My::Namespace'
191
+ )
192
+ end
193
+
194
+ describe '#relations' do
195
+ it 'loads files and returns constants' do
196
+ expect(setup.relation_classes).to eql([My::Namespace::Users])
197
+ end
198
+ end
199
+
200
+ describe '#commands' do
201
+ it 'loads files and returns constants' do
202
+ expect(setup.command_classes).to eql([My::Namespace::CreateUser])
203
+ end
204
+ end
205
+
206
+ describe '#mappers' do
207
+ it 'loads files and returns constants' do
208
+ expect(setup.mapper_classes).to eql([My::Namespace::UserList])
209
+ end
148
210
  end
149
211
  end
150
212
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.2
4
+ version: 3.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-05 00:00:00.000000000 Z
11
+ date: 2017-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -258,12 +258,18 @@ files:
258
258
  - spec/fixtures/custom/commands/create_user.rb
259
259
  - spec/fixtures/custom/mappers/user_list.rb
260
260
  - spec/fixtures/custom/relations/users.rb
261
+ - spec/fixtures/custom_namespace/commands/create_customer.rb
262
+ - spec/fixtures/custom_namespace/mappers/customer_list.rb
263
+ - spec/fixtures/custom_namespace/relations/customers.rb
261
264
  - spec/fixtures/lib/persistence/commands/create_user.rb
262
265
  - spec/fixtures/lib/persistence/mappers/user_list.rb
263
266
  - spec/fixtures/lib/persistence/my_commands/create_user.rb
264
267
  - spec/fixtures/lib/persistence/my_mappers/user_list.rb
265
268
  - spec/fixtures/lib/persistence/my_relations/users.rb
266
269
  - spec/fixtures/lib/persistence/relations/users.rb
270
+ - spec/fixtures/wrong/commands/create_customer.rb
271
+ - spec/fixtures/wrong/mappers/customer_list.rb
272
+ - spec/fixtures/wrong/relations/customers.rb
267
273
  - spec/integration/command_registry_spec.rb
268
274
  - spec/integration/commands/create_spec.rb
269
275
  - spec/integration/commands/delete_spec.rb
@@ -353,6 +359,7 @@ files:
353
359
  - spec/unit/rom/relation/curried_spec.rb
354
360
  - spec/unit/rom/relation/graph_spec.rb
355
361
  - spec/unit/rom/relation/lazy/combine_spec.rb
362
+ - spec/unit/rom/relation/lazy/graph_spec.rb
356
363
  - spec/unit/rom/relation/lazy_spec.rb
357
364
  - spec/unit/rom/relation/loaded_spec.rb
358
365
  - spec/unit/rom/relation/name_spec.rb