scrivener 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +108 -70
- data/lib/scrivener.rb +12 -8
- data/test/scrivener_test.rb +9 -1
- metadata +14 -13
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a1646faeced5318ac81a17b7fc8d05b59508b0d9
|
4
|
+
data.tar.gz: 80b3fa99edfe7c6e079bafa33fe3e90870701d5d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 207456238ab18834fa1ab9834610e19a20def26196fac1780edaee47ed6046d2581cbae5c0a07e58877c4a30b85e5a3a347b21406b0a910900ae19488c5e1ea7
|
7
|
+
data.tar.gz: 5a8fe4ca21cd06578fa4287324f44ce58420ac8c9f7d87f1dccd34e0df3348eb7c2c10aa176a2ec6dd52cce3649a68af8dc1afdc152f789af22f1b4d2caecb27
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ and its features are a subset of Bureaucrat's. For a more robust and tested
|
|
23
23
|
solution, please [check it](https://github.com/tizoc/bureaucrat).
|
24
24
|
|
25
25
|
This library exists to satify the need of extracting Ohm's validations for
|
26
|
-
reuse in other scenarios. By doing this, all projects using Ohm::Validations
|
26
|
+
reuse in other scenarios. By doing this, all projects using `Ohm::Validations`
|
27
27
|
will be able to profit from extra assertions such as those provided by
|
28
28
|
[ohm-contrib](https://github.com/cyx/ohm-contrib).
|
29
29
|
|
@@ -32,35 +32,35 @@ Usage
|
|
32
32
|
|
33
33
|
Using Scrivener feels very natural no matter what underlying model you are
|
34
34
|
using. As it provides its own validation and whitelisting features, you can
|
35
|
-
|
35
|
+
choose to ignore the ones that come bundled with ORMs.
|
36
36
|
|
37
37
|
This short example illustrates how to move the validation and whitelisting
|
38
38
|
responsibilities away from the model and into Scrivener:
|
39
39
|
|
40
40
|
```ruby
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
41
|
+
# We use Sequel::Model in this example, but it applies to other ORMs such
|
42
|
+
# as Ohm or ActiveRecord.
|
43
|
+
class Article < Sequel::Model
|
44
|
+
|
45
|
+
# Whitelist for mass assigned attributes.
|
46
|
+
set_allowed_columns :title, :body, :state
|
47
|
+
|
48
|
+
# Validations for all contexts.
|
49
|
+
def validate
|
50
|
+
validates_presence :title
|
51
|
+
validates_presence :body
|
52
|
+
validates_presence :state
|
53
|
+
end
|
54
|
+
end
|
55
55
|
|
56
|
-
|
57
|
-
|
56
|
+
title = "Bartleby, the Scrivener"
|
57
|
+
body = "I am a rather elderly man..."
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
# When using the model...
|
60
|
+
article = Article.new(title: title, body: body)
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
article.valid? #=> false
|
63
|
+
article.errors.on(:state) #=> ["cannot be empty"]
|
64
64
|
```
|
65
65
|
|
66
66
|
Of course, what you would do instead is declare `:title` and `:body` as allowed
|
@@ -72,55 +72,94 @@ feature and in others is a minor obstacle.
|
|
72
72
|
Now see what happens with Scrivener:
|
73
73
|
|
74
74
|
```ruby
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
# Now the model has no validations or whitelists. It may still have schema
|
76
|
+
# constraints, which is a good practice to enforce data integrity.
|
77
|
+
class Article < Sequel::Model
|
78
|
+
end
|
79
|
+
|
80
|
+
# The attribute accessors are the only fields that will be set. If more
|
81
|
+
# fields are sent when using mass assignment, a NoMethodError exception is
|
82
|
+
# raised.
|
83
|
+
#
|
84
|
+
# Note how in this example we don't accept the status attribute.
|
85
|
+
class Edit < Scrivener
|
86
|
+
attr_accessor :title
|
87
|
+
attr_accessor :body
|
88
|
+
|
89
|
+
def validate
|
90
|
+
assert_present :title
|
91
|
+
assert_present :body
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
edit = Edit.new(title: title, body: body)
|
96
|
+
edit.valid? #=> true
|
97
|
+
|
98
|
+
article = Article.new(edit.attributes)
|
99
|
+
article.save
|
100
|
+
|
101
|
+
# And now we only ask for the status.
|
102
|
+
class Publish < Scrivener
|
103
|
+
attr_accessor :status
|
104
|
+
|
105
|
+
def validate
|
106
|
+
assert_format :status, /^(published|draft)$/
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
publish = Publish.new(status: "published")
|
111
|
+
publish.valid? #=> true
|
112
|
+
|
113
|
+
article.update_attributes(publish.attributes)
|
114
|
+
|
115
|
+
# If we try to change other fields...
|
116
|
+
publish = Publish.new(status: "published", title: "foo")
|
117
|
+
#=> NoMethodError: undefined method `title=' for #<Publish...>
|
118
|
+
```
|
79
119
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
attr_accessor :title
|
87
|
-
attr_accessor :body
|
88
|
-
|
89
|
-
def validate
|
90
|
-
assert_present :title
|
91
|
-
assert_present :body
|
92
|
-
end
|
93
|
-
end
|
120
|
+
It's important to note that using Scrivener implies a greater risk than using
|
121
|
+
the model validations. Having a central repository of mass assignable
|
122
|
+
attributes and validations is more secure in most scenarios.
|
123
|
+
|
124
|
+
Slices
|
125
|
+
------
|
94
126
|
|
95
|
-
|
96
|
-
|
127
|
+
If you don't need all the attributes after the filtering is done,
|
128
|
+
you can fetch just the ones you need. For example:
|
97
129
|
|
98
|
-
|
99
|
-
|
130
|
+
```ruby
|
131
|
+
class SignUp < Scrivener
|
132
|
+
attr_accessor :email
|
133
|
+
attr_accessor :password
|
134
|
+
attr_accessor :password_confirmation
|
100
135
|
|
101
|
-
|
102
|
-
|
103
|
-
attr_accessor :status
|
136
|
+
def validate
|
137
|
+
assert_email :email
|
104
138
|
|
105
|
-
|
106
|
-
|
107
|
-
end
|
139
|
+
if assert_present :password
|
140
|
+
assert_equal :password, :password_confirmation
|
108
141
|
end
|
142
|
+
end
|
109
143
|
|
110
|
-
|
111
|
-
|
144
|
+
def assert_equal(f1, f2)
|
145
|
+
assert send(f1) == send(f2), [f1, f2, :not_equal]
|
146
|
+
end
|
147
|
+
end
|
112
148
|
|
113
|
-
|
149
|
+
filter = SignUp.new(email: "info@example.com",
|
150
|
+
password: "monkey",
|
151
|
+
password_confirmation: "monkey")
|
114
152
|
|
115
|
-
# If we try to change other fields...
|
116
|
-
publish = Publish.new(status: "published", title: "foo")
|
117
|
-
#=> NoMethodError: undefined method `title=' for #<Publish...>
|
118
|
-
```
|
119
153
|
|
120
|
-
|
121
|
-
|
122
|
-
|
154
|
+
# If the validation succeeds, we only need email and password to
|
155
|
+
# create a new user, and we can discard the password_confirmation.
|
156
|
+
if filter.valid?
|
157
|
+
User.create(filter.slice(:email, :password))
|
158
|
+
end
|
159
|
+
```
|
123
160
|
|
161
|
+
By calling `slice` with a list of attributes, you get a hash with only
|
162
|
+
those key/value pairs.
|
124
163
|
|
125
164
|
Assertions
|
126
165
|
-----------
|
@@ -135,9 +174,9 @@ second parameter to the list of errors if the first parameter evaluates
|
|
135
174
|
to false.
|
136
175
|
|
137
176
|
``` ruby
|
138
|
-
|
139
|
-
|
140
|
-
|
177
|
+
def assert(value, error)
|
178
|
+
value or errors[error.first].push(error.last) && false
|
179
|
+
end
|
141
180
|
```
|
142
181
|
|
143
182
|
### assert_present
|
@@ -174,9 +213,9 @@ Checks that a given field is contained within a set of values (i.e.
|
|
174
213
|
like an `ENUM`).
|
175
214
|
|
176
215
|
``` ruby
|
177
|
-
|
178
|
-
|
179
|
-
|
216
|
+
def validate
|
217
|
+
assert_member :state, %w{pending paid delivered}
|
218
|
+
end
|
180
219
|
```
|
181
220
|
|
182
221
|
The error code for this assertion is `:not_valid`
|
@@ -186,9 +225,9 @@ The error code for this assertion is `:not_valid`
|
|
186
225
|
Checks that a given field's length falls under a specified range.
|
187
226
|
|
188
227
|
``` ruby
|
189
|
-
|
190
|
-
|
191
|
-
|
228
|
+
def validate
|
229
|
+
assert_length :username, 3..20
|
230
|
+
end
|
192
231
|
```
|
193
232
|
|
194
233
|
The error code for this assertion is `:not_in_range`.
|
@@ -200,7 +239,6 @@ of the word. Valid numbers are: 0.1, .1, 1, 1.1, 3.14159, etc.
|
|
200
239
|
|
201
240
|
The error code for this assertion is `:not_decimal`.
|
202
241
|
|
203
|
-
|
204
242
|
Installation
|
205
243
|
------------
|
206
244
|
|
data/lib/scrivener.rb
CHANGED
@@ -1,16 +1,13 @@
|
|
1
|
-
|
1
|
+
require_relative "scrivener/validations"
|
2
2
|
|
3
3
|
class Scrivener
|
4
|
-
VERSION = "0.0
|
4
|
+
VERSION = "0.1.0"
|
5
5
|
|
6
6
|
include Validations
|
7
7
|
|
8
8
|
# Initialize with a hash of attributes and values.
|
9
9
|
# If extra attributes are sent, a NoMethodError exception will be raised.
|
10
10
|
#
|
11
|
-
# The grand daddy of all assertions. If you want to build custom
|
12
|
-
# assertions, or even quick and dirty ones, you can simply use this method.
|
13
|
-
#
|
14
11
|
# @example
|
15
12
|
#
|
16
13
|
# class EditPost < Scrivener
|
@@ -37,8 +34,8 @@ class Scrivener
|
|
37
34
|
# # Now it's safe to initialize the model.
|
38
35
|
# post = Post.new(edit.attributes)
|
39
36
|
# post.save
|
40
|
-
def initialize(
|
41
|
-
|
37
|
+
def initialize(atts)
|
38
|
+
atts.each do |key, val|
|
42
39
|
send(:"#{key}=", val)
|
43
40
|
end
|
44
41
|
end
|
@@ -54,5 +51,12 @@ class Scrivener
|
|
54
51
|
end
|
55
52
|
end
|
56
53
|
end
|
57
|
-
end
|
58
54
|
|
55
|
+
def slice(*keys)
|
56
|
+
Hash.new.tap do |atts|
|
57
|
+
keys.each do |att|
|
58
|
+
atts[att] = send(att)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/test/scrivener_test.rb
CHANGED
@@ -27,6 +27,14 @@ scope do
|
|
27
27
|
|
28
28
|
assert_equal atts, s.attributes
|
29
29
|
end
|
30
|
+
|
31
|
+
test "return only the required attributes" do
|
32
|
+
atts = { :a => 1, :b => 2 }
|
33
|
+
|
34
|
+
s = S.new(atts)
|
35
|
+
|
36
|
+
assert_equal s.slice(:a), { :a => 1 }
|
37
|
+
end
|
30
38
|
end
|
31
39
|
|
32
40
|
class T < Scrivener
|
@@ -190,4 +198,4 @@ scope do
|
|
190
198
|
assert p.valid?
|
191
199
|
end
|
192
200
|
end
|
193
|
-
end
|
201
|
+
end
|
metadata
CHANGED
@@ -1,27 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scrivener
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Michel Martens
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2013-04-25 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: cutest
|
16
|
-
requirement:
|
17
|
-
none: false
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
25
27
|
description: Scrivener removes the validation responsibility from models and acts
|
26
28
|
as a filter for whitelisted attributes.
|
27
29
|
email:
|
@@ -40,26 +42,25 @@ files:
|
|
40
42
|
- test/scrivener_test.rb
|
41
43
|
homepage: http://github.com/soveran/scrivener
|
42
44
|
licenses: []
|
45
|
+
metadata: {}
|
43
46
|
post_install_message:
|
44
47
|
rdoc_options: []
|
45
48
|
require_paths:
|
46
49
|
- lib
|
47
50
|
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
-
none: false
|
49
51
|
requirements:
|
50
|
-
- -
|
52
|
+
- - '>='
|
51
53
|
- !ruby/object:Gem::Version
|
52
54
|
version: '0'
|
53
55
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
-
none: false
|
55
56
|
requirements:
|
56
|
-
- -
|
57
|
+
- - '>='
|
57
58
|
- !ruby/object:Gem::Version
|
58
59
|
version: '0'
|
59
60
|
requirements: []
|
60
61
|
rubyforge_project:
|
61
|
-
rubygems_version:
|
62
|
+
rubygems_version: 2.0.3
|
62
63
|
signing_key:
|
63
|
-
specification_version:
|
64
|
+
specification_version: 4
|
64
65
|
summary: Validation frontend for models.
|
65
66
|
test_files: []
|