calendrier 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +661 -0
- data/README.md +158 -0
- data/Rakefile +13 -0
- data/calendrier.gemspec +23 -0
- data/lib/calendrier.rb +21 -0
- data/lib/calendrier/calendrier_builder.rb +74 -0
- data/lib/calendrier/controllers/event_extension.rb +57 -0
- data/lib/calendrier/helpers/calendrier_helper.rb +94 -0
- data/lib/calendrier/helpers/event_helper.rb +63 -0
- data/lib/calendrier/version.rb +3 -0
- data/test/lib/calendrier/calendrier_builder_test.rb +175 -0
- data/test/lib/calendrier/controllers/event_extension_test.rb +40 -0
- data/test/lib/calendrier/helpers/calendrier_helper_test.rb +60 -0
- data/test/lib/calendrier/helpers/event_helper_test.rb +94 -0
- data/test/lib/calendrier/version_test.rb +9 -0
- data/test/minitest_helper.rb +19 -0
- data/test/test_helper.rb +52 -0
- metadata +138 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
module Calendrier
|
2
|
+
module EventHelper
|
3
|
+
|
4
|
+
def count_sorted_events(events_by_date, cell_begin_time, cell_end_time)
|
5
|
+
counter = 0
|
6
|
+
sorted_events_do(events_by_date, cell_begin_time, cell_end_time) { |event| counter += 1 }
|
7
|
+
counter
|
8
|
+
end
|
9
|
+
|
10
|
+
def yield_sorted_events(events_by_date, cell_begin_time, cell_end_time, &block)
|
11
|
+
sorted_events_do(events_by_date, cell_begin_time, cell_end_time) { |event| yield event }
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def sorted_events_do(events_by_date, cell_begin_time, cell_end_time, &block)
|
17
|
+
begin
|
18
|
+
unless events_by_date[cell_begin_time.year.to_s][cell_begin_time.month.to_s][cell_begin_time.day.to_s].nil?
|
19
|
+
events_by_date[cell_begin_time.year.to_s][cell_begin_time.month.to_s][cell_begin_time.day.to_s].each do |event|
|
20
|
+
yield event if display_event?(event, cell_begin_time, cell_end_time) # && block_given?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
rescue NoMethodError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def display_event?(event, cell_begin_time, cell_end_time)
|
28
|
+
event_begin_time = nil
|
29
|
+
event_end_time = nil
|
30
|
+
|
31
|
+
if event.respond_to?(:year) && event.respond_to?(:month) && event.respond_to?(:day)
|
32
|
+
event_begin_time = Time.utc(event.year, event.month, event.day)
|
33
|
+
event_end_time = Time.utc(event.year, event.month, event.day, 23, 59, 59)
|
34
|
+
end
|
35
|
+
|
36
|
+
if event.respond_to?(:begin_time) && event.respond_to?(:end_time)
|
37
|
+
event_begin_time = event.begin_time
|
38
|
+
event_end_time = event.end_time
|
39
|
+
end
|
40
|
+
|
41
|
+
if event_begin_time.to_i <= cell_begin_time.to_i
|
42
|
+
if event_end_time.to_i <= cell_end_time.to_i
|
43
|
+
if event_end_time.to_i > cell_begin_time.to_i
|
44
|
+
ok = true
|
45
|
+
end
|
46
|
+
else
|
47
|
+
ok = true
|
48
|
+
end
|
49
|
+
else
|
50
|
+
if event_end_time.to_i <= cell_end_time.to_i
|
51
|
+
ok = true
|
52
|
+
else
|
53
|
+
if event_begin_time.to_i < cell_end_time.to_i
|
54
|
+
ok = true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
return ok
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Calendrier::CalendrierBuilder do
|
4
|
+
before do
|
5
|
+
|
6
|
+
ActionView::Base.send(:include, Calendrier::CalendrierHelper)
|
7
|
+
ActionView::Base.send(:include, Calendrier::EventHelper)
|
8
|
+
@view = ActionView::Base.new
|
9
|
+
@cal_options = { :year => 2012, :month => 5, :day => 25, :start_on_monday => true, :title => 'This is the calendar title' }
|
10
|
+
|
11
|
+
# preparing array for the month of may 2012
|
12
|
+
@days_of_may = []
|
13
|
+
@days_of_may << ''
|
14
|
+
31.times do |idx|
|
15
|
+
@days_of_may << (idx + 1).to_s
|
16
|
+
end
|
17
|
+
3.times { @days_of_may << '' }
|
18
|
+
|
19
|
+
# preparing array for the week of the 25th of may 2012
|
20
|
+
@days_of_may_weekly = []
|
21
|
+
24.times do |hour_idx|
|
22
|
+
@days_of_may_weekly << (hour_idx).to_s
|
23
|
+
7.times do |day_idx|
|
24
|
+
@days_of_may_weekly << ''
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
# builder
|
31
|
+
|
32
|
+
it "should require context and elements" do
|
33
|
+
proc { Calendrier::CalendrierBuilder::Builder.new }.must_raise ArgumentError
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise NotImplementedError for Builder instance" do
|
37
|
+
builder = Calendrier::CalendrierBuilder::Builder.new(@view)
|
38
|
+
proc { builder.render }.must_raise NotImplementedError
|
39
|
+
end
|
40
|
+
|
41
|
+
# simple builder #
|
42
|
+
|
43
|
+
it "should respond to render for SimpleBuilder instance" do
|
44
|
+
builder = Calendrier::CalendrierBuilder::SimpleBuilder.new(@view)
|
45
|
+
#proc { builder.render }.must_raise NotImplementedError
|
46
|
+
builder.render(nil, nil)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return valid code for monthly calendar" do
|
50
|
+
options = { :display => :month }
|
51
|
+
header, content = generate_header_and_content(options)
|
52
|
+
builder = Calendrier::CalendrierBuilder::SimpleBuilder.new(@view, options)
|
53
|
+
html_doc = Nokogiri::XML::Document.parse(builder.render(header, content).html_safe)
|
54
|
+
html_doc.errors.must_equal []
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return valid code for weekly calendar" do
|
58
|
+
options = { :display => :week }
|
59
|
+
header, content = generate_header_and_content(options)
|
60
|
+
builder = Calendrier::CalendrierBuilder::SimpleBuilder.new(@view, options)
|
61
|
+
html_doc = Nokogiri::XML::Document.parse(builder.render(header, content).html_safe)
|
62
|
+
html_doc.errors.must_equal []
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should have the right calendar title" do
|
66
|
+
cal = generate_calendar(:month)
|
67
|
+
html_doc = Nokogiri::HTML(cal.html_safe)
|
68
|
+
calendar_title = html_doc.css('div.calendar > span').map { |link| link.children.to_s }.first
|
69
|
+
calendar_title.must_match /#{@cal_options[:title]}/
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# monthly
|
74
|
+
it "should return the default monthly calendar" do
|
75
|
+
cal = generate_calendar(:month)
|
76
|
+
cal.must_match %r{calendar month}
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should have the right amount of lines for monthly calendar" do
|
80
|
+
cal = generate_calendar(:month)
|
81
|
+
html_doc = Nokogiri::HTML(cal.html_safe)
|
82
|
+
calendar_lines = html_doc.css('div.calendar tr')
|
83
|
+
calendar_lines_count = html_doc.css('div.calendar tr').count
|
84
|
+
calendar_lines_count.must_equal 5
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should have the right amount of columns for monthly calendar" do
|
88
|
+
cal = generate_calendar(:month)
|
89
|
+
html_doc = Nokogiri::HTML(cal.html_safe)
|
90
|
+
calendar_columns_count = html_doc.css('div.calendar td').count
|
91
|
+
calendar_columns_count.must_equal 5 * 7
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should have the rights columns for monthly calendar" do
|
95
|
+
cal = generate_calendar(:month)
|
96
|
+
html_doc = Nokogiri::HTML(cal.html_safe)
|
97
|
+
calendar_columns_arr = html_doc.css('div.calendar td')
|
98
|
+
content_arr = calendar_columns_arr.map { |col| col.children.text.to_s }
|
99
|
+
content_arr.must_equal @days_of_may
|
100
|
+
end
|
101
|
+
|
102
|
+
# weekly
|
103
|
+
it "should return the weekly calendar" do
|
104
|
+
cal = generate_calendar(:week)
|
105
|
+
cal.must_match %r{calendar week}
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should have the right amount of lines for weekly calendar" do
|
109
|
+
cal = generate_calendar(:week)
|
110
|
+
html_doc = Nokogiri::HTML(cal.html_safe)
|
111
|
+
calendar_lines_count = html_doc.css('div.calendar tr').count
|
112
|
+
calendar_lines_count.must_equal 24
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should have the right amount of columns for monthly calendar" do
|
116
|
+
cal = generate_calendar(:week)
|
117
|
+
html_doc = Nokogiri::HTML(cal.html_safe)
|
118
|
+
calendar_columns_count = html_doc.css('div.calendar td').count
|
119
|
+
calendar_columns_count.must_equal (1 + 7) * 24
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should have the rights columns for monthly calendar" do
|
123
|
+
cal = generate_calendar(:week)
|
124
|
+
html_doc = Nokogiri::HTML(cal.html_safe)
|
125
|
+
calendar_columns_arr = html_doc.css('div.calendar td')
|
126
|
+
content_arr = calendar_columns_arr.map { |col| col.children.to_s }
|
127
|
+
content_arr.must_equal @days_of_may_weekly
|
128
|
+
end
|
129
|
+
|
130
|
+
def generate_calendar(display = :month)
|
131
|
+
options = @cal_options.merge :display => display
|
132
|
+
header, content = generate_header_and_content(options)
|
133
|
+
builder = Calendrier::CalendrierBuilder::SimpleBuilder.new(@view, options)
|
134
|
+
builder.render(header, content).html_safe
|
135
|
+
end
|
136
|
+
|
137
|
+
def generate_header_and_content(options = {})
|
138
|
+
display = options[:display] || :month
|
139
|
+
header = []
|
140
|
+
time_iterate(Time.utc(2012,5,21), Time.utc(2012,5,28)-1, 60*60*24) do |date|
|
141
|
+
header << date.to_date
|
142
|
+
end
|
143
|
+
content = []
|
144
|
+
content_intermediate = []
|
145
|
+
if display == :month
|
146
|
+
content_intermediate << content_hash(nil, nil)
|
147
|
+
time_iterate(Time.utc(2012,5,1), Time.utc(2012,5,31), 60*60*24) do |time|
|
148
|
+
content_intermediate << content_hash(time, nil)
|
149
|
+
end
|
150
|
+
3.times { content_intermediate << content_hash(nil, nil) }
|
151
|
+
else
|
152
|
+
24.times do |idx|
|
153
|
+
time_iterate(Time.utc(2012,5,21), Time.utc(2012,5,27), 60*60*24) do |time|
|
154
|
+
content_intermediate << content_hash(time + idx*60*60, nil)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
(content_intermediate.count / 7).times do |idx|
|
160
|
+
content << content_intermediate.slice(idx * 7, 7)
|
161
|
+
end
|
162
|
+
[header, content]
|
163
|
+
end
|
164
|
+
|
165
|
+
def content_hash(time, content)
|
166
|
+
{ time: time, content: content }
|
167
|
+
end
|
168
|
+
|
169
|
+
def time_iterate(start_time, end_time, step, &block)
|
170
|
+
begin
|
171
|
+
yield(start_time, start_time + step)
|
172
|
+
end while (start_time += step) <= end_time
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Calendrier::EventExtension do
|
4
|
+
before do
|
5
|
+
|
6
|
+
ActionController::Base.send(:include, Calendrier::EventExtension)
|
7
|
+
@ctrl = ActionController::Base.new
|
8
|
+
|
9
|
+
de = FakeDailyEvent.new(2012,5,21)
|
10
|
+
de2 = FakeDailyEvent.new(2012,5,24)
|
11
|
+
le = FakeLongEvent.new(Time.utc(2012,5,23).to_i, Time.utc(2012,5,25,12).to_i)
|
12
|
+
|
13
|
+
@events_sorted_manually = {"2012"=>{
|
14
|
+
"5"=>{
|
15
|
+
"21"=>[ de ],
|
16
|
+
"23"=>[ le ],
|
17
|
+
"24"=>[ le, de2 ],
|
18
|
+
"25"=>[ le ],
|
19
|
+
# "26"=>[ le ] # this one should not be display
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
@events_unordered = [ de, le, de2 ]
|
26
|
+
|
27
|
+
@events = @events_sorted_manually
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should integrate with ActionController::Base" do
|
32
|
+
@ctrl.respond_to?(:sort_events).must_equal true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return hash of events sorted by date" do
|
36
|
+
@ctrl.sort_events(@events_unordered).must_equal @events_sorted_manually
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Calendrier::CalendrierHelper do
|
4
|
+
before do
|
5
|
+
|
6
|
+
ActionView::Base.send(:include, Calendrier::CalendrierHelper)
|
7
|
+
ActionView::Base.send(:include, Calendrier::EventHelper)
|
8
|
+
@view = ActionView::Base.new
|
9
|
+
@cal_options = { :year => 2012, :month => 5, :day => 25, :start_on_monday => true }
|
10
|
+
de = FakeDailyEvent.new(2012,5,21)
|
11
|
+
de2 = FakeDailyEvent.new(2012,5,24)
|
12
|
+
le2 = FakeLongEvent.new(Time.utc(2012,5,23).to_i, Time.utc(2012,5,25).to_i)
|
13
|
+
@events_test = {"2012"=>{
|
14
|
+
"5"=>{
|
15
|
+
"21"=>[ de ],
|
16
|
+
"23"=>[ le2 ],
|
17
|
+
"24"=>[ de2, le2 ],
|
18
|
+
"25"=>[ le2 ],
|
19
|
+
"26"=>[ le2 ] # this one should not be display
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
# preparing events counter array for the week of the 25th of may 2012
|
25
|
+
@counter_of_may_weekly = []
|
26
|
+
24.times { @counter_of_may_weekly = @counter_of_may_weekly + [1,0,1,2,0,0,0] }
|
27
|
+
|
28
|
+
# preparing events counter array for the week of the 25th of may 2012
|
29
|
+
@counter_of_may_monthly = []
|
30
|
+
20.times { @counter_of_may_monthly << 0 }
|
31
|
+
@counter_of_may_monthly << 1
|
32
|
+
@counter_of_may_monthly << 0
|
33
|
+
@counter_of_may_monthly << 1
|
34
|
+
@counter_of_may_monthly << 2
|
35
|
+
7.times { @counter_of_may_monthly << 0 }
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should integrate with ActionView::Base" do
|
39
|
+
@view.respond_to?(:calendrier).must_equal true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have the right amount of events for monthly calendar" do
|
43
|
+
counts = []
|
44
|
+
cal = @view.calendrier(@cal_options.merge :display => :month) do |cell_begin_time, cell_end_time|
|
45
|
+
counts << @view.count_sorted_events(@events_test, cell_begin_time, cell_end_time)
|
46
|
+
end
|
47
|
+
counts.must_equal @counter_of_may_monthly
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should have the right amount of events for weekly calendar" do
|
51
|
+
counts = []
|
52
|
+
cal = @view.calendrier(@cal_options.merge :display => :week) do |cell_begin_time, cell_end_time|
|
53
|
+
counts << @view.count_sorted_events(@events_test, cell_begin_time, cell_end_time)
|
54
|
+
end
|
55
|
+
counts.must_equal @counter_of_may_weekly
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
describe Calendrier::EventHelper do
|
4
|
+
before do
|
5
|
+
|
6
|
+
#ActionView::Base.send(:include, Calendrier::CalendrierHelper)
|
7
|
+
ActionView::Base.send(:include, Calendrier::EventHelper)
|
8
|
+
@view = ActionView::Base.new
|
9
|
+
@cal_options = { :year => 2012, :month => 5, :day => 25, :start_on_monday => true }
|
10
|
+
|
11
|
+
de = FakeDailyEvent.new(2012,5,21)
|
12
|
+
de2 = FakeDailyEvent.new(2012,5,24)
|
13
|
+
le = FakeLongEvent.new(Time.utc(2012,5,23).to_i, Time.utc(2012,5,25,12).to_i)
|
14
|
+
|
15
|
+
@events_sorted_manually = {"2012"=>{
|
16
|
+
"5"=>{
|
17
|
+
"21"=>[ de ],
|
18
|
+
"23"=>[ le ],
|
19
|
+
"24"=>[ le, de2 ],
|
20
|
+
"25"=>[ le ],
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
# "26"=>[ le ] # this one should not be displayed
|
26
|
+
|
27
|
+
@events = @events_sorted_manually
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should integrate with ActionView::Base" do
|
32
|
+
@view.respond_to?(:count_sorted_events).must_equal true
|
33
|
+
@view.respond_to?(:yield_sorted_events).must_equal true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should count only one event" do
|
37
|
+
cell_begin_time = Time.utc(2012, 5, 23, 12)
|
38
|
+
cell_end_time = Time.utc(2012, 5, 23, 13)
|
39
|
+
@view.count_sorted_events(@events, cell_begin_time, cell_end_time).must_equal 1
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should count the two events" do
|
43
|
+
cell_begin_time = Time.utc(2012, 5, 24, 12)
|
44
|
+
cell_end_time = Time.utc(2012, 5, 24, 13)
|
45
|
+
@view.count_sorted_events(@events, cell_begin_time, cell_end_time).must_equal 2
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should count the right amount of events in the month" do
|
49
|
+
calendar_begin_time = Time.utc(2012, 5, 1)
|
50
|
+
calendar_end_time = Time.utc(2012, 5, 31)
|
51
|
+
events_count_of_may = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0]
|
52
|
+
|
53
|
+
step = 60 * 60 * 24 # 1.day
|
54
|
+
|
55
|
+
events_counts = []
|
56
|
+
|
57
|
+
time_iterate(calendar_begin_time, calendar_end_time, step) do |cell_begin_time, cell_end_time|
|
58
|
+
events_counts << @view.count_sorted_events(@events, cell_begin_time, cell_end_time)
|
59
|
+
end
|
60
|
+
|
61
|
+
events_counts.must_equal events_count_of_may
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should count the right amount of events in the week" do
|
65
|
+
calendar_begin_time = Time.utc(2012, 5, 21, 0)
|
66
|
+
calendar_end_time = Time.utc(2012, 5, 27, 23, 59, 59)
|
67
|
+
events_count_of_one_week_in_may = []
|
68
|
+
24.times { events_count_of_one_week_in_may << 1 }
|
69
|
+
24.times { events_count_of_one_week_in_may << 0 }
|
70
|
+
24.times { events_count_of_one_week_in_may << 1 }
|
71
|
+
24.times { events_count_of_one_week_in_may << 2 }
|
72
|
+
12.times { events_count_of_one_week_in_may << 1 }
|
73
|
+
(12+24+24).times { events_count_of_one_week_in_may << 0 }
|
74
|
+
|
75
|
+
step = 60 * 60 # 1.hour
|
76
|
+
|
77
|
+
events_counts = []
|
78
|
+
|
79
|
+
time_iterate(calendar_begin_time, calendar_end_time, step) do |cell_begin_time, cell_end_time|
|
80
|
+
events_counts << @view.count_sorted_events(@events, cell_begin_time, cell_end_time)
|
81
|
+
end
|
82
|
+
|
83
|
+
events_counts.must_equal events_count_of_one_week_in_may
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def time_iterate(start_time, end_time, step, &block)
|
88
|
+
begin
|
89
|
+
yield(start_time, start_time + step)
|
90
|
+
end while (start_time += step) <= end_time
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|