nform 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/nform/attributes.rb +105 -0
- data/lib/nform/builder.rb +219 -0
- data/lib/nform/coercions.rb +55 -0
- data/lib/nform/core_ext.rb +12 -0
- data/lib/nform/form.rb +44 -0
- data/lib/nform/helpers.rb +7 -0
- data/lib/nform/html.rb +50 -0
- data/lib/nform/service.rb +47 -0
- data/lib/nform/validations.rb +62 -0
- data/lib/nform.rb +20 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 71b2f87653d2d3d13a8bbad3e3c312b7bbf7d22a
|
4
|
+
data.tar.gz: 5ce2e00185bb43437f9572183a228082799b7d97
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 76f4261d63c26976981e7eaf961e5f0237ba0c737bc26e867a06aad2403f71d36f856078a60573e17e2c164b687f03e2e9238e6ae43b25ad9905a12c234d45dc
|
7
|
+
data.tar.gz: abb4f49d0931d307ba9f88b163f654c6556635c77d7cbec482ceecb6579a7b229c9471fc1bb3db30632152fc30b7e3e396f2527aef03f964c65b2f927d039cf2
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'active_support/core_ext/hash'
|
2
|
+
require 'nform/coercions'
|
3
|
+
|
4
|
+
module NForm
|
5
|
+
module Attributes
|
6
|
+
def attribute(name,coerce:nil,required:false,default:nil)
|
7
|
+
attribute_set[name.to_sym] = {coerce: coerce, required: required, default: default}
|
8
|
+
end
|
9
|
+
|
10
|
+
def attribute_set
|
11
|
+
@attribute_set ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def undefined_attributes(option)
|
15
|
+
unless %i|raise ignore|.include?(option)
|
16
|
+
raise ArgumentError, "Unknown option `#{option}` for undefined attributes. Options are :raise or :ignore"
|
17
|
+
end
|
18
|
+
@undef_attr = option
|
19
|
+
end
|
20
|
+
|
21
|
+
def __undef_attr
|
22
|
+
@undef_attr ||= :raise
|
23
|
+
end
|
24
|
+
|
25
|
+
def define_attributes
|
26
|
+
attribute_set.each do |name,options|
|
27
|
+
define_method(name) do
|
28
|
+
instance_variable_get("@#{name}")
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO: must use coercion set
|
32
|
+
c = get_coercion(options[:coerce])
|
33
|
+
define_method("#{name}=") do |input|
|
34
|
+
instance_variable_set("@#{name}", c.call(input,self))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_coercion(coerce_option)
|
40
|
+
case
|
41
|
+
when coerce_option.nil?
|
42
|
+
proc{|n| n }
|
43
|
+
when coerce_option.is_a?(Symbol)
|
44
|
+
NForm::Coercions.fetch(coerce_option)
|
45
|
+
when coerce_option.respond_to?(:call)
|
46
|
+
coerce_option
|
47
|
+
when coerce_option.is_a?(Enumerable)
|
48
|
+
chain = coerce_option.map{|o| get_coercion(o) }
|
49
|
+
proc do |input,scope|
|
50
|
+
chain.reduce(input){|i,c| c.call(i,scope) }
|
51
|
+
end
|
52
|
+
else
|
53
|
+
raise Error, "Invalid coerce option given"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.extended(base)
|
58
|
+
base.include(InstanceMethods)
|
59
|
+
end
|
60
|
+
|
61
|
+
module InstanceMethods
|
62
|
+
def initialize(input={})
|
63
|
+
i = input.symbolize_keys
|
64
|
+
require_attributes!(i)
|
65
|
+
self.class.define_attributes
|
66
|
+
set_attributes!(i)
|
67
|
+
set_missing_defaults
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_hash
|
71
|
+
self.class.attribute_set.each.with_object({}) do |(k,v),memo|
|
72
|
+
memo[k] = send(k)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def require_attributes!(input_hash)
|
78
|
+
required = self.class.attribute_set.map{|name,options| name if options[:required]}.compact
|
79
|
+
missing = (required - input_hash.keys)
|
80
|
+
if missing.any?
|
81
|
+
raise ArgumentError, "Missing required attributes: #{missing.inspect}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_attributes!(input_hash)
|
86
|
+
input_hash.each do |k,v|
|
87
|
+
if self.class.__undef_attr == :raise
|
88
|
+
raise ArgumentError, "Undefined attribute: #{k}" unless respond_to?("#{k}=")
|
89
|
+
end
|
90
|
+
send "#{k}=", v if respond_to?("#{k}=")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_missing_defaults
|
95
|
+
self.class.attribute_set.each do |name, options|
|
96
|
+
default = options[:default]
|
97
|
+
unless default.nil?
|
98
|
+
send("#{name}=",default) if send(name).nil?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
@@ -0,0 +1,219 @@
|
|
1
|
+
require 'nform/core_ext'
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
|
4
|
+
module NForm
|
5
|
+
class Builder
|
6
|
+
include HTML
|
7
|
+
|
8
|
+
attr_reader :object, :form_class
|
9
|
+
def initialize(object, id: nil, form_class: nil, action: nil, method: nil)
|
10
|
+
@object = object
|
11
|
+
@form_id = id
|
12
|
+
@form_class = form_class
|
13
|
+
@action = action
|
14
|
+
@http_method = method
|
15
|
+
end
|
16
|
+
|
17
|
+
def form_id
|
18
|
+
@form_id || object_name.dasherize
|
19
|
+
end
|
20
|
+
|
21
|
+
def action
|
22
|
+
@action or
|
23
|
+
"/#{collection_name.dasherize}" + (new_object? ? "" : "/#{object.id}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def http_method
|
27
|
+
@http_method || (new_object? ? "POST" : "PATCH")
|
28
|
+
end
|
29
|
+
|
30
|
+
def new_object?
|
31
|
+
object.respond_to?(:new?) ? object.new? : true
|
32
|
+
end
|
33
|
+
|
34
|
+
def object_name
|
35
|
+
@object_name || detect_object_name(object).underscore
|
36
|
+
end
|
37
|
+
|
38
|
+
def collection_name
|
39
|
+
object_name.pluralize
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_tag
|
43
|
+
tag(:input, type:"hidden", name:"_method", value:http_method) if http_method != "POST"
|
44
|
+
end
|
45
|
+
|
46
|
+
def errors
|
47
|
+
@errors = if object.respond_to?(:errors)
|
48
|
+
object.errors
|
49
|
+
else
|
50
|
+
{}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def base_errors
|
55
|
+
if e = errors[:base]
|
56
|
+
tag(:ul, class: 'base errors') do
|
57
|
+
if e.respond_to?(:map)
|
58
|
+
zjoin e.map{|m| base_error(m) }
|
59
|
+
else
|
60
|
+
base_error(e)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def base_error(e)
|
67
|
+
tag(:li){ e }
|
68
|
+
end
|
69
|
+
|
70
|
+
def render
|
71
|
+
tag(:form, id: form_id, class: form_class, action:action, method:"POST") do
|
72
|
+
body = yield(self) if block_given?
|
73
|
+
zjoin(method_tag,base_errors,body)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def title
|
78
|
+
sjoin (new_object? ? "Create" : "Edit"), object_name.titleize
|
79
|
+
end
|
80
|
+
|
81
|
+
def param(*args)
|
82
|
+
object_name + args.map{|a|"[#{a}]"}.join
|
83
|
+
end
|
84
|
+
|
85
|
+
# allow "label: false" to prevent label being generated so that function that call label_for
|
86
|
+
# can all consistently omit the label when label value is given as false
|
87
|
+
def label_for(k, label: nil)
|
88
|
+
tag(:label, for: k.to_s.dasherize){ label || k.to_s.titleize } unless label == false
|
89
|
+
end
|
90
|
+
|
91
|
+
def input_for(k, type: "text", default: nil, **args)
|
92
|
+
val = object.send(k) || default
|
93
|
+
opts = {type:type, id:k.to_s.dasherize, name:param(k), value:val}.merge(args)
|
94
|
+
tag(:input,opts)
|
95
|
+
end
|
96
|
+
|
97
|
+
def error_for(k)
|
98
|
+
tag(:span, class: 'error'){ errors[k] } if errors[k]
|
99
|
+
end
|
100
|
+
|
101
|
+
def text_field(k, label: nil, default: nil, **args)
|
102
|
+
zjoin label_for(k, label:label), input_for(k,default:default,**args), error_for(k)
|
103
|
+
end
|
104
|
+
|
105
|
+
def number_field(k, label: nil, default: nil, **args)
|
106
|
+
opts = {type:'number', pattern: '\d*'}.merge(args)
|
107
|
+
zjoin label_for(k, label:label), input_for(k,type:'number',default:default,**opts), error_for(k)
|
108
|
+
end
|
109
|
+
|
110
|
+
def password_field(k, label: nil, **args)
|
111
|
+
zjoin label_for(k, label:label), input_for(k,type:"password",**args), error_for(k)
|
112
|
+
end
|
113
|
+
|
114
|
+
def hidden_field(k,**args)
|
115
|
+
input_for(k, type: "hidden",**args)
|
116
|
+
end
|
117
|
+
|
118
|
+
def text_area(k, label: nil, default: nil,**args)
|
119
|
+
val = object.send(k) || default
|
120
|
+
zjoin(
|
121
|
+
label_for(k, label:label),
|
122
|
+
tag(:textarea, id:k.to_s.dasherize, name:param(k),**args){ "#{val}" if val },
|
123
|
+
error_for(k)
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def bool_field(k, label: nil,**args)
|
128
|
+
checked = ( !object.send(k) || object.send(k) == "false" ) ? false : true
|
129
|
+
zjoin label_for(k, label: label),
|
130
|
+
tag(:input, type:'hidden',name:param(k), value:"false"),
|
131
|
+
tag(:input, type:'checkbox', id: k.to_s.dasherize, name:param(k), value:"true", checked:checked,**args),
|
132
|
+
error_for(k)
|
133
|
+
end
|
134
|
+
|
135
|
+
def select(k, options:, label: nil, blank: true,**args)
|
136
|
+
opts = options.map{|value,text| option_for(k,value,text) }
|
137
|
+
opts.unshift option_for(k,nil,nil) if blank
|
138
|
+
zjoin(
|
139
|
+
label_for(k, label: label),
|
140
|
+
tag(:select, id:k.to_s.dasherize, name:param(k), **args){
|
141
|
+
zjoin opts
|
142
|
+
},
|
143
|
+
error_for(k)
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
def option_for(k,value,text)
|
148
|
+
opts = {value: value}
|
149
|
+
opts[:selected] = true if object.send(k) == value
|
150
|
+
tag(:option, opts){text ? text : value}
|
151
|
+
end
|
152
|
+
|
153
|
+
def association_select(association,key_method: :id, label_method: :name, label: nil, **args)
|
154
|
+
aname = detect_object_name(association)
|
155
|
+
key = (aname.underscore + "_id").to_sym
|
156
|
+
options = Hash[ association.map{|i| [i.send(key_method), i.send(label_method)]}]
|
157
|
+
|
158
|
+
unless label == false
|
159
|
+
label ||= aname.underscore.titleize
|
160
|
+
end
|
161
|
+
|
162
|
+
select(key,options: options, label: label, **args)
|
163
|
+
end
|
164
|
+
|
165
|
+
def date_input(k, label: nil, start_year: nil, end_year: nil, default:{})
|
166
|
+
start_year ||= Date.today.year
|
167
|
+
end_year ||= start_year+20
|
168
|
+
val = get_value(object,k)
|
169
|
+
tag :div, class: "date-input" do
|
170
|
+
zjoin label_for(nil,label:(label||k.to_s.titleize)),
|
171
|
+
tag(:input, date_attrs(k,:month,"MM",01,12,get_value(val,:month, default[:month]))),
|
172
|
+
tag(:input, date_attrs(k,:day,"DD",01,31,get_value(val,:day, default[:day]))),
|
173
|
+
tag(:input, date_attrs(k,:year,"YYYY",start_year,end_year,get_value(val,:year, default[:year]))),
|
174
|
+
error_for(k)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def date_attrs(k,time,ph,min,max,val)
|
179
|
+
{ class: "date-#{time}", type: "number", name: param(k,time),
|
180
|
+
placeholder: ph, min: min, max: max, step: 1, value: val }
|
181
|
+
end
|
182
|
+
|
183
|
+
def submit_button(**args)
|
184
|
+
text = args.delete(:text)
|
185
|
+
tag(:button,**args){ text || (new_object? ? "Create" : "Save") }
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
def detect_object_name(o)
|
190
|
+
if o.is_a?(Symbol)
|
191
|
+
o.to_s
|
192
|
+
elsif o.is_a?(Class)
|
193
|
+
o.name
|
194
|
+
elsif o.respond_to?(:object_name)
|
195
|
+
o.object_name
|
196
|
+
elsif o.respond_to?(:model)
|
197
|
+
o.model
|
198
|
+
elsif o.is_a?(Enumerable)
|
199
|
+
detect_object_name(o.first)
|
200
|
+
else
|
201
|
+
o.class
|
202
|
+
end.to_s.demodulize
|
203
|
+
end
|
204
|
+
|
205
|
+
def get_value(object,key,default=nil)
|
206
|
+
if object.nil?
|
207
|
+
nil
|
208
|
+
elsif object.respond_to?(key)
|
209
|
+
object.send(key)
|
210
|
+
elsif object.respond_to? :fetch
|
211
|
+
object.fetch(key,nil)
|
212
|
+
else
|
213
|
+
raise BuilderError, "Undefined object method: #{key}"
|
214
|
+
end or default
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
BuilderError = Class.new(Error)
|
219
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'nform/core_ext'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
require 'active_support/core_ext/object'
|
4
|
+
|
5
|
+
module NForm
|
6
|
+
class CoercionSet
|
7
|
+
def [](key)
|
8
|
+
set[key.to_sym]
|
9
|
+
end
|
10
|
+
|
11
|
+
def []=(key,val)
|
12
|
+
set[key.to_sym] = val
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch(key)
|
16
|
+
if v = set[key]
|
17
|
+
v
|
18
|
+
else
|
19
|
+
raise Error, "Undefined coercion: #{key}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def respond_to_missing?(name,*)
|
24
|
+
set.has_key?(name.to_sym)
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(name,*args,&block)
|
28
|
+
if set[name.to_sym]
|
29
|
+
set[name.to_sym].call(*args,&block)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def set
|
37
|
+
@set ||= {}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Coercions = CoercionSet.new
|
42
|
+
Coercions[:to_presence] = proc {|v| v.presence }
|
43
|
+
Coercions[:to_bool] = proc { |v| !(v.nil? || v == false || v == 'false') }
|
44
|
+
Coercions[:to_float] = proc { |v| v.to_f }
|
45
|
+
Coercions[:to_integer] = proc { |v| v.to_i }
|
46
|
+
Coercions[:to_string] = proc {|v| v.to_s.strip }
|
47
|
+
Coercions[:to_symbol] = proc {|v| v.to_sym unless v.nil? }
|
48
|
+
Coercions[:to_number] = proc do |v|
|
49
|
+
if v && v.is_a?(String)
|
50
|
+
v.gsub(/,/,'').to_f
|
51
|
+
else
|
52
|
+
v
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module NForm
|
4
|
+
module Hashable
|
5
|
+
# A convenience method for making a hash with the
|
6
|
+
# given methods on self as the keys and return for
|
7
|
+
# the given methods as the values
|
8
|
+
def hash_of(*keys)
|
9
|
+
keys.each.with_object({}){|k,h| h[k] = send(k) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/nform/form.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'nform/core_ext'
|
2
|
+
|
3
|
+
module NForm
|
4
|
+
class Form
|
5
|
+
extend NForm::Attributes
|
6
|
+
include NForm::Validations
|
7
|
+
|
8
|
+
def valid?
|
9
|
+
errors.clear
|
10
|
+
validate!
|
11
|
+
true
|
12
|
+
rescue ValidationError
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate!
|
17
|
+
yield if block_given?
|
18
|
+
validation_error! if errors.any?
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def validation_error!(hash={})
|
23
|
+
errors.merge(hash)
|
24
|
+
raise ValidationError.new(errors)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ValidationError < Error
|
29
|
+
attr_reader :errors
|
30
|
+
def initialize(errors={})
|
31
|
+
@errors = errors
|
32
|
+
end
|
33
|
+
|
34
|
+
def message
|
35
|
+
"\nPlease correct the following errors:\n#{error_messages}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def error_messages
|
39
|
+
if errors.any?
|
40
|
+
errors.map{|k,v| "#{k.to_s.humanize}: #{v}"}.join("\n")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/nform/html.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module NForm
|
2
|
+
# Helper Methods for generating HTML markup
|
3
|
+
module HTML
|
4
|
+
VOID_ELEMENTS = %i|area base br col embed hr img input keygen link meta param source track wbr|
|
5
|
+
BOOL_ATTRIBUTES = %i|allowfullscreen async autofocus autoplay checked compact controls declare default defaultchecked defaultmuted defaultselected defer disabled draggable enabled formnovalidate hidden indeterminate inert ismap itemscope loop multiple muted nohref noresize noshade novalidate nowrap open pauseonexit readonly required reversed scoped seamless selected sortable spellcheck translate truespeed typemustmatch visible|
|
6
|
+
|
7
|
+
# Generate an HTML Tag
|
8
|
+
def tag(name, attributes={}, &block)
|
9
|
+
open = sjoin name, attrs(attributes)
|
10
|
+
body = block.call if block_given?
|
11
|
+
if VOID_ELEMENTS.include?(name.to_sym)
|
12
|
+
raise BuilderError, "Void elements cannot have content" if body
|
13
|
+
"<#{open}>"
|
14
|
+
else
|
15
|
+
"<#{open}>#{body}</#{name}>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def attrs(hash={})
|
20
|
+
hash.delete_if{|k,v| v.nil? || v == "" }
|
21
|
+
.map{|k,v| attr_string(k,v) }
|
22
|
+
.compact
|
23
|
+
.join(" ")
|
24
|
+
end
|
25
|
+
|
26
|
+
def attr_string(k,v)
|
27
|
+
if BOOL_ATTRIBUTES.include?(k)
|
28
|
+
attr_key(k) if v
|
29
|
+
else
|
30
|
+
%Q|#{attr_key(k)}="#{v}"|
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def attr_key(k)
|
35
|
+
k.is_a?(Symbol) ? k.to_s.gsub("_","-") : k
|
36
|
+
end
|
37
|
+
|
38
|
+
def zjoin(*args)
|
39
|
+
args.delete_if{|a| a.nil? || a == ""}.join('')
|
40
|
+
end
|
41
|
+
|
42
|
+
def sjoin(*args)
|
43
|
+
args.delete_if{|a| a.nil? || a == ""}.join(' ')
|
44
|
+
end
|
45
|
+
|
46
|
+
def njoin(*args)
|
47
|
+
args.delete_if{|a| a.nil? || a == ""}.join("\n")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'nform/core_ext'
|
2
|
+
|
3
|
+
module NForm
|
4
|
+
# Services expect valid input
|
5
|
+
# A service performs a single action
|
6
|
+
# A service should not accept unfiltered user input,
|
7
|
+
# but accept a form object when user input is required
|
8
|
+
class Service
|
9
|
+
include Hashable
|
10
|
+
|
11
|
+
attr_reader :form
|
12
|
+
def initialize(input)
|
13
|
+
@form = get_form(input)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
raise "Must be defined in subclass"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.call(*args)
|
21
|
+
new(*args).call
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.form_class(klass=nil)
|
25
|
+
@@form_class = klass || const_get(:Form)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def get_form(input)
|
30
|
+
input.is_a?(@@form_class) ? input : @@form_class.new(input)
|
31
|
+
end
|
32
|
+
|
33
|
+
def error!(message)
|
34
|
+
raise ServiceError.new(message)
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class ServiceError < Error
|
42
|
+
attr_reader :message
|
43
|
+
def initialize(message="Unknown Error")
|
44
|
+
@message = message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module NForm
|
2
|
+
# A Module of simple validation methods.
|
3
|
+
# Including objects are required to implement a simple API:
|
4
|
+
# 1. Keys passed in to a validation must match instance method names
|
5
|
+
# 2. Objects must provide an errors object which responds to []
|
6
|
+
#
|
7
|
+
# When called, validators will return true/false indicating whether
|
8
|
+
# the validation passed or failed
|
9
|
+
module Validations
|
10
|
+
def errors
|
11
|
+
@errors ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_presence_of(*keys)
|
15
|
+
pass = true
|
16
|
+
keys.each do |key|
|
17
|
+
unless respond_to?(key) && send(key) && send(key) != ""
|
18
|
+
errors[key] = "#{key.to_s.humanize} is required"
|
19
|
+
pass = false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
pass
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate_numericality_of(*keys)
|
26
|
+
pass = true
|
27
|
+
keys.each do |key|
|
28
|
+
val = send(key)
|
29
|
+
return true if val.is_a?(Numeric)
|
30
|
+
unless (val.respond_to?(:to_i) || val.respond_to?(:to_f)) &&
|
31
|
+
(val == val.to_i.to_s || val == val.to_f.to_s)
|
32
|
+
errors[key] = "#{key.to_s.humanize} must be a number"
|
33
|
+
pass = false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
pass
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate_length_of(key,length)
|
40
|
+
val = send(key)
|
41
|
+
if val && val.respond_to?(:length) && val.length >= length
|
42
|
+
true
|
43
|
+
else
|
44
|
+
errors[key] = "#{key.to_s.humanize} must be at least #{length} characters long"
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_confirmation_of(attribute)
|
50
|
+
confirm_key = attribute.to_s.concat("_confirmation").to_sym
|
51
|
+
if !respond_to?(confirm_key)
|
52
|
+
errors[attribute] = "#{attribute.to_s.humanize} requires confirmation"
|
53
|
+
false
|
54
|
+
elsif send(attribute) != send(confirm_key)
|
55
|
+
errors[confirm_key] = "#{attribute.to_s.humanize} confirmation does not match"
|
56
|
+
false
|
57
|
+
else
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/nform.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module NForm
|
2
|
+
# A base error class for any NForm exceptions to extend
|
3
|
+
Error = Class.new(StandardError)
|
4
|
+
end
|
5
|
+
|
6
|
+
# Food for thought:
|
7
|
+
# Not all this code is really required,
|
8
|
+
# the library could be configured to not require all
|
9
|
+
# and let the user just require the bits they want instead...
|
10
|
+
# In that case, this list should be used as the basis for
|
11
|
+
# `require nform/all`
|
12
|
+
# For now, continuing to load all.
|
13
|
+
require 'nform/helpers'
|
14
|
+
require 'nform/html'
|
15
|
+
require 'nform/builder'
|
16
|
+
require 'nform/attributes'
|
17
|
+
require 'nform/validations'
|
18
|
+
require 'nform/coercions'
|
19
|
+
require 'nform/form'
|
20
|
+
require 'nform/service'
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nform
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Burleson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
description: A nifty form builder and such.
|
28
|
+
email: burlesona@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/nform.rb
|
34
|
+
- lib/nform/attributes.rb
|
35
|
+
- lib/nform/builder.rb
|
36
|
+
- lib/nform/coercions.rb
|
37
|
+
- lib/nform/core_ext.rb
|
38
|
+
- lib/nform/form.rb
|
39
|
+
- lib/nform/helpers.rb
|
40
|
+
- lib/nform/html.rb
|
41
|
+
- lib/nform/service.rb
|
42
|
+
- lib/nform/validations.rb
|
43
|
+
homepage: http://github.com/burlesona/nform
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 2.4.5.1
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: A form library
|
67
|
+
test_files: []
|