tod 1.5.0 → 2.0.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.
@@ -1,41 +1,55 @@
1
1
  module Tod
2
+
3
+ # Shift is a range-like class that handles wrapping around midnight.
4
+ # For example, the Shift of 2300 to 0200 would include 0100.
2
5
  class Shift
3
- attr_reader :beginning, :ending
6
+ attr_reader :beginning, :ending, :range
4
7
 
5
- def initialize(beginning, ending)
8
+ def initialize(beginning, ending, exclude_end=false)
6
9
  raise ArgumentError, "beginning can not be nil" unless beginning
7
10
  raise ArgumentError, "ending can not be nil" unless ending
11
+ unless [true, false].include? exclude_end
12
+ raise ArgumentError, "exclude_end must be true or false"
13
+ end
8
14
 
9
15
  @beginning = beginning
10
16
  @ending = ending
17
+ @exclude_end = exclude_end
18
+
19
+ normalized_ending = ending.to_i
20
+ normalized_ending += TimeOfDay::NUM_SECONDS_IN_DAY if normalized_ending < beginning.to_i
21
+
22
+ @range = Range.new(beginning.to_i, normalized_ending, @exclude_end)
23
+
11
24
  freeze # Shift instances are value objects
12
25
  end
13
26
 
14
- # Returns true if the time of day is inside the shift (inclusive range), false otherwise
27
+ # Returns true if the time of day is inside the shift, false otherwise.
15
28
  def include?(tod)
16
- if ending >= beginning
17
- tod >= beginning && tod <= ending
18
- else
19
- start_of_day = TimeOfDay.new(0,0,0)
20
- end_of_day = TimeOfDay.new(23,59,59)
21
- (tod >= beginning && tod <= end_of_day) || (tod >= start_of_day && tod <= ending)
22
- end
29
+ second = tod.to_i
30
+ second += TimeOfDay::NUM_SECONDS_IN_DAY if second < @range.first
31
+ @range.cover?(second)
32
+ end
33
+
34
+ # Returns true if ranges overlap, false otherwise.
35
+ def overlaps?(other)
36
+ a, b = [self, other].map(&:range).sort_by(&:first)
37
+ op = a.exclude_end? ? :> : :>=
38
+ a.last.send(op, b.first)
39
+ end
40
+
41
+ def contains?(shift)
42
+ self.include?(shift.beginning) && self.include?(shift.ending)
23
43
  end
24
44
 
25
45
  # Return shift duration in seconds.
26
46
  # if ending is lower than beginning this method will calculate the duration as the ending time is from the following day
27
47
  def duration
28
- if ending >= beginning
29
- (ending.to_i - beginning.to_i)
30
- else
31
- start_of_day = TimeOfDay.new(0,0,0)
32
- end_of_day = TimeOfDay.new(23,59,59)
33
- duration_day_1 = (end_of_day.to_i - beginning.to_i) + 1
34
- duration_day_2 = (ending.to_i - start_of_day.to_i)
35
- duration_day_1 + duration_day_2
36
- end
48
+ @range.last - @range.first
49
+ end
50
+
51
+ def exclude_end?
52
+ @exclude_end
37
53
  end
38
54
  end
39
55
  end
40
-
41
- Shift = Tod::Shift
@@ -0,0 +1,9 @@
1
+ module Tod
2
+ module TimeExtensions
3
+ def to_time_of_day
4
+ Tod::TimeOfDay.new hour, min, sec
5
+ end
6
+ end
7
+ end
8
+
9
+ Time.send :include, Tod::TimeExtensions
@@ -1,3 +1,3 @@
1
1
  module Tod
2
- VERSION = "1.5.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -3,5 +3,5 @@ ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
3
3
 
4
4
  ActiveRecord::Migration.create_table :orders do |t|
5
5
  t.time :time
6
- t.timestamps
7
- end
6
+ t.timestamps null: false
7
+ end
@@ -1,7 +1,9 @@
1
1
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__),'..','lib')
2
2
 
3
3
  require 'bundler/setup'
4
+ require 'active_support/time'
4
5
  require 'tod'
5
- require 'test/unit'
6
- require 'shoulda'
7
- require 'mocha/setup'
6
+ require 'tod/core_extensions'
7
+ require 'minitest/autorun'
8
+
9
+ Time.zone = "Central Time (US & Canada)"
@@ -1,48 +1,52 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
2
- require 'active_support/time'
3
2
 
4
- class TimeOfDayConversionTest < Test::Unit::TestCase
5
- should "handle TimeOfDay" do
6
- t = TimeOfDay.new(13, 56, 12)
7
- tod = TimeOfDay(t)
3
+ describe "TimeOfDay()" do
4
+ it "handles Tod::TimeOfDay" do
5
+ t = Tod::TimeOfDay.new(13, 56, 12)
6
+ tod = Tod::TimeOfDay(t)
8
7
 
9
8
  assert_equal(t, tod)
10
9
  end
11
- should "handle Time" do
10
+
11
+ it "handles Time" do
12
12
  t = Time.new(2014, 2, 27, 12, 01, 02)
13
- tod = TimeOfDay(t)
13
+ tod = Tod::TimeOfDay(t)
14
14
 
15
- assert_equal(tod, TimeOfDay.new(12, 01, 02))
15
+ assert_equal(tod, Tod::TimeOfDay.new(12, 01, 02))
16
16
  end
17
- should "handle Date" do
17
+
18
+ it "handles Date" do
18
19
  t = Date.new(2014, 2, 27)
19
- tod = TimeOfDay(t)
20
+ tod = Tod::TimeOfDay(t)
20
21
 
21
- assert_equal(tod, TimeOfDay.new(0, 0, 0))
22
+ assert_equal(tod, Tod::TimeOfDay.new(0, 0, 0))
22
23
  end
23
- should "handle DateTime" do
24
+
25
+ it "handles DateTime" do
24
26
  t = DateTime.new(2014, 2, 27, 12, 01, 02)
25
- tod = TimeOfDay(t)
27
+ tod = Tod::TimeOfDay(t)
26
28
 
27
- assert_equal(tod, TimeOfDay.new(12, 01, 02))
29
+ assert_equal(tod, Tod::TimeOfDay.new(12, 01, 02))
28
30
  end
29
- should "string" do
31
+
32
+ it "parses string" do
30
33
  t = "12:01:02"
31
- tod = TimeOfDay(t)
34
+ tod = Tod::TimeOfDay(t)
32
35
 
33
- assert_equal(tod, TimeOfDay.new(12, 01, 02))
36
+ assert_equal(tod, Tod::TimeOfDay.new(12, 01, 02))
34
37
  end
35
- should "parse 'noon'" do
38
+
39
+ it "parses 'noon'" do
36
40
  t = "noon"
37
- tod = TimeOfDay(t)
41
+ tod = Tod::TimeOfDay(t)
38
42
 
39
- assert_equal(tod, TimeOfDay.new(12, 00, 00))
43
+ assert_equal(tod, Tod::TimeOfDay.new(12, 00, 00))
40
44
  end
41
- should "parse 'midnight'" do
45
+
46
+ it "parses 'midnight'" do
42
47
  t = "midnight"
43
- tod = TimeOfDay(t)
48
+ tod = Tod::TimeOfDay(t)
44
49
 
45
- assert_equal(tod, TimeOfDay.new(0, 00, 00))
50
+ assert_equal(tod, Tod::TimeOfDay.new(0, 00, 00))
46
51
  end
47
-
48
- end
52
+ end
@@ -1,28 +1,27 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
2
- require 'active_support/time'
3
2
 
4
- class DateTest < Test::Unit::TestCase
5
- context "at" do
6
- should "accept TimeOfDay and return Time on same date" do
3
+ describe "Date extensions" do
4
+ describe "#at" do
5
+ it "accepts TimeOfDay and return Time on same date" do
7
6
  date = Date.civil 2000,1,1
8
- tod = TimeOfDay.new 8,30
9
- assert_equal Time.local(2000,1,1, 8,30), date.at(tod)
7
+ tod = Tod::TimeOfDay.new 8,30
8
+ assert_equal Time.zone.local(2000,1,1, 8,30), date.at(tod)
10
9
  end
11
10
 
12
- context "with a time zone" do
13
- should "accept TimeOfDay and TimeWithZone on same date" do
11
+ describe "with a time zone" do
12
+ it "accepts TimeOfDay and TimeWithZone on same date" do
14
13
  date = Date.civil 2000,1,1
15
- tod = TimeOfDay.new 8,30
14
+ tod = Tod::TimeOfDay.new 8,30
16
15
  time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)']
17
16
  assert_equal time_zone.local(2000,1,1, 8,30), date.at(tod, time_zone)
18
17
  end
19
18
  end
20
19
  end
21
20
 
22
- context "to_time_day" do
23
- should "be TimeOfDay" do
21
+ describe "#to_time_day" do
22
+ it "is TimeOfDay" do
24
23
  date_time = DateTime.new 2013, 9, 19, 15, 17, 34
25
- assert_equal TimeOfDay.new(15, 17, 34), date_time.to_time_of_day
24
+ assert_equal Tod::TimeOfDay.new(15, 17, 34), date_time.to_time_of_day
26
25
  end
27
26
  end
28
27
  end
@@ -1,94 +1,169 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
2
- require 'active_support/time'
3
2
 
4
- class ShiftTest < Test::Unit::TestCase
5
- context "duration" do
6
- should "return correct duration when first time is lower than the second one" do
3
+ describe "Shift" do
4
+ describe "#initialize" do
5
+ it "parses bounds" do
6
+ shift = Tod::Shift.new Tod::TimeOfDay.new(8), Tod::TimeOfDay.new(10), false
7
+ refute shift.exclude_end?
8
+
9
+ shift = Tod::Shift.new Tod::TimeOfDay.new(8), Tod::TimeOfDay.new(10), true
10
+ assert shift.exclude_end?
11
+ end
12
+ end
13
+
14
+ describe "#duration" do
15
+ it "returns correct duration when first time is lower than the second one" do
7
16
  duration_expected = 4 * 60 * 60 + 30 * 60 + 30 # 4 hours, 30 min and 30 sec later
8
- tod1 = TimeOfDay.new 8,30
9
- tod2 = TimeOfDay.new 13,00,30
10
- shift = Shift.new tod1, tod2
17
+ tod1 = Tod::TimeOfDay.new 8,30
18
+ tod2 = Tod::TimeOfDay.new 13,00,30
19
+ shift = Tod::Shift.new tod1, tod2
11
20
  duration = shift.duration
12
21
  assert_equal duration, duration_expected
13
22
  end
14
- should "return correct duration when first time is greater than the second one" do
23
+
24
+ it "returns correct duration when first time is greater than the second one" do
15
25
  duration_expected = 4 * 60 * 60 + 30 * 60 + 30 # 4 hours, 30 min and 30 sec later
16
- tod1 = TimeOfDay.new 22,30
17
- tod2 = TimeOfDay.new 3,00,30
18
- shift = Shift.new tod1, tod2
26
+ tod1 = Tod::TimeOfDay.new 22,30
27
+ tod2 = Tod::TimeOfDay.new 3,00,30
28
+ shift = Tod::Shift.new tod1, tod2
19
29
  duration = shift.duration
20
30
  assert_equal duration, duration_expected
21
31
  end
22
- should "be zero when both times are equal" do
23
- tod1 = TimeOfDay.new 3,00,30
24
- shift = Shift.new tod1, tod1
32
+
33
+ it "is zero when both times are equal" do
34
+ tod1 = Tod::TimeOfDay.new 3,00,30
35
+ shift = Tod::Shift.new tod1, tod1
25
36
  duration = shift.duration
26
37
  assert_equal duration, 0
27
38
  end
28
39
  end
29
40
 
30
- context "include?" do
41
+ describe "overlaps?" do
42
+ it "is true when shifts overlap" do
43
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(12), Tod::TimeOfDay.new(18))
44
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(13), Tod::TimeOfDay.new(15))
45
+ assert shift1.overlaps?(shift2)
46
+ end
47
+
48
+ it "is false when shifts don't overlap" do
49
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(1), Tod::TimeOfDay.new(5))
50
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(9), Tod::TimeOfDay.new(12))
51
+ refute shift1.overlaps?(shift2)
52
+ end
53
+
54
+ it "is true when shifts touch with inclusive end" do
55
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(1), Tod::TimeOfDay.new(5))
56
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(5), Tod::TimeOfDay.new(12))
57
+ assert shift1.overlaps?(shift2)
58
+ end
59
+
60
+ it "is false when shifts touch with exclusive end" do
61
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(1), Tod::TimeOfDay.new(5), true)
62
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(5), Tod::TimeOfDay.new(12), true)
63
+ refute shift1.overlaps?(shift2)
64
+ end
65
+ end
66
+
67
+ describe "contains?" do
68
+ it "is true when one shift contains another" do
69
+ outside = Tod::Shift.new(Tod::TimeOfDay.new(12), Tod::TimeOfDay.new(18))
70
+ inside = Tod::Shift.new(Tod::TimeOfDay.new(13), Tod::TimeOfDay.new(15))
71
+ assert outside.contains?(inside)
72
+ end
73
+
74
+ it "is false when a shift is contained by another" do
75
+ outside = Tod::Shift.new(Tod::TimeOfDay.new(12), Tod::TimeOfDay.new(18))
76
+ inside = Tod::Shift.new(Tod::TimeOfDay.new(13), Tod::TimeOfDay.new(15))
77
+ refute inside.contains?(outside)
78
+ end
79
+
80
+ it "is false when shifts don't even overlap" do
81
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(12), Tod::TimeOfDay.new(15))
82
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(18), Tod::TimeOfDay.new(19))
83
+ refute shift1.contains?(shift2)
84
+ end
85
+ end
86
+
87
+ describe "#include?" do
31
88
  # |------------------------|--------T1----V----T2----|------------------------|
32
- should "be true when value is between ToDs and boths tods are in the same day" do
33
- tod1 = TimeOfDay.new 8
34
- tod2 = TimeOfDay.new 16
35
- value = TimeOfDay.new 12
36
- shift = Shift.new tod1, tod2
37
- assert_equal shift.include?(value), true
89
+ it "is true when value is between ToDs and boths tods are in the same day" do
90
+ tod1 = Tod::TimeOfDay.new 8
91
+ tod2 = Tod::TimeOfDay.new 16
92
+ value = Tod::TimeOfDay.new 12
93
+ shift = Tod::Shift.new tod1, tod2
94
+ assert shift.include?(value)
38
95
  end
39
96
 
40
97
  # |------------------T1----|-------V----------T2-----|------------------------|
41
- should "be true when value is on second day between ToDs and start ToD is in a different day" do
42
- tod1 = TimeOfDay.new 20
43
- tod2 = TimeOfDay.new 15
44
- value = TimeOfDay.new 12
45
- shift = Shift.new tod1, tod2
46
- assert_equal shift.include?(value), true
98
+ it "is true when value is on second day between ToDs and start ToD is in a different day" do
99
+ tod1 = Tod::TimeOfDay.new 20
100
+ tod2 = Tod::TimeOfDay.new 15
101
+ value = Tod::TimeOfDay.new 12
102
+ shift = Tod::Shift.new tod1, tod2
103
+ assert shift.include?(value)
47
104
  end
48
105
 
49
106
  # |------------------T1--V-|------------------T2-----|------------------------|
50
- should "be true when value is on first day between ToDs and start ToD is in a different day" do
51
- tod1 = TimeOfDay.new 20
52
- tod2 = TimeOfDay.new 15
53
- value = TimeOfDay.new 22
54
- shift = Shift.new tod1, tod2
55
- assert_equal shift.include?(value), true
107
+ it "is true when value is on first day between ToDs and start ToD is in a different day" do
108
+ tod1 = Tod::TimeOfDay.new 20
109
+ tod2 = Tod::TimeOfDay.new 15
110
+ value = Tod::TimeOfDay.new 22
111
+ shift = Tod::Shift.new tod1, tod2
112
+ assert shift.include?(value)
56
113
  end
57
114
 
58
115
  # |------------------------|--------T1----------V----|----T2------------------|
59
- should "be true when value is on first day between ToDs and end ToD is in a different day" do
60
- tod1 = TimeOfDay.new 16
61
- tod2 = TimeOfDay.new 4
62
- value = TimeOfDay.new 20
63
- shift = Shift.new tod1, tod2
64
- assert_equal shift.include?(value), true
116
+ it "is true when value is on first day between ToDs and end ToD is in a different day" do
117
+ tod1 = Tod::TimeOfDay.new 16
118
+ tod2 = Tod::TimeOfDay.new 4
119
+ value = Tod::TimeOfDay.new 20
120
+ shift = Tod::Shift.new tod1, tod2
121
+ assert shift.include?(value)
65
122
  end
66
123
 
67
124
  # |------------------------|--------T1---------------|--V---T2----------------|
68
- should "be true when value is on second day between ToDs and end ToD is in a different day" do
69
- tod1 = TimeOfDay.new 16
70
- tod2 = TimeOfDay.new 4
71
- value = TimeOfDay.new 2
72
- shift = Shift.new tod1, tod2
73
- assert_equal shift.include?(value), true
125
+ it "is true when value is on second day between ToDs and end ToD is in a different day" do
126
+ tod1 = Tod::TimeOfDay.new 16
127
+ tod2 = Tod::TimeOfDay.new 4
128
+ value = Tod::TimeOfDay.new 2
129
+ shift = Tod::Shift.new tod1, tod2
130
+ assert shift.include?(value)
74
131
  end
75
132
 
76
133
  # |------------------------|--------T1-----T2----V---|------------------------|
77
- should "be false when value is after second ToD" do
78
- tod1 = TimeOfDay.new 10
79
- tod2 = TimeOfDay.new 16
80
- value = TimeOfDay.new 20
81
- shift = Shift.new tod1, tod2
82
- assert_equal shift.include?(value), false
134
+ it "is false when value is after second ToD" do
135
+ tod1 = Tod::TimeOfDay.new 10
136
+ tod2 = Tod::TimeOfDay.new 16
137
+ value = Tod::TimeOfDay.new 20
138
+ shift = Tod::Shift.new tod1, tod2
139
+ refute shift.include?(value)
83
140
  end
84
141
 
85
142
  # |------------------------|--V-----T1-----T2--------|------------------------|
86
- should "be false when value is before first ToD" do
87
- tod1 = TimeOfDay.new 10
88
- tod2 = TimeOfDay.new 16
89
- value = TimeOfDay.new 8
90
- shift = Shift.new tod1, tod2
91
- assert_equal shift.include?(value), false
143
+ it "is false when value is before first ToD" do
144
+ tod1 = Tod::TimeOfDay.new 10
145
+ tod2 = Tod::TimeOfDay.new 16
146
+ value = Tod::TimeOfDay.new 8
147
+ shift = Tod::Shift.new tod1, tod2
148
+ refute shift.include?(value)
149
+ end
150
+
151
+ # |------------------------|--------T1-----T2V-------|------------------------|
152
+ it "is false when value is equal to second ToD and Shift is ending exclusive" do
153
+ tod1 = Tod::TimeOfDay.new 10
154
+ tod2 = Tod::TimeOfDay.new 16
155
+ value = Tod::TimeOfDay.new 16
156
+ shift = Tod::Shift.new tod1, tod2, true
157
+ refute shift.include?(value)
158
+ end
159
+
160
+ # |------------------------|--------T1-----T2V-------|------------------------|
161
+ it "is true when value is equal to second ToD and Shift is ending inclusive" do
162
+ tod1 = Tod::TimeOfDay.new 10
163
+ tod2 = Tod::TimeOfDay.new 16
164
+ value = Tod::TimeOfDay.new 16
165
+ shift = Tod::Shift.new tod1, tod2, false
166
+ assert shift.include?(value)
92
167
  end
93
168
  end
94
169
  end