merb_helpers 0.5 → 0.9.2

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/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'spec/rake/spectask'
5
5
 
6
6
  PLUGIN = "merb_helpers"
7
7
  NAME = "merb_helpers"
8
- GEM_VERSION = "0.5"
8
+ VERSION = "0.9.2"
9
9
  AUTHOR = "Yehuda Katz"
10
10
  EMAIL = "wycats@gmail.com"
11
11
  HOMEPAGE = "http://merb.rubyforge.org/"
@@ -17,7 +17,7 @@ SUDO = windows ? "" : "sudo"
17
17
 
18
18
  spec = Gem::Specification.new do |s|
19
19
  s.name = NAME
20
- s.version = GEM_VERSION
20
+ s.version = VERSION
21
21
  s.platform = Gem::Platform::RUBY
22
22
  s.has_rdoc = true
23
23
  s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
@@ -26,7 +26,7 @@ spec = Gem::Specification.new do |s|
26
26
  s.author = AUTHOR
27
27
  s.email = EMAIL
28
28
  s.homepage = HOMEPAGE
29
- s.add_dependency("merb", ">=0.5")
29
+ s.add_dependency("merb-core", ">=0.9.2")
30
30
  s.require_path = 'lib'
31
31
  s.autorequire = PLUGIN
32
32
  s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
@@ -39,7 +39,7 @@ end
39
39
 
40
40
  desc "Run :package and install resulting .gem"
41
41
  task :install => [:package] do
42
- sh %{#{SUDO} gem install pkg/#{NAME}-#{GEM_VERSION} --no-rdoc --no-ri}
42
+ sh %{#{SUDO} gem install pkg/#{NAME}-#{VERSION} --no-rdoc --no-ri --no-update-sources}
43
43
  end
44
44
 
45
45
  Rake::RDocTask.new do |rdoc|
@@ -54,7 +54,6 @@ end
54
54
 
55
55
 
56
56
  Spec::Rake::SpecTask.new do |t|
57
- t.warning = true
58
57
  t.spec_opts = ["--format", "specdoc", "--colour"]
59
58
  t.spec_files = Dir['spec/**/*_spec.rb'].sort
60
59
  end
data/lib/merb_helpers.rb CHANGED
@@ -24,12 +24,12 @@ module Merb
24
24
  else
25
25
  load_helpers
26
26
  end
27
-
28
- Merb::Plugins.add_rakefiles "tasks/merb_tasks"
29
27
  end
30
28
 
31
29
  end
32
30
 
33
31
  end
34
32
 
35
- Merb::Helpers.load if defined?(Merb::Plugins)
33
+ Merb::BootLoader.before_app_loads do
34
+ Merb::Helpers.load if defined?(Merb::Plugins)
35
+ end
@@ -1,7 +1,276 @@
1
+ module TimeDSL
2
+ {:second => 1,
3
+ :minute => 60,
4
+ :hour => 3600,
5
+ :day => [24,:hours],
6
+ :week => [7,:days],
7
+ :month => [30,:days],
8
+ :year => [364.25, :days]}.each do |meth, amount|
9
+ define_method meth do
10
+ amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount
11
+ self * amount
12
+ end
13
+ alias_method "#{meth}s".intern, meth
14
+ end
15
+
16
+ # Reads best without arguments: 10.minutes.ago
17
+ def ago(time = ::Time.now)
18
+ time - self
19
+ end
20
+ alias :until :ago
21
+
22
+ # Reads best with argument: 10.minutes.since(time)
23
+ def since(time = ::Time.now)
24
+ time + self
25
+ end
26
+ alias :from_now :since
27
+ end
28
+
29
+ class Integer
30
+ # Ordinalize turns a number into an ordinal string used to denote the
31
+ # position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
32
+ #
33
+ # Examples
34
+ # 1.ordinalize # => "1st"
35
+ # 2.ordinalize # => "2nd"
36
+ # 1002.ordinalize # => "1002nd"
37
+ # 1003.ordinalize # => "1003rd"
38
+ def ordinalize
39
+ if (11..13).include?(self % 100)
40
+ "#{self}th"
41
+ else
42
+ case self % 10
43
+ when 1; "#{self}st"
44
+ when 2; "#{self}nd"
45
+ when 3; "#{self}rd"
46
+ else "#{self}th"
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ Numeric.send :include, TimeDSL
53
+ # Everything above here has pretty much been implemented in the assistance gem...
54
+
55
+ # Time.now.to_ordinalized_s :long
56
+ # => "February 28th, 2006 21:10"
57
+ module OrdinalizedFormatting
58
+ def to_ordinalized_s(format = :default)
59
+ format = Merb::Helpers::DateAndTime::DATE_FORMATS[format]
60
+ return to_default_s if format.nil?
61
+ strftime_ordinalized(format)
62
+ end
63
+
64
+ def strftime_ordinalized(fmt)
65
+ strftime(fmt.gsub(/%d/, '_%d_')).gsub(/_(\d+)_/) { |s| s.to_i.ordinalize }
66
+ end
67
+ end
68
+
69
+ class Date
70
+ include OrdinalizedFormatting
71
+ # Converts a Date instance to a Time, where the time is set to the beginning of the day.
72
+ # The timezone can be either :local or :utc (default :utc).
73
+ #
74
+ # ==== Examples:
75
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
76
+ #
77
+ # date.to_time # => Sat Nov 10 00:00:00 0800 2007
78
+ # date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007
79
+ #
80
+ # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
81
+ def to_time(form = :utc)
82
+ ::Time.send("#{form}_time", year, month, day)
83
+ end
84
+ def to_date; self; end
85
+ end
86
+
87
+ class Time
88
+ include OrdinalizedFormatting
89
+ # Ruby 1.8-cvs and 1.9 define private Time#to_date
90
+ %w(to_date to_datetime).each do |method|
91
+ public method if private_instance_methods.include?(method)
92
+ end
93
+ def to_time; self; end
94
+ end
95
+
1
96
  module Merb
2
97
  module Helpers
98
+ # Provides a number of methods for displaying and dealing with dates and times
99
+ #
100
+ # Parts were strongly based on http://ar-code.svn.engineyard.com/plugins/relative_time_helpers/, and
101
+ # active_support
102
+ #
103
+ # The key methods are `relative_date`, `relative_date_span`, and `relative_time_span`. This also gives
104
+ # you the Rails style Time DSL for working with numbers eg. 3.months.ago or 5.days.until(1.year.from_now)
3
105
  module DateAndTime
106
+ TIME_CLASS = Time
107
+ TIME_OUTPUT = {
108
+ :today => 'today',
109
+ :yesterday => 'yesterday',
110
+ :tomorrow => 'tomorrow',
111
+ :initial_format => '%b %d',
112
+ :year_format => ', %Y'
113
+ }
114
+ DATE_FORMATS = {
115
+ :db => "%Y-%m-%d %H:%M:%S",
116
+ :time => "%H:%M",
117
+ :short => "%d %b %H:%M",
118
+ :long => "%B %d, %Y %H:%M",
119
+ :long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") },
120
+ :rfc822 => "%a, %d %b %Y %H:%M:%S %z"
121
+ }
122
+
123
+ # Gives you a relative date in an attractive format
124
+ #
125
+ # ==== Parameters
126
+ # time<~to_date>:: The Date or Time to test
127
+ #
128
+ # ==== Returns
129
+ # String:: The sexy relative date
130
+ #
131
+ # ==== Examples
132
+ # relative_date(Time.now.utc) => "today"
133
+ # relative_date(5.days.ago) => "March 5th"
134
+ # relative_date(1.year.ago) => "March 10th, 2007"
135
+ def relative_date(time)
136
+ date = time.to_date
137
+ today = TIME_CLASS.now.to_date
138
+ if date == today
139
+ TIME_OUTPUT[:today]
140
+ elsif date == (today - 1)
141
+ TIME_OUTPUT[:yesterday]
142
+ elsif date == (today + 1)
143
+ TIME_OUTPUT[:tomorrow]
144
+ else
145
+ fmt = TIME_OUTPUT[:initial_format].dup
146
+ fmt << TIME_OUTPUT[:year_format] unless date.year == today.year
147
+ time.strftime_ordinalized(fmt)
148
+ end
149
+ end
150
+
151
+ # Gives you a relative date span in an attractive format
152
+ #
153
+ # ==== Parameters
154
+ # times<~first,~last>:: The Dates or Times to test
155
+ #
156
+ # ==== Returns
157
+ # String:: The sexy relative date span
158
+ #
159
+ # ==== Examples
160
+ # relative_date([1.second.ago, 10.seconds.ago]) => "March 10th"
161
+ # relative_date([1.year.ago, 1.year.ago) => "March 10th, 2007"
162
+ # relative_date([Time.now, 1.day.from_now]) => "March 10th - 11th"
163
+ # relative_date([Time.now, 1.year.ago]) => "March 10th, 2007 - March 10th, 2008"
164
+ def relative_date_span(times)
165
+ times = [times.first, times.last].collect! { |t| t.to_date }
166
+ times.sort!
167
+ if times.first == times.last
168
+ relative_date(times.first)
169
+ else
170
+ first = times.first; last = times.last; now = TIME_CLASS.now
171
+ arr = [first.strftime_ordinalized('%b %d')]
172
+ arr << ", #{first.year}" unless first.year == last.year
173
+ arr << ' - '
174
+ arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
175
+ arr << last.day.ordinalize
176
+ arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
177
+ arr.to_s
178
+ end
179
+ end
180
+
181
+ # Gives you a relative date span in an attractive format
182
+ #
183
+ # ==== Parameters
184
+ # times<~first,~last>:: The Dates or Times to test
185
+ #
186
+ # ==== Returns
187
+ # String:: The sexy relative time span
188
+ #
189
+ # ==== Examples
190
+ # relative_time_span([1.second.ago, 10.seconds.ago]) => "12:00 - 12:09 AM March 10th"
191
+ # relative_time_span([1.year.ago, 1.year.ago) => "12:09 AM March 10th, 2007"
192
+ # relative_time_span([Time.now, 13.hours.from_now]) => "12:09 AM - 1:09 PM March 10th"
193
+ # relative_time_span([Time.now, 1.year.ago]) => "12:09 AM March 10th, 2007 - 12:09 AM March 10th, 2008"
194
+ def relative_time_span(times)
195
+ times = [times.first, times.last].collect! { |t| t.to_time }
196
+ times.sort!
197
+ if times.first == times.last
198
+ "#{prettier_time(times.first)} #{relative_date(times.first)}"
199
+ elsif times.first.to_date == times.last.to_date
200
+ same_half = (times.first.hour/12 == times.last.hour/12)
201
+ "#{prettier_time(times.first, !same_half)} - #{prettier_time(times.last)} #{relative_date(times.first)}"
202
+
203
+ else
204
+ first = times.first; last = times.last; now = TIME_CLASS.now
205
+ arr = [prettier_time(first)]
206
+ arr << ' '
207
+ arr << first.strftime_ordinalized('%b %d')
208
+ arr << ", #{first.year}" unless first.year == last.year
209
+ arr << ' - '
210
+ arr << prettier_time(last)
211
+ arr << ' '
212
+ arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
213
+ arr << last.day.ordinalize
214
+ arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
215
+ arr.to_s
216
+ end
217
+ end
218
+
219
+ # Condenses time... very similar to time_ago_in_words in ActionPack
220
+ #
221
+ # ==== Parameters
222
+ # from_time<~to_time>:: The Date or Time to start from
223
+ # to_time<~to_time>:: The Date or Time to go to, Defaults to Time.now.utc
224
+ # include_seconds<Boolean>:: Count the seconds initially, Defaults to false
225
+ #
226
+ # ==== Returns
227
+ # String:: The time distance
228
+ #
229
+ # ==== Examples
230
+ # time_lost_in_words(3.minutes.from_now) # => 3 minutes
231
+ # time_lost_in_words(Time.now - 15.hours) # => 15 hours
232
+ # time_lost_in_words(Time.now, 3.minutes.from_now) # => 3 minutes
233
+ # time_lost_in_words(Time.now) # => less than a minute
234
+ # time_lost_in_words(Time.now, Time.now, true) # => less than 5 seconds
235
+ #
236
+ def time_lost_in_words(from_time, to_time = Time.now.utc, include_seconds = false)
237
+ from_time = from_time.to_time if from_time.respond_to?(:to_time)
238
+ to_time = to_time.to_time if to_time.respond_to?(:to_time)
239
+ distance_in_minutes = (((to_time - from_time).abs)/60).round
240
+ distance_in_seconds = ((to_time - from_time).abs).round
241
+
242
+ case distance_in_minutes
243
+ when 0..1
244
+ return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
245
+ case distance_in_seconds
246
+ when 0..4 then 'less than 5 seconds'
247
+ when 5..9 then 'less than 10 seconds'
248
+ when 10..19 then 'less than 20 seconds'
249
+ when 20..39 then 'half a minute'
250
+ when 40..59 then 'less than a minute'
251
+ else '1 minute'
252
+ end
253
+
254
+ when 2..44 then "#{distance_in_minutes} minutes"
255
+ when 45..89 then 'about 1 hour'
256
+ when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
257
+ when 1440..2879 then '1 day'
258
+ when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
259
+ when 43200..86399 then 'about 1 month'
260
+ when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
261
+ when 525600..1051199 then 'about 1 year'
262
+ else "over #{(distance_in_minutes / 525600).round} years"
263
+ end
264
+ end
265
+ alias :time_ago_in_words :time_lost_in_words
4
266
 
267
+ def prettier_time(time, ampm=true)
268
+ time.strftime("%I:%M#{" %p" if ampm}").sub(/^0/, '')
269
+ end
5
270
  end
6
271
  end
272
+ end
273
+
274
+ class Merb::Controller #:nodoc:
275
+ include Merb::Helpers::DateAndTime
7
276
  end
@@ -1,3 +1,5 @@
1
+ require "#{File.dirname(__FILE__)}/tag_helpers"
2
+
1
3
  module Merb #:nodoc:
2
4
 
3
5
  # Merb helpers include several helpers used for simplifying view creation.
@@ -28,7 +30,7 @@ module Merb #:nodoc:
28
30
  # </form>
29
31
  #
30
32
  # You may also create a normal form using form_tag
31
- # <% form_tag({url(:controller => "foo", :action => "bar", :id => 1)} do %>
33
+ # <% form_tag(:action => url(:controller => "foo", :action => "bar", :id => 1)) do %>
32
34
  # <%= text_field :name => 'first_name', :label => 'First Name' %>
33
35
  # <%= submit_button 'Create' %>
34
36
  # <% end %>
@@ -43,20 +45,35 @@ module Merb #:nodoc:
43
45
 
44
46
  # Provides a HTML formatted display of resource errors in an unordered list with a h2 form submission error
45
47
  # ==== Options
48
+ # +build_li+:: Block for generating a list item for an error. It receives an instance of the error.
46
49
  # +html_class+:: Set for custom error div class default is <tt>submittal_failed<tt>
47
50
  #
48
- # ==== Example
49
- # <%= error_messages_for :person %>
50
- def error_messages_for(obj, error_li = nil, html_class='submittal_failed')
51
- return "" if !obj.respond_to?(:errors) || obj.errors.empty?
52
- header_message = block_given? ? yield(obj.errors) : "<h2>Form submittal failed because of #{obj.errors.size} #{obj.errors.size == 1 ? 'problem' : 'problems'}</h2>"
53
- ret = %Q{
51
+ # ==== Examples
52
+ # <%= error_messages_for :person %>
53
+ # <%= error_messages_for :person {|errors| "You can has probs nao: #{errors.size} of em!"}
54
+ # <%= error_messages_for :person, lambda{|error| "<li class='aieeee'>#{error.join(' ')}"} %>
55
+ # <%= error_messages_for :person, nil, 'bad_mojo' %>
56
+ def error_messages_for(obj, build_li = nil, html_class='error')
57
+ return "" unless obj.respond_to?(:errors) && ! obj.errors.empty?
58
+
59
+ header_message = if block_given?
60
+ yield(obj.errors)
61
+ else
62
+ error_plurality = (obj.errors.size == 1 ? 'problem' : 'problems')
63
+ "<h2>Form submittal failed because of #{obj.errors.size} #{error_plurality}</h2>"
64
+ end
65
+
66
+ build_li ||= lambda{|err| "<li>#{err.join(' ')}</li>"}
67
+
68
+ markup = %Q{
54
69
  <div class='#{html_class}'>
55
70
  #{header_message}
56
71
  <ul>
57
72
  }
58
- obj.errors.each {|err| ret << (error_li ? error_li.call(err) : "<li>#{err.join(" ")}</li>") }
59
- ret << %Q{
73
+
74
+ obj.errors.each {|error| markup << build_li.call(error) }
75
+
76
+ markup << %Q{
60
77
  </ul>
61
78
  </div>
62
79
  }
@@ -65,15 +82,10 @@ module Merb #:nodoc:
65
82
  def obj_from_ivar_or_sym(obj) #:nodoc:
66
83
  obj.is_a?(Symbol) ? instance_variable_get("@#{obj}") : obj
67
84
  end
68
-
69
- # Creates a generic HTML tag
70
- def tag(tag_name, contents, attrs = {}) #:nodoc:
71
- open_tag(tag_name, attrs) + contents.to_s + "</#{tag_name}>"
72
- end
73
-
85
+
74
86
  # Generates a form tag, which accepts a block that is not directly based on resource attributes
75
87
  #
76
- # <% form_tag({url(:controller => "foo", :action => "bar", :id => 1)} do %>
88
+ # <% form_tag(:action => url(:controller => "foo", :action => "bar", :id => 1)) do %>
77
89
  # <%= text_field :name => 'first_name', :label => 'First Name' %>
78
90
  # <%= submit_button 'Create' %>
79
91
  # <% end %>
@@ -152,7 +164,7 @@ module Merb #:nodoc:
152
164
  end
153
165
 
154
166
  def control_value(col) #:nodoc:
155
- @_obj.send(col)
167
+ escape_xml(@_obj.send(col))
156
168
  end
157
169
 
158
170
  def control_name_value(col, attrs) #:nodoc:
@@ -175,7 +187,7 @@ module Merb #:nodoc:
175
187
  # Provides a HTML text input tag based on a resource attribute.
176
188
  #
177
189
  # ==== Example
178
- # <%= text_field :fav_color, :label => 'Your Favorite Color' %>
190
+ # <%= text_field :name => :fav_color, :label => 'Your Favorite Color' %>
179
191
  # # => <label for="fav_color">Your Favorite Color</label><input type="text" name="fav_color" id="fav_color"/>
180
192
  def text_field(attrs = {})
181
193
  attrs.merge!(:type => "text")
@@ -197,7 +209,7 @@ module Merb #:nodoc:
197
209
  # Provides a generic HTML password input tag.
198
210
  #
199
211
  # ==== Example
200
- # <%= password_field :password, :label => "Password" %>
212
+ # <%= password_field :name => :password, :label => "Password" %>
201
213
  # # => <label for="password">Password</label><input type="password" name="password" id="password"/>
202
214
  def password_field(attrs = {})
203
215
  attrs.delete(:value)
@@ -296,9 +308,10 @@ module Merb #:nodoc:
296
308
  val = @_obj.send(col)
297
309
  ret = ""
298
310
  options.each do |opt|
299
- value, label = opt.is_a?(Hash) ? [opt[:value], opt[:label]] : [opt, opt]
300
- hash = {:name => "#{@_object_name}[#{col}]", :value => value, :label => label}
301
- hash.merge!(:selected => "selected") if val.to_s == value.to_s
311
+ value, label = opt.is_a?(Hash) ? [opt.delete(:value), opt.delete(:label)] : [opt, opt]
312
+ hash = {:name => "#{@_object_name}[#{col}]", :value => value, :label => label, :id => "#{control_id(col)}_#{value}" }
313
+ hash.merge!(opt) if opt.is_a?(Hash)
314
+ hash.merge!(:checked => "checked") if val.to_s == value.to_s
302
315
  ret << radio_field(hash)
303
316
  end
304
317
  ret
@@ -324,6 +337,7 @@ module Merb #:nodoc:
324
337
  def text_area_control(col, attrs = {})
325
338
  attrs ||= {}
326
339
  errorify_field(attrs, col)
340
+ attrs.merge!(:id => control_id(col))
327
341
  text_area_field(control_value(col), attrs.merge(:name => control_name(col)))
328
342
  end
329
343
 
@@ -388,6 +402,7 @@ module Merb #:nodoc:
388
402
  def select_control(col, attrs = {})
389
403
  attrs.merge!(:name => attrs[:name] || control_name(col))
390
404
  attrs.merge!(:id => attrs[:id] || control_id(col))
405
+ attrs.merge!(:selected => attrs[:selected] || control_value(col))
391
406
  errorify_field(attrs, col)
392
407
  optional_label(attrs) { select_field(attrs) }
393
408
  end
@@ -414,22 +429,24 @@ module Merb #:nodoc:
414
429
  prompt = attrs.delete(:prompt)
415
430
  blank = attrs.delete(:include_blank)
416
431
  selected = attrs.delete(:selected)
417
- returning '' do |ret|
418
- ret << tag('option', prompt, :value => '') if prompt
419
- ret << tag("option", '', :value => '') if blank
420
- unless collection.blank?
421
- if collection.is_a?(Hash)
422
- collection.each do |label,group|
423
- ret << open_tag("optgroup", :label => label.to_s.titleize) + options_for_select(group, :selected => selected) + "</optgroup>"
424
- end
425
- else
426
- collection.each do |value,text|
427
- options = selected.to_a.include?(value) ? {:selected => 'selected'} : {}
428
- ret << tag( 'option', text, {:value => value}.merge(options) )
429
- end
432
+ ret = String.new
433
+ ret << tag('option', prompt, :value => '') if prompt
434
+ ret << tag("option", '', :value => '') if blank
435
+ unless collection.blank?
436
+ if collection.is_a?(Hash)
437
+ collection.each do |label,group|
438
+ ret << open_tag("optgroup", :label => label.to_s.gsub(/\b[a-z]/) {|x| x.upcase}) +
439
+ options_for_select(group, :selected => selected) + "</optgroup>"
440
+ end
441
+ else
442
+ collection.each do |value,text|
443
+ options = selected.to_a.include?(value) ? {:selected => 'selected'} : {}
444
+ ret << tag( 'option', text, {:value => value}.merge(options) )
430
445
  end
431
446
  end
432
447
  end
448
+
449
+ return ret
433
450
  end
434
451
 
435
452
  # Returns a string of option tags that have been compiled by iterating over the collection and
@@ -442,7 +459,7 @@ module Merb #:nodoc:
442
459
  # If we had a collection of people within a @project object, and want to use 'id' as the value, and 'name'
443
460
  # as the option content we could do something similar to this;
444
461
  #
445
- # <%= options_from_collection_for_select(@project.people, :text_method => "id", :value_method => "name") %>
462
+ # <%= options_from_collection_for_select(@project.people, :value_method => "id", :text_method => "name") %>
446
463
  # The iteration of the collection would create options in this manner;
447
464
  # => <option value="#{person.id}">#{person.name}</option>
448
465
  #
@@ -458,14 +475,16 @@ module Merb #:nodoc:
458
475
  def options_from_collection_for_select(collection, attrs = {})
459
476
  prompt = attrs.delete(:prompt)
460
477
  blank = attrs.delete(:include_blank)
478
+ ret = String.new
461
479
  if collection.is_a?(Hash)
462
- returning '' do |ret|
463
- ret << tag("option", prompt, :value => '') if prompt
464
- ret << tag("option", '', :value => '') if blank
465
- collection.each do |label, group|
466
- ret << open_tag("optgroup", :label => label.to_s.humanize.titleize) + options_from_collection_for_select(group, attrs) + "</optgroup>"
467
- end
480
+ ret << tag("option", prompt, :value => '') if prompt
481
+ ret << tag("option", '', :value => '') if blank
482
+ collection.each do |label, group|
483
+ # .gsub(/_/, " ").gsub(/\b[a-z]/) {|x| x.upcase}) == .humanize.titleize, which is no longer in -core
484
+ ret << open_tag("optgroup", :label => label.to_s.gsub(/_/, " ").gsub(/\b[a-z]/) {|x| x.upcase}) +
485
+ options_from_collection_for_select(group, attrs) + "</optgroup>"
468
486
  end
487
+ return ret
469
488
  else
470
489
  text_method = attrs[:text_method]
471
490
  value_method = attrs[:value_method]
@@ -552,45 +571,51 @@ module Merb #:nodoc:
552
571
  end
553
572
 
554
573
  private
555
-
556
- # Fake out the browser to send back the method for RESTful stuff.
557
- # Fall silently back to post if a method is given that is not supported here
558
- def set_form_method(options = {}, obj = nil)
559
- options[:method] ||= ((obj && obj.respond_to?(:new_record?) && !obj.new_record?) ? :put : :post)
560
- if ![:get,:post].include?(options[:method])
561
- fake_form_method = options[:method] if [:put, :delete].include?(options[:method])
562
- options[:method] = :post
563
- end
564
- fake_form_method
565
- end
566
-
567
- def generate_fake_form_method(fake_form_method)
568
- fake_form_method ? hidden_field(:name => "_method", :value => "#{fake_form_method}") : ""
569
- end
570
-
571
- def optional_label(attrs = {})
572
- label = attrs.delete(:label) if attrs
573
- if label
574
- title = label.is_a?(Hash) ? label.delete(:title) : label
575
- named = attrs[:id].blank? ? {} : {:for => attrs[:id]}
576
- label(title, '', label.is_a?(Hash) ? label.merge(named) : named) + yield
574
+ # Fake out the browser to send back the method for RESTful stuff.
575
+ # Fall silently back to post if a method is given that is not supported here
576
+ def set_form_method(options = {}, obj = nil)
577
+ options[:method] ||= ((obj && obj.respond_to?(:new_record?) && !obj.new_record?) ? :put : :post)
578
+ if ![:get,:post].include?(options[:method])
579
+ fake_form_method = options[:method] if [:put, :delete].include?(options[:method])
580
+ options[:method] = :post
581
+ end
582
+ fake_form_method
583
+ end
584
+
585
+ def generate_fake_form_method(fake_form_method)
586
+ fake_form_method ? hidden_field(:name => "_method", :value => "#{fake_form_method}") : ""
587
+ end
588
+
589
+ def optional_label(attrs = {})
590
+ label = attrs.delete(:label) if attrs
591
+ if label
592
+ title = label.is_a?(Hash) ? label.delete(:title) : label
593
+ named = attrs[:id].blank? ? {} : {:for => attrs[:id]}
594
+ align = label.delete(:align) if label.is_a?(Hash)
595
+ align ||= ['radio', 'checkbox'].include?(attrs[:type].to_s) ? :right : :left
596
+ label_tag = label(title, '', label.is_a?(Hash) ? label.merge(named) : named)
597
+ if align && align.to_sym == :right
598
+ yield + label_tag
577
599
  else
578
- yield
600
+ label_tag + yield
579
601
  end
602
+ else
603
+ yield
580
604
  end
581
-
582
- def errorify_field(attrs, col)
583
- attrs.add_html_class!("error") if @_obj.respond_to?(:errors) && @_obj.errors.on(col)
584
- end
585
-
586
- def set_multipart_attribute!(attrs = {})
587
- attrs.merge!( :enctype => "multipart/form-data" ) if attrs.delete(:multipart)
588
- end
605
+ end
606
+
607
+ def errorify_field(attrs, col)
608
+ attrs.add_html_class!("error") if @_obj.respond_to?(:errors) && @_obj.errors.on(col)
609
+ end
610
+
611
+ def set_multipart_attribute!(attrs = {})
612
+ attrs.merge!( :enctype => "multipart/form-data" ) if attrs.delete(:multipart)
613
+ end
589
614
 
590
615
  end
591
616
  end
592
617
  end
593
618
 
594
- class Merb::ViewContext #:nodoc:
619
+ class Merb::Controller #:nodoc:
595
620
  include Merb::Helpers::Form
596
621
  end
@@ -0,0 +1,61 @@
1
+ module Merb
2
+ module Helpers
3
+ module Tag
4
+ # Creates a generic HTML tag. You can invoke it a variety of ways.
5
+ #
6
+ # tag :div
7
+ # # <div></div>
8
+ #
9
+ # tag :div, 'content'
10
+ # # <div>content</div>
11
+ #
12
+ # tag :div, :class => 'class'
13
+ # # <div class="class"></div>
14
+ #
15
+ # tag :div, 'content', :class => 'class'
16
+ # # <div class="class">content</div>
17
+ #
18
+ # tag :div do
19
+ # 'content'
20
+ # end
21
+ # # <div>content</div>
22
+ #
23
+ # tag :div, :class => 'class' do
24
+ # 'content'
25
+ # end
26
+ # # <div class="class">content</div>
27
+ #
28
+ def tag(name, contents = nil, attrs = {}, &block)
29
+ attrs = contents if contents.is_a?(Hash)
30
+ contents = capture(&block) if block_given?
31
+ open_tag(name, attrs) + contents.to_s + close_tag(name)
32
+ end
33
+
34
+ # Creates the opening tag with attributes for the provided +name+
35
+ # attrs is a hash where all members will be mapped to key="value"
36
+ #
37
+ # Note: This tag will need to be closed
38
+ def open_tag(name, attrs = nil)
39
+ "<#{name}#{' ' + attrs.to_html_attributes if attrs && !attrs.empty?}>"
40
+ end
41
+
42
+ # Creates a closing tag
43
+ def close_tag(name)
44
+ "</#{name}>"
45
+ end
46
+
47
+ # Creates a self closing tag. Like <br/> or <img src="..."/>
48
+ #
49
+ # +name+ : the name of the tag to create
50
+ # +attrs+ : a hash where all members will be mapped to key="value"
51
+ def self_closing_tag(name, attrs = nil)
52
+ "<#{name}#{' ' + attrs.to_html_attributes if attrs && !attrs.empty?}/>"
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+
59
+ class Merb::Controller #:nodoc:
60
+ include Merb::Helpers::Tag
61
+ end
metadata CHANGED
@@ -1,66 +1,72 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
3
- specification_version: 1
4
2
  name: merb_helpers
5
3
  version: !ruby/object:Gem::Version
6
- version: "0.5"
7
- date: 2008-01-09 00:00:00 -08:00
8
- summary: Helper support for merb (similar to the Rails form helpers)
9
- require_paths:
10
- - lib
11
- email: wycats@gmail.com
12
- homepage: http://merb.rubyforge.org/
13
- rubyforge_project:
14
- description: Helper support for merb (similar to the Rails form helpers)
15
- autorequire: merb_helpers
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.9.2
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
6
  authors:
30
7
  - Yehuda Katz
8
+ autorequire: merb_helpers
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-24 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb-core
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.9.2
23
+ version:
24
+ description: Helper support for merb (similar to the Rails form helpers)
25
+ email: wycats@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README
32
+ - LICENSE
33
+ - TODO
31
34
  files:
32
35
  - LICENSE
33
36
  - README
34
37
  - Rakefile
35
38
  - TODO
36
39
  - lib/merb_helpers
37
- - lib/merb_helpers.rb
38
- - lib/tasks
39
40
  - lib/merb_helpers/date_time_helpers.rb
40
41
  - lib/merb_helpers/form_helpers.rb
41
42
  - lib/merb_helpers/form_model.rb
42
- - lib/tasks/merb_tasks.rb
43
- test_files: []
44
-
43
+ - lib/merb_helpers/tag_helpers.rb
44
+ - lib/merb_helpers.rb
45
+ has_rdoc: true
46
+ homepage: http://merb.rubyforge.org/
47
+ post_install_message:
45
48
  rdoc_options: []
46
49
 
47
- extra_rdoc_files:
48
- - README
49
- - LICENSE
50
- - TODO
51
- executables: []
52
-
53
- extensions: []
54
-
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
55
64
  requirements: []
56
65
 
57
- dependencies:
58
- - !ruby/object:Gem::Dependency
59
- name: merb
60
- version_requirement:
61
- version_requirements: !ruby/object:Gem::Version::Requirement
62
- requirements:
63
- - - ">="
64
- - !ruby/object:Gem::Version
65
- version: "0.5"
66
- version:
66
+ rubyforge_project:
67
+ rubygems_version: 1.0.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: Helper support for merb (similar to the Rails form helpers)
71
+ test_files: []
72
+
@@ -1,6 +0,0 @@
1
- namespace :merb_helpers do
2
- desc "Do something for merb_helpers"
3
- task :default do
4
- puts "merb_helpers doesn't do anything"
5
- end
6
- end