smart_properties 1.13.0 → 1.13.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/README.md +17 -1
- data/dev.yml +7 -0
- data/experiments/initialization_performance.rb +34 -0
- data/lib/smart_properties/property.rb +21 -21
- data/lib/smart_properties/version.rb +1 -1
- data/lib/smart_properties.rb +12 -0
- data/spec/base_spec.rb +37 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b393bac2287b2fc8bc96acdfe0da75ee774d9193
|
4
|
+
data.tar.gz: f6cc1a80370cdd4d2c361c4eaf6b933841747a10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f878809a07157695137651ad2a20daf44b7dbbec3beae5685fc05c9512f6c165a366d6cf9b67256912bc8e1e50acb3fff98245997364560e894d35a816f46c0d
|
7
|
+
data.tar.gz: 70571022057eb569d0b0702e25218d99a052be2506fb63d43262ef31ce869a05f462b38e3dbce681f2368b52516f4321328207cb40f9a0311df5cd9989cb8f8b
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.1
|
data/README.md
CHANGED
@@ -220,7 +220,7 @@ class Person
|
|
220
220
|
end
|
221
221
|
```
|
222
222
|
|
223
|
-
#### Custom
|
223
|
+
#### Custom reader naming
|
224
224
|
|
225
225
|
In Ruby, predicate methods by convention end with a `?`.
|
226
226
|
This convention is violated in the example above, but can easily be fixed by supplying a custom `reader` name:
|
@@ -235,6 +235,22 @@ end
|
|
235
235
|
To ensure backwards compatibility, boolean properties do not automatically change their reader name.
|
236
236
|
It is thus your responsibility to configure the property properly.
|
237
237
|
|
238
|
+
#### Custom reader implementation
|
239
|
+
|
240
|
+
For convenience, it is possible to use the `super` method to access the original reader when overriding a reader.
|
241
|
+
This is recommended over direct access to the instance variable.
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
class Person
|
245
|
+
property :name
|
246
|
+
property! :address
|
247
|
+
|
248
|
+
def name
|
249
|
+
super || address.name
|
250
|
+
end
|
251
|
+
end
|
252
|
+
```
|
253
|
+
|
238
254
|
### Constructor argument forwarding
|
239
255
|
|
240
256
|
The `SmartProperties` initializer forwards anything to the super constructor
|
data/dev.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require_relative '../lib/smart_properties'
|
3
|
+
|
4
|
+
class A
|
5
|
+
include SmartProperties
|
6
|
+
property :a
|
7
|
+
end
|
8
|
+
|
9
|
+
class B < A
|
10
|
+
property :b
|
11
|
+
end
|
12
|
+
|
13
|
+
class C < B
|
14
|
+
property :c
|
15
|
+
end
|
16
|
+
|
17
|
+
class A2
|
18
|
+
def initialize(**attrs)
|
19
|
+
attrs.each { |k, v| send("#{k}=", v) }
|
20
|
+
end
|
21
|
+
attr_accessor :a
|
22
|
+
end
|
23
|
+
|
24
|
+
class B2 < A2
|
25
|
+
attr_accessor :b
|
26
|
+
end
|
27
|
+
|
28
|
+
class C2 < B2
|
29
|
+
attr_accessor :c
|
30
|
+
end
|
31
|
+
|
32
|
+
puts Benchmark.measure { 1_000_000.times { C.new(a: 1, b: 2, c: 3) } }
|
33
|
+
# puts Benchmark.measure { 1_000_000.times { C2.new(a: 1, b: 2, c: 3) } }
|
34
|
+
|
@@ -2,22 +2,6 @@ module SmartProperties
|
|
2
2
|
class Property
|
3
3
|
MODULE_REFERENCE = :"@_smart_properties_method_scope"
|
4
4
|
|
5
|
-
# Defines the two index methods #[] and #[]=. This module will be included
|
6
|
-
# in the SmartProperties method scope.
|
7
|
-
module IndexMethods
|
8
|
-
def [](name)
|
9
|
-
return if name.nil?
|
10
|
-
name = name.to_sym
|
11
|
-
reader = self.class.properties[name].reader
|
12
|
-
public_send(reader) if self.class.properties.key?(name)
|
13
|
-
end
|
14
|
-
|
15
|
-
def []=(name, value)
|
16
|
-
return if name.nil?
|
17
|
-
public_send(:"#{name.to_sym}=", value) if self.class.properties.key?(name)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
5
|
attr_reader :name
|
22
6
|
attr_reader :converter
|
23
7
|
attr_reader :accepter
|
@@ -65,7 +49,13 @@ module SmartProperties
|
|
65
49
|
def convert(scope, value)
|
66
50
|
return value unless converter
|
67
51
|
return value if null_object?(value)
|
68
|
-
|
52
|
+
|
53
|
+
case converter
|
54
|
+
when Symbol
|
55
|
+
converter.to_proc.call(value)
|
56
|
+
else
|
57
|
+
scope.instance_exec(value, &converter)
|
58
|
+
end
|
69
59
|
end
|
70
60
|
|
71
61
|
def default(scope)
|
@@ -99,7 +89,7 @@ module SmartProperties
|
|
99
89
|
if klass.instance_variable_defined?(MODULE_REFERENCE)
|
100
90
|
klass.instance_variable_get(MODULE_REFERENCE)
|
101
91
|
else
|
102
|
-
m = Module.new
|
92
|
+
m = Module.new
|
103
93
|
klass.send(:include, m)
|
104
94
|
klass.instance_variable_set(MODULE_REFERENCE, m)
|
105
95
|
m
|
@@ -132,12 +122,22 @@ module SmartProperties
|
|
132
122
|
scope.instance_variable_get(instance_variable_name)
|
133
123
|
end
|
134
124
|
|
125
|
+
def to_h
|
126
|
+
{
|
127
|
+
accepter: @accepter,
|
128
|
+
converter: @converter,
|
129
|
+
default: @default,
|
130
|
+
instance_variable_name: @instance_variable_name,
|
131
|
+
name: @name,
|
132
|
+
reader: @reader,
|
133
|
+
required: @required
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
135
137
|
private
|
136
138
|
|
137
139
|
def null_object?(object)
|
138
|
-
|
139
|
-
return true if object.nil?
|
140
|
-
false
|
140
|
+
object.nil?
|
141
141
|
rescue NoMethodError => error
|
142
142
|
# BasicObject does not respond to #nil? by default, so we need to double
|
143
143
|
# check if somebody implemented it and it fails internally or if the
|
data/lib/smart_properties.rb
CHANGED
@@ -153,6 +153,18 @@ module SmartProperties
|
|
153
153
|
|
154
154
|
raise SmartProperties::InitializationError.new(self, missing_properties) unless missing_properties.empty?
|
155
155
|
end
|
156
|
+
|
157
|
+
def [](name)
|
158
|
+
return if name.nil?
|
159
|
+
name = name.to_sym
|
160
|
+
reader = self.class.properties[name].reader
|
161
|
+
public_send(reader) if self.class.properties.key?(name)
|
162
|
+
end
|
163
|
+
|
164
|
+
def []=(name, value)
|
165
|
+
return if name.nil?
|
166
|
+
public_send(:"#{name.to_sym}=", value) if self.class.properties.key?(name)
|
167
|
+
end
|
156
168
|
end
|
157
169
|
|
158
170
|
require_relative 'smart_properties/property_collection'
|
data/spec/base_spec.rb
CHANGED
@@ -47,6 +47,13 @@ RSpec.describe SmartProperties do
|
|
47
47
|
|
48
48
|
it { is_expected.to have_smart_property(:title) }
|
49
49
|
|
50
|
+
it "should return a property's configuration with #to_h" do
|
51
|
+
expect(klass.properties.values.first.to_h).to match(
|
52
|
+
accepter: String, converter: :to_title, default: an_instance_of(RSpec::Mocks::Double),
|
53
|
+
instance_variable_name: :@title, name: :title, reader: :title, required: true
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
50
57
|
context "an instance of this class when initialized with no arguments" do
|
51
58
|
subject(:instance) { klass.new }
|
52
59
|
|
@@ -157,4 +164,34 @@ RSpec.describe SmartProperties do
|
|
157
164
|
end
|
158
165
|
end
|
159
166
|
end
|
167
|
+
|
168
|
+
context "when used to build a class that has a property called relation for an arbitrary Relation class" do
|
169
|
+
class Relation
|
170
|
+
attr_reader :equality_tested
|
171
|
+
|
172
|
+
def initialize
|
173
|
+
@equality_tested = false
|
174
|
+
end
|
175
|
+
|
176
|
+
def ==(_)
|
177
|
+
@equality_tested = true
|
178
|
+
false
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
subject(:klass) do
|
183
|
+
DummyClass.new do
|
184
|
+
property :relation, accepts: Relation, required: true
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'with an instance of Relation' do
|
189
|
+
let(:relation) { Relation.new }
|
190
|
+
|
191
|
+
it 'should not execute #== on the object' do
|
192
|
+
instance = klass.new(relation: relation)
|
193
|
+
expect(relation.equality_tested).to eq(false)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
160
197
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_properties
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.13.
|
4
|
+
version: 1.13.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Tennhard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -63,11 +63,14 @@ extensions: []
|
|
63
63
|
extra_rdoc_files: []
|
64
64
|
files:
|
65
65
|
- ".gitignore"
|
66
|
+
- ".ruby-version"
|
66
67
|
- ".yardopts"
|
67
68
|
- Gemfile
|
68
69
|
- LICENSE
|
69
70
|
- README.md
|
70
71
|
- Rakefile
|
72
|
+
- dev.yml
|
73
|
+
- experiments/initialization_performance.rb
|
71
74
|
- lib/smart_properties.rb
|
72
75
|
- lib/smart_properties/errors.rb
|
73
76
|
- lib/smart_properties/property.rb
|
@@ -105,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
108
|
version: '0'
|
106
109
|
requirements: []
|
107
110
|
rubyforge_project:
|
108
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.6.11
|
109
112
|
signing_key:
|
110
113
|
specification_version: 4
|
111
114
|
summary: SmartProperties – Ruby accessors on steroids
|