rom 0.6.0 → 0.6.1

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 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
  - - ">="