turba_chronos 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +68 -0
- data/Rakefile +11 -0
- data/lib/turba_chronos.rb +31 -0
- data/lib/turba_chronos/core_ext/range.rb +5 -0
- data/lib/turba_chronos/day.rb +71 -0
- data/lib/turba_chronos/period.rb +44 -0
- data/lib/turba_chronos/period_converter.rb +69 -0
- data/lib/turba_chronos/periods.rb +43 -0
- data/lib/turba_chronos/rule.rb +52 -0
- data/lib/turba_chronos/stored_periods.rb +68 -0
- data/lib/turba_chronos/timeline.rb +139 -0
- data/lib/turba_chronos/version.rb +3 -0
- data/spec/fixtures/base_fixture.rb +31 -0
- data/spec/fixtures/disney_fixture.rb +19 -0
- data/spec/fixtures/empty_periods_fixture.rb +13 -0
- data/spec/fixtures/future_reopen_fixture.rb +19 -0
- data/spec/fixtures/lcl_fixture.rb +18 -0
- data/spec/fixtures/november_bug_fixture.rb +13 -0
- data/spec/fixtures/opened_fixture.rb +12 -0
- data/spec/lib/alt_timeline_spec.rb +48 -0
- data/spec/lib/disney_2_spec.rb +21 -0
- data/spec/lib/disney_3_spec.rb +21 -0
- data/spec/lib/disney_spec.rb +21 -0
- data/spec/lib/empty_periods_spec.rb +21 -0
- data/spec/lib/future_reopen_spec.rb +21 -0
- data/spec/lib/lcl_spec.rb +28 -0
- data/spec/lib/november_bug_spec.rb +20 -0
- data/spec/lib/opened_spec.rb +21 -0
- data/spec/lib/timeline_spec.rb +70 -0
- data/spec/spec_helper.rb +8 -0
- data/test/fixtures/base_fixture.rb +31 -0
- data/test/test_helper.rb +6 -0
- data/test/test_periods.rb +16 -0
- data/test/test_periods_converter.rb +62 -0
- data/test/test_rule.rb +33 -0
- data/test/test_timeline.rb +51 -0
- data/turba_chronos.gemspec +30 -0
- metadata +236 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 045e46b1f23ed3f38ce1781e8f8e97d2598e0f1a
|
4
|
+
data.tar.gz: 0b904b08a2cc996436f7af39acb24cf6dc5783da
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 51a32b800f6074844aa3fec0d365d3d9ea9bedad2365e89bc239bdf6603bc7eab5e74fa06f375f9a009de6cf9dcac45a19987ac31eb7d0e308530270a7e5d89f
|
7
|
+
data.tar.gz: ebc555d435e2082bdf28985f8431c04cb0d17ae07c60a19867ad493c7155995d1789590976ce77ef73202fab2e1e7c2d0c992a28d1bf5762fb8eaf5a8db78b37
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.0
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Joffrey JAFFEUX
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# TurbaChronos
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'turba_chronos'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install turba_chronos
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
periods_for_days
|
43
|
+
|
44
|
+
period_for_day
|
45
|
+
|
46
|
+
|
47
|
+
period_1
|
48
|
+
period_2
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'active_support/all'
|
3
|
+
require 'turba_chronos/core_ext/range'
|
4
|
+
require 'turba_chronos/version'
|
5
|
+
require 'turba_chronos/timeline'
|
6
|
+
require 'turba_chronos/day'
|
7
|
+
require 'turba_chronos/periods'
|
8
|
+
require 'turba_chronos/period'
|
9
|
+
require 'turba_chronos/period_converter'
|
10
|
+
require 'turba_chronos/stored_periods'
|
11
|
+
require 'turba_chronos/rule'
|
12
|
+
|
13
|
+
module TurbaChronos
|
14
|
+
FULL_DAY_TIMERANGE = ['00:00', '23:59']
|
15
|
+
|
16
|
+
def self.load(periods, from, to, timezone = 'Europe/Paris')
|
17
|
+
Time.zone = timezone
|
18
|
+
TurbaChronos.current_numeric_time = Time.zone.now.strftime("%k%M").to_i
|
19
|
+
|
20
|
+
periods = periods.map!(&:with_indifferent_access)
|
21
|
+
@timeline = Timeline.new(periods, Time.parse(from).utc, Time.parse(to).utc)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.current_numeric_time
|
25
|
+
@current_numeric_time
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.current_numeric_time=(current_numeric_time)
|
29
|
+
@current_numeric_time = current_numeric_time
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module TurbaChronos
|
2
|
+
class Day
|
3
|
+
attr_reader :beginning_of_day
|
4
|
+
def initialize(beginning_of_day, periods, timeranges_for_days)
|
5
|
+
@beginning_of_day = beginning_of_day.to_time
|
6
|
+
@rules = get_rules_for_day(periods)
|
7
|
+
@timeranges_for_days = timeranges_for_days
|
8
|
+
end
|
9
|
+
|
10
|
+
def date
|
11
|
+
@date ||= @beginning_of_day.to_datetime.iso8601
|
12
|
+
end
|
13
|
+
|
14
|
+
def opened?
|
15
|
+
current_timeframe.level != 6
|
16
|
+
end
|
17
|
+
|
18
|
+
def timeframes
|
19
|
+
@timeframes ||= get_timeframes(:business_timeranges)
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_timeframe
|
23
|
+
get_timeframes(:timeranges).each do |timeframe|
|
24
|
+
return timeframe if timeframe.timerange === TurbaChronos.current_numeric_time
|
25
|
+
end
|
26
|
+
|
27
|
+
range = (Time.now.utc.beginning_of_hour.strftime("%k%M").to_i..Time.now.utc.end_of_hour.strftime("%k%M").to_i)
|
28
|
+
return TempTimerange.new(range, 6)
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_timeframe_index
|
32
|
+
timeframes.map {|x| x.timerange}.index(current_timeframe.timerange)
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def get_rules_for_day(periods)
|
38
|
+
periods.each do |period|
|
39
|
+
next if ([@beginning_of_day.yday] & period.yday_array).blank?
|
40
|
+
return period.rules
|
41
|
+
end
|
42
|
+
raise "Didn’t find rules for this day : #{@beginning_of_day}"
|
43
|
+
end
|
44
|
+
|
45
|
+
TempTimerange = Struct.new(:timerange, :level)do
|
46
|
+
def start_time
|
47
|
+
string_time(timerange.min)
|
48
|
+
end
|
49
|
+
|
50
|
+
def end_time
|
51
|
+
string_time(timerange.max)
|
52
|
+
end
|
53
|
+
|
54
|
+
def string_time(numeric_time)
|
55
|
+
numeric_time.to_s.rjust(4, '0').insert(2, ':')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
def get_timeframes(type)
|
59
|
+
timeframes = []
|
60
|
+
@timeranges_for_days[type].each_with_index do |timerange, index|
|
61
|
+
@rules.each do |rule|
|
62
|
+
if rule.start_time.integer <= timerange.min && rule.end_time.integer >= timerange.max
|
63
|
+
level = rule.wdays[@beginning_of_day.to_datetime.cwday - 1]
|
64
|
+
timeframes.push(TempTimerange.new(timerange, level))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
timeframes
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module TurbaChronos
|
2
|
+
class Period
|
3
|
+
attr_accessor :rules
|
4
|
+
attr_accessor :start_date
|
5
|
+
attr_accessor :end_date
|
6
|
+
|
7
|
+
def initialize(from, to, rules)
|
8
|
+
@rules = complete_rules(rules)
|
9
|
+
@start_date = from
|
10
|
+
@end_date = to.month < from.month ? to.next_year : to
|
11
|
+
end
|
12
|
+
|
13
|
+
def distance
|
14
|
+
@distance ||= end_yday - start_yday
|
15
|
+
end
|
16
|
+
|
17
|
+
def timerange
|
18
|
+
@timerange ||= @rules.map {|rule| rule.range.string_time_array}
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_yday
|
22
|
+
@start_yday ||= @start_date.yday
|
23
|
+
end
|
24
|
+
|
25
|
+
def end_yday
|
26
|
+
@end_yday ||= @end_date.yday
|
27
|
+
end
|
28
|
+
|
29
|
+
def yday_array
|
30
|
+
@yday_array ||= (start_yday..end_yday).to_a
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def complete_rules(rules)
|
36
|
+
completed_rules = rules.map {|rule| Rule.new(rule)}
|
37
|
+
ranges = completed_rules.map(&:range)
|
38
|
+
uniq_times = ranges.each_with_object([]) { |r,a| a << r.first << r.last }.uniq.sort
|
39
|
+
completed_rules.prepend(Rule.new([FULL_DAY_TIMERANGE.first, completed_rules.first.start_time.text, *[6]*7], true)) if uniq_times[0] != 0
|
40
|
+
completed_rules.push(Rule.new([completed_rules.last.end_time.text, FULL_DAY_TIMERANGE.last, *[6]*7], true)) if uniq_times[-1] != 2359
|
41
|
+
completed_rules
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module TurbaChronos
|
2
|
+
class PeriodConverter
|
3
|
+
Bounds = Struct.new(:from, :to)
|
4
|
+
|
5
|
+
def initialize(dates)
|
6
|
+
raise ArgumentError if dates.empty?
|
7
|
+
@dates = dates
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse
|
11
|
+
return days_parser(*@dates.split(':')) if @dates.include?(':')
|
12
|
+
return day_parser(*@dates.split('/')) if @dates.include?('/')
|
13
|
+
return month_parser(@dates) if month_names.include?(@dates)
|
14
|
+
return months_parser(@dates.split('-')) if @dates.include?('-')
|
15
|
+
return stored_period_parser(@dates)
|
16
|
+
raise ArgumentError
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def month_names
|
22
|
+
@month_names ||= Date::MONTHNAMES.compact.map(&:downcase)
|
23
|
+
end
|
24
|
+
|
25
|
+
def stored_period_parser(stored_period_name)
|
26
|
+
stored_period_dates = stored_periods.fetch(stored_period_name.to_sym)
|
27
|
+
dates = []
|
28
|
+
stored_period_dates.each do |date|
|
29
|
+
dates.push(day_parser(*date[0].split('/'))) if date.count == 1
|
30
|
+
dates.push(days_parser(*date)) if date.count == 2
|
31
|
+
end
|
32
|
+
dates.flatten
|
33
|
+
end
|
34
|
+
|
35
|
+
def stored_periods
|
36
|
+
@stored_periods ||= TurbaChronos::StoredPeriods.all
|
37
|
+
end
|
38
|
+
|
39
|
+
def days_parser(first_day, second_day)
|
40
|
+
first_day = first_day.split('/')
|
41
|
+
second_day = second_day.split('/')
|
42
|
+
year = Time.now.utc.year
|
43
|
+
first_parsed_day = Time.local(year, first_day[1], first_day[0]).utc
|
44
|
+
second_parsed_day = Time.local(year, second_day[1], second_day[0]).utc
|
45
|
+
if second_parsed_day < first_parsed_day
|
46
|
+
second_parsed_day = second_parsed_day.next_year
|
47
|
+
end
|
48
|
+
|
49
|
+
[Bounds.new(first_parsed_day, second_parsed_day)]
|
50
|
+
end
|
51
|
+
|
52
|
+
def day_parser(day, month)
|
53
|
+
parsed_day = Time.local(Time.now.utc.year, month, day).utc
|
54
|
+
[Bounds.new(parsed_day, parsed_day)]
|
55
|
+
end
|
56
|
+
|
57
|
+
def months_parser(months)
|
58
|
+
from = Time.parse(months[0]).utc
|
59
|
+
to = Time.parse(months[1]).utc.end_of_month
|
60
|
+
raise ArgumentError if from > to
|
61
|
+
[Bounds.new(from, to)]
|
62
|
+
end
|
63
|
+
|
64
|
+
def month_parser(month)
|
65
|
+
parsed_month = Time.parse(month).utc
|
66
|
+
[Bounds.new(parsed_month, parsed_month.end_of_month)]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module TurbaChronos
|
2
|
+
class Periods
|
3
|
+
|
4
|
+
def initialize(periods)
|
5
|
+
@raw_periods = raw_periods_from_dates(periods)
|
6
|
+
end
|
7
|
+
|
8
|
+
def raw_periods
|
9
|
+
@raw_periods
|
10
|
+
end
|
11
|
+
|
12
|
+
def complete
|
13
|
+
start_year = Time.now.utc.beginning_of_year
|
14
|
+
end_year = Time.now.utc.end_of_year
|
15
|
+
|
16
|
+
@raw_periods.map! do |period|
|
17
|
+
if period[1].year > period[0].year
|
18
|
+
end_date = Time.local(Time.now.utc.year, period[1].month, period[1].day).utc
|
19
|
+
[
|
20
|
+
Period.new(start_year, end_date, period[2]),
|
21
|
+
Period.new(period[0], end_year, period[2])
|
22
|
+
]
|
23
|
+
else
|
24
|
+
[Period.new(period[0], period[1], period[2])]
|
25
|
+
end
|
26
|
+
end.flatten!.sort_by!(&:distance)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def raw_periods_from_dates(periods)
|
32
|
+
raw_periods = []
|
33
|
+
periods.each do |period|
|
34
|
+
period[:dates].each do |dates|
|
35
|
+
PeriodConverter.new(dates).parse.each do |date|
|
36
|
+
raw_periods.push([date.from, date.to, period[:rules]])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
raw_periods
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module TurbaChronos
|
2
|
+
class Rule
|
3
|
+
attr_accessor :start_time
|
4
|
+
attr_accessor :end_time
|
5
|
+
attr_accessor :range
|
6
|
+
attr_accessor :business_hours
|
7
|
+
|
8
|
+
def initialize(rule, business_hours=false)
|
9
|
+
@business_hours = business_hours
|
10
|
+
if rule.is_a?(Array)
|
11
|
+
@wdays = rule[2..-2]
|
12
|
+
self.start_time = rule[0]
|
13
|
+
self.end_time = rule[1]
|
14
|
+
else
|
15
|
+
@wdays = [rule[:mo], rule[:tu], rule[:we], rule[:th], rule[:fr], rule[:sa], rule[:su]]
|
16
|
+
self.start_time = rule[:s]
|
17
|
+
self.end_time = rule[:e]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def min
|
22
|
+
range.min
|
23
|
+
end
|
24
|
+
|
25
|
+
def max
|
26
|
+
range.max
|
27
|
+
end
|
28
|
+
|
29
|
+
def start_time=(start_time)
|
30
|
+
@start_time = text_time_to_hash(start_time)
|
31
|
+
end
|
32
|
+
|
33
|
+
def end_time=(end_time)
|
34
|
+
@end_time = text_time_to_hash(end_time)
|
35
|
+
end
|
36
|
+
|
37
|
+
def range
|
38
|
+
(start_time.integer..end_time.integer)
|
39
|
+
end
|
40
|
+
|
41
|
+
def wdays
|
42
|
+
@cachewdays ||= @wdays.map(&:to_i)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
TextTime = Struct.new(:text, :integer)
|
48
|
+
def text_time_to_hash(text_time)
|
49
|
+
TextTime.new(text_time, text_time.gsub(':', '').to_i)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|