fast_attributes_rails 1.0.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 +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +194 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +292 -0
- data/Rakefile +1 -0
- data/benchmarks/Gemfile +8 -0
- data/benchmarks/comparison.rb +56 -0
- data/fast_attributes.gemspec +30 -0
- data/lib/fast_attributes.rb +83 -0
- data/lib/fast_attributes/builder.rb +125 -0
- data/lib/fast_attributes/default_attributes.rb +33 -0
- data/lib/fast_attributes/type_cast.rb +81 -0
- data/lib/fast_attributes/version.rb +3 -0
- data/spec/fast_attributes/type_cast_spec.rb +170 -0
- data/spec/fast_attributes_spec.rb +423 -0
- data/spec/fixtures/classes.rb +177 -0
- data/spec/spec_helper.rb +18 -0
- metadata +159 -0
@@ -0,0 +1,423 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FastAttributes do
|
4
|
+
describe '.type_casting' do
|
5
|
+
it 'returns predefined type casting rules' do
|
6
|
+
expect(FastAttributes.type_casting.keys).to include(String)
|
7
|
+
expect(FastAttributes.type_casting.keys).to include(Integer)
|
8
|
+
expect(FastAttributes.type_casting.keys).to include(Float)
|
9
|
+
expect(FastAttributes.type_casting.keys).to include(Array)
|
10
|
+
expect(FastAttributes.type_casting.keys).to include(Date)
|
11
|
+
expect(FastAttributes.type_casting.keys).to include(Time)
|
12
|
+
expect(FastAttributes.type_casting.keys).to include(DateTime)
|
13
|
+
expect(FastAttributes.type_casting.keys).to include(BigDecimal)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.get_type_casting' do
|
18
|
+
it 'returns type casting function' do
|
19
|
+
expect(FastAttributes.get_type_casting(String)).to be_a(FastAttributes::TypeCast)
|
20
|
+
expect(FastAttributes.get_type_casting(Time)).to be_a(FastAttributes::TypeCast)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.set_type_casting' do
|
25
|
+
after do
|
26
|
+
FastAttributes.remove_type_casting(OpenStruct)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'adds type to supported type casting list' do
|
30
|
+
expect(FastAttributes.get_type_casting(OpenStruct)).to be(nil)
|
31
|
+
FastAttributes.set_type_casting(OpenStruct, 'OpenStruct.new(a: %s)')
|
32
|
+
expect(FastAttributes.get_type_casting(OpenStruct)).to be_a(FastAttributes::TypeCast)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '.remove_type_casting' do
|
37
|
+
before do
|
38
|
+
FastAttributes.set_type_casting(OpenStruct, 'OpenStruct.new(a: %s)')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'removes type casting function from supported list' do
|
42
|
+
FastAttributes.remove_type_casting(OpenStruct)
|
43
|
+
expect(FastAttributes.get_type_casting(OpenStruct)).to be(nil)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '.type_exists?' do
|
48
|
+
it 'checks if type is registered' do
|
49
|
+
expect(FastAttributes.type_exists?(DateTime)).to be(true)
|
50
|
+
expect(FastAttributes.type_exists?(OpenStruct)).to be(false)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#attribute' do
|
55
|
+
it 'raises an exception when type is not supported' do
|
56
|
+
type = Class.new(Object) { def self.inspect; 'CustomType' end }
|
57
|
+
klass = Class.new(Object) { extend FastAttributes }
|
58
|
+
expect{klass.attribute(:name, type)}.to raise_error(FastAttributes::UnsupportedTypeError, 'Unsupported attribute type "CustomType"')
|
59
|
+
expect{klass.attribute(:name, :type)}.to raise_error(FastAttributes::UnsupportedTypeError, 'Unsupported attribute type ":type"')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'generates getter methods' do
|
63
|
+
book = Book.new
|
64
|
+
expect(book.respond_to?(:title)).to be(true)
|
65
|
+
expect(book.respond_to?(:name)).to be(true)
|
66
|
+
expect(book.respond_to?(:pages)).to be(true)
|
67
|
+
expect(book.respond_to?(:price)).to be(true)
|
68
|
+
expect(book.respond_to?(:authors)).to be(true)
|
69
|
+
expect(book.respond_to?(:published)).to be(true)
|
70
|
+
expect(book.respond_to?(:sold)).to be(true)
|
71
|
+
expect(book.respond_to?(:finished)).to be(true)
|
72
|
+
expect(book.respond_to?(:rate)).to be(true)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'is possible to override getter method' do
|
76
|
+
toy = Toy.new
|
77
|
+
expect(toy.name).to eq(' toy!')
|
78
|
+
toy.name = 'bear'
|
79
|
+
expect(toy.name).to eq('bear toy!')
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'generates setter methods' do
|
83
|
+
book = Book.new
|
84
|
+
expect(book.respond_to?(:title=)).to be(true)
|
85
|
+
expect(book.respond_to?(:name=)).to be(true)
|
86
|
+
expect(book.respond_to?(:pages=)).to be(true)
|
87
|
+
expect(book.respond_to?(:price=)).to be(true)
|
88
|
+
expect(book.respond_to?(:authors=)).to be(true)
|
89
|
+
expect(book.respond_to?(:published=)).to be(true)
|
90
|
+
expect(book.respond_to?(:sold=)).to be(true)
|
91
|
+
expect(book.respond_to?(:finished=)).to be(true)
|
92
|
+
expect(book.respond_to?(:rate=)).to be(true)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'is possible to override setter method' do
|
96
|
+
toy = Toy.new
|
97
|
+
expect(toy.price).to be(nil)
|
98
|
+
toy.price = 2
|
99
|
+
expect(toy.price).to eq(4)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'setter methods convert values to correct datatype' do
|
103
|
+
book = Book.new
|
104
|
+
book.title = 123
|
105
|
+
book.name = 456
|
106
|
+
book.pages = '250'
|
107
|
+
book.price = '2.55'
|
108
|
+
book.authors = 'Jobs'
|
109
|
+
book.published = '2014-06-21'
|
110
|
+
book.sold = '2014-06-21 20:45:15'
|
111
|
+
book.finished = '2014-05-20 21:35:20'
|
112
|
+
book.rate = '4.1'
|
113
|
+
|
114
|
+
expect(book.title).to eq('123')
|
115
|
+
expect(book.name).to eq('456')
|
116
|
+
expect(book.pages).to be(250)
|
117
|
+
expect(book.price).to eq(BigDecimal.new('2.55'))
|
118
|
+
expect(book.authors).to eq(%w[Jobs])
|
119
|
+
expect(book.published).to eq(Date.new(2014, 6, 21))
|
120
|
+
expect(book.sold).to eq(Time.new(2014, 6, 21, 20, 45, 15))
|
121
|
+
expect(book.finished).to eq(DateTime.new(2014, 5, 20, 21, 35, 20))
|
122
|
+
expect(book.rate).to eq(4.1)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'setter methods accept values which are already in a proper type' do
|
126
|
+
book = Book.new
|
127
|
+
book.title = title = 'One'
|
128
|
+
book.name = name = 'Two'
|
129
|
+
book.pages = pages = 250
|
130
|
+
book.price = price = BigDecimal.new('2.55')
|
131
|
+
book.authors = authors = %w[Jobs]
|
132
|
+
book.published = published = Date.new(2014, 06, 21)
|
133
|
+
book.sold = sold = Time.new(2014, 6, 21, 20, 45, 15)
|
134
|
+
book.finished = finished = DateTime.new(2014, 05, 20, 21, 35, 20)
|
135
|
+
book.rate = rate = 4.1
|
136
|
+
|
137
|
+
expect(book.title).to be(title)
|
138
|
+
expect(book.name).to be(name)
|
139
|
+
expect(book.pages).to be(pages)
|
140
|
+
expect(book.price).to eq(price)
|
141
|
+
expect(book.authors).to be(authors)
|
142
|
+
expect(book.published).to be(published)
|
143
|
+
expect(book.sold).to be(sold)
|
144
|
+
expect(book.finished).to be(finished)
|
145
|
+
expect(book.rate).to be(rate)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'setter methods accept nil values' do
|
149
|
+
book = Book.new
|
150
|
+
book.title = 'One'
|
151
|
+
book.name = 'Two'
|
152
|
+
book.pages = 250
|
153
|
+
book.price = BigDecimal.new('2.55')
|
154
|
+
book.authors = %w[Jobs]
|
155
|
+
book.published = Date.new(2014, 06, 21)
|
156
|
+
book.sold = Time.new(2014, 6, 21, 20, 45, 15)
|
157
|
+
book.finished = DateTime.new(2014, 05, 20, 21, 35, 20)
|
158
|
+
book.rate = 4.1
|
159
|
+
|
160
|
+
book.title = nil
|
161
|
+
book.name = nil
|
162
|
+
book.pages = nil
|
163
|
+
book.price = nil
|
164
|
+
book.authors = nil
|
165
|
+
book.published = nil
|
166
|
+
book.sold = nil
|
167
|
+
book.finished = nil
|
168
|
+
book.rate = nil
|
169
|
+
|
170
|
+
expect(book.title).to be(nil)
|
171
|
+
expect(book.name).to be(nil)
|
172
|
+
expect(book.pages).to be(nil)
|
173
|
+
expect(book.price).to be(nil)
|
174
|
+
expect(book.authors).to be(nil)
|
175
|
+
expect(book.published).to be(nil)
|
176
|
+
expect(book.sold).to be(nil)
|
177
|
+
expect(book.finished).to be(nil)
|
178
|
+
expect(book.rate).to be(nil)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'setter methods raise an exception when cannot parse values' do
|
182
|
+
object = BasicObject.new
|
183
|
+
def object.to_s; 'BasicObject'; end
|
184
|
+
def object.to_str; 1/0 end
|
185
|
+
|
186
|
+
book = Book.new
|
187
|
+
expect{ book.title = object }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "BasicObject" for attribute "title" of type "String"')
|
188
|
+
expect{ book.name = object }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "BasicObject" for attribute "name" of type "String"')
|
189
|
+
expect{ book.pages = 'number' }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "number" for attribute "pages" of type "Integer"')
|
190
|
+
expect{ book.price = 'bigdecimal' }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "bigdecimal" for attribute "price" of type "BigDecimal"')
|
191
|
+
expect{ book.published = 'date' }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "date" for attribute "published" of type "Date"')
|
192
|
+
expect{ book.sold = 'time' }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "time" for attribute "sold" of type "Time"')
|
193
|
+
expect{ book.finished = 'datetime' }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "datetime" for attribute "finished" of type "DateTime"')
|
194
|
+
expect{ book.rate = 'float' }.to raise_error(FastAttributes::TypeCast::InvalidValueError, 'Invalid value "float" for attribute "rate" of type "Float"')
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'setter method can escape placeholder using double %' do
|
198
|
+
placeholder = PlaceholderClass.new
|
199
|
+
placeholder.value = 3
|
200
|
+
expect(placeholder.value).to eq('value %s %value %%s 2')
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'setter method can accept %a placeholder which return attribute name' do
|
204
|
+
placeholder = PlaceholderClass.new
|
205
|
+
|
206
|
+
placeholder.title = 'attribute name 1'
|
207
|
+
expect(placeholder.title).to eq('title')
|
208
|
+
|
209
|
+
placeholder.title = 'attribute name 2'
|
210
|
+
expect(placeholder.title).to eq('title%a%title%title!')
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'generates lenient attributes which do not correspond to a particular data type' do
|
214
|
+
lenient_attribute = LenientAttributes.new
|
215
|
+
expect(lenient_attribute.terms_of_service).to be(nil)
|
216
|
+
|
217
|
+
lenient_attribute.terms_of_service = 'yes'
|
218
|
+
expect(lenient_attribute.terms_of_service).to be(true)
|
219
|
+
|
220
|
+
lenient_attribute.terms_of_service = 'no'
|
221
|
+
expect(lenient_attribute.terms_of_service).to be(false)
|
222
|
+
|
223
|
+
lenient_attribute.terms_of_service = 42
|
224
|
+
expect(lenient_attribute.terms_of_service).to be(nil)
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'allows to define attributes using symbols as a data type' do
|
228
|
+
book = DefaultLenientAttributes.new
|
229
|
+
book.title = title = 'One'
|
230
|
+
book.pages = pages = 250
|
231
|
+
book.price = price = BigDecimal.new('2.55')
|
232
|
+
book.authors = authors = %w[Jobs]
|
233
|
+
book.published = published = Date.new(2014, 06, 21)
|
234
|
+
book.sold = sold = Time.new(2014, 6, 21, 20, 45, 15)
|
235
|
+
book.finished = finished = DateTime.new(2014, 05, 20, 21, 35, 20)
|
236
|
+
book.rate = rate = 4.1
|
237
|
+
|
238
|
+
expect(book.title).to be(title)
|
239
|
+
expect(book.pages).to be(pages)
|
240
|
+
expect(book.price).to eq(price)
|
241
|
+
expect(book.authors).to be(authors)
|
242
|
+
expect(book.published).to be(published)
|
243
|
+
expect(book.sold).to be(sold)
|
244
|
+
expect(book.finished).to be(finished)
|
245
|
+
expect(book.rate).to be(rate)
|
246
|
+
end
|
247
|
+
|
248
|
+
context 'boolean attribute' do
|
249
|
+
let(:object) { DefaultLenientAttributes.new }
|
250
|
+
|
251
|
+
context 'when value is not set' do
|
252
|
+
it 'return nil' do
|
253
|
+
expect(object.active).to be(nil)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'when value represents true' do
|
258
|
+
it 'returns true' do
|
259
|
+
object.active = true
|
260
|
+
expect(object.active).to be(true)
|
261
|
+
|
262
|
+
object.active = 1
|
263
|
+
expect(object.active).to be(true)
|
264
|
+
|
265
|
+
object.active = '1'
|
266
|
+
expect(object.active).to be(true)
|
267
|
+
|
268
|
+
object.active = 't'
|
269
|
+
expect(object.active).to be(true)
|
270
|
+
|
271
|
+
object.active = 'T'
|
272
|
+
expect(object.active).to be(true)
|
273
|
+
|
274
|
+
object.active = 'true'
|
275
|
+
expect(object.active).to be(true)
|
276
|
+
|
277
|
+
object.active = 'TRUE'
|
278
|
+
expect(object.active).to be(true)
|
279
|
+
|
280
|
+
object.active = 'on'
|
281
|
+
expect(object.active).to be(true)
|
282
|
+
|
283
|
+
object.active = 'ON'
|
284
|
+
expect(object.active).to be(true)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'when value represents false' do
|
289
|
+
it 'returns false' do
|
290
|
+
object.active = false
|
291
|
+
expect(object.active).to be(false)
|
292
|
+
|
293
|
+
object.active = 0
|
294
|
+
expect(object.active).to be(false)
|
295
|
+
|
296
|
+
object.active = '0'
|
297
|
+
expect(object.active).to be(false)
|
298
|
+
|
299
|
+
object.active = 'f'
|
300
|
+
expect(object.active).to be(false)
|
301
|
+
|
302
|
+
object.active = 'F'
|
303
|
+
expect(object.active).to be(false)
|
304
|
+
|
305
|
+
object.active = 'false'
|
306
|
+
expect(object.active).to be(false)
|
307
|
+
|
308
|
+
object.active = 'FALSE'
|
309
|
+
expect(object.active).to be(false)
|
310
|
+
|
311
|
+
object.active = 'off'
|
312
|
+
expect(object.active).to be(false)
|
313
|
+
|
314
|
+
object.active = 'OFF'
|
315
|
+
expect(object.active).to be(false)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
describe '#define_attributes' do
|
322
|
+
describe 'option initialize: true' do
|
323
|
+
it 'generates initialize method' do
|
324
|
+
reader = Reader.new(name: 104, age: '23')
|
325
|
+
expect(reader.name).to eq('104')
|
326
|
+
expect(reader.age).to be(23)
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'is possible to override initialize method' do
|
330
|
+
window = Window.new
|
331
|
+
expect(window.height).to be(200)
|
332
|
+
expect(window.width).to be(80)
|
333
|
+
|
334
|
+
window = Window.new(height: 210, width: 100)
|
335
|
+
expect(window.height).to be(210)
|
336
|
+
expect(window.width).to be(100)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
describe 'option attributes: true' do
|
341
|
+
it 'generates attributes method' do
|
342
|
+
publisher = Publisher.new
|
343
|
+
expect(publisher.attributes).to eq({'name' => nil, 'books' => nil})
|
344
|
+
|
345
|
+
reader = Reader.new
|
346
|
+
expect(reader.attributes).to eq({'name' => nil, 'age' => nil})
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'is possible to override attributes method' do
|
350
|
+
window = Window.new(height: 220, width: 100)
|
351
|
+
expect(window.attributes).to eq({'height' => 220, 'width' => 100, 'color' => 'white'})
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'attributes method return all attributes with their values' do
|
355
|
+
publisher = Publisher.new
|
356
|
+
publisher.name = 101
|
357
|
+
publisher.books = '20'
|
358
|
+
expect(publisher.attributes).to eq({'name' => '101', 'books' => 20})
|
359
|
+
|
360
|
+
reader = Reader.new
|
361
|
+
reader.name = 102
|
362
|
+
reader.age = '25'
|
363
|
+
expect(reader.attributes).to eq({'name' => '102', 'age' => 25})
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
describe 'option attributes: :accessors' do
|
368
|
+
it 'doesn\'t interfere when you don\'t use the option' do
|
369
|
+
klass = AttributesWithoutAccessors.new
|
370
|
+
expect(klass.attributes).to eq({'title' => nil, 'pages' => nil, 'color' => 'white'})
|
371
|
+
end
|
372
|
+
|
373
|
+
it "is returns the values of accessors, not the ivars" do
|
374
|
+
klass = AttributesWithAccessors.new(pages: 10, title: 'Something')
|
375
|
+
expect(klass.attributes['pages']).to be(20)
|
376
|
+
expect(klass.attributes['title']).to eq('A Longer Title: Something')
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'is possible to override attributes method' do
|
380
|
+
klass = AttributesWithAccessors.new(pages: 10, title: 'Something')
|
381
|
+
expect(klass.attributes).to eq({'pages' => 20, 'title' => 'A Longer Title: Something', 'color' => 'white'})
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'works with default attributes' do
|
385
|
+
klass = AttributesWithAccessorsAndDefaults.new
|
386
|
+
expect(klass.attributes).to eq({'pages' => 20, 'title' => 'a title'})
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "default attributes" do
|
392
|
+
it "sets the default values" do
|
393
|
+
class_with_defaults = ClassWithDefaults.new
|
394
|
+
|
395
|
+
expect(class_with_defaults.title).to eq('a title')
|
396
|
+
expect(class_with_defaults.pages).to be(10)
|
397
|
+
expect(class_with_defaults.authors).to eq([1, 2, 4])
|
398
|
+
end
|
399
|
+
|
400
|
+
it "allows you to override default values" do
|
401
|
+
class_with_defaults = ClassWithDefaults.new(title: 'Something', authors: [1, 5, 7])
|
402
|
+
|
403
|
+
expect(class_with_defaults.title).to eq('Something')
|
404
|
+
expect(class_with_defaults.pages).to be(10)
|
405
|
+
expect(class_with_defaults.authors).to eq([1, 5, 7])
|
406
|
+
end
|
407
|
+
|
408
|
+
it "allows callable default values" do
|
409
|
+
class_with_defaults = ClassWithDefaults.new
|
410
|
+
|
411
|
+
expect(class_with_defaults.callable).to eq("callable value")
|
412
|
+
end
|
413
|
+
|
414
|
+
it "doesn't use the same instance between multiple instances" do
|
415
|
+
class_with_defaults = ClassWithDefaults.new
|
416
|
+
class_with_defaults.authors << 2
|
417
|
+
|
418
|
+
class_with_defaults2 = ClassWithDefaults.new
|
419
|
+
|
420
|
+
expect(class_with_defaults2.authors).to eq([1, 2, 4])
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
class Book
|
2
|
+
extend FastAttributes
|
3
|
+
|
4
|
+
attribute :title, :name, String
|
5
|
+
attribute :pages, Integer
|
6
|
+
attribute :price, BigDecimal
|
7
|
+
attribute :authors, Array
|
8
|
+
attribute :published, Date
|
9
|
+
attribute :sold, Time
|
10
|
+
attribute :finished, DateTime
|
11
|
+
attribute :rate, Float
|
12
|
+
end
|
13
|
+
|
14
|
+
class Author
|
15
|
+
extend FastAttributes
|
16
|
+
|
17
|
+
define_attributes initialize: true do
|
18
|
+
attribute :name, String
|
19
|
+
attribute :age, Integer
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Publisher
|
24
|
+
extend FastAttributes
|
25
|
+
|
26
|
+
define_attributes attributes: true do
|
27
|
+
attribute :name, String
|
28
|
+
attribute :books, Integer
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Reader
|
33
|
+
extend FastAttributes
|
34
|
+
|
35
|
+
define_attributes initialize: true, attributes: true do
|
36
|
+
attribute :name, String
|
37
|
+
attribute :age, Integer
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Toy
|
42
|
+
extend FastAttributes
|
43
|
+
|
44
|
+
attribute :name, String
|
45
|
+
attribute :price, Float
|
46
|
+
|
47
|
+
def name
|
48
|
+
"#{super} toy!"
|
49
|
+
end
|
50
|
+
|
51
|
+
def price=(value)
|
52
|
+
super((value.to_f + 2).to_s)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Window
|
57
|
+
extend FastAttributes
|
58
|
+
|
59
|
+
define_attributes initialize: true, attributes: true do
|
60
|
+
attribute :height, Integer
|
61
|
+
attribute :width, Integer
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(attributes = {})
|
65
|
+
self.height = 200
|
66
|
+
self.width = 80
|
67
|
+
|
68
|
+
super(attributes)
|
69
|
+
end
|
70
|
+
|
71
|
+
def attributes
|
72
|
+
super.merge('color' => 'white')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Placeholder < String
|
77
|
+
end
|
78
|
+
|
79
|
+
FastAttributes.type_cast Placeholder do
|
80
|
+
from '"attribute name 1"', to: '"%a"'
|
81
|
+
from '"attribute name 2"', to: %q("%a%%a%%%a%#{%a<<'!'}")
|
82
|
+
otherwise '"%s %%s %%%s %%%%s #{5%%%s}"'
|
83
|
+
end
|
84
|
+
|
85
|
+
class PlaceholderClass
|
86
|
+
extend FastAttributes
|
87
|
+
attribute :value, Placeholder
|
88
|
+
attribute :title, Placeholder
|
89
|
+
end
|
90
|
+
|
91
|
+
FastAttributes.type_cast :lenient_attribute do
|
92
|
+
from '"yes"', to: 'true'
|
93
|
+
from '"no"', to: 'false'
|
94
|
+
otherwise 'nil'
|
95
|
+
end
|
96
|
+
|
97
|
+
class LenientAttributes
|
98
|
+
extend FastAttributes
|
99
|
+
|
100
|
+
attribute :terms_of_service, :lenient_attribute
|
101
|
+
end
|
102
|
+
|
103
|
+
class DefaultLenientAttributes
|
104
|
+
extend FastAttributes
|
105
|
+
|
106
|
+
attribute :title, :string
|
107
|
+
attribute :pages, :integer
|
108
|
+
attribute :price, :big_decimal
|
109
|
+
attribute :authors, :array
|
110
|
+
attribute :published, :date
|
111
|
+
attribute :sold, :time
|
112
|
+
attribute :finished, :date_time
|
113
|
+
attribute :rate, :float
|
114
|
+
attribute :active, :boolean
|
115
|
+
end
|
116
|
+
|
117
|
+
class AttributesWithoutAccessors
|
118
|
+
extend FastAttributes
|
119
|
+
|
120
|
+
define_attributes initialize: true, attributes: true do
|
121
|
+
attribute :title, :string
|
122
|
+
attribute :pages, :integer
|
123
|
+
end
|
124
|
+
|
125
|
+
def title
|
126
|
+
"Some title"
|
127
|
+
end
|
128
|
+
|
129
|
+
def attributes
|
130
|
+
super.merge('color' => 'white')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class AttributesWithAccessors
|
135
|
+
extend FastAttributes
|
136
|
+
|
137
|
+
define_attributes initialize: true, attributes: :accessors do
|
138
|
+
attribute :title, :string
|
139
|
+
attribute :pages, :integer
|
140
|
+
end
|
141
|
+
|
142
|
+
def attributes
|
143
|
+
super.merge('color' => 'white')
|
144
|
+
end
|
145
|
+
|
146
|
+
def pages
|
147
|
+
@pages + 10
|
148
|
+
end
|
149
|
+
|
150
|
+
def title
|
151
|
+
"A Longer Title: #{@title}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class AttributesWithAccessorsAndDefaults
|
156
|
+
extend FastAttributes
|
157
|
+
|
158
|
+
define_attributes initialize: true, attributes: :accessors do
|
159
|
+
attribute :title, String, default: "a title"
|
160
|
+
attribute :pages, Integer, default: 10
|
161
|
+
end
|
162
|
+
|
163
|
+
def pages
|
164
|
+
@pages + 10
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class ClassWithDefaults
|
169
|
+
extend FastAttributes
|
170
|
+
|
171
|
+
define_attributes initialize: true, attributes: true do
|
172
|
+
attribute :title, String, default: "a title"
|
173
|
+
attribute :pages, Integer, default: 10
|
174
|
+
attribute :authors, Array, default: [1, 2, 4]
|
175
|
+
attribute :callable, String, default: lambda { "callable value" }
|
176
|
+
end
|
177
|
+
end
|