smart_properties 1.13.0 → 1.13.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 +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
|