eigindir 0.0.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 +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +9 -0
- data/.metrics +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +9 -0
- data/.yardopts +3 -0
- data/Gemfile +7 -0
- data/Guardfile +14 -0
- data/LICENSE +21 -0
- data/README.md +342 -0
- data/Rakefile +22 -0
- data/config/metrics/STYLEGUIDE +230 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +15 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +72 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +6 -0
- data/config/metrics/yardstick.yml +37 -0
- data/eigindir.gemspec +22 -0
- data/lib/eigindir.rb +63 -0
- data/lib/eigindir/api.rb +79 -0
- data/lib/eigindir/coercer.rb +70 -0
- data/lib/eigindir/patches.rb +39 -0
- data/lib/eigindir/version.rb +9 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/tests/eigindir/api_spec.rb +395 -0
- data/spec/tests/eigindir/patches_spec.rb +34 -0
- data/spec/tests/eigindir_spec.rb +86 -0
- metadata +97 -0
data/lib/eigindir.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require_relative "eigindir/patches"
|
4
|
+
require_relative "eigindir/coercer"
|
5
|
+
require_relative "eigindir/api"
|
6
|
+
|
7
|
+
# Module Eigindir provides PORO attributes declaration and coersion
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# class Foo
|
11
|
+
# include Eigindir
|
12
|
+
#
|
13
|
+
# attribute(
|
14
|
+
# :foo,
|
15
|
+
# writer: proc { |val| val.to_i + 1 },
|
16
|
+
# reader: proc { |val| val.to_s }
|
17
|
+
# )
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @author Andrew Kozin <Andrew.Kozin@gmail.com>
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
module Eigindir
|
24
|
+
using Patches
|
25
|
+
|
26
|
+
# Returns the hash of the object's attributes
|
27
|
+
#
|
28
|
+
# @return [Hash]
|
29
|
+
def attributes
|
30
|
+
__readers.zip(__readers.map(&method(:public_send))).to_h
|
31
|
+
end
|
32
|
+
|
33
|
+
# Assigns attributes from hash
|
34
|
+
#
|
35
|
+
# Unknown attributes are ignored
|
36
|
+
#
|
37
|
+
# @param [Hash] options
|
38
|
+
#
|
39
|
+
# @return [self] itself
|
40
|
+
def attributes=(options)
|
41
|
+
options
|
42
|
+
.normalize
|
43
|
+
.slice(*__writers)
|
44
|
+
.each { |key, value| public_send :"#{ key }=", value }
|
45
|
+
end
|
46
|
+
|
47
|
+
# @!parse extend Eigindir::API
|
48
|
+
# @private
|
49
|
+
def self.included(klass)
|
50
|
+
klass.extend API
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def __readers
|
56
|
+
self.class.__send__ :__readers
|
57
|
+
end
|
58
|
+
|
59
|
+
def __writers
|
60
|
+
self.class.__send__ :__writers
|
61
|
+
end
|
62
|
+
|
63
|
+
end # module Eigindir
|
data/lib/eigindir/api.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Eigindir
|
4
|
+
|
5
|
+
# The module provides class-level API
|
6
|
+
#
|
7
|
+
# @author Andrew Kozin <Andrew.Kozin@gmail.com>
|
8
|
+
module API
|
9
|
+
|
10
|
+
# Declares the attribute
|
11
|
+
#
|
12
|
+
# @param (see #attribute_reader)
|
13
|
+
# @option (see #attribute_reader)
|
14
|
+
# @option [Proc, Symbol, String] :reader
|
15
|
+
# The coercer to be used by method getter
|
16
|
+
# @option [Proc, Symbol, String] :writer
|
17
|
+
# The coercer to be used by method writer
|
18
|
+
#
|
19
|
+
# @return [undefined]
|
20
|
+
def attribute(name, coerce: nil, reader: nil, writer: nil, strict: nil)
|
21
|
+
attribute_reader name, coerce: (reader || coerce), strict: strict
|
22
|
+
attribute_writer name, coerce: (writer || coerce), strict: strict
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!method attribute_reader(name, coerce: nil, strict: nil)
|
26
|
+
# Declares the attribute getter
|
27
|
+
#
|
28
|
+
# @param [Symbol, String] name
|
29
|
+
# The name of the attribute
|
30
|
+
# @option [Proc, Symbol, String] :coerce
|
31
|
+
# The coercer for the attribute
|
32
|
+
# @option [Boolean] :strict
|
33
|
+
# Whether +nil+ should be coerced
|
34
|
+
#
|
35
|
+
# @return [undefined]
|
36
|
+
def attribute_reader(name, **options)
|
37
|
+
__declare_reader name, Coercer.new(options)
|
38
|
+
__readers << name.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
# @!method attribute_writer(name, coerce: nil, strict: nil)
|
42
|
+
# Declares the attribute writer
|
43
|
+
#
|
44
|
+
# @param (see #attribute_reader)
|
45
|
+
# @option (see #attribute_reader)
|
46
|
+
#
|
47
|
+
# @return [undefined]
|
48
|
+
def attribute_writer(name, **options)
|
49
|
+
__declare_writer name, Coercer.new(options)
|
50
|
+
__writers << name.to_sym
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def __readers
|
56
|
+
@__readers ||= []
|
57
|
+
end
|
58
|
+
|
59
|
+
def __writers
|
60
|
+
@__writers ||= []
|
61
|
+
end
|
62
|
+
|
63
|
+
def __declare_reader(name, coercer)
|
64
|
+
return attr_reader(name) unless coercer
|
65
|
+
define_method(name) do
|
66
|
+
coercer.call self, instance_variable_get(:"@#{ name }")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def __declare_writer(name, coercer)
|
71
|
+
return attr_writer(name) unless coercer
|
72
|
+
define_method("#{ name }=") do |value|
|
73
|
+
instance_variable_set :"@#{ name }", coercer.call(self, value)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end # module API
|
78
|
+
|
79
|
+
end # module Eigindir
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Eigindir
|
4
|
+
|
5
|
+
# Class Coercer creates the proc to be called by attribute getter and setter
|
6
|
+
#
|
7
|
+
# @author Andrew Kozin <Andrew.Kozin@gmail.com>
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class Coercer
|
11
|
+
|
12
|
+
# Checks the coercer validity and creates its istance
|
13
|
+
#
|
14
|
+
# @option [Proc, Symbol, String, NilClass] :coerce
|
15
|
+
# @option [Boolean] :strict
|
16
|
+
#
|
17
|
+
# @return [Eigindir::Coercer]
|
18
|
+
def self.new(coerce: nil, strict: nil)
|
19
|
+
super if coerce
|
20
|
+
end
|
21
|
+
|
22
|
+
# @private
|
23
|
+
def initialize(coerce: nil, strict: nil)
|
24
|
+
@coerce = coerce
|
25
|
+
@strict = strict
|
26
|
+
check_type
|
27
|
+
check_arity
|
28
|
+
end
|
29
|
+
|
30
|
+
# Coerces a value in a context of some instance
|
31
|
+
#
|
32
|
+
# @param [Object] instance
|
33
|
+
# The object whose method is used to coerce value
|
34
|
+
# @param [Object] value
|
35
|
+
# The value to coerce
|
36
|
+
#
|
37
|
+
# @return [Object] the coerced value
|
38
|
+
def call(instance, value)
|
39
|
+
proc.call(instance, value) if value || strict
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :coerce, :strict, :proc
|
45
|
+
|
46
|
+
def proc
|
47
|
+
coerce.instance_of?(Proc) ? proc_coercer : method_coercer
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_coercer
|
51
|
+
->(instance, value) { instance.__send__ coerce, value }
|
52
|
+
end
|
53
|
+
|
54
|
+
def proc_coercer
|
55
|
+
->(_, value) { coerce.call value }
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_type
|
59
|
+
return if [Proc, String, Symbol].include? coerce.class
|
60
|
+
fail TypeError.new "#{ coerce } is not a Proc, Symbol, or String"
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_arity
|
64
|
+
return unless coerce.instance_of?(Proc) && coerce.arity != 1
|
65
|
+
fail ArgumentError.new "Coercer should take exactly one argument"
|
66
|
+
end
|
67
|
+
|
68
|
+
end # class Coercer
|
69
|
+
|
70
|
+
end # module Eigindir
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Eigindir
|
4
|
+
|
5
|
+
# @api private
|
6
|
+
module Patches
|
7
|
+
|
8
|
+
refine Hash do
|
9
|
+
|
10
|
+
# Returns a new hash whose keys are symbolized
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# { "foo" => "foo", "bar" => { "baz" => "baz" } }.normalize
|
14
|
+
# # => { foo: "foo", bar: { "baz" => "baz" } }
|
15
|
+
#
|
16
|
+
# @return [Hash]
|
17
|
+
def normalize
|
18
|
+
keys.map(&:to_sym).zip(values).to_h
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a new hash with given keys only
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# { foo: "foo", bar: "bar" }.slice(:foo, :baz)
|
25
|
+
# # => { foo: "foo" }
|
26
|
+
#
|
27
|
+
# @param [Array] list The keys to slice from the hash
|
28
|
+
#
|
29
|
+
# @return [Hash]
|
30
|
+
def slice(*list)
|
31
|
+
sliced_keys = keys & list
|
32
|
+
sliced_keys.zip(values_at(*sliced_keys)).to_h
|
33
|
+
end
|
34
|
+
|
35
|
+
end # refine Hash
|
36
|
+
|
37
|
+
end # module Patches
|
38
|
+
|
39
|
+
end # module Eigindir
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,395 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe Eigindir::API do
|
4
|
+
|
5
|
+
let(:coercer) { ->(value) { value.to_s } }
|
6
|
+
let(:klass) do
|
7
|
+
Class.new do
|
8
|
+
extend Eigindir::API
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def coercer(value)
|
13
|
+
value.to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
subject { klass.new }
|
19
|
+
|
20
|
+
shared_examples "adding readonly attribute :foo" do
|
21
|
+
|
22
|
+
it "declares the getter" do
|
23
|
+
expect(subject).to respond_to :foo
|
24
|
+
end
|
25
|
+
|
26
|
+
it "doesn't declare the setter" do
|
27
|
+
expect(subject).not_to respond_to :foo=
|
28
|
+
end
|
29
|
+
|
30
|
+
end # shared example
|
31
|
+
|
32
|
+
shared_examples "adding writeonly attribute :foo" do
|
33
|
+
|
34
|
+
it "declares the setter" do
|
35
|
+
expect(subject).to respond_to :foo=
|
36
|
+
end
|
37
|
+
|
38
|
+
it "doesn't declare the getter" do
|
39
|
+
expect(subject).not_to respond_to :foo
|
40
|
+
end
|
41
|
+
|
42
|
+
end # shared example
|
43
|
+
|
44
|
+
shared_examples "making :foo to coerce something" do
|
45
|
+
|
46
|
+
it "coerces the getter" do
|
47
|
+
subject.instance_eval "@foo = 1"
|
48
|
+
expect(subject.foo).to eq "1"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "doesn't coerce nil" do
|
52
|
+
expect(subject.foo).to be_nil
|
53
|
+
end
|
54
|
+
|
55
|
+
end # shared example
|
56
|
+
|
57
|
+
shared_examples "making :foo to coerce anything" do
|
58
|
+
|
59
|
+
it "coerces the getter" do
|
60
|
+
subject.instance_eval "@foo = 1"
|
61
|
+
expect(subject.foo).to eq "1"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "doesn't coerce nil" do
|
65
|
+
expect(subject.foo).to eq ""
|
66
|
+
end
|
67
|
+
|
68
|
+
end # shared example
|
69
|
+
|
70
|
+
shared_examples "making :foo= to coerce something" do
|
71
|
+
|
72
|
+
it "coerces the setter" do
|
73
|
+
subject.foo = 1
|
74
|
+
expect(subject.instance_eval "@foo").to eq "1"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "doesn't coerce nil" do
|
78
|
+
subject.foo = nil
|
79
|
+
expect(subject.instance_eval "@foo").to be_nil
|
80
|
+
end
|
81
|
+
|
82
|
+
end # shared example
|
83
|
+
|
84
|
+
shared_examples "making :foo= to coerce anything" do
|
85
|
+
|
86
|
+
it "coerces the setter" do
|
87
|
+
subject.foo = 1
|
88
|
+
expect(subject.instance_eval "@foo").to eq "1"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "coerces nil" do
|
92
|
+
subject.foo = nil
|
93
|
+
expect(subject.instance_eval "@foo").to eq ""
|
94
|
+
end
|
95
|
+
|
96
|
+
end # shared example
|
97
|
+
|
98
|
+
shared_examples "reporting a wrong coercer arity" do
|
99
|
+
|
100
|
+
it "fails with ArgumentError" do
|
101
|
+
expect { subject }.to raise_error ArgumentError
|
102
|
+
end
|
103
|
+
|
104
|
+
it "returns a proper error message" do
|
105
|
+
begin
|
106
|
+
subject
|
107
|
+
rescue => error
|
108
|
+
expect(error.message).to eq "Coercer should take exactly one argument"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end # shared example
|
113
|
+
|
114
|
+
shared_examples "reporting a wrong coercer type" do
|
115
|
+
|
116
|
+
it "fails with TypeError" do
|
117
|
+
expect { subject }.to raise_error TypeError
|
118
|
+
end
|
119
|
+
|
120
|
+
it "returns a proper error message" do
|
121
|
+
begin
|
122
|
+
subject
|
123
|
+
rescue => error
|
124
|
+
expect(error.message).to eq "1 is not a Proc, Symbol, or String"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end # shared example
|
129
|
+
|
130
|
+
describe ".attribute_reader" do
|
131
|
+
|
132
|
+
context "without coercer" do
|
133
|
+
|
134
|
+
before { klass.attribute_reader :foo }
|
135
|
+
|
136
|
+
it_behaves_like "adding readonly attribute :foo"
|
137
|
+
|
138
|
+
end # context
|
139
|
+
|
140
|
+
context "with proc coercer" do
|
141
|
+
|
142
|
+
before { klass.attribute_reader :foo, coerce: coercer.to_proc }
|
143
|
+
|
144
|
+
it_behaves_like "adding readonly attribute :foo"
|
145
|
+
it_behaves_like "making :foo to coerce something"
|
146
|
+
|
147
|
+
end # context
|
148
|
+
|
149
|
+
context "with lambda coercer" do
|
150
|
+
|
151
|
+
before { klass.attribute_reader :foo, coerce: coercer }
|
152
|
+
|
153
|
+
it_behaves_like "adding readonly attribute :foo"
|
154
|
+
it_behaves_like "making :foo to coerce something"
|
155
|
+
|
156
|
+
end # context
|
157
|
+
|
158
|
+
context "with a symbolic coercer" do
|
159
|
+
|
160
|
+
before { klass.attribute_reader :foo, coerce: :coercer }
|
161
|
+
|
162
|
+
it_behaves_like "adding readonly attribute :foo"
|
163
|
+
it_behaves_like "making :foo to coerce something"
|
164
|
+
|
165
|
+
end # context
|
166
|
+
|
167
|
+
context "with a string coercer" do
|
168
|
+
|
169
|
+
before { klass.attribute_reader :foo, coerce: "coercer" }
|
170
|
+
|
171
|
+
it_behaves_like "adding readonly attribute :foo"
|
172
|
+
it_behaves_like "making :foo to coerce something"
|
173
|
+
|
174
|
+
end # context
|
175
|
+
|
176
|
+
context "in a strict mode" do
|
177
|
+
|
178
|
+
before { klass.attribute_reader :foo, coerce: coercer, strict: true }
|
179
|
+
|
180
|
+
it_behaves_like "adding readonly attribute :foo"
|
181
|
+
it_behaves_like "making :foo to coerce anything"
|
182
|
+
|
183
|
+
end # context
|
184
|
+
|
185
|
+
context "with coercer that has a wrong type" do
|
186
|
+
|
187
|
+
subject { klass.attribute_reader :foo, coerce: 1 }
|
188
|
+
|
189
|
+
it_behaves_like "reporting a wrong coercer type"
|
190
|
+
|
191
|
+
end # context
|
192
|
+
|
193
|
+
context "with coercer that takes no attributes" do
|
194
|
+
|
195
|
+
subject { klass.attribute_reader :foo, coerce: proc { 1 } }
|
196
|
+
|
197
|
+
it_behaves_like "reporting a wrong coercer arity"
|
198
|
+
|
199
|
+
end # context
|
200
|
+
|
201
|
+
context "with coercer that takes more than one attribute" do
|
202
|
+
|
203
|
+
subject { klass.attribute_reader :foo, coerce: proc { |_, _| 1 } }
|
204
|
+
|
205
|
+
it_behaves_like "reporting a wrong coercer arity"
|
206
|
+
|
207
|
+
end # context
|
208
|
+
|
209
|
+
context "without method name" do
|
210
|
+
|
211
|
+
it "fails with ArgumentError" do
|
212
|
+
expect { klass.attribute_reader }.to raise_error ArgumentError
|
213
|
+
end
|
214
|
+
|
215
|
+
end # context
|
216
|
+
|
217
|
+
end # describe .attribute_reader
|
218
|
+
|
219
|
+
describe ".attribute_writer" do
|
220
|
+
|
221
|
+
context "without coercer" do
|
222
|
+
|
223
|
+
before { klass.attribute_writer :foo }
|
224
|
+
|
225
|
+
it_behaves_like "adding writeonly attribute :foo"
|
226
|
+
|
227
|
+
end # context
|
228
|
+
|
229
|
+
context "with proc coercer" do
|
230
|
+
|
231
|
+
before { klass.attribute_writer :foo, coerce: coercer.to_proc }
|
232
|
+
|
233
|
+
it_behaves_like "adding writeonly attribute :foo"
|
234
|
+
it_behaves_like "making :foo= to coerce something"
|
235
|
+
|
236
|
+
end # context
|
237
|
+
|
238
|
+
context "with lambda coercer" do
|
239
|
+
|
240
|
+
before { klass.attribute_writer :foo, coerce: coercer }
|
241
|
+
|
242
|
+
it_behaves_like "adding writeonly attribute :foo"
|
243
|
+
it_behaves_like "making :foo= to coerce something"
|
244
|
+
|
245
|
+
end # context
|
246
|
+
|
247
|
+
context "with a symbolic coercer" do
|
248
|
+
|
249
|
+
before { klass.attribute_writer :foo, coerce: :coercer }
|
250
|
+
|
251
|
+
it_behaves_like "adding writeonly attribute :foo"
|
252
|
+
it_behaves_like "making :foo= to coerce something"
|
253
|
+
|
254
|
+
end # context
|
255
|
+
|
256
|
+
context "with a string coercer" do
|
257
|
+
|
258
|
+
before { klass.attribute_writer :foo, coerce: "coercer" }
|
259
|
+
|
260
|
+
it_behaves_like "adding writeonly attribute :foo"
|
261
|
+
it_behaves_like "making :foo= to coerce something"
|
262
|
+
|
263
|
+
end # context
|
264
|
+
|
265
|
+
context "in a strict mode" do
|
266
|
+
|
267
|
+
before { klass.attribute_writer :foo, coerce: coercer, strict: true }
|
268
|
+
|
269
|
+
it_behaves_like "adding writeonly attribute :foo"
|
270
|
+
it_behaves_like "making :foo= to coerce anything"
|
271
|
+
|
272
|
+
end # context
|
273
|
+
|
274
|
+
context "with coercer of a wrong type" do
|
275
|
+
|
276
|
+
subject { klass.attribute_writer :foo, coerce: 1 }
|
277
|
+
|
278
|
+
it_behaves_like "reporting a wrong coercer type"
|
279
|
+
|
280
|
+
end # context
|
281
|
+
|
282
|
+
context "with coercer that takes no attributes" do
|
283
|
+
|
284
|
+
subject { klass.attribute_writer :foo, coerce: proc { 1 } }
|
285
|
+
|
286
|
+
it_behaves_like "reporting a wrong coercer arity"
|
287
|
+
|
288
|
+
end # context
|
289
|
+
|
290
|
+
context "with coercer that takes more than one attribute" do
|
291
|
+
|
292
|
+
subject { klass.attribute_writer :foo, coerce: proc { |_, _| 1 } }
|
293
|
+
|
294
|
+
it_behaves_like "reporting a wrong coercer arity"
|
295
|
+
|
296
|
+
end # context
|
297
|
+
|
298
|
+
context "without method name" do
|
299
|
+
|
300
|
+
it "fails with ArgumentError" do
|
301
|
+
expect { klass.attribute_writer }.to raise_error ArgumentError
|
302
|
+
end
|
303
|
+
|
304
|
+
end # context
|
305
|
+
|
306
|
+
end # describe .attribute_reader
|
307
|
+
|
308
|
+
describe ".attribute" do
|
309
|
+
|
310
|
+
let(:other) { proc { |value| value.to_i } }
|
311
|
+
|
312
|
+
context "without coercers" do
|
313
|
+
|
314
|
+
after { klass.attribute :foo }
|
315
|
+
|
316
|
+
it "calls .attribute_writer without coercer" do
|
317
|
+
expect(klass).to receive(:attribute_writer)
|
318
|
+
.with(:foo, coerce: nil, strict: nil)
|
319
|
+
.once
|
320
|
+
end
|
321
|
+
|
322
|
+
it "calls .attribute_reader without coercer" do
|
323
|
+
expect(klass).to receive(:attribute_reader)
|
324
|
+
.with(:foo, coerce: nil, strict: nil)
|
325
|
+
.once
|
326
|
+
end
|
327
|
+
|
328
|
+
end # context
|
329
|
+
|
330
|
+
context "with :coerce" do
|
331
|
+
|
332
|
+
after { klass.attribute :foo, coerce: coercer, strict: true }
|
333
|
+
|
334
|
+
it "calls .attribute_writer with coercer" do
|
335
|
+
expect(klass)
|
336
|
+
.to receive(:attribute_writer)
|
337
|
+
.with(:foo, coerce: coercer, strict: true)
|
338
|
+
.once
|
339
|
+
end
|
340
|
+
|
341
|
+
it "calls .attribute_reader with coercer" do
|
342
|
+
expect(klass)
|
343
|
+
.to receive(:attribute_reader)
|
344
|
+
.with(:foo, coerce: coercer, strict: true)
|
345
|
+
.once
|
346
|
+
end
|
347
|
+
|
348
|
+
end # context
|
349
|
+
|
350
|
+
context "with :writer" do
|
351
|
+
|
352
|
+
after do
|
353
|
+
klass.attribute :foo, coerce: coercer, writer: other, strict: true
|
354
|
+
end
|
355
|
+
|
356
|
+
it "calls .attribute_writer with specific coercer" do
|
357
|
+
expect(klass)
|
358
|
+
.to receive(:attribute_writer)
|
359
|
+
.with(:foo, coerce: other, strict: true)
|
360
|
+
.once
|
361
|
+
end
|
362
|
+
|
363
|
+
it "calls .attribute_reader with common coercer" do
|
364
|
+
expect(klass).to receive(:attribute_reader)
|
365
|
+
.with(:foo, coerce: coercer, strict: true)
|
366
|
+
.once
|
367
|
+
end
|
368
|
+
|
369
|
+
end # context
|
370
|
+
|
371
|
+
context "with :reader" do
|
372
|
+
|
373
|
+
after do
|
374
|
+
klass.attribute :foo, coerce: coercer, reader: other, strict: true
|
375
|
+
end
|
376
|
+
|
377
|
+
it "calls .attribute_writer with common coercer" do
|
378
|
+
expect(klass)
|
379
|
+
.to receive(:attribute_writer)
|
380
|
+
.with(:foo, coerce: coercer, strict: true)
|
381
|
+
.once
|
382
|
+
end
|
383
|
+
|
384
|
+
it "calls .attribute_reader with specific coercer" do
|
385
|
+
expect(klass)
|
386
|
+
.to receive(:attribute_reader)
|
387
|
+
.with(:foo, coerce: other, strict: true)
|
388
|
+
.once
|
389
|
+
end
|
390
|
+
|
391
|
+
end # context
|
392
|
+
|
393
|
+
end # describe .attribute
|
394
|
+
|
395
|
+
end # describe Eigindir::API
|