riveter 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +21 -21
- data/README.md +233 -16
- data/app/helpers/riveter/enquiry_form_helper.rb +4 -0
- data/config/locales/validators.en.yml +5 -0
- data/lib/generators/riveter/command/templates/command.rb +1 -0
- data/lib/generators/riveter/query_filter/templates/query_filter.rb +2 -1
- data/lib/riveter.rb +5 -3
- data/lib/riveter/attributes.rb +58 -7
- data/lib/riveter/date_range_validator.rb +34 -0
- data/lib/riveter/enumerated.rb +1 -6
- data/lib/riveter/version.rb +1 -1
- data/riveter.gemspec +15 -15
- data/spec/examples/attribute_examples.rb +8 -6
- data/spec/helpers/riveter/enquiry_form_helper_spec.rb +16 -0
- data/spec/riveter/attributes_spec.rb +44 -10
- data/spec/riveter/booleaness_validator_spec.rb +60 -62
- data/spec/riveter/date_range_validator_spec.rb +97 -0
- data/spec/riveter/email_validator_spec.rb +73 -0
- data/spec/riveter/enumerated_spec.rb +2 -2
- data/spec/support/test_class_with_attributes.rb +1 -0
- data/spec/support/validate_date_range_of_matcher.rb +17 -0
- metadata +63 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ebc95b71c75212a93969b10807e5ed3e1d1748c
|
4
|
+
data.tar.gz: fa04871bf94a6a4a3fabd6144f161da7662ac802
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 654cb072df071d5b1ce69f10b85047750d514ee2d104245aae1ce0fc151ba7b2ef77110b226d9c811acd8f1f7073c2c149d3c1af430e30759a722562baa30183
|
7
|
+
data.tar.gz: 94a50c282014f605438bed1304124041ae735db5bd494e5d586380588673a6b2291a0b70d9df98e65affb173e11c7a6b3d23915604d43b25f664227c1b70f874
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
riveter (0.0.
|
5
|
-
actionpack
|
6
|
-
activemodel
|
7
|
-
activerecord
|
8
|
-
activesupport
|
4
|
+
riveter (0.0.7)
|
5
|
+
actionpack (~> 4.0.0)
|
6
|
+
activemodel (~> 4.0.0)
|
7
|
+
activerecord (~> 4.0.0)
|
8
|
+
activesupport (~> 4.0.0)
|
9
9
|
railties (~> 4.0.0)
|
10
|
-
validates_timeliness
|
10
|
+
validates_timeliness (~> 3.0.0)
|
11
11
|
|
12
12
|
GEM
|
13
13
|
remote: https://rubygems.org/
|
@@ -55,7 +55,7 @@ GEM
|
|
55
55
|
thor
|
56
56
|
debugger-linecache (1.2.0)
|
57
57
|
diff-lcs (1.2.5)
|
58
|
-
docile (1.1.
|
58
|
+
docile (1.1.5)
|
59
59
|
erubis (2.7.0)
|
60
60
|
haml (4.0.5)
|
61
61
|
tilt
|
@@ -72,8 +72,8 @@ GEM
|
|
72
72
|
method_source (0.8.2)
|
73
73
|
mime-types (1.25.1)
|
74
74
|
minitest (4.7.5)
|
75
|
-
multi_json (1.10.
|
76
|
-
polyglot (0.3.
|
75
|
+
multi_json (1.10.1)
|
76
|
+
polyglot (0.3.5)
|
77
77
|
pry (0.9.12.6)
|
78
78
|
coderay (~> 1.0)
|
79
79
|
method_source (~> 0.8)
|
@@ -97,7 +97,7 @@ GEM
|
|
97
97
|
activesupport (= 4.0.5)
|
98
98
|
rake (>= 0.8.7)
|
99
99
|
thor (>= 0.18.1, < 2.0)
|
100
|
-
rake (10.3.
|
100
|
+
rake (10.3.2)
|
101
101
|
rest-client (1.6.7)
|
102
102
|
mime-types (>= 1.16)
|
103
103
|
rspec-core (2.14.8)
|
@@ -120,7 +120,7 @@ GEM
|
|
120
120
|
simplecov-html (~> 0.8.0)
|
121
121
|
simplecov-html (0.8.0)
|
122
122
|
slop (3.5.0)
|
123
|
-
sprockets (2.
|
123
|
+
sprockets (2.12.1)
|
124
124
|
hike (~> 1.2)
|
125
125
|
multi_json (~> 1.0)
|
126
126
|
rack (~> 1.0)
|
@@ -132,7 +132,7 @@ GEM
|
|
132
132
|
term-ansicolor (1.3.0)
|
133
133
|
tins (~> 1.0)
|
134
134
|
thor (0.19.1)
|
135
|
-
thread_safe (0.3.
|
135
|
+
thread_safe (0.3.4)
|
136
136
|
tilt (1.4.1)
|
137
137
|
timeliness (0.3.7)
|
138
138
|
tins (1.3.0)
|
@@ -147,14 +147,14 @@ PLATFORMS
|
|
147
147
|
ruby
|
148
148
|
|
149
149
|
DEPENDENCIES
|
150
|
-
ammeter
|
151
|
-
bundler (~> 1.
|
152
|
-
coveralls
|
153
|
-
haml-rails
|
154
|
-
pry
|
155
|
-
pry-byebug
|
156
|
-
rails (~> 4.0.
|
157
|
-
rake
|
150
|
+
ammeter (~> 1.0.0)
|
151
|
+
bundler (~> 1.6.0)
|
152
|
+
coveralls (~> 0.7.0)
|
153
|
+
haml-rails (~> 0.5.0)
|
154
|
+
pry (~> 0.9.0)
|
155
|
+
pry-byebug (~> 1.3.0)
|
156
|
+
rails (~> 4.0.0)
|
157
|
+
rake (~> 10.3.0)
|
158
158
|
riveter!
|
159
|
-
rspec-rails
|
159
|
+
rspec-rails (~> 2.14.0)
|
160
160
|
shoulda-matchers (~> 2.6.1)
|
data/README.md
CHANGED
@@ -6,19 +6,238 @@
|
|
6
6
|
[![Coverage Status](https://coveralls.io/repos/virtualstaticvoid/riveter/badge.png)](https://coveralls.io/r/virtualstaticvoid/riveter)
|
7
7
|
[![Dependency Status](https://gemnasium.com/virtualstaticvoid/riveter.svg)](https://gemnasium.com/virtualstaticvoid/riveter)
|
8
8
|
|
9
|
-
Provides several useful patterns, packaged in a gem, for use in Rails
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
Provides several useful patterns, packaged in a gem, for use in Rails and other web based applications, including generators to help improve
|
10
|
+
consistency in your applications.
|
11
|
+
|
12
|
+
## Motivation
|
13
|
+
In an effort to refactor large Rails applications, a number of patterns emerged, which this gem seeks to formalize. Encapsulating
|
14
|
+
each pattern helps provide consistency and promotes standardization of implementation in a team of developers. Also, having generators
|
15
|
+
to create all the necessary classes and specs helps developers follow the standards more easily and prevents unnecessary coding and
|
16
|
+
ensures the focus remains on the business problem being solved instead.
|
17
|
+
|
18
|
+
Some of these patterns have been discussed at length within the Ruby and Rails communities, with many people making cases for
|
19
|
+
and against some of these patterns. The important thing to bear in mind is that there is no "one" solution for everything, nor
|
20
|
+
"one" way to solve a problem, so these patterns will _not_ always be applicable. Please use them where it makes sense to do so, and
|
21
|
+
the solution to the problem you are trying to solve becomes clearer by doing so.
|
22
|
+
|
23
|
+
## Patterns Included
|
24
|
+
The following patterns are included, and an explaination of each follows:
|
25
|
+
|
26
|
+
### Enumerated
|
27
|
+
Rails 4+ now has support for enumerated attributes on models, however the `Riverter::Enumerated` module is a slightly different take on
|
28
|
+
the idea but can still be used on conjunction with the default functionality.
|
29
|
+
|
30
|
+
You define an enumerated type by creating a module, adding the desired members as constants and then include the `Riveter::Enumerated` module.
|
31
|
+
|
32
|
+
E.g. Module containing enumeration members:
|
33
|
+
```ruby
|
34
|
+
module FooStatusEnum
|
35
|
+
Bar = 1
|
36
|
+
Baz = 2
|
37
|
+
|
38
|
+
include Riveter::Enumerated
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
The `FooStatusEnum` module will now have the following methods exposed:
|
43
|
+
|
44
|
+
* `::All` - a constant which behaves like an `Array` for enumerating the members. E.g. `FooBarStatusEnum::All #=> [FooBarStatusEnum::Member1, FooBarStatusEnum::Member2]`
|
45
|
+
* `human` - if a locale file is provided, gives the human name for the enumeration. E.g. `FooStatusEnum.human #=> "Foo Status"`
|
46
|
+
* `names` - lists all the member names. E.g. `FooStatusEnum.names #=> [Bar, Baz]`
|
47
|
+
* `values` - lists all the member values. E.g. `FooStatusEnum.values #=> [1, 2]`
|
48
|
+
* `collection` - provides a collection of the members for use in form inputs.
|
49
|
+
|
50
|
+
And when enumerating over the members using `FooStatusEnum::All`, each member will have the following methods:
|
51
|
+
|
52
|
+
* `name` - the member name
|
53
|
+
* `human` - if a locale file is provided, gives the human name for the member
|
54
|
+
* `value` - the member value
|
55
|
+
|
56
|
+
### QueryFilter
|
57
|
+
A common requirement in a Rails application is to collect criteria from the user and then prepairing a query using those criteria
|
58
|
+
within the `where` clauses. The query filter pattern encapsulates the criteria attributes so that they can be converted from params
|
59
|
+
and validated prior to building up the query.
|
60
|
+
|
61
|
+
Create a class which inherits from `Riveter::QueryFilter::Base` and then define the attributes, their default values and validations as needed.
|
62
|
+
|
63
|
+
E.g. Query filter example class
|
64
|
+
```ruby
|
65
|
+
class FooQueryFilter < Riveter::QueryFilter::Base
|
66
|
+
attr_string :bar_like, :required => true
|
67
|
+
attr_boolean :baz, :default => true
|
68
|
+
attr_date :qux, :default => { Time.now }
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
There are a number of `attr_*` methods as follows:
|
73
|
+
|
74
|
+
* `attr_string`
|
75
|
+
* `attr_integer`
|
76
|
+
* `attr_decimal`
|
77
|
+
* `attr_date`
|
78
|
+
* `attr_date_range`
|
79
|
+
* `attr_time`
|
80
|
+
* `attr_boolean`
|
81
|
+
* `attr_enum`
|
82
|
+
* `attr_array`
|
83
|
+
* `attr_hash`
|
84
|
+
* `attr_model`
|
85
|
+
* `attr_object`
|
86
|
+
|
87
|
+
In your controller, create an instance of the query filter as if it were a model. It can be used within your views easily as there is
|
88
|
+
a view helper method, `query_filter_form_for`, which makes it easy to build HTML forms for the specified attributes.
|
89
|
+
If you have `simple_form` installed, it will behave like a `simple_form_for`, otherwise the standard Rails `form_for` is used.
|
90
|
+
|
91
|
+
E.g. Controller example
|
92
|
+
```ruby
|
93
|
+
class FooController < ApplicationController
|
94
|
+
|
95
|
+
def new_search
|
96
|
+
@query_filter = FooQueryFilter.new()
|
97
|
+
end
|
98
|
+
|
99
|
+
def search
|
100
|
+
@query_filter = FooQueryFilter.new(foo_query_filter_params)
|
101
|
+
respond_to do |format|
|
102
|
+
if @query_filter.valid?
|
103
|
+
# E.g. your query logic here
|
104
|
+
@list = BarModel.where(:bar => @query_filter.bar_like)
|
105
|
+
.where(:baz => @query_filter.baz)
|
106
|
+
.where(:qux => @query_filter.qux)
|
107
|
+
format.html
|
108
|
+
else
|
109
|
+
format.html {render :action => :new_search}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def foo_query_filter_params
|
116
|
+
params.require(:foo_query_filter).permit(:bar_like, :baz, :qux)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
### Query
|
122
|
+
Given that the query filter is encapsulated, it follows that the query, which is built using the query filter, should be encapsulated too.
|
123
|
+
Also, considering the controller example code above, it would be better to encapsulate the building of the query into it's own class, instead
|
124
|
+
of coding it in the controller, especially if the criteria is applied conditionally to the query.
|
125
|
+
|
126
|
+
By abstracting the query filter and query as separate classes, it is easier to test each component individually, and there are greater
|
127
|
+
possibility for reuse of either class in other scenarios.
|
128
|
+
|
129
|
+
Create a class which inherits from `Riveter::Query::Base` class and implement the `build_relation` method to define the query.
|
130
|
+
|
131
|
+
E.g. The query class
|
132
|
+
```ruby
|
133
|
+
class FooQuery < Riveter::Query::Base
|
134
|
+
def build_relation(filter)
|
135
|
+
query = FooModel.all
|
136
|
+
|
137
|
+
# apply criteria to the query conditionally...
|
138
|
+
if filter.bar_like.present?
|
139
|
+
query = query.where(:bar => filter.bar_like)
|
140
|
+
end
|
141
|
+
|
142
|
+
...
|
143
|
+
|
144
|
+
query
|
145
|
+
end
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
The `FooQuery` with now have the following methods, which help in rendering the results in your views:
|
150
|
+
|
151
|
+
* `has_data?` - given the relation provided, yields true to indicate whether there is result data
|
152
|
+
* `relation` - the built relation
|
153
|
+
* `find_each` - this method is used to enumerate over the result data in the most efficient way
|
154
|
+
|
155
|
+
### Enquiry
|
156
|
+
Since the query filter and query encapsulate filtering and querying, and as they are defined individually, it follows that
|
157
|
+
there should be a way to bring them together, and thus make them easier to work with in controllers and views.
|
158
|
+
|
159
|
+
An enquiry is defined by specifying the query filter and query to use. Provide a class which inherits from `Riveter::Enquiry::Base` and
|
160
|
+
specify which query filter and query to use with the `filter_with` and `query_with` methods respectively.
|
161
|
+
|
162
|
+
E.g. A simple enquiry class
|
163
|
+
```ruby
|
164
|
+
class FooEnquiry < Riveter::Enquiry::Base
|
165
|
+
filter_with FooQueryFilter
|
166
|
+
query_with FooQuery
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
In your controller, create an instance of the enquiry as if it were a model. It can be used within your views as there is
|
171
|
+
a view helper method, `enquiry_form_for`, which makes it easy to build HTML forms for the specified attributes of the query filter.
|
172
|
+
If you have `simple_form` installed, it will behave like a `simple_form_for`, otherwise the standard Rails `form_for` is used.
|
173
|
+
|
174
|
+
Then on submission of the form, call the `submit` method passing in the form parameters, and then enumerate over the resultant data
|
175
|
+
using the `find_each` method.
|
176
|
+
|
177
|
+
E.g. An example enquiry controller
|
178
|
+
```ruby
|
179
|
+
class FooEnquiryController < ApplicationController
|
180
|
+
def index
|
181
|
+
@enquiry = FooEnquiry.new()
|
182
|
+
respond_to do |format|
|
183
|
+
unless @enquiry.submit(enquiry_params)
|
184
|
+
flash[:notice] = 'Invalid enquiry criteria, please correct and try again.'
|
185
|
+
end
|
186
|
+
format.html
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
def enquiry_params
|
192
|
+
params
|
193
|
+
.require(:foo_enquiry)
|
194
|
+
.permit(:bar_like, :baz, :qux)
|
195
|
+
.merge(:page => params.fetch(:page, 1))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
```
|
199
|
+
|
200
|
+
And the corresponding view, in HAML using `simple_form_for` to build the criteria inputs and Kaminari for pagination:
|
201
|
+
```haml
|
202
|
+
.criteria
|
203
|
+
= enquiry_form_for(@enquiry) do |f|
|
204
|
+
= f.input :bar_like
|
205
|
+
= f.input :baz
|
206
|
+
= f.input :qux
|
207
|
+
|
208
|
+
.results
|
209
|
+
%table
|
210
|
+
%tr
|
211
|
+
%th Foo
|
212
|
+
%th Bar
|
213
|
+
%th Baz
|
214
|
+
- unless @enquiry.has_data?
|
215
|
+
%tr
|
216
|
+
%td(colspan=3)
|
217
|
+
No data found for enquiry...
|
218
|
+
- else
|
219
|
+
- @enquiry.find_each do |result|
|
220
|
+
%tr
|
221
|
+
%td= result.bar
|
222
|
+
%td= result.bax
|
223
|
+
%td= result.qux
|
224
|
+
= paginate_enquiry(@enquiry)
|
225
|
+
```
|
226
|
+
|
227
|
+
### EnquiryController
|
228
|
+
_TDB_
|
229
|
+
|
230
|
+
### Command
|
231
|
+
_TDB_
|
232
|
+
|
233
|
+
### CommandController
|
234
|
+
_TDB_
|
235
|
+
|
236
|
+
### Service
|
237
|
+
_TDB_
|
238
|
+
|
239
|
+
### Presenter
|
240
|
+
_TDB_
|
22
241
|
|
23
242
|
## Installation
|
24
243
|
|
@@ -44,9 +263,7 @@ To get the list of available generators, execute:
|
|
44
263
|
|
45
264
|
The generator names are prefixed with `riveter`.
|
46
265
|
|
47
|
-
E.g.
|
48
|
-
|
49
|
-
To generate an enquiry controller, query filter, query, views and associated specs, execute:
|
266
|
+
E.g. To generate an enquiry controller, query filter, query, views and associated specs, execute:
|
50
267
|
|
51
268
|
$ rails generate riveter:enquiry SomeEnquiryName filter1:string filter2:integer:required
|
52
269
|
|
@@ -12,5 +12,9 @@ module Riveter
|
|
12
12
|
simple_form_for(enquiry.query_filter, options, &block) :
|
13
13
|
form_for(enquiry.query_filter, options, &block)
|
14
14
|
end
|
15
|
+
|
16
|
+
def paginate_enquiry(enquiry, options={}, &block)
|
17
|
+
paginate(enquiry.query, options, &block) if respond_to?(:paginate)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
@@ -24,3 +24,8 @@ en:
|
|
24
24
|
messages:
|
25
25
|
booleaness: is not valid
|
26
26
|
email: is not valid
|
27
|
+
invalid_date: is not a valid date
|
28
|
+
invalid_time: is not a valid time
|
29
|
+
date_range: is not a valid date range
|
30
|
+
date_range_date_from: "must be before %{date_to}"
|
31
|
+
date_range_date_to: "must be after %{date_from}"
|
@@ -25,6 +25,7 @@ class <%= class_name %>QueryFilter < Riveter::QueryFilter::Base
|
|
25
25
|
# attr_integer
|
26
26
|
# attr_decimal
|
27
27
|
# attr_date
|
28
|
+
# attr_date_range
|
28
29
|
# attr_time
|
29
30
|
# attr_boolean
|
30
31
|
# attr_enum
|
@@ -37,4 +38,4 @@ class <%= class_name %>QueryFilter < Riveter::QueryFilter::Base
|
|
37
38
|
<% end -%>
|
38
39
|
|
39
40
|
end
|
40
|
-
<% end -%>
|
41
|
+
<% end -%>
|
data/lib/riveter.rb
CHANGED
@@ -12,8 +12,11 @@ module Riveter
|
|
12
12
|
autoload :AttributeDefaultValues, 'riveter/attribute_default_values'
|
13
13
|
autoload :AssociatedTypeRegistry, 'riveter/associated_type_registry'
|
14
14
|
autoload :Attributes, 'riveter/attributes'
|
15
|
+
autoload :BooleanessValidator, 'riveter/booleaness_validator'
|
15
16
|
autoload :Command, 'riveter/command'
|
16
17
|
autoload :CommandController, 'riveter/command_controller'
|
18
|
+
autoload :DateRangeValidator, 'riveter/date_range_validator'
|
19
|
+
autoload :EmailValidator, 'riveter/email_validator'
|
17
20
|
autoload :Enquiry, 'riveter/enquiry'
|
18
21
|
autoload :EnquiryController, 'riveter/enquiry_controller'
|
19
22
|
autoload :Enumerated, 'riveter/enumerated'
|
@@ -28,6 +31,7 @@ end
|
|
28
31
|
module ActiveModel
|
29
32
|
module Validations
|
30
33
|
autoload :BooleanessValidator, 'riveter/booleaness_validator'
|
34
|
+
autoload :DateRangeValidator, 'riveter/date_range_validator'
|
31
35
|
autoload :EmailValidator, 'riveter/email_validator'
|
32
36
|
end
|
33
37
|
end
|
@@ -40,6 +44,4 @@ require 'riveter/rails/railtie' if defined?(::Rails::Railtie)
|
|
40
44
|
require 'riveter/rails/engine' if defined?(::Rails)
|
41
45
|
|
42
46
|
# include locale in load path
|
43
|
-
Dir
|
44
|
-
I18n.load_path << file
|
45
|
-
end
|
47
|
+
I18n.load_path += Dir.glob(File.expand_path('../../config/locales/*.yml', __FILE__))
|
data/lib/riveter/attributes.rb
CHANGED
@@ -54,6 +54,62 @@ module Riveter
|
|
54
54
|
|
55
55
|
alias :attr_datetime :attr_time
|
56
56
|
|
57
|
+
def attr_date_range(name, options={}, &block)
|
58
|
+
options = {
|
59
|
+
:validate => true
|
60
|
+
}.merge(options)
|
61
|
+
|
62
|
+
required = (true == options.delete(:required))
|
63
|
+
|
64
|
+
# expecting the default value to be a date range
|
65
|
+
# so extract out the first and last parts for the from and to
|
66
|
+
# otherwise, it may just be a date or nil
|
67
|
+
default = options.delete(:default)
|
68
|
+
default = default.is_a?(Range) ? default : (default..default)
|
69
|
+
defaults = {
|
70
|
+
:from => default.first,
|
71
|
+
:to => default.last
|
72
|
+
}
|
73
|
+
|
74
|
+
converter = block_given? ? block : Converters.converter_for(:date)
|
75
|
+
|
76
|
+
# return from and to as range
|
77
|
+
define_method name do
|
78
|
+
# can't have range starting or ending with nil, so return nil
|
79
|
+
send(:"#{name}_from")..send(:"#{name}_to") rescue nil
|
80
|
+
end
|
81
|
+
|
82
|
+
define_method "#{name}=" do |value|
|
83
|
+
value ||= nil..nil
|
84
|
+
range = value.is_a?(Range) ? value : value..value
|
85
|
+
send(:"#{name}_from=", range.first)
|
86
|
+
send(:"#{name}_to=", range.last)
|
87
|
+
end
|
88
|
+
|
89
|
+
validates name,
|
90
|
+
:allow_nil => !required,
|
91
|
+
:date_range => true if options[:validate]
|
92
|
+
|
93
|
+
add_attr(name, :date_range)
|
94
|
+
|
95
|
+
# break down into parts
|
96
|
+
[:from, :to].each do |part|
|
97
|
+
attr_reader_with_converter :"#{name}_#{part}", converter
|
98
|
+
|
99
|
+
define_method :"#{name}_#{part}?" do
|
100
|
+
send(:"#{name}_#{part}").present?
|
101
|
+
end
|
102
|
+
|
103
|
+
attr_writer :"#{name}_#{part}"
|
104
|
+
|
105
|
+
validates :"#{name}_#{part}",
|
106
|
+
:allow_nil => !required,
|
107
|
+
:timeliness => { :type => :date } if options[:validate]
|
108
|
+
|
109
|
+
add_attr(:"#{name}_#{part}", :date, converter, options.merge(:default => defaults[part]))
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
57
113
|
def attr_boolean(name, options={}, &block)
|
58
114
|
options = {
|
59
115
|
:validate => true
|
@@ -65,11 +121,6 @@ module Riveter
|
|
65
121
|
attr_reader_with_converter name, converter
|
66
122
|
alias_method "#{name}?", name
|
67
123
|
|
68
|
-
validates name,
|
69
|
-
:allow_blank => !required,
|
70
|
-
:allow_nil => !required,
|
71
|
-
:booleaness => true if options[:validate]
|
72
|
-
|
73
124
|
attr_writer name
|
74
125
|
|
75
126
|
add_attr(name, :boolean, converter, options)
|
@@ -100,7 +151,7 @@ module Riveter
|
|
100
151
|
validates name,
|
101
152
|
:allow_blank => !required,
|
102
153
|
:allow_nil => !required,
|
103
|
-
:inclusion => { :in => enum.
|
154
|
+
:inclusion => { :in => enum.values } if options[:validate]
|
104
155
|
|
105
156
|
attr_writer name
|
106
157
|
|
@@ -244,7 +295,7 @@ module Riveter
|
|
244
295
|
add_attr(name, type, converter, options)
|
245
296
|
end
|
246
297
|
|
247
|
-
def add_attr(name, type, converter, options={})
|
298
|
+
def add_attr(name, type, converter=nil, options={})
|
248
299
|
self._attributes[name] = attribute_info = AttributeInfo.new(name, type, converter, options)
|
249
300
|
validates name, :presence => true if attribute_info.required?
|
250
301
|
attribute_info
|