later_dude 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +13 -0
- data/MIT-LICENSE +20 -0
- data/README +142 -0
- data/Rakefile +10 -0
- data/VERSION +1 -0
- data/init.rb +2 -0
- data/lib/later_dude.rb +212 -0
- data/tasks/distribution.rb +22 -0
- data/tasks/documentation.rb +8 -0
- data/tasks/testing.rb +7 -0
- data/test/calendar_helper_test.rb +24 -0
- data/test/calendar_test.rb +255 -0
- data/test/test_helper.rb +5 -0
- metadata +66 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
2009/10/30
|
2
|
+
----------
|
3
|
+
- Introduced new :yield_surrounding_days option to yield surrounding days of other months to passed block.
|
4
|
+
|
5
|
+
2009/2/2
|
6
|
+
---------
|
7
|
+
- Introduced options to show and format next and previous month.
|
8
|
+
- Replaced option :header_month_format with :current_month to align it with :next_month and :previous_month.
|
9
|
+
- Removed some unused methods for month names.
|
10
|
+
|
11
|
+
2009/1/14
|
12
|
+
---------
|
13
|
+
First release
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Clemens Kofler
|
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.
|
data/README
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
LaterDude
|
2
|
+
=========
|
3
|
+
|
4
|
+
LaterDude is a small calendar helper plugin for Rails with i18n support.
|
5
|
+
|
6
|
+
It was heavily inspired by "Jeremy Voorhis'/Geoffrey Grosenbach's calendar_helper plugin":http://topfunky.net/svn/plugins/calendar_helper/. Here's what's different:
|
7
|
+
|
8
|
+
* LaterDude leverages the power of the "Rails i18n plugin":http://rails-i18n.org. This means that if you have Rails 2.2 or higher (or if you've installed the i18n gem and the plugin separately), you can just drop in locales and you'll get localized month and day names.
|
9
|
+
* Where the calendar_helper had one helper method that internally called multiple other private methods, LaterDude keeps the namespace clean by tucking away all of its functionality in a presenter (of sorts).
|
10
|
+
* Most CSS class names are given implictly, e.g. "day", "weekendDay" (both are given to the displayed month as well as to the previous and following month), "otherMonth" (all days that don't belong to the displayed month) and "today". The only CSS class that can be configured is the table's class (which defaults to "calendar"). Further customization can be taken care of by passing a block (see examples).
|
11
|
+
|
12
|
+
Installation
|
13
|
+
============
|
14
|
+
|
15
|
+
You can use LaterDude either as a gem (preferred) or as a Rails plugin.
|
16
|
+
|
17
|
+
To use the gem version, put the following gem requirement in your environment.rb:
|
18
|
+
|
19
|
+
config.gem "later_dude", :source => 'http://gemcutter.org'
|
20
|
+
|
21
|
+
To install it as a plugin, fire up your terminal, go to your Rails app and type:
|
22
|
+
|
23
|
+
$ ruby script/plugin install git://github.com/clemens/later_dude.git
|
24
|
+
|
25
|
+
Examples
|
26
|
+
========
|
27
|
+
|
28
|
+
There are two basic ways of outputting a calendar: via the presenter itself or by using the helper method:
|
29
|
+
|
30
|
+
<%= calendar_for(2009, 1) %> and
|
31
|
+
<%= LaterDude::Calendar.new(2009, 1).to_html %>
|
32
|
+
|
33
|
+
both yield the same results. This is similar to what Rails does with RedCloth/BlueCloth filters.
|
34
|
+
|
35
|
+
In addition to year and month which are required parameters you can optionally supply an options hash:
|
36
|
+
|
37
|
+
<%= calendar_for(2009, 1, :calendar_class => "my_calendar", :first_day_of_week => 1)
|
38
|
+
|
39
|
+
Possible options are:
|
40
|
+
|
41
|
+
* :calendar_class: The CSS class for the surrounding table. Defaults to "calendar".
|
42
|
+
* :first_day_of_week: The first day of the week (0 = Sunday, 1 = Monday etc.). Defaults to the :'date.first_day_of_week' translation in the respective locale or 0 if no translation can be found.
|
43
|
+
* :hide_day_names: Hide the table header showing day names. Defaults to false.
|
44
|
+
* :hide_month_name: Hide the table header showing the month name. Defaults to false.
|
45
|
+
* :use_full_day_names: Use full instead of abbreviated day names. Defaults to false.
|
46
|
+
* :use_full_month_names: Use full instead of abbreviated month names. Defaults to true.
|
47
|
+
* :yield_surrounding_days: Defines whether or not days or the previous and next month are yielded to the passed block. Defaults to false.
|
48
|
+
|
49
|
+
* :next_month: Defines if and how the next month should be displayed. See section "Formatting the header section" for further information.
|
50
|
+
* :previous_month: Defines if and how the previous month should be displayed. See section "Formatting the header section" for further information.
|
51
|
+
* :next_and_previous_month: Defines if and how the next and previous month should be displayed. See section "Formatting the header section" for further information.
|
52
|
+
* :current_month: Defines how the current month should be displayed. See section "Formatting the header section" for further information.
|
53
|
+
|
54
|
+
You can also pass in a block to mark days according to your own set of rules. The block gets passed each day of the current month (i.e. days of the previous and following month are *not* yielded):
|
55
|
+
|
56
|
+
<%= calendar_for(2009, 1) do |day|
|
57
|
+
if Calendar.has_events_on?(day)
|
58
|
+
[link_to(day.day, events_path(day.year, day.month, day.day)), { :class => "dayWithEvents" }]
|
59
|
+
else
|
60
|
+
day.day
|
61
|
+
end
|
62
|
+
end %>
|
63
|
+
|
64
|
+
The block can either return an array containing two elements or a single value. If an array is returned, the first element will be the content of the table cell and the second will be used as HTML options for the table cell tag. If a single value is returned, it will be used as the content of the table cell.
|
65
|
+
|
66
|
+
Hint: You can avoid cluttering up your views and move the block to a helper:
|
67
|
+
|
68
|
+
# app/helpers/calendar_helper.rb
|
69
|
+
def calendar_events_proc
|
70
|
+
lambda do |day|
|
71
|
+
if Calendar.has_events_on?(day)
|
72
|
+
[link_to(day.day, events_path(day.year, day.month, day.day)), { :class => "dayWithEvents" }]
|
73
|
+
else
|
74
|
+
day.day
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# app/views/calendar/show.html
|
80
|
+
<%= calendar_for(2009, 1, &calendar_events_proc)
|
81
|
+
|
82
|
+
Formatting the header section
|
83
|
+
=============================
|
84
|
+
|
85
|
+
You can customize the calendar's header section (i.e. the first table row) by using one or more of the following options:
|
86
|
+
* :next_month
|
87
|
+
* :previous_month
|
88
|
+
* :next_and_previous_month
|
89
|
+
* :current_month
|
90
|
+
|
91
|
+
All of these can either take a single value or an array of two values:
|
92
|
+
|
93
|
+
# simple string
|
94
|
+
:next_month => "»"
|
95
|
+
|
96
|
+
# strftime string
|
97
|
+
:next_month => "%b"
|
98
|
+
|
99
|
+
# proc - will evaluate the proc
|
100
|
+
:next_month => lambda { |date| link_to "»", calendar_path(date.year, month.year) }
|
101
|
+
|
102
|
+
# simple string and proc - will evaluate the proc and use it for link_to, e.g. link_to("»", calendar_path(date.year, month.year))
|
103
|
+
:next_month => ["»", lambda { |date| calendar_path(date.year, month.year) }]
|
104
|
+
|
105
|
+
# strftime string and proc - will evaluate the proc and use it for link_to, e.g. link_to("Jan", calendar_path(date.year, month.year))
|
106
|
+
:next_month => ["%b", lambda { |date| calendar_path(date.year, month.year) }]
|
107
|
+
|
108
|
+
If you use a proc it gets passed a Date object carrying the respective month, i.e. the proc for :previous_month gets passed a Date object representing the previous month etc.
|
109
|
+
|
110
|
+
You can do all kinds of mighty stuff with a proc. Imagine a situation where you want to show the abbreviated month name and then the number of events for the given month:
|
111
|
+
|
112
|
+
# depending on your routes, this outputs something like <a href="/calendar/2009/1">Jan (3 events)</a>
|
113
|
+
:next_month => lambda { |date| link_to I18n.localize(date, :format => "%b (#{pluralize(Event.in_month(date))})", calendar_path(date.year, date.month) }
|
114
|
+
|
115
|
+
The option :next_and_previous_month can be used as a shortcut if you want to use the same formatting for the next and previous month. Both, :next_month and :previous_month override the :next_and_previous_month if given.
|
116
|
+
|
117
|
+
i18n
|
118
|
+
====
|
119
|
+
|
120
|
+
You can define the following keys in your locale files to customize output:
|
121
|
+
|
122
|
+
* date.formats.calendar_header: Defines the date format to be used for the table header.
|
123
|
+
* date.first_day_of_week: Defines the first day of a week (0 = Sunday, 1 = Monday etc.).
|
124
|
+
|
125
|
+
Of course, you can also put other configuration options in the locale and then pass them in manually:
|
126
|
+
|
127
|
+
# somewhere in a locale
|
128
|
+
date:
|
129
|
+
calendar:
|
130
|
+
calendar_class: my_cool_calendar
|
131
|
+
|
132
|
+
# in the view
|
133
|
+
<%= calendar_for(2009, 1, :calendar_class => I18n.translate(:'date.calendar.calendar_class', :default => "my_calendar"))
|
134
|
+
|
135
|
+
Note that you should always pass in a default in case a translation can't be found since your options override the default options which might result in weird exceptions if the translation is missing.
|
136
|
+
|
137
|
+
Bugs & Feedback
|
138
|
+
===============
|
139
|
+
|
140
|
+
You can send me feedback, bug reports and patches via "GitHub":http://github.com/clemens.
|
141
|
+
|
142
|
+
Copyright (c) 2009 Clemens Kofler <clemens@railway.at>, released under the MIT license.
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.1
|
data/init.rb
ADDED
data/lib/later_dude.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
require 'action_view'
|
3
|
+
|
4
|
+
module LaterDude
|
5
|
+
module CalendarHelper
|
6
|
+
def calendar_for(year, month, options={}, &block)
|
7
|
+
Calendar.new(year, month, options, &block).to_html
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# TODO: Maybe make output prettier?
|
12
|
+
class Calendar
|
13
|
+
include ActionView::Helpers::TagHelper
|
14
|
+
include ActionView::Helpers::UrlHelper
|
15
|
+
|
16
|
+
def initialize(year, month, options={}, &block)
|
17
|
+
@year, @month = year, month
|
18
|
+
@options = options.symbolize_keys.reverse_merge(Calendar.default_calendar_options)
|
19
|
+
|
20
|
+
# next_month and previous_month take precedence over next_and_previous_month
|
21
|
+
@options[:next_month] ||= @options[:next_and_previous_month]
|
22
|
+
@options[:previous_month] ||= @options[:next_and_previous_month]
|
23
|
+
|
24
|
+
@days = Date.civil(@year, @month, 1)..Date.civil(@year, @month, -1)
|
25
|
+
@block = block
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_html
|
29
|
+
<<-EOF
|
30
|
+
<table class="#{@options[:calendar_class]}">
|
31
|
+
<thead>
|
32
|
+
#{show_month_names}
|
33
|
+
#{show_day_names}
|
34
|
+
</thead>
|
35
|
+
<tbody>
|
36
|
+
#{show_days}
|
37
|
+
</tbody>
|
38
|
+
</table>
|
39
|
+
EOF
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def show_days
|
44
|
+
"<tr>#{show_previous_month}#{show_current_month}#{show_following_month}</tr>"
|
45
|
+
end
|
46
|
+
|
47
|
+
def show_previous_month
|
48
|
+
return if @days.first.wday == first_day_of_week # don't display anything if the first day is the first day of a week
|
49
|
+
|
50
|
+
returning "" do |output|
|
51
|
+
beginning_of_week(@days.first).upto(@days.first - 1) { |d| output << show_day(d) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def show_current_month
|
56
|
+
returning "" do |output|
|
57
|
+
@days.first.upto(@days.last) { |d| output << show_day(d) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def show_following_month
|
62
|
+
return if @days.last.wday == last_day_of_week # don't display anything if the last day is the last day of a week
|
63
|
+
|
64
|
+
returning "" do |output|
|
65
|
+
(@days.last + 1).upto(beginning_of_week(@days.last + 1.week) - 1) { |d| output << show_day(d) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def show_day(day)
|
70
|
+
options = { :class => "day" }
|
71
|
+
options[:class] << " otherMonth" if day.month != @days.first.month
|
72
|
+
options[:class] << " weekend" if Calendar.weekend?(day)
|
73
|
+
options[:class] << " today" if day.today?
|
74
|
+
|
75
|
+
# block is only called for current month or if :yield_surrounding_days is set to true
|
76
|
+
if @block && (@options[:yield_surrounding_days] || day.month == @days.first.month)
|
77
|
+
content, options_from_block = Array(@block.call(day))
|
78
|
+
|
79
|
+
# passing options is optional
|
80
|
+
if options_from_block.is_a?(Hash)
|
81
|
+
options[:class] << " #{options_from_block.delete(:class)}" if options_from_block[:class]
|
82
|
+
options.merge!(options_from_block)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
content = day.day
|
86
|
+
end
|
87
|
+
|
88
|
+
returning content_tag(:td, content, options) do |output|
|
89
|
+
if day < @days.last && day.wday == last_day_of_week # opening and closing tag for the first and last week are included in #show_days
|
90
|
+
output << "</tr><tr>" # close table row at the end of a week and start a new one
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def beginning_of_week(day)
|
96
|
+
diff = day.wday - first_day_of_week
|
97
|
+
diff += 7 if first_day_of_week > day.wday # hackish ;-)
|
98
|
+
day - diff
|
99
|
+
end
|
100
|
+
|
101
|
+
def show_month_names
|
102
|
+
return if @options[:hide_month_name]
|
103
|
+
|
104
|
+
%(<tr class="month_names">
|
105
|
+
#{previous_month}#{current_month}#{next_month}
|
106
|
+
</tr>)
|
107
|
+
end
|
108
|
+
|
109
|
+
# @options[:previous_month] can either be a single value or an array containing two values. For a single value, the
|
110
|
+
# value can either be a strftime compatible string or a proc.
|
111
|
+
# For an array, the first value is considered to be a strftime compatible string and the second is considered to be
|
112
|
+
# a proc. If the second value is not a proc then it will be ignored.
|
113
|
+
def previous_month
|
114
|
+
return unless @options[:previous_month]
|
115
|
+
|
116
|
+
show_month(@days.first - 1.month, @options[:previous_month], :class => "previous")
|
117
|
+
end
|
118
|
+
|
119
|
+
# see previous_month
|
120
|
+
def next_month
|
121
|
+
return unless @options[:next_month]
|
122
|
+
|
123
|
+
show_month(@days.first + 1.month, @options[:next_month], :class => "next")
|
124
|
+
end
|
125
|
+
|
126
|
+
# see previous_month and next_month
|
127
|
+
def current_month
|
128
|
+
colspan = @options[:previous_month] || @options[:next_month] ? 3 : 7 # span across all 7 days if previous and next month aren't shown
|
129
|
+
|
130
|
+
show_month(@days.first, @options[:current_month], :colspan => colspan, :class => "current")
|
131
|
+
end
|
132
|
+
|
133
|
+
def show_month(month, format, options={})
|
134
|
+
options[:colspan] ||= 2
|
135
|
+
|
136
|
+
returning %(<th colspan="#{options[:colspan]}" class="#{options[:class]} #{Date::MONTHNAMES[month.month].downcase}">) do |output|
|
137
|
+
output << if format.kind_of?(Array) && format.size == 2
|
138
|
+
text = I18n.localize(month, :format => format.first.to_s)
|
139
|
+
format.last.respond_to?(:call) ? link_to(text, format.last.call(month)) : text
|
140
|
+
else
|
141
|
+
format.respond_to?(:call) ? format.call(month) : I18n.localize(month, :format => format.to_s)
|
142
|
+
end
|
143
|
+
output << '</th>'
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def day_names
|
148
|
+
@day_names ||= @options[:use_full_day_names] ? full_day_names : abbreviated_day_names
|
149
|
+
end
|
150
|
+
|
151
|
+
def full_day_names
|
152
|
+
@full_day_names ||= I18n.translate(:'date.day_names')
|
153
|
+
end
|
154
|
+
|
155
|
+
def abbreviated_day_names
|
156
|
+
@abbreviated_day_names ||= I18n.translate(:'date.abbr_day_names')
|
157
|
+
end
|
158
|
+
|
159
|
+
def show_day_names
|
160
|
+
return if @options[:hide_day_names]
|
161
|
+
|
162
|
+
returning '<tr class="day_names">' do |output|
|
163
|
+
apply_first_day_of_week(day_names).each do |day|
|
164
|
+
output << %(<th scope="col" class="#{Date::DAYNAMES[day_names.index(day)].downcase}">#{include_day_abbreviation(day)}</th>)
|
165
|
+
end
|
166
|
+
output << "</tr>"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# => <abbr title="Sunday">Sun</abbr>
|
171
|
+
def include_day_abbreviation(day)
|
172
|
+
return day if @options[:use_full_day_names]
|
173
|
+
|
174
|
+
%(<abbr title="#{full_day_names[abbreviated_day_names.index(day)]}">#{day}</abbr>)
|
175
|
+
end
|
176
|
+
|
177
|
+
def apply_first_day_of_week(day_names)
|
178
|
+
names = day_names.dup
|
179
|
+
first_day_of_week.times { names.push(names.shift) }
|
180
|
+
names
|
181
|
+
end
|
182
|
+
|
183
|
+
def first_day_of_week
|
184
|
+
@options[:first_day_of_week]
|
185
|
+
end
|
186
|
+
|
187
|
+
def last_day_of_week
|
188
|
+
@options[:first_day_of_week] > 0 ? @options[:first_day_of_week] - 1 : 6
|
189
|
+
end
|
190
|
+
|
191
|
+
class << self
|
192
|
+
def weekend?(day)
|
193
|
+
[0,6].include?(day.wday) # 0 = Sunday, 6 = Saturday
|
194
|
+
end
|
195
|
+
|
196
|
+
def default_calendar_options
|
197
|
+
{
|
198
|
+
:calendar_class => "calendar",
|
199
|
+
:first_day_of_week => I18n.translate(:'date.first_day_of_week', :default => "0").to_i,
|
200
|
+
:hide_day_names => false,
|
201
|
+
:hide_month_name => false,
|
202
|
+
:use_full_day_names => false,
|
203
|
+
:current_month => I18n.translate(:'date.formats.calendar_header', :default => "%B"),
|
204
|
+
:next_month => false,
|
205
|
+
:previous_month => false,
|
206
|
+
:next_and_previous_month => false,
|
207
|
+
:yield_surrounding_days => false
|
208
|
+
}
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |s|
|
4
|
+
s.name = "later_dude"
|
5
|
+
s.summary = "Small calendar helper plugin for Rails with i18n support"
|
6
|
+
s.email = "clemens@railway.at"
|
7
|
+
s.homepage = "http://github.com/clemens/later_dude"
|
8
|
+
s.description = "LaterDude is a small calendar helper plugin for Rails with i18n support."
|
9
|
+
s.authors = ["Clemens Kofler"]
|
10
|
+
s.files = FileList["CHANGELOG",
|
11
|
+
"init.rb",
|
12
|
+
"lib/later_dude.rb",
|
13
|
+
"MIT-LICENSE",
|
14
|
+
"Rakefile",
|
15
|
+
"README",
|
16
|
+
"tasks/**/*.rb",
|
17
|
+
"VERSION"]
|
18
|
+
s.test_files = FileList["test/**/*.rb"]
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
22
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
desc 'Generate documentation for the later_dude plugin.'
|
2
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
3
|
+
rdoc.rdoc_dir = 'rdoc'
|
4
|
+
rdoc.title = 'LaterDude'
|
5
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
6
|
+
rdoc.rdoc_files.include('README')
|
7
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
8
|
+
end
|
data/tasks/testing.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CalendarHelperTest < ActiveSupport::TestCase
|
4
|
+
include LaterDude::CalendarHelper
|
5
|
+
|
6
|
+
test "requires year and month" do
|
7
|
+
assert_raises(ArgumentError) { calendar_for }
|
8
|
+
assert_raises(ArgumentError) { calendar_for(2009) }
|
9
|
+
assert_nothing_raised { calendar_for(2009, 1) }
|
10
|
+
end
|
11
|
+
|
12
|
+
test "accepts optional options hash" do
|
13
|
+
options = { :calendar_class => "my_calendar", :first_day_of_week => 1 }
|
14
|
+
assert_nothing_raised { calendar_for(2009, 1, options) }
|
15
|
+
end
|
16
|
+
|
17
|
+
test "accepts optional block" do
|
18
|
+
options = { :calendar_class => "my_calendar", :first_day_of_week => 1 }
|
19
|
+
some_block = lambda { nil }
|
20
|
+
|
21
|
+
assert_nothing_raised { calendar_for(2009, 1, &some_block) }
|
22
|
+
assert_nothing_raised { calendar_for(2009, 1, options, &some_block) }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# TODO: figure out why I have to reference Calendar via its module ...
|
4
|
+
class CalendarTest < ActiveSupport::TestCase
|
5
|
+
# some constants for increased readability
|
6
|
+
FULL_DAY_NAMES = I18n.translate(:'date.day_names')
|
7
|
+
ABBR_DAY_NAMES = I18n.translate(:'date.abbr_day_names')
|
8
|
+
FULL_MONTH_NAMES = I18n.translate(:'date.month_names')
|
9
|
+
ABBR_MONTH_NAMES = I18n.translate(:'date.abbr_month_names')
|
10
|
+
|
11
|
+
test "has default options" do
|
12
|
+
# TODO improve this so that every call gets a fresh copy of the default options
|
13
|
+
default_calendar_options = LaterDude::Calendar.send(:default_calendar_options)
|
14
|
+
|
15
|
+
assert_kind_of Hash, default_calendar_options
|
16
|
+
|
17
|
+
assert_equal "calendar", default_calendar_options[:calendar_class]
|
18
|
+
|
19
|
+
[:hide_day_names, :hide_month_name, :use_full_day_names].each do |key|
|
20
|
+
assert !default_calendar_options[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
# default date format for header is to show the full month name if no translation is set in locale
|
24
|
+
assert_equal "%B", default_calendar_options[:current_month]
|
25
|
+
|
26
|
+
# next and previous month aren't shown by default
|
27
|
+
assert !default_calendar_options[:next_month]
|
28
|
+
assert !default_calendar_options[:previous_month]
|
29
|
+
assert !default_calendar_options[:next_and_previous_month]
|
30
|
+
|
31
|
+
# some options use i18n ...
|
32
|
+
I18n.stubs(:translate).with(:'date.first_day_of_week', :default => "0").then.returns("1")
|
33
|
+
I18n.stubs(:translate).with(:'date.formats.calendar_header', :default => "%B").then.returns("%B %Y")
|
34
|
+
|
35
|
+
# default first day of week is Sunday (= 0) if no translation is set in locale
|
36
|
+
assert_equal 0, default_calendar_options[:first_day_of_week]
|
37
|
+
# with default first day of week set in locale
|
38
|
+
assert_equal 1, (LaterDude::Calendar.send(:default_calendar_options)[:first_day_of_week]) # have to do this so that we don't use the cached version
|
39
|
+
|
40
|
+
# with default date format set in locale
|
41
|
+
assert_equal "%B %Y", (LaterDude::Calendar.send(:default_calendar_options)[:current_month])
|
42
|
+
end
|
43
|
+
|
44
|
+
# options
|
45
|
+
test "uses full day names" do
|
46
|
+
assert_equal FULL_DAY_NAMES, LaterDude::Calendar.new(2009, 1, :use_full_day_names => true).send(:day_names)
|
47
|
+
end
|
48
|
+
|
49
|
+
test "uses abbreviated day names" do
|
50
|
+
assert_equal ABBR_DAY_NAMES, LaterDude::Calendar.new(2009, 1).send(:day_names)
|
51
|
+
assert_equal ABBR_DAY_NAMES, LaterDude::Calendar.new(2009, 1, :use_full_day_names => false).send(:day_names)
|
52
|
+
end
|
53
|
+
|
54
|
+
test "doesn't show day names" do
|
55
|
+
assert_nil LaterDude::Calendar.new(2009, 1, :hide_day_names => true).send(:show_day_names)
|
56
|
+
end
|
57
|
+
|
58
|
+
# TODO I think this isn't needed anymore due to the new :header_date_format option
|
59
|
+
test "doesn't show month names" do
|
60
|
+
assert_nil LaterDude::Calendar.new(2009, 1, :hide_month_name => true).send(:show_month_names)
|
61
|
+
end
|
62
|
+
|
63
|
+
# links/texts for next, previous and current month
|
64
|
+
test "uses next month for a string" do
|
65
|
+
assert_match %r(»), LaterDude::Calendar.new(2009, 1, :next_month => "»").send(:next_month)
|
66
|
+
end
|
67
|
+
|
68
|
+
test "uses next month for a strftime string" do
|
69
|
+
assert_match %r(Feb), LaterDude::Calendar.new(2009, 1, :next_month => "%b").send(:next_month)
|
70
|
+
end
|
71
|
+
|
72
|
+
test "uses next month for proc" do
|
73
|
+
assert_match %r(<a href="/events/2009/2">»</a>), LaterDude::Calendar.new(2009, 1, :next_month => lambda { |date| link_to "»", "/events/#{date.year}/#{date.month}" }).send(:next_month)
|
74
|
+
end
|
75
|
+
|
76
|
+
test "uses next month for array if first value is a string and second is a proc" do
|
77
|
+
assert_match %r(<a href="/events/2009/2">»</a>), LaterDude::Calendar.new(2009, 1, :next_month => ["»", lambda { |date| "/events/#{date.year}/#{date.month}" }]).send(:next_month)
|
78
|
+
end
|
79
|
+
|
80
|
+
test "uses next month for array if first value is a strftime string and second is a proc" do
|
81
|
+
assert_match %r(<a href="/events/2009/2">Feb</a>), LaterDude::Calendar.new(2009, 1, :next_month => ["%b", lambda { |date| "/events/#{date.year}/#{date.month}" }]).send(:next_month)
|
82
|
+
end
|
83
|
+
|
84
|
+
test "uses previous month for a string" do
|
85
|
+
assert_match %r(«), LaterDude::Calendar.new(2009, 1, :previous_month => "«").send(:previous_month)
|
86
|
+
end
|
87
|
+
|
88
|
+
test "uses previous month for a strftime string" do
|
89
|
+
assert_match %r(Dec), LaterDude::Calendar.new(2009, 1, :previous_month => "%b").send(:previous_month)
|
90
|
+
end
|
91
|
+
|
92
|
+
test "uses previous month for proc" do
|
93
|
+
assert_match %r(<a href="/events/2008/12">«</a>), LaterDude::Calendar.new(2009, 1, :previous_month => lambda { |date| link_to "«", "/events/#{date.year}/#{date.month}" }).send(:previous_month)
|
94
|
+
end
|
95
|
+
|
96
|
+
test "uses previous month for array if first value is a string and second is a proc" do
|
97
|
+
assert_match %r(<a href="/events/2008/12">«</a>), LaterDude::Calendar.new(2009, 1, :previous_month => ["«", lambda { |date| "/events/#{date.year}/#{date.month}" }]).send(:previous_month)
|
98
|
+
end
|
99
|
+
|
100
|
+
test "uses previous month for array if first value is a strftime string and second is a proc" do
|
101
|
+
assert_match %r(<a href="/events/2008/12">Dec</a>), LaterDude::Calendar.new(2009, 1, :previous_month => ["%b", lambda { |date| "/events/#{date.year}/#{date.month}" }]).send(:previous_month)
|
102
|
+
end
|
103
|
+
|
104
|
+
test "uses next and previous month for array if first value is a strftime string and second is a proc" do
|
105
|
+
calendar = LaterDude::Calendar.new(2009, 1, :next_and_previous_month => ["%b", lambda { |date| "/events/#{date.year}/#{date.month}" }])
|
106
|
+
assert_match %r(<a href="/events/2008/12">Dec</a>), calendar.send(:previous_month)
|
107
|
+
assert_match %r(<a href="/events/2009/2">Feb</a>), calendar.send(:next_month)
|
108
|
+
end
|
109
|
+
|
110
|
+
test "uses next/previous month options rather than combined option if both are given" do
|
111
|
+
calendar = LaterDude::Calendar.new(2009, 1, :next_month => "»", :previous_month => "«", :next_and_previous_month => ["%b", lambda { |date| "/events/#{date.year}/#{date.month}" }])
|
112
|
+
assert_match %r(«), calendar.send(:previous_month)
|
113
|
+
assert_match %r(»), calendar.send(:next_month)
|
114
|
+
end
|
115
|
+
|
116
|
+
test "uses current month for a string" do
|
117
|
+
assert_match %r(Current), LaterDude::Calendar.new(2009, 1, :current_month => "Current").send(:current_month)
|
118
|
+
end
|
119
|
+
|
120
|
+
test "uses current month for a strftime string" do
|
121
|
+
assert_match %r(Jan), LaterDude::Calendar.new(2009, 1, :current_month => "%b").send(:current_month)
|
122
|
+
end
|
123
|
+
|
124
|
+
test "uses current month for proc" do
|
125
|
+
assert_match %r(<a href="/events/2009/1">Current</a>), LaterDude::Calendar.new(2009, 1, :current_month => lambda { |date| link_to "Current", "/events/#{date.year}/#{date.month}" }).send(:current_month)
|
126
|
+
end
|
127
|
+
|
128
|
+
test "uses current month for array if first value is a string and second is a proc" do
|
129
|
+
assert_match %r(<a href="/events/2009/1">Current</a>), LaterDude::Calendar.new(2009, 1, :current_month => ["Current", lambda { |date| "/events/#{date.year}/#{date.month}" }]).send(:current_month)
|
130
|
+
end
|
131
|
+
|
132
|
+
test "uses current month for array if first value is a strftime string and second is a proc" do
|
133
|
+
assert_match %r(<a href="/events/2009/1">Jan</a>), LaterDude::Calendar.new(2009, 1, :current_month => ["%b", lambda { |date| "/events/#{date.year}/#{date.month}" }]).send(:current_month)
|
134
|
+
end
|
135
|
+
|
136
|
+
# helper methods
|
137
|
+
test "shows whether a given day is on a weekend or not" do
|
138
|
+
[0, 6].each { |day| assert LaterDude::Calendar.weekend?(mock(:wday => day)) }
|
139
|
+
(1..5).each { |day| assert !LaterDude::Calendar.weekend?(mock(:wday => day)) }
|
140
|
+
end
|
141
|
+
|
142
|
+
test "includes day name abbreviation" do
|
143
|
+
assert_equal %q(<abbr title="Sunday">Sun</abbr>), LaterDude::Calendar.new(2009, 1, :use_full_day_names => false).send(:include_day_abbreviation, "Sun")
|
144
|
+
end
|
145
|
+
|
146
|
+
test "doesn't include day name abbreviation" do
|
147
|
+
assert_equal "Sunday", LaterDude::Calendar.new(2009, 1, :use_full_day_names => true).send(:include_day_abbreviation, "Sunday")
|
148
|
+
end
|
149
|
+
|
150
|
+
test "shows index of first and last day of week" do
|
151
|
+
assert_equal 0, LaterDude::Calendar.new(2009, 1).send(:first_day_of_week)
|
152
|
+
assert_equal 6, LaterDude::Calendar.new(2009, 1).send(:last_day_of_week)
|
153
|
+
|
154
|
+
assert_equal 1, LaterDude::Calendar.new(2009, 1, :first_day_of_week => 1).send(:first_day_of_week)
|
155
|
+
assert_equal 0, LaterDude::Calendar.new(2009, 1, :first_day_of_week => 1).send(:last_day_of_week)
|
156
|
+
end
|
157
|
+
|
158
|
+
test "applies first day of week accordingly" do
|
159
|
+
assert_equal %w(Mon Tue Wed Thu Fri Sat Sun), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 1).send(:apply_first_day_of_week, ABBR_DAY_NAMES)
|
160
|
+
end
|
161
|
+
|
162
|
+
test "returns the first day of the week for a given date" do
|
163
|
+
day = Date.civil(2009, 1, 4) # first Sunday in 2009
|
164
|
+
|
165
|
+
assert_equal Date.civil(2009, 1, 4), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 0).send(:beginning_of_week, day)
|
166
|
+
assert_equal Date.civil(2008, 12, 29), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 1).send(:beginning_of_week, day)
|
167
|
+
assert_equal Date.civil(2008, 12, 30), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 2).send(:beginning_of_week, day)
|
168
|
+
assert_equal Date.civil(2008, 12, 31), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 3).send(:beginning_of_week, day)
|
169
|
+
assert_equal Date.civil(2009, 1, 1), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 4).send(:beginning_of_week, day)
|
170
|
+
assert_equal Date.civil(2009, 1, 2), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 5).send(:beginning_of_week, day)
|
171
|
+
assert_equal Date.civil(2009, 1, 3), LaterDude::Calendar.new(2009, 1, :first_day_of_week => 6).send(:beginning_of_week, day)
|
172
|
+
end
|
173
|
+
|
174
|
+
# TODO: may consider to mock some of the behavior so I don't have to use concrete months that fit for a test
|
175
|
+
test "shows previous month if first day of month isn't the first day of a week" do
|
176
|
+
assert_not_nil LaterDude::Calendar.new(2009, 4).send(:show_previous_month) # April 1st is a Wednesday
|
177
|
+
end
|
178
|
+
|
179
|
+
test "shows following month if last day of month isn't the last day of a week" do
|
180
|
+
assert_not_nil LaterDude::Calendar.new(2009, 4).send(:show_following_month) # April 30th is a Thursday
|
181
|
+
end
|
182
|
+
|
183
|
+
test "shouldn't show previous month if first day of month is the first day of a week" do
|
184
|
+
assert_nil LaterDude::Calendar.new(2009, 2).send(:show_previous_month) # February 1st is a Sunday
|
185
|
+
end
|
186
|
+
|
187
|
+
test "shouldn't show following month if last day of month is the last day of a week" do
|
188
|
+
assert_nil LaterDude::Calendar.new(2009, 2).send(:show_following_month) # February 28th is a Saturday
|
189
|
+
end
|
190
|
+
|
191
|
+
test "highlights current day (= today)" do
|
192
|
+
Date.stubs(:current).then.returns(Date.civil(2009, 1, 14))
|
193
|
+
assert_match %r(<td class="([^\"]*)today([^\"]*)">14</td>), LaterDude::Calendar.new(2009, 1).to_html
|
194
|
+
end
|
195
|
+
|
196
|
+
test "shows special days as designated by a block" do
|
197
|
+
CalendarTest.send(:include, ActionView::Helpers)
|
198
|
+
|
199
|
+
# all even days should be linked
|
200
|
+
special_days_proc = lambda do |day|
|
201
|
+
if day.day.even?
|
202
|
+
[link_to(day.day, "/calendar/#{day.year}/#{day.month}/#{day.day}"), { :class => "specialDay" } ]
|
203
|
+
else
|
204
|
+
day.day
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
calendar_html = LaterDude::Calendar.new(2009, 1, &special_days_proc).to_html
|
209
|
+
|
210
|
+
(Date.civil(2009, 1, 1)..Date.civil(2009, 1, -1)).each do |day|
|
211
|
+
if day.day.even?
|
212
|
+
assert_match %r(<td class="day([^\"]*)specialDay"><a href="/calendar/#{day.year}/#{day.month}/#{day.day}">#{day.day}</a></td>), calendar_html
|
213
|
+
else
|
214
|
+
assert_match %r(<td class="day([^\"]*)">#{day.day}</td>), calendar_html
|
215
|
+
assert_no_match %r(<td class="day([^\"]*)specialDay"><a href="/calendar/#{day.year}/#{day.month}/#{day.day}">#{day.day}</a></td>), calendar_html
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
test "yields days of surrounding months :yield_surrounding_days is set to true" do
|
221
|
+
CalendarTest.send(:include, ActionView::Helpers)
|
222
|
+
|
223
|
+
# make it bold
|
224
|
+
special_days_proc = lambda { |day| "<b>#{day.day}</b>" }
|
225
|
+
|
226
|
+
calendar_html = LaterDude::Calendar.new(2009, 4, { :yield_surrounding_days => true }, &special_days_proc).to_html
|
227
|
+
|
228
|
+
# start of first week: 29 March 2009
|
229
|
+
# end of last week: 2 May 2009
|
230
|
+
surrounding_days = [Date.civil(2009, 3, 29), Date.civil(2009, 3, 30), Date.civil(2009, 3, 31), Date.civil(2009, 5, 1), Date.civil(2009, 5, 2)]
|
231
|
+
surrounding_days.each do |day|
|
232
|
+
assert_match %r(<td class="day([^\"]*)otherMonth([^\"]*)"><b>#{day.day}</b></td>), calendar_html
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
test "yields days of surrounding months :yield_surrounding_days isn't set to true" do
|
237
|
+
CalendarTest.send(:include, ActionView::Helpers)
|
238
|
+
|
239
|
+
# make it bold
|
240
|
+
special_days_proc = lambda { |day| "<b>#{day.day}</b>" }
|
241
|
+
|
242
|
+
calendar_html = LaterDude::Calendar.new(2009, 4, &special_days_proc).to_html
|
243
|
+
calendar_html2 = LaterDude::Calendar.new(2009, 4, { :yield_surrounding_days => false }, &special_days_proc).to_html
|
244
|
+
|
245
|
+
# start of first week: 29 March 2009
|
246
|
+
# end of last week: 2 May 2009
|
247
|
+
surrounding_days = [Date.civil(2009, 3, 29), Date.civil(2009, 3, 30), Date.civil(2009, 3, 31), Date.civil(2009, 5, 1), Date.civil(2009, 5, 2)]
|
248
|
+
surrounding_days.each do |day|
|
249
|
+
assert_no_match %r(<td class="day([^\"]*)otherMonth([^\"]*)"><b>#{day.day}</b></td>), calendar_html
|
250
|
+
assert_no_match %r(<td class="day([^\"]*)otherMonth([^\"]*)"><b>#{day.day}</b></td>), calendar_html2
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# TODO: Should I do "real" output testing despite the good coverage of output-related methods? Testing HTML is tedious ...
|
255
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: later_dude
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Clemens Kofler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-31 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: LaterDude is a small calendar helper plugin for Rails with i18n support.
|
17
|
+
email: clemens@railway.at
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- CHANGELOG
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- init.rb
|
31
|
+
- lib/later_dude.rb
|
32
|
+
- tasks/distribution.rb
|
33
|
+
- tasks/documentation.rb
|
34
|
+
- tasks/testing.rb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/clemens/later_dude
|
37
|
+
licenses: []
|
38
|
+
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options:
|
41
|
+
- --charset=UTF-8
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.3.5
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: Small calendar helper plugin for Rails with i18n support
|
63
|
+
test_files:
|
64
|
+
- test/calendar_helper_test.rb
|
65
|
+
- test/calendar_test.rb
|
66
|
+
- test/test_helper.rb
|