calendrier 0.9.0
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/.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
|
+
|