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.
Files changed (57) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +34 -0
  3. data/Rakefile +40 -0
  4. data/app/models/calendar.rb +26 -0
  5. data/app/models/calendar_date.rb +76 -0
  6. data/app/models/calendar_event.rb +157 -0
  7. data/app/models/calendar_event_date.rb +8 -0
  8. data/app/models/calendar_event_mod.rb +8 -0
  9. data/app/models/calendar_event_type.rb +3 -0
  10. data/app/models/calendar_recurrence.rb +9 -0
  11. data/config/routes.rb +2 -0
  12. data/db/migrate/20120121210741_add_schedule_fu_tables.rb +167 -0
  13. data/lib/schedule_fu.rb +8 -0
  14. data/lib/schedule_fu/calendar_helper.rb +247 -0
  15. data/lib/schedule_fu/engine.rb +5 -0
  16. data/lib/schedule_fu/finder.rb +16 -0
  17. data/lib/schedule_fu/parser.rb +108 -0
  18. data/lib/schedule_fu/schedule_fu_helper.rb +17 -0
  19. data/lib/schedule_fu/version.rb +3 -0
  20. data/lib/tasks/schedule_fu_tasks.rake +4 -0
  21. data/test/calendar_event_test.rb +229 -0
  22. data/test/dummy/README.rdoc +261 -0
  23. data/test/dummy/Rakefile +7 -0
  24. data/test/dummy/app/assets/javascripts/application.js +15 -0
  25. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  26. data/test/dummy/app/controllers/application_controller.rb +3 -0
  27. data/test/dummy/app/helpers/application_helper.rb +2 -0
  28. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  29. data/test/dummy/config.ru +4 -0
  30. data/test/dummy/config/application.rb +56 -0
  31. data/test/dummy/config/boot.rb +10 -0
  32. data/test/dummy/config/database.yml +9 -0
  33. data/test/dummy/config/environment.rb +5 -0
  34. data/test/dummy/config/environments/development.rb +37 -0
  35. data/test/dummy/config/environments/production.rb +67 -0
  36. data/test/dummy/config/environments/test.rb +37 -0
  37. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  38. data/test/dummy/config/initializers/inflections.rb +15 -0
  39. data/test/dummy/config/initializers/mime_types.rb +5 -0
  40. data/test/dummy/config/initializers/secret_token.rb +7 -0
  41. data/test/dummy/config/initializers/session_store.rb +8 -0
  42. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  43. data/test/dummy/config/locales/en.yml +5 -0
  44. data/test/dummy/config/routes.rb +4 -0
  45. data/test/dummy/db/migrate/20120121220057_add_schedule_fu_tables.schedule_fu.rb +168 -0
  46. data/test/dummy/db/schema.rb +82 -0
  47. data/test/dummy/log/development.log +283 -0
  48. data/test/dummy/log/test.log +2224 -0
  49. data/test/dummy/public/404.html +26 -0
  50. data/test/dummy/public/422.html +26 -0
  51. data/test/dummy/public/500.html +25 -0
  52. data/test/dummy/public/favicon.ico +0 -0
  53. data/test/dummy/script/rails +6 -0
  54. data/test/factories/calendar.rb +5 -0
  55. data/test/factories/calendar_event.rb +35 -0
  56. data/test/test_helper.rb +20 -0
  57. metadata +215 -0
@@ -0,0 +1,8 @@
1
+ require "schedule_fu/calendar_helper"
2
+ require "schedule_fu/engine"
3
+ require "schedule_fu/parser"
4
+ require "schedule_fu/finder"
5
+ require "schedule_fu/schedule_fu_helper"
6
+
7
+ module ScheduleFu
8
+ end
@@ -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,5 @@
1
+ module ScheduleFu
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace ScheduleFu
4
+ end
5
+ 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,3 @@
1
+ module ScheduleFu
2
+ VERSION = "0.2"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :schedule_fu do
3
+ # # Task goes here
4
+ # 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