fast_attributes_rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b789314937d4fe9b190cce7f27be1506803447e8
4
+ data.tar.gz: d9802b4d4caea346145bdccb2b839bf452a39eff
5
+ SHA512:
6
+ metadata.gz: 8932e7676e3a54707b3256d2ae93cd2a23412c6043f7ea24f9cec8ec9bef0b1e143e6e6fb3aed2e7ec24af26691dd7bc4bf8da4a6eb4b3ba01f9cb916cd06a64
7
+ data.tar.gz: d18ae5cf462917e8d3117fdd963a5d8e259504d6aa664b98c2c535f4d2506ad3dcbf74e46b8662f49cbd2a95320e99a465f7df611dcc5ce4902be7267c6c24fd
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format d
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ script: bundle exec rspec spec
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.1
6
+ - 2.2.5
data/CHANGELOG.md ADDED
@@ -0,0 +1,194 @@
1
+ **0.9.0 (September 15, 2016)**
2
+ * Attributes via accessors [Phil Schalm](https://github.com/pnomolos)
3
+ ```ruby
4
+ class Book
5
+ extend FastAttributes
6
+
7
+ define_attributes attributes: :accessors do
8
+ attribute :author, String
9
+ end
10
+
11
+ def author
12
+ @author || "No author set"
13
+ end
14
+ end
15
+
16
+ book = Book.new
17
+ book.attributes
18
+ {"author" => "No author set"}
19
+ ```
20
+
21
+ **0.8.0 (September 15, 2016)**
22
+ * Support of default values [Phil Schalm](https://github.com/pnomolos)
23
+ ```ruby
24
+ class Product
25
+ extend FastAttributes
26
+
27
+ define_attributes initialize: true, attributes: true do
28
+ attribute :title, String, default: "Book"
29
+ attribute :price, Float, default: 10
30
+ end
31
+ end
32
+ ```
33
+
34
+ **0.7.0 (August 31, 2014)**
35
+ * Support `boolean` data type as a lenient type.
36
+ ```ruby
37
+ class Product
38
+ extend FastAttributes
39
+ attribute :active, :boolean
40
+ end
41
+
42
+ product = Product.new
43
+ product.active = 1
44
+ product.active # true
45
+ ```
46
+
47
+ * Add support of lenient data types. It allows to define attribute which doesn't correspond to a specific ruby class
48
+ ```ruby
49
+ FastAttributes.type_cast :lenient_attribute do
50
+ from '"yes"', to: 'true'
51
+ from '"no"', to: 'false'
52
+ otherwise 'nil'
53
+ end
54
+
55
+ class LenientAttributes
56
+ extend FastAttributes
57
+ attribute :terms_of_service, :lenient_attribute
58
+ end
59
+
60
+ lenient = LenientAttribute.new
61
+ lenient.terms_of_service = 'yes'
62
+ lenient.terms_of_service # true
63
+ ```
64
+
65
+ * Allow to define default data types using class or symbol.
66
+ ```ruby
67
+ class Book
68
+ extend FastAttributes
69
+
70
+ attribute :title String
71
+ attribute :pages, Integer
72
+ attribute :price, BigDecimal
73
+ attribute :authors, Array
74
+ attribute :published, Date
75
+ attribute :sold, Time
76
+ attribute :finished, DateTime
77
+ attribute :rate, Float
78
+ end
79
+
80
+ class LenientBook
81
+ extend FastAttributes
82
+
83
+ attribute :title, :string
84
+ attribute :pages, :integer
85
+ attribute :price, :big_decimal
86
+ attribute :authors, :array
87
+ attribute :published, :date
88
+ attribute :sold, :time
89
+ attribute :finished, :date_time
90
+ attribute :rate, :float
91
+ end
92
+ ```
93
+
94
+ **0.6.0 (July 20, 2014)**
95
+ * Throw custom `FastAttributes::TypeCast::InvalidValueError` exception when value has invalid type.
96
+ How auto-generated method looks like:
97
+ ```ruby
98
+ FastAttributes.set_type_casting(String, 'String(%s)')
99
+ # def name=(value)
100
+ # @name = begin
101
+ # case value
102
+ # when nil then nil
103
+ # when String then value
104
+ # else String(value)
105
+ # end
106
+ # rescue => e
107
+ # raise FastAttributes::TypeCast::InvalidValueError, %(Invalid value "#{value}" for attribute "name" of type "String")
108
+ # end
109
+ # end
110
+ ```
111
+
112
+ * Add `on_error` method to override default rescue block:
113
+ ```ruby
114
+ FastAttributes.type_cast String do
115
+ from 'nil', to: 'nil'
116
+ from 'String', to: '%s'
117
+ otherwise 'String(%s)'
118
+ on_error 'ArgumentError', act: 'nil'
119
+ on_error 'TypeError', act: '""'
120
+ on_error 'StandardError', act: 'e.message'
121
+ end
122
+
123
+ # def name=(value)
124
+ # @name = begin
125
+ # case value
126
+ # when nil then nil
127
+ # when String then value
128
+ # else String(value)
129
+ # end
130
+ # rescue ArgumentError => e
131
+ # nil
132
+ # rescue TypeError => e
133
+ # ""
134
+ # rescue StandardError => e
135
+ # e.message
136
+ # end
137
+ # end
138
+ ```
139
+
140
+ **0.5.2 (July 18, 2014)**
141
+ * Throw proper exception when type casting function is not defined
142
+
143
+ **0.5.1 (July 16, 2014)**
144
+ * Fix `BigDecimal` type casting. It threw an exception when input value was `Float`
145
+
146
+ **0.5.0 (July 16, 2014)**
147
+ * Allow to control any switch statements during typecasting using new DSL.
148
+
149
+ The default typecasting rule which `fast_attributes` generates for `String` is:
150
+ ```ruby
151
+ case value
152
+ when nil then nil
153
+ when String then value
154
+ else String(%s)
155
+ end
156
+ ```
157
+ Method `FastAttributes.set_type_casting` allows only to change `else` condition.
158
+ ```ruby
159
+ FastAttributes.set_type_casting(String, 'String("#{%s}-suffix")')
160
+ ```
161
+
162
+ Using `FastAttributes.type_cast` method it's possible to define custom `switch` condition
163
+ ```ruby
164
+ FastAttributes.type_cast String do # case value
165
+ from 'nil', to: 'nil' # when nil then nil
166
+ from 'String', to: '%s' # when String then value
167
+ from Array, to: 'raise "Error"' # when Array then raise "Error"
168
+ otherwise 'String(%s)' # else String(value)
169
+ end # end
170
+ ```
171
+
172
+ * Add support to BigDecimal [Filipe Costa](https://github.com/applift/fast_attributes/pull/2)
173
+
174
+ **0.4.0 (July 5, 2014)**
175
+ * Allow to override generated methods
176
+
177
+ **0.3.0 (July 4, 2014)**
178
+ * Support `Float` data type
179
+
180
+ **0.2.2 (July 2, 2014)**
181
+ * Fix uninitialized `@type_casting` variable
182
+
183
+ **0.2.1 (June 27, 2014)**
184
+ * Set minimum ruby version to `1.9.2`
185
+
186
+ **0.2.0 (June 27, 2014)**
187
+ * Add `define_attributes` method which allows to generate `initialize` and `attributes`
188
+ * Raise `FastAttributes::UnsupportedTypeError` error when unknown attribute type is specified
189
+
190
+ **0.1.0 (June 26, 2014)**
191
+ * Support `Integer`, `String`, `Array`, `Date`, `Time` and `DateTime` attribute types
192
+
193
+ **0.0.1 (June 20, 2014)**
194
+ * Initial commit
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fast_attributes.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 AppLift GmbH
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # FastAttributes
2
+ [![Gem Version](http://img.shields.io/gem/v/fast_attributes.svg)](http://rubygems.org/gems/fast_attributes)
3
+ [![Build Status](http://img.shields.io/travis/applift/fast_attributes.svg)](https://travis-ci.org/applift/fast_attributes)
4
+ [![Coverage Status](http://img.shields.io/coveralls/applift/fast_attributes.svg)](https://coveralls.io/r/applift/fast_attributes?branch=master)
5
+ [![Code Climate](http://img.shields.io/codeclimate/github/applift/fast_attributes.svg)](https://codeclimate.com/github/applift/fast_attributes)
6
+ [![Dependency Status](http://img.shields.io/gemnasium/applift/fast_attributes.svg)](https://gemnasium.com/applift/fast_attributes)
7
+
8
+ ## Motivation
9
+ There are already a lot of good and flexible gems which solve a similar problem, allowing attributes to be defined with their types, for example: [virtus](https://github.com/solnic/virtus) or [attrio](https://github.com/jetrockets/attrio). However, the disadvantage of these gems is performance. So, the goal of `fast_attributes` is to provide a simple solution which is fast, understandable and extendable.
10
+
11
+ This is the [performance benchmark](https://github.com/applift/fast_attributes/blob/master/benchmarks/comparison.rb) of `fast_attributes` compared to other popular gems.
12
+
13
+ ```
14
+ Comparison:
15
+ FastAttributes: without values : 1528209.4 i/s
16
+ FastAttributes: integer values for integer attributes: 88794.2 i/s - 17.21x slower
17
+ FastAttributes: string values for integer attributes : 77673.3 i/s - 19.67x slower
18
+ Virtus: integer values for integer attributes : 21104.7 i/s - 72.41x slower
19
+ Attrio: integer values for integer attributes : 11932.2 i/s - 128.07x slower
20
+ Attrio: string values for integer attributes : 11007.2 i/s - 138.84x slower
21
+ Virtus: without values : 10151.0 i/s - 150.55x slower
22
+ Attrio: without values : 7164.3 i/s - 213.31x slower
23
+ Virtus: string values for integer attributes : 3195.6 i/s - 478.22x slower
24
+ ```
25
+
26
+ ## Installation
27
+
28
+ Add this line to your application's Gemfile:
29
+
30
+ gem 'fast_attributes'
31
+
32
+ And then execute:
33
+
34
+ $ bundle
35
+
36
+ Or install it yourself as:
37
+
38
+ $ gem install fast_attributes
39
+
40
+ ## Usage
41
+
42
+ Define getter/setter methods:
43
+ ```ruby
44
+ class Book
45
+ extend FastAttributes
46
+
47
+ attribute :title, :name, String
48
+ attribute :pages, Integer
49
+ attribute :authors, Array
50
+ attribute :published, Date
51
+ attribute :sold, Time
52
+ attribute :finished, DateTime
53
+ end
54
+
55
+ book = Book.new
56
+ book.title = 'There and Back Again'
57
+ book.name = 'The Hobbit'
58
+ book.pages = '200'
59
+ book.authors = 'Tolkien'
60
+ book.published = '1937-09-21'
61
+ book.sold = '2014-06-25 13:45'
62
+ book.finished = '1937-08-20 12:35'
63
+
64
+ #<Book:0x007f9a0110be20
65
+ @authors=["Tolkien"],
66
+ @finished=
67
+ #<DateTime: 1937-08-20T12:35:00+00:00 ((2428766j,45300s,0n),+0s,2299161j)>,
68
+ @name="The Hobbit",
69
+ @pages=200,
70
+ @published=#<Date: 1937-09-21 ((2428798j,0s,0n),+0s,2299161j)>,
71
+ @sold=2014-06-25 13:45:00 +0200,
72
+ @title="There and Back Again">
73
+ ```
74
+
75
+ To generate `initialize` and `attributes` methods, attribute definition should be wrapped with `define_attributes`:
76
+ ```ruby
77
+ class Book
78
+ extend FastAttributes
79
+
80
+ define_attributes initialize: true, attributes: true do
81
+ attribute :title, :name, String
82
+ attribute :pages, Integer
83
+ attribute :authors, Array
84
+ attribute :published, Date
85
+ attribute :sold, Time
86
+ attribute :finished, DateTime
87
+ end
88
+ end
89
+
90
+ book = Book.new(
91
+ title: 'There and Back Again',
92
+ name: 'The Hobbit',
93
+ pages: '200',
94
+ authors: 'Tolkien',
95
+ published: '1937-09-21',
96
+ sold: '2014-06-25 13:45',
97
+ finished: '1937-08-20 12:35'
98
+ )
99
+
100
+ book.attributes
101
+ {"title"=>"There and Back Again",
102
+ "name"=>"The Hobbit",
103
+ "pages"=>200,
104
+ "authors"=>["Tolkien"],
105
+ "published"=>#<Date: 1937-09-21 ((2428798j,0s,0n),+0s,2299161j)>,
106
+ "sold"=>2014-06-25 13:45:00 +0200,
107
+ "finished"=>
108
+ #<DateTime: 1937-08-20T12:35:00+00:00 ((2428766j,45300s,0n),+0s,2299161j)>}
109
+ ```
110
+
111
+ ## Default values
112
+
113
+ Requires `define_attributes` to be used with `initialize: true` (this is where the default values are set):
114
+
115
+ ```ruby
116
+ class Book
117
+ extend FastAttributes
118
+
119
+ define_attributes initialize: true do
120
+ attribute :author, String, default: "Some String"
121
+ end
122
+ end
123
+
124
+ book = Book.new
125
+ book.attributes
126
+ {"author" => "Some String"}
127
+ ```
128
+
129
+ ## Attributes via accessors
130
+
131
+ Sometimes you want `attributes` to return the value of your accessors, rather than the instance variables.
132
+ This is slower than using ivars directly, so use `attributes: :accessors`:
133
+
134
+ ```ruby
135
+ class Book
136
+ extend FastAttributes
137
+
138
+ define_attributes attributes: :accessors do
139
+ attribute :author, String
140
+ end
141
+
142
+ def author
143
+ @author || "No author set"
144
+ end
145
+ end
146
+
147
+ book = Book.new
148
+ book.attributes
149
+ {"author" => "No author set"}
150
+ ```
151
+
152
+
153
+ ## Custom Type
154
+ It's easy to add a custom attribute type.
155
+ ```ruby
156
+ FastAttributes.set_type_casting(OpenStruct, 'OpenStruct.new(name: %s)')
157
+
158
+ class Book
159
+ extend FastAttributes
160
+ attribute :author, OpenStruct
161
+ end
162
+
163
+ book = Book.new
164
+ book.author = 'Rowling'
165
+ book.author
166
+ # => #<OpenStruct name="Rowling">
167
+ ```
168
+
169
+ Notice, that second parameter is a string. It's necessary because this code is compiled into a ruby method in runtime. The placeholder `%s` represents a value which this method accepts.
170
+
171
+ It's possible to refer to a placeholder several times.
172
+ ```ruby
173
+ Size = Class.new(Array)
174
+ FastAttributes.set_type_casting Size, <<-EOS
175
+ Size[%s, %s]
176
+ EOS
177
+
178
+ class Square
179
+ extend FastAttributes
180
+ attribute :size, Size
181
+ end
182
+
183
+ square = Square.new
184
+ square.size = 5
185
+ square.size
186
+ # => [5, 5]
187
+ ```
188
+
189
+ Method `FastAttributes.set_type_casting` generates the following template:
190
+ ```ruby
191
+ FastAttributes.set_type_casting String, 'String(%s)'
192
+ # begin
193
+ # case %s
194
+ # when nil then nil
195
+ # when String then %s
196
+ # else String(%s)
197
+ # end
198
+ # rescue => e
199
+ # raise FastAttributes::TypeCast::InvalidValueError, %(Invalid value "\#{%s}" for attribute "%a" of type "String")
200
+ # end
201
+ ```
202
+ and when the attribute is defined, `fast_attributes` generates the following setter method:
203
+ ```ruby
204
+ class A
205
+ extend FastAttributes
206
+ attribute :name, String
207
+ end
208
+
209
+ # def name=(value)
210
+ # @name = begin
211
+ # case value
212
+ # when nil then nil
213
+ # when String then value
214
+ # else String(value)
215
+ # end
216
+ # rescue => e
217
+ # raise FastAttributes::TypeCast::InvalidValueError, %(Invalid value "#{value}" for attribute "name" of type "String")
218
+ # end
219
+ # end
220
+ ```
221
+ 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.
222
+
223
+ If you need to conrol the whole type casting process, you can use the following DSL:
224
+ ```ruby
225
+ FastAttributes.type_cast String do # begin
226
+ # case String
227
+ from 'nil', to: 'nil' # when nil then nil
228
+ from 'String', to: '%s' # when String then %s
229
+ otherwise 'String(%s)' # else String(%s)
230
+ # end
231
+ on_error 'TypeError', act: 'nil' # rescue TypeError => e
232
+ # nil
233
+ on_error 'StandardError', act: '""' # rescue StandardError => e
234
+ # ""
235
+ end # end
236
+ ```
237
+
238
+ ## Lenient Data Types
239
+ It's also possible to define a lenient data type which doesn't correspond to any of ruby classes:
240
+ ```ruby
241
+ FastAttributes.type_cast :yes_no do
242
+ from '"yes"', to: 'true'
243
+ from '"no"', to: 'false'
244
+ otherwise 'nil'
245
+ end
246
+
247
+ class Order
248
+ extend FastAttributes
249
+
250
+ attribute :terms_of_service, :yes_no
251
+ end
252
+
253
+ order = Order.new
254
+ order.terms_of_service = 'yes'
255
+ order.terms_of_service
256
+ # => true
257
+ order.terms_of_service = 'no'
258
+ order.terms_of_service
259
+ # => false
260
+ order.terms_of_service = 42
261
+ order.terms_of_service
262
+ # => nil
263
+ ```
264
+
265
+ All default data types have lenient notation:
266
+ ```ruby
267
+ class Book
268
+ extend FastAttributes
269
+
270
+ attribute :title, :string
271
+ attribute :pages, :integer
272
+ attribute :price, :big_decimal
273
+ attribute :authors, :array
274
+ attribute :published, :date
275
+ attribute :sold, :time
276
+ attribute :finished, :date_time
277
+ attribute :rate, :float
278
+ attribute :active, :boolean
279
+ end
280
+ ```
281
+ Notice, `Boolean` attribute can be defined only via symbol, `fast_attribute` doesn't create `Boolean` class.
282
+
283
+ ## Extensions
284
+ * [fast_attributes-uuid](https://github.com/applift/fast_attributes-uuid) - adds support of `UUID` to `fast_attributes`
285
+
286
+ ## Contributing
287
+
288
+ 1. Fork it ( http://github.com/applift/fast_attributes/fork )
289
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
290
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
291
+ 4. Push to the branch (`git push origin my-new-feature`)
292
+ 5. Create new Pull Request