riveter 0.0.6 → 0.0.7
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/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
|
[](https://coveralls.io/r/virtualstaticvoid/riveter)
|
7
7
|
[](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
|