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.
@@ -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,37 @@ module Formeze
103
164
  end
104
165
  end
105
166
 
106
- class FieldSet
107
- include Enumerable
167
+ class Validation
168
+ include Presence
108
169
 
109
- def initialize
110
- @fields, @index = [], {}
111
- end
170
+ def initialize(field, **kwargs, &block)
171
+ @field = field
112
172
 
113
- def each(&block)
114
- @fields.each(&block)
115
- end
173
+ @error = kwargs[:error] || :invalid
116
174
 
117
- def <<(field)
118
- @fields << field
175
+ @precondition = kwargs[:if]
119
176
 
120
- @index[field.name] = field
177
+ @block = block
121
178
  end
122
179
 
123
- def [](field_name)
124
- @index.fetch(field_name)
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 error_key
134
- @options.fetch(:error) { :invalid }
184
+ def validates?(form)
185
+ @precondition ? form.instance_eval(&@precondition) : true
135
186
  end
136
187
 
137
- def error_message
138
- Formeze.translate(error_key, :scope => [:formeze, :errors], :default => 'is invalid')
188
+ def field_value?(form)
189
+ present?(form.send(@field.name))
139
190
  end
140
191
 
141
- def validates?(form)
142
- @options.has_key?(:when) ? form.instance_eval(&@options[:when]) : true
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) && !form.errors_on?(@field.name)
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 ||= FieldSet.new
211
+ @fields ||= {}
186
212
  end
187
213
 
188
- def field(*args)
189
- field = Field.new(*args)
214
+ def field(name, **options)
215
+ field = Field.new(name, **options)
190
216
 
191
- fields << field
217
+ fields[field.name] = field
192
218
 
193
- if field.multiple?
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 = {}, &block)
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.each do |field|
222
- if Hash === object && object.has_key?(field.name)
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(encoded_form_data)
231
- 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
232
272
 
233
- self.class.fields.each do |field|
273
+ self.class.fields.each_value do |field|
234
274
  next unless field_defined?(field)
235
275
 
236
- unless form_data.has_key?(field.key)
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.each do |value|
249
- field.validate(value, self)
250
- end
288
+ field.validate_all(values, self)
251
289
  end
252
290
 
253
291
  if defined?(Rails)
254
- %w(utf8 authenticity_token).each do |key|
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.inject({}) do |hash, field|
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
- def self.translate(key, options)
343
- 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)
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: 2.1.0
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: 2013-08-27 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-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
- - 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/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: '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.2
49
+ signing_key:
50
+ specification_version: 4
81
51
  summary: See description
82
52
  test_files: []