schedule_fu 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +34 -0
- data/Rakefile +40 -0
- data/app/models/calendar.rb +26 -0
- data/app/models/calendar_date.rb +76 -0
- data/app/models/calendar_event.rb +157 -0
- data/app/models/calendar_event_date.rb +8 -0
- data/app/models/calendar_event_mod.rb +8 -0
- data/app/models/calendar_event_type.rb +3 -0
- data/app/models/calendar_recurrence.rb +9 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20120121210741_add_schedule_fu_tables.rb +167 -0
- data/lib/schedule_fu.rb +8 -0
- data/lib/schedule_fu/calendar_helper.rb +247 -0
- data/lib/schedule_fu/engine.rb +5 -0
- data/lib/schedule_fu/finder.rb +16 -0
- data/lib/schedule_fu/parser.rb +108 -0
- data/lib/schedule_fu/schedule_fu_helper.rb +17 -0
- data/lib/schedule_fu/version.rb +3 -0
- data/lib/tasks/schedule_fu_tasks.rake +4 -0
- data/test/calendar_event_test.rb +229 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +56 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +9 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/db/migrate/20120121220057_add_schedule_fu_tables.schedule_fu.rb +168 -0
- data/test/dummy/db/schema.rb +82 -0
- data/test/dummy/log/development.log +283 -0
- data/test/dummy/log/test.log +2224 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/factories/calendar.rb +5 -0
- data/test/factories/calendar_event.rb +35 -0
- data/test/test_helper.rb +20 -0
- metadata +215 -0
data/lib/schedule_fu.rb
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
# CalendarHelper allows you to draw a databound calendar with fine-grained CSS formatting
|
4
|
+
module ScheduleFu
|
5
|
+
module CalendarHelper
|
6
|
+
|
7
|
+
# Returns an HTML calendar. In its simplest form, this method generates a plain
|
8
|
+
# calendar (which can then be customized using CSS) for a given month and year.
|
9
|
+
# However, this may be customized in a variety of ways -- changing the default CSS
|
10
|
+
# classes, generating the individual day entries yourself, and so on.
|
11
|
+
#
|
12
|
+
# The following options are required:
|
13
|
+
# :year # The year number to show the calendar for.
|
14
|
+
# :month # The month number to show the calendar for.
|
15
|
+
#
|
16
|
+
# The following are optional, available for customizing the default behaviour:
|
17
|
+
# :table_class => "calendar" # The class for the <table> tag.
|
18
|
+
# :month_name_class => "monthName" # The class for the name of the month, at the top of the table.
|
19
|
+
# :other_month_class => "otherMonth" # Not implemented yet.
|
20
|
+
# :day_name_class => "dayName" # The class is for the names of the weekdays, at the top.
|
21
|
+
# :day_class => "day" # The class for the individual day number cells.
|
22
|
+
# This may or may not be used if you specify a block (see below).
|
23
|
+
# :abbrev => (0..2) # This option specifies how the day names should be abbreviated.
|
24
|
+
# Use (0..2) for the first three letters, (0..0) for the first, and
|
25
|
+
# (0..-1) for the entire name.
|
26
|
+
# :first_day_of_week => 0 # Renders calendar starting on Sunday. Use 1 for Monday, and so on.
|
27
|
+
# :accessible => true # Turns on accessibility mode. This suffixes dates within the
|
28
|
+
# # calendar that are outside the range defined in the <caption> with
|
29
|
+
# # <span class="hidden"> MonthName</span>
|
30
|
+
# # Defaults to false.
|
31
|
+
# # You'll need to define an appropriate style in order to make this disappear.
|
32
|
+
# # Choose your own method of hiding content appropriately.
|
33
|
+
#
|
34
|
+
# :show_today => false # Highlights today on the calendar using the CSS class 'today'.
|
35
|
+
# # Defaults to true.
|
36
|
+
# :previous_month_text => nil # Displayed left of the month name if set
|
37
|
+
# :next_month_text => nil # Displayed right of the month name if set
|
38
|
+
# :month_name_array => Date::MONTHNAMES # Array of months
|
39
|
+
# :display_year => options[:year] # Year to display
|
40
|
+
#
|
41
|
+
# For more customization, you can pass a code block to this method, that will get one argument, a Date object,
|
42
|
+
# and return a values for the individual table cells. The block can return an array, [cell_text, cell_attrs],
|
43
|
+
# cell_text being the text that is displayed and cell_attrs a hash containing the attributes for the <td> tag
|
44
|
+
# (this can be used to change the <td>'s class for customization with CSS).
|
45
|
+
# This block can also return the cell_text only, in which case the <td>'s class defaults to the value given in
|
46
|
+
# +:day_class+. If the block returns nil, the default options are used.
|
47
|
+
#
|
48
|
+
# Example usage:
|
49
|
+
# calendar(:year => 2005, :month => 6) # This generates the simplest possible calendar.
|
50
|
+
# calendar({:year => 2005, :month => 6, :table_class => "calendar_helper"}) # This generates a calendar, as
|
51
|
+
# # before, but the <table>'s class
|
52
|
+
# # is set to "calendar_helper".
|
53
|
+
# calendar(:year => 2005, :month => 6, :abbrev => (0..-1)) # This generates a simple calendar but shows the
|
54
|
+
# # entire day name ("Sunday", "Monday", etc.) instead
|
55
|
+
# # of only the first three letters.
|
56
|
+
# calendar(:year => 2005, :month => 5) do |d| # This generates a simple calendar, but gives special days
|
57
|
+
# if listOfSpecialDays.include?(d) # (days that are in the array listOfSpecialDays) one CSS class,
|
58
|
+
# [d.mday, {:class => "specialDay"}] # "specialDay", and gives the rest of the days another CSS class,
|
59
|
+
# else # "normalDay". You can also use this highlight today differently
|
60
|
+
# [d.mday, {:class => "normalDay"}] # from the rest of the days, etc.
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# An additional 'weekend' class is applied to weekend days.
|
65
|
+
#
|
66
|
+
# For consistency with the themes provided in the calendar_styles generator, use "specialDay" as the CSS class for marked days.
|
67
|
+
#
|
68
|
+
def calendar(options = {}, &block)
|
69
|
+
raise(ArgumentError, "No year given") unless options.has_key?(:year)
|
70
|
+
raise(ArgumentError, "No month given") unless options.has_key?(:month)
|
71
|
+
|
72
|
+
block ||= Proc.new {|d| nil}
|
73
|
+
|
74
|
+
options = defaults(options).merge(options)
|
75
|
+
vars = setup_variables(options)
|
76
|
+
|
77
|
+
content_tag(:table, :class => options[:table_class], :border => 0,
|
78
|
+
:cellspacing => 0, :cellpadding => 0) do
|
79
|
+
text = calendar_head(options, vars).html_safe
|
80
|
+
text << calendar_body(options, vars, &block).html_safe
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def first_day_of_week(day)
|
87
|
+
day
|
88
|
+
end
|
89
|
+
|
90
|
+
def last_day_of_week(day)
|
91
|
+
if day > 0
|
92
|
+
day - 1
|
93
|
+
else
|
94
|
+
6
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def days_between(first, second)
|
99
|
+
if first > second
|
100
|
+
second + (7 - first)
|
101
|
+
else
|
102
|
+
second - first
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def beginning_of_week(date, start = 1)
|
107
|
+
days_to_beg = days_between(start, date.wday)
|
108
|
+
date - days_to_beg
|
109
|
+
end
|
110
|
+
|
111
|
+
def weekend?(date)
|
112
|
+
[0, 6].include?(date.wday)
|
113
|
+
end
|
114
|
+
|
115
|
+
def defaults(options)
|
116
|
+
{
|
117
|
+
:table_class => 'calendar',
|
118
|
+
:month_name_class => 'monthName',
|
119
|
+
:other_month_class => 'otherMonth',
|
120
|
+
:day_name_class => 'dayName',
|
121
|
+
:day_class => 'day',
|
122
|
+
:abbrev => (0..2),
|
123
|
+
:first_day_of_week => 0,
|
124
|
+
:accessible => false,
|
125
|
+
:show_today => true,
|
126
|
+
:previous_month_text => nil,
|
127
|
+
:next_month_text => nil,
|
128
|
+
:month_name_array => Date::MONTHNAMES,
|
129
|
+
:display_year => options[:year]
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
def setup_variables(options)
|
134
|
+
vars = {}
|
135
|
+
vars[:first] = Date.civil(options[:year], options[:month], 1)
|
136
|
+
vars[:last] = Date.civil(options[:year], options[:month], -1)
|
137
|
+
|
138
|
+
vars[:first_weekday] = first_day_of_week(options[:first_day_of_week])
|
139
|
+
vars[:last_weekday] = last_day_of_week(options[:first_day_of_week])
|
140
|
+
vars
|
141
|
+
end
|
142
|
+
|
143
|
+
def calendar_head(options, vars)
|
144
|
+
content_tag(:thead) do
|
145
|
+
contents = content_tag(:tr) do
|
146
|
+
text = "".html_safe
|
147
|
+
text << content_tag(:th, :colspan => determine_colspan(text, options),
|
148
|
+
:class => options[:month_name_class]) do
|
149
|
+
"#{options[:month_name_array][options[:month]]} #{options[:display_year]}"
|
150
|
+
end
|
151
|
+
text << content_tag(:th, options[:next_month_text], :colspan => 2) if options[:next_month_text]
|
152
|
+
text
|
153
|
+
end
|
154
|
+
contents << content_tag(:tr, :class => options[:day_name_class]) do
|
155
|
+
add_day_names(options, vars)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def add_day_names(options, vars)
|
161
|
+
text = "".html_safe
|
162
|
+
day_names(vars[:first_weekday]).each do |d|
|
163
|
+
text << content_tag(:th, :scope => 'col') do
|
164
|
+
unless d[options[:abbrev]].eql? d
|
165
|
+
content_tag(:abbr, d[options[:abbrev]], :title => d)
|
166
|
+
else
|
167
|
+
d[options[:abbrev]]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
text
|
172
|
+
end
|
173
|
+
|
174
|
+
def day_names(first_weekday)
|
175
|
+
day_names = Date::DAYNAMES.dup
|
176
|
+
first_weekday.times do
|
177
|
+
day_names.push(day_names.shift)
|
178
|
+
end
|
179
|
+
day_names
|
180
|
+
end
|
181
|
+
|
182
|
+
def determine_colspan(contents, options)
|
183
|
+
if options[:previous_month_text] || options[:next_month_text]
|
184
|
+
contents << content_tag(:th, :colspan => 2) do
|
185
|
+
options[:previous_month_text]
|
186
|
+
end
|
187
|
+
3
|
188
|
+
else
|
189
|
+
7
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def calendar_body(options, vars, &block)
|
194
|
+
content_tag(:tbody) do
|
195
|
+
content_tag(:tr) do
|
196
|
+
text = fill_days_last_month(options, vars[:first], vars[:first_weekday], &block)
|
197
|
+
text << fill_days_this_month(options, vars[:first], vars[:last], vars[:last_weekday], &block)
|
198
|
+
text << fill_days_next_month(options, vars[:last], vars[:first_weekday], vars[:last_weekday], &block)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def fill_days_last_month(options, first, first_weekday, &block)
|
204
|
+
text = "".html_safe
|
205
|
+
beginning_of_week(first, first_weekday).upto(first - 1) do |d|
|
206
|
+
text << fill_day(d, options, false, &block)
|
207
|
+
end unless first.wday == first_weekday
|
208
|
+
text
|
209
|
+
end
|
210
|
+
|
211
|
+
def fill_days_this_month(options, first, last, last_weekday, &block)
|
212
|
+
text = "".html_safe
|
213
|
+
first.upto(last) do |d|
|
214
|
+
text << fill_day(d, options, true, &block)
|
215
|
+
text << "</tr><tr>".html_safe if d.wday == last_weekday
|
216
|
+
end
|
217
|
+
text
|
218
|
+
end
|
219
|
+
|
220
|
+
def fill_days_next_month(options, last, first_weekday, last_weekday, &block)
|
221
|
+
text = "".html_safe
|
222
|
+
(last + 1).upto(beginning_of_week(last + 7, first_weekday) - 1) do |d|
|
223
|
+
text << fill_day(d, options, false, &block)
|
224
|
+
end unless last.wday == last_weekday
|
225
|
+
text
|
226
|
+
end
|
227
|
+
|
228
|
+
def fill_day(d, options = nil, current = false, &block)
|
229
|
+
cell_text, cell_attrs = block.call(d)
|
230
|
+
cell_text ||= d.mday
|
231
|
+
cell_attrs ||= {}
|
232
|
+
cell_attrs[:class] ||= options[:day_class]
|
233
|
+
cell_attrs[:class] += " weekendDay" if weekend?(d)
|
234
|
+
cell_attrs[:class] += " today" if (d == Date.today) && options[:show_today]
|
235
|
+
content_tag(:td, cell_attrs) do
|
236
|
+
text = cell_text
|
237
|
+
text << accessible_text(options) if current
|
238
|
+
text
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def accessible_text(options)
|
243
|
+
options[:accessible] ?
|
244
|
+
"<span class='hidden'> #{options[:month_name_array][d.mon]}</span>" : ""
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ScheduleFu
|
2
|
+
module Finder
|
3
|
+
include ScheduleFu::Parser
|
4
|
+
|
5
|
+
def conditions_for_date_finders(*args)
|
6
|
+
dates = parse(*args)
|
7
|
+
case dates
|
8
|
+
when Date then ['value = ?', dates]
|
9
|
+
when Range then ['value BETWEEN ? AND ?', dates.first, dates.last]
|
10
|
+
when Enumerable then ['value IN (?)', dates]
|
11
|
+
else
|
12
|
+
raise ArgumentError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# Some methods for parsing date expressions from strings
|
2
|
+
module ScheduleFu
|
3
|
+
module Parser
|
4
|
+
def parse(*args)
|
5
|
+
raise ArgumentError unless args.length > 0
|
6
|
+
if args.length == 1
|
7
|
+
case args[0]
|
8
|
+
when String then parse_dates(args[0])
|
9
|
+
when Date then args[0]
|
10
|
+
when Time then args[0]
|
11
|
+
when Enumerable then args[0].map {|arg| parse(arg)}
|
12
|
+
else raise ArgumentError, args[0].class.to_s
|
13
|
+
end
|
14
|
+
elsif args.length == 2
|
15
|
+
(parse_date(args[0]) .. parse_date(args[1]))
|
16
|
+
else
|
17
|
+
args.map {|arg| parse(arg) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_date(string)
|
22
|
+
unless string.nil?
|
23
|
+
begin
|
24
|
+
Date.parse(string)
|
25
|
+
rescue; end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_dates(string)
|
30
|
+
parse_recurring_dates(string) || parse_specific_dates(string)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def parse_specific_dates(value)
|
36
|
+
if (parts = value.split('-')).length == 2
|
37
|
+
first = parse_date(parts[0])
|
38
|
+
last = parse_date(parts[1])
|
39
|
+
if first && last
|
40
|
+
return (first .. last)
|
41
|
+
end
|
42
|
+
elsif (parts = value.split(',')).length > 1
|
43
|
+
parts = parts.map {|part| parse_date(part) }
|
44
|
+
if parts.all? {|part| !part.nil? }
|
45
|
+
return parts
|
46
|
+
end
|
47
|
+
elsif date = parse_date(value)
|
48
|
+
return date
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Parses the given value for repeating date strings of the form:
|
53
|
+
#
|
54
|
+
# * Saturdays
|
55
|
+
# * Every Friday
|
56
|
+
# * every 3rd tuesday
|
57
|
+
# * 2nd and 4th Fridays of the month
|
58
|
+
#
|
59
|
+
# and returns a hash with keys :weekday and :monthweek, where the weekday
|
60
|
+
# is the index of the day in the Date::DAYNAMES array (0-based) and the
|
61
|
+
# monthweek is either nil, an integer, or an array of integers,
|
62
|
+
# corresponding to the offset of the week(s) of the month.
|
63
|
+
def parse_weekly_dates(value)
|
64
|
+
# FIXME repeats data from monthweek. we should probably get a more
|
65
|
+
# robust parser going here
|
66
|
+
unless md = /^\s*(?:Every )?\s*(1st|2nd|3rd|4th|last|first|second|third|fourth)?(?:\s*(?:and|&)\s*(1st|2nd|3rd|4th|last|first|second|third|fourth))?\s*((?:Sun|Mon|Tues|Wednes|Thurs|Fri|Satur)day)s?\s*(?:of each month|of the month|every month)?\s*$/i.match(value)
|
67
|
+
return nil
|
68
|
+
end
|
69
|
+
weekday = Date::DAYNAMES.index(md[3].downcase.capitalize)
|
70
|
+
if md[2]
|
71
|
+
monthweek = [monthweek(md[1]), monthweek(md[2])]
|
72
|
+
return [{:weekday => weekday, :monthweek => md[1]}, {:weekday => weekday, :monthweek => md[2]}]
|
73
|
+
elsif md[1]
|
74
|
+
monthweek = monthweek(md[1])
|
75
|
+
else
|
76
|
+
monthweek = nil
|
77
|
+
end
|
78
|
+
{:weekday => weekday, :monthweek => monthweek }
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the monthweek integer value of the given string, e.g.
|
82
|
+
# first -> 0. It ignores case, and allows both full and abbreviated
|
83
|
+
# ordinal number names, as well as the special name 'last'. If unable
|
84
|
+
# to convert, it will raise an ArgumentError.
|
85
|
+
def monthweek(value)
|
86
|
+
case value.downcase
|
87
|
+
when 'last' then -1
|
88
|
+
when '1st' then 0
|
89
|
+
when 'first' then 0
|
90
|
+
when '2nd' then 1
|
91
|
+
when 'second' then 1
|
92
|
+
when '3rd' then 2
|
93
|
+
when 'third' then 2
|
94
|
+
when '4th' then 3
|
95
|
+
when 'fourth' then 3
|
96
|
+
else raise ArgumentError, value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#module Icalendar
|
103
|
+
# DAYCODES = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']
|
104
|
+
#
|
105
|
+
# class Calendar < Component
|
106
|
+
# ical_property :x_wr_calname, :name
|
107
|
+
# end
|
108
|
+
#end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ScheduleFu
|
2
|
+
module ScheduleFuHelper
|
3
|
+
|
4
|
+
def previous_sunday(date)
|
5
|
+
date = parse_date_or_now(date)
|
6
|
+
date.wday.ago date
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_date_or_now(date)
|
10
|
+
begin
|
11
|
+
Date.parse(date)
|
12
|
+
rescue
|
13
|
+
Time.now.to_date
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CalendarEventTest < ActiveSupport::TestCase
|
4
|
+
describe CalendarEvent do
|
5
|
+
it { should validate_presence_of :calendar }
|
6
|
+
it { should validate_presence_of :start_date }
|
7
|
+
it { should validate_presence_of :calendar_event_type_id }
|
8
|
+
end
|
9
|
+
|
10
|
+
context "norepeat event" do
|
11
|
+
setup do
|
12
|
+
@event = FactoryGirl.create(:calendar_event_norepeat, :start_date => 1.day.from_now,
|
13
|
+
:end_date => 2.weeks.from_now)
|
14
|
+
end
|
15
|
+
|
16
|
+
should "have no recurrences" do
|
17
|
+
assert_equal 0, @event.recurrences.count
|
18
|
+
end
|
19
|
+
|
20
|
+
should "have 1 event date that matches the start date" do
|
21
|
+
assert_equal 1, @event.dates.count
|
22
|
+
assert_equal @event.start_date.to_date, @event.dates.first.value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "weekdays event" do
|
27
|
+
setup do
|
28
|
+
@event = FactoryGirl.create(:calendar_event_weekdays, :start_date => 1.day.from_now,
|
29
|
+
:end_date => 2.weeks.from_now)
|
30
|
+
@count_of_weekdays = Hash.new {|hash, key| hash[key] = 0}
|
31
|
+
@event.dates.each do |d|
|
32
|
+
@count_of_weekdays[d.weekday] += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
should "have no recurrences" do
|
37
|
+
assert_equal 0, @event.recurrences.count
|
38
|
+
end
|
39
|
+
|
40
|
+
should "have 10 event dates" do
|
41
|
+
assert_equal 10, @event.event_dates.count
|
42
|
+
end
|
43
|
+
|
44
|
+
should "have 2 of each weekday" do
|
45
|
+
(1..5).each do |n|
|
46
|
+
assert_equal 2, @count_of_weekdays[n]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
should "not have Sunday or Saturday" do
|
51
|
+
[0,6].each do |n|
|
52
|
+
assert_equal 0, @count_of_weekdays[n]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "daily event with 14 event dates" do
|
58
|
+
setup do
|
59
|
+
@event = FactoryGirl.create(:calendar_event_daily, :start_date => 1.day.from_now,
|
60
|
+
:end_date => 2.weeks.from_now)
|
61
|
+
end
|
62
|
+
|
63
|
+
should "have no recurrences" do
|
64
|
+
assert_equal 0, @event.recurrences.count
|
65
|
+
end
|
66
|
+
|
67
|
+
should "have 14 event dates" do
|
68
|
+
assert_equal 14, @event.event_dates.count
|
69
|
+
end
|
70
|
+
|
71
|
+
should "be in the correct range" do
|
72
|
+
@event.dates.each do |d|
|
73
|
+
assert d.value >= @event.start_date.to_date
|
74
|
+
assert d.value <= @event.end_date.to_date
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "weekly event" do
|
80
|
+
context "on Monday, Wednesday, and Friday with 6 event dates" do
|
81
|
+
setup do
|
82
|
+
@event = FactoryGirl.create(:calendar_event_weekly, :repeat_0 => false, :repeat_1 => true,
|
83
|
+
:repeat_2 => false, :repeat_3 => true, :repeat_4 => false,
|
84
|
+
:repeat_5 => true, :repeat_6 => false, :start_date => 1.day.from_now,
|
85
|
+
:end_date => 2.weeks.from_now)
|
86
|
+
@count_of_weekdays = Hash.new {|hash, key| hash[key] = 0}
|
87
|
+
@event.dates.each do |d|
|
88
|
+
@count_of_weekdays[d.weekday] += 1
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
should "have 3 recurrences" do
|
93
|
+
assert_equal 3, @event.recurrences.count
|
94
|
+
end
|
95
|
+
|
96
|
+
should "have 6 event dates" do
|
97
|
+
assert_equal 6, @event.event_dates.count
|
98
|
+
end
|
99
|
+
|
100
|
+
should "have 2 each of Monday, Wednesday, and Friday" do
|
101
|
+
[1,3,5].each do |n|
|
102
|
+
assert_equal 2, @count_of_weekdays[n]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
should "not have Sunday, Tuesday, Thursday, or Saturday" do
|
107
|
+
[0,2,4,6].each do |n|
|
108
|
+
assert_equal 0, @count_of_weekdays[n]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "monthly event" do
|
115
|
+
context "by day of month with 6 event dates" do
|
116
|
+
setup do
|
117
|
+
@event = FactoryGirl.create(:calendar_event_monthly, :by_day_of_month => true,
|
118
|
+
:start_date => 1.week.ago, :end_date => 5.months.from_now)
|
119
|
+
@recurrence = @event.recurrences.first
|
120
|
+
end
|
121
|
+
|
122
|
+
should "have 1 recurrence" do
|
123
|
+
assert_equal 1, @event.recurrences.count
|
124
|
+
end
|
125
|
+
|
126
|
+
should "have 6 event dates" do
|
127
|
+
assert_equal 6, @event.event_dates.count
|
128
|
+
end
|
129
|
+
|
130
|
+
should "have the correct day of month" do
|
131
|
+
@event.dates.each do |d|
|
132
|
+
assert_equal @recurrence.monthday, d.monthday
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "by day of week with 6 event dates" do
|
138
|
+
setup do
|
139
|
+
@event = FactoryGirl.create(:calendar_event_monthly, :by_day_of_month => false,
|
140
|
+
:start_date => 1.week.ago, :end_date => 5.months.from_now)
|
141
|
+
@recurrence = @event.recurrences.first
|
142
|
+
end
|
143
|
+
|
144
|
+
should "have 1 recurrence" do
|
145
|
+
assert_equal 1, @event.recurrences.count
|
146
|
+
end
|
147
|
+
|
148
|
+
should "have 6 event dates" do
|
149
|
+
assert_equal 6, @event.event_dates.count
|
150
|
+
end
|
151
|
+
|
152
|
+
should "have the correct day of week" do
|
153
|
+
@event.dates.each do |d|
|
154
|
+
assert_equal @recurrence.weekday, d.weekday
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
should "have the correct week" do
|
159
|
+
@event.dates.each do |d|
|
160
|
+
assert_equal @recurrence.monthweek, d.monthweek
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "yearly event" do
|
167
|
+
context "by day of month with 2 event dates" do
|
168
|
+
setup do
|
169
|
+
@event = FactoryGirl.create(:calendar_event_yearly, :by_day_of_month => true,
|
170
|
+
:start_date => 1.month.ago, :end_date => 1.year.from_now)
|
171
|
+
@recurrence = @event.recurrences.first
|
172
|
+
end
|
173
|
+
|
174
|
+
should "have 1 recurrence" do
|
175
|
+
assert_equal 1, @event.recurrences.count
|
176
|
+
end
|
177
|
+
|
178
|
+
should "have 2 event dates" do
|
179
|
+
assert_equal 2, @event.event_dates.count
|
180
|
+
end
|
181
|
+
|
182
|
+
should "have the correct month" do
|
183
|
+
@event.dates.each do |d|
|
184
|
+
assert_equal @recurrence.month, d.month
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
should "have the correct day of month" do
|
189
|
+
@event.dates.each do |d|
|
190
|
+
assert_equal @recurrence.monthday, d.monthday
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context "by day of week with 2 event dates" do
|
196
|
+
setup do
|
197
|
+
@event = FactoryGirl.create(:calendar_event_yearly, :by_day_of_month => false,
|
198
|
+
:start_date => 1.month.ago, :end_date => 1.year.from_now)
|
199
|
+
@recurrence = @event.recurrences.first
|
200
|
+
end
|
201
|
+
|
202
|
+
should "have 1 recurrence" do
|
203
|
+
assert_equal 1, @event.recurrences.count
|
204
|
+
end
|
205
|
+
|
206
|
+
should "have 2 event dates" do
|
207
|
+
assert_equal 2, @event.event_dates.count
|
208
|
+
end
|
209
|
+
|
210
|
+
should "have the correct month" do
|
211
|
+
@event.dates.each do |d|
|
212
|
+
assert_equal @recurrence.month, d.month
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
should "have the correct day of week" do
|
217
|
+
@event.dates.each do |d|
|
218
|
+
assert_equal @recurrence.weekday, d.weekday
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
should "have the correct week" do
|
223
|
+
@event.dates.each do |d|
|
224
|
+
assert_equal @recurrence.monthweek, d.monthweek
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|