formeze 2.1.0 → 4.0.0

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,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: []