event_calendar 0.0.0 → 0.0.1

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.
@@ -24,7 +24,7 @@
24
24
  :-webkit-border-top-right-radius= 0px
25
25
  :border-top-right-radius= 0px
26
26
 
27
- .calendar
27
+ .event_calendar
28
28
 
29
29
  table
30
30
  border-collapse: collapse
@@ -92,7 +92,7 @@
92
92
  !label_background_color = #EBEDE2
93
93
  !label_color = #000
94
94
 
95
- .calendar
95
+ .event_calendar
96
96
  border-bottom= !border_width "solid" !border_color
97
97
 
98
98
  table td
@@ -1,71 +1,71 @@
1
- div.calendar.send(calendar.date.strftime('%B').downcase).send("#{calendar.id}!") do
1
+ div.event_calendar.send(event_calendar.date.strftime('%B').downcase).send("#{event_calendar.id}!") do
2
2
  div.header do
3
3
  table do
4
4
  tbody do
5
5
  tr.navigation do
6
6
  td.previous_month(:colspan => 2) do
7
- a(:rel => 'previous', :href => calendar.navigation_url.call(calendar.date.last_month)) do
8
- calendar.evaluate_date_format_option(:navigation_label, calendar.date.last_month, calendar.date)
7
+ a(:rel => 'previous', :href => event_calendar.navigation_url.call(event_calendar.date.last_month)) do
8
+ event_calendar.evaluate_date_format_option(:navigation_label, event_calendar.date.last_month, event_calendar.date)
9
9
  end
10
10
  end
11
- td.current_month calendar.evaluate_date_format_option(:header_label, calendar.date), :colspan => 3
11
+ td.current_month event_calendar.evaluate_date_format_option(:header_label, event_calendar.date), :colspan => 3
12
12
  td.next_month(:colspan => 2) do
13
- a(:rel => 'next', :href => calendar.navigation_url.call(calendar.date.next_month)) do
14
- calendar.evaluate_date_format_option(:navigation_label, calendar.date.next_month, calendar.date)
13
+ a(:rel => 'next', :href => event_calendar.navigation_url.call(event_calendar.date.next_month)) do
14
+ event_calendar.evaluate_date_format_option(:navigation_label, event_calendar.date.next_month, event_calendar.date)
15
15
  end
16
16
  end
17
17
  end
18
18
  tr.labels do
19
- calendar.weeks.first.each_with_index do |day, index|
19
+ event_calendar.weeks.first.each_with_index do |day, index|
20
20
  day_label = td.day
21
21
  day_label = day_label.send(day.strftime('%A').downcase)
22
22
  day_label = day_label.today if day.cwday == Time.now.to_date.cwday
23
- day_label.label calendar.evaluate_date_format_option(:header_day_label, day)
23
+ day_label.label event_calendar.evaluate_date_format_option(:header_day_label, day)
24
24
  end
25
25
  end
26
26
  end
27
27
  end
28
28
  end
29
29
  div.body do
30
- calendar.weeks.each do |week|
31
- div.week.send("#{calendar.id}_week_#{week.first}_#{week.last}!") do
32
- table.send("#{calendar.id}_labels_#{week.first}_#{week.last}!") do
30
+ event_calendar.weeks.each do |week|
31
+ div.week.send("#{event_calendar.id}_week_#{week.first}_#{week.last}!") do
32
+ table.send("#{event_calendar.id}_labels_#{week.first}_#{week.last}!") do
33
33
  tbody do
34
34
  tr.labels do
35
35
  week.each do |day|
36
36
  day_label = td.day
37
- day_label = day_label.send(day.month == calendar.date.month ? 'current_month' : day < calendar.date ? 'previous_month' : 'next_month')
37
+ day_label = day_label.send(day.month == event_calendar.date.month ? 'current_month' : day < event_calendar.date ? 'previous_month' : 'next_month')
38
38
  day_label = day_label.send([6, 7].include?(day.cwday) ? 'weekend' : 'weekday')
39
39
  day_label = day_label.send(day.strftime('%A').downcase)
40
40
  day_label = day_label.send(day.strftime('%B').downcase)
41
41
  day_label = day_label.send("day_#{day.strftime('%d').gsub(/^0/, '')}")
42
42
  day_label = day_label.today if day == Time.now.to_date
43
- day_label = day_label.scheduled if calendar.events.any? { |event| event.start_date <= day && event.end_date >= day }
44
- day_label.label calendar.evaluate_date_format_option(:day_label, day)
43
+ day_label = day_label.scheduled if event_calendar.events.any? { |event| event.start_date <= day && event.end_date >= day }
44
+ day_label.label event_calendar.evaluate_date_format_option(:day_label, day)
45
45
  end
46
46
  end
47
47
  end
48
48
  end
49
- div.days.send("#{calendar.id}_days_#{week.first}_#{week.last}!") do
50
- table.grid.send("#{calendar.id}_grid_#{week.first}_#{week.last}!") do
49
+ div.days.send("#{event_calendar.id}_days_#{week.first}_#{week.last}!") do
50
+ table.grid.send("#{event_calendar.id}_grid_#{week.first}_#{week.last}!") do
51
51
  tbody do
52
52
  tr do
53
53
  week.each do |day|
54
54
  day_grid = td.day
55
- day_grid = day_grid.send(day.month == calendar.date.month ? 'current_month' : day < calendar.date ? 'previous_month' : 'next_month')
55
+ day_grid = day_grid.send(day.month == event_calendar.date.month ? 'current_month' : day < event_calendar.date ? 'previous_month' : 'next_month')
56
56
  day_grid = day_grid.send([6, 7].include?(day.cwday) ? 'weekend' : 'weekday')
57
57
  day_grid = day_grid.send(day.strftime('%A').downcase)
58
58
  day_grid = day_grid.send(day.strftime('%B').downcase)
59
59
  day_grid = day_grid.send("day_#{day.strftime('%d').gsub(/^0/, '')}")
60
60
  day_grid = day_grid.today if day == Time.now.to_date
61
- day_grid = day_grid.scheduled if calendar.events.any? { |event| event.start_date <= day && event.end_date >= day }
62
- day_grid.send("#{calendar.id}_day_#{day}!") {}
61
+ day_grid = day_grid.scheduled if event_calendar.events.any? { |event| event.start_date <= day && event.end_date >= day }
62
+ day_grid.send("#{event_calendar.id}_day_#{day}!") {}
63
63
  end
64
64
  end
65
65
  end
66
66
  end
67
67
  unless week.events.empty?
68
- table.events.send("#{calendar.id}_events_#{week.first}_#{week.last}!") do
68
+ table.events.send("#{event_calendar.id}_events_#{week.first}_#{week.last}!") do
69
69
  tbody do
70
70
  tr.grid do
71
71
  week.each { |day| td('') }
@@ -78,7 +78,7 @@ div.calendar.send(calendar.date.strftime('%B').downcase).send("#{calendar.id}!")
78
78
  else
79
79
  html_options = { :class => 'event' }
80
80
  html_options[:colspan] = cell[:span] unless cell[:span] == 1
81
- html_options[:class] << " #{calendar.event_class}" unless calendar.event_class.nil?
81
+ html_options[:class] << " #{event_calendar.event_class}" unless event_calendar.event_class.nil?
82
82
  if cell[:continued]
83
83
  html_options[:class] << ' continuation' if cell[:event].start_date < week.first
84
84
  html_options[:class] << ' continued' if cell[:event].end_date > week.last
@@ -86,8 +86,8 @@ div.calendar.send(calendar.date.strftime('%B').downcase).send("#{calendar.id}!")
86
86
  event_id = "event_#{cell[:event].id}"
87
87
  begin
88
88
  td.send("#{event_id}!", html_options) do
89
- calendar.event_output.call(cell[:event]) + div.fields do
90
- calendar.event_fields.each do |field|
89
+ event_calendar.event_output.call(cell[:event]) + div.fields do
90
+ event_calendar.event_fields.each do |field|
91
91
  span(cell[:event].send(field), :title => field)
92
92
  end
93
93
  end
@@ -0,0 +1,67 @@
1
+ class EventCalendar
2
+
3
+ # Contains an array of days representing a calendar week
4
+ class Week < Array
5
+
6
+ extend ActiveSupport::Memoizable
7
+
8
+ # Accepts two arguments, an array of days and an array of events
9
+ def initialize(days, events)
10
+ super days
11
+ add_associated_events_to_days(events)
12
+ end
13
+
14
+ # Returns an array of arrays containing hashes of events to fit in an HTML calendar week row.
15
+ #
16
+ # Each hash in the array represents a table cell <tt>td</tt> when the calendar is generated.
17
+ # If the hash is empty, an empty <tt>td</tt> would be generated. Otherwise, the <tt>td</tt>
18
+ # will contain information related to the associated event. An event hash contains:
19
+ #
20
+ # :event => The event object.
21
+ # :span => The number of days this event takes up in the current week row.
22
+ # :continued => A boolean determining if this event starts before or ends after the current week.
23
+ #
24
+ # For example:
25
+ #
26
+ # puts @week.events.inspect
27
+ #
28
+ # # [
29
+ # # [{}, {}, { :event => ..., :span => 1, :continued => false }, { :event => ..., :span => 1, :continued => false}, {}, {}, {}],
30
+ # # [{}, {}, { :event => ..., :span => 1, :continued => false }, {}, {}, {}, { :event => ..., :span => 1, :continued => true }],
31
+ # # [{}, {}, { :event => ..., :span => 1, :continued => false }, {}, {}, {}, {}],
32
+ # # [{}, {}, { :event => ..., :span => 1, :continued => false }, {}, {}, {}, {}],
33
+ # # [{}, {}, { :event => ..., :span => 4, :continued => false }, {}]
34
+ # # ]
35
+ def events
36
+ events = []
37
+ day_events_index = inject({}) { |hash, day| hash.merge! day => 0 }
38
+ until all? { |day| day_events_index[day] == day.events.size }
39
+ row = []
40
+ each_with_index do |day, index|
41
+ cell_count = row.inject(0) { |sum, cell| sum += (cell.empty? ? 1 : cell[:span]) }
42
+ next if cell_count > index || cell_count >= 7
43
+
44
+ cell = {}
45
+ unless day_events_index[day] == day.events.size
46
+ cell[:event] = day.events[day_events_index[day]]
47
+ cell[:span] = cell[:event].days(first, last)
48
+ cell[:continued] = cell[:event].days != cell[:span]
49
+ day_events_index[day] += 1
50
+ end
51
+ row << cell
52
+ end
53
+ events << row
54
+ end
55
+ events
56
+ end
57
+ memoize :events
58
+
59
+ protected
60
+
61
+ # Loops through each day in this week and adds any associated events to its <tt>:events</tt> array.
62
+ def add_associated_events_to_days(events)
63
+ each { |day| day.events = events.select { |event| event.start_date == day || (event.start_date < day && event.end_date >= day && day == first) } }
64
+ end
65
+
66
+ end
67
+ end
@@ -1,28 +1,26 @@
1
1
  require 'fileutils'
2
2
 
3
- CALENDAR_ROOT = File.join(File.dirname(__FILE__), '..', '..')
4
- ASSETS_ROOT = File.join(CALENDAR_ROOT, 'assets')
5
- SANDBOX_ROOT = File.join(CALENDAR_ROOT, 'sandbox')
3
+ EVENT_CALENDAR_ROOT = File.join(File.dirname(__FILE__), '..', '..')
4
+ ASSETS_ROOT = File.join(EVENT_CALENDAR_ROOT, 'assets')
5
+ SANDBOX_ROOT = File.join(EVENT_CALENDAR_ROOT, 'sandbox')
6
6
 
7
- namespace :calendar do
7
+ namespace :event_calendar do
8
8
  namespace :generate do
9
- desc 'Generates css for the calendar'
9
+ desc 'Generates css for the event calendar'
10
10
  task :css => :build_css do
11
- puts File.read(File.join(ASSETS_ROOT, 'stylesheets', 'calendar.css'))
11
+ puts File.read(File.join(ASSETS_ROOT, 'stylesheets', 'event_calendar.css'))
12
12
  end
13
13
 
14
- desc 'Generates js for the calendar'
14
+ desc 'Generates js for the event calendar'
15
15
  task :js do
16
- puts File.read(File.join(ASSETS_ROOT, 'javascripts', 'calendar.js'))
16
+ puts File.read(File.join(ASSETS_ROOT, 'javascripts', 'event_calendar.prototype.js'))
17
17
  end
18
18
 
19
- desc 'Creates a sandbox in the gem root for testing'
19
+ desc 'Creates a sandbox in the current working directory for testing'
20
20
  task :sandbox => [:build_css] do
21
- $:.unshift(File.join(CALENDAR_ROOT, 'lib'))
21
+ $:.unshift(File.join(EVENT_CALENDAR_ROOT, 'lib'))
22
22
  require 'timecop'
23
- require 'active_support'
24
- require 'markaby'
25
- require 'calendar'
23
+ require 'event_calendar'
26
24
 
27
25
  FileUtils.mkdir(SANDBOX_ROOT) unless File.exists?(SANDBOX_ROOT)
28
26
  FileUtils.cp_r(File.join(ASSETS_ROOT, '.'), SANDBOX_ROOT)
@@ -42,7 +40,7 @@ namespace :calendar do
42
40
  Event.new('Event 4 has a longer title', 3.days.from_now, 5.days.from_now),
43
41
  Event.new('Event 5 spans across multiple weeks', 4.days.from_now, 12.days.from_now)
44
42
  ]
45
- @calendar = Calendar.new(Time.now.year, Time.now.month, :events => events)
43
+ @event_calendar = EventCalendar.new(Time.now.year, Time.now.month, :events => events)
46
44
  end
47
45
 
48
46
  File.open(File.join(SANDBOX_ROOT, 'index.html'), 'w+') do |file|
@@ -50,24 +48,24 @@ namespace :calendar do
50
48
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
51
49
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
52
50
  <head>
53
- <title>Calendar</title>
51
+ <title>Event Calendar</title>
54
52
  <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
55
- <link href="stylesheets/yui-2.7.0.css" media="screen" rel="stylesheet" type="text/css" />
56
- <link href="stylesheets/calendar.css" media="screen" rel="stylesheet" type="text/css" />
57
- <script src="javascripts/prototype-1.6.1.js" type="text/javascript"></script>
58
- <script src="javascripts/calendar.js" type="text/javascript"></script>
53
+ <link href="http://yui.yahooapis.com/combo?2.7.0/build/reset-fonts-grids/reset-fonts-grids.css&amp;2.7.0/build/base/base-min.css" media="screen" rel="stylesheet" type="text/css" />
54
+ <link href="stylesheets/event_calendar.css" media="screen" rel="stylesheet" type="text/css" />
55
+ <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js" type="text/javascript"></script>
56
+ <script src="javascripts/event_calendar.prototype.js" type="text/javascript"></script>
59
57
  <script type="text/javascript">
60
58
  //<![CDATA[
61
59
  document.observe('dom:loaded', function() {
62
- $$('.calendar').each(function(element) {
63
- new Calendar(element);
60
+ $$('.event_calendar').each(function(element) {
61
+ new EventCalendar(element);
64
62
  });
65
63
  });
66
64
  //]]>
67
65
  </script>
68
66
  </head>
69
67
  <body>
70
- #{@calendar}
68
+ #{@event_calendar}
71
69
  </body>
72
70
  </html>
73
71
  EOF
@@ -78,8 +76,8 @@ namespace :calendar do
78
76
  require 'haml'
79
77
  require 'sass/engine'
80
78
 
81
- sass = File.join(CALENDAR_ROOT, 'lib', 'calendar', 'stylesheet.sass')
82
- File.open(File.join(ASSETS_ROOT, 'stylesheets', 'calendar.css'), 'w+') do |file|
79
+ sass = File.join(EVENT_CALENDAR_ROOT, 'lib', 'event_calendar', 'stylesheet.sass')
80
+ File.open(File.join(ASSETS_ROOT, 'stylesheets', 'event_calendar.css'), 'w+') do |file|
83
81
  file.write Sass::Engine.new(File.read(sass)).to_css
84
82
  end
85
83
  end
data/test/date_test.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'test_helper'
2
+
3
+ class DateTest < Test::Unit::TestCase
4
+
5
+ context 'a date' do
6
+ setup { @date = Time.now.to_date }
7
+
8
+ should 'have an events attr_accessor' do
9
+ assert @date.respond_to?(:events)
10
+ assert @date.respond_to?(:events=)
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ class EventCalendarTest < Test::Unit::TestCase
4
+
5
+ context 'an EventCalendar instance' do
6
+ setup do
7
+ Timecop.freeze(Date.civil(2009, 10, 6)) do
8
+ @event_calendar = EventCalendar.new(Time.now.year, Time.now.month,
9
+ :events => events,
10
+ :date_format_string => '%B',
11
+ :date_format_symbol => :year,
12
+ :date_format_proc => proc { |date| date.year },
13
+ :date_format_integer => 2009
14
+ )
15
+ end
16
+ end
17
+
18
+ should 'return the first day of its specified month and year when calling date' do
19
+ assert_equal Date.civil(2009, 10, 1), @event_calendar.date
20
+ end
21
+
22
+ context 'when calling evaluate_date_format_option it' do
23
+ setup { @date = @event_calendar.date }
24
+
25
+ should 'evaluate strings' do
26
+ assert_equal @date.strftime('%B'), @event_calendar.evaluate_date_format_option(:date_format_string, @date)
27
+ end
28
+
29
+ should 'evaluate symbols' do
30
+ assert_equal @date.year, @event_calendar.evaluate_date_format_option(:date_format_symbol, @date)
31
+ end
32
+
33
+ should 'evaluate procs' do
34
+ assert_equal @date.year, @event_calendar.evaluate_date_format_option(:date_format_proc, @date)
35
+ end
36
+
37
+ should 'return all other values' do
38
+ assert_equal 2009, @event_calendar.evaluate_date_format_option(:date_format_integer, @date)
39
+ end
40
+ end
41
+
42
+ context 'when calling method_missing it' do
43
+ should 'read an option' do
44
+ assert_equal @event_calendar.options[:date_format_string], @event_calendar.date_format_string
45
+ end
46
+
47
+ should 'write an option' do
48
+ assert_equal @event_calendar.options[:date_format_string], @event_calendar.date_format_string
49
+ @event_calendar.date_format_string = 'testing'
50
+ assert_equal 'testing', @event_calendar.options[:date_format_string]
51
+ end
52
+
53
+ should 'call super if an option does not exist' do
54
+ assert_raises NoMethodError do
55
+ @event_calendar.missing_option
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'when rendering it' do
61
+ should 'render the default template' do
62
+ assert_match /id="#{@event_calendar.id}"/, @event_calendar.to_s
63
+ end
64
+
65
+ should 'read and render a different template file' do
66
+ @event_calendar.template = File.join(fixtures_path, 'template.mab')
67
+ assert_equal '<div class="event_calendar"></div>', @event_calendar.to_s
68
+ end
69
+
70
+ should 'render a template string' do
71
+ @event_calendar.template = "div.testing do\nend"
72
+ assert_equal '<div class="testing"></div>', @event_calendar.to_s
73
+ end
74
+ end
75
+
76
+ should 'return an array of weeks containing seven days when calling weeks' do
77
+ @weeks = (Date.civil(2009, 9, 27)..Date.civil(2009, 10, 31)).to_a.in_groups_of(7).collect { |week| EventCalendar::Week.new(week, @event_calendar.events) }
78
+ assert_equal @weeks, @event_calendar.weeks
79
+ end
80
+ end
81
+
82
+ end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+
3
+ class EventTest < Test::Unit::TestCase
4
+
5
+ context 'an EventCalendar::Event' do
6
+ setup do
7
+ @event_title = 'testing'
8
+ @start_time = Time.local(2010, 1, 3, 10, 5, 0)
9
+ @end_time = Time.local(2010, 1, 5, 11, 35, 0)
10
+ @raw_event = Event.new(@event_title, @start_time, @end_time)
11
+ @event = EventCalendar::Event.new(@raw_event, EventCalendar.default_options.merge({
12
+ :event_title_symbol => :title,
13
+ :event_title_string => 'string',
14
+ :event_title_proc => proc { |event| event.title + '_proc' }
15
+ }))
16
+ end
17
+
18
+ should 'have a start_date' do
19
+ assert_equal @start_time.to_date, @event.start_date
20
+ end
21
+
22
+ should 'have an end_date' do
23
+ assert_equal @end_time.to_date, @event.end_date
24
+ end
25
+
26
+ should 'return the number of days it spans' do
27
+ assert_equal 3, @event.days
28
+ end
29
+
30
+ should 'return the number of days it spans with a starting week offset' do
31
+ assert_equal 2, @event.days(@event.start_date + 1.day)
32
+ end
33
+
34
+ should 'return the number of days it spans with an ending week offset' do
35
+ assert_equal 2, @event.days(@event.start_date, @event.end_date - 1.day)
36
+ end
37
+
38
+ should 'return the number of days it spans with a starting and ending week offset' do
39
+ assert_equal 1, @event.days(@event.start_date + 1.day, @event.end_date - 1.day)
40
+ end
41
+
42
+ should 'evaluate missing attributes as symbols' do
43
+ assert_equal @event_title, @event.title_symbol
44
+ end
45
+
46
+ should 'evaluate missing attributes as objects' do
47
+ assert_equal 'string', @event.title_string
48
+ end
49
+
50
+ should 'evaluate missing attributes as procs and pass the raw event' do
51
+ assert_equal @event_title + '_proc', @event.title_proc
52
+ end
53
+
54
+ should 'delegate all other missing attributes to the raw event' do
55
+ assert_equal @raw_event.id, @event.id
56
+ end
57
+ end
58
+
59
+ end