├── .yardopts
├── init.rb
├── lib
├── table_builder
│ ├── version.rb
│ ├── table_builder.rb
│ └── calendar_helper.rb
└── table_builder.rb
├── .gitignore
├── Gemfile
├── .travis.yml
├── Rakefile
├── .autotest
├── test
├── test_helper.rb
├── table_builder_test.rb
└── calendar_helper_test.rb
├── LICENSE
├── table_builder.gemspec
└── README.md
/.yardopts:
--------------------------------------------------------------------------------
1 | --markup markdown lib/**/*.rb
--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
1 | require 'table_builder'
2 |
--------------------------------------------------------------------------------
/lib/table_builder/version.rb:
--------------------------------------------------------------------------------
1 | module TableBuilder
2 | VERSION = "0.3.0"
3 | end
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | pkg
3 | .idea
4 | *.gem
5 | .bundle
6 | Gemfile.lock
7 | pkg/*
8 | .yardoc
9 | doc
10 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "http://rubygems.org"
2 |
3 | # Specify your gem's dependencies in table_builder.gemspec
4 | gemspec
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | rvm:
3 | - 1.9.3
4 | # uncomment this line if your project needs to run something other than `rake`:
5 | # script: bundle exec rspec spec
--------------------------------------------------------------------------------
/lib/table_builder.rb:
--------------------------------------------------------------------------------
1 | require "table_builder/table_builder.rb"
2 | require "table_builder/calendar_helper.rb"
3 | require "table_builder/version.rb"
4 |
5 | ActionView::Base.send :include, TableHelper
6 | ActionView::Base.send :include, CalendarHelper
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "rake"
2 | require "rake/testtask"
3 | require "bundler/gem_tasks"
4 |
5 | desc "Default: run unit tests."
6 | task :default => :test
7 |
8 | desc "Test the table_builder plugin."
9 | Rake::TestTask.new(:test) do |t|
10 | t.libs << "lib"
11 | t.pattern = "test/**/*_test.rb"
12 | t.verbose = true
13 | end
14 |
--------------------------------------------------------------------------------
/.autotest:
--------------------------------------------------------------------------------
1 | Autotest.add_hook :initialize do |at|
2 | at.clear_mappings
3 | at.add_mapping(/^lib\/.*\.rb$/) do |filename, _|
4 | possible = File.basename(filename).gsub '_', '_?'
5 | at.files_matching %r%^test/.*#{possible}$%
6 | end
7 |
8 | at.add_mapping(/^test\/.*\_test.rb/) do |f, _|
9 | at.files_matching(/^test\/.*_test.rb$/)
10 | end
11 |
12 | end
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | require 'test/unit'
2 |
3 | require "rubygems"
4 | require 'active_support'
5 | require 'action_pack'
6 | require 'action_controller'
7 | require 'action_view'
8 | require 'action_controller'
9 | require 'action_view'
10 | require 'action_view/base'
11 | require 'action_view/template'
12 | require 'action_view/test_case'
13 |
14 | require(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'table_builder')))
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008 Petrik de Heus
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/table_builder.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 |
3 | $:.push File.expand_path("../lib", __FILE__)
4 | require "table_builder/version"
5 |
6 | Gem::Specification.new do |s|
7 | s.name = "watu_table_builder"
8 | s.version = TableBuilder::VERSION
9 | s.authors = ["Petrik de Heus", "Andrew C. Greenberg", "Jason Cheong-Kee-You", "J. Pablo Fernández"]
10 | s.email = ["pupeno@watuhq.com"]
11 | s.homepage = "https://github.com/watu/table_builder"
12 | s.summary = %q{Rails builder for creating tables and calendars inspired by ActionView's FormBuilder.}
13 | s.description = %q{Rails builder for creating tables and calendars inspired by ActionView's FormBuilder.}
14 | s.license = "MIT"
15 |
16 | s.rubyforge_project = "table_builder"
17 |
18 | s.files = Dir["{lib,test}/**/*", "[A-Z]*", "init.rb"] - ["Gemfile.lock"]
19 | s.test_files = Dir["test/**/*"]
20 | s.require_paths = ["lib"]
21 |
22 | # specify any dependencies here; for example:
23 | # s.add_development_dependency "rspec"
24 | # s.add_runtime_dependency "rest-client"
25 | s.add_development_dependency "rake"
26 | s.add_development_dependency "test-unit"
27 | s.add_development_dependency "activesupport"
28 | s.add_development_dependency "actionpack"
29 | end
30 |
--------------------------------------------------------------------------------
/lib/table_builder/table_builder.rb:
--------------------------------------------------------------------------------
1 | module TableHelper
2 |
3 | def table_for(objects, *args)
4 | raise ArgumentError, "Missing block" unless block_given?
5 | options = args.last.is_a?(Hash) ? args.pop : {}
6 | html_options = options[:html]
7 | builder = options[:builder] || TableBuilder
8 |
9 | content_tag(:table, html_options) do
10 | yield builder.new(objects || [], self, options)
11 | end
12 | end
13 |
14 | class TableBuilder
15 | include ::ActionView::Helpers::TagHelper
16 |
17 | def initialize(objects, template, options)
18 | raise ArgumentError, "TableBuilder expects an Enumerable object but found #{objects.inspect}" unless objects.respond_to? :each
19 | @objects, @template, @options = objects, template, options
20 | end
21 |
22 | def head(*args)
23 | if block_given?
24 | concat(tag(:thead, options_from_hash(args), true))
25 | yield
26 | concat('')
27 | else
28 | @num_of_columns = args.size
29 | content_tag(:thead,
30 | content_tag(:tr,
31 | args.collect { |c| content_tag(:th, c.html_safe)}.join('').html_safe
32 | )
33 | )
34 | end
35 | end
36 |
37 | def head_r(*args)
38 | raise ArgumentError, "Missing block" unless block_given?
39 | options = options_from_hash(args)
40 | head do
41 | concat(tag(:tr, options, true))
42 | yield
43 | concat('')
44 | end
45 | end
46 |
47 | def body(*args)
48 | raise ArgumentError, "Missing block" unless block_given?
49 | options = options_from_hash(args)
50 | tbody do
51 | @objects.each { |c| yield(c) }
52 | end
53 | end
54 |
55 | def body_r(*args)
56 | raise ArgumentError, "Missing block" unless block_given?
57 | options = options_from_hash(args)
58 | tbody do
59 | @objects.each { |c|
60 | concat(tag(:tr, options, true))
61 | yield(c)
62 | concat(''.html_safe)
63 | }
64 | end
65 | end
66 |
67 | def r(*args)
68 | raise ArgumentError, "Missing block" unless block_given?
69 | options = options_from_hash(args)
70 | tr(options) do
71 | yield
72 | end
73 | end
74 |
75 | def h(*args)
76 | if block_given?
77 | concat(tag(:th, options_from_hash(args), true))
78 | yield
79 | concat('')
80 | else
81 | content = args.shift
82 | content_tag(:th, content, options_from_hash(args))
83 | end
84 | end
85 |
86 | def d(*args)
87 | if block_given?
88 | concat(tag(:td, options_from_hash(args), true))
89 | yield
90 | concat('')
91 | else
92 | content = args.shift
93 | content_tag(:td, content, options_from_hash(args))
94 | end
95 | end
96 |
97 |
98 | private
99 |
100 | def options_from_hash(args)
101 | args.last.is_a?(Hash) ? args.pop : {}
102 | end
103 |
104 | def concat(tag)
105 | @template.safe_concat(tag)
106 | ""
107 | end
108 |
109 | def content_tag(tag, content, *args)
110 | options = options_from_hash(args)
111 | @template.content_tag(tag, content, options)
112 | end
113 |
114 | def tbody
115 | concat('
')
116 | yield
117 | concat('')
118 | end
119 |
120 | def tr options
121 | concat(tag(:tr, options, true))
122 | yield
123 | concat('')
124 | end
125 | end
126 | end
127 |
--------------------------------------------------------------------------------
/test/table_builder_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__) + '/test_helper.rb')
2 |
3 | class TableBuilderTest < ActionView::TestCase
4 | include ActionView::Helpers::TextHelper
5 | include ActionView::Helpers::TagHelper
6 | include TableHelper
7 | attr_accessor :output_buffer
8 |
9 | def setup
10 | @drummer1 = Drummer.new(1, 'John "Stumpy" Pepys')
11 | @drummer2 = Drummer.new(2, 'Eric "Stumpy Joe" Childs')
12 | @drummer3 = Drummer.new(3, 'Peter "James" Bond')
13 | @drummer4 = Drummer.new(4, 'Mick Shrimpton (R. J. "Ric" Parnell)')
14 | end
15 |
16 | def test_table_for
17 | output = table_for([], :html => { :id => 'id', :style => 'style', :class => 'class'}) do |t|
18 | end
19 | expected = %()
21 | assert_dom_equal expected, output
22 | end
23 |
24 | def test_table_for_without_an_array_raises_error
25 | assert_raises(ArgumentError) do
26 | table_for('a') {|t| }
27 | end
28 | end
29 |
30 | def test_head
31 | output = table_for([]) do |t|
32 | t.head do
33 | t.r do
34 | output_buffer.concat t.h('Id')
35 | output_buffer.concat t.h('Name')
36 | end
37 | end
38 | end
39 | expected = %() <<
40 | %() <<
41 | %() <<
42 | %(| Id | ) <<
43 | %(Name | ) <<
44 | %(
) <<
45 | %() <<
46 | %(
)
47 | assert_dom_equal expected, output
48 | end
49 |
50 | def test_head_r
51 | output = table_for([]) do |t|
52 | t.head_r do
53 | output_buffer.concat t.h('Id')
54 | output_buffer.concat t.h('Name')
55 | end
56 | end
57 | expected = %() <<
58 | %() <<
59 | %() <<
60 | %(| Id | ) <<
61 | %(Name | ) <<
62 | %(
) <<
63 | %() <<
64 | %(
)
65 | assert_dom_equal expected, output
66 | end
67 |
68 | def test_head_with_array
69 | output = table_for([@drummer1, @drummer2]) do |t|
70 | concat t.head('Id', 'Name')
71 | end
72 | expected = %() <<
73 | %() <<
74 | %() <<
75 | %(| Id | ) <<
76 | %(Name | ) <<
77 | %(
) <<
78 | %() <<
79 | %(
)
80 | assert_dom_equal expected, output
81 | end
82 |
83 | def test_body
84 | output = table_for([@drummer3, @drummer4]) do |t|
85 | t.body do |e|
86 | t.r do
87 | concat t.d(e.id)
88 | concat t.d(e.name)
89 | end
90 | end
91 | end
92 | expected = %() <<
93 | %() <<
94 | %() <<
95 | %(| 3 | ) <<
96 | %(Peter "James" Bond | ) <<
97 | %(
) <<
98 | %() <<
99 | %(| 4 | ) <<
100 | %(Mick Shrimpton (R. J. "Ric" Parnell) | ) <<
101 | %(
) <<
102 | %() <<
103 | %(
)
104 | assert_dom_equal expected, output
105 | end
106 |
107 | def test_body_r
108 | output = table_for([@drummer3, @drummer4]) do |t|
109 | t.body_r do |e|
110 | concat t.d(e.id)
111 | concat t.d(e.name)
112 | end
113 | end
114 | expected = %() <<
115 | %() <<
116 | %() <<
117 | %(| 3 | ) <<
118 | %(Peter "James" Bond | ) <<
119 | %(
) <<
120 | %() <<
121 | %(| 4 | ) <<
122 | %(Mick Shrimpton (R. J. "Ric" Parnell) | ) <<
123 | %(
) <<
124 | %() <<
125 | %(
)
126 | assert_dom_equal expected, output
127 | end
128 |
129 | def test_td_with_options
130 | output = table_for([@drummer1]) do |t|
131 | t.body_r do |e|
132 | output_buffer.concat t.d(e.name, :class => 'class')
133 | end
134 | end
135 | expected = %() <<
136 | %() <<
137 | %() <<
138 | %(| John "Stumpy" Pepys | ) <<
139 | %(
) <<
140 | %() <<
141 | %(
)
142 | assert_dom_equal expected, output
143 | end
144 |
145 | def test_td_with_block
146 | output = table_for([@drummer1]) do |t|
147 | t.body_r do |e|
148 | t.d do
149 | concat 'content'
150 | end
151 | end
152 | end
153 | expected = %() <<
154 | %() <<
155 | %() <<
156 | %(| content | ) <<
157 | %(
) <<
158 | %() <<
159 | %(
)
160 | assert_dom_equal expected, output
161 | end
162 |
163 | def test_td_with_block_and_options
164 | output = table_for([@drummer1]) do |t|
165 | t.body_r do |e|
166 | t.d(:class => 'class') do
167 | concat 'content'
168 | end
169 | end
170 | end
171 | expected = %() <<
172 | %() <<
173 | %() <<
174 | %(| content | ) <<
175 | %(
) <<
176 | %() <<
177 | %(
)
178 | assert_dom_equal expected, output
179 | end
180 |
181 | end
182 |
183 | class Drummer < Struct.new(:id, :name); end
184 |
--------------------------------------------------------------------------------
/lib/table_builder/calendar_helper.rb:
--------------------------------------------------------------------------------
1 | module CalendarHelper
2 | # Generates a calendar (as a table) for an array of objects placing each of them on the corresponding date.
3 | #
4 | # **TODO: fully document this method, the current documentation is far from done.**
5 | #
6 | # @param [Hash] options extra options
7 | #
8 | # :row_header if true, each row will have an extra cell at the beginning, as a row header. A typical usage would be
9 | # to output week numbers. When the block is called, it will get the date that would normally be passed to the
10 | # first day of the week (to give you some context) and a nil list of objects (and that's how you recognize it as
11 | # a header, because empty days get an empty array, not nil).
12 | def calendar_for(objects, *args)
13 | raise ArgumentError, "Missing block" unless block_given?
14 | options = args.last.is_a?(Hash) ? args.pop : {}
15 | html_options = options[:html]
16 | builder = options[:builder] || CalendarBuilder
17 | calendar = options[:calendar] || Calendar
18 | content_tag(:table, nil, html_options) do
19 | yield builder.new(objects || [], self, calendar, options)
20 | end
21 | end
22 |
23 | class CalendarBuilder < TableHelper::TableBuilder
24 | def initialize(objects, template, calendar, options)
25 | super(objects, template, options)
26 | @calendar = calendar.new(options)
27 | @today = options[:today] || Time.now
28 | @row_header = options[:row_header] || false
29 | end
30 |
31 | def day(*args)
32 | raise ArgumentError, "Missing block" unless block_given?
33 | options = options_from_hash(args)
34 | day_method = options.delete(:day_method) || :date
35 | id_pattern = options.delete(:id)
36 | tbody do
37 | @calendar.objects_for_days(@objects, day_method).to_a.sort{|a1, a2| a1.first <=> a2.first }.each do |o|
38 | key, array = o
39 | day, objects = array
40 | concat(tag(:tr, options, true)) if(day.wday == @calendar.first_weekday)
41 | if @row_header && day.wday == @calendar.first_weekday
42 | row_header_options = td_options(day, id_pattern)
43 | row_header_options[:class] ||= ""
44 | row_header_options[:class] << " row_header"
45 | concat(tag(:td, row_header_options, true))
46 | yield(day, nil)
47 | concat("")
48 | end
49 | concat(tag(:td, td_options(day, id_pattern), true))
50 | yield(day, objects)
51 | concat('')
52 | concat('') if(day.wday == @calendar.last_weekday)
53 | end
54 | end
55 | end
56 |
57 | private
58 |
59 | def objects_for_days
60 | @calendar.objects_for_days(@objects)
61 | end
62 |
63 | def td_options(day, id_pattern)
64 | options = {}
65 | css_classes = []
66 | css_classes << 'today' if day.strftime("%Y-%m-%d") == @today.strftime("%Y-%m-%d")
67 | css_classes << 'notmonth' if day.month != @calendar.month
68 | css_classes << 'weekend' if day.wday == 0 or day.wday == 6
69 | css_classes << 'future' if day > @today.to_date
70 | options[:class] = css_classes.join(' ') unless css_classes.empty?
71 | options[:id] = day.strftime(id_pattern) if id_pattern
72 | options
73 | end
74 |
75 | end
76 |
77 | class Calendar
78 | attr_accessor :first_weekday, :last_weekday, :month
79 |
80 | # :first lets you set the first day to start the calendar on (default is the first day of the given :month and :year).
81 | # :first => :today will use Date.today
82 | # :last lets you set the last day of the calendar (default is the last day of the given :month and :year).
83 | # :last => :thirty will show 30 days from :first
84 | # :last => :week will show one week
85 | def initialize(options={})
86 | @year = options[:year] || Time.now.year
87 | @month = options[:month] || Time.now.month
88 | @first_day_of_week = options[:first_day_of_week] || 0
89 | @first_weekday = first_day_of_week(@first_day_of_week)
90 | @last_weekday = last_day_of_week(@first_day_of_week)
91 |
92 | @first = options[:first]==:today ? Date.today : options[:first] || Date.civil(@year, @month, 1)
93 |
94 | if options[:last] == :thirty_days || options[:last] == :thirty
95 | @last = @first + 30
96 | elsif options[:last] == :one_week || options[:last] == :week
97 | @last = @first
98 | else
99 | @last = options[:last] || Date.civil(@year, @month, -1)
100 | end
101 |
102 | end
103 |
104 | def each_day
105 | first_day.upto(last_day) do |day|
106 | yield(day)
107 | end
108 | end
109 |
110 | def last_day
111 | last = @last
112 | while(last.wday % 7 != @last_weekday % 7)
113 | last = last.next
114 | end
115 | last
116 | end
117 |
118 | def first_day
119 | first = @first - 6
120 | while(first.wday % 7 != (@first_weekday) % 7)
121 | first = first.next
122 | end
123 | first
124 | end
125 |
126 | def objects_for_days(objects, day_method)
127 | unless @objects_for_days
128 | @objects_for_days = {}
129 | days.each{|day| @objects_for_days[day.strftime("%Y-%m-%d")] = [day, []]}
130 | objects.each do |o|
131 | date = o.send(day_method.to_sym).strftime("%Y-%m-%d")
132 | if @objects_for_days[date]
133 | @objects_for_days[date][1] << o
134 | end
135 | end
136 | end
137 | @objects_for_days
138 | end
139 |
140 | def days
141 | unless @days
142 | @days = []
143 | each_day{|day| @days << day}
144 | end
145 | @days
146 | end
147 |
148 | def mjdays
149 | unless @mjdays
150 | @mdays = []
151 | each_day{|day| @days << day}
152 | end
153 | @days
154 | end
155 |
156 | def first_day_of_week(day)
157 | day
158 | end
159 |
160 | def last_day_of_week(day)
161 | if day > 0
162 | day - 1
163 | else
164 | 6
165 | end
166 | end
167 | end
168 |
169 | end
170 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/watu/table_builder)
2 | [](https://coveralls.io/r/watu/table_builder)
3 | [](https://codeclimate.com/github/watu/table_builder)
4 | [](http://badge.fury.io/rb/watu_table_builder)
5 |
6 | About watu_table_builder
7 | ========================
8 |
9 | watu_table_builder is a fork of [table_builder](https://github.com/jchunky/table_builder) in an effort to bring it up to
10 | speed with the current Ruby and Rails practices (bundler, gem, ci) as well as maybe re-vive it, start merging useful
11 | branches, implementing new features, fixing bugs, etc.
12 |
13 | Install
14 | =======
15 |
16 | Add this to your Gemfile:
17 |
18 | gem "watu_table_builder", :require => "table_builder"
19 |
20 | or if you prefer to use it straight from GitHub:
21 |
22 | gem "watu_table_builder", :require => "table_builder", :git => "git://github.com/watu/table_builder.git"
23 |
24 | TableBuilder
25 | ============
26 |
27 | Rails builder for creating tables and calendars inspired by ActionView's FormBuilder, updated for Rails 3.0beta
28 | This is a fork of Petrik de Heus plugin for earlier versions of Rails. Note the new idiomatic use of "<%=" for the
29 | table_for and calendar_for functions.
30 |
31 | Examples
32 | ========
33 |
34 | table_for has methods for each tag used in a table (table, thead, tr, td, etc.)
35 |
36 | A basic example would look like this:
37 |
38 | @front_men = [FrontMan.new(1, 'David St. Hubbins'), FrontMan.new(2, 'David Lee Roth')]
39 |
40 | and
41 |
42 | <%= table_for(@front_men) do |t| %>
43 | <%= t.head do %>
44 | <%= t.r do %>
45 | <%= t.h('Id') %>
46 | <%= t.h('Name') %>
47 | <% end %>
48 | <% end %>
49 | <%= t.body do |front_man| %>
50 | <%= t.r do %>
51 | <%= t.d(h(front_man.id)) %>
52 | <%= t.d(h(front_man.name)) %>
53 | <% end %>
54 | <% end %>
55 | <% end %>
56 |
57 | You can pass an array to the head method:
58 |
59 | <%= t.head('Id', 'Name') %>
60 |
61 | The body and r method can be combined for easier usage:
62 |
63 | <%= t.body_r do |front_man| %>
64 | <%= t.d(h(front_man.id)) %>
65 | <%= t.d(h(front_man.name)) %>
66 | <% end %>
67 |
68 | You can also pass blocks to the d and h methods for more flexibility:
69 |
70 |
71 | <%= t.d(:class => 'name') do %>
72 | <%= link_to(h(front_man.name), front_man_url(front_man)) %>
73 | <% end %>
74 |
75 | All tag methods are rails tag methods, so they can have extra html options.
76 |
77 | @drummers = [Drummer.new(1, 'John "Stumpy" Pepys'), Drummer.new(2, 'Eric "Stumpy Joe" Childs')]
78 |
79 | and
80 |
81 | <%= table_for(@drummers, :html => { :id => 'spinal_tap', :class => 'drummers'}) do |t| %>
82 | <%= t.body_r(:class => 'row') do |e| %>
83 | <%= t.d(h(e.id), :title => 'id') %>
84 | <%= t.d(h(e.name)) %>
85 | <% end %>
86 | <% end %>
87 |
88 | which produces the following html:
89 |
90 |
91 |
92 |
93 | | 1 |
94 | John "Stumpy" Pepys |
95 |
96 |
97 | | 2 |
98 | Eric "Stumpy Joe" Childs |
99 |
100 |
101 |
102 |
103 |
104 | You can customize the table by creating your own TableBuilder:
105 |
106 | <%= table_for(@drummers, :builder => PagedTableBuilder) do |t| %>
107 |
108 | Calendar Table
109 | ==============
110 |
111 | calendar_for creates a table like table_for.
112 | All objects get sorted per day of the month
113 |
114 | A basic example would look like this:
115 |
116 | @tasks = Task.this_month
117 |
118 | and
119 |
120 | <%= calendar_for(@tasks) do |t| %>
121 | <%= t.head('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun') %>
122 | <%= t.day do |day, tasks| %>
123 | <%= day.day %>
124 | <% tasks.each do |task| %>
125 | <%= h(task.name) %>
126 | <% end %>
127 | <% end %>
128 | <% end %>
129 |
130 | To show a different month you can pass the :year and :month options:
131 |
132 | <%= calendar_for(@tasks, :year => 2009, :month => 1) do |t| %>
133 |
134 | To highlight a different day you can pass the :today option:
135 |
136 | <%= calendar_for(@tasks, :today => Date.civil(2008, 12, 26)) do |t| %>
137 |
138 | By default the :date method is called on the objects for sorting.
139 | To use another method you can pass the :day_method option:
140 |
141 | <%= t.day(:day_method => :calendar_date) do |day, tasks| %>
142 |
143 | If you want to add id's to your td tag you can pass a pattern:
144 |
145 | <%= t.day(:id => 'day_%d') do |day, tasks| %>
146 |
147 | To have a header at the begining of each row:
148 |
149 | <%= calendar_for(@tasks, :row_header => true) do |t| %>
150 |
151 | and then in your block you get nil as the list of objects and the first day of thet upcoming week. For example:
152 |
153 | <%= calendar_for(@tasks) do |t| %>
154 | <%= t.day do |day, tasks| %>
155 | <% if tasks.nil? %>
156 | <%= day.cweek %>
157 | <% else %>
158 | <%= day.day %>
159 | <% tasks.each do |task| %>
160 | <%= h(task.name) %>
161 | <% end %>
162 | <% end %>
163 | <% end %>
164 | <% end %>
165 |
166 | Contributing
167 | ============
168 |
169 | Document any new options and verify the documentation looks correct by running:
170 |
171 | yard server --reload
172 |
173 | and going to http://localhost:8808
174 |
175 | Contributors
176 | ============
177 |
178 | Petrik de Heus, Sean Dague, F. Kocherga, John Duff, Andrew C. Greenberg, Jason Cheong-Kee-You, [J. Pablo Fernández](http://pupeno.com).
179 |
180 | Original Work Copyright (c) 2008 Petrik de Heus, released under the MIT license.
181 |
182 | Fork revisions Copyright (c) 2010 Andrew C. Greenberg, released under the MIT license.
183 |
184 | Fork revisions Copyright (c) 2012 [Carrousel Apps Ltd (Watu)](http://watuhq.com), released under the MIT license.
185 |
--------------------------------------------------------------------------------
/test/calendar_helper_test.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__) + '/test_helper.rb')
2 |
3 | class CalendarHelperTest < ActionView::TestCase
4 | include ActionView::Helpers::TextHelper
5 | include ActionView::Helpers::TagHelper
6 | include CalendarHelper
7 | attr_accessor :output_buffer
8 |
9 | def setup
10 | @events = [Event.new(3, 'Jimmy Page', Date.civil(2008, 12, 26)),
11 | Event.new(4, 'Robert Plant', Date.civil(2008, 12, 26))]
12 | end
13 |
14 | def test_calendar_for
15 | output = calendar_for(@events, :html => { :id => 'id', :style => 'style', :class => 'class'}) do |t|
16 | end
17 | expected = %()
19 | assert_dom_equal expected, output
20 | end
21 |
22 | def test_calendar_for_without_an_array
23 | self.output_buffer = ''
24 | assert_raises(ArgumentError) do
25 | calendar_for('a') {|t| }
26 | end
27 | end
28 |
29 | def test_calendar_for_with_empty_array
30 | output = calendar_for([], :year=> 2008, :month => 12) do |c|
31 | c.day do |day, events|
32 | concat(events.collect{|e| e.id}.join)
33 | end
34 | end
35 | expected = %() <<
36 | %() <<
37 | %( | | | | | | |
) <<
38 | %( | | | | | | |
) <<
39 | %( | | | | | | |
) <<
40 | %( | | | | | | |
) <<
41 | %( | | | | | | |
) <<
42 | %() <<
43 | %(
)
44 | assert_dom_equal expected, output
45 | end
46 |
47 | def test_calendar_for_with_events
48 | output = calendar_for(@events, :year=> 2008, :month => 12) do |c|
49 | c.day do |day, events|
50 | content = events.collect{|e| e.id}.join
51 | concat("(#{day.day})#{content}")
52 | end
53 | end
54 | expected = %() <<
55 | %() <<
56 | %(| (30) | (1) | (2) | (3) | (4) | (5) | (6) |
) <<
57 | %(| (7) | (8) | (9) | (10) | (11) | (12) | (13) |
) <<
58 | %(| (14) | (15) | (16) | (17) | (18) | (19) | (20) |
) <<
59 | %(| (21) | (22) | (23) | (24) | (25) | (26)34 | (27) |
) <<
60 | %(| (28) | (29) | (30) | (31) | (1) | (2) | (3) |
) <<
61 | %() <<
62 | %(
)
63 | assert_dom_equal expected, output
64 | end
65 |
66 | def test_calendar_for_sets_css_classes
67 | output = calendar_for([], :year=> 2008, :month => 12, :today => Date.civil(2008, 12, 15)) do |c|
68 | c.day do |day, events|
69 | concat(events.collect{|e| e.id}.join)
70 | end
71 | end
72 | expected = %() <<
73 | %() <<
74 | %( | | | | | | |
) <<
75 | %( | | | | | | |
) <<
76 | %( | | | | | | |
) <<
77 | %( | | | | | | |
) <<
78 | %( | | | | | | |
) <<
79 | %() <<
80 | %(
)
81 | assert_dom_equal expected, output
82 | end
83 |
84 | def test_calendar_for_thirty_days
85 | today = Date.civil(2008, 12, 15)
86 | output = calendar_for([], :today => today, :year=>2008, :month=>12, :first=>today, :last=>:thirty_days) do |c|
87 | c.day do |day, events|
88 | concat(events.collect{|e| e.id}.join)
89 | end
90 | end
91 | expected = %() <<
92 | %() <<
93 | %( | | | | | | |
) <<
94 | %( | | | | | | |
) <<
95 | %( | | | | | | |
) <<
96 | %( | | | | | | |
) <<
97 | %( | | | | | | |
) <<
98 | %() <<
99 | %(
)
100 | assert_dom_equal expected, output
101 | end
102 |
103 | def test_calendar_for_week
104 | today = Date.civil(2008, 12, 15)
105 | output = calendar_for([], :today => today, :year=>2008, :month=>12, :first=>today, :last=>:week) do |c|
106 | c.day do |day, events|
107 | concat(events.collect{|e| e.id}.join)
108 | end
109 | end
110 | expected = %() <<
111 | %() <<
112 | %( | | | | | | |
) <<
113 | %() <<
114 | %(
)
115 | assert_dom_equal expected, output
116 | end
117 |
118 | def test_calendar_for_sets_css_ids
119 | output = calendar_for([], :year=> 2008, :month => 12, :today => Date.civil(2008, 12, 15)) do |c|
120 | c.day(:id => 'day_%d') do |day, events|
121 | concat(events.collect{|e| e.id}.join)
122 | end
123 | end
124 | expected = %() <<
125 | %() <<
126 | %( | | | | | | |
) <<
127 | %( | | | | | | |
) <<
128 | %( | | | | | | |
) <<
129 | %( | | | | | | |
) <<
130 | %( | | | | | | |
) <<
131 | %() <<
132 | %(
)
133 | assert_dom_equal expected, output
134 | end
135 |
136 | def test_calendar_for_with_row_headers
137 | output = calendar_for([], :year=> 2008, :month => 12, :row_header => true) do |c|
138 | c.day do |day, events|
139 | if events.nil?
140 | concat(day.cweek)
141 | else
142 | concat(events.collect{|e| e.id}.join)
143 | end
144 | end
145 | end
146 | expected = %() <<
147 | %() <<
148 | %( | | | | | | |
) <<
149 | %( | | | | | | |
) <<
150 | %( | | | | | | |
) <<
151 | %( | | | | | | |
) <<
152 | %( | | | | | | |
) <<
153 | %() <<
154 | %(
)
155 | assert_dom_equal expected, output
156 | end
157 |
158 | def test_calendar_for_with_enumerable_object
159 | output = calendar_for(Wrapped.new(@events), :year=> 2008, :month => 12) do |c|
160 | c.day do |day, events|
161 | content = events.collect{|e| e.id}.join
162 | concat("(#{day.day})#{content}")
163 | end
164 | end
165 | expected = %() <<
166 | %() <<
167 | %(| (30) | (1) | (2) | (3) | (4) | (5) | (6) |
) <<
168 | %(| (7) | (8) | (9) | (10) | (11) | (12) | (13) |
) <<
169 | %(| (14) | (15) | (16) | (17) | (18) | (19) | (20) |
) <<
170 | %(| (21) | (22) | (23) | (24) | (25) | (26)34 | (27) |
) <<
171 | %(| (28) | (29) | (30) | (31) | (1) | (2) | (3) |
) <<
172 | %() <<
173 | %(
)
174 | assert_dom_equal expected, output
175 | end
176 |
177 | end
178 |
179 | class CalendarHelperTest < ActionView::TestCase
180 |
181 | def setup
182 | @events = [Event.new(3, 'Jimmy Page', Date.civil(2008, 12, 26)),
183 | Event.new(4, 'Robert Plant', Date.civil(2008, 12, 26))]
184 | end
185 |
186 | def test_objects_for_days_with_events
187 | calendar = CalendarHelper::Calendar.new(:year=> 2008, :month => 12)
188 | objects_for_days = {}
189 | Date.civil(2008, 11, 30).upto(Date.civil(2009, 1, 3)){|day| objects_for_days[day.strftime("%Y-%m-%d")] = [day, []]}
190 | objects_for_days['2008-12-26'][1] = @events
191 | assert_equal objects_for_days, calendar.objects_for_days(@events, :date)
192 | end
193 |
194 | def test_objects_for_days
195 | calendar = CalendarHelper::Calendar.new(:year=> 2008, :month => 12)
196 | objects_for_days = {}
197 | Date.civil(2008, 11, 30).upto(Date.civil(2009, 1, 3)){|day| objects_for_days[day.strftime("%Y-%m-%d")] = [day, []]}
198 | assert_equal objects_for_days, calendar.objects_for_days([], :date)
199 | end
200 |
201 | def test_days
202 | calendar = CalendarHelper::Calendar.new(:year=> 2008, :month => 12)
203 | days = []
204 | Date.civil(2008, 11, 30).upto(Date.civil(2009, 1, 3)){|day| days << day}
205 | assert_equal days, calendar.days
206 | end
207 |
208 | def test_days_with_first_day_of_week_set
209 | calendar = CalendarHelper::Calendar.new(:year=> 2008, :month => 12, :first_day_of_week => 1)
210 | days = []
211 | Date.civil(2008, 12, 1).upto(Date.civil(2009, 1, 4)){|day| days << day}
212 | assert_equal days, calendar.days
213 | end
214 |
215 | def test_first_day
216 | calendar = CalendarHelper::Calendar.new(:year=> 2008, :month => 12)
217 | assert_equal Date.civil(2008, 11, 30), calendar.first_day
218 | end
219 |
220 | def test_last_day
221 | calendar = CalendarHelper::Calendar.new(:year=> 2008, :month => 12)
222 | assert_equal Date.civil(2009, 1, 3), calendar.last_day
223 | end
224 |
225 | def test_last_day_with_first_day_of_week_set
226 | calendar = CalendarHelper::Calendar.new(:year=> 2008, :month => 12, :first_day_of_week => 1)
227 | assert_equal Date.civil(2009, 1, 4), calendar.last_day
228 | end
229 | end
230 |
231 | class Event < Struct.new(:id, :name, :date); end
232 |
233 | class Wrapped
234 | include Enumerable
235 | attr_accessor :objects
236 |
237 | def initialize(objects)
238 | @objects = objects
239 | end
240 |
241 | def each
242 | @objects.each { |item| yield item }
243 | end
244 |
245 | def <=>(other)
246 | @objects <=> other
247 | end
248 | end
249 |
--------------------------------------------------------------------------------