smart_properties 1.8.0 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/smart_properties.rb +2 -1
- data/spec/acceptance_checking_spec.rb +99 -0
- data/spec/base_spec.rb +85 -0
- data/spec/configuration_error_spec.rb +17 -0
- data/spec/conversion_spec.rb +30 -0
- data/spec/default_values_spec.rb +51 -0
- data/spec/inheritance_spec.rb +136 -0
- data/spec/required_values_spec.rb +104 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/dummy_class.rb +9 -0
- metadata +18 -4
- data/spec/smart_properties_spec.rb +0 -794
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01dcc093f88456b5adc03fda8756ce4c82fadf2d
|
4
|
+
data.tar.gz: 02e619aa94f6b2a1106e787f5f4ccfe4745f5b4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba7245f78b5720fe02adbf55f89a87f4a92c6525813fde45160c647f6506a76de3127606c0835c58584562a74ed05e2e106a69590372049983f89168a75014bd
|
7
|
+
data.tar.gz: 7b2ec9c3656e8d361e370118c9ef7f964770541a5ad84b725136796516179d25ddb225ea1fccb643fbe8fbe1408b0a429fdc97fb9227bb1bf15071e77c605c95
|
data/lib/smart_properties.rb
CHANGED
@@ -21,7 +21,7 @@
|
|
21
21
|
# :required => true
|
22
22
|
#
|
23
23
|
module SmartProperties
|
24
|
-
VERSION = "1.8.
|
24
|
+
VERSION = "1.8.1"
|
25
25
|
|
26
26
|
class Error < ::ArgumentError; end
|
27
27
|
class ConfigurationError < Error; end
|
@@ -156,6 +156,7 @@ module SmartProperties
|
|
156
156
|
def prepare(value, scope)
|
157
157
|
raise MissingValueError.new(scope, self) if required?(scope) && value.nil?
|
158
158
|
value = convert(value, scope) unless value.nil?
|
159
|
+
raise MissingValueError.new(scope, self) if required?(scope) && value.nil?
|
159
160
|
raise InvalidValueError.new(scope, self, value) unless accepts?(value, scope)
|
160
161
|
value
|
161
162
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SmartProperties, 'acceptance checking' do
|
4
|
+
context "when used to build a class that has a property called :visible which uses an array of valid values for acceptance checking" do
|
5
|
+
subject(:klass) { DummyClass.new { property :visible, accepts: [true, false] } }
|
6
|
+
|
7
|
+
context "an instance of this class" do
|
8
|
+
subject(:instance) { klass.new }
|
9
|
+
|
10
|
+
it "should allow to set true as value for visible" do
|
11
|
+
expect { instance.visible = true }.to_not raise_error
|
12
|
+
expect { instance[:visible] = true }.to_not raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should allow to set false as value for visible" do
|
16
|
+
expect { instance.visible = false }.to_not raise_error
|
17
|
+
expect { instance[:visible] = false }.to_not raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not allow to set :maybe as value for visible" do
|
21
|
+
exception = SmartProperties::InvalidValueError
|
22
|
+
message = "Dummy does not accept :maybe as value for the property visible"
|
23
|
+
further_expectations = lambda { |error| expect(error.to_hash[:visible]).to eq('does not accept :maybe as value') }
|
24
|
+
|
25
|
+
expect { klass.new visible: :maybe }.to raise_error(exception, message, &further_expectations)
|
26
|
+
expect { klass.new { |i| i.visible = :maybe } }.to raise_error(exception, message, &further_expectations)
|
27
|
+
|
28
|
+
expect { instance.visible = :maybe }.to raise_error(exception, message, &further_expectations)
|
29
|
+
expect { instance[:visible] = :maybe }.to raise_error(exception, message, &further_expectations)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when used to build a class that has a property called :title that accepts either a String or a Symbol" do
|
35
|
+
subject(:klass) { DummyClass.new { property :title, accepts: [String, Symbol] } }
|
36
|
+
|
37
|
+
context "an instance of this class" do
|
38
|
+
subject(:instance) { klass.new }
|
39
|
+
|
40
|
+
it "should accept a String as title" do
|
41
|
+
expect { subject.title = "Test" }.to_not raise_error
|
42
|
+
expect { subject[:title] = "Test" }.to_not raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should accept a Symbol as title" do
|
46
|
+
expect { subject.title = :test }.to_not raise_error
|
47
|
+
expect { subject[:title] = :test }.to_not raise_error
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not an instance of any other type' do
|
51
|
+
exception = SmartProperties::InvalidValueError
|
52
|
+
message = 'Dummy does not accept 13 as value for the property title'
|
53
|
+
further_expectations = lambda { |error| expect(error.to_hash[:title]).to eq('does not accept 13 as value') }
|
54
|
+
|
55
|
+
expect { klass.new title: 13 }.to raise_error(exception, message, &further_expectations)
|
56
|
+
expect { klass.new { |i| i.title = 13 } }.to raise_error(exception, message, &further_expectations)
|
57
|
+
|
58
|
+
expect { instance.title = 13 }.to raise_error(exception, message, &further_expectations)
|
59
|
+
expect { instance[:title] = 13 }.to raise_error(exception, message, &further_expectations)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when used to build a class that has a property called :license_plate which uses a lambda statement for accpetance checking' do
|
65
|
+
subject(:klass) do
|
66
|
+
DummyClass.new do
|
67
|
+
property :license_plate, accepts: lambda { |v| license_plate_pattern.match(v) }
|
68
|
+
|
69
|
+
def license_plate_pattern
|
70
|
+
/\w{1,2} \w{1,2} \d{1,4}/
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'an instance of this class' do
|
76
|
+
subject(:instance) { klass.new }
|
77
|
+
|
78
|
+
it 'should not a accept "invalid" as value for license_plate' do
|
79
|
+
exception = SmartProperties::InvalidValueError
|
80
|
+
message = 'Dummy does not accept "invalid" as value for the property license_plate'
|
81
|
+
further_expectations = lambda { |error| expect(error.to_hash[:license_plate]).to eq('does not accept "invalid" as value') }
|
82
|
+
|
83
|
+
expect { klass.new license_plate: "invalid" }.to raise_error(exception, message, &further_expectations)
|
84
|
+
expect { klass.new { |i| i.license_plate = "invalid" } }.to raise_error(exception, message, &further_expectations)
|
85
|
+
|
86
|
+
expect { instance.license_plate = "invalid" }.to raise_error(exception, message, &further_expectations)
|
87
|
+
expect { instance[:license_plate] = "invalid" }.to raise_error(exception, message, &further_expectations)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should accept "NE RD 1337" as license plate' do
|
91
|
+
expect { klass.new.license_plate = "NE RD 1337" }.to_not raise_error
|
92
|
+
expect { klass.new { |i| i.license_plate = "NE RD 1337" } }.to_not raise_error
|
93
|
+
|
94
|
+
expect { instance.license_plate = "NE RD 1337" }.to_not raise_error
|
95
|
+
expect { instance[:license_plate] = "NE RD 1337" }.to_not raise_error
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SmartProperties do
|
4
|
+
it 'should add a protected class method called .property when included' do
|
5
|
+
klass = Class.new { include SmartProperties }
|
6
|
+
expect(klass.respond_to?(:property, true)).to eq(true)
|
7
|
+
expect { klass.property }.to raise_error(NoMethodError)
|
8
|
+
end
|
9
|
+
|
10
|
+
context "when used to build a class that has a property called title that utilizes the full feature set of SmartProperties" do
|
11
|
+
subject(:klass) do
|
12
|
+
default_title = double(to_title: 'chunky')
|
13
|
+
|
14
|
+
DummyClass.new do
|
15
|
+
property :title, converts: :to_title, accepts: String, required: true, default: default_title
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it { is_expected.to have_smart_property(:title) }
|
20
|
+
|
21
|
+
context "an instance of this class when initialized with no arguments" do
|
22
|
+
subject(:instance) { klass.new }
|
23
|
+
|
24
|
+
it "should have the default title" do
|
25
|
+
expect(instance.title).to eq('chunky')
|
26
|
+
expect(instance[:title]).to eq('chunky')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should convert all values that are assigned to title into strings when using the #title= method" do
|
30
|
+
instance.title = double(to_title: 'bacon')
|
31
|
+
expect(instance.title).to eq('bacon')
|
32
|
+
|
33
|
+
instance[:title] = double(to_title: 'yummy')
|
34
|
+
expect(instance.title).to eq('yummy')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not allow to assign an object as title that do not respond to #to_title" do
|
38
|
+
exception = NoMethodError
|
39
|
+
message = /undefined method `to_title'/
|
40
|
+
|
41
|
+
expect { instance.title = Object.new }.to raise_error(exception, message)
|
42
|
+
expect { instance[:title] = Object.new }.to raise_error(exception, message)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not allow to assign nil as the title" do
|
46
|
+
exception = SmartProperties::MissingValueError
|
47
|
+
message = "Dummy requires the property title to be set"
|
48
|
+
further_expectations = lambda do |error|
|
49
|
+
expect(error.to_hash[:title]).to eq('must be set')
|
50
|
+
end
|
51
|
+
|
52
|
+
expect { instance.title = nil }.to raise_error(exception, message, &further_expectations)
|
53
|
+
expect { instance[:title] = nil }.to raise_error(exception, message, &further_expectations)
|
54
|
+
|
55
|
+
expect { instance.title = double(to_title: nil) }.to raise_error(exception, message, &further_expectations)
|
56
|
+
expect { instance[:title] = double(to_title: nil) }.to raise_error(exception, message, &further_expectations)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not influence other instances that have been initialized with different attributes" do
|
60
|
+
other_instance = klass.new title: double(to_title: 'Lorem ipsum')
|
61
|
+
|
62
|
+
expect(instance.title).to eq('chunky')
|
63
|
+
expect(other_instance.title).to eq('Lorem ipsum')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'an instance of this class when initialized with a title argument' do
|
68
|
+
it "should have the title specified by the corresponding keyword argument" do
|
69
|
+
instance = klass.new(title: double(to_title: 'bacon'))
|
70
|
+
expect(instance.title).to eq('bacon')
|
71
|
+
expect(instance[:title]).to eq('bacon')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "an instance of this class when initialized with a block" do
|
76
|
+
it "should have the title specified in the block" do
|
77
|
+
instance = klass.new do |c|
|
78
|
+
c.title = double(to_title: 'bacon')
|
79
|
+
end
|
80
|
+
expect(instance.title).to eq('bacon')
|
81
|
+
expect(instance[:title]).to eq('bacon')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SmartProperties, 'configuration error' do
|
4
|
+
subject(:klass) { DummyClass.new }
|
5
|
+
|
6
|
+
context "when defining a property with invalid configuration options" do
|
7
|
+
it "should report all invalid options" do
|
8
|
+
invalid_property_definition = lambda do
|
9
|
+
klass.class_eval do
|
10
|
+
property :title, invalid_option_1: 'boom', invalid_option_2: 'boom', invalid_option_3: 'boom'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
expect(&invalid_property_definition).to raise_error(SmartProperties::ConfigurationError, "SmartProperties do not support the following configuration options: invalid_option_1, invalid_option_2, invalid_option_3.")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SmartProperties, 'conversion' do
|
4
|
+
context "when defining a class with a property whose converter is an object that responds to #to_proc" do
|
5
|
+
subject(:klass) do
|
6
|
+
converter = double(to_proc: lambda { |t| content_tag(:p, t.to_s) })
|
7
|
+
DummyClass.new do
|
8
|
+
property :title, converts: converter
|
9
|
+
|
10
|
+
def content_tag(name, content)
|
11
|
+
"<%s>%s</%s>" % [name, content, name]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "an instance of this class" do
|
17
|
+
subject(:instance) { klass.new }
|
18
|
+
|
19
|
+
it "should convert the property using the proc" do
|
20
|
+
instance = klass.new title: 'Chunky Bacon'
|
21
|
+
expect(instance.title).to eq("<p>Chunky Bacon</p>")
|
22
|
+
expect(instance[:title]).to eq("<p>Chunky Bacon</p>")
|
23
|
+
|
24
|
+
instance.title = "Lorem Ipsum"
|
25
|
+
expect(instance.title).to eq("<p>Lorem Ipsum</p>")
|
26
|
+
expect(instance[:title]).to eq("<p>Lorem Ipsum</p>")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SmartProperties, 'default values' do
|
4
|
+
context 'when used to build a class that has a property called :id whose default value is a lambda statement for retrieving the object_id' do
|
5
|
+
subject(:klass) { DummyClass.new { property :id, default: lambda { object_id } } }
|
6
|
+
|
7
|
+
context "an instance of this class" do
|
8
|
+
it "should evaluate the lambda in its own scope and thus differ from every other instance" do
|
9
|
+
first_instance, second_instance = klass.new, klass.new
|
10
|
+
expect(klass.new.id).to_not eq(klass.new.id)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when used to build a class that has a property called :boom whose default value is a lambda statement that raises an exception' do
|
16
|
+
subject(:klass) { DummyClass.new { property :boom, default: lambda { raise 'Boom!' } } }
|
17
|
+
|
18
|
+
context "an instance of this class" do
|
19
|
+
it "should raise during initialization if no other value for :boom has been provided" do
|
20
|
+
expect { klass.new }.to raise_error(RuntimeError, 'Boom!')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not evaluate the lambda expression and thus not raise during initialization if a different value for :boom has been provided as a a parameter or in the initalization block" do
|
24
|
+
expect { klass.new(boom: 'Everything is just fine!') }.not_to raise_error
|
25
|
+
expect { klass.new { |inst| inst.boom = 'Everything is just fine!' } }.not_to raise_error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when building a class that has a property with a default value" do
|
31
|
+
subject(:klass) { DummyClass.new { property :title, default: 'Lorem Ipsum' } }
|
32
|
+
|
33
|
+
context 'an instance of that class' do
|
34
|
+
it 'should return nil for the title when the title was explicitly set to this value during initialization' do
|
35
|
+
instance = klass.new(title: nil)
|
36
|
+
expect(instance.title).to be_nil
|
37
|
+
expect(instance[:title]).to be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should return the default value if no other value has been provided during initialization' do
|
41
|
+
instance = klass.new
|
42
|
+
expect(instance.title).to eq('Lorem Ipsum')
|
43
|
+
expect(instance[:title]).to eq('Lorem Ipsum')
|
44
|
+
|
45
|
+
instance = klass.new {}
|
46
|
+
expect(instance.title).to eq('Lorem Ipsum')
|
47
|
+
expect(instance[:title]).to eq('Lorem Ipsum')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SmartProperties, 'intheritance' do
|
4
|
+
context 'when used to build a class that has a required property with no default called :text whose getter is overriden' do
|
5
|
+
subject(:klass) do
|
6
|
+
DummyClass.new do
|
7
|
+
property :text, required: true
|
8
|
+
def text; "<em>#{super}</em>"; end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "an instance of this class should raise an error during initilization if no value for :text has been specified" do
|
13
|
+
expect { klass.new }.to raise_error(SmartProperties::InitializationError)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when modeling the following class hiearchy: Base > Section > SectionWithSubtitle' do
|
18
|
+
let!(:base) do
|
19
|
+
Class.new do
|
20
|
+
attr_reader :content
|
21
|
+
def initialize(content = nil)
|
22
|
+
@content = content
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
let!(:section) { DummyClass.new(base) { property :title } }
|
27
|
+
let!(:subsection) { DummyClass.new(section) { property :subtitle } }
|
28
|
+
|
29
|
+
context 'the base class' do
|
30
|
+
it('should not respond to #properties') { expect(base).to_not respond_to(:properties) }
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'the section class' do
|
34
|
+
it('should respond to #properties') { expect(section).to respond_to(:properties) }
|
35
|
+
|
36
|
+
context 'an instance of this class' do
|
37
|
+
subject { section.new }
|
38
|
+
it { is_expected.to have_smart_property(:title) }
|
39
|
+
it { is_expected.to_not have_smart_property(:subtitle) }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'an instance of this class when initialized with content' do
|
43
|
+
subject(:instance) { section.new('some content') }
|
44
|
+
it('should have content') { expect(instance.content).to eq('some content') }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'the subsectionclass' do
|
49
|
+
it('should respond to #properties') { expect(subsection).to respond_to(:properties) }
|
50
|
+
|
51
|
+
context 'an instance of this class' do
|
52
|
+
subject(:instance) { subsection.new }
|
53
|
+
it { is_expected.to have_smart_property(:title) }
|
54
|
+
it { is_expected.to have_smart_property(:subtitle) }
|
55
|
+
|
56
|
+
it 'should have content, a title, and a subtile when initialized with these parameters' do
|
57
|
+
instance = subsection.new('some content', title: 'some title', subtitle: 'some subtitle')
|
58
|
+
expect(instance.content).to eq('some content')
|
59
|
+
expect(instance.title).to eq('some title')
|
60
|
+
expect(instance.subtitle).to eq('some subtitle')
|
61
|
+
|
62
|
+
instance = subsection.new('some content') do |s|
|
63
|
+
s.title, s.subtitle = 'some title', 'some subtitle'
|
64
|
+
end
|
65
|
+
expect(instance.content).to eq('some content')
|
66
|
+
expect(instance.title).to eq('some title')
|
67
|
+
expect(instance.subtitle).to eq('some subtitle')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when the section class is extended with a property at runtime' do
|
73
|
+
before { section.send(:property, :type) }
|
74
|
+
|
75
|
+
context 'the section class' do
|
76
|
+
subject { section }
|
77
|
+
it { is_expected.to have_smart_property(:type) }
|
78
|
+
|
79
|
+
it 'should have content, a title, and a type when initialized with these parameters' do
|
80
|
+
instance = subsection.new('some content', title: 'some title', type: 'important')
|
81
|
+
expect(instance.content).to eq('some content')
|
82
|
+
expect(instance.title).to eq('some title')
|
83
|
+
expect(instance.type).to eq('important')
|
84
|
+
|
85
|
+
instance = subsection.new('some content') do |s|
|
86
|
+
s.title, s.type = 'some title', 'important'
|
87
|
+
end
|
88
|
+
expect(instance.content).to eq('some content')
|
89
|
+
expect(instance.title).to eq('some title')
|
90
|
+
expect(instance.type).to eq('important')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'the subsection class' do
|
95
|
+
subject { subsection }
|
96
|
+
it { is_expected.to have_smart_property(:type) }
|
97
|
+
|
98
|
+
it 'should have content, a title, a subtitle, and a type when initialized with these parameters' do
|
99
|
+
instance = subsection.new('some content', title: 'some title', subtitle: 'some subtitle', type: 'important')
|
100
|
+
expect(instance.content).to eq('some content')
|
101
|
+
expect(instance.title).to eq('some title')
|
102
|
+
expect(instance.subtitle).to eq('some subtitle')
|
103
|
+
expect(instance.type).to eq('important')
|
104
|
+
|
105
|
+
instance = subsection.new('some content') do |s|
|
106
|
+
s.title, s.subtitle, s.type = 'some title', 'some subtitle', 'important'
|
107
|
+
end
|
108
|
+
expect(instance.content).to eq('some content')
|
109
|
+
expect(instance.title).to eq('some title')
|
110
|
+
expect(instance.subtitle).to eq('some subtitle')
|
111
|
+
expect(instance.type).to eq('important')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when the section class overrides the getter of the title property and uses super to retrieve the property\'s original value' do
|
117
|
+
before do
|
118
|
+
section.class_eval do
|
119
|
+
def title; super.to_s.upcase; end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
specify 'an instance of the section class should transform the value as defined in the overridden getter' do
|
124
|
+
instance = section.new(title: 'some title')
|
125
|
+
expect(instance.title).to eq('SOME TITLE')
|
126
|
+
expect(instance[:title]).to eq('SOME TITLE')
|
127
|
+
end
|
128
|
+
|
129
|
+
specify 'an instance of the subsection class should transform the value as defined in the overridden getter in the superclass' do
|
130
|
+
instance = subsection.new(title: 'some title')
|
131
|
+
expect(instance.title).to eq('SOME TITLE')
|
132
|
+
expect(instance[:title]).to eq('SOME TITLE')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SmartProperties do
|
4
|
+
context "when building a class that has a property which is required and has no default" do
|
5
|
+
subject(:klass) { DummyClass.new { property :title, required: true } }
|
6
|
+
|
7
|
+
context 'an instance of this class' do
|
8
|
+
it 'should have the correct title when provided with a title during initialization' do
|
9
|
+
instance = klass.new title: 'Lorem Ipsum'
|
10
|
+
expect(instance.title).to eq('Lorem Ipsum')
|
11
|
+
expect(instance[:title]).to eq('Lorem Ipsum')
|
12
|
+
|
13
|
+
instance = klass.new { |i| i.title = 'Lorem Ipsum' }
|
14
|
+
expect(instance.title).to eq('Lorem Ipsum')
|
15
|
+
expect(instance[:title]).to eq('Lorem Ipsum')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should raise an error stating that required properties are missing when initialized without a title" do
|
19
|
+
exception = SmartProperties::InitializationError
|
20
|
+
message = "Dummy requires the following properties to be set: title"
|
21
|
+
further_expectations = lambda { |error| expect(error.to_hash[:title]).to eq('must be set') }
|
22
|
+
|
23
|
+
expect { klass.new }.to raise_error(exception, message, &further_expectations)
|
24
|
+
expect { klass.new {} }.to raise_error(exception, message, &further_expectations)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not allow to set nil as the property's value" do
|
28
|
+
instance = klass.new title: 'Lorem Ipsum'
|
29
|
+
|
30
|
+
exception = SmartProperties::MissingValueError
|
31
|
+
message = "Dummy requires the property title to be set"
|
32
|
+
further_expectations = lambda do |error|
|
33
|
+
expect(error.to_hash[:title]).to eq('must be set')
|
34
|
+
end
|
35
|
+
|
36
|
+
expect { instance.title = nil }.to raise_error(exception, message, &further_expectations)
|
37
|
+
expect { instance[:title] = nil }.to raise_error(exception, message, &further_expectations)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when building a class that has a property name which is only required if the property anonymous is set to false" do
|
43
|
+
subject(:klass) do
|
44
|
+
DummyClass.new do
|
45
|
+
property :name, required: lambda { not anonymous }
|
46
|
+
property :anonymous, accepts: [true, false], default: true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not raise an error when created with no arguments" do
|
51
|
+
expect { klass.new }.to_not raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should raise an error indicating that a required property was not specified when created with no name and anonymous being set to false" do
|
55
|
+
exception = SmartProperties::InitializationError
|
56
|
+
message = "Dummy requires the following properties to be set: name"
|
57
|
+
further_expectations = lambda { |error| expect(error.to_hash[:name]).to eq("must be set") }
|
58
|
+
|
59
|
+
expect { klass.new anonymous: false }.to raise_error(exception, message, &further_expectations)
|
60
|
+
expect { klass.new { |i| i.anonymous = false } }.to raise_error(exception, message, &further_expectations)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not raise an error when created with a name and anonymous being set to false" do
|
64
|
+
expect { klass.new name: "John Doe", anonymous: false }.to_not raise_error
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when building a class that has a property which is required and has false as default" do
|
69
|
+
subject(:klass) { DummyClass.new { property :flag, required: true, default: false } }
|
70
|
+
|
71
|
+
context 'an instance of this class' do
|
72
|
+
it 'should return true as value for this property if provided with this value for the property during initialization' do
|
73
|
+
instance = klass.new flag: true
|
74
|
+
expect(instance.flag).to eq(true)
|
75
|
+
expect(instance[:flag]).to eq(true)
|
76
|
+
|
77
|
+
instance = klass.new { |i| i.flag = true }
|
78
|
+
expect(instance.flag).to eq(true)
|
79
|
+
expect(instance[:flag]).to eq(true)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should return false as value for this property when initialized with no arguments' do
|
83
|
+
instance = klass.new
|
84
|
+
expect(instance.flag).to eq(false)
|
85
|
+
expect(instance[:flag]).to eq(false)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when building a class that has a required property with a default value and a malicious converter that always returns nil" do
|
91
|
+
subject(:klass) { DummyClass.new { property :title, required: true, converts: ->(_) { nil }, default: "Lorem Ipsum" } }
|
92
|
+
|
93
|
+
context 'an instance of this class' do
|
94
|
+
it "should raise an error when initialized" do
|
95
|
+
exception = SmartProperties::MissingValueError
|
96
|
+
message = "Dummy requires the property title to be set"
|
97
|
+
further_expectations = lambda { |error| expect(error.to_hash[:title]).to eq("must be set") }
|
98
|
+
|
99
|
+
expect { klass.new }.to raise_error(exception, message)
|
100
|
+
expect { klass.new(title: 'Lorem Ipsum') }.to raise_error(exception, message, &further_expectations)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/spec/spec_helper.rb
CHANGED
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.8.
|
4
|
+
version: 1.8.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: 2015-09-
|
11
|
+
date: 2015-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -57,8 +57,15 @@ files:
|
|
57
57
|
- Rakefile
|
58
58
|
- lib/smart_properties.rb
|
59
59
|
- smart_properties.gemspec
|
60
|
-
- spec/
|
60
|
+
- spec/acceptance_checking_spec.rb
|
61
|
+
- spec/base_spec.rb
|
62
|
+
- spec/configuration_error_spec.rb
|
63
|
+
- spec/conversion_spec.rb
|
64
|
+
- spec/default_values_spec.rb
|
65
|
+
- spec/inheritance_spec.rb
|
66
|
+
- spec/required_values_spec.rb
|
61
67
|
- spec/spec_helper.rb
|
68
|
+
- spec/support/dummy_class.rb
|
62
69
|
- spec/support/smart_property_matcher.rb
|
63
70
|
homepage: ''
|
64
71
|
licenses: []
|
@@ -84,7 +91,14 @@ signing_key:
|
|
84
91
|
specification_version: 4
|
85
92
|
summary: SmartProperties – Ruby accessors on steroids
|
86
93
|
test_files:
|
87
|
-
- spec/
|
94
|
+
- spec/acceptance_checking_spec.rb
|
95
|
+
- spec/base_spec.rb
|
96
|
+
- spec/configuration_error_spec.rb
|
97
|
+
- spec/conversion_spec.rb
|
98
|
+
- spec/default_values_spec.rb
|
99
|
+
- spec/inheritance_spec.rb
|
100
|
+
- spec/required_values_spec.rb
|
88
101
|
- spec/spec_helper.rb
|
102
|
+
- spec/support/dummy_class.rb
|
89
103
|
- spec/support/smart_property_matcher.rb
|
90
104
|
has_rdoc:
|