turba_chronos 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +6 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +68 -0
  8. data/Rakefile +11 -0
  9. data/lib/turba_chronos.rb +31 -0
  10. data/lib/turba_chronos/core_ext/range.rb +5 -0
  11. data/lib/turba_chronos/day.rb +71 -0
  12. data/lib/turba_chronos/period.rb +44 -0
  13. data/lib/turba_chronos/period_converter.rb +69 -0
  14. data/lib/turba_chronos/periods.rb +43 -0
  15. data/lib/turba_chronos/rule.rb +52 -0
  16. data/lib/turba_chronos/stored_periods.rb +68 -0
  17. data/lib/turba_chronos/timeline.rb +139 -0
  18. data/lib/turba_chronos/version.rb +3 -0
  19. data/spec/fixtures/base_fixture.rb +31 -0
  20. data/spec/fixtures/disney_fixture.rb +19 -0
  21. data/spec/fixtures/empty_periods_fixture.rb +13 -0
  22. data/spec/fixtures/future_reopen_fixture.rb +19 -0
  23. data/spec/fixtures/lcl_fixture.rb +18 -0
  24. data/spec/fixtures/november_bug_fixture.rb +13 -0
  25. data/spec/fixtures/opened_fixture.rb +12 -0
  26. data/spec/lib/alt_timeline_spec.rb +48 -0
  27. data/spec/lib/disney_2_spec.rb +21 -0
  28. data/spec/lib/disney_3_spec.rb +21 -0
  29. data/spec/lib/disney_spec.rb +21 -0
  30. data/spec/lib/empty_periods_spec.rb +21 -0
  31. data/spec/lib/future_reopen_spec.rb +21 -0
  32. data/spec/lib/lcl_spec.rb +28 -0
  33. data/spec/lib/november_bug_spec.rb +20 -0
  34. data/spec/lib/opened_spec.rb +21 -0
  35. data/spec/lib/timeline_spec.rb +70 -0
  36. data/spec/spec_helper.rb +8 -0
  37. data/test/fixtures/base_fixture.rb +31 -0
  38. data/test/test_helper.rb +6 -0
  39. data/test/test_periods.rb +16 -0
  40. data/test/test_periods_converter.rb +62 -0
  41. data/test/test_rule.rb +33 -0
  42. data/test/test_timeline.rb +51 -0
  43. data/turba_chronos.gemspec +30 -0
  44. metadata +236 -0
@@ -0,0 +1,68 @@
1
+ module TurbaChronos
2
+ module StoredPeriods
3
+
4
+ def self.all
5
+ @all ||= [self.FR, self.DE, self.BR, self.RU, self.TR].reduce(:merge)
6
+ end
7
+
8
+ def self.FR
9
+ {
10
+ vacances_noel: [['20/12', '31/12'], ['01/01', '05/01']],
11
+ vacances_toussaint: [['18/10', '02/11']],
12
+ vacances_hiver_zone_a: [['07/02', '22/02']],
13
+ vacances_hiver_zone_b: [['21/02', '08/03']],
14
+ vacances_hiver_zone_c: [['14/02', '01/03']],
15
+ vacances_hiver: [['07/02', '08/03']],
16
+ vacances_printemps_zone_a: [['11/04', '26/04']],
17
+ vacances_printemps_zone_b: [['25/04', '10/05']],
18
+ vacances_printemps_zone_c: [['18/04', '03/05']],
19
+ vacances_printemps: [['11/04', '10/05']],
20
+ vacances_ete: [['05/07', '01/09']],
21
+ week_end_paques: [['04/04', '06/04']],
22
+ weekend_14_juillet: [['12/07', '14/07']],
23
+ premiere_semaine_juillet: [['30/06', '06/07']],
24
+ premiere_quinzaine_aout: [['01/08', '17/08']],
25
+ derniere_quinzaine_aout: [['18/08', '31/08']],
26
+ derniere_quinzaine_juillet: [['12/07', '31/07']],
27
+ premiere_quinzaine_juillet: [['01/07', '11/07']],
28
+ derniere_semaine_juillet: [['22/07', '31/07']],
29
+ pentecote: [['08/06', '09/06']],
30
+ carnaval_venise: [['22/02', '04/03']],
31
+ ponts_mai: [['01/05', '03/05'], ['08/05', '10/05'], ['23/05', '25/05'], ['25/06'], ['28/06']],
32
+ jours_feries: [['01/01'],['06/04'],['01/05'],['08/05'],['14/05'],['25/05'],['14/07'],['15/08'],['01/11'],['11/11'],['25/12']]
33
+ }
34
+ end
35
+
36
+ def self.DE
37
+ {
38
+ ostern: [['02/04', '05/05']],
39
+ pfingsten: [['08/06', '09/06']],
40
+ buss_und_bettag: [['19/11']],
41
+ himmelfahrt: [['29/05']],
42
+ tag_der_deutschen_einheit: [['03/10']]
43
+ }
44
+ end
45
+
46
+ def self.BR
47
+ {
48
+ pascoa: [['02/04', '05/05']],
49
+ ferias_escolares: [['01/07', '31/07']],
50
+ semana_dia_das_criancas: [['12/10']],
51
+ proclamacao_de_republica: [['15/11', '17/11']],
52
+ feriados_fixos: [['01/01'],['21/04'],['01/05'],['07/09'],['12/10'],['02/11'],['15/11'],['25/12']]
53
+ }
54
+ end
55
+
56
+ def self.GB
57
+ {}
58
+ end
59
+
60
+ def self.RU
61
+ {}
62
+ end
63
+
64
+ def self.TR
65
+ {}
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,139 @@
1
+ module TurbaChronos
2
+ class Timeline
3
+ def initialize(periods, from, to)
4
+ @periods = Periods.new(periods).complete
5
+ @from = from
6
+ @to = to
7
+ end
8
+
9
+ def business_timeranges
10
+ timeranges_for_days[:business_timeranges].map! {|x|
11
+ [x.min.to_s.rjust(4, '0').insert(2, ':'), x.max.to_s.rjust(4, '0').insert(2, ':')]
12
+ }
13
+ end
14
+
15
+ def levels
16
+ @levels ||= days.map(&:timeframes).flatten.map(&:level).uniq
17
+ end
18
+
19
+ def timeranges_for_days
20
+ @timeranges_for_days ||= get_timeranges_for_days(@from, @to)
21
+ end
22
+
23
+ def days
24
+ @days ||= get_days(@from, @to)
25
+ end
26
+
27
+ def current_day
28
+ @current_day ||= days.first
29
+ end
30
+
31
+ def opened?
32
+ current_day.opened?
33
+ end
34
+
35
+ def next
36
+ get_list(days)[0..2]
37
+ end
38
+
39
+ def reopen
40
+ get_list(days).each do |data|
41
+ return data if data.timeframe.level != 6
42
+ end
43
+
44
+ iteration = 14
45
+ count = 0
46
+ loop do
47
+ if count == 0
48
+ next_days = get_days(@to+1.day, @to+iteration.days)
49
+ else
50
+ next_days = get_days((@to+(count * iteration).days), (@to+((count+1) * iteration).days))
51
+ end
52
+ get_list(next_days).each do |data|
53
+ return data if data.timeframe.level != 6
54
+ end
55
+ count += 1
56
+ end
57
+ end
58
+
59
+ def current_timeframe
60
+ current_day.current_timeframe
61
+ end
62
+
63
+ protected
64
+
65
+ def get_uniq_periods_for_days(from, to)
66
+ (from.to_date..to.to_date).step(1).to_a.map! do |day|
67
+ get_periods_for_day(day).first
68
+ end.uniq.sort_by!(&:distance)
69
+ end
70
+
71
+ def get_periods_for_day(day)
72
+ periods = @periods.reject do |period|
73
+ ([day.yday] & period.yday_array).blank?
74
+ end
75
+ periods.push(default_period) if periods.empty?
76
+ periods
77
+ end
78
+
79
+ def default_period
80
+ start_year = Time.now.utc.beginning_of_year
81
+ end_year = Time.now.utc.end_of_year
82
+ Period.new(start_year, end_year, [[*FULL_DAY_TIMERANGE, *[6]*7]])
83
+ end
84
+
85
+ def get_days(from, to)
86
+ periods = get_uniq_periods_for_days(from, to)
87
+ rules = get_rules_for_periods(periods)
88
+ timeranges = get_timeranges_for_rules(rules)
89
+ (from.to_date..to.to_date).step(1).to_a.map do |day|
90
+ Day.new(day, periods, timeranges)
91
+ end
92
+ end
93
+
94
+ def get_rules_for_periods(periods)
95
+ periods.map(&:rules).flatten!
96
+ end
97
+
98
+ def get_timeranges_for_rules(rules)
99
+ business_timeranges = rules.select {|r| !r.business_hours}.flatten.uniq.map(&:range).sort
100
+ timeranges = rules.flatten.uniq.map(&:range).sort
101
+
102
+ {
103
+ timeranges: timeranges,
104
+ business_timeranges: business_timeranges.uniq
105
+ }
106
+ end
107
+
108
+ def get_timeranges_for_days(from, to)
109
+ rules = get_rules_for_days(from, to)
110
+ business_timeranges = rules.select {|r| !r.business_hours}.flatten.uniq.map(&:range).sort
111
+ timeranges = rules.flatten.uniq.map(&:range).sort
112
+ {
113
+ timeranges: timeranges,
114
+ business_timeranges: business_timeranges.uniq
115
+ }
116
+ end
117
+
118
+ def get_rules_for_days(from, to)
119
+ rules = []
120
+ get_uniq_periods_for_days(from, to).each do |period|
121
+ next if ([from.yday] & period.yday_array || [to.yday] & period.yday_array).blank?
122
+ rules.push(period.rules)
123
+ end
124
+ rules.flatten
125
+ end
126
+
127
+ TempTimeframe = Struct.new(:date, :timeframe)
128
+ def get_list(days)
129
+ list = []
130
+ days.each_with_index do |day, day_index|
131
+ day.timeframes.each do |timeframe|
132
+ next if day_index == 0 && timeframe.timerange.min < TurbaChronos.current_numeric_time
133
+ list.push TempTimeframe.new(day.date, timeframe)
134
+ end
135
+ end
136
+ list
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,3 @@
1
+ module TurbaChronos
2
+ VERSION = "5.2.0"
3
+ end
@@ -0,0 +1,31 @@
1
+ def base
2
+ crowd = OpenStruct.new
3
+ crowd.periods = [
4
+ {
5
+ dates: '01/01:31/12',
6
+ rules: [
7
+ ['08:00', '10:00', 1, 1, 1, 1, 6, 6, 6],
8
+ ['10:00', '17:00', 1, 1, 1, 1, 6, 6, 6]
9
+ ]
10
+ },
11
+ {
12
+ dates: '18/05',
13
+ rules: [
14
+ ['06:00', '15:00', 3, 3, 3, 3, 3, 3, 3]
15
+ ]
16
+ },
17
+ {
18
+ dates: '01/05,25/08:28/08',
19
+ rules: [
20
+ ['08:00', '10:00', 6, 6, 6, 6, 6, 6, 6]
21
+ ]
22
+ },
23
+ {
24
+ dates: 'august,vacances_toussaint,vacances_noel',
25
+ rules: [
26
+ ['08:00', '10:00', 2, 2, 2, 2, 2, 2, 2]
27
+ ]
28
+ }
29
+ ]
30
+ crowd
31
+ end
@@ -0,0 +1,19 @@
1
+ def disney
2
+ crowd = OpenStruct.new
3
+ crowd.periods = [
4
+ {
5
+ dates: '01/01:31/12',
6
+ rules: [
7
+ ['07:00', '13:00', 4, 4, 4, 4, 4, 4, 4]
8
+ ]
9
+ },
10
+ {
11
+ dates: '03/11:30/11',
12
+ rules: [
13
+ ['08:00', '10:00', 8, 8, 8, 8, 8, 8, 8],
14
+ ['10:00', '21:00', 1, 1, 1, 1, 1, 3, 2]
15
+ ]
16
+ }
17
+ ]
18
+ crowd
19
+ end
@@ -0,0 +1,13 @@
1
+ def empty_periods
2
+ crowd = OpenStruct.new
3
+ crowd.periods = [
4
+ {
5
+ dates: '03/11:30/11',
6
+ rules: [
7
+ ['08:00', '10:00', 8, 8, 8, 8, 8, 8, 8],
8
+ ['10:00', '21:00', 1, 1, 1, 1, 1, 3, 2]
9
+ ]
10
+ }
11
+ ]
12
+ crowd
13
+ end
@@ -0,0 +1,19 @@
1
+ def future_reopen
2
+ crowd = OpenStruct.new
3
+ crowd.periods = [
4
+ {
5
+ dates: '01/01:31/12',
6
+ rules: [
7
+ ['08:00', '10:00', 6, 6, 6, 6, 6, 6, 6],
8
+ ['10:00', '17:00', 6, 6, 6, 6, 6, 6, 6]
9
+ ]
10
+ },
11
+ {
12
+ dates: '13/08:15/08',
13
+ rules: [
14
+ ['08:00', '10:00', 2, 2, 2, 2, 2, 2, 2]
15
+ ]
16
+ }
17
+ ]
18
+ crowd
19
+ end
@@ -0,0 +1,18 @@
1
+ def lcl
2
+ crowd = OpenStruct.new
3
+ crowd.periods = [
4
+ {
5
+ dates: '01/01:31/12',
6
+ rules: [
7
+ ['07:00', '08:00', 3, 3, 3, 3, 3, 6, 6],
8
+ ['08:00', '09:00', 1, 1, 1, 1, 1, 6, 6],
9
+ ['09:00', '12:00', 3, 3, 3, 3, 3, 3, 6],
10
+ ['12:00', '14:00', 1, 1, 1, 1, 1, 1, 6],
11
+ ['14:00', '17:00', 3, 3, 3, 3, 3, 1, 6],
12
+ ['17:00', '17:30', 1, 1, 1, 1, 1, 1, 6],
13
+ ['17:30', '19:00', 1, 1, 1, 1, 1, 3, 6]
14
+ ]
15
+ }
16
+ ]
17
+ crowd
18
+ end
@@ -0,0 +1,13 @@
1
+ def november_bug
2
+ crowd = OpenStruct.new
3
+ crowd.periods = [
4
+ {
5
+ dates: '01/01:31/12',
6
+ rules: [
7
+ ['12:00', '16:00', 1, 2, 2, 2, 2, 2, 2],
8
+ ['16:00', '18:00', 4, 3, 3, 3, 3, 3, 3]
9
+ ]
10
+ }
11
+ ]
12
+ crowd
13
+ end
@@ -0,0 +1,12 @@
1
+ def opened
2
+ crowd = OpenStruct.new
3
+ crowd.periods = [
4
+ {
5
+ dates: '01/01:31/12',
6
+ rules: [
7
+ ['12:00', '18:00', 7, 7, 7, 7, 7, 7, 7]
8
+ ]
9
+ }
10
+ ]
11
+ crowd
12
+ end
@@ -0,0 +1,48 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe TurbaChronos::Timeline do
4
+ before(:all) do
5
+ Timecop.freeze(Time.zone.parse("September 23 2014, 14:30").iso8601)
6
+ end
7
+
8
+ after(:all) do
9
+ Timecop.return
10
+ end
11
+
12
+ def default_timeline
13
+ Time.zone = 'Europe/Paris'
14
+ TurbaChronos.load([], Time.now.utc.iso8601, (Time.now.utc + 1.day).iso8601)
15
+ end
16
+
17
+ describe '.business_timeranges' do
18
+ it "returns the business timeranges" do
19
+ expect(default_timeline.business_timeranges).to eql([["00:00", "23:59"]])
20
+ end
21
+ end
22
+
23
+ describe '.levels' do
24
+ it "returns the levels" do
25
+ expect(default_timeline.levels).to eql([6])
26
+ end
27
+ end
28
+
29
+ describe '.days' do
30
+ it "returns the days" do
31
+ expect(default_timeline.days.count).to eql(2)
32
+ expect(default_timeline.days.first.instance_of?(TurbaChronos::Day)).to eql(true)
33
+ end
34
+ end
35
+
36
+ describe '.current_day' do
37
+ it "returns the current_day" do
38
+ expect(default_timeline.current_day.instance_of?(TurbaChronos::Day)).to eql(true)
39
+ end
40
+ end
41
+
42
+ describe '.opened?' do
43
+ it "returns boolean if the day is opened or not" do
44
+ expect(default_timeline.opened?).to eql(false)
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../fixtures/disney_fixture'
3
+
4
+ describe TurbaChronos::Timeline do
5
+ before(:all) do
6
+ Timecop.freeze(Time.zone.parse("November 02 2014, 14:30"))
7
+ from = Time.zone.parse("November 04 2014, 00:00").iso8601
8
+ to = Time.zone.parse("November 05 2014, 23:59").iso8601
9
+ @subject = TurbaChronos.load(disney.periods, from, to)
10
+ end
11
+
12
+ after(:all) do
13
+ Timecop.return
14
+ end
15
+
16
+ describe '.days' do
17
+ it "returns the days" do
18
+ expect(@subject.days.first.timeframes.count).to eql(2)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../fixtures/disney_fixture'
3
+
4
+ describe TurbaChronos::Timeline do
5
+ before(:all) do
6
+ Timecop.freeze(Time.zone.parse("November 30 2014, 14:30"))
7
+ from = Time.zone.parse("November 30 2014, 00:00").iso8601
8
+ to = Time.zone.parse("December 01 2014, 23:59").iso8601
9
+ @subject = TurbaChronos.load(disney.periods, from, to)
10
+ end
11
+
12
+ after(:all) do
13
+ Timecop.return
14
+ end
15
+
16
+ describe '.days' do
17
+ it "returns the days" do
18
+ expect(@subject.current_day.current_timeframe.level).to eql(2)
19
+ end
20
+ end
21
+ end