fast_attributes 0.6.0 → 0.7.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 +4 -4
- data/CHANGELOG.md +60 -0
- data/README.md +46 -1
- data/lib/fast_attributes/builder.rb +1 -1
- data/lib/fast_attributes/version.rb +1 -1
- data/lib/fast_attributes.rb +25 -5
- data/spec/fast_attributes_spec.rb +112 -4
- data/spec/fixtures/classes.rb +26 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 714fe623705696e372c8b188c47dd28e59a79462
|
|
4
|
+
data.tar.gz: 36390f23832e5c3c2253a0f2f54628254fb9faa6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 758076d95b01e4b721ccfe1674708514584024ce84f94e37fcaf9eb09019c4851ee5b2ba3ea8dbe3dca8ea4119e9a31806252e2cef6f1e6db011d7d4fd91f797
|
|
7
|
+
data.tar.gz: c433c6a45235e96011f55b6314abc087038d1872d8a6f08ac1159d1282f651d53139b351c6622115f0f346adf8183b61e3c66301bce1878cb91be49744aaaa79
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,63 @@
|
|
|
1
|
+
**0.7.0 (August 31, 2014)**
|
|
2
|
+
* Support `boolean` data type as a lenient type.
|
|
3
|
+
```ruby
|
|
4
|
+
class Product
|
|
5
|
+
extend FastAttributes
|
|
6
|
+
attribute :active, :boolean
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
product = Product.new
|
|
10
|
+
product.active = 1
|
|
11
|
+
product.active # true
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
* Add support of lenient data types. It allows to define attribute which doesn't correspond to a specific ruby class
|
|
15
|
+
```ruby
|
|
16
|
+
FastAttributes.type_cast :lenient_attribute do
|
|
17
|
+
from '"yes"', to: 'true'
|
|
18
|
+
from '"no"', to: 'false'
|
|
19
|
+
otherwise 'nil'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class LenientAttributes
|
|
23
|
+
extend FastAttributes
|
|
24
|
+
attribute :terms_of_service, :lenient_attribute
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
lenient = LenientAttribute.new
|
|
28
|
+
lenient.terms_of_service = 'yes'
|
|
29
|
+
lenient.terms_of_service # true
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
* Allow to define default data types using class or symbol.
|
|
33
|
+
```ruby
|
|
34
|
+
class Book
|
|
35
|
+
extend FastAttributes
|
|
36
|
+
|
|
37
|
+
attribute :title String
|
|
38
|
+
attribute :pages, Integer
|
|
39
|
+
attribute :price, BigDecimal
|
|
40
|
+
attribute :authors, Array
|
|
41
|
+
attribute :published, Date
|
|
42
|
+
attribute :sold, Time
|
|
43
|
+
attribute :finished, DateTime
|
|
44
|
+
attribute :rate, Float
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class LenientBook
|
|
48
|
+
extend FastAttributes
|
|
49
|
+
|
|
50
|
+
attribute :title, :string
|
|
51
|
+
attribute :pages, :integer
|
|
52
|
+
attribute :price, :big_decimal
|
|
53
|
+
attribute :authors, :array
|
|
54
|
+
attribute :published, :date
|
|
55
|
+
attribute :sold, :time
|
|
56
|
+
attribute :finished, :date_time
|
|
57
|
+
attribute :rate, :float
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
1
61
|
**0.6.0 (July 20, 2014)**
|
|
2
62
|
* Throw custom `FastAttributes::TypeCast::InvalidValueError` exception when value has invalid type.
|
|
3
63
|
How auto-generated method looks like:
|
data/README.md
CHANGED
|
@@ -175,7 +175,7 @@ end
|
|
|
175
175
|
# end
|
|
176
176
|
# end
|
|
177
177
|
```
|
|
178
|
-
Notice, placeholder `%a` represents method name.
|
|
178
|
+
Notice, placeholder `%a` represents method name. Also, `set_type_casting` method generates lenient date type. See [Lenient Data Types](https://github.com/applift/fast_attributes/blob/lenient_data_types/README.md#lenient-data-types) section.
|
|
179
179
|
|
|
180
180
|
If you need to conrol the whole type casting process, you can use the following DSL:
|
|
181
181
|
```ruby
|
|
@@ -192,6 +192,51 @@ FastAttributes.type_cast String do # begin
|
|
|
192
192
|
end # end
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
+
## Lenient Data Types
|
|
196
|
+
It's also possible to define a lenient data type which doesn't correspond to any of ruby classes:
|
|
197
|
+
```ruby
|
|
198
|
+
FastAttributes.type_cast :yes_no do
|
|
199
|
+
from '"yes"', to: 'true'
|
|
200
|
+
from '"no"', to: 'false'
|
|
201
|
+
otherwise 'nil'
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
class Order
|
|
205
|
+
extend FastAttributes
|
|
206
|
+
|
|
207
|
+
attribute :terms_of_service, :yes_no
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
order = Order.new
|
|
211
|
+
order.terms_of_service = 'yes'
|
|
212
|
+
order.terms_of_service
|
|
213
|
+
# => true
|
|
214
|
+
order.terms_of_service = 'no'
|
|
215
|
+
order.terms_of_service
|
|
216
|
+
# => false
|
|
217
|
+
order.terms_of_service = 42
|
|
218
|
+
order.terms_of_service
|
|
219
|
+
# => nil
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
All default data types have lenient notation:
|
|
223
|
+
```ruby
|
|
224
|
+
class Book
|
|
225
|
+
extend FastAttributes
|
|
226
|
+
|
|
227
|
+
attribute :title, :string
|
|
228
|
+
attribute :pages, :integer
|
|
229
|
+
attribute :price, :big_decimal
|
|
230
|
+
attribute :authors, :array
|
|
231
|
+
attribute :published, :date
|
|
232
|
+
attribute :sold, :time
|
|
233
|
+
attribute :finished, :date_time
|
|
234
|
+
attribute :rate, :float
|
|
235
|
+
attribute :active, :boolean
|
|
236
|
+
end
|
|
237
|
+
```
|
|
238
|
+
Notice, `Boolean` attribute can be defined only via symbol, `fast_attribute` doesn't create `Boolean` class.
|
|
239
|
+
|
|
195
240
|
## Extensions
|
|
196
241
|
* [fast_attributes-uuid](https://github.com/applift/fast_attributes-uuid) - adds support of `UUID` to `fast_attributes`
|
|
197
242
|
|
|
@@ -12,7 +12,7 @@ module FastAttributes
|
|
|
12
12
|
|
|
13
13
|
def attribute(*attributes, type)
|
|
14
14
|
unless FastAttributes.type_exists?(type)
|
|
15
|
-
raise UnsupportedTypeError, %(Unsupported attribute type "#{type.
|
|
15
|
+
raise UnsupportedTypeError, %(Unsupported attribute type "#{type.inspect}")
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
@attributes << [attributes, type]
|
data/lib/fast_attributes.rb
CHANGED
|
@@ -6,6 +6,9 @@ require 'fast_attributes/builder'
|
|
|
6
6
|
require 'fast_attributes/type_cast'
|
|
7
7
|
|
|
8
8
|
module FastAttributes
|
|
9
|
+
TRUE_VALUES = {true => nil, 1 => nil, '1' => nil, 't' => nil, 'T' => nil, 'true' => nil, 'TRUE' => nil, 'on' => nil, 'ON' => nil}
|
|
10
|
+
FALSE_VALUES = {false => nil, 0 => nil, '0' => nil, 'f' => nil, 'F' => nil, 'false' => nil, 'FALSE' => nil, 'off' => nil, 'OFF' => nil}
|
|
11
|
+
|
|
9
12
|
class << self
|
|
10
13
|
def type_casting
|
|
11
14
|
@type_casting ||= {}
|
|
@@ -16,7 +19,8 @@ module FastAttributes
|
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def set_type_casting(klass, casting)
|
|
19
|
-
|
|
22
|
+
symbol = klass.name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym # DateTime => :date_time
|
|
23
|
+
type_cast symbol, klass do
|
|
20
24
|
from 'nil', to: 'nil'
|
|
21
25
|
from klass.name, to: '%s'
|
|
22
26
|
otherwise casting
|
|
@@ -31,10 +35,12 @@ module FastAttributes
|
|
|
31
35
|
type_casting.has_key?(klass)
|
|
32
36
|
end
|
|
33
37
|
|
|
34
|
-
def type_cast(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
def type_cast(*types_or_classes, &block)
|
|
39
|
+
types_or_classes.each do |type_or_class|
|
|
40
|
+
type_cast = TypeCast.new(type_or_class)
|
|
41
|
+
type_cast.instance_eval(&block)
|
|
42
|
+
type_casting[type_or_class] = type_cast
|
|
43
|
+
end
|
|
38
44
|
end
|
|
39
45
|
end
|
|
40
46
|
|
|
@@ -58,4 +64,18 @@ module FastAttributes
|
|
|
58
64
|
set_type_casting Time, 'Time.parse(%s)'
|
|
59
65
|
set_type_casting DateTime, 'DateTime.parse(%s)'
|
|
60
66
|
set_type_casting BigDecimal, 'Float(%s);BigDecimal(%s.to_s)'
|
|
67
|
+
|
|
68
|
+
type_cast :boolean do
|
|
69
|
+
otherwise <<-EOS
|
|
70
|
+
if FastAttributes::TRUE_VALUES.has_key?(%s)
|
|
71
|
+
true
|
|
72
|
+
elsif FastAttributes::FALSE_VALUES.has_key?(%s)
|
|
73
|
+
false
|
|
74
|
+
elsif %s.nil?
|
|
75
|
+
nil
|
|
76
|
+
else
|
|
77
|
+
raise FastAttributes::TypeCast::InvalidValueError, %(Invalid value "\#{%s}" for attribute "%a" of type ":boolean")
|
|
78
|
+
end
|
|
79
|
+
EOS
|
|
80
|
+
end
|
|
61
81
|
end
|
|
@@ -53,9 +53,10 @@ describe FastAttributes do
|
|
|
53
53
|
|
|
54
54
|
describe '#attribute' do
|
|
55
55
|
it 'raises an exception when type is not supported' do
|
|
56
|
-
type = Class.new(Object) { def self.
|
|
56
|
+
type = Class.new(Object) { def self.inspect; 'CustomType' end }
|
|
57
57
|
klass = Class.new(Object) { extend FastAttributes }
|
|
58
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"')
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
it 'generates getter methods' do
|
|
@@ -113,7 +114,7 @@ describe FastAttributes do
|
|
|
113
114
|
expect(book.title).to eq('123')
|
|
114
115
|
expect(book.name).to eq('456')
|
|
115
116
|
expect(book.pages).to be(250)
|
|
116
|
-
expect(book.price).to eq(BigDecimal.new(
|
|
117
|
+
expect(book.price).to eq(BigDecimal.new('2.55'))
|
|
117
118
|
expect(book.authors).to eq(%w[Jobs])
|
|
118
119
|
expect(book.published).to eq(Date.new(2014, 6, 21))
|
|
119
120
|
expect(book.sold).to eq(Time.new(2014, 6, 21, 20, 45, 15))
|
|
@@ -126,7 +127,7 @@ describe FastAttributes do
|
|
|
126
127
|
book.title = title = 'One'
|
|
127
128
|
book.name = name = 'Two'
|
|
128
129
|
book.pages = pages = 250
|
|
129
|
-
book.price = price = BigDecimal.new(
|
|
130
|
+
book.price = price = BigDecimal.new('2.55')
|
|
130
131
|
book.authors = authors = %w[Jobs]
|
|
131
132
|
book.published = published = Date.new(2014, 06, 21)
|
|
132
133
|
book.sold = sold = Time.new(2014, 6, 21, 20, 45, 15)
|
|
@@ -149,7 +150,7 @@ describe FastAttributes do
|
|
|
149
150
|
book.title = 'One'
|
|
150
151
|
book.name = 'Two'
|
|
151
152
|
book.pages = 250
|
|
152
|
-
book.price = BigDecimal.new(
|
|
153
|
+
book.price = BigDecimal.new('2.55')
|
|
153
154
|
book.authors = %w[Jobs]
|
|
154
155
|
book.published = Date.new(2014, 06, 21)
|
|
155
156
|
book.sold = Time.new(2014, 6, 21, 20, 45, 15)
|
|
@@ -208,6 +209,113 @@ describe FastAttributes do
|
|
|
208
209
|
placeholder.title = 'attribute name 2'
|
|
209
210
|
expect(placeholder.title).to eq('title%a%title%title!')
|
|
210
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
|
|
211
319
|
end
|
|
212
320
|
|
|
213
321
|
describe '#define_attributes' do
|
data/spec/fixtures/classes.rb
CHANGED
|
@@ -87,3 +87,29 @@ class PlaceholderClass
|
|
|
87
87
|
attribute :value, Placeholder
|
|
88
88
|
attribute :title, Placeholder
|
|
89
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
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fast_attributes
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kostiantyn Stepaniuk
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
11
|
+
date: 2014-08-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -136,3 +136,4 @@ test_files:
|
|
|
136
136
|
- spec/fast_attributes_spec.rb
|
|
137
137
|
- spec/fixtures/classes.rb
|
|
138
138
|
- spec/spec_helper.rb
|
|
139
|
+
has_rdoc:
|