formeze 2.1.0 → 4.0.0
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 +7 -0
- data/CHANGES.md +164 -0
- data/LICENSE.txt +4 -0
- data/README.md +69 -92
- data/formeze.gemspec +12 -7
- data/lib/formeze.rb +139 -92
- metadata +23 -53
- data/Rakefile.rb +0 -8
- data/spec/formeze_spec.rb +0 -776
data/lib/formeze.rb
CHANGED
@@ -1,20 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'cgi'
|
2
3
|
|
3
4
|
module Formeze
|
5
|
+
module Presence
|
6
|
+
REGEXP = /\S/
|
7
|
+
|
8
|
+
def present?(string)
|
9
|
+
string =~ REGEXP
|
10
|
+
end
|
11
|
+
|
12
|
+
def blank?(string)
|
13
|
+
string !~ REGEXP
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private_constant :Presence
|
18
|
+
|
4
19
|
class Field
|
20
|
+
include Presence
|
21
|
+
|
5
22
|
attr_reader :name
|
6
23
|
|
7
|
-
def initialize(name, options
|
24
|
+
def initialize(name, **options)
|
8
25
|
@name, @options = name, options
|
9
26
|
end
|
10
27
|
|
28
|
+
def validate_all(values, form)
|
29
|
+
size = 0
|
30
|
+
|
31
|
+
values.each do |value|
|
32
|
+
if String === value
|
33
|
+
validate(value, form)
|
34
|
+
else
|
35
|
+
validate_file(value, form)
|
36
|
+
|
37
|
+
size += value.size
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
form.add_error(self, error(:too_large, 'is too large')) if maxsize? && size > maxsize
|
42
|
+
end
|
43
|
+
|
11
44
|
def validate(value, form)
|
12
45
|
value = Formeze.scrub(value, @options[:scrub])
|
13
46
|
|
14
|
-
if value
|
47
|
+
if blank?(value)
|
15
48
|
form.add_error(self, error(:required, 'is required')) if required?
|
16
49
|
|
17
|
-
|
50
|
+
value = blank_value if blank_value?
|
18
51
|
else
|
19
52
|
form.add_error(self, error(:not_multiline, 'cannot contain newlines')) if !multiline? && value.lines.count > 1
|
20
53
|
|
@@ -25,13 +58,29 @@ module Formeze
|
|
25
58
|
form.add_error(self, error(:no_match, 'is invalid')) if no_match?(value)
|
26
59
|
|
27
60
|
form.add_error(self, error(:bad_value, 'is invalid')) if values? && !values.include?(value)
|
61
|
+
end
|
28
62
|
|
29
|
-
|
63
|
+
value = Array(form.send(name)).push(value) if multiple?
|
64
|
+
|
65
|
+
form.send(:"#{name}=", value)
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_file(object, form)
|
69
|
+
type = MIME::Types[object.content_type].first
|
70
|
+
|
71
|
+
filename_type = MIME::Types.type_for(object.original_filename).first
|
72
|
+
|
73
|
+
if type.nil? || type != filename_type || !accept.include?(type)
|
74
|
+
form.add_error(self, error(:not_accepted, 'is not an accepted file type'))
|
30
75
|
end
|
76
|
+
|
77
|
+
object = Array(form.send(name)).push(object) if multiple?
|
78
|
+
|
79
|
+
form.send(:"#{name}=", object)
|
31
80
|
end
|
32
81
|
|
33
82
|
def error(key, default)
|
34
|
-
Formeze.translate(key,
|
83
|
+
Formeze.translate(key, scope: ERRORS_SCOPE, default: default)
|
35
84
|
end
|
36
85
|
|
37
86
|
def key
|
@@ -43,7 +92,7 @@ module Formeze
|
|
43
92
|
end
|
44
93
|
|
45
94
|
def label
|
46
|
-
@options.fetch(:label) { Formeze.translate(name,
|
95
|
+
@options.fetch(:label) { Formeze.translate(name, scope: LABELS_SCOPE, default: Formeze.label(name)) }
|
47
96
|
end
|
48
97
|
|
49
98
|
def required?
|
@@ -58,20 +107,32 @@ module Formeze
|
|
58
107
|
@options.fetch(:multiple) { false }
|
59
108
|
end
|
60
109
|
|
110
|
+
def maxsize?
|
111
|
+
@options.key?(:maxsize)
|
112
|
+
end
|
113
|
+
|
114
|
+
def maxsize
|
115
|
+
@options.fetch(:maxsize)
|
116
|
+
end
|
117
|
+
|
118
|
+
def accept
|
119
|
+
@accept ||= @options.fetch(:accept).split(',').flat_map { |type| MIME::Types[type] }
|
120
|
+
end
|
121
|
+
|
61
122
|
def too_long?(value)
|
62
123
|
value.chars.count > @options.fetch(:maxlength) { 64 }
|
63
124
|
end
|
64
125
|
|
65
126
|
def too_short?(value)
|
66
|
-
@options.
|
127
|
+
@options.key?(:minlength) && value.chars.count < @options.fetch(:minlength)
|
67
128
|
end
|
68
129
|
|
69
130
|
def no_match?(value)
|
70
|
-
@options.
|
131
|
+
@options.key?(:pattern) && value !~ @options[:pattern]
|
71
132
|
end
|
72
133
|
|
73
134
|
def blank_value?
|
74
|
-
@options.
|
135
|
+
@options.key?(:blank)
|
75
136
|
end
|
76
137
|
|
77
138
|
def blank_value
|
@@ -79,7 +140,7 @@ module Formeze
|
|
79
140
|
end
|
80
141
|
|
81
142
|
def values?
|
82
|
-
@options.
|
143
|
+
@options.key?(:values)
|
83
144
|
end
|
84
145
|
|
85
146
|
def values
|
@@ -87,7 +148,7 @@ module Formeze
|
|
87
148
|
end
|
88
149
|
|
89
150
|
def defined_if?
|
90
|
-
@options.
|
151
|
+
@options.key?(:defined_if)
|
91
152
|
end
|
92
153
|
|
93
154
|
def defined_if
|
@@ -95,7 +156,7 @@ module Formeze
|
|
95
156
|
end
|
96
157
|
|
97
158
|
def defined_unless?
|
98
|
-
@options.
|
159
|
+
@options.key?(:defined_unless)
|
99
160
|
end
|
100
161
|
|
101
162
|
def defined_unless
|
@@ -103,47 +164,37 @@ module Formeze
|
|
103
164
|
end
|
104
165
|
end
|
105
166
|
|
106
|
-
class
|
107
|
-
include
|
167
|
+
class Validation
|
168
|
+
include Presence
|
108
169
|
|
109
|
-
def initialize
|
110
|
-
@
|
111
|
-
end
|
170
|
+
def initialize(field, **kwargs, &block)
|
171
|
+
@field = field
|
112
172
|
|
113
|
-
|
114
|
-
@fields.each(&block)
|
115
|
-
end
|
173
|
+
@error = kwargs[:error] || :invalid
|
116
174
|
|
117
|
-
|
118
|
-
@fields << field
|
175
|
+
@precondition = kwargs[:if]
|
119
176
|
|
120
|
-
@
|
177
|
+
@block = block
|
121
178
|
end
|
122
179
|
|
123
|
-
def
|
124
|
-
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
class Validation
|
129
|
-
def initialize(field, options, &block)
|
130
|
-
@field, @options, @block = field, options, block
|
180
|
+
def error_message
|
181
|
+
Formeze.translate(@error, scope: ERRORS_SCOPE, default: 'is invalid')
|
131
182
|
end
|
132
183
|
|
133
|
-
def
|
134
|
-
@
|
184
|
+
def validates?(form)
|
185
|
+
@precondition ? form.instance_eval(&@precondition) : true
|
135
186
|
end
|
136
187
|
|
137
|
-
def
|
138
|
-
|
188
|
+
def field_value?(form)
|
189
|
+
present?(form.send(@field.name))
|
139
190
|
end
|
140
191
|
|
141
|
-
def
|
142
|
-
|
192
|
+
def field_errors?(form)
|
193
|
+
form.errors_on?(@field.name)
|
143
194
|
end
|
144
195
|
|
145
196
|
def validate(form)
|
146
|
-
if validates?(form) && !
|
197
|
+
if validates?(form) && field_value?(form) && !field_errors?(form)
|
147
198
|
return_value = if @block.arity == 1
|
148
199
|
@block.call(form.send(@field.name))
|
149
200
|
else
|
@@ -155,58 +206,25 @@ module Formeze
|
|
155
206
|
end
|
156
207
|
end
|
157
208
|
|
158
|
-
module ArrayAttrAccessor
|
159
|
-
def array_attr_reader(name)
|
160
|
-
define_method(name) do
|
161
|
-
ivar = :"@#{name}"
|
162
|
-
|
163
|
-
instance_variable_defined?(ivar) ? Array(instance_variable_get(ivar)) : []
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def array_attr_writer(name)
|
168
|
-
define_method(:"#{name}=") do |value|
|
169
|
-
ivar = :"@#{name}"
|
170
|
-
|
171
|
-
instance_variable_set(ivar, send(name) + [value])
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def array_attr_accessor(name)
|
176
|
-
array_attr_reader(name)
|
177
|
-
array_attr_writer(name)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
209
|
module ClassMethods
|
182
|
-
include ArrayAttrAccessor
|
183
|
-
|
184
210
|
def fields
|
185
|
-
@fields ||=
|
211
|
+
@fields ||= {}
|
186
212
|
end
|
187
213
|
|
188
|
-
def field(
|
189
|
-
field = Field.new(
|
214
|
+
def field(name, **options)
|
215
|
+
field = Field.new(name, **options)
|
190
216
|
|
191
|
-
fields
|
217
|
+
fields[field.name] = field
|
192
218
|
|
193
|
-
|
194
|
-
array_attr_accessor field.name
|
195
|
-
else
|
196
|
-
attr_accessor field.name
|
197
|
-
end
|
219
|
+
attr_accessor field.name
|
198
220
|
end
|
199
221
|
|
200
222
|
def validations
|
201
223
|
@validations ||= []
|
202
224
|
end
|
203
225
|
|
204
|
-
def validates(field_name, options
|
205
|
-
validations << Validation.new(fields[field_name], options, &block)
|
206
|
-
end
|
207
|
-
|
208
|
-
def parse(encoded_form_data)
|
209
|
-
new.tap { |form| form.parse(encoded_form_data) }
|
226
|
+
def validates(field_name, **options, &block)
|
227
|
+
validations << Validation.new(fields[field_name], **options, &block)
|
210
228
|
end
|
211
229
|
end
|
212
230
|
|
@@ -216,24 +234,46 @@ module Formeze
|
|
216
234
|
|
217
235
|
class ValidationError < StandardError; end
|
218
236
|
|
237
|
+
class RequestCGI < CGI
|
238
|
+
def env_table
|
239
|
+
@options[:request].env
|
240
|
+
end
|
241
|
+
|
242
|
+
def stdinput
|
243
|
+
@options[:request].body
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
private_constant :RequestCGI
|
248
|
+
|
249
|
+
RAILS_FORM_KEYS = %w[utf8 authenticity_token commit]
|
250
|
+
|
251
|
+
private_constant :RAILS_FORM_KEYS
|
252
|
+
|
219
253
|
module InstanceMethods
|
220
254
|
def fill(object)
|
221
|
-
self.class.fields.
|
222
|
-
if Hash === object && object.
|
255
|
+
self.class.fields.each_value do |field|
|
256
|
+
if Hash === object && object.key?(field.name)
|
223
257
|
send(:"#{field.name}=", object[field.name])
|
224
258
|
elsif object.respond_to?(field.name)
|
225
259
|
send(:"#{field.name}=", object.send(field.name))
|
226
260
|
end
|
227
261
|
end
|
262
|
+
|
263
|
+
return self
|
228
264
|
end
|
229
265
|
|
230
|
-
def parse(
|
231
|
-
form_data =
|
266
|
+
def parse(input)
|
267
|
+
form_data = if String === input
|
268
|
+
CGI.parse(input)
|
269
|
+
else
|
270
|
+
RequestCGI.new(request: input).params
|
271
|
+
end
|
232
272
|
|
233
|
-
self.class.fields.
|
273
|
+
self.class.fields.each_value do |field|
|
234
274
|
next unless field_defined?(field)
|
235
275
|
|
236
|
-
unless form_data.
|
276
|
+
unless form_data.key?(field.key)
|
237
277
|
next if field.multiple? || !field.key_required?
|
238
278
|
|
239
279
|
raise KeyError, "missing form key: #{field.key}"
|
@@ -245,13 +285,11 @@ module Formeze
|
|
245
285
|
raise ValueError unless field.multiple?
|
246
286
|
end
|
247
287
|
|
248
|
-
values
|
249
|
-
field.validate(value, self)
|
250
|
-
end
|
288
|
+
field.validate_all(values, self)
|
251
289
|
end
|
252
290
|
|
253
291
|
if defined?(Rails)
|
254
|
-
|
292
|
+
RAILS_FORM_KEYS.each do |key|
|
255
293
|
form_data.delete(key)
|
256
294
|
end
|
257
295
|
end
|
@@ -263,6 +301,8 @@ module Formeze
|
|
263
301
|
self.class.validations.each do |validation|
|
264
302
|
validation.validate(self)
|
265
303
|
end
|
304
|
+
|
305
|
+
return self
|
266
306
|
end
|
267
307
|
|
268
308
|
def add_error(field, message)
|
@@ -294,9 +334,8 @@ module Formeze
|
|
294
334
|
end
|
295
335
|
|
296
336
|
def to_h
|
297
|
-
self.class.fields.
|
337
|
+
self.class.fields.values.each_with_object({}) do |field, hash|
|
298
338
|
hash[field.name] = send(field.name)
|
299
|
-
hash
|
300
339
|
end
|
301
340
|
end
|
302
341
|
|
@@ -339,8 +378,16 @@ module Formeze
|
|
339
378
|
end
|
340
379
|
end
|
341
380
|
|
342
|
-
|
343
|
-
|
381
|
+
ERRORS_SCOPE = [:formeze, :errors].freeze
|
382
|
+
|
383
|
+
private_constant :ERRORS_SCOPE
|
384
|
+
|
385
|
+
LABELS_SCOPE = [:formeze, :labels].freeze
|
386
|
+
|
387
|
+
private_constant :LABELS_SCOPE
|
388
|
+
|
389
|
+
def self.translate(key, **options)
|
390
|
+
defined?(I18n) ? I18n.translate(key, **options) : options.fetch(:default)
|
344
391
|
end
|
345
392
|
|
346
393
|
def self.setup(form)
|
metadata
CHANGED
@@ -1,82 +1,52 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: formeze
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 4.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Tim Craft
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
14
|
-
|
15
|
-
name: rake
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 0.9.3
|
22
|
-
type: :development
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 0.9.3
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: i18n
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ~>
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 0.6.0
|
38
|
-
type: :development
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 0.6.0
|
46
|
-
description: A little library for handling form data/input
|
11
|
+
date: 2020-07-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Ruby gem for validating form data
|
47
14
|
email:
|
48
15
|
- mail@timcraft.com
|
49
16
|
executables: []
|
50
17
|
extensions: []
|
51
18
|
extra_rdoc_files: []
|
52
19
|
files:
|
53
|
-
-
|
54
|
-
-
|
20
|
+
- CHANGES.md
|
21
|
+
- LICENSE.txt
|
55
22
|
- README.md
|
56
|
-
- Rakefile.rb
|
57
23
|
- formeze.gemspec
|
58
|
-
|
59
|
-
|
60
|
-
|
24
|
+
- lib/formeze.rb
|
25
|
+
homepage: https://github.com/readysteady/formeze
|
26
|
+
licenses:
|
27
|
+
- LGPL-3.0
|
28
|
+
metadata:
|
29
|
+
homepage: https://github.com/readysteady/formeze
|
30
|
+
source_code_uri: https://github.com/readysteady/formeze
|
31
|
+
bug_tracker_uri: https://github.com/readysteady/formeze/issues
|
32
|
+
changelog_uri: https://github.com/readysteady/formeze/blob/master/CHANGES.md
|
33
|
+
post_install_message:
|
61
34
|
rdoc_options: []
|
62
35
|
require_paths:
|
63
36
|
- lib
|
64
37
|
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
38
|
requirements:
|
67
|
-
- -
|
39
|
+
- - ">="
|
68
40
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
41
|
+
version: 2.4.0
|
70
42
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
-
none: false
|
72
43
|
requirements:
|
73
|
-
- -
|
44
|
+
- - ">="
|
74
45
|
- !ruby/object:Gem::Version
|
75
46
|
version: '0'
|
76
47
|
requirements: []
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
specification_version: 3
|
48
|
+
rubygems_version: 3.1.2
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
81
51
|
summary: See description
|
82
52
|
test_files: []
|