formalize 0.0.1

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.
@@ -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: []