smart_properties 1.1.0 → 1.2.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.
- data/lib/smart_properties.rb +97 -29
- data/spec/smart_properties_spec.rb +157 -120
- metadata +5 -5
data/lib/smart_properties.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
##
|
2
|
-
# {SmartProperties} can be used to easily build more full-fledged accessors
|
3
|
-
# for standard Ruby classes. In contrast to regular accessors,
|
4
|
-
# {SmartProperties} support validation and conversion of input data, as well
|
5
|
-
# as, the specification of default values. Additionally, individual
|
2
|
+
# {SmartProperties} can be used to easily build more full-fledged accessors
|
3
|
+
# for standard Ruby classes. In contrast to regular accessors,
|
4
|
+
# {SmartProperties} support validation and conversion of input data, as well
|
5
|
+
# as, the specification of default values. Additionally, individual
|
6
6
|
# {SmartProperties} can be marked as required. This causes the runtime to
|
7
7
|
# throw an +ArgumentError+ whenever a required property has not been
|
8
8
|
# specified.
|
9
9
|
#
|
10
|
-
# In order to use {SmartProperties}, simply include the {SmartProperties}
|
10
|
+
# In order to use {SmartProperties}, simply include the {SmartProperties}
|
11
11
|
# module and use the {ClassMethods#property} method to define properties.
|
12
12
|
#
|
13
|
-
# @see ClassMethods#property
|
13
|
+
# @see ClassMethods#property
|
14
14
|
# More information on how to configure properties
|
15
15
|
#
|
16
16
|
# @example Definition of a property that makes use of all {SmartProperties} features.
|
@@ -21,9 +21,9 @@
|
|
21
21
|
# :required => true
|
22
22
|
#
|
23
23
|
module SmartProperties
|
24
|
-
|
25
|
-
VERSION = "1.
|
26
|
-
|
24
|
+
|
25
|
+
VERSION = "1.2.0"
|
26
|
+
|
27
27
|
class Property
|
28
28
|
|
29
29
|
attr_reader :name
|
@@ -32,13 +32,13 @@ module SmartProperties
|
|
32
32
|
|
33
33
|
def initialize(name, attrs = {})
|
34
34
|
attrs = attrs.dup
|
35
|
-
|
35
|
+
|
36
36
|
@name = name.to_sym
|
37
37
|
@default = attrs.delete(:default)
|
38
38
|
@converter = attrs.delete(:converts)
|
39
39
|
@accepter = attrs.delete(:accepts)
|
40
40
|
@required = !!attrs.delete(:required)
|
41
|
-
|
41
|
+
|
42
42
|
unless attrs.empty?
|
43
43
|
raise ArgumentError, "SmartProperties do not support the following configuration options: #{attrs.keys.join(', ')}."
|
44
44
|
end
|
@@ -65,7 +65,7 @@ module SmartProperties
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def default(scope)
|
70
70
|
@default.kind_of?(Proc) ? scope.instance_exec(&@default) : @default
|
71
71
|
end
|
@@ -73,7 +73,7 @@ module SmartProperties
|
|
73
73
|
def accepts?(value, scope)
|
74
74
|
return true unless value
|
75
75
|
return true unless accepter
|
76
|
-
|
76
|
+
|
77
77
|
if accepter.kind_of?(Enumerable)
|
78
78
|
accepter.include?(value)
|
79
79
|
elsif !accepter.kind_of?(Proc)
|
@@ -82,7 +82,7 @@ module SmartProperties
|
|
82
82
|
!!scope.instance_exec(value, &accepter)
|
83
83
|
end
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
def prepare(value, scope)
|
87
87
|
if required? && value.nil?
|
88
88
|
raise ArgumentError, "#{scope.class.name} requires the property #{self.name} to be set"
|
@@ -96,10 +96,10 @@ module SmartProperties
|
|
96
96
|
|
97
97
|
@value = value
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
def define(klass)
|
101
101
|
property = self
|
102
|
-
|
102
|
+
|
103
103
|
scope = klass.instance_variable_get(:"@_smart_properties_method_scope") || begin
|
104
104
|
m = Module.new
|
105
105
|
klass.send(:include, m)
|
@@ -114,21 +114,88 @@ module SmartProperties
|
|
114
114
|
end
|
115
115
|
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
|
+
##
|
119
|
+
# {AttributeBuilder} is a singleton object that builds and keeps track of
|
120
|
+
# annonymous class that can be used to build attribute hashes for smart
|
121
|
+
# property enabled classes.
|
122
|
+
#
|
123
|
+
class << (AttributeBuilder = Object.new)
|
124
|
+
|
125
|
+
##
|
126
|
+
# Returns an attribute builder for a given klass. If the attribute builder
|
127
|
+
# does not exist yet, it is created.
|
128
|
+
#
|
129
|
+
# @return [Class]
|
130
|
+
#
|
131
|
+
def [](klass)
|
132
|
+
store.fetch(klass) { new(property_names_for(klass)) }
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Constructs a hash of attributes for a smart property enabled class using
|
137
|
+
# the instructions provided by the block.
|
138
|
+
#
|
139
|
+
# @return [Hash<String, Object>] Hash of attributes
|
140
|
+
#
|
141
|
+
def build_attributes_for(klass, &block)
|
142
|
+
block.nil? ? {} : self[klass].new(&block).to_hash
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Returns the name of this singleton object.
|
147
|
+
#
|
148
|
+
# @return String
|
149
|
+
#
|
150
|
+
def inspect
|
151
|
+
"AttributeBuilder"
|
152
|
+
end
|
153
|
+
alias :to_s :inspect
|
154
|
+
|
155
|
+
##
|
156
|
+
# Creates a new anonymous class that can act as an attribute builder.
|
157
|
+
#
|
158
|
+
# @return [Class]
|
159
|
+
#
|
160
|
+
def new(fields)
|
161
|
+
Struct.new(*fields) do
|
162
|
+
def initialize(*args, &block)
|
163
|
+
super
|
164
|
+
yield(self) if block
|
165
|
+
end
|
166
|
+
|
167
|
+
def to_hash
|
168
|
+
Hash[members.zip(entries)]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def property_names_for(klass)
|
176
|
+
klass.properties.keys
|
177
|
+
end
|
178
|
+
|
179
|
+
def store
|
180
|
+
@store ||= {}
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
118
185
|
module ClassMethods
|
119
186
|
|
120
187
|
##
|
121
|
-
# Returns
|
122
|
-
#
|
188
|
+
# Returns a class's smart properties. This includes the properties that
|
189
|
+
# have been defined in the parent classes.
|
123
190
|
#
|
124
|
-
# @return [
|
191
|
+
# @return [Hash<String, Property>] A map of property names to property instances.
|
125
192
|
#
|
126
193
|
def properties
|
127
|
-
@_smart_properties ||= begin
|
194
|
+
@_smart_properties ||= begin
|
128
195
|
parent = if self != SmartProperties
|
129
196
|
(ancestors[1..-1].find { |klass| klass.ancestors.include?(SmartProperties) && klass != SmartProperties })
|
130
197
|
end
|
131
|
-
|
198
|
+
|
132
199
|
parent ? parent.properties.dup : {}
|
133
200
|
end
|
134
201
|
end
|
@@ -189,13 +256,13 @@ module SmartProperties
|
|
189
256
|
protected :property
|
190
257
|
|
191
258
|
end
|
192
|
-
|
259
|
+
|
193
260
|
class << self
|
194
|
-
|
261
|
+
|
195
262
|
private
|
196
|
-
|
263
|
+
|
197
264
|
##
|
198
|
-
# Extends the class, which this module is included in, with a property
|
265
|
+
# Extends the class, which this module is included in, with a property
|
199
266
|
# method to define properties.
|
200
267
|
#
|
201
268
|
# @param [Class] base the class this module is included in
|
@@ -203,17 +270,18 @@ module SmartProperties
|
|
203
270
|
def included(base)
|
204
271
|
base.extend(ClassMethods)
|
205
272
|
end
|
206
|
-
|
273
|
+
|
207
274
|
end
|
208
|
-
|
275
|
+
|
209
276
|
##
|
210
277
|
# Implements a key-value enabled constructor that acts as default
|
211
278
|
# constructor for all {SmartProperties}-enabled classes.
|
212
279
|
#
|
213
280
|
# @param [Hash] attrs the set of attributes that is used for initialization
|
214
281
|
#
|
215
|
-
def initialize(attrs = {})
|
282
|
+
def initialize(attrs = {}, &block)
|
216
283
|
attrs ||= {}
|
284
|
+
attrs = attrs.merge(AttributeBuilder.build_attributes_for(self.class, &block)) if block
|
217
285
|
|
218
286
|
self.class.properties.each do |_, property|
|
219
287
|
value = attrs.key?(property.name) ? attrs.delete(property.name) : property.default(self)
|
@@ -13,9 +13,9 @@ describe SmartProperties do
|
|
13
13
|
it "should add a .property method" do
|
14
14
|
subject.should respond_to(:property)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
context "and defining a property with invalid configuration options" do
|
18
|
-
|
18
|
+
|
19
19
|
it "should raise an error reporting one invalid option when one invalid option was given" do
|
20
20
|
expect {
|
21
21
|
subject.tap do |c|
|
@@ -25,7 +25,7 @@ describe SmartProperties do
|
|
25
25
|
end
|
26
26
|
}.to raise_error(ArgumentError, "SmartProperties do not support the following configuration options: invalid_option.")
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it "should raise an error reporting three invalid options when three invalid options were given" do
|
30
30
|
expect {
|
31
31
|
subject.tap do |c|
|
@@ -35,30 +35,30 @@ describe SmartProperties do
|
|
35
35
|
end
|
36
36
|
}.to raise_error(ArgumentError, "SmartProperties do not support the following configuration options: invalid_option_1, invalid_option_2, invalid_option_3.")
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
end
|
40
40
|
|
41
41
|
end
|
42
42
|
|
43
|
-
context "when used to build a class that has a property called :title
|
44
|
-
|
43
|
+
context "when used to build a class that has a property called :title" do
|
44
|
+
|
45
45
|
subject do
|
46
46
|
title = Object.new.tap do |o|
|
47
47
|
def o.to_title; 'chunky'; end
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
klass = Class.new.tap do |c|
|
51
51
|
c.send(:include, described_class)
|
52
52
|
c.instance_eval do
|
53
53
|
def name; "TestDummy"; end
|
54
|
-
|
54
|
+
|
55
55
|
property :title, :accepts => String,
|
56
56
|
:converts => :to_title,
|
57
57
|
:required => true,
|
58
58
|
:default => title
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
klass
|
63
63
|
end
|
64
64
|
|
@@ -66,40 +66,54 @@ describe SmartProperties do
|
|
66
66
|
its(:properties) { should have_key(:title) }
|
67
67
|
|
68
68
|
context "instances of this class" do
|
69
|
-
|
69
|
+
|
70
70
|
klass = subject.call
|
71
|
-
|
71
|
+
|
72
72
|
subject do
|
73
73
|
klass.new
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
it { should respond_to(:title) }
|
77
77
|
it { should respond_to(:title=) }
|
78
|
-
|
78
|
+
|
79
79
|
it "should have 'chucky' as default value for title" do
|
80
80
|
subject.title.should be == 'chunky'
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
it "should convert all values that are assigned to title into strings" do
|
84
84
|
subject.title = double(:to_title => 'bacon')
|
85
85
|
subject.title.should be == 'bacon'
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
it "should not allow to set nil as title" do
|
89
89
|
expect { subject.title = nil }.to raise_error(ArgumentError, "TestDummy requires the property title to be set")
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
it "should not allow to set objects as title that do not respond to #to_title" do
|
93
93
|
expect { subject.title = Object.new }.to raise_error(ArgumentError, "Object does not respond to #to_title")
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
it "should not influence other instances that have been initialized with different attributes" do
|
97
97
|
other = klass.new :title => double(:to_title => 'Lorem ipsum')
|
98
|
-
|
98
|
+
|
99
99
|
subject.title.should be == 'chunky'
|
100
100
|
other.title.should be == 'Lorem ipsum'
|
101
101
|
end
|
102
102
|
|
103
|
+
context "when initialized with a block" do
|
104
|
+
|
105
|
+
subject do
|
106
|
+
klass.new do |c|
|
107
|
+
c.title = double(:to_title => 'bacon')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should have the title specified in the block" do
|
112
|
+
subject.title.should be == 'bacon'
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
103
117
|
end
|
104
118
|
|
105
119
|
context "when subclassed" do
|
@@ -127,25 +141,25 @@ describe SmartProperties do
|
|
127
141
|
end
|
128
142
|
|
129
143
|
context "instances of this subclass that have been intialized from a set of attributes" do
|
130
|
-
|
144
|
+
|
131
145
|
klass = subject.call
|
132
|
-
|
146
|
+
|
133
147
|
subject do
|
134
148
|
klass.new :title => stub(:to_title => 'Message')
|
135
149
|
end
|
136
|
-
|
150
|
+
|
137
151
|
it "should have the correct title" do
|
138
152
|
subject.title.should be == 'Message'
|
139
153
|
end
|
140
|
-
|
154
|
+
|
141
155
|
end
|
142
|
-
|
156
|
+
|
143
157
|
end
|
144
158
|
|
145
159
|
context "when subclassed and extended with a property called text" do
|
146
|
-
|
160
|
+
|
147
161
|
superklass = subject.call
|
148
|
-
|
162
|
+
|
149
163
|
subject do
|
150
164
|
Class.new(superklass).tap do |c|
|
151
165
|
c.instance_eval do
|
@@ -159,55 +173,78 @@ describe SmartProperties do
|
|
159
173
|
its(:properties) { should have_key(:text) }
|
160
174
|
|
161
175
|
context "instances of this subclass" do
|
162
|
-
|
176
|
+
|
163
177
|
klass = subject.call
|
164
|
-
|
178
|
+
|
165
179
|
subject do
|
166
180
|
klass.new
|
167
181
|
end
|
168
|
-
|
182
|
+
|
169
183
|
it { should respond_to(:title) }
|
170
184
|
it { should respond_to(:title=) }
|
171
185
|
it { should respond_to(:text) }
|
172
186
|
it { should respond_to(:text=) }
|
173
|
-
|
187
|
+
|
174
188
|
end
|
175
|
-
|
189
|
+
|
176
190
|
context "instances of the super class" do
|
177
|
-
|
191
|
+
|
178
192
|
subject do
|
179
193
|
superklass.new
|
180
194
|
end
|
181
|
-
|
195
|
+
|
182
196
|
it { should_not respond_to(:text) }
|
183
197
|
it { should_not respond_to(:text=) }
|
184
|
-
|
198
|
+
|
185
199
|
end
|
186
|
-
|
187
|
-
context "instances of this subclass
|
188
|
-
|
200
|
+
|
201
|
+
context "instances of this subclass" do
|
202
|
+
|
189
203
|
klass = subject.call
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
204
|
+
|
205
|
+
context "when initialized with a set of attributes" do
|
206
|
+
|
207
|
+
subject do
|
208
|
+
klass.new :title => stub(:to_title => 'Message'), :text => "Hello"
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should have the correct title" do
|
212
|
+
subject.title.should be == 'Message'
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should have the correct text" do
|
216
|
+
subject.text.should be == 'Hello'
|
217
|
+
end
|
218
|
+
|
197
219
|
end
|
198
|
-
|
199
|
-
|
200
|
-
|
220
|
+
|
221
|
+
context "when initialized with a block" do
|
222
|
+
|
223
|
+
subject do
|
224
|
+
klass.new do |c|
|
225
|
+
c.title = stub(:to_title => 'Message')
|
226
|
+
c.text = "Hello"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should have the title specified in the block" do
|
231
|
+
subject.title.should be == 'Message'
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should have the text specified in the block" do
|
235
|
+
subject.text.should be == 'Hello'
|
236
|
+
end
|
237
|
+
|
201
238
|
end
|
202
|
-
|
239
|
+
|
203
240
|
end
|
204
|
-
|
241
|
+
|
205
242
|
end
|
206
|
-
|
243
|
+
|
207
244
|
context "when extended with a :type property at runtime" do
|
208
|
-
|
245
|
+
|
209
246
|
klass = subject.call
|
210
|
-
|
247
|
+
|
211
248
|
subject do
|
212
249
|
klass.tap do |c|
|
213
250
|
c.instance_eval do
|
@@ -221,50 +258,50 @@ describe SmartProperties do
|
|
221
258
|
its(:properties) { should have_key(:type) }
|
222
259
|
|
223
260
|
context "instances of this class" do
|
224
|
-
|
261
|
+
|
225
262
|
klass = subject.call
|
226
|
-
|
263
|
+
|
227
264
|
subject do
|
228
265
|
klass.new :title => double(:to_title => 'Lorem ipsum')
|
229
266
|
end
|
230
|
-
|
267
|
+
|
231
268
|
it { should respond_to(:type) }
|
232
269
|
it { should respond_to(:type=) }
|
233
|
-
|
270
|
+
|
234
271
|
end
|
235
|
-
|
272
|
+
|
236
273
|
context "when subclassing this class" do
|
237
|
-
|
274
|
+
|
238
275
|
superklass = subject.call
|
239
|
-
|
276
|
+
|
240
277
|
subject do
|
241
278
|
Class.new(superklass)
|
242
279
|
end
|
243
|
-
|
280
|
+
|
244
281
|
context "instances of this class" do
|
245
|
-
|
282
|
+
|
246
283
|
klass = subject.call
|
247
|
-
|
284
|
+
|
248
285
|
subject do
|
249
286
|
klass.new :title => double(:to_title => 'Lorem ipsum')
|
250
287
|
end
|
251
|
-
|
288
|
+
|
252
289
|
it { should respond_to :title }
|
253
290
|
it { should respond_to :title= }
|
254
|
-
|
291
|
+
|
255
292
|
it { should respond_to :type }
|
256
293
|
it { should respond_to :type= }
|
257
|
-
|
294
|
+
|
258
295
|
end
|
259
|
-
|
296
|
+
|
260
297
|
end
|
261
|
-
|
298
|
+
|
262
299
|
end
|
263
|
-
|
300
|
+
|
264
301
|
end
|
265
|
-
|
302
|
+
|
266
303
|
context "when used to build a class that has a property called :title which a lambda statement for conversion" do
|
267
|
-
|
304
|
+
|
268
305
|
subject do
|
269
306
|
Class.new.tap do |c|
|
270
307
|
c.send(:include, described_class)
|
@@ -273,106 +310,106 @@ describe SmartProperties do
|
|
273
310
|
end
|
274
311
|
end
|
275
312
|
end
|
276
|
-
|
313
|
+
|
277
314
|
context "instances of this class" do
|
278
|
-
|
315
|
+
|
279
316
|
klass = subject.call
|
280
|
-
|
317
|
+
|
281
318
|
subject do
|
282
319
|
klass.new
|
283
320
|
end
|
284
|
-
|
321
|
+
|
285
322
|
it "should convert the property title as specified the lambda statement" do
|
286
323
|
subject.title = "Lorem ipsum"
|
287
324
|
subject.title.should be == "<title>Lorem ipsum</title>"
|
288
325
|
end
|
289
|
-
|
326
|
+
|
290
327
|
end
|
291
|
-
|
328
|
+
|
292
329
|
end
|
293
|
-
|
330
|
+
|
294
331
|
context "when used to build a class that has a property called :visible which uses an array of valid values for acceptance checking" do
|
295
|
-
|
332
|
+
|
296
333
|
subject do
|
297
334
|
Class.new.tap do |c|
|
298
335
|
def c.name; "TestDummy"; end
|
299
|
-
|
336
|
+
|
300
337
|
c.send(:include, described_class)
|
301
|
-
|
338
|
+
|
302
339
|
c.instance_eval do
|
303
340
|
property :visible, :accepts => [true, false]
|
304
341
|
end
|
305
342
|
end
|
306
343
|
end
|
307
|
-
|
344
|
+
|
308
345
|
context "instances of this class" do
|
309
|
-
|
346
|
+
|
310
347
|
klass = subject.call
|
311
348
|
|
312
349
|
subject do
|
313
350
|
klass.new
|
314
351
|
end
|
315
|
-
|
352
|
+
|
316
353
|
it "should allow to set true as value for visible" do
|
317
354
|
expect { subject.visible = true }.to_not raise_error
|
318
355
|
end
|
319
|
-
|
356
|
+
|
320
357
|
it "should allow to set false as value for visible" do
|
321
358
|
expect { subject.visible = false }.to_not raise_error
|
322
359
|
end
|
323
|
-
|
360
|
+
|
324
361
|
it "should not allow to set :maybe as value for visible" do
|
325
362
|
expect { subject.visible = :maybe }.to raise_error(ArgumentError, "TestDummy does not accept :maybe as value for the property visible")
|
326
363
|
end
|
327
|
-
|
364
|
+
|
328
365
|
end
|
329
|
-
|
366
|
+
|
330
367
|
end
|
331
|
-
|
368
|
+
|
332
369
|
context 'when used to build a class that has a property called :license_plate which uses a lambda statement for accpetance checking' do
|
333
|
-
|
370
|
+
|
334
371
|
subject do
|
335
372
|
Class.new.tap do |c|
|
336
373
|
def c.name; 'TestDummy'; end
|
337
|
-
|
374
|
+
|
338
375
|
c.send(:include, described_class)
|
339
|
-
|
376
|
+
|
340
377
|
c.instance_eval do
|
341
378
|
property :license_plate, :accepts => lambda { |v| /\w{1,2} \w{1,2} \d{1,4}/.match(v) }
|
342
379
|
end
|
343
380
|
end
|
344
381
|
end
|
345
|
-
|
382
|
+
|
346
383
|
context 'instances of this class' do
|
347
|
-
|
384
|
+
|
348
385
|
klass = subject.call
|
349
|
-
|
386
|
+
|
350
387
|
subject do
|
351
388
|
klass.new
|
352
389
|
end
|
353
|
-
|
390
|
+
|
354
391
|
it 'should not a accept "invalid" as value for license_plate' do
|
355
392
|
expect { subject.license_plate = "invalid" }.to raise_error(ArgumentError, 'TestDummy does not accept "invalid" as value for the property license_plate')
|
356
393
|
end
|
357
|
-
|
394
|
+
|
358
395
|
it 'should accept "NE RD 1337" as license plate' do
|
359
396
|
expect { subject.license_plate = "NE RD 1337" }.to_not raise_error
|
360
397
|
end
|
361
|
-
|
398
|
+
|
362
399
|
end
|
363
|
-
|
400
|
+
|
364
401
|
end
|
365
|
-
|
402
|
+
|
366
403
|
context 'when used to build a class that has a property called :text whose getter is overriden' do
|
367
|
-
|
404
|
+
|
368
405
|
subject do
|
369
406
|
Class.new.tap do |c|
|
370
407
|
c.send(:include, described_class)
|
371
|
-
|
408
|
+
|
372
409
|
c.instance_eval do
|
373
410
|
property :text, :default => 'Hello'
|
374
411
|
end
|
375
|
-
|
412
|
+
|
376
413
|
c.class_eval do
|
377
414
|
def text
|
378
415
|
"<em>#{super}</em>"
|
@@ -380,59 +417,59 @@ describe SmartProperties do
|
|
380
417
|
end
|
381
418
|
end
|
382
419
|
end
|
383
|
-
|
420
|
+
|
384
421
|
context "instances of this class" do
|
385
|
-
|
422
|
+
|
386
423
|
klass = subject.call
|
387
|
-
|
424
|
+
|
388
425
|
subject do
|
389
426
|
klass.new
|
390
427
|
end
|
391
|
-
|
428
|
+
|
392
429
|
it "should return the accepted value for the property called :text" do
|
393
430
|
subject.text.should be == '<em>Hello</em>'
|
394
431
|
end
|
395
|
-
|
432
|
+
|
396
433
|
end
|
397
|
-
|
434
|
+
|
398
435
|
end
|
399
|
-
|
436
|
+
|
400
437
|
context 'when used to build a class that has a property called :id whose default value is a lambda statement' do
|
401
|
-
|
438
|
+
|
402
439
|
subject do
|
403
440
|
counter = Class.new.tap do |c|
|
404
|
-
|
441
|
+
|
405
442
|
c.class_eval do
|
406
443
|
def next
|
407
444
|
@counter ||= 0
|
408
445
|
@counter += 1
|
409
446
|
end
|
410
447
|
end
|
411
|
-
|
448
|
+
|
412
449
|
end.new
|
413
|
-
|
450
|
+
|
414
451
|
Class.new.tap do |c|
|
415
452
|
c.send(:include, described_class)
|
416
|
-
|
453
|
+
|
417
454
|
c.instance_eval do
|
418
455
|
property :id, :default => lambda { counter.next }
|
419
456
|
end
|
420
457
|
end
|
421
458
|
end
|
422
|
-
|
459
|
+
|
423
460
|
context "instances of this class" do
|
424
|
-
|
461
|
+
|
425
462
|
klass = subject.call
|
426
|
-
|
463
|
+
|
427
464
|
it "should have auto-incrementing ids" do
|
428
465
|
first_instance = klass.new
|
429
466
|
second_instance = klass.new
|
430
|
-
|
467
|
+
|
431
468
|
(second_instance.id - first_instance.id).should be == 1
|
432
469
|
end
|
433
|
-
|
470
|
+
|
434
471
|
end
|
435
|
-
|
472
|
+
|
436
473
|
end
|
437
|
-
|
474
|
+
|
438
475
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_properties
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -126,7 +126,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
126
|
version: '0'
|
127
127
|
segments:
|
128
128
|
- 0
|
129
|
-
hash:
|
129
|
+
hash: 2972832392315398871
|
130
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
131
|
none: false
|
132
132
|
requirements:
|
@@ -135,10 +135,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
135
|
version: '0'
|
136
136
|
segments:
|
137
137
|
- 0
|
138
|
-
hash:
|
138
|
+
hash: 2972832392315398871
|
139
139
|
requirements: []
|
140
140
|
rubyforge_project:
|
141
|
-
rubygems_version: 1.8.
|
141
|
+
rubygems_version: 1.8.24
|
142
142
|
signing_key:
|
143
143
|
specification_version: 3
|
144
144
|
summary: SmartProperties – Ruby accessors on steroids
|