formeze 2.1.1 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 !~ /\S/
47
+ if blank?(value)
15
48
  form.add_error(self, error(:required, 'is required')) if required?
16
49
 
17
- form.send(:"#{name}=", blank_value? ? blank_value : value)
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
- form.send(:"#{name}=", value)
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, :scope => [:formeze, :errors], :default => default)
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, :scope => [:formeze, :labels], :default => Formeze.label(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.has_key?(:minlength) && value.chars.count < @options.fetch(:minlength)
127
+ @options.key?(:minlength) && value.chars.count < @options.fetch(:minlength)
67
128
  end
68
129
 
69
130
  def no_match?(value)
70
- @options.has_key?(:pattern) && value !~ @options[:pattern]
131
+ @options.key?(:pattern) && value !~ @options[:pattern]
71
132
  end
72
133
 
73
134
  def blank_value?
74
- @options.has_key?(:blank)
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.has_key?(:values)
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.has_key?(:defined_if)
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.has_key?(:defined_unless)
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 FieldSet
107
- include Enumerable
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
- @index[field.name] = field
121
- end
170
+ def initialize(field, **kwargs, &block)
171
+ @field = field
122
172
 
123
- def [](field_name)
124
- @index.fetch(field_name)
125
- end
126
- end
173
+ @error = kwargs[:error] || :invalid
127
174
 
128
- class Validation
129
- def initialize(field, options, &block)
130
- @field, @options, @block = field, options, block
131
- end
175
+ @precondition = kwargs[:if]
132
176
 
133
- def error_key
134
- @options.fetch(:error) { :invalid }
177
+ @block = block
135
178
  end
136
179
 
137
180
  def error_message
138
- Formeze.translate(error_key, :scope => [:formeze, :errors], :default => 'is invalid')
181
+ Formeze.translate(@error, scope: ERRORS_SCOPE, default: 'is invalid')
139
182
  end
140
183
 
141
184
  def validates?(form)
142
- @options.has_key?(:when) ? form.instance_eval(&@options[:when]) : true
185
+ @precondition ? form.instance_eval(&@precondition) : true
143
186
  end
144
187
 
145
188
  def field_value?(form)
146
- form.send(@field.name) =~ /\S/
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 ||= FieldSet.new
211
+ @fields ||= {}
194
212
  end
195
213
 
196
- def field(*args)
197
- field = Field.new(*args)
214
+ def field(name, **options)
215
+ field = Field.new(name, **options)
198
216
 
199
- fields << field
217
+ fields[field.name] = field
200
218
 
201
- if field.multiple?
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 = {}, &block)
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.each do |field|
230
- if Hash === object && object.has_key?(field.name)
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(encoded_form_data)
239
- form_data = CGI.parse(encoded_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.each do |field|
273
+ self.class.fields.each_value do |field|
242
274
  next unless field_defined?(field)
243
275
 
244
- unless form_data.has_key?(field.key)
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.each do |value|
257
- field.validate(value, self)
258
- end
288
+ field.validate_all(values, self)
259
289
  end
260
290
 
261
291
  if defined?(Rails)
262
- %w(utf8 authenticity_token).each do |key|
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.inject({}) do |hash, field|
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
- def self.translate(key, options)
351
- defined?(I18n) ? I18n.translate(key, options) : options.fetch(:default)
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: 2.1.1
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: 2013-08-28 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
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
- - lib/formeze.rb
54
- - spec/formeze_spec.rb
20
+ - CHANGES.md
21
+ - LICENSE.txt
55
22
  - README.md
56
- - Rakefile.rb
57
23
  - formeze.gemspec
58
- homepage: http://github.com/timcraft/formeze
59
- licenses: []
60
- post_install_message:
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: '0'
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
- rubyforge_project:
78
- rubygems_version: 1.8.23
79
- signing_key:
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: []