fast_attributes 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 156410fa3391841eaf2b70060f777f96e70b17cb
4
- data.tar.gz: d272b8684e3b06afe7de0562a06f116f9de9f168
3
+ metadata.gz: 714fe623705696e372c8b188c47dd28e59a79462
4
+ data.tar.gz: 36390f23832e5c3c2253a0f2f54628254fb9faa6
5
5
  SHA512:
6
- metadata.gz: 5770eaeb6359e8fe89fe78301fc6e8dc4242c02edcf99b132def5c27fed34b3e30d2c270c33a4b8ad2f01695d48789ae93d40ef35f8abdef86acaf1984db035d
7
- data.tar.gz: 087d805216430a6cb94d7dd8bce84b72f8fdc644f1853f957aefb39941109f054f0f0ff1c985902a2d7f018a8f863698ec097a81cb8c87494367b7303888182c
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.name}")
15
+ raise UnsupportedTypeError, %(Unsupported attribute type "#{type.inspect}")
16
16
  end
17
17
 
18
18
  @attributes << [attributes, type]
@@ -1,3 +1,3 @@
1
1
  module FastAttributes
2
- VERSION = '0.6.0'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -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
- type_cast klass do
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(klass, &block)
35
- type_cast = TypeCast.new(klass)
36
- type_cast.instance_eval(&block)
37
- type_casting[klass] = type_cast
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.name; 'CustomType' end }
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("2.55"))
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("2.55")
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("2.55")
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
@@ -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.6.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-07-20 00:00:00.000000000 Z
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: