padrino-helpers 0.9.20 → 0.9.21

Sign up to get free protection for your applications and to get access to all the features.
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