rom-support 0.1.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29285bc52be91138894978734ea97b5ff8cf1916
4
- data.tar.gz: cb55485edd81dcf8e45a44a0df2c99a8d156ee10
3
+ metadata.gz: 79e147630a7e44dd323b446498ff1e39942b9c17
4
+ data.tar.gz: 27b5f1b27100413d380b2e1d8e0a389ce4bf6443
5
5
  SHA512:
6
- metadata.gz: 7e107d16dcec735f0ce71c4c6f820102f62fee1852b31329a29d6322233ecb0b10ea713939053b4c8a0737f9544dcfcf72cc72fd67a9ee1253872ff6bd8aa3e1
7
- data.tar.gz: 53d9fe73f2c618604142cee6a294d002a9f0f9e0eb0406dbea6697bc57c749c5fa8e2aced4d01aaf225006f72c1eca00b1e4c549747ccb6c5f7b0fb98ab53982
6
+ metadata.gz: 680c23f519ead5ad0db2e0951f38a25eedbe63e8cb7d2cfc1dafdf56faed15361f60c2ac5b48b56b32805be68eb89caba06827e30500d9f6e796e6b6a4c5ddce
7
+ data.tar.gz: 3957e00c4f16d4bee3610772e246a630c01526dd8717010ef76489626974e45bed4b801011cbf1865c012b5ded39327ca58aca7fec19c3a3b39d0f5f1c198c9b
@@ -10,7 +10,7 @@ rvm:
10
10
  - 2.1
11
11
  - 2.2
12
12
  - rbx-2
13
- - jruby
13
+ - jruby-9000
14
14
  - ruby-head
15
15
  - jruby-head
16
16
  env:
@@ -1,3 +1,9 @@
1
- v0.1.0 2015-08-10
1
+ ## v0.1.1 to be released
2
+
3
+ ### Added
4
+
5
+ * Support for `:coercer` option key (nepalez)
6
+
7
+ ## v0.1.0 2015-08-10
2
8
 
3
9
  First public release. The code was ported from rom 0.8.1
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'transproc', github: 'solnic/transproc', branch: 'master'
5
6
  gem 'rom-mapper', github: 'rom-rb/rom-mapper', branch: 'master'
6
7
 
7
8
  group :console do
@@ -1 +1,2 @@
1
+ require 'dry-equalizer'
1
2
  require 'rom/support/constants'
@@ -1,27 +1,41 @@
1
1
  module ROM
2
2
  module AutoCurry
3
3
  def self.extended(klass)
4
- busy = false
5
-
6
4
  klass.define_singleton_method(:method_added) do |name|
7
- return if busy
8
- busy = true
9
- auto_curry(name)
10
- busy = false
5
+ return if auto_curry_busy?
6
+ auto_curry_guard { auto_curry(name) }
11
7
  super(name)
12
8
  end
13
9
  end
14
10
 
15
- def auto_curry(name)
11
+ def auto_curry_guard
12
+ @__auto_curry_busy__ = true
13
+ yield
14
+ ensure
15
+ @__auto_curry_busy__ = false
16
+ end
17
+
18
+ def auto_curry_busy?
19
+ @__auto_curry_busy__ ||= false
20
+ end
21
+
22
+ def auto_curry(name, &block)
16
23
  curried = self.curried
17
24
  meth = instance_method(name)
18
25
  arity = meth.arity
19
26
 
20
27
  define_method(name) do |*args|
21
- if arity < 0 || arity == args.size
22
- meth.bind(self).(*args)
28
+ response =
29
+ if arity < 0 || arity == args.size
30
+ meth.bind(self).(*args)
31
+ else
32
+ curried.new(self, name: name, curry_args: args, arity: arity)
33
+ end
34
+
35
+ if block
36
+ response.instance_exec(&block)
23
37
  else
24
- curried.new(self, name: name, curry_args: args, arity: arity)
38
+ response
25
39
  end
26
40
  end
27
41
  end
@@ -8,12 +8,12 @@ module ROM
8
8
  include Options
9
9
 
10
10
  option :name, type: String, reader: true
11
- option :parent, type: Class, reader: true, parent: Object
11
+ option :parent, type: Class, reader: true, default: Object
12
12
 
13
13
  # Generate a class based on options
14
14
  #
15
15
  # @example
16
- # builder = ROM::ClasBuilder.new(name: 'MyClass')
16
+ # builder = ROM::ClassBuilder.new(name: 'MyClass')
17
17
  #
18
18
  # klass = builder.call
19
19
  # klass.name # => "MyClass"
@@ -1,5 +1,3 @@
1
- require 'equalizer'
2
-
3
1
  module ROM
4
2
  # Helper module for dataset classes
5
3
  #
@@ -33,7 +31,7 @@ module ROM
33
31
  klass.class_eval do
34
32
  extend ClassMethods
35
33
 
36
- include Equalizer.new(:data)
34
+ include Dry::Equalizer(:data)
37
35
 
38
36
  option :row_proc, reader: true, default: proc { |obj| obj.class.row_proc }
39
37
  end
@@ -1,3 +1,5 @@
1
+ require 'transproc'
2
+
1
3
  module ROM
2
4
  # Helper module for classes with a constructor accepting option hash
3
5
  #
@@ -40,39 +42,59 @@ module ROM
40
42
  #
41
43
  # @api private
42
44
  class Option
43
- attr_reader :name, :type, :allow, :default
45
+ attr_reader :name, :reader
44
46
 
45
47
  def initialize(name, options = {})
46
- @name = name
47
- @type = options.fetch(:type) { Object }
48
+ @name = name
48
49
  @reader = options.fetch(:reader) { false }
49
- @allow = options.fetch(:allow) { [] }
50
- @default = options.fetch(:default) { Undefined }
51
- @ivar = :"@#{name}" if @reader
50
+ # Prepares transformations applied by [#transform]
51
+ add_coercer options[:coercer]
52
+ add_default options[:default] if options.key? :default
53
+ add_type_checker options[:type]
54
+ add_value_checker options[:allow]
55
+ add_reader if reader
56
+ end
57
+
58
+ # Takes options of some object, applies current transformations
59
+ # and returns updated options
60
+ #
61
+ # @param [Object] object
62
+ # @param [Hash] options
63
+ #
64
+ # @return [Hash] options
65
+ #
66
+ def transform(object, options)
67
+ transformers.inject(options) { |a, e| e[object, a] }
52
68
  end
53
69
 
54
- def reader?
55
- @reader
70
+ private
71
+
72
+ def transformers
73
+ @transformers ||= []
56
74
  end
57
75
 
58
- def assign_reader_value(object, value)
59
- object.instance_variable_set(@ivar, value)
76
+ def add_reader
77
+ transformers << Transformers[:reader_assigner, name]
60
78
  end
61
79
 
62
- def default?
63
- @default != Undefined
80
+ def add_default(value)
81
+ transformer = value.respond_to?(:call) ? :default_proc : :default_value
82
+ transformers << Transformers[transformer, name, value]
64
83
  end
65
84
 
66
- def default_value(object)
67
- default.is_a?(Proc) ? default.call(object) : default
85
+ def add_coercer(fn)
86
+ return unless fn.is_a?(Proc)
87
+ transformers << Transformers[:coercer, name, fn]
68
88
  end
69
89
 
70
- def type_matches?(value)
71
- value.is_a?(type)
90
+ def add_type_checker(type)
91
+ return unless type.is_a?(Class)
92
+ transformers << Transformers[:type_checker, name, type]
72
93
  end
73
94
 
74
- def allow?(value)
75
- allow.empty? || allow.include?(value)
95
+ def add_value_checker(values)
96
+ return unless values.respond_to?(:include?)
97
+ transformers << Transformers[:value_checker, name, values]
76
98
  end
77
99
  end
78
100
 
@@ -95,18 +117,7 @@ module ROM
95
117
 
96
118
  def process(object, options)
97
119
  ensure_known_options(options)
98
-
99
- each do |name, option|
100
- if option.default? && !options.key?(name)
101
- options[name] = option.default_value(object)
102
- end
103
-
104
- if options.key?(name)
105
- validate_option_value(option, name, options[name])
106
- end
107
-
108
- option.assign_reader_value(object, options[name]) if option.reader?
109
- end
120
+ each { |_, option| options.update option.transform(object, options) }
110
121
  end
111
122
 
112
123
  def names
@@ -122,23 +133,10 @@ module ROM
122
133
  def ensure_known_options(options)
123
134
  options.each_key do |name|
124
135
  @options.fetch(name) do
125
- raise InvalidOptionKeyError,
126
- "#{name.inspect} is not a valid option"
136
+ fail InvalidOptionKeyError, "#{name.inspect} is not a valid option"
127
137
  end
128
138
  end
129
139
  end
130
-
131
- def validate_option_value(option, name, value)
132
- unless option.type_matches?(value)
133
- raise InvalidOptionValueError,
134
- "#{name.inspect}:#{value.inspect} has incorrect type"
135
- end
136
-
137
- unless option.allow?(value)
138
- raise InvalidOptionValueError,
139
- "#{name.inspect}:#{value.inspect} has incorrect value"
140
- end
141
- end
142
140
  end
143
141
 
144
142
  # @api private
@@ -159,12 +157,13 @@ module ROM
159
157
  # @option settings [Boolean] :reader Define a reader? Default: +false+
160
158
  # @option settings [Array] :allow Allow certain values. Default: Allow anything
161
159
  # @option settings [Object] :default Set default value for missing option
160
+ # @option settings [Proc] :coercer Set coercer for assigned option
162
161
  #
163
162
  # @api public
164
163
  def option(name, settings = {})
165
164
  option = Option.new(name, settings)
166
165
  option_definitions.define(option)
167
- attr_reader(name) if option.reader?
166
+ attr_reader(name) if option.reader
168
167
  end
169
168
 
170
169
  # @api private
@@ -194,5 +193,57 @@ module ROM
194
193
  self.class.option_definitions.process(self, options)
195
194
  @options = options.freeze
196
195
  end
196
+
197
+ # Collection of transformers for options
198
+ #
199
+ module Transformers
200
+ extend Transproc::Registry
201
+
202
+ import :identity, from: Transproc::Coercions
203
+
204
+ def self.default_value(_, options, name, value)
205
+ return options if options.key?(name)
206
+ options.merge(name => value)
207
+ end
208
+
209
+ def self.default_proc(object, options, name, fn)
210
+ return options if options.key?(name)
211
+ options.merge(name => fn.call(object))
212
+ end
213
+
214
+ def self.coercer(_, options, name, fn)
215
+ return options unless options.key?(name)
216
+ value = options[name]
217
+ options.merge name => fn[value]
218
+ end
219
+
220
+ def self.type_checker(_, options, name, type)
221
+ return options unless options.key?(name)
222
+ value = options[name]
223
+
224
+ return options if options[name].is_a?(type)
225
+ fail(
226
+ InvalidOptionValueError,
227
+ "#{name.inspect}:#{value.inspect} has incorrect type" \
228
+ " (#{type} is expected)"
229
+ )
230
+ end
231
+
232
+ def self.value_checker(_, options, name, list)
233
+ return options unless options.key?(name)
234
+ value = options[name]
235
+
236
+ return options if list.include?(options[name])
237
+ fail(
238
+ InvalidOptionValueError,
239
+ "#{name.inspect}:#{value.inspect} has incorrect value."
240
+ )
241
+ end
242
+
243
+ def self.reader_assigner(object, options, name)
244
+ object.instance_variable_set(:"@#{name}", options[name])
245
+ options
246
+ end
247
+ end
197
248
  end
198
249
  end
@@ -2,7 +2,7 @@ module ROM
2
2
  # @api private
3
3
  class Registry
4
4
  include Enumerable
5
- include Equalizer.new(:elements)
5
+ include Dry::Equalizer(:elements)
6
6
 
7
7
  class ElementNotFoundError < KeyError
8
8
  def initialize(key, name)
@@ -1,5 +1,5 @@
1
1
  module ROM
2
2
  module Support
3
- VERSION = '0.1.0'.freeze
3
+ VERSION = '1.0.0.beta1'.freeze
4
4
  end
5
5
  end
@@ -15,7 +15,9 @@ Gem::Specification.new do |gem|
15
15
  gem.test_files = `git ls-files -- {spec}/*`.split("\n")
16
16
  gem.license = 'MIT'
17
17
 
18
+ gem.add_runtime_dependency 'dry-equalizer', '~> 0.2'
18
19
  gem.add_runtime_dependency 'wisper', '~> 1.6', '>= 1.6.0'
20
+ gem.add_runtime_dependency 'transproc', '~> 0.4.0'
19
21
 
20
22
  gem.add_development_dependency 'rake', '~> 10.3'
21
23
  gem.add_development_dependency 'rspec', '~> 3.3'
@@ -0,0 +1,53 @@
1
+ require 'rom/support/auto_curry'
2
+
3
+ RSpec.describe ROM::AutoCurry do
4
+ subject(:object) { klass.new }
5
+
6
+ let(:klass) do
7
+ Class.new do
8
+ extend ROM::AutoCurry
9
+
10
+ def self.curried(*)
11
+ self
12
+ end
13
+
14
+ def initialize(*)
15
+ end
16
+
17
+ def arity_0
18
+ 0
19
+ end
20
+
21
+ def arity_1(x)
22
+ x
23
+ end
24
+
25
+ def arity_2(x, y)
26
+ [x,y]
27
+ end
28
+
29
+ def arity_many(*args)
30
+ args
31
+ end
32
+ end
33
+ end
34
+
35
+ it 'auto-curries method with arity == 0' do
36
+ expect(object.arity_0).to be(0)
37
+ end
38
+
39
+ it 'auto-curries method with arity == 1' do
40
+ expect(object.arity_1).to be_instance_of(klass)
41
+ expect(object.arity_1(1)).to be(1)
42
+ end
43
+
44
+ it 'auto-curries method with arity > 0' do
45
+ expect(object.arity_2).to be_instance_of(klass)
46
+ expect(object.arity_2(1, 2)).to eql([1, 2])
47
+ end
48
+
49
+ it 'auto-curries method with arity < 0' do
50
+ expect(object.arity_many).to eql([])
51
+ expect(object.arity_many(1, 2)).to eql([1, 2])
52
+ end
53
+ end
@@ -88,6 +88,22 @@ describe ROM::Options do
88
88
  expect(object.options).to eql(args: nil)
89
89
  end
90
90
 
91
+ it 'coerces assigned values' do
92
+ klass.option :number, coercer: -> v { v.to_i }
93
+
94
+ object = klass.new(number: '1')
95
+
96
+ expect(object.options).to eql(number: 1)
97
+ end
98
+
99
+ it 'not coerces default values' do
100
+ klass.option :number, default: '1', coercer: -> v { v.to_i }
101
+
102
+ object = klass.new
103
+
104
+ expect(object.options).to eql(number: '1')
105
+ end
106
+
91
107
  it 'options are frozen' do
92
108
  object = klass.new
93
109
 
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-support
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0.beta1
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-08-10 00:00:00.000000000 Z
11
+ date: 2015-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-equalizer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.2'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: wisper
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +44,20 @@ dependencies:
30
44
  - - ">="
31
45
  - !ruby/object:Gem::Version
32
46
  version: 1.6.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: transproc
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.4.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.4.0
33
61
  - !ruby/object:Gem::Dependency
34
62
  name: rake
35
63
  requirement: !ruby/object:Gem::Requirement
@@ -82,7 +110,6 @@ files:
82
110
  - lib/rom/support/data_proxy.rb
83
111
  - lib/rom/support/deprecations.rb
84
112
  - lib/rom/support/enumerable_dataset.rb
85
- - lib/rom/support/guarded_inheritance_hook.rb
86
113
  - lib/rom/support/inflector.rb
87
114
  - lib/rom/support/inheritance_hook.rb
88
115
  - lib/rom/support/options.rb
@@ -97,6 +124,7 @@ files:
97
124
  - spec/support/constant_leak_finder.rb
98
125
  - spec/support/mutant.rb
99
126
  - spec/unit/rom/support/array_dataset_spec.rb
127
+ - spec/unit/rom/support/auto_curry_spec.rb
100
128
  - spec/unit/rom/support/class_builder_spec.rb
101
129
  - spec/unit/rom/support/enumerable_dataset_spec.rb
102
130
  - spec/unit/rom/support/inflector_spec.rb
@@ -116,9 +144,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
144
  version: '0'
117
145
  required_rubygems_version: !ruby/object:Gem::Requirement
118
146
  requirements:
119
- - - ">="
147
+ - - ">"
120
148
  - !ruby/object:Gem::Version
121
- version: '0'
149
+ version: 1.3.1
122
150
  requirements: []
123
151
  rubyforge_project:
124
152
  rubygems_version: 2.4.5
@@ -126,3 +154,4 @@ signing_key:
126
154
  specification_version: 4
127
155
  summary: Ruby Object Mapper - Support libraries
128
156
  test_files: []
157
+ has_rdoc:
@@ -1,21 +0,0 @@
1
- require 'rom/support/publisher'
2
-
3
- module ROM
4
- module Support
5
- module GuardedInheritanceHook
6
- def self.extended(base)
7
- base.class_eval <<-RUBY
8
- class << self
9
- include ROM::Support::Publisher
10
-
11
- def inherited(klass)
12
- super
13
- return if klass.superclass == #{base}
14
- #{base}.__send__(:broadcast, :inherited, klass)
15
- end
16
- end
17
- RUBY
18
- end
19
- end
20
- end
21
- end