rom 0.8.1 → 0.9.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +5 -1
- data/lib/rom.rb +35 -16
- data/lib/rom/command.rb +1 -9
- data/lib/rom/commands/graph/class_interface.rb +2 -2
- data/lib/rom/constants.rb +0 -6
- data/lib/rom/{env.rb → container.rb} +3 -3
- data/lib/rom/environment.rb +238 -0
- data/lib/rom/environment_plugin.rb +17 -0
- data/lib/rom/environment_plugins/auto_registration.rb +17 -0
- data/lib/rom/global.rb +0 -203
- data/lib/rom/mapper_registry.rb +2 -0
- data/lib/rom/pipeline.rb +2 -0
- data/lib/rom/plugin.rb +4 -18
- data/lib/rom/plugin_base.rb +31 -0
- data/lib/rom/plugin_registry.rb +54 -17
- data/lib/rom/relation.rb +54 -11
- data/lib/rom/relation/class_interface.rb +14 -21
- data/lib/rom/relation/curried.rb +36 -2
- data/lib/rom/relation/graph.rb +7 -0
- data/lib/rom/relation_registry.rb +4 -0
- data/lib/rom/setup.rb +9 -8
- data/lib/rom/setup/finalize.rb +5 -5
- data/lib/rom/version.rb +1 -1
- data/rom.gemspec +2 -0
- data/spec/integration/commands/create_spec.rb +1 -1
- data/spec/integration/commands/update_spec.rb +1 -1
- data/spec/integration/mappers/unwrap_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/rom/{env_spec.rb → container_spec.rb} +5 -5
- data/spec/unit/rom/plugin_spec.rb +0 -8
- data/spec/unit/rom/relation/composite_spec.rb +2 -2
- data/spec/unit/rom/relation/curried_spec.rb +53 -0
- data/spec/unit/rom/relation/graph_spec.rb +4 -0
- data/spec/unit/rom/relation/lazy/combine_spec.rb +6 -6
- data/spec/unit/rom/relation/lazy_spec.rb +4 -8
- data/spec/unit/rom/relation_spec.rb +0 -14
- data/spec/unit/rom/setup_spec.rb +1 -1
- metadata +52 -35
- data/lib/rom/header.rb +0 -193
- data/lib/rom/header/attribute.rb +0 -184
- data/lib/rom/mapper.rb +0 -103
- data/lib/rom/mapper/attribute_dsl.rb +0 -477
- data/lib/rom/mapper/dsl.rb +0 -119
- data/lib/rom/mapper/model_dsl.rb +0 -55
- data/lib/rom/model_builder.rb +0 -101
- data/lib/rom/processor.rb +0 -28
- data/lib/rom/processor/transproc.rb +0 -388
- data/lib/rom/relation/lazy.rb +0 -145
- data/lib/rom/support/array_dataset.rb +0 -41
- data/lib/rom/support/class_builder.rb +0 -44
- data/lib/rom/support/class_macros.rb +0 -56
- data/lib/rom/support/data_proxy.rb +0 -102
- data/lib/rom/support/deprecations.rb +0 -36
- data/lib/rom/support/enumerable_dataset.rb +0 -65
- data/lib/rom/support/inflector.rb +0 -73
- data/lib/rom/support/options.rb +0 -195
- data/lib/rom/support/registry.rb +0 -43
- data/spec/unit/rom/header_spec.rb +0 -102
- data/spec/unit/rom/mapper/dsl_spec.rb +0 -467
- data/spec/unit/rom/mapper_spec.rb +0 -84
- data/spec/unit/rom/model_builder_spec.rb +0 -46
- data/spec/unit/rom/processor/transproc_spec.rb +0 -448
- data/spec/unit/rom/support/array_dataset_spec.rb +0 -61
- data/spec/unit/rom/support/class_builder_spec.rb +0 -42
- data/spec/unit/rom/support/enumerable_dataset_spec.rb +0 -17
- data/spec/unit/rom/support/inflector_spec.rb +0 -89
- data/spec/unit/rom/support/options_spec.rb +0 -119
data/lib/rom/relation/lazy.rb
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
require 'rom/pipeline'
|
2
|
-
require 'rom/mapper_registry'
|
3
|
-
|
4
|
-
require 'rom/relation/loaded'
|
5
|
-
require 'rom/relation/composite'
|
6
|
-
require 'rom/relation/graph'
|
7
|
-
require 'rom/relation/materializable'
|
8
|
-
|
9
|
-
module ROM
|
10
|
-
class Relation
|
11
|
-
# Lazy relation wraps canonical relation for data-pipelining
|
12
|
-
#
|
13
|
-
# @example
|
14
|
-
# ROM.setup(:memory)
|
15
|
-
#
|
16
|
-
# class Users < ROM::Relation[:memory]
|
17
|
-
# def by_name(name)
|
18
|
-
# restrict(name: name)
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# rom = ROM.finalize.env
|
23
|
-
#
|
24
|
-
# rom.relations.users << { name: 'Jane' }
|
25
|
-
# rom.relations.users << { name: 'Joe' }
|
26
|
-
#
|
27
|
-
# mapper = proc { |users| users.map { |user| user[:name] } }
|
28
|
-
# users = rom.relation(:users)
|
29
|
-
#
|
30
|
-
# (users.by_name >> mapper)['Jane'].inspect # => ["Jane"]
|
31
|
-
#
|
32
|
-
# @api public
|
33
|
-
class Lazy
|
34
|
-
include Equalizer.new(:relation, :options)
|
35
|
-
include Options
|
36
|
-
include Materializable
|
37
|
-
include Pipeline
|
38
|
-
|
39
|
-
option :mappers, reader: true, default: proc { MapperRegistry.new }
|
40
|
-
|
41
|
-
# @return [Relation]
|
42
|
-
#
|
43
|
-
# @api private
|
44
|
-
attr_reader :relation
|
45
|
-
|
46
|
-
# Map of exposed relation methods
|
47
|
-
#
|
48
|
-
# @return [Hash<Symbol=>TrueClass>]
|
49
|
-
#
|
50
|
-
# @api private
|
51
|
-
attr_reader :exposed_relations
|
52
|
-
|
53
|
-
# @api private
|
54
|
-
def initialize(relation, options = {})
|
55
|
-
super
|
56
|
-
@relation = relation
|
57
|
-
@exposed_relations = @relation.exposed_relations
|
58
|
-
end
|
59
|
-
|
60
|
-
# Eager load other relation(s) for this relation
|
61
|
-
#
|
62
|
-
# @param [Array<Relation>] others The other relation(s) to eager load
|
63
|
-
#
|
64
|
-
# @return [Relation::Graph]
|
65
|
-
#
|
66
|
-
# @api public
|
67
|
-
def combine(*others)
|
68
|
-
Graph.build(self, others)
|
69
|
-
end
|
70
|
-
|
71
|
-
# Build a relation pipeline using registered mappers
|
72
|
-
#
|
73
|
-
# @example
|
74
|
-
# rom.relation(:users).map_with(:json_serializer)
|
75
|
-
#
|
76
|
-
# @return [Relation::Composite]
|
77
|
-
#
|
78
|
-
# @api public
|
79
|
-
def map_with(*names)
|
80
|
-
[self, *names.map { |name| mappers[name] }]
|
81
|
-
.reduce { |a, e| Composite.new(a, e) }
|
82
|
-
end
|
83
|
-
alias_method :as, :map_with
|
84
|
-
|
85
|
-
# Load relation
|
86
|
-
#
|
87
|
-
# @return [Relation::Loaded]
|
88
|
-
#
|
89
|
-
# @api public
|
90
|
-
def call
|
91
|
-
Loaded.new(relation)
|
92
|
-
end
|
93
|
-
|
94
|
-
# @api private
|
95
|
-
def respond_to_missing?(name, include_private = false)
|
96
|
-
exposed_relations.include?(name) || super
|
97
|
-
end
|
98
|
-
|
99
|
-
# Return if this lazy relation is curried
|
100
|
-
#
|
101
|
-
# @return [false]
|
102
|
-
#
|
103
|
-
# @api private
|
104
|
-
def curried?
|
105
|
-
false
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
# Forward methods to the underlaying relation
|
111
|
-
#
|
112
|
-
# Auto-curry relations when args size doesn't match arity
|
113
|
-
#
|
114
|
-
# @return [Lazy,Curried]
|
115
|
-
#
|
116
|
-
# @api private
|
117
|
-
def method_missing(meth, *args, &block)
|
118
|
-
if !exposed_relations.include?(meth) || (curried? && name != meth)
|
119
|
-
super
|
120
|
-
else
|
121
|
-
arity = relation.method(meth).arity
|
122
|
-
|
123
|
-
if arity < 0 || arity == args.size
|
124
|
-
response = relation.__send__(meth, *args, &block)
|
125
|
-
|
126
|
-
if response.is_a?(Relation)
|
127
|
-
__new__(response)
|
128
|
-
else
|
129
|
-
response
|
130
|
-
end
|
131
|
-
else
|
132
|
-
Curried.new(relation, name: meth, curry_args: args, arity: arity)
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# Return new lazy relation with updated options
|
138
|
-
#
|
139
|
-
# @api private
|
140
|
-
def __new__(relation, new_opts = {})
|
141
|
-
Lazy.new(relation, options.merge(new_opts))
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'rom/support/enumerable_dataset'
|
2
|
-
|
3
|
-
module ROM
|
4
|
-
# A helper module that adds data-proxy behavior to an array-like object
|
5
|
-
#
|
6
|
-
# @see EnumerableDataset
|
7
|
-
#
|
8
|
-
# @api public
|
9
|
-
module ArrayDataset
|
10
|
-
extend DataProxy::ClassMethods
|
11
|
-
include EnumerableDataset
|
12
|
-
|
13
|
-
# Extends the class with data-proxy behavior
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
def self.included(klass)
|
17
|
-
klass.class_eval do
|
18
|
-
include Options
|
19
|
-
include DataProxy
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
forward(
|
24
|
-
:*, :+, :-, :compact, :compact!, :flatten, :flatten!, :length, :pop,
|
25
|
-
:reverse, :reverse!, :sample, :size, :shift, :shuffle, :shuffle!,
|
26
|
-
:slice, :slice!, :sort!, :uniq, :uniq!, :unshift, :values_at
|
27
|
-
)
|
28
|
-
|
29
|
-
[
|
30
|
-
:map!, :combination, :cycle, :delete_if, :keep_if, :permutation, :reject!,
|
31
|
-
:select!, :sort_by!
|
32
|
-
].each do |method|
|
33
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
34
|
-
def #{method}(*args, &block)
|
35
|
-
return to_enum unless block
|
36
|
-
self.class.new(data.send(:#{method}, *args, &block), options)
|
37
|
-
end
|
38
|
-
RUBY
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module ROM
|
2
|
-
# Internal support class for generating classes
|
3
|
-
#
|
4
|
-
# @private
|
5
|
-
class ClassBuilder
|
6
|
-
include Options
|
7
|
-
|
8
|
-
option :name, type: String, reader: true
|
9
|
-
option :parent, type: Class, reader: true, parent: Object
|
10
|
-
|
11
|
-
# Generate a class based on options
|
12
|
-
#
|
13
|
-
# @example
|
14
|
-
# builder = ROM::ClasBuilder.new(name: 'MyClass')
|
15
|
-
#
|
16
|
-
# klass = builder.call
|
17
|
-
# klass.name # => "MyClass"
|
18
|
-
#
|
19
|
-
# @return [Class]
|
20
|
-
#
|
21
|
-
# @api private
|
22
|
-
def call
|
23
|
-
klass = Class.new(parent)
|
24
|
-
|
25
|
-
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
26
|
-
def self.name
|
27
|
-
#{name.inspect}
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.inspect
|
31
|
-
name
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.to_s
|
35
|
-
name
|
36
|
-
end
|
37
|
-
RUBY
|
38
|
-
|
39
|
-
yield(klass) if block_given?
|
40
|
-
|
41
|
-
klass
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module ROM
|
2
|
-
# Internal support module for class-level settings
|
3
|
-
#
|
4
|
-
# @private
|
5
|
-
module ClassMacros
|
6
|
-
# Specify what macros a class will use
|
7
|
-
#
|
8
|
-
# @example
|
9
|
-
# class MyClass
|
10
|
-
# extend ROM::ClassMacros
|
11
|
-
#
|
12
|
-
# defines :one, :two
|
13
|
-
#
|
14
|
-
# one 1
|
15
|
-
# two 2
|
16
|
-
# end
|
17
|
-
#
|
18
|
-
# class OtherClass < MyClass
|
19
|
-
# two 'two'
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# MyClass.one # => 1
|
23
|
-
# MyClass.two # => 2
|
24
|
-
#
|
25
|
-
# OtherClass.one # => 1
|
26
|
-
# OtherClass.two # => 'two'
|
27
|
-
#
|
28
|
-
# @api private
|
29
|
-
def defines(*args)
|
30
|
-
mod = Module.new
|
31
|
-
|
32
|
-
args.each do |name|
|
33
|
-
mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
34
|
-
def #{name}(value = Undefined)
|
35
|
-
if value == Undefined
|
36
|
-
defined?(@#{name}) && @#{name}
|
37
|
-
else
|
38
|
-
@#{name} = value
|
39
|
-
end
|
40
|
-
end
|
41
|
-
RUBY
|
42
|
-
end
|
43
|
-
|
44
|
-
delegates = args.map { |name| "klass.#{name}(#{name})" }.join("\n")
|
45
|
-
|
46
|
-
mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
47
|
-
def inherited(klass)
|
48
|
-
super
|
49
|
-
#{delegates}
|
50
|
-
end
|
51
|
-
RUBY
|
52
|
-
|
53
|
-
extend(mod)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'equalizer'
|
2
|
-
|
3
|
-
module ROM
|
4
|
-
# Helper module for dataset classes
|
5
|
-
#
|
6
|
-
# It provides a constructor accepting data, header and an optional row_proc.
|
7
|
-
# This module is used internally by EnumerableDataset and ArrayDataset.
|
8
|
-
#
|
9
|
-
# @private
|
10
|
-
module DataProxy
|
11
|
-
NON_FORWARDABLE = [
|
12
|
-
:each, :to_a, :to_ary, :kind_of?, :instance_of?, :is_a?
|
13
|
-
].freeze
|
14
|
-
|
15
|
-
# Wrapped data array
|
16
|
-
#
|
17
|
-
# @return [Object] Data object for the iterator
|
18
|
-
#
|
19
|
-
# @api private
|
20
|
-
attr_reader :data
|
21
|
-
|
22
|
-
# @return [Proc] tuple processing proc
|
23
|
-
#
|
24
|
-
# @api private
|
25
|
-
attr_reader :row_proc
|
26
|
-
|
27
|
-
# Extends the class with `forward` DSL and Equalizer using `data` attribute
|
28
|
-
#
|
29
|
-
# @see ClassMethods#forward
|
30
|
-
#
|
31
|
-
# @api private
|
32
|
-
def self.included(klass)
|
33
|
-
klass.class_eval do
|
34
|
-
extend ClassMethods
|
35
|
-
|
36
|
-
include Equalizer.new(:data)
|
37
|
-
|
38
|
-
option :row_proc, reader: true, default: proc { |obj| obj.class.row_proc }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# @api private
|
43
|
-
def initialize(data, options = {})
|
44
|
-
@data = data
|
45
|
-
super(data, options)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Iterate over data using row_proc
|
49
|
-
#
|
50
|
-
# @return [Enumerator] if block is not given
|
51
|
-
#
|
52
|
-
# @api private
|
53
|
-
def each
|
54
|
-
return to_enum unless block_given?
|
55
|
-
data.each { |tuple| yield(row_proc[tuple]) }
|
56
|
-
end
|
57
|
-
|
58
|
-
module ClassMethods
|
59
|
-
# Default no-op tuple proc
|
60
|
-
#
|
61
|
-
# @return [Proc]
|
62
|
-
#
|
63
|
-
# @api private
|
64
|
-
def row_proc
|
65
|
-
-> tuple { tuple }
|
66
|
-
end
|
67
|
-
|
68
|
-
# Forward provided methods to the underlaying data object
|
69
|
-
#
|
70
|
-
# @example
|
71
|
-
#
|
72
|
-
# class MyDataset
|
73
|
-
# include DataProxy
|
74
|
-
#
|
75
|
-
# forward(:find_all, :map)
|
76
|
-
# end
|
77
|
-
#
|
78
|
-
# @return [undefined]
|
79
|
-
#
|
80
|
-
# @api public
|
81
|
-
def forward(*methods)
|
82
|
-
# FIXME: we should probably raise if one of the non-forwardable methods
|
83
|
-
# was provided
|
84
|
-
(methods - NON_FORWARDABLE).each do |method_name|
|
85
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
86
|
-
def #{method_name}(*args, &block)
|
87
|
-
response = data.public_send(#{method_name.inspect}, *args, &block)
|
88
|
-
|
89
|
-
if response.equal?(data)
|
90
|
-
self
|
91
|
-
elsif response.is_a?(data.class)
|
92
|
-
self.class.new(response)
|
93
|
-
else
|
94
|
-
response
|
95
|
-
end
|
96
|
-
end
|
97
|
-
RUBY
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module ROM
|
2
|
-
module Deprecations
|
3
|
-
# @api private
|
4
|
-
def deprecate(old_name, new_name, msg = nil)
|
5
|
-
class_eval do
|
6
|
-
define_method(old_name) do |*args, &block|
|
7
|
-
ROM::Deprecations.announce "#{self.class}##{old_name} is", <<-MSG
|
8
|
-
Please use #{self.class}##{new_name} instead.
|
9
|
-
#{msg}
|
10
|
-
MSG
|
11
|
-
__send__(new_name, *args, &block)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def deprecate_class_method(old_name, new_name, msg = nil)
|
17
|
-
class_eval do
|
18
|
-
define_singleton_method(old_name) do |*args, &block|
|
19
|
-
ROM::Deprecations.announce"#{self}.#{old_name} is", <<-MSG
|
20
|
-
Please use #{self}.#{new_name} instead.
|
21
|
-
#{msg}
|
22
|
-
MSG
|
23
|
-
__send__(new_name, *args, &block)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.announce(name, msg)
|
29
|
-
warn <<-MSG.gsub(/^\s+/, '')
|
30
|
-
#{name} deprecated and will be removed in 1.0.0.
|
31
|
-
#{msg}
|
32
|
-
#{caller.detect { |l| !l.include?('lib/rom')}}
|
33
|
-
MSG
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'rom/support/data_proxy'
|
2
|
-
|
3
|
-
module ROM
|
4
|
-
# A helper module that adds data-proxy behavior to an enumerable object
|
5
|
-
#
|
6
|
-
# This module is intended to be used by gateways
|
7
|
-
#
|
8
|
-
# Class that includes this module can define `row_proc` class method which
|
9
|
-
# must return a proc-like object which will be used to process each element
|
10
|
-
# in the enumerable
|
11
|
-
#
|
12
|
-
# @example
|
13
|
-
# class MyDataset
|
14
|
-
# include ROM::EnumerableDataset
|
15
|
-
#
|
16
|
-
# def self.row_proc
|
17
|
-
# -> tuple { tuple.each_with_object({}) { |(k,v), h| h[k.to_sym] = v } }
|
18
|
-
# end
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# ds = MyDataset.new([{ 'name' => 'Jane' }, [:name])
|
22
|
-
# ds.to_a # => { :name => 'Jane' }
|
23
|
-
#
|
24
|
-
# @api public
|
25
|
-
module EnumerableDataset
|
26
|
-
extend DataProxy::ClassMethods
|
27
|
-
include Enumerable
|
28
|
-
|
29
|
-
# Coerce a dataset to an array
|
30
|
-
#
|
31
|
-
# @return [Array]
|
32
|
-
#
|
33
|
-
# @api public
|
34
|
-
alias_method :to_ary, :to_a
|
35
|
-
|
36
|
-
# Included hook which extends a class with DataProxy behavior
|
37
|
-
#
|
38
|
-
# This module can also be included into other modules so we apply the
|
39
|
-
# extension only for classes
|
40
|
-
#
|
41
|
-
# @api private
|
42
|
-
def self.included(klass)
|
43
|
-
return unless klass.is_a?(Class)
|
44
|
-
|
45
|
-
klass.class_eval do
|
46
|
-
include Options
|
47
|
-
include DataProxy
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
forward :take
|
52
|
-
|
53
|
-
[
|
54
|
-
:chunk, :collect, :collect_concat, :drop_while, :find_all, :flat_map,
|
55
|
-
:grep, :map, :reject, :select, :sort, :sort_by, :take_while
|
56
|
-
].each do |method|
|
57
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
58
|
-
def #{method}(*args, &block)
|
59
|
-
return to_enum unless block
|
60
|
-
self.class.new(super(*args, &block), options)
|
61
|
-
end
|
62
|
-
RUBY
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|