rom 0.8.1 → 0.9.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|