padrino-helpers 0.9.20 → 0.9.21

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.
data/README.rdoc CHANGED
@@ -152,6 +152,8 @@ A form_for using these basic fields might look like:
152
152
  %p
153
153
  = f.submit "Create", :class => 'button'
154
154
 
155
+ Forms can also accept nested attributes using `fields_for` within the form builder in recent releases. Check out the guide for {Padrino Helpers}[http://www.padrinorb.com/guides/application-helpers] to learn more about nested forms.
156
+
155
157
  There is also an additional StandardFormBuilder which builds on the abstract fields that can be used within a form_for.
156
158
 
157
159
  A form_for using these standard fields might be:
@@ -1,6 +1,7 @@
1
1
  require 'padrino-core/support_lite' unless defined?(SupportLite)
2
2
  require 'cgi'
3
3
  require 'i18n'
4
+ require 'enumerator'
4
5
 
5
6
  FileSet.glob_require('padrino-helpers/**/*.rb', __FILE__)
6
7
 
@@ -4,9 +4,10 @@ module Padrino
4
4
  class AbstractFormBuilder #:nodoc:
5
5
  attr_accessor :template, :object
6
6
 
7
- def initialize(template, object)
7
+ def initialize(template, object, options={})
8
8
  @template = template
9
9
  @object = build_object(object)
10
+ @options = options
10
11
  raise "FormBuilder template must be initialized!" unless template
11
12
  raise "FormBuilder object must be not be nil value. If there's no object, use a symbol instead! (i.e :user)" unless object
12
13
  end
@@ -19,7 +20,7 @@ module Padrino
19
20
 
20
21
  # f.error_message_on(field)
21
22
  def error_message_on(field, options={})
22
- @template.error_message_on(object_name, field, options)
23
+ @template.error_message_on(object, field, options)
23
24
  end
24
25
 
25
26
  # f.label :username, :caption => "Nickname"
@@ -91,57 +92,105 @@ module Padrino
91
92
  @template.submit_tag caption, options
92
93
  end
93
94
 
94
- # f.simage_submitubmit "buttons/submit.png", :class => 'large'
95
+ # f.image_submit "buttons/submit.png", :class => 'large'
95
96
  def image_submit(source, options={})
96
97
  @template.image_submit_tag source, options
97
98
  end
98
99
 
100
+ # Supports nested fields for a child model within a form
101
+ # f.fields_for :addresses
102
+ # f.fields_for :addresses, address
103
+ # f.fields_for :addresses, @addresses
104
+ def fields_for(child_association, instance_or_collection=nil, &block)
105
+ default_collection = self.object.send(child_association)
106
+ include_index = default_collection.respond_to?(:each)
107
+ nested_options = { :parent => self, :association => child_association }
108
+ nested_objects = instance_or_collection ? Array(instance_or_collection) : Array(default_collection)
109
+ result = nested_objects.each_with_index.map do |child_instance, index|
110
+ nested_options[:index] = include_index ? index : nil
111
+ @template.fields_for(child_instance, { :nested => nested_options }, &block)
112
+ end.join("\n")
113
+ end
114
+
99
115
  protected
100
116
  # Returns the known field types for a formbuilder
101
117
  def self.field_types
102
118
  [:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
103
119
  end
104
120
 
105
- # Returns the object's models name
106
- # => user_assignment
107
- def object_name
108
- object.is_a?(Symbol) ? object : object.class.to_s.underscore.gsub('/', '-')
109
- end
110
-
111
121
  # Returns true if the value matches the value in the field
112
122
  # field_has_value?(:gender, 'male')
113
123
  def values_matches_field?(field, value)
114
124
  value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
115
125
  end
116
126
 
117
- # Returns the value for the object's field
118
- # field_value(:username) => "Joey"
119
- def field_value(field)
120
- @object && @object.respond_to?(field) ? @object.send(field) : ""
121
- end
122
-
123
127
  # Add a :invalid css class to the field if it contain an error
124
128
  def field_error(field, options)
125
129
  error = @object.errors[field] rescue nil
126
130
  error.blank? ? options[:class] : [options[:class], :invalid].flatten.compact.join(" ")
127
131
  end
128
132
 
129
- # Returns the name for the given field
130
- # field_name(:username) => "user[username]"
131
- def field_name(field)
132
- "#{object_name}[#{field}]"
133
- end
134
-
135
133
  # Returns the human name of the field. Look that use builtin I18n.
136
134
  def field_human_name(field)
137
- I18n.translate("#{object_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models)
135
+ I18n.translate("#{object_model_name}.attributes.#{field}", :count => 1, :default => field.to_s.humanize, :scope => :models)
136
+ end
137
+
138
+ # Returns the name for the given field
139
+ # field_name(:username) => "user[username]"
140
+ # field_name(:number) => "user[telephone_attributes][number]"
141
+ # field_name(:street) => "user[addresses_attributes][0][street]"
142
+ def field_name(field=nil)
143
+ result = []
144
+ if root_form?
145
+ result << object_model_name
146
+ elsif nested_form?
147
+ parent_form = @options[:nested][:parent]
148
+ attributes_name = "#{@options[:nested][:association]}_attributes"
149
+ nested_index = @options[:nested][:index]
150
+ fragment = [parent_form.field_name, "[#{attributes_name}", "]"]
151
+ fragment.insert(2, "][#{nested_index}") if nested_index
152
+ result << fragment
153
+ end
154
+ result << "[#{field}]" unless field.blank?
155
+ result.flatten.join
138
156
  end
139
157
 
140
158
  # Returns the id for the given field
141
159
  # field_id(:username) => "user_username"
142
160
  # field_id(:gender, :male) => "user_gender_male"
143
- def field_id(field, value=nil)
144
- value.blank? ? "#{object_name}_#{field}" : "#{object_name}_#{field}_#{value}"
161
+ # field_name(:number) => "user_telephone_attributes_number"
162
+ # field_name(:street) => "user_addresses_attributes_0_street"
163
+ def field_id(field=nil, value=nil)
164
+ result = []
165
+ if root_form?
166
+ result << object_model_name
167
+ elsif nested_form?
168
+ parent_form = @options[:nested][:parent]
169
+ attributes_name = "#{@options[:nested][:association]}_attributes"
170
+ nested_index = @options[:nested][:index]
171
+ fragment = [parent_form.field_id, "_#{attributes_name}"]
172
+ fragment.push("_#{nested_index}") if nested_index
173
+ result << fragment
174
+ end
175
+ result << "_#{field}" unless field.blank?
176
+ result << "_#{value}" unless value.blank?
177
+ result.flatten.join
178
+ end
179
+
180
+ # Returns the child object if it exists
181
+ def nested_object_id
182
+ nested_form? && object.respond_to?(:new_record?) && !object.new_record? && object.id
183
+ end
184
+
185
+ # Returns true if this form object is nested in a parent form
186
+ def nested_form?
187
+ @options[:nested] && @options[:nested][:parent] && @options[:nested][:parent].respond_to?(:object)
188
+ end
189
+
190
+ # Returns the value for the object's field
191
+ # field_value(:username) => "Joey"
192
+ def field_value(field)
193
+ @object && @object.respond_to?(field) ? @object.send(field) : ""
145
194
  end
146
195
 
147
196
  # explicit_object is either a symbol or a record
@@ -150,10 +199,21 @@ module Padrino
150
199
  object_or_symbol.is_a?(Symbol) ? @template.instance_variable_get("@#{object_or_symbol}") || object_class(object_or_symbol).new : object_or_symbol
151
200
  end
152
201
 
202
+ # Returns the object's models name
203
+ # => user_assignment
204
+ def object_model_name(explicit_object=object)
205
+ explicit_object.is_a?(Symbol) ? explicit_object : explicit_object.class.to_s.underscore.gsub('/', '-')
206
+ end
207
+
153
208
  # Returns the class type for the given object
154
209
  def object_class(explicit_object)
155
210
  explicit_object.is_a?(Symbol) ? explicit_object.to_s.camelize.constantize : explicit_object.class
156
211
  end
212
+
213
+ # Returns true if this form is the top-level (not nested)
214
+ def root_form?
215
+ !nested_form?
216
+ end
157
217
  end # AbstractFormBuilder
158
218
  end # FormBuilder
159
219
  end # Helpers
@@ -10,8 +10,7 @@ module Padrino
10
10
  # form_for @user, '/register', :id => 'register' do |f| ... end
11
11
  #
12
12
  def form_for(object, url, settings={}, &block)
13
- builder_class = configured_form_builder_class(settings[:builder])
14
- form_html = capture_html(builder_class.new(self, object), &block)
13
+ form_html = capture_html(builder_instance(object, settings), &block)
15
14
  form_tag(url, settings) { form_html }
16
15
  end
17
16
 
@@ -25,8 +24,9 @@ module Padrino
25
24
  # fields_for :assignment do |assigment| ... end
26
25
  #
27
26
  def fields_for(object, settings={}, &block)
28
- builder_class = configured_form_builder_class(settings[:builder])
29
- fields_html = capture_html(builder_class.new(self, object), &block)
27
+ instance = builder_instance(object, settings)
28
+ fields_html = capture_html(instance, &block)
29
+ fields_html << instance.hidden_field(:id) if instance.send(:nested_object_id)
30
30
  concat_content fields_html
31
31
  end
32
32
 
@@ -46,7 +46,7 @@ module Padrino
46
46
  options["data-method"] = data_method if data_method
47
47
  options["accept-charset"] ||= "UTF-8"
48
48
  inner_form_html = hidden_form_method_field(desired_method)
49
- inner_form_html += hidden_field_tag(:"_utf8", :value => "&#9731;") + capture_html(&block)
49
+ inner_form_html += capture_html(&block)
50
50
  concat_content content_tag('form', inner_form_html, options)
51
51
  end
52
52
 
@@ -163,6 +163,7 @@ module Padrino
163
163
  #
164
164
  # # => <span class="error">can't be blank</div>
165
165
  # error_message_on :post, :title
166
+ # error_message_on @post, :title
166
167
  #
167
168
  # # => <div class="custom" style="border:1px solid red">can't be blank</div>
168
169
  # error_message_on :post, :title, :tag => :id, :class => :custom, :style => "border:1px solid red"
@@ -171,7 +172,7 @@ module Padrino
171
172
  # error_message_on :post, :title, :prepend => "This title", :append => "(or it won't work)"
172
173
  #
173
174
  def error_message_on(object, field, options={})
174
- object = instance_variable_get("@#{object}")
175
+ object = object.is_a?(Symbol) ? instance_variable_get("@#{object}") : object
175
176
  error = object.errors[field] rescue nil
176
177
  if error
177
178
  options.reverse_merge!(:tag => :span, :class => :error)
@@ -377,17 +378,22 @@ module Padrino
377
378
  configured_builder
378
379
  end
379
380
 
380
-
381
+ ##
382
+ # Returns an initialized builder instance for the given object and settings
381
383
  #
384
+ # builder_instance(@account, :nested => { ... }) => <FormBuilder>
385
+ #
386
+ def builder_instance(object, settings={})
387
+ builder_class = configured_form_builder_class(settings.delete(:builder))
388
+ builder_class.new(self, object, settings)
389
+ end
390
+
391
+ ##
382
392
  # Returns whether the option should be selected or not
383
393
  #
384
- def option_is_selected?(value, caption, selected_value)
385
- if selected_value.is_a? Array
386
- selected_value.any? do |selected|
387
- selected.to_s =~ /^(#{value}|#{caption})$/
388
- end
389
- else
390
- selected_value.to_s =~ /^(#{value}|#{caption})$/
394
+ def option_is_selected?(value, caption, selected_values)
395
+ Array(selected_values).any? do |selected|
396
+ [value.to_s, caption.to_s].include?(selected.to_s)
391
397
  end
392
398
  end
393
399
  end # FormHelpers
@@ -0,0 +1,103 @@
1
+ zh_tw:
2
+ number:
3
+ # Used in number_with_delimiter()
4
+ # These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
5
+ format:
6
+ # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
7
+ separator: "."
8
+ # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
9
+ delimiter: ","
10
+ # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
11
+ precision: 3
12
+
13
+ # Used in number_to_currency()
14
+ currency:
15
+ format:
16
+ # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
17
+ format: "%u %n"
18
+ unit: "NT$"
19
+ # These three are to override number.format and are optional
20
+ separator: "."
21
+ delimiter: ","
22
+ precision: 2
23
+
24
+ # Used in number_to_percentage()
25
+ percentage:
26
+ format:
27
+ # These three are to override number.format and are optional
28
+ # separator:
29
+ delimiter: ""
30
+ # precision:
31
+
32
+ # Used in number_to_precision()
33
+ precision:
34
+ format:
35
+ # These three are to override number.format and are optional
36
+ # separator:
37
+ delimiter: ""
38
+ # precision:
39
+
40
+ # Used in number_to_human_size()
41
+ human:
42
+ format:
43
+ # These three are to override number.format and are optional
44
+ # separator:
45
+ delimiter: ""
46
+ precision: 1
47
+ storage_units:
48
+ # Storage units output formatting.
49
+ # %u is the storage unit, %n is the number (default: 2 MB)
50
+ format: "%n %u"
51
+ units:
52
+ byte:
53
+ one: "Byte"
54
+ other: "Bytes"
55
+ kb: "KB"
56
+ mb: "MB"
57
+ gb: "GB"
58
+ tb: "TB"
59
+
60
+ # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words()
61
+ datetime:
62
+ distance_in_words:
63
+ half_a_minute: "半分鐘"
64
+ less_than_x_seconds:
65
+ one: "不到一秒"
66
+ other: "不到 %{count} 秒"
67
+ x_seconds:
68
+ one: "一秒"
69
+ other: "%{count} 秒"
70
+ less_than_x_minutes:
71
+ one: "不到一分鐘"
72
+ other: "不到 %{count} 分鐘"
73
+ x_minutes:
74
+ one: "一分鐘"
75
+ other: "%{count} 分鐘"
76
+ about_x_hours:
77
+ one: "大約一小時"
78
+ other: "大約 %{count} 小時"
79
+ x_days:
80
+ one: "一天"
81
+ other: "%{count} 天"
82
+ about_x_months:
83
+ one: "大約一個月"
84
+ other: "大約 %{count} 個月"
85
+ x_months:
86
+ one: "一個月"
87
+ other: "%{count} 個月"
88
+ about_x_years:
89
+ one: "大約一年"
90
+ other: "大約 %{count} 年"
91
+ over_x_years:
92
+ one: "一年多"
93
+ other: "%{count} 年多"
94
+ almost_x_years:
95
+ one: "接近一年"
96
+ other: "接近 %{count} 年"
97
+ models:
98
+ errors:
99
+ template:
100
+ header:
101
+ one: "有 1 個錯誤發生使得「%{model}」無法被儲存。"
102
+ other: "有 %{count} 個錯誤發生使得「%{model}」無法被儲存。"
103
+ body: "以下欄位發生問題:"
@@ -2,21 +2,20 @@ module Padrino
2
2
  module Helpers
3
3
  module OutputHelpers
4
4
  ##
5
- # Captures the html from a block of template code for erb or haml
5
+ # Captures the html from a block of template code for any available handler
6
6
  #
7
7
  # ==== Examples
8
8
  #
9
9
  # capture_html(&block) => "...html..."
10
10
  #
11
11
  def capture_html(*args, &block)
12
- if self.respond_to?(:is_haml?) && is_haml?
13
- block_is_haml?(block) ? capture_haml(*args, &block) : block.call
14
- elsif has_erb_buffer?
15
- result_text = capture_erb(*args, &block)
16
- result_text.present? ? result_text : (block_given? && block.call(*args))
17
- else # theres no template to capture, invoke the block directly
18
- block.call(*args)
12
+ handler = self.find_proper_handler
13
+ if handler && handler.is_type? && handler.block_is_type?(block)
14
+ captured_html = handler.capture_from_template(*args, &block)
19
15
  end
16
+ # invoking the block directly if there was no template
17
+ captured_html = block_given? && block.call(*args) if captured_html.blank?
18
+ captured_html
20
19
  end
21
20
 
22
21
  ##
@@ -24,28 +23,28 @@ module Padrino
24
23
  #
25
24
  # ==== Examples
26
25
  #
27
- # concat_content("This will be output to the template buffer in erb or haml")
26
+ # concat_content("This will be output to the template buffer")
28
27
  #
29
28
  def concat_content(text="")
30
- if self.respond_to?(:is_haml?) && is_haml?
31
- haml_concat(text)
32
- elsif has_erb_buffer?
33
- erb_concat(text)
29
+ handler = self.find_proper_handler
30
+ if handler && handler.is_type?
31
+ handler.concat_to_template(text)
34
32
  else # theres no template to concat, return the text directly
35
33
  text
36
34
  end
37
35
  end
38
36
 
39
37
  ##
40
- # Returns true if the block is from an ERB or HAML template; false otherwise.
41
- # Used to determine if html should be returned or concatted to view
38
+ # Returns true if the block is from a supported template type; false otherwise.
39
+ # Used to determine if html should be returned or concatenated to the view
42
40
  #
43
41
  # ==== Examples
44
42
  #
45
43
  # block_is_template?(block)
46
44
  #
47
45
  def block_is_template?(block)
48
- block && (block_is_erb?(block) || (self.respond_to?(:block_is_haml?) && block_is_haml?(block)))
46
+ handler = self.find_proper_handler
47
+ block && handler && handler.block_is_type?(block)
49
48
  end
50
49
 
51
50
  ##
@@ -81,7 +80,7 @@ module Padrino
81
80
  }.join
82
81
  end
83
82
 
84
- private
83
+ protected
85
84
  ##
86
85
  # Retrieves content_blocks stored by content_for or within yield_content
87
86
  #
@@ -94,61 +93,15 @@ module Padrino
94
93
  end
95
94
 
96
95
  ##
97
- # Used to capture the html from a block of erb code
96
+ # Retrieves the template handler for the given output context.
97
+ # Can handle any output related to capturing or concating in a given template.
98
98
  #
99
99
  # ==== Examples
100
100
  #
101
- # capture_erb(&block) => '...html...'
101
+ # find_proper_handler => <OutputHelpers::HamlHandler>
102
102
  #
103
- def capture_erb(*args, &block)
104
- erb_with_output_buffer { block_given? && block.call(*args) }
105
- end
106
-
107
- ##
108
- # Concats directly to an erb template
109
- #
110
- # ==== Examples
111
- #
112
- # erb_concat("Direct to buffer")
113
- #
114
- def erb_concat(text)
115
- @_out_buf << text if has_erb_buffer?
116
- end
117
-
118
- ##
119
- # Returns true if an erb buffer is detected
120
- #
121
- # ==== Examples
122
- #
123
- # has_erb_buffer? => true
124
- #
125
- def has_erb_buffer?
126
- !@_out_buf.nil?
127
- end
128
-
129
- if RUBY_VERSION < '1.9.0'
130
- # Check whether we're called from an erb template.
131
- # We'd return a string in any other case, but erb <%= ... %>
132
- # can't take an <% end %> later on, so we have to use <% ... %>
133
- # and implicitly concat.
134
- def block_is_erb?(block)
135
- has_erb_buffer? || (block && eval('defined? __in_erb_template', block))
136
- end
137
- else
138
- def block_is_erb?(block)
139
- has_erb_buffer? || (block && eval('defined? __in_erb_template', block.binding))
140
- end
141
- end
142
-
143
- ##
144
- # Used to direct the buffer for the erb capture
145
- #
146
- def erb_with_output_buffer(buf = '')
147
- @_out_buf, old_buffer = buf, @_out_buf
148
- yield
149
- @_out_buf
150
- ensure
151
- @_out_buf = old_buffer
103
+ def find_proper_handler
104
+ OutputHelpers.handlers.map { |h| h.new(self) }.find { |h| h.is_type? }
152
105
  end
153
106
  end # OutputHelpers
154
107
  end # Helpers
@@ -0,0 +1,96 @@
1
+ module Padrino
2
+ module Helpers
3
+
4
+ module OutputHelpers
5
+ @template_handlers = []
6
+
7
+ ##
8
+ # Returns the list of all available template handlers
9
+ #
10
+ # ==== Examples
11
+ #
12
+ # OutputHelpers.handlers => [<OutputHelpers::HamlHandler>, <OutputHelpers::ErbHandler>]
13
+ #
14
+ def self.handlers
15
+ @template_handlers
16
+ end
17
+
18
+ ##
19
+ # Registers a new handler as available to the output helpers
20
+ #
21
+ # ==== Examples
22
+ #
23
+ # OutputHelpers.register(OutputHelpers::HamlHandler)
24
+ #
25
+ def self.register(handler)
26
+ handlers << handler
27
+ end
28
+
29
+ class AbstractHandler
30
+ attr_reader :template
31
+
32
+ def initialize(template)
33
+ @template = template
34
+ end
35
+
36
+ ##
37
+ # Returns extension of the template
38
+ #
39
+ # ==== Examples
40
+ #
41
+ # @handler.template_extension => "erubis"
42
+ #
43
+ def template_extension
44
+ caller.find { |c| c =~ /\/views\// }[/\.([\w]*?)\:/, 1] rescue nil
45
+ # "/some/path/app/views/posts/foo.html.erubis:3:in `evaluate_source'"
46
+ # => "erubis"
47
+ end
48
+
49
+ ##
50
+ # Returns true if the current template type is same as this handlers; false otherwise.
51
+ #
52
+ # ==== Examples
53
+ #
54
+ # @handler.is_type? => true
55
+ #
56
+ def is_type?
57
+ # Implemented in subclass
58
+ end
59
+
60
+ ##
61
+ # Returns true if the block given is of the handler's template type; false otherwise.
62
+ #
63
+ # ==== Examples
64
+ #
65
+ # @handler.block_is_type?(block) => true
66
+ #
67
+ def block_is_type?(block)
68
+ # Implemented in subclass
69
+ end
70
+
71
+ ##
72
+ # Captures the html from a block of template code for this handler
73
+ #
74
+ # ==== Examples
75
+ #
76
+ # @handler.capture_from_template(&block) => "...html..."
77
+ #
78
+ def capture_from_template(*args, &block)
79
+ # Implemented in subclass
80
+ end
81
+
82
+ ##
83
+ # Outputs the given text to the templates buffer directly
84
+ #
85
+ # ==== Examples
86
+ #
87
+ # @handler.concat_to_template("This will be output to the template buffer")
88
+ #
89
+ def concat_to_template(text="")
90
+ # Implemented in subclass
91
+ end
92
+ end # AbstractHandler
93
+ end # OutputHelpers
94
+
95
+ end
96
+ end
@@ -0,0 +1,80 @@
1
+ module Padrino
2
+ module Helpers
3
+
4
+ module OutputHelpers
5
+ class ErbHandler < AbstractHandler
6
+ attr_reader :output_buffer
7
+
8
+ def initialize(template)
9
+ super
10
+ @output_buffer = template.instance_variable_get(:@_out_buf)
11
+ end
12
+
13
+ ##
14
+ # Returns true if the current template type is same as this handlers; false otherwise.
15
+ #
16
+ # ==== Examples
17
+ #
18
+ # @handler.is_type? => true
19
+ #
20
+ def is_type?
21
+ self.output_buffer.present?
22
+ end
23
+
24
+ # Captures the html from a block of template code for this handler
25
+ #
26
+ # ==== Examples
27
+ #
28
+ # @handler.capture_from_template(&block) => "...html..."
29
+ #
30
+ def capture_from_template(*args, &block)
31
+ erb_with_output_buffer { block_given? && block.call(*args) }
32
+ end
33
+
34
+ ##
35
+ # Outputs the given text to the templates buffer directly
36
+ #
37
+ # ==== Examples
38
+ #
39
+ # @handler.concat_to_template("This will be output to the template buffer")
40
+ #
41
+ def concat_to_template(text="")
42
+ self.output_buffer << text if self.is_type? && text
43
+ nil
44
+ end
45
+
46
+ if RUBY_VERSION < '1.9.0'
47
+ # Check whether we're called from an erb template.
48
+ # We'd return a string in any other case, but erb <%= ... %>
49
+ # can't take an <% end %> later on, so we have to use <% ... %>
50
+ # and implicitly concat.
51
+ def block_is_type?(block)
52
+ self.is_type? || (block && eval('defined? __in_erb_template', block))
53
+ end
54
+ else
55
+ def block_is_type?(block)
56
+ self.is_type? || (block && eval('defined? __in_erb_template', block.binding))
57
+ end
58
+ end
59
+
60
+ protected
61
+
62
+ ##
63
+ # Used to direct the buffer for the erb capture
64
+ #
65
+ def erb_with_output_buffer(buf = '')
66
+ self.output_buffer, old_buffer = buf, self.output_buffer
67
+ yield
68
+ buf
69
+ ensure
70
+ self.output_buffer = old_buffer
71
+ end
72
+
73
+ def output_buffer=(val)
74
+ template.instance_variable_set(:@_out_buf, val)
75
+ end
76
+ end # ErbHandler
77
+ OutputHelpers.register(ErbHandler)
78
+ end # OutputHelpers
79
+ end
80
+ end
@@ -0,0 +1,54 @@
1
+ module Padrino
2
+ module Helpers
3
+
4
+ module OutputHelpers
5
+ class HamlHandler < AbstractHandler
6
+ ##
7
+ # Returns true if the current template type is same as this handlers; false otherwise.
8
+ #
9
+ # ==== Examples
10
+ #
11
+ # @handler.is_type? => true
12
+ #
13
+ def is_type?
14
+ template.respond_to?(:is_haml?) && template.is_haml?
15
+ end
16
+
17
+ ##
18
+ # Returns true if the block given is of the handler's template type; false otherwise.
19
+ #
20
+ # ==== Examples
21
+ #
22
+ # @handler.block_is_type?(block) => true
23
+ #
24
+ def block_is_type?(block)
25
+ template.block_is_haml?(block)
26
+ end
27
+
28
+ # Captures the html from a block of template code for this handler
29
+ #
30
+ # ==== Examples
31
+ #
32
+ # @handler.capture_from_template(&block) => "...html..."
33
+ #
34
+ def capture_from_template(*args, &block)
35
+ template.capture_haml(*args, &block)
36
+ end
37
+
38
+ ##
39
+ # Outputs the given text to the templates buffer directly
40
+ #
41
+ # ==== Examples
42
+ #
43
+ # @handler.concat_to_template("This will be output to the template buffer")
44
+ #
45
+ def concat_to_template(text="")
46
+ template.haml_concat(text)
47
+ nil
48
+ end
49
+ end # HamlHandler
50
+
51
+ OutputHelpers.register(HamlHandler)
52
+ end # OutputHelpers
53
+ end
54
+ end
@@ -46,6 +46,19 @@ class MarkupUser
46
46
  def gender; 'male'; end
47
47
  def remember_me; '1'; end
48
48
  def permission; Permission.new; end
49
+ def telephone; Telephone.new; end
50
+ def addresses; [Address.new('Greenfield', true), Address.new('Willowrun', false)]; end
51
+ end
52
+
53
+ class Telephone
54
+ def number; "62634576545"; end
55
+ end
56
+
57
+ class Address
58
+ attr_accessor :name
59
+ def initialize(name, existing); @name, @existing = name, existing; end
60
+ def new_record?; !@existing; end
61
+ def id; @existing ? 25 : nil; end
49
62
  end
50
63
 
51
64
  class Permission
@@ -5,4 +5,16 @@
5
5
  <%= permission.check_box :can_edit %>
6
6
  <%= permission.check_box :can_delete %>
7
7
  <% end %>
8
+ <% f.fields_for :telephone do |child_form| %>
9
+ <%= child_form.label :number %>
10
+ <%= child_form.text_field :number %>
11
+ <% end %>
12
+ <% f.fields_for :addresses do |child_form| %>
13
+ <%= child_form.label :name %>
14
+ <%= child_form.text_field :name %>
15
+ <% unless child_form.object.new_record? %>
16
+ <%= child_form.check_box '_destroy' %>
17
+ <%= child_form.label '_destroy', :caption => 'Remove' %>
18
+ <% end %>
19
+ <% end %>
8
20
  <% end %>
@@ -3,4 +3,13 @@
3
3
  = f.text_field :gender
4
4
  - fields_for @user.permission do |permission|
5
5
  = permission.check_box :can_edit
6
- = permission.check_box :can_delete
6
+ = permission.check_box :can_delete
7
+ - f.fields_for :telephone do |child_form|
8
+ = child_form.label :number
9
+ = child_form.text_field :number
10
+ - f.fields_for :addresses do |child_form|
11
+ = child_form.label :name
12
+ = child_form.text_field :name
13
+ - unless child_form.object.new_record?
14
+ = child_form.check_box '_destroy'
15
+ = child_form.label '_destroy', :caption => 'Remove'
data/test/helper.rb CHANGED
@@ -70,6 +70,14 @@ class Test::Unit::TestCase
70
70
  assert File.exist?(file), "File '#{file}' does not exist!"
71
71
  assert_match pattern, File.read(file)
72
72
  end
73
+
74
+ # mock_model("Business", :new_record? => true) => <Business>
75
+ def mock_model(klazz, options={})
76
+ options.reverse_merge!(:class => klazz, :new_record? => false, :id => 20, :errors => {})
77
+ record = stub(options)
78
+ record.stubs(:to_ary => [record])
79
+ record
80
+ end
73
81
  end
74
82
 
75
83
  module Webrat
@@ -9,10 +9,12 @@ class TestFormBuilder < Test::Unit::TestCase
9
9
  end
10
10
 
11
11
  def setup
12
- role_types = [stub(:name => 'Admin', :id => 1), stub(:name => 'Moderate', :id => 2), stub(:name => 'Limited', :id => 3)]
13
- @user = stub(:errors => {:a => "must be present", :b => "must be valid", :email => "Must be valid", :first_name => []}, :class => 'User', :first_name => "Joe", :email => '', :session_id => 54)
12
+ role_types = [mock_model('Role', :name => "Admin", :id => 1),
13
+ mock_model('Role', :name => 'Moderate', :id => 2), mock_model('Role', :name => 'Limited', :id => 3)]
14
+ @user = mock_model("User", :first_name => "Joe", :email => '', :session_id => 54)
15
+ @user.stubs(:errors => {:a => "must be present", :b => "must be valid", :email => "Must be valid", :first_name => []})
14
16
  @user.stubs(:role_types => role_types, :role => "1")
15
- @user_none = stub(:errors => {}, :class => 'User')
17
+ @user_none = mock_model("User")
16
18
  end
17
19
 
18
20
  def standard_builder(object=@user)
@@ -184,6 +186,24 @@ class TestFormBuilder < Test::Unit::TestCase
184
186
  end
185
187
  end
186
188
 
189
+ context 'for #error_message_on method' do
190
+ should "display correct form html with no record" do
191
+ actual_html = standard_builder(@user_none).error_message_on(:name)
192
+ assert actual_html.blank?
193
+ end
194
+
195
+ should "display error for specified invalid object" do
196
+ actual_html = standard_builder(@user).error_message_on(:a, :prepend => "foo", :append => "bar")
197
+ assert_has_tag('span.error', :content => "foo must be present bar") { actual_html }
198
+ end
199
+
200
+ should "display error for specified invalid object not matching class name" do
201
+ @bob = mock_model("User", :first_name => "Frank", :errors => { :foo => "must be bob" })
202
+ actual_html = standard_builder(@bob).error_message_on(:foo, :prepend => "foo", :append => "bar")
203
+ assert_has_tag('span.error', :content => "foo must be bob bar") { actual_html }
204
+ end
205
+ end
206
+
187
207
  context 'for #label method' do
188
208
  should "display correct label html" do
189
209
  actual_html = standard_builder.label(:first_name, :class => 'large', :caption => "F. Name: ")
@@ -520,6 +540,126 @@ class TestFormBuilder < Test::Unit::TestCase
520
540
  end
521
541
  end
522
542
 
543
+ context 'for #fields_for method' do
544
+ setup do
545
+ @telephone = mock_model("Telephone", :number => "4568769876")
546
+ @user.stubs(:telephone).returns(@telephone)
547
+ @businesses = [ mock_model("Business", :name => "Silver", :new_record? => false, :id => 20) ]
548
+ @businesses << mock_model("Business", :name => "Gold", :new_record? => true)
549
+ @addresses = [ mock_model("Address", :name => "Foo", :new_record? => false, :id => 20, :businesses => @businesses) ]
550
+ @addresses << mock_model("Address", :name => "Bar", :new_record? => true, :businesses => @businesses)
551
+ @user.stubs(:addresses).returns(@addresses)
552
+ end
553
+
554
+ should "display nested children fields one-to-one within form" do
555
+ actual_html = standard_builder.fields_for :telephone do |child_form|
556
+ child_form.label(:number) +
557
+ child_form.text_field(:number) +
558
+ child_form.check_box('_destroy')
559
+ end
560
+ assert_has_tag('label', :for => 'user_telephone_attributes_number') { actual_html }
561
+ assert_has_tag('input', :type => 'text', :id => 'user_telephone_attributes_number', :name => 'user[telephone_attributes][number]', :value => "4568769876") { actual_html }
562
+ assert_has_tag('input', :type => 'hidden', :name => 'user[telephone_attributes][_destroy]', :value => '0') { actual_html }
563
+ assert_has_tag('input', :type => 'checkbox', :id => 'user_telephone_attributes__destroy', :name => 'user[telephone_attributes][_destroy]', :value => '1') { actual_html }
564
+ end
565
+
566
+ should "display nested children fields one-to-many within form" do
567
+ actual_html = standard_builder.fields_for(:addresses) do |child_form|
568
+ html = child_form.label(:name)
569
+ html << child_form.check_box('_destroy') unless child_form.object.new_record?
570
+ html << child_form.text_field(:name)
571
+ end
572
+ # Address 1 (Saved)
573
+ assert_has_tag('input', :type => 'hidden', :id => 'user_addresses_attributes_0_id', :name => "user[addresses_attributes][0][id]", :value => '20') { actual_html }
574
+ assert_has_tag('label', :for => 'user_addresses_attributes_0_name', :content => 'Name') { actual_html }
575
+ assert_has_tag('input', :type => 'text', :id => 'user_addresses_attributes_0_name', :name => 'user[addresses_attributes][0][name]') { actual_html }
576
+ assert_has_tag('input', :type => 'checkbox', :id => 'user_addresses_attributes_0__destroy', :name => 'user[addresses_attributes][0][_destroy]') { actual_html }
577
+ # Address 2 (New)
578
+ assert_has_no_tag('input', :type => 'hidden', :id => 'user_addresses_attributes_1_id') { actual_html }
579
+ assert_has_tag('label', :for => 'user_addresses_attributes_1_name', :content => 'Name') { actual_html }
580
+ assert_has_tag('input', :type => 'text', :id => 'user_addresses_attributes_1_name', :name => 'user[addresses_attributes][1][name]') { actual_html }
581
+ assert_has_no_tag('input', :type => 'checkbox', :id => 'user_addresses_attributes_1__destroy') { actual_html }
582
+ end
583
+
584
+ should "display fields for explicit instance object" do
585
+ address = mock_model("Address", :name => "Page", :new_record? => false, :id => 40)
586
+ actual_html = standard_builder.fields_for(:addresses, address) do |child_form|
587
+ html = child_form.label(:name)
588
+ html << child_form.text_field(:name)
589
+ html << child_form.check_box('_destroy')
590
+ end
591
+ assert_has_tag('input', :type => 'hidden', :id => 'user_addresses_attributes_0_id', :name => "user[addresses_attributes][0][id]", :value => '40') { actual_html }
592
+ assert_has_tag('label', :for => 'user_addresses_attributes_0_name', :content => 'Name') { actual_html }
593
+ assert_has_tag('input', :type => 'text', :id => 'user_addresses_attributes_0_name', :name => 'user[addresses_attributes][0][name]', :value => "Page") { actual_html }
594
+ assert_has_tag('input', :type => 'checkbox', :id => 'user_addresses_attributes_0__destroy', :name => 'user[addresses_attributes][0][_destroy]', :value => '1') { actual_html }
595
+ end
596
+
597
+ should "display fields for collection object" do
598
+ addresses = @addresses + [mock_model("Address", :name => "Walter", :new_record? => false, :id => 50)]
599
+ actual_html = standard_builder.fields_for(:addresses, addresses) do |child_form|
600
+ child_form.label(:name) +
601
+ child_form.text_field(:name) +
602
+ child_form.check_box('_destroy')
603
+ end
604
+ # Address 1
605
+ assert_has_tag('input', :type => 'hidden', :id => 'user_addresses_attributes_0_id', :name => "user[addresses_attributes][0][id]", :value => '20') { actual_html }
606
+ assert_has_tag('label', :for => 'user_addresses_attributes_0_name', :content => 'Name') { actual_html }
607
+ assert_has_tag('input', :type => 'text', :id => 'user_addresses_attributes_0_name', :name => 'user[addresses_attributes][0][name]', :value => "Foo") { actual_html }
608
+ assert_has_tag('input', :type => 'checkbox', :id => 'user_addresses_attributes_0__destroy', :name => 'user[addresses_attributes][0][_destroy]') { actual_html }
609
+ # Address 3
610
+ assert_has_tag('input', :type => 'hidden', :id => 'user_addresses_attributes_2_id', :value => '50') { actual_html }
611
+ assert_has_tag('label', :for => 'user_addresses_attributes_2_name', :content => 'Name') { actual_html }
612
+ assert_has_tag('input', :type => 'text', :id => 'user_addresses_attributes_2_name', :name => 'user[addresses_attributes][2][name]', :value => "Walter") { actual_html }
613
+ assert_has_tag('input', :type => 'checkbox', :id => 'user_addresses_attributes_2__destroy') { actual_html }
614
+ end
615
+
616
+ should "display fields for arbitrarily deep nested forms" do
617
+ actual_html = standard_builder.fields_for :addresses do |child_form|
618
+ child_form.fields_for(:businesses) do |second_child_form|
619
+ second_child_form.label(:name) +
620
+ second_child_form.text_field(:name) +
621
+ second_child_form.check_box('_destroy')
622
+ end
623
+ end
624
+ assert_has_tag('label', :for => 'user_addresses_attributes_1_businesses_attributes_0_name', :content => 'Name') { actual_html }
625
+ assert_has_tag('input', :type => 'text', :id => 'user_addresses_attributes_1_businesses_attributes_0_name', :name => 'user[addresses_attributes][1][businesses_attributes][0][name]') { actual_html }
626
+ end
627
+
628
+ should "display nested children fields in erb" do
629
+ visit '/erb/fields_for'
630
+ # Telephone
631
+ assert_have_selector('label', :for => 'markup_user_telephone_attributes_number')
632
+ assert_have_selector('input', :type => 'text', :id => 'markup_user_telephone_attributes_number', :name => 'markup_user[telephone_attributes][number]', :value => "62634576545")
633
+ # Address 1 (Saved)
634
+ assert_have_selector('input', :type => 'hidden', :id => 'markup_user_addresses_attributes_0_id', :name => "markup_user[addresses_attributes][0][id]", :value => '25')
635
+ assert_have_selector('label', :for => 'markup_user_addresses_attributes_0_name', :content => 'Name')
636
+ assert_have_selector('input', :type => 'text', :id => 'markup_user_addresses_attributes_0_name', :name => 'markup_user[addresses_attributes][0][name]')
637
+ assert_have_selector('input', :type => 'checkbox', :id => 'markup_user_addresses_attributes_0__destroy', :name => 'markup_user[addresses_attributes][0][_destroy]')
638
+ # Address 2 (New)
639
+ assert_have_no_selector('input', :type => 'hidden', :id => 'markup_user_addresses_attributes_1_id')
640
+ assert_have_selector('label', :for => 'markup_user_addresses_attributes_1_name', :content => 'Name')
641
+ assert_have_selector('input', :type => 'text', :id => 'markup_user_addresses_attributes_1_name', :name => 'markup_user[addresses_attributes][1][name]')
642
+ assert_have_no_selector('input', :type => 'checkbox', :id => 'markup_user_addresses_attributes_1__destroy')
643
+ end
644
+
645
+ should "display nested children fields in haml" do
646
+ visit '/haml/fields_for'
647
+ # Telephone
648
+ assert_have_selector('label', :for => 'markup_user_telephone_attributes_number')
649
+ assert_have_selector('input', :type => 'text', :id => 'markup_user_telephone_attributes_number', :name => 'markup_user[telephone_attributes][number]', :value => "62634576545")
650
+ # Address 1 (Saved)
651
+ assert_have_selector('input', :type => 'hidden', :id => 'markup_user_addresses_attributes_0_id', :name => "markup_user[addresses_attributes][0][id]", :value => '25')
652
+ assert_have_selector('label', :for => 'markup_user_addresses_attributes_0_name', :content => 'Name')
653
+ assert_have_selector('input', :type => 'text', :id => 'markup_user_addresses_attributes_0_name', :name => 'markup_user[addresses_attributes][0][name]')
654
+ assert_have_selector('input', :type => 'checkbox', :id => 'markup_user_addresses_attributes_0__destroy', :name => 'markup_user[addresses_attributes][0][_destroy]')
655
+ # Address 2 (New)
656
+ assert_have_no_selector('input', :type => 'hidden', :id => 'markup_user_addresses_attributes_1_id')
657
+ assert_have_selector('label', :for => 'markup_user_addresses_attributes_1_name', :content => 'Name')
658
+ assert_have_selector('input', :type => 'text', :id => 'markup_user_addresses_attributes_1_name', :name => 'markup_user[addresses_attributes][1][name]')
659
+ assert_have_no_selector('input', :type => 'checkbox', :id => 'markup_user_addresses_attributes_1__destroy')
660
+ end
661
+ end
662
+
523
663
  # ===========================
524
664
  # StandardFormBuilder
525
665
  # ===========================
@@ -685,4 +825,4 @@ class TestFormBuilder < Test::Unit::TestCase
685
825
  assert_have_selector '#demo2 p input', :type => 'image', :class => 'image', :src => "/images/buttons/ok.png?#{@stamp}"
686
826
  end
687
827
  end
688
- end
828
+ end
@@ -42,13 +42,11 @@ class TestFormHelpers < Test::Unit::TestCase
42
42
  actual_html = form_tag('/remove', :"accept-charset" => "UTF-8", :class => 'delete-form', :method => "delete") { "Demo" }
43
43
  assert_has_tag(:form, :class => "delete-form", :"accept-charset" => "UTF-8", :method => 'post') { actual_html }
44
44
  assert_has_tag('form input', :type => 'hidden', :name => "_method", :value => 'delete') { actual_html }
45
- assert_has_tag('form input', :type => 'hidden', :name => "_utf8") { actual_html }
46
45
  end
47
46
 
48
47
  should "display correct form with charset" do
49
48
  actual_html = form_tag('/charset', :"accept-charset" => "UTF-8", :class => 'charset-form') { "Demo" }
50
49
  assert_has_tag(:form, :class => "charset-form", :"accept-charset" => "UTF-8", :method => 'post') { actual_html }
51
- assert_has_tag('form input', :type => 'hidden', :name => "_utf8") { actual_html }
52
50
  end
53
51
 
54
52
  should "display correct form with multipart encoding" do
@@ -95,7 +93,7 @@ class TestFormHelpers < Test::Unit::TestCase
95
93
 
96
94
  context 'for #error_messages_for method' do
97
95
  should "display correct error messages list in ruby" do
98
- user = stub(:class => "User", :errors => { :a => "1", :b => "2" }, :blank? => false)
96
+ user = mock_model("User", :errors => { :a => "1", :b => "2" }, :blank? => false)
99
97
  actual_html = error_messages_for(user)
100
98
  assert_has_tag('div.field-errors') { actual_html }
101
99
  assert_has_tag('div.field-errors h2', :content => "2 errors prohibited this User from being saved") { actual_html }
@@ -133,6 +131,26 @@ class TestFormHelpers < Test::Unit::TestCase
133
131
  end
134
132
  end
135
133
 
134
+ context 'for #error_message_on method' do
135
+ should "display correct error message on specified model name in ruby" do
136
+ @user = mock_model("User", :errors => { :a => "1", :b => "2" }, :blank? => false)
137
+ actual_html = error_message_on(:user, :a, :prepend => "foo", :append => "bar")
138
+ assert_has_tag('span.error', :content => "foo 1 bar") { actual_html }
139
+ end
140
+
141
+ should "display correct error message on specified object in ruby" do
142
+ @bob = mock_model("User", :errors => { :a => "1", :b => "2" }, :blank? => false)
143
+ actual_html = error_message_on(@bob, :a, :prepend => "foo", :append => "bar")
144
+ assert_has_tag('span.error', :content => "foo 1 bar") { actual_html }
145
+ end
146
+
147
+ should "display no message when error isn't present" do
148
+ @user = mock_model("User", :errors => { :a => "1", :b => "2" }, :blank? => false)
149
+ actual_html = error_message_on(:user, :fake, :prepend => "foo", :append => "bar")
150
+ assert actual_html.blank?
151
+ end
152
+ end
153
+
136
154
  context 'for #label_tag method' do
137
155
  should "display label tag in ruby" do
138
156
  actual_html = label_tag(:username, :class => 'long-label', :caption => "Nickname")
@@ -349,7 +367,7 @@ class TestFormHelpers < Test::Unit::TestCase
349
367
  assert_has_tag(:select, :multiple => 'multiple', :name => 'favorite_color[]') { actual_html }
350
368
  end
351
369
 
352
- should "display options with values and selected" do
370
+ should "display options with values and single selected" do
353
371
  options = [['Green', 'green1'], ['Blue', 'blue1'], ['Black', "black1"]]
354
372
  actual_html = select_tag(:favorite_color, :options => options, :selected => 'green1')
355
373
  assert_has_tag(:select, :name => 'favorite_color') { actual_html }
@@ -359,6 +377,16 @@ class TestFormHelpers < Test::Unit::TestCase
359
377
  assert_has_tag('select option', :content => 'Black', :value => 'black1') { actual_html }
360
378
  end
361
379
 
380
+ should "display option with values and multiple selected" do
381
+ options = [['Green', 'green1'], ['Blue', 'blue1'], ['Black', "black1"]]
382
+ actual_html = select_tag(:favorite_color, :options => options, :selected => ['green1', 'Black'])
383
+ assert_has_tag(:select, :name => 'favorite_color') { actual_html }
384
+ assert_has_tag('select option', :selected => 'selected', :count => 2) { actual_html }
385
+ assert_has_tag('select option', :content => 'Green', :value => 'green1', :selected => 'selected') { actual_html }
386
+ assert_has_tag('select option', :content => 'Blue', :value => 'blue1') { actual_html }
387
+ assert_has_tag('select option', :content => 'Black', :value => 'black1', :selected => 'selected') { actual_html }
388
+ end
389
+
362
390
  should "display options selected only for exact match" do
363
391
  options = [['One', '1'], ['1', '10'], ['Two', "-1"]]
364
392
  actual_html = select_tag(:range, :options => options, :selected => '-1')
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: padrino-helpers
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
5
- prerelease: false
4
+ hash: 17
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 20
10
- version: 0.9.20
9
+ - 21
10
+ version: 0.9.21
11
11
  platform: ruby
12
12
  authors:
13
13
  - Padrino Team
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-01-19 00:00:00 -08:00
21
+ date: 2011-02-28 00:00:00 -08:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -29,12 +29,12 @@ dependencies:
29
29
  requirements:
30
30
  - - "="
31
31
  - !ruby/object:Gem::Version
32
- hash: 19
32
+ hash: 17
33
33
  segments:
34
34
  - 0
35
35
  - 9
36
- - 20
37
- version: 0.9.20
36
+ - 21
37
+ version: 0.9.21
38
38
  type: :runtime
39
39
  version_requirements: *id001
40
40
  - !ruby/object:Gem::Dependency
@@ -88,7 +88,11 @@ files:
88
88
  - lib/padrino-helpers/locale/ru.yml
89
89
  - lib/padrino-helpers/locale/tr.yml
90
90
  - lib/padrino-helpers/locale/uk.yml
91
+ - lib/padrino-helpers/locale/zh_tw.yml
91
92
  - lib/padrino-helpers/number_helpers.rb
93
+ - lib/padrino-helpers/output_helpers/abstract_handler.rb
94
+ - lib/padrino-helpers/output_helpers/erb_handler.rb
95
+ - lib/padrino-helpers/output_helpers/haml_handler.rb
92
96
  - lib/padrino-helpers/output_helpers.rb
93
97
  - lib/padrino-helpers/render_helpers.rb
94
98
  - lib/padrino-helpers/tag_helpers.rb
@@ -161,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
165
  requirements: []
162
166
 
163
167
  rubyforge_project: padrino-helpers
164
- rubygems_version: 1.3.7
168
+ rubygems_version: 1.5.2
165
169
  signing_key:
166
170
  specification_version: 3
167
171
  summary: Helpers for padrino