smart_properties 1.13.1 → 1.14.0
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 +5 -5
- data/.gitignore +2 -1
- data/.ruby-version +1 -1
- data/README.md +10 -0
- data/lib/smart_properties.rb +1 -0
- data/lib/smart_properties/property.rb +12 -2
- data/lib/smart_properties/property_collection.rb +3 -1
- data/lib/smart_properties/validations.rb +8 -0
- data/lib/smart_properties/validations/ancestor.rb +27 -0
- data/lib/smart_properties/version.rb +1 -1
- data/spec/property_collection_caching_spec.rb +10 -0
- data/spec/validations/ancestor_validation_spec.rb +62 -0
- data/spec/writable_spec.rb +39 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 845948d63c5a647048b44f96e405808bdf3697430323a9ebf29b57c13ed157c9
|
4
|
+
data.tar.gz: be7cc4c03ab7bcba3dbdaea8a04676ada44f50f07d3f5a323926098af6560c97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc5370fce67258915440c7e6fe3b02b1207d04ab1716be3f22b478f7ebf1d22807115b2f7aa7639b82030ad4309a69941606b20d6a64815e9afacd4fb48cdafb
|
7
|
+
data.tar.gz: 003da1d3daab182873e5ccd4ba6359707309fc06161f095c52803cfd6e1d3cb055c0baa59886aaed8b51f3eb5d05d4c6efdfc6188445a6e6de8d4c48a607b8ec
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.2
|
data/README.md
CHANGED
@@ -171,6 +171,16 @@ class Article
|
|
171
171
|
end
|
172
172
|
```
|
173
173
|
|
174
|
+
There are also a set of common validation helpers you may use. These common
|
175
|
+
cases are provided to help avoid rewriting validation logic that occurs
|
176
|
+
often. These validations can be found in the `SmartProperties::Validations` module.
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
class Article
|
180
|
+
property :view_count, accepts: Ancestor.must_be(Number)
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
174
184
|
#### Default values
|
175
185
|
|
176
186
|
There is also support for default values. Simply use the `:default`
|
data/lib/smart_properties.rb
CHANGED
@@ -7,6 +7,7 @@ module SmartProperties
|
|
7
7
|
attr_reader :accepter
|
8
8
|
attr_reader :reader
|
9
9
|
attr_reader :instance_variable_name
|
10
|
+
attr_reader :writable
|
10
11
|
|
11
12
|
def self.define(scope, name, options = {})
|
12
13
|
new(name, options).tap { |p| p.define(scope) }
|
@@ -21,6 +22,7 @@ module SmartProperties
|
|
21
22
|
@accepter = attrs.delete(:accepts)
|
22
23
|
@required = attrs.delete(:required)
|
23
24
|
@reader = attrs.delete(:reader)
|
25
|
+
@writable = attrs.delete(:writable)
|
24
26
|
@reader ||= @name
|
25
27
|
|
26
28
|
@instance_variable_name = :"@#{name}"
|
@@ -46,6 +48,11 @@ module SmartProperties
|
|
46
48
|
!null_object?(get(scope))
|
47
49
|
end
|
48
50
|
|
51
|
+
def writable?
|
52
|
+
return true if @writable.nil?
|
53
|
+
@writable
|
54
|
+
end
|
55
|
+
|
49
56
|
def convert(scope, value)
|
50
57
|
return value unless converter
|
51
58
|
return value if null_object?(value)
|
@@ -98,8 +105,11 @@ module SmartProperties
|
|
98
105
|
scope.send(:define_method, reader) do
|
99
106
|
property.get(self)
|
100
107
|
end
|
101
|
-
|
102
|
-
|
108
|
+
|
109
|
+
if writable?
|
110
|
+
scope.send(:define_method, :"#{name}=") do |value|
|
111
|
+
property.set(self, value)
|
112
|
+
end
|
103
113
|
end
|
104
114
|
end
|
105
115
|
|
@@ -6,7 +6,9 @@ module SmartProperties
|
|
6
6
|
|
7
7
|
def self.for(scope)
|
8
8
|
parent = scope.ancestors[1..-1].find do |ancestor|
|
9
|
-
ancestor.ancestors.include?(SmartProperties) &&
|
9
|
+
ancestor.ancestors.include?(SmartProperties) &&
|
10
|
+
ancestor != scope &&
|
11
|
+
ancestor != SmartProperties
|
10
12
|
end
|
11
13
|
|
12
14
|
if parent.nil?
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module SmartProperties
|
3
|
+
module Validations
|
4
|
+
class Ancestor
|
5
|
+
include SmartProperties
|
6
|
+
|
7
|
+
property! :type, accepts: ->(type) { type.is_a?(Class) }
|
8
|
+
|
9
|
+
def validate(klass)
|
10
|
+
klass.is_a?(Class) && klass < type
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_proc
|
14
|
+
validator = self
|
15
|
+
->(klass) { validator.validate(klass) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"subclasses of #{type.to_s}"
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
alias_method :must_be, :new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -26,4 +26,14 @@ RSpec.describe SmartProperties, "property collection caching:" do
|
|
26
26
|
expect(subsubclass.properties.keys - expected_names).to be_empty
|
27
27
|
expect(subsubclass.properties.to_hash.keys - expected_names).to be_empty
|
28
28
|
end
|
29
|
+
|
30
|
+
specify "a SmartProperty enabled object should not check itself for properties if prepended" do
|
31
|
+
expect do
|
32
|
+
base_class = DummyClass.new {
|
33
|
+
prepend Module.new
|
34
|
+
property :title
|
35
|
+
}
|
36
|
+
expect(base_class.new).to have_smart_property(:title)
|
37
|
+
end.not_to raise_error(SystemStackError)
|
38
|
+
end
|
29
39
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'smart_properties/validations/ancestor'
|
4
|
+
|
5
|
+
RSpec.describe SmartProperties::Validations::Ancestor, 'validates ancestor' do
|
6
|
+
context 'used to validate the ancestor of a smart_properties value' do
|
7
|
+
let!(:test_base) do
|
8
|
+
Class.new do
|
9
|
+
def self.to_s
|
10
|
+
'TestBase'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
subject(:klass) do
|
16
|
+
test_base_ref = test_base
|
17
|
+
|
18
|
+
DummyClass.new do
|
19
|
+
property :visible, accepts: SmartProperties::Validations::Ancestor.must_be(type: test_base_ref)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return an error for any non Class based value' do
|
24
|
+
expect { subject.new(visible: true) }
|
25
|
+
.to raise_error(SmartProperties::InvalidValueError, /Only accepts: subclasses of TestBase/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return an error for any Class instance instead of a class type' do
|
29
|
+
non_ancestor_class = Class.new
|
30
|
+
|
31
|
+
expect { subject.new(visible: non_ancestor_class.new) }
|
32
|
+
.to raise_error(SmartProperties::InvalidValueError, /Only accepts: subclasses of TestBase/)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
it 'should return an error for any Class instance instead of a class type even if it is a child' do
|
37
|
+
test_base_child = Class.new(test_base)
|
38
|
+
|
39
|
+
expect { subject.new(visible: test_base_child.new) }
|
40
|
+
.to raise_error(SmartProperties::InvalidValueError, /Only accepts: subclasses of TestBase/)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return an error for a Class type that is not a child of the required ancestor' do
|
44
|
+
non_ancestor_class = Class.new
|
45
|
+
|
46
|
+
expect { subject.new(visible: non_ancestor_class) }
|
47
|
+
.to raise_error(SmartProperties::InvalidValueError, /Only accepts: subclasses of TestBase/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should return an error if the class is the ancestor itself' do
|
51
|
+
expect { subject.new(visible: test_base) }
|
52
|
+
.to raise_error(SmartProperties::InvalidValueError, /Only accepts: subclasses of TestBase/)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should succeed if the given class is a subtype ' do
|
56
|
+
test_valid_class = Class.new(test_base)
|
57
|
+
|
58
|
+
expect { subject.new(visible: test_valid_class) }
|
59
|
+
.not_to raise_error
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe SmartProperties, 'writable properties' do
|
6
|
+
context 'when a property is defined as not writable there should be no accessor for the property' do
|
7
|
+
subject(:klass) { DummyClass.new { property :id, writable: false } }
|
8
|
+
|
9
|
+
it "should throw a no method error when trying to set the property" do
|
10
|
+
new_class_instance = klass.new(id: 42)
|
11
|
+
|
12
|
+
expect(new_class_instance.id).to eq(42)
|
13
|
+
expect { new_class_instance.id = 50 }.to raise_error(NoMethodError)
|
14
|
+
expect(new_class_instance.id).to eq(42)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when a property is defined as writable there should be an accessor available' do
|
19
|
+
subject(:klass) { DummyClass.new { property :id, writable: true } }
|
20
|
+
|
21
|
+
it "should allow changing of the property" do
|
22
|
+
new_class_instance = klass.new(id: 42)
|
23
|
+
|
24
|
+
new_class_instance.id = 50
|
25
|
+
expect(new_class_instance.id).to eq(50)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when writable is not defined on the property it should default to being writable' do
|
30
|
+
subject(:klass) { DummyClass.new { property :id } }
|
31
|
+
|
32
|
+
it "should allow changing of the property" do
|
33
|
+
new_class_instance = klass.new(id: 42)
|
34
|
+
|
35
|
+
new_class_instance.id = 50
|
36
|
+
expect(new_class_instance.id).to eq(50)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
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.
|
4
|
+
version: 1.14.0
|
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: 2019-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -75,6 +75,8 @@ files:
|
|
75
75
|
- lib/smart_properties/errors.rb
|
76
76
|
- lib/smart_properties/property.rb
|
77
77
|
- lib/smart_properties/property_collection.rb
|
78
|
+
- lib/smart_properties/validations.rb
|
79
|
+
- lib/smart_properties/validations/ancestor.rb
|
78
80
|
- lib/smart_properties/version.rb
|
79
81
|
- smart_properties.gemspec
|
80
82
|
- spec/acceptance_checking_spec.rb
|
@@ -89,6 +91,8 @@ files:
|
|
89
91
|
- spec/spec_helper.rb
|
90
92
|
- spec/support/dummy_class.rb
|
91
93
|
- spec/support/smart_property_matcher.rb
|
94
|
+
- spec/validations/ancestor_validation_spec.rb
|
95
|
+
- spec/writable_spec.rb
|
92
96
|
homepage: ''
|
93
97
|
licenses: []
|
94
98
|
metadata: {}
|
@@ -107,8 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
111
|
- !ruby/object:Gem::Version
|
108
112
|
version: '0'
|
109
113
|
requirements: []
|
110
|
-
|
111
|
-
rubygems_version: 2.6.11
|
114
|
+
rubygems_version: 3.0.3
|
112
115
|
signing_key:
|
113
116
|
specification_version: 4
|
114
117
|
summary: SmartProperties – Ruby accessors on steroids
|
@@ -125,3 +128,5 @@ test_files:
|
|
125
128
|
- spec/spec_helper.rb
|
126
129
|
- spec/support/dummy_class.rb
|
127
130
|
- spec/support/smart_property_matcher.rb
|
131
|
+
- spec/validations/ancestor_validation_spec.rb
|
132
|
+
- spec/writable_spec.rb
|