formalize 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ module Formalize
2
+ VERSION = "0.0.1"
3
+ 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: []