merb_helpers 0.5 → 0.9.2

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