visionmedia-dm-forms 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +4 -0
- data/Manifest +19 -16
- data/README.rdoc +4 -33
- data/Rakefile +6 -4
- data/Todo.rdoc +13 -15
- data/dm-forms.gemspec +7 -4
- data/examples/benchmarks.rb +26 -110
- data/examples/login.rb +20 -0
- data/lib/dm-forms.rb +5 -6
- data/lib/dm-forms/base.rb +115 -0
- data/lib/dm-forms/core_ext.rb +27 -22
- data/lib/dm-forms/helpers.rb +83 -0
- data/lib/dm-forms/mixins.rb +8 -0
- data/lib/dm-forms/mixins/descriptions.rb +18 -0
- data/lib/dm-forms/mixins/errors.rb +0 -0
- data/lib/dm-forms/mixins/labels.rb +16 -0
- data/lib/dm-forms/mixins/wrappers.rb +26 -0
- data/lib/dm-forms/tag.rb +67 -134
- data/lib/dm-forms/version.rb +1 -4
- data/spec/functional/helpers_spec.rb +186 -0
- data/spec/functional/mixins/descriptions_spec.rb +19 -0
- data/spec/functional/mixins/labels_spec.rb +19 -0
- data/spec/functional/mixins/wrappers_spec.rb +21 -0
- data/spec/functional/tag_spec.rb +33 -41
- data/spec/integration/datamapper_spec.rb +73 -45
- data/spec/spec_helper.rb +5 -7
- data/tasks/spec.rake +5 -0
- metadata +42 -22
- data/examples/datamapper.rb +0 -37
- data/examples/elements.rb +0 -31
- data/examples/haml.rb +0 -21
- data/examples/login.haml +0 -4
- data/lib/dm-forms/elements.rb +0 -210
- data/lib/dm-forms/model_elements.rb +0 -33
- data/spec/functional/core_ext_spec.rb +0 -56
- data/spec/functional/elements_spec.rb +0 -209
- data/spec/integration/haml_spec.rb +0 -29
data/lib/dm-forms/core_ext.rb
CHANGED
@@ -1,39 +1,44 @@
|
|
1
1
|
|
2
|
-
class
|
3
|
-
|
4
|
-
|
2
|
+
class String
|
3
|
+
|
4
|
+
##
|
5
|
+
# String to bool.
|
6
|
+
|
7
|
+
def to_bool
|
8
|
+
!empty? and self != '0' and self != 'false' and self != 'nil'
|
5
9
|
end
|
6
|
-
|
10
|
+
|
7
11
|
end
|
8
12
|
|
9
|
-
class
|
10
|
-
|
13
|
+
class TrueClass
|
14
|
+
|
11
15
|
##
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# 'im_a_simple.String'.humanize # => 'im a simple String'
|
17
|
-
#
|
18
|
-
|
19
|
-
def humanize
|
20
|
-
gsub(/[^a-zA-Z\d]/, ' ') || self
|
16
|
+
# True to bool.
|
17
|
+
|
18
|
+
def to_bool
|
19
|
+
self
|
21
20
|
end
|
22
21
|
|
22
|
+
end
|
23
|
+
|
24
|
+
class FalseClass
|
25
|
+
|
23
26
|
##
|
24
|
-
#
|
27
|
+
# False to bool.
|
25
28
|
|
26
|
-
def
|
27
|
-
|
29
|
+
def to_bool
|
30
|
+
self
|
28
31
|
end
|
32
|
+
|
29
33
|
end
|
30
34
|
|
31
|
-
class
|
35
|
+
class NilClass
|
32
36
|
|
33
37
|
##
|
34
|
-
#
|
38
|
+
# Nil to bool.
|
35
39
|
|
36
|
-
def
|
37
|
-
|
40
|
+
def to_bool
|
41
|
+
false
|
38
42
|
end
|
43
|
+
|
39
44
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
|
2
|
+
module DataMapper
|
3
|
+
module Form
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
def fields_for model, attrs = {}, &block
|
7
|
+
with_form_context model do
|
8
|
+
capture &block
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def submit value = nil, attrs = {}
|
13
|
+
attrs[:value] = value unless value.blank?
|
14
|
+
form_context(nil, self).unbound_submit attrs
|
15
|
+
end
|
16
|
+
|
17
|
+
%w( form fieldset ).each do |type|
|
18
|
+
class_eval <<-EOF
|
19
|
+
def #{type} *args, &block
|
20
|
+
form_context(nil, self).#{type} *args, &block
|
21
|
+
end
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
|
25
|
+
%w( form_for fieldset_for ).each do |type|
|
26
|
+
class_eval <<-EOF
|
27
|
+
def #{type} model, attrs = {}, &block
|
28
|
+
with_form_context model do
|
29
|
+
#{type.sub(/_for/, '')} attrs, &block
|
30
|
+
end
|
31
|
+
end
|
32
|
+
EOF
|
33
|
+
end
|
34
|
+
|
35
|
+
%w( checkbox button file textarea
|
36
|
+
hidden password radio select textfield ).each do |type|
|
37
|
+
define_method type do |*args|
|
38
|
+
method = bound?(*args) ? :"bound_#{type}" : :"unbound_#{type}"
|
39
|
+
form_context(nil, self).send method, *args
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#:nodoc:
|
44
|
+
|
45
|
+
def new_form_context *args
|
46
|
+
Base.new *args
|
47
|
+
end
|
48
|
+
|
49
|
+
def form_context *args
|
50
|
+
@__form_context ||= new_form_context *args
|
51
|
+
end
|
52
|
+
|
53
|
+
def with_form_context model, attrs = {}, &block
|
54
|
+
last_context, @__form_context = form_context, new_form_context(model, self)
|
55
|
+
captured = instance_eval &block
|
56
|
+
@__form_context = last_context
|
57
|
+
captured
|
58
|
+
end
|
59
|
+
|
60
|
+
def bound? *args
|
61
|
+
args.first.is_a? Symbol
|
62
|
+
end
|
63
|
+
|
64
|
+
def clear_buffer
|
65
|
+
@buffer = ''
|
66
|
+
end
|
67
|
+
|
68
|
+
def buffer string = nil
|
69
|
+
@buffer ||= ''
|
70
|
+
end
|
71
|
+
|
72
|
+
def capture &block
|
73
|
+
if block.arity > 0
|
74
|
+
yield self
|
75
|
+
else
|
76
|
+
instance_eval &block
|
77
|
+
end
|
78
|
+
buffer
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module DataMapper::Form::Descriptions
|
3
|
+
|
4
|
+
def tag name, contents = nil, attrs = {}, &block
|
5
|
+
description = description_tag attrs
|
6
|
+
super + description
|
7
|
+
end
|
8
|
+
|
9
|
+
def self_closing_tag name, attrs = {}
|
10
|
+
description = description_tag attrs
|
11
|
+
super + description
|
12
|
+
end
|
13
|
+
|
14
|
+
def description_tag attrs = {}
|
15
|
+
(description = attrs.delete(:description)) ? tag(:span, description, :class => 'description') : ''
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module DataMapper::Form::Labels
|
3
|
+
|
4
|
+
def tag name, contents = nil, attrs = {}, &block
|
5
|
+
label_tag(attrs) + super
|
6
|
+
end
|
7
|
+
|
8
|
+
def self_closing_tag name, attrs = {}
|
9
|
+
label_tag(attrs) + super
|
10
|
+
end
|
11
|
+
|
12
|
+
def label_tag attrs = {}
|
13
|
+
(label = attrs.delete(:label)) ? tag(:label, label, :for => attrs[:name]) : ''
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module DataMapper::Form::Wrappers
|
3
|
+
|
4
|
+
def tag name, contents = nil, attrs = {}, &block
|
5
|
+
attrs, contents = contents, nil if contents.is_a? Hash
|
6
|
+
unless name.in? :form, :fieldset, :legend, :span, :div, :option, :optgroup
|
7
|
+
tag(:div, super, :class => wrapper_classes(name, attrs))
|
8
|
+
else
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self_closing_tag name, attrs = {}
|
14
|
+
tag :div, super, :class => wrapper_classes(name, attrs)
|
15
|
+
end
|
16
|
+
|
17
|
+
def wrapper_classes name, attrs = {}
|
18
|
+
classes = attrs.include?(:type) ? "form-#{attrs[:type]}" : "form-#{name}"
|
19
|
+
classes.add_class "form-#{classify_name(attrs[:name])}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def classify_name name
|
23
|
+
name.to_s.gsub('[', '-').gsub(']', '')
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/dm-forms/tag.rb
CHANGED
@@ -1,156 +1,89 @@
|
|
1
1
|
|
2
2
|
module DataMapper
|
3
3
|
module Form
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
#
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
# Tag's description.
|
43
|
-
|
44
|
-
attr_accessor :description
|
45
|
-
|
46
|
-
def initialize name, options = {}, &block
|
47
|
-
@name, @options, @attributes = name, options, (options[:attributes] ||= {})
|
48
|
-
@before, @after = attribute(:before, ''), attribute(:after, '')
|
49
|
-
@description = Elements.desc(attribute(:description)) || ''
|
50
|
-
@model = attribute :model
|
51
|
-
(@attributes[:value] ||= '') << Elements.capture_elements(@model, &block) if block_given?
|
4
|
+
module Tag
|
5
|
+
|
6
|
+
#--
|
7
|
+
# Borrowed / adapted from Merb
|
8
|
+
#++
|
9
|
+
|
10
|
+
BOOL_ATTRIBUTES = :selected, :checked, :multiple
|
11
|
+
|
12
|
+
##
|
13
|
+
# Creates a generic tag. You can invoke it a variety of ways.
|
14
|
+
#
|
15
|
+
# tag :div
|
16
|
+
# # <div></div>
|
17
|
+
#
|
18
|
+
# tag :div, 'content'
|
19
|
+
# # <div>content</div>
|
20
|
+
#
|
21
|
+
# tag :div, :class => 'class'
|
22
|
+
# # <div class="class"></div>
|
23
|
+
#
|
24
|
+
# tag :div, 'content', :class => 'class'
|
25
|
+
# # <div class="class">content</div>
|
26
|
+
#
|
27
|
+
# tag :div do
|
28
|
+
# 'content'
|
29
|
+
# end
|
30
|
+
# # <div>content</div>
|
31
|
+
#
|
32
|
+
# tag :div, :class => 'class' do
|
33
|
+
# 'content'
|
34
|
+
# end
|
35
|
+
# # <div class="class">content</div>
|
36
|
+
#
|
37
|
+
|
38
|
+
def tag name, contents = nil, attrs = {}, &block
|
39
|
+
attrs, contents = contents, nil if contents.is_a? Hash
|
40
|
+
contents = yield if block_given?
|
41
|
+
open_tag(name, attrs) + contents.to_s + close_tag(name)
|
52
42
|
end
|
53
43
|
|
54
44
|
##
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
prepare_boolean_attributes
|
60
|
-
before << label
|
61
|
-
close = self_closing? ? " />" : ">#{inner_html}</#{@name}>"
|
62
|
-
open = "<#{@name} #{@attributes.to_html_attributes}"
|
63
|
-
tag = before << open << close << description << after << "\n"
|
64
|
-
end
|
65
|
-
alias :to_s :render
|
45
|
+
# Creates the opening tag with attributes for the provided +name+
|
46
|
+
# attrs is a hash where all members will be mapped to key="value"
|
47
|
+
#
|
48
|
+
# Note: This tag will need to be closed
|
66
49
|
|
67
|
-
|
68
|
-
|
69
|
-
# utilize :multiple => true, instead of :multiple => :multiple.
|
70
|
-
|
71
|
-
def prepare_boolean_attributes
|
72
|
-
@attributes.each_pair do |key, value|
|
73
|
-
if BOOLEAN_ATTRIBUTES.include? key
|
74
|
-
if value
|
75
|
-
@attributes[key] = key
|
76
|
-
else
|
77
|
-
@attributes.delete key
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
50
|
+
def open_tag name, attrs = {}
|
51
|
+
"<#{name}#{optional_attrs(attrs)}>"
|
81
52
|
end
|
82
53
|
|
83
54
|
##
|
84
|
-
#
|
85
|
-
|
86
|
-
def
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
##
|
91
|
-
# The inner HTML of this tag, only available for
|
92
|
-
# elements which are not self-closing.
|
93
|
-
|
94
|
-
def inner_html
|
95
|
-
attribute :value, '' unless self_closing?
|
55
|
+
# Creates a closing tag
|
56
|
+
|
57
|
+
def close_tag name
|
58
|
+
"</#{name}>\n"
|
96
59
|
end
|
97
|
-
|
98
|
-
##
|
99
|
-
# Is the element required.
|
100
60
|
|
101
|
-
def required?
|
102
|
-
attribute :required, false
|
103
|
-
end
|
104
|
-
|
105
61
|
##
|
106
|
-
#
|
62
|
+
# Creates a self closing tag. Like <br/> or <img src="..."/>
|
63
|
+
#
|
64
|
+
# +name+ : the name of the tag to create
|
65
|
+
# +attrs+ : a hash where all members will be mapped to key="value"
|
107
66
|
|
108
|
-
def
|
109
|
-
|
67
|
+
def self_closing_tag name, attrs = {}
|
68
|
+
"<#{name}#{optional_attrs(attrs)}/>\n"
|
110
69
|
end
|
111
70
|
|
112
|
-
##
|
113
|
-
# Wither or not this tag has a label.
|
114
|
-
|
115
|
-
def has_label?
|
116
|
-
!@attributes[:label].blank?
|
117
|
-
end
|
118
|
-
|
119
|
-
##
|
120
|
-
# Returns user generated classes as well as those generated by
|
121
|
-
# dm-forms for styling consistancy.
|
122
|
-
|
123
|
-
def classes
|
124
|
-
@classes ||= [@attributes[:class], generate_classes].join(' ').strip if should_add_classes?
|
125
|
-
end
|
126
|
-
|
127
71
|
private
|
128
72
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
classes = "form-#{@name == :input ? @attributes[:type] : @name}"
|
134
|
-
classes << " form-#{@attributes[:name]}" unless @attributes[:name].blank?
|
135
|
-
classes
|
136
|
-
end
|
137
|
-
|
138
|
-
##
|
139
|
-
# Wither or not classes should be added to this element.
|
140
|
-
|
141
|
-
def should_add_classes?
|
142
|
-
!(IGNORE_CLASSES_ON_ELEMENTS.include? @name or IGNORE_CLASSES_ON_ELEMENTS.include? @attributes[:type])
|
73
|
+
#:stopdoc:
|
74
|
+
|
75
|
+
def optional_attrs attrs = {}
|
76
|
+
' ' + boolean_attrs(attrs).to_html_attributes unless attrs.blank?
|
143
77
|
end
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
@attributes.delete(attribute) || default
|
78
|
+
|
79
|
+
def boolean_attrs attrs = {}
|
80
|
+
attrs.each do |key, value|
|
81
|
+
if key.in? BOOL_ATTRIBUTES
|
82
|
+
value.to_bool ? attrs[key] = key : attrs.delete(key)
|
83
|
+
end
|
84
|
+
end
|
152
85
|
end
|
153
|
-
|
86
|
+
|
154
87
|
end
|
155
88
|
end
|
156
|
-
end
|
89
|
+
end
|