rom 0.6.0.beta3 → 0.6.0.rc1

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: 3860ac36d7e9d938342e022c7fb0e227fc6273e1
4
- data.tar.gz: 1a650f4573310fd5d543839c258338344827989b
3
+ metadata.gz: 0ea7e1a611937b1db33e9bb5f6495c116ff163bd
4
+ data.tar.gz: 98243b1e80fc05db0038fdeea7465a7b913990f8
5
5
  SHA512:
6
- metadata.gz: b1239e346a1626da09367e8d4c37a222a43d9a7f70dd248d427dc2046fc1272033913859b38c9e5183d316bd31296c72bdbff4d0a55be590ab9f94f9c907d669
7
- data.tar.gz: 4a711b1a776e137d1e953acc7eb8230f5c7c1695d5e8a812b9a7ef23f2673f3fe91619c83b9a93e317dc72e66f2a39b6ce37d082a19ab03110c84abbea8be7e8
6
+ metadata.gz: fde6f6d9efc44fe43c2bffefdfcf809e6f7d3991a4059185ac58909c3455c3e821dda71843503c3a4c31f36178eaff0454ef48c2d71c4ae1106beb30f95623c0
7
+ data.tar.gz: 1fa7191e19578e32cfc72c71db3eeebb7a28a7410dd98db8064af3f19f85bfa19e7397f22d46c86eaf42013943a91cc7f754f89fd2f62e96f6de12737fc7e7c9
data/.gitignore CHANGED
@@ -12,6 +12,7 @@ test/tmp
12
12
  test/version_tmp
13
13
  tmp
14
14
  Gemfile.lock
15
+ vendor/
15
16
 
16
17
  .idea/
17
18
 
@@ -19,5 +20,3 @@ Gemfile.lock
19
20
  .yardoc
20
21
  _yardoc
21
22
  doc/
22
-
23
- Gemfile.lock
data/CHANGELOG.md CHANGED
@@ -20,8 +20,9 @@
20
20
 
21
21
  ### Changed
22
22
 
23
- * [BREAKING] Command API was simplified - commands should be accessed directly in `.try` block (solnic)
24
23
  * [BREAKING] Schema DSL was **removed** - attributes can be specified only in mapper DSL
24
+ * [BREAKING] Reader was **removed** in favor of relation interface with explicit mapping (solnic)
25
+ * [BREAKING] Command API was simplified - commands should be accessed directly in `.try` block (solnic)
25
26
  and default repository can be changed when defining a relation (solnic)
26
27
  * `.setup` interface requires either an adapter identifier or can accept a repository
27
28
  instance (aflatter)
data/Gemfile CHANGED
@@ -29,7 +29,7 @@ end
29
29
 
30
30
  group :benchmarks do
31
31
  gem 'activerecord', '4.2.0'
32
- gem 'benchmark-ips'
32
+ gem 'benchmark-ips', git: 'https://github.com/evanphx/benchmark-ips.git', branch: 'master'
33
33
  end
34
34
 
35
35
  group :tools do
data/lib/rom.rb CHANGED
@@ -13,7 +13,6 @@ require 'rom/support/class_builder'
13
13
  # core parts
14
14
  require 'rom/relation'
15
15
  require 'rom/mapper'
16
- require 'rom/reader'
17
16
  require 'rom/command'
18
17
 
19
18
  # default mapper processor using Transproc gem
@@ -33,5 +32,4 @@ module ROM
33
32
  extend Global
34
33
 
35
34
  RelationRegistry = Class.new(Registry)
36
- ReaderRegistry = Class.new(Registry)
37
35
  end
@@ -21,7 +21,7 @@ module ROM
21
21
  option :target
22
22
  option :validator, reader: true
23
23
  option :input, reader: true
24
- option :curry_args, type: Array, reader: true, default: []
24
+ option :curry_args, type: Array, reader: true, default: EMPTY_ARRAY
25
25
 
26
26
  attr_reader :relation
27
27
 
data/lib/rom/env.rb CHANGED
@@ -88,15 +88,17 @@ module ROM
88
88
  #
89
89
  # @param [Symbol] name of the registered reader
90
90
  #
91
+ # @deprecated
92
+ #
91
93
  # @api public
92
94
  def read(name, &block)
93
- reader = readers[name]
94
-
95
- if block
96
- yield(reader)
97
- else
98
- reader
99
- end
95
+ warn <<-MSG
96
+ #{self.class}#read is deprecated.
97
+ Please use `#{self.class}#relation(#{name.inspect})` instead.
98
+ For mapping append `.map_with(:your_mapper_name)`
99
+ [#{caller[0]}]
100
+ MSG
101
+ relation(name, &block)
100
102
  end
101
103
 
102
104
  # Returns commands registry for the given relation
@@ -1,4 +1,9 @@
1
- require 'thread_safe'
1
+ begin
2
+ require 'thread_safe'
3
+ rescue LoadError
4
+ raise LoadError, 'Please install the `thread_safe` gem.'
5
+ end
6
+
2
7
  require 'rom/memory/dataset'
3
8
 
4
9
  module ROM
data/lib/rom/relation.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'set'
2
- require 'rom/relation/registry_reader'
1
+ require 'rom/relation/class_interface'
2
+
3
3
  require 'rom/relation/lazy'
4
4
  require 'rom/relation/curried'
5
5
 
@@ -19,147 +19,26 @@ module ROM
19
19
  #
20
20
  # @api public
21
21
  class Relation
22
- extend ClassMacros
22
+ extend ClassInterface
23
23
 
24
24
  include Options
25
25
  include Equalizer.new(:dataset)
26
26
 
27
- defines :repository, :dataset, :register_as, :exposed_relations
28
-
29
- repository :default
30
-
31
- attr_reader :name, :dataset, :exposed_relations
32
-
33
- # Register adapter relation subclasses during setup phase
34
- #
35
- # In adition those subclasses are extended with an interface for accessing
36
- # relation registry and to define `register_as` setting
37
- #
38
- # @api private
39
- def self.inherited(klass)
40
- super
41
-
42
- return if self == ROM::Relation
43
-
44
- klass.class_eval do
45
- include ROM::Relation::RegistryReader
46
-
47
- dataset(default_name)
48
- exposed_relations Set.new
49
-
50
- def self.register_as(value = Undefined)
51
- if value == Undefined
52
- @register_as || dataset
53
- else
54
- super
55
- end
56
- end
57
-
58
- def self.method_added(name)
59
- super
60
- exposed_relations << name if public_instance_methods.include?(name)
61
- end
62
- end
63
-
64
- ROM.register_relation(klass)
65
- end
66
-
67
- # Return adapter-specific relation subclass
68
- #
69
- # @example
70
- # ROM::Relation[:memory]
71
- # # => ROM::Memory::Relation
27
+ # Dataset used by the relation
72
28
  #
73
- # @return [Class]
74
- #
75
- # @api public
76
- def self.[](type)
77
- ROM.adapters.fetch(type).const_get(:Relation)
78
- end
79
-
80
- # Dynamically define a method that will forward to the dataset and wrap
81
- # response in the relation itself
82
- #
83
- # @example
84
- # class SomeAdapterRelation < ROM::Relation
85
- # forward :super_query
86
- # end
87
- #
88
- # @api public
89
- def self.forward(*methods)
90
- methods.each do |method|
91
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
92
- def #{method}(*args, &block)
93
- __new__(dataset.__send__(:#{method}, *args, &block))
94
- end
95
- RUBY
96
- end
97
- end
98
-
99
- # Return default relation name used for `register_as` setting
29
+ # This object is provided by the repository during the setup
100
30
  #
101
- # @return [Symbol]
31
+ # @return [Object]
102
32
  #
103
33
  # @api private
104
- def self.default_name
105
- return unless name
106
- Inflector.underscore(name).gsub('/', '_').to_sym
107
- end
108
-
109
- # Build relation registry of specified descendant classes
110
- #
111
- # This is used by the setup
112
- #
113
- # @param [Hash] repositories
114
- # @param [Array] descendants a list of relation descendants
115
- #
116
- # @return [Hash]
117
- #
118
- # @api private
119
- def self.registry(repositories, descendants)
120
- registry = {}
121
-
122
- descendants.each do |klass|
123
- # TODO: raise a meaningful error here and add spec covering the case
124
- # where klass' repository points to non-existant repo
125
- repository = repositories.fetch(klass.repository)
126
- dataset = repository.dataset(klass.dataset)
127
-
128
- relation = klass.new(dataset, __registry__: registry)
129
-
130
- name = klass.register_as
131
-
132
- if registry.key?(name)
133
- raise RelationAlreadyDefinedError,
134
- "Relation with `register_as #{name.inspect}` registered more " \
135
- "than once"
136
- end
137
-
138
- registry[name] = relation
139
- end
140
-
141
- registry.each_value do |relation|
142
- relation.class.finalize(registry, relation)
143
- end
144
-
145
- registry
146
- end
34
+ attr_reader :dataset
147
35
 
148
36
  # @api private
149
37
  def initialize(dataset, options = {})
150
38
  @dataset = dataset
151
- @name = self.class.dataset
152
- @exposed_relations = self.class.exposed_relations
153
39
  super
154
40
  end
155
41
 
156
- # Hook to finalize a relation after its instance was created
157
- #
158
- # @api private
159
- def self.finalize(_env, _relation)
160
- # noop
161
- end
162
-
163
42
  # Yield dataset tuples
164
43
  #
165
44
  # @yield [Hash]
@@ -170,7 +49,7 @@ module ROM
170
49
  dataset.each { |tuple| yield(tuple) }
171
50
  end
172
51
 
173
- # Materialize relation into an array
52
+ # Materialize a relation into an array
174
53
  #
175
54
  # @return [Array<Hash>]
176
55
  #
@@ -179,11 +58,12 @@ module ROM
179
58
  to_enum.to_a
180
59
  end
181
60
 
182
- # @api private
183
- def repository
184
- self.class.repository
185
- end
186
-
61
+ # Turn relation into a lazy-loadable and composable relation
62
+ #
63
+ # @see Lazy
64
+ #
65
+ # @return [Lazy]
66
+ #
187
67
  # @api public
188
68
  def to_lazy(*args)
189
69
  Lazy.new(self, *args)
@@ -0,0 +1,180 @@
1
+ require 'set'
2
+ require 'rom/relation/registry_reader'
3
+
4
+ module ROM
5
+ class Relation
6
+ module ClassInterface
7
+ # Register adapter relation subclasses during setup phase
8
+ #
9
+ # In adition those subclasses are extended with an interface for accessing
10
+ # relation registry and to define `register_as` setting
11
+ #
12
+ # @api private
13
+ def inherited(klass)
14
+ super
15
+
16
+ return if klass.superclass == ROM::Relation
17
+
18
+ klass.class_eval do
19
+ extend ClassMacros
20
+ include RegistryReader
21
+
22
+ defines :repository, :dataset, :register_as, :exposed_relations
23
+
24
+ repository :default
25
+
26
+ dataset(default_name)
27
+ exposed_relations Set.new
28
+
29
+ # Relation's dataset name
30
+ #
31
+ # In example a table name in an SQL database
32
+ #
33
+ # @return [Symbol]
34
+ #
35
+ # @api public
36
+ attr_reader :name
37
+
38
+ # A set with public method names that return "virtual" relations
39
+ #
40
+ # Only those methods are exposed directly on relations return by
41
+ # Env#relation interface
42
+ #
43
+ # @return [Set]
44
+ #
45
+ # @api private
46
+ attr_reader :exposed_relations
47
+
48
+ # Set or get name under which a relation will be registered
49
+ #
50
+ # This defaults to `dataset` name
51
+ #
52
+ # @return [Symbol]
53
+ #
54
+ # @api public
55
+ def self.register_as(value = Undefined)
56
+ if value == Undefined
57
+ super() || dataset
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ # Hook used to collect public method names
64
+ #
65
+ # @api private
66
+ def self.method_added(name)
67
+ super
68
+ exposed_relations << name if public_instance_methods.include?(name)
69
+ end
70
+
71
+ # @api private
72
+ def initialize(dataset, options = {})
73
+ @name = self.class.dataset
74
+ @exposed_relations = self.class.exposed_relations
75
+ super
76
+ end
77
+
78
+ # Return name of the source repository of this relation
79
+ #
80
+ # @return [Symbol]
81
+ #
82
+ # @api private
83
+ def repository
84
+ self.class.repository
85
+ end
86
+ end
87
+
88
+ ROM.register_relation(klass)
89
+ end
90
+
91
+ # Return adapter-specific relation subclass
92
+ #
93
+ # @example
94
+ # ROM::Relation[:memory]
95
+ # # => ROM::Memory::Relation
96
+ #
97
+ # @return [Class]
98
+ #
99
+ # @api public
100
+ def [](type)
101
+ ROM.adapters.fetch(type).const_get(:Relation)
102
+ end
103
+
104
+ # Dynamically define a method that will forward to the dataset and wrap
105
+ # response in the relation itself
106
+ #
107
+ # @example
108
+ # class SomeAdapterRelation < ROM::Relation
109
+ # forward :super_query
110
+ # end
111
+ #
112
+ # @api public
113
+ def forward(*methods)
114
+ methods.each do |method|
115
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
116
+ def #{method}(*args, &block)
117
+ __new__(dataset.__send__(:#{method}, *args, &block))
118
+ end
119
+ RUBY
120
+ end
121
+ end
122
+
123
+ # Return default relation name used for `register_as` setting
124
+ #
125
+ # @return [Symbol]
126
+ #
127
+ # @api private
128
+ def default_name
129
+ return unless name
130
+ Inflector.underscore(name).gsub('/', '_').to_sym
131
+ end
132
+
133
+ # Build relation registry of specified descendant classes
134
+ #
135
+ # This is used by the setup
136
+ #
137
+ # @param [Hash] repositories
138
+ # @param [Array] descendants a list of relation descendants
139
+ #
140
+ # @return [Hash]
141
+ #
142
+ # @api private
143
+ def registry(repositories, descendants)
144
+ registry = {}
145
+
146
+ descendants.each do |klass|
147
+ # TODO: raise a meaningful error here and add spec covering the case
148
+ # where klass' repository points to non-existant repo
149
+ repository = repositories.fetch(klass.repository)
150
+ dataset = repository.dataset(klass.dataset)
151
+
152
+ relation = klass.new(dataset, __registry__: registry)
153
+
154
+ name = klass.register_as
155
+
156
+ if registry.key?(name)
157
+ raise RelationAlreadyDefinedError,
158
+ "Relation with `register_as #{name.inspect}` registered more " \
159
+ "than once"
160
+ end
161
+
162
+ registry[name] = relation
163
+ end
164
+
165
+ registry.each_value do |relation|
166
+ relation.class.finalize(registry, relation)
167
+ end
168
+
169
+ registry
170
+ end
171
+
172
+ # Hook to finalize a relation after its instance was created
173
+ #
174
+ # @api private
175
+ def finalize(_env, _relation)
176
+ # noop
177
+ end
178
+ end
179
+ end
180
+ end