formalize 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/formalize/field.rb +159 -0
- data/lib/formalize/helpers.rb +35 -0
- data/lib/formalize/version.rb +3 -0
- data/lib/formalize.rb +59 -0
- metadata +50 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require "formalize/helpers"
|
3
|
+
|
4
|
+
class BasicField
|
5
|
+
include Helpers
|
6
|
+
|
7
|
+
def initialize(id, opts={})
|
8
|
+
@errors = []
|
9
|
+
@opts = opts
|
10
|
+
@opts[:name] = id
|
11
|
+
end
|
12
|
+
|
13
|
+
def input(attrs = @opts)
|
14
|
+
input = tag(:input, attrs)
|
15
|
+
attrs[:label] ? tag_content(:label, "#{ attrs[:label] } #{ input }") : input
|
16
|
+
end
|
17
|
+
|
18
|
+
def errors
|
19
|
+
# REVIEW: What gets returned when @errors is empty?
|
20
|
+
unless @errors.empty?
|
21
|
+
list_items = @errors.collect { |error| tag_content(:li, error)}.join("\n")
|
22
|
+
tag_content(:ul, list_items)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def errors=(message)
|
27
|
+
@errors.push(message)
|
28
|
+
end
|
29
|
+
|
30
|
+
def value
|
31
|
+
@opts[:value]
|
32
|
+
end
|
33
|
+
|
34
|
+
def value=(val)
|
35
|
+
@opts[:value] = val
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid?
|
39
|
+
@errors.empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate
|
43
|
+
validate_presence if @opts.has_key?(:required)
|
44
|
+
validate_length if @opts.has_key?(:maxlength)
|
45
|
+
unless @opts[:value].nil? || @opts[:value].is_a?(Array) || @opts[:value].strip.empty?
|
46
|
+
validate_format if @opts.has_key?(:pattern)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_presence
|
51
|
+
if @opts[:required] == true && @opts[:value].strip.empty?
|
52
|
+
@errors << "#{ @opts[:name].capitalize } must not be blank"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_length
|
57
|
+
if @opts[:value].size > @opts[:maxlength].to_i
|
58
|
+
@errors << "#{ @opts[:name].capitalize } must not be more than #{ @opts[:maxlength] } characters long"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate_format
|
63
|
+
re = Regexp.new(@opts[:pattern])
|
64
|
+
unless re =~ @opts[:value]
|
65
|
+
@errors << "#{ @opts[:name].capitalize } must be in a valid format"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
class TextField < BasicField
|
72
|
+
def initialize(id, opts={})
|
73
|
+
super
|
74
|
+
@opts[:type] = :text
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class EmailField < BasicField
|
79
|
+
def initialize(id, opts={})
|
80
|
+
super
|
81
|
+
@opts[:type] = :email
|
82
|
+
@opts[:pattern] ||= /^[^@]+@[^@]+\.[a-zA-Z]{2,6}$/
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class UrlField < BasicField
|
87
|
+
def initialize(id, opts={})
|
88
|
+
super
|
89
|
+
@opts[:type] = :url
|
90
|
+
# REVIEW: The HTML this renders isn't great. Maybe only apply this on post?
|
91
|
+
@opts[:pattern] ||= /^#{URI::regexp(['http', 'https'])}$/
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class TextareaField < BasicField
|
96
|
+
def initialize(id, opts={})
|
97
|
+
super
|
98
|
+
@opts[:type] = :textarea
|
99
|
+
end
|
100
|
+
def input(attrs = @opts)
|
101
|
+
value = attrs.delete(:value)
|
102
|
+
input = tag_content(:textarea, value, attrs)
|
103
|
+
attrs[:label] ? tag_content(:label, "#{ attrs[:label] } #{ input }") : input
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class RadioField < BasicField
|
108
|
+
attr_accessor :opts
|
109
|
+
def initialize(id, opts={})
|
110
|
+
super
|
111
|
+
@opts[:type] = :radio
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class CheckboxField < BasicField
|
116
|
+
attr_accessor :opts
|
117
|
+
def initialize(id, opts={})
|
118
|
+
super
|
119
|
+
@opts[:type] = :checkbox
|
120
|
+
end
|
121
|
+
def input
|
122
|
+
attrs = @opts.dup
|
123
|
+
attrs[:name] = attrs[:name].to_s << '[]'
|
124
|
+
super(attrs)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Group < BasicField
|
129
|
+
def initialize(id, &block)
|
130
|
+
super
|
131
|
+
@choices = []
|
132
|
+
instance_eval(&block)
|
133
|
+
end
|
134
|
+
def input
|
135
|
+
@choices.collect { |choice| choice.input }.join("\n")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class RadioGroup < Group
|
140
|
+
def choice(value, choice_opts={})
|
141
|
+
choice_opts[:value] = value
|
142
|
+
@choices.push(RadioField.new(@opts[:name], choice_opts))
|
143
|
+
end
|
144
|
+
def value=(val)
|
145
|
+
@opts[:value] = val
|
146
|
+
@choices.each { |choice| choice.opts[:checked] = (choice.opts[:value] === val.to_sym) }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class CheckboxGroup < Group
|
151
|
+
def choice(value, choice_opts={})
|
152
|
+
choice_opts[:value] = value
|
153
|
+
@choices.push(CheckboxField.new(@opts[:name], choice_opts))
|
154
|
+
end
|
155
|
+
def value=(values)
|
156
|
+
@opts[:value] = values
|
157
|
+
@choices.each { |choice| choice.opts[:checked] = (values.include?(choice.opts[:value].to_s)) }
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Helpers
|
2
|
+
|
3
|
+
# TODO: This leaves a extra space when there are no attributes
|
4
|
+
def tag(name, opts = {})
|
5
|
+
attributes = tag_attributes(opts)
|
6
|
+
"<#{ name } #{ attributes }>"
|
7
|
+
end
|
8
|
+
|
9
|
+
# TODO: This leaves a extra space when there are no attributes
|
10
|
+
def tag_content(name, content, opts = {})
|
11
|
+
attributes = tag_attributes(opts)
|
12
|
+
"<#{ name } #{ attributes }>#{ content }</#{ name }>"
|
13
|
+
end
|
14
|
+
|
15
|
+
def tag_attributes(opts)
|
16
|
+
opts.sort.collect do |key, val|
|
17
|
+
next if key == :label # REVIEW: Move to a NonStandardAttributes constant?
|
18
|
+
case val
|
19
|
+
when TrueClass
|
20
|
+
"#{ key }"
|
21
|
+
when FalseClass
|
22
|
+
""
|
23
|
+
when Array
|
24
|
+
# REVIEW Comma or no comma? Not sure what attributes this could be used with
|
25
|
+
"#{ key }='#{ val.join(',') }'"
|
26
|
+
when Regexp
|
27
|
+
pattern = val.inspect[1..-2]
|
28
|
+
"#{ key }='#{ pattern }'"
|
29
|
+
else
|
30
|
+
"#{ key }='#{ val }'"
|
31
|
+
end
|
32
|
+
end.join(' ').squeeze(' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/formalize.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require "formalize/version"
|
2
|
+
require "formalize/field"
|
3
|
+
|
4
|
+
module Form
|
5
|
+
|
6
|
+
def text(id, opts={})
|
7
|
+
@fields ||= {}
|
8
|
+
@fields[id] = TextField.new(id, opts)
|
9
|
+
end
|
10
|
+
|
11
|
+
def email(id, opts={})
|
12
|
+
@fields ||= {}
|
13
|
+
@fields[id] = EmailField.new(id, opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def url(id, opts={})
|
17
|
+
@fields ||= {}
|
18
|
+
@fields[id] = UrlField.new(id, opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
def textarea(id, opts={})
|
22
|
+
@fields ||= {}
|
23
|
+
@fields[id] = TextareaField.new(id, opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def radio(id, &block)
|
27
|
+
@fields ||= {}
|
28
|
+
@fields[id] = RadioGroup.new(id, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def checkbox(id, &block)
|
32
|
+
@fields ||= {}
|
33
|
+
@fields[id] = CheckboxGroup.new(id, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def option(val, opts={})
|
37
|
+
end
|
38
|
+
|
39
|
+
def fill(params)
|
40
|
+
@fields.each do |id, field|
|
41
|
+
field.value = params[id.to_s] unless params[id.to_s].nil?
|
42
|
+
field.validate
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def valid?
|
48
|
+
@fields.values.all? { |field| field.valid? }
|
49
|
+
end
|
50
|
+
|
51
|
+
def [](id)
|
52
|
+
@fields[id]
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
@fields.values.collect { |field| "#{ field.errors }\n<p>#{ field.input }</p>\n" }.join.squeeze("\n").strip
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: formalize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alex Edwards
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-22 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: This is a very basic (and untested!) RubyGem to simplify web form creation,
|
15
|
+
validation and processing. It is designed for use with the Sinatra framework.
|
16
|
+
email:
|
17
|
+
- ajmedwards@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/formalize/field.rb
|
23
|
+
- lib/formalize/version.rb
|
24
|
+
- lib/formalize/helpers.rb
|
25
|
+
- lib/formalize.rb
|
26
|
+
homepage: ''
|
27
|
+
licenses: []
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 1.8.11
|
47
|
+
signing_key:
|
48
|
+
specification_version: 3
|
49
|
+
summary: Form processing and validation for Sinatra.
|
50
|
+
test_files: []
|