rom 0.6.0 → 0.6.1

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: 6771ee9f6bab9f361d07a23f01fac0dddcf72ee6
4
- data.tar.gz: c88e61d11bab08abeb09c1650a4cec39f89c47e1
3
+ metadata.gz: 865d4e2694bbdadfd473db6464100f268393559d
4
+ data.tar.gz: b676c75f27251e94c18c654213f27129a6be0651
5
5
  SHA512:
6
- metadata.gz: f543134ad51fbfeb9d8c9b6abb2de2eb9ecf492398240056df3db3e3ed2679f3a909d106fdbd72bd5d200d8ce5f21e049250109e679d8c385b60165eab71bf73
7
- data.tar.gz: e758461e01f25ba9cfde075a5b0a36fa3f74a1a114f0c24c21029c4a4b0cca9cbf8a3716c2a32bc2d58d1dd5b455fd42cdd8c678275077d2136c30372df36825
6
+ metadata.gz: e89088463acbd0e5f6f90d599e9d6c8ab2fbc6ef35f9c6f5a12f41c68e5f2a2a471a710ccbc7172568faf750f0cd124abb79a0907b9d4bb9c9d12e3addbd72fa
7
+ data.tar.gz: f4a6d18309f9874329f7d3ec927ec10ea46bfb19e90d2c73fd5c09009c2735294a01eede5f858531fdeae52748ccc3e2b47c25880ddebae619e41862c02b3837
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## v0.6.1 2015-04-04
2
+
3
+ ### Added
4
+
5
+ * Ability to auto-map command result via `rom.command(:rel_name).as(:mapper_name)` (solnic)
6
+
7
+ ### Changed
8
+
9
+ * gemspec no longer specifies required_ruby_version so that rom can be installed on jruby (solnic)
10
+ * Obsolete `Env#readers` was removed (splattael)
11
+
12
+ [Compare v0.6.0...v0.6.1](https://github.com/rom-rb/rom/compare/v0.6.0...v0.6.1)
13
+
1
14
  ## v0.6.0 2015-03-22
2
15
 
3
16
  ### Added
data/Gemfile CHANGED
@@ -9,6 +9,7 @@ end
9
9
 
10
10
  group :test do
11
11
  gem 'virtus'
12
+ gem 'anima'
12
13
  gem 'minitest'
13
14
  gem 'thread_safe'
14
15
  gem 'activesupport'
data/README.md CHANGED
@@ -21,7 +21,7 @@ your datastore.
21
21
  Learn more:
22
22
 
23
23
  * [Introduction](http://rom-rb.org/introduction/)
24
- * [Rails tutorial](http://rom-rb.org/tutorials/rails/)
24
+ * [Rails tutorial](http://rom-rb.org/tutorials/todo-app-with-rails/)
25
25
 
26
26
  ## Adapters
27
27
 
@@ -1,11 +1,33 @@
1
1
  require 'rom/commands/result'
2
2
 
3
3
  module ROM
4
- # Command registry exposes "try" interface for executing commands
4
+ # Specialized registry class for commands
5
5
  #
6
6
  # @api public
7
- class CommandRegistry < Registry
7
+ class CommandRegistry
8
8
  include Commands
9
+ include Options
10
+
11
+ # Internal command registry
12
+ #
13
+ # @return [Registry]
14
+ #
15
+ # @api private
16
+ attr_reader :registry
17
+
18
+ option :mappers, reader: true
19
+ option :mapper, reader: true
20
+
21
+ # @api private
22
+ def initialize(elements, options = {})
23
+ super
24
+ @registry =
25
+ if elements.is_a?(Registry)
26
+ elements
27
+ else
28
+ Registry.new(elements, self.class.name)
29
+ end
30
+ end
9
31
 
10
32
  # Try to execute a command in a block
11
33
  #
@@ -31,5 +53,71 @@ module ROM
31
53
  rescue CommandError => e
32
54
  Result::Failure.new(e)
33
55
  end
56
+
57
+ # Return a command from the registry
58
+ #
59
+ # If mapper is set command will be turned into a composite command with
60
+ # auto-mapping
61
+ #
62
+ # @example
63
+ # create_user = rom.command(:users)[:create]
64
+ # create_user[name: 'Jane']
65
+ #
66
+ # # with mapping, assuming :entity mapper is registered for :users relation
67
+ # create_user = rom.command(:users).as(:entity)[:create]
68
+ # create_user[name: 'Jane'] # => result is send through :entity mapper
69
+ #
70
+ # @param [Symbol] name The name of a registered command
71
+ #
72
+ # @return [Command,Command::Composite]
73
+ #
74
+ # @api public
75
+ def [](name)
76
+ command = registry[name]
77
+ mapper = options[:mapper]
78
+
79
+ if mapper
80
+ command.curry >> mapper
81
+ else
82
+ command
83
+ end
84
+ end
85
+
86
+ # Specify a mapper that should be used for commands from this registry
87
+ #
88
+ # @example
89
+ # entity_commands = rom.command(:users).as(:entity)
90
+ #
91
+ #
92
+ # @param [Symbol] mapper_name The name of a registered mapper
93
+ #
94
+ # @return [CommandRegistry]
95
+ #
96
+ # @api public
97
+ def as(mapper_name)
98
+ with(mapper: mappers[mapper_name])
99
+ end
100
+
101
+ # Return new instance of this registry with updated options
102
+ #
103
+ # @return [CommandRegistry]
104
+ #
105
+ # @api private
106
+ def with(new_options)
107
+ self.class.new(registry, options.merge(new_options))
108
+ end
109
+
110
+ private
111
+
112
+ # Allow retrieving commands using dot-notation
113
+ #
114
+ # @api private
115
+ def method_missing(name, *)
116
+ if registry.key?(name)
117
+ self[name]
118
+ else
119
+ super
120
+ end
121
+ end
34
122
  end
35
123
  end
@@ -57,6 +57,7 @@ module ROM
57
57
  tuples
58
58
  end
59
59
  end
60
+ alias_method :[], :call
60
61
 
61
62
  # Curry this command with provided args
62
63
  #
@@ -29,8 +29,19 @@ module ROM
29
29
  #
30
30
  # @api public
31
31
  def call(*args)
32
- right.call(left.call(*args))
32
+ response = left.call(*args)
33
+
34
+ if result == :one
35
+ if right.is_a?(Command) || right.is_a?(Commands::Composite)
36
+ right.call([response].first)
37
+ else
38
+ right.call([response]).first
39
+ end
40
+ else
41
+ right.call(response)
42
+ end
33
43
  end
44
+ alias_method :[], :call
34
45
 
35
46
  # Compose another composite command from self and other
36
47
  #
@@ -42,6 +53,34 @@ module ROM
42
53
  def >>(other)
43
54
  self.class.new(self, other)
44
55
  end
56
+
57
+ # @api private
58
+ def result
59
+ left.result
60
+ end
61
+
62
+ # @api private
63
+ def respond_to_missing?(name, include_private = false)
64
+ left.respond_to?(name) || super
65
+ end
66
+
67
+ private
68
+
69
+ # Allow calling methods on the left side object
70
+ #
71
+ # @api private
72
+ def method_missing(name, *args, &block)
73
+ if left.respond_to?(name)
74
+ response = left.__send__(name, *args, &block)
75
+ if response.is_a?(left.class)
76
+ self.class.new(response, right)
77
+ else
78
+ response
79
+ end
80
+ else
81
+ super
82
+ end
83
+ end
45
84
  end
46
85
  end
47
86
  end
data/lib/rom/env.rb CHANGED
@@ -17,11 +17,6 @@ module ROM
17
17
  # @api public
18
18
  attr_reader :relations
19
19
 
20
- # @return [ReaderRegistry] reader registry
21
- #
22
- # @api public
23
- attr_reader :readers
24
-
25
20
  # @return [Registry] command registry
26
21
  #
27
22
  # @api public
@@ -33,12 +28,11 @@ module ROM
33
28
  attr_reader :mappers
34
29
 
35
30
  # @api private
36
- def initialize(repositories, relations, mappers, commands, readers = nil)
31
+ def initialize(repositories, relations, mappers, commands)
37
32
  @repositories = repositories
38
33
  @relations = relations
39
34
  @mappers = mappers
40
35
  @commands = commands
41
- @readers = readers
42
36
  freeze
43
37
  end
44
38
 
@@ -69,7 +63,7 @@ module ROM
69
63
  relations[name]
70
64
  end
71
65
 
72
- if mappers.elements.key?(name)
66
+ if mappers.key?(name)
73
67
  relation.to_lazy(mappers: mappers[name])
74
68
  else
75
69
  relation.to_lazy
@@ -92,7 +86,7 @@ module ROM
92
86
  #
93
87
  # @api public
94
88
  def read(name, &block)
95
- warn <<-MSG
89
+ warn <<-MSG.gsub(/^\s+/, '')
96
90
  #{self.class}#read is deprecated.
97
91
  Please use `#{self.class}#relation(#{name.inspect})` instead.
98
92
  For mapping append `.map_with(:your_mapper_name)`
@@ -105,11 +99,19 @@ module ROM
105
99
  #
106
100
  # @example
107
101
  #
102
+ # # plain command returning tuples
108
103
  # rom.command(:users).create
109
104
  #
105
+ # # allow auto-mapping using registered mappers
106
+ # rom.command(:users).as(:entity)
107
+ #
110
108
  # @api public
111
109
  def command(name)
112
- commands[name]
110
+ if mappers.key?(name)
111
+ commands[name].with(mappers: mappers[name])
112
+ else
113
+ commands[name]
114
+ end
113
115
  end
114
116
  end
115
117
  end
@@ -106,6 +106,10 @@ module ROM
106
106
  end
107
107
  end
108
108
 
109
+ def names
110
+ @options.keys
111
+ end
112
+
109
113
  private
110
114
 
111
115
  def each(&block)
@@ -12,9 +12,9 @@ module ROM
12
12
 
13
13
  attr_reader :elements, :name
14
14
 
15
- def initialize(elements = {})
15
+ def initialize(elements = {}, name = self.class.name)
16
16
  @elements = elements
17
- @name = self.class.name
17
+ @name = name
18
18
  end
19
19
 
20
20
  def each(&block)
@@ -22,6 +22,10 @@ module ROM
22
22
  elements.each { |element| yield(element) }
23
23
  end
24
24
 
25
+ def key?(name)
26
+ elements.key?(name)
27
+ end
28
+
25
29
  def [](key)
26
30
  elements.fetch(key) { raise ElementNotFoundError.new(key, name) }
27
31
  end
data/lib/rom/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ROM
2
- VERSION = '0.6.0'.freeze
2
+ VERSION = '0.6.1'.freeze
3
3
  end
data/rom.gemspec CHANGED
@@ -14,7 +14,6 @@ Gem::Specification.new do |gem|
14
14
  gem.files = `git ls-files`.split("\n").reject { |name| name.include?('benchmarks') }
15
15
  gem.test_files = `git ls-files -- {spec}/*`.split("\n")
16
16
  gem.license = 'MIT'
17
- gem.required_ruby_version = '~> 2.0'
18
17
 
19
18
  gem.add_runtime_dependency 'transproc', '~> 0.1', '>= 0.1.2'
20
19
  gem.add_runtime_dependency 'equalizer', '~> 0.0', '>= 0.0.9'
@@ -35,9 +35,33 @@ describe 'Commands / Create' do
35
35
  result :one
36
36
 
37
37
  def execute(user, task)
38
- super(task.merge(name: user[:name]))
38
+ super(task.merge(name: user.to_h[:name]))
39
39
  end
40
40
  end
41
+
42
+ Test::User = Class.new do
43
+ include Anima.new(:name, :email)
44
+ end
45
+
46
+ Test::Task = Class.new do
47
+ include Anima.new(:name, :title)
48
+ end
49
+
50
+ class Test::UserMapper < ROM::Mapper
51
+ relation :users
52
+ register_as :entity
53
+ model Test::User
54
+ attribute :name
55
+ attribute :email
56
+ end
57
+
58
+ class Test::TaskMapper < ROM::Mapper
59
+ relation :tasks
60
+ register_as :entity
61
+ model Test::Task
62
+ attribute :name
63
+ attribute :title
64
+ end
41
65
  end
42
66
 
43
67
  it 'inserts user on successful validation' do
@@ -94,4 +118,53 @@ describe 'Commands / Create' do
94
118
  }.to raise_error(ROM::InvalidOptionValueError)
95
119
  end
96
120
  end
121
+
122
+ describe 'sending result through a mapper' do
123
+ let(:attributes) do
124
+ { name: 'Jane', email: 'jane@doe.org' }
125
+ end
126
+
127
+ it 'uses registered mapper to process the result for :one result' do
128
+ command = rom.command(:users).as(:entity).create
129
+ result = command[attributes]
130
+
131
+ expect(result).to eql(Test::User.new(attributes))
132
+ end
133
+
134
+ it 'with two composed commands respects the :result option' do
135
+ mapper_input = nil
136
+
137
+ mapper = proc do |tuples|
138
+ mapper_input = tuples
139
+ end
140
+
141
+ left = rom.command(:users).as(:entity).create.with(
142
+ name: 'Jane', email: 'jane@doe.org'
143
+ )
144
+
145
+ right = rom.command(:tasks).as(:entity).create.with(
146
+ title: 'Jane task'
147
+ )
148
+
149
+ command = left >> right >> mapper
150
+
151
+ result = command.call
152
+
153
+ task = Test::Task.new(name: 'Jane', title: 'Jane task')
154
+
155
+ expect(mapper_input).to eql([task])
156
+ expect(result).to eql(task)
157
+ end
158
+
159
+ it 'uses registered mapper to process the result for :many results' do
160
+ setup.commands(:users) do
161
+ define(:create_many, type: :create)
162
+ end
163
+
164
+ command = rom.command(:users).as(:entity).create_many
165
+ result = command[attributes]
166
+
167
+ expect(result).to eql([Test::User.new(attributes)])
168
+ end
169
+ end
97
170
  end
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,7 @@ if RUBY_ENGINE == "rbx"
10
10
  end
11
11
 
12
12
  require 'rom'
13
+ require 'anima'
13
14
 
14
15
  begin
15
16
  require 'byebug'
@@ -160,6 +160,23 @@ describe 'Commands' do
160
160
  expect(result).to eql(task_tuple)
161
161
  expect(logs).to include(task_tuple)
162
162
  end
163
+
164
+ it 'forwards methods to the left' do
165
+ user_input = { name: 'Jane' }
166
+ user_tuple = { user_id: 1, name: 'Jane' }
167
+
168
+ create_user = Class.new(ROM::Commands::Create) {
169
+ def execute(user_input)
170
+ relation.insert(user_input)
171
+ end
172
+ }.build(users)
173
+
174
+ command = create_user >> proc {}
175
+
176
+ expect(users).to receive(:insert).with(user_input).and_return(user_tuple)
177
+
178
+ command.with(user_input).call
179
+ end
163
180
  end
164
181
 
165
182
  describe 'access to exposed relations' do
@@ -44,6 +44,15 @@ describe ROM::Env do
44
44
  end
45
45
  end
46
46
 
47
+ describe '#read' do
48
+ it 'returns loaded relation and display a deprecation warning' do
49
+ expect {
50
+ result = rom.read(:users) { |r| r.by_name('Jane') }.as(:name_list)
51
+ expect(result.call).to match_array([{ name: 'Jane' }])
52
+ }.to output(/^ROM::Env#read is deprecated/).to_stderr
53
+ end
54
+ end
55
+
47
56
  describe '#mappers' do
48
57
  it 'returns mappers for all relations' do
49
58
  expect(rom.mappers.users[:name_list]).to_not be(nil)
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: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-22 00:00:00.000000000 Z
11
+ date: 2015-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: transproc
@@ -248,9 +248,9 @@ require_paths:
248
248
  - lib
249
249
  required_ruby_version: !ruby/object:Gem::Requirement
250
250
  requirements:
251
- - - "~>"
251
+ - - ">="
252
252
  - !ruby/object:Gem::Version
253
- version: '2.0'
253
+ version: '0'
254
254
  required_rubygems_version: !ruby/object:Gem::Requirement
255
255
  requirements:
256
256
  - - ">="