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.
@@ -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: []