Skip to content

Instantly share code, notes, and snippets.

@kwatch
Created June 12, 2010 00:03
Show Gist options
  • Save kwatch/435213 to your computer and use it in GitHub Desktop.
Save kwatch/435213 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
module SelectTagHelper
##
## Generate <select> tag. Both <option> and <opttags> are supported.
##
## ex.
## <% values = {'H'=>'Haruhi', 'M'=>'Mikuru', 'Y'=>'Yuki'} %>
## <%= select_tag('yome', 'H', 'class="yome"') do |t|
## t.option(nil, 'Please select')
## values.each {|k,v| t.option(k, v) }
## end %>
##
## #=> <select name="yome" class="yome">
## # <option value="">Please select</option>
## # <option value="H" selected="selected">Haruhi</option>
## # <option value="M">Mikuru</option>
## # <option value="Y">Yuki</option>
## # </select>
##
## ex.
## <% girls = {'H'=>'Haruhi', 'M'=>'Mikuru', 'Y'=>'Yuki'} %>
## <% boys = {'I'=>'Itsuki', 'K'=>'Kyon'} %>
## <%= select_tag('yome', 'H', :class=>"yome") do |t|
## t.option(nil, 'Please select')
## t.optgroup('Girls') do girls.each {|k, v| t.option(k, v) } end
## t.optgroup('Boys') do boys.each {|k, v| t.option(k, v) } end
## end %>
##
## #=> <select name="yome" class="yome">
## # <option value="">Please select</option>
## # <optgroup label="Girls">
## # <option value="H" selected="selected">Haruhi</option>
## # <option value="M">Mikuru</option>
## # <option value="Y">Yuki</option>
## # </optgroup>
## # <optgroup label="Boys">
## # <option value="I">Itsuki</option>
## # <option value="K">Kyon</option>
## # </optgroup>
## # </select>
##
def select_tag(name, value, attrs=nil, &block)
return SelectTag.new.build(name, value, attrs, &block)
end
##
## Generate <select multiple="multiple"> tag.
##
## 'values' arguments can be an Array, Hash, or scalar value.
##
def multiple_select_tag(name, values, attrs=nil, &block)
return MultipleSelectTag.new.build(name, values, attrs, &block)
end
##
## Helper class for select_tag() method
##
class SelectTag # :nodoc:
def build(name, value=nil, attrs=nil)
@value = value
@tag = "<select name=\"#{name}\"#{tag_attr_str(attrs)}>\n"
yield self
@tag << "</select>"
@tag
end
def option(val, label=nil, attrs=nil)
label = val if label.nil?
s1 = selected?(val) ? ' selected="selected"' : nil
s2 = tag_attr_str(attrs)
@tag << "<option value=\"#{val}\"#{s1}#{s2}>#{label}</option>\n"
end
def optgroup(label, attrs=nil)
@tag << "<optgroup label=\"#{label}\">\n"
yield self
@tag << "</optgroup>\n"
end
private
def tag_attr_str(html)
case html
when nil ; nil
when String ; " #{html}"
when Hash ; html.collect {|k, v| " #{k}=\"#{v}\"" }.join
else ; raise ArgumentError.new("#{html.inspect}: String or Hash expected")
end
end
def selected?(val)
@value == val && ! val.nil?
end
end
##
## Helper class for multiple_select_tag() method
##
class MultipleSelectTag < SelectTag # :nodoc:
def build(name, values=nil, attrs=nil, &block)
set_values(values)
@tag = "<select name=\"#{name}\" multiple=\"multiple\"#{tag_attr_str(attrs)}>\n"
yield self
@tag << "</select>"
@tag
end
private
def set_values(values)
case values
when nil ; @values = {}
when Hash ; @values = values
when Enumerable ; @values = {}
values.each {|x| @values[x] = true }
else ; @values = {values => true}
end
end
def selected?(val)
@values.include?(val)
end
end
end
if __FILE__ == $0
ARGV.concat(%w[-f nested -c]) # or %w[-D -f nested]
require 'rubygems'
require 'spec'
## describe のかわりに specs_of を、また it のかわりに spec を使う
Spec::DSL::Main.module_eval { alias specs_of describe }
Spec::Example::ExampleGroupMethods.module_eval { alias spec it }
Object.class_eval { include SelectTagHelper }
specs_of SelectTagHelper, "#select_tag()" do
girls = {'H'=>'Haruhi', 'M'=>'Mikuru', 'Y'=>'Yuki'}
boys = {'I'=>'Itsuki', 'K'=>'Kyon'}
expected1 = <<'END'
<select name="yome" class="yome">
<option value="">Please select</option>
<option value="H" selected="selected">Haruhi</option>
<option value="M">Mikuru</option>
<option value="Y">Yuki</option>
</select>
END
expected1.chomp!
expected2 = <<'END'
<select name="yome" class="yome">
<option value="">Please select</option>
<optgroup label="Girls">
<option value="H" selected="selected">Haruhi</option>
<option value="M">Mikuru</option>
<option value="Y">Yuki</option>
</optgroup>
<optgroup label="Boys">
<option value="I">Itsuki</option>
<option value="K">Kyon</option>
</optgroup>
</select>
END
expected2.chomp!
spec "<select> タグを生成する" do
html = select_tag('yome', nil, 'class="yome"') do |t|
t.option(nil, 'Please select')
girls.each {|k,v| t.option(k, v) }
end
html.should == expected1.sub(/ selected="selected"/, '')
end
spec "現在値が指定されたら <option> タグに 'selected' 属性を追加する" do
html = select_tag('yome', 'H', 'class="yome"') do |t|
t.option(nil, 'Please select')
girls.each {|k,v| t.option(k, v) }
end
html.should == expected1
end
spec "<option> タグと同様に <optgroup> タグもサポートする" do
html = select_tag('yome', nil, 'class="yome"') do |t|
t.option(nil, 'Please select')
t.optgroup('Girls') do
girls.each {|k, v| t.option(k, v) }
end
t.optgroup('Boys') do
boys.each {|k, v| t.option(k, v) }
end
end
html.should == expected2.sub(/ selected="selected"/, '')
end
end
specs_of SelectTagHelper, "#multiple_selected()" do
girls = {'H'=>'Haruhi', 'M'=>'Mikuru', 'Y'=>'Yuki'}
boys = {'I'=>'Itsuki', 'K'=>'Kyon'}
expected1 = <<'END'
<select name="yome" multiple="multiple" class="yome">
<option value="">Please select</option>
<option value="H" selected="selected">Haruhi</option>
<option value="M">Mikuru</option>
<option value="Y" selected="selected">Yuki</option>
</select>
END
expected1.chomp!
expected2 = <<'END'
<select name="yome" multiple="multiple" class="yome">
<option value="">Please select</option>
<optgroup label="Girls">
<option value="H" selected="selected">Haruhi</option>
<option value="M">Mikuru</option>
<option value="Y">Yuki</option>
</optgroup>
<optgroup label="Boys">
<option value="I">Itsuki</option>
<option value="K" selected="selected">Kyon</option>
</optgroup>
</select>
END
expected2.chomp!
spec "'multiple' 属性つきの <select> タグを生成する" do
html = multiple_select_tag('yome', nil, 'class="yome"') do |t|
t.option(nil, 'Please select')
girls.each {|k, v| t.option(k, v) }
end
html.should == expected1.gsub(/ selected="selected"/, '')
end
spec "現在値が配列で指定されたら <option> タグに 'selected' 属性を追加する" do
html = multiple_select_tag('yome', ['H', 'Y'], 'class="yome"') do |t|
t.option(nil, 'Please select')
girls.each {|k, v| t.option(k, v) }
end
html.should == expected1
end
spec "現在値がHashで指定されたら <option> タグに 'selected' 属性を追加する" do
html = multiple_select_tag('yome', {'H'=>true, 'Y'=>true}, 'class="yome"') do |t|
t.option(nil, 'Please select')
girls.each {|k, v| t.option(k, v) }
end
html.should == expected1
end
spec "現在値が文字列や数値で指定されたら <option> タグに 'selected' 属性を追加する" do
html = multiple_select_tag('yome', 'Y', 'class="yome"') do |t|
t.option(nil, 'Please select')
girls.each {|k, v| t.option(k, v) }
end
html.should == expected1.sub(/ selected="selected"/, '') # remove the first one
end
spec "<option> タグだけでなく <optgroups> タグもサポートする" do
html = multiple_select_tag('yome', ['H', 'K'], 'class="yome"') do |t|
t.option(nil, 'Please select')
t.optgroup('Girls') do
girls.each {|k, v| t.option(k, v) }
end
t.optgroup('Boys') do
boys.each {|k, v| t.option(k, v) }
end
end
html.should == expected2
end
end
require 'spec/autorun'
exit Spec::Runner::CommandLine.run
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment