formeze 2.1.1 → 4.0.1
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 +168 -0
- data/LICENSE.txt +4 -0
- data/README.md +69 -92
- data/formeze.gemspec +12 -7
- data/lib/formeze.rb +133 -94
- metadata +23 -53
- data/Rakefile.rb +0 -8
- data/spec/formeze_spec.rb +0 -809
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,29 @@ module Formeze
|
|
103
164
|
end
|
104
165
|
end
|
105
166
|
|
106
|
-
class
|
107
|
-
include
|
108
|
-
|
109
|
-
def initialize
|
110
|
-
@fields, @index = [], {}
|
111
|
-
end
|
112
|
-
|
113
|
-
def each(&block)
|
114
|
-
@fields.each(&block)
|
115
|
-
end
|
116
|
-
|
117
|
-
def <<(field)
|
118
|
-
@fields << field
|
167
|
+
class Validation
|
168
|
+
include Presence
|
119
169
|
|
120
|
-
|
121
|
-
|
170
|
+
def initialize(field, **kwargs, &block)
|
171
|
+
@field = field
|
122
172
|
|
123
|
-
|
124
|
-
@index.fetch(field_name)
|
125
|
-
end
|
126
|
-
end
|
173
|
+
@error = kwargs[:error] || :invalid
|
127
174
|
|
128
|
-
|
129
|
-
def initialize(field, options, &block)
|
130
|
-
@field, @options, @block = field, options, block
|
131
|
-
end
|
175
|
+
@precondition = kwargs[:if]
|
132
176
|
|
133
|
-
|
134
|
-
@options.fetch(:error) { :invalid }
|
177
|
+
@block = block
|
135
178
|
end
|
136
179
|
|
137
180
|
def error_message
|
138
|
-
Formeze.translate(
|
181
|
+
Formeze.translate(@error, scope: ERRORS_SCOPE, default: 'is invalid')
|
139
182
|
end
|
140
183
|
|
141
184
|
def validates?(form)
|
142
|
-
@
|
185
|
+
@precondition ? form.instance_eval(&@precondition) : true
|
143
186
|
end
|
144
187
|
|
145
188
|
def field_value?(form)
|
146
|
-
form.send(@field.name)
|
189
|
+
present?(form.send(@field.name))
|
147
190
|
end
|
148
191
|
|
149
192
|
def field_errors?(form)
|
@@ -163,58 +206,25 @@ module Formeze
|
|
163
206
|
end
|
164
207
|
end
|
165
208
|
|
166
|
-
module ArrayAttrAccessor
|
167
|
-
def array_attr_reader(name)
|
168
|
-
define_method(name) do
|
169
|
-
ivar = :"@#{name}"
|
170
|
-
|
171
|
-
instance_variable_defined?(ivar) ? Array(instance_variable_get(ivar)) : []
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def array_attr_writer(name)
|
176
|
-
define_method(:"#{name}=") do |value|
|
177
|
-
ivar = :"@#{name}"
|
178
|
-
|
179
|
-
instance_variable_set(ivar, send(name) + [value])
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def array_attr_accessor(name)
|
184
|
-
array_attr_reader(name)
|
185
|
-
array_attr_writer(name)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
209
|
module ClassMethods
|
190
|
-
include ArrayAttrAccessor
|
191
|
-
|
192
210
|
def fields
|
193
|
-
@fields ||=
|
211
|
+
@fields ||= {}
|
194
212
|
end
|
195
213
|
|
196
|
-
def field(
|
197
|
-
field = Field.new(
|
214
|
+
def field(name, **options)
|
215
|
+
field = Field.new(name, **options)
|
198
216
|
|
199
|
-
fields
|
217
|
+
fields[field.name] = field
|
200
218
|
|
201
|
-
|
202
|
-
array_attr_accessor field.name
|
203
|
-
else
|
204
|
-
attr_accessor field.name
|
205
|
-
end
|
219
|
+
attr_accessor field.name
|
206
220
|
end
|
207
221
|
|
208
222
|
def validations
|
209
223
|
@validations ||= []
|
210
224
|
end
|
211
225
|
|
212
|
-
def validates(field_name, options
|
213
|
-
validations << Validation.new(fields[field_name], options, &block)
|
214
|
-
end
|
215
|
-
|
216
|
-
def parse(encoded_form_data)
|
217
|
-
new.tap { |form| form.parse(encoded_form_data) }
|
226
|
+
def validates(field_name, **options, &block)
|
227
|
+
validations << Validation.new(fields[field_name], **options, &block)
|
218
228
|
end
|
219
229
|
end
|
220
230
|
|
@@ -224,24 +234,46 @@ module Formeze
|
|
224
234
|
|
225
235
|
class ValidationError < StandardError; end
|
226
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
|
+
|
227
253
|
module InstanceMethods
|
228
254
|
def fill(object)
|
229
|
-
self.class.fields.
|
230
|
-
if Hash === object && object.
|
255
|
+
self.class.fields.each_value do |field|
|
256
|
+
if Hash === object && object.key?(field.name)
|
231
257
|
send(:"#{field.name}=", object[field.name])
|
232
258
|
elsif object.respond_to?(field.name)
|
233
259
|
send(:"#{field.name}=", object.send(field.name))
|
234
260
|
end
|
235
261
|
end
|
262
|
+
|
263
|
+
return self
|
236
264
|
end
|
237
265
|
|
238
|
-
def parse(
|
239
|
-
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
|
240
272
|
|
241
|
-
self.class.fields.
|
273
|
+
self.class.fields.each_value do |field|
|
242
274
|
next unless field_defined?(field)
|
243
275
|
|
244
|
-
unless form_data.
|
276
|
+
unless form_data.key?(field.key)
|
245
277
|
next if field.multiple? || !field.key_required?
|
246
278
|
|
247
279
|
raise KeyError, "missing form key: #{field.key}"
|
@@ -253,13 +285,11 @@ module Formeze
|
|
253
285
|
raise ValueError unless field.multiple?
|
254
286
|
end
|
255
287
|
|
256
|
-
values
|
257
|
-
field.validate(value, self)
|
258
|
-
end
|
288
|
+
field.validate_all(values, self)
|
259
289
|
end
|
260
290
|
|
261
291
|
if defined?(Rails)
|
262
|
-
|
292
|
+
RAILS_FORM_KEYS.each do |key|
|
263
293
|
form_data.delete(key)
|
264
294
|
end
|
265
295
|
end
|
@@ -271,6 +301,8 @@ module Formeze
|
|
271
301
|
self.class.validations.each do |validation|
|
272
302
|
validation.validate(self)
|
273
303
|
end
|
304
|
+
|
305
|
+
return self
|
274
306
|
end
|
275
307
|
|
276
308
|
def add_error(field, message)
|
@@ -302,9 +334,8 @@ module Formeze
|
|
302
334
|
end
|
303
335
|
|
304
336
|
def to_h
|
305
|
-
self.class.fields.
|
337
|
+
self.class.fields.values.each_with_object({}) do |field, hash|
|
306
338
|
hash[field.name] = send(field.name)
|
307
|
-
hash
|
308
339
|
end
|
309
340
|
end
|
310
341
|
|
@@ -347,8 +378,16 @@ module Formeze
|
|
347
378
|
end
|
348
379
|
end
|
349
380
|
|
350
|
-
|
351
|
-
|
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)
|
352
391
|
end
|
353
392
|
|
354
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.1
|
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-11-03 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/main/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.4
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
81
51
|
summary: See description
|
82
52
|
test_files: []
|