rom-support 0.1.0 → 1.0.0.beta1

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: 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