tod 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0e1df7c0f812d7e18d6d9b10c256f2e26e63268c
4
- data.tar.gz: f01a512e048fa9087ab1b89376a2f6a49574357f
2
+ SHA256:
3
+ metadata.gz: 8986b140f4dcc736d253b188cd5f9a46a72110f38887cd6e8ff93ecee823c438
4
+ data.tar.gz: 95d31c83abc1264946bf2ce6aa6ba6fac45dcaeca1362b76a22d54eab27f402f
5
5
  SHA512:
6
- metadata.gz: cf81e8e52153b7e894d0a970a88c6da2fe94dbabf984cd289be160b7ab1eb43ce78e6c991c0f833ac25ebc818a7950deae44d19610a1f66081ba1998dae3bbd3
7
- data.tar.gz: d6665499e05b78076fab42c5dfe4b67c94750ad71fc722384f51b7c97aad9b6fc78fc3b2e9906d3af273f66c769bdd73bce956cb206f7a4b63209cd8237d43d0
6
+ metadata.gz: 2d1c3b50deb1df502928666b38e113fb7d58b4a25c140119bac8155ad3ff3add0689cffba810b7bdd6ab1461493838873a839ac259895630210e47679ae9ef89
7
+ data.tar.gz: 98a76ddcb2b8c866f602efe1def27c236b88ffcc6bbb12812580794113dc964d5b6df1bd95b0f055a48e9e95ca4b69ccf3dea93b20f866ca72be7932596e1aaf
data/.gitignore CHANGED
@@ -4,3 +4,5 @@ pkg/*
4
4
  nbproject
5
5
  *.swp
6
6
  .rvmrc
7
+ vendor/
8
+ .idea
data/.travis.yml CHANGED
@@ -1,11 +1,3 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.0
4
- - 2.1.5
5
- - 2.0.0
6
- - 1.9.3
7
- gemfile:
8
- - gemfiles/3.2.gemfile
9
- - gemfiles/4.0.gemfile
10
- - gemfiles/4.1.gemfile
11
- - gemfiles/4.2.gemfile
3
+ - 2.6.5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ # 3.0.0 (March 6, 2021)
2
+
3
+ * Support and require Rails 6
4
+
5
+ # 2.2.0 (October 10, 2018)
6
+
7
+ * Add string formatting compatible with Rails (Tate Johnson)
8
+ * Add ability to use ActiveRecord's attribute API (Brent Wheeldon)
9
+ * Add method for use in Rails database quoting (Ben Jackson)
10
+
11
+ # 2.1.1 (April 14, 2017)
12
+
13
+ * Fix serialize Ruby Time to Tod::TimeOfDay (Ryan Dick)
14
+ * Fix TimeOfDay.from_second_of_day when passed float (Jack Christensen)
15
+ * Fix Rails 5 multi-param assignment (Miklos Fazekas)
16
+
17
+ # 2.1.0 (May 9, 2016)
18
+
19
+ * Fix date extensions requiring date (ambirdsall)
20
+ * Add subtraction to TimeOfDay (Hiroki Shirai)
21
+ * Add equality comparison for shifts (Greg Beech)
22
+ * Add arel_extensions for TimeOfDay (Paul Tyng)
23
+ * Support for shifts that span to other days (kennyeni)
24
+
25
+ # 2.0.2 (May 21, 2015)
26
+
27
+ * Fix ActiveRecord serialization when core extensions not loaded
28
+
1
29
  # 2.0.1 (May 8, 2015)
2
30
 
3
31
  * Fix Tod::TimeOfDay() without core extensions
data/Gemfile.lock CHANGED
@@ -1,50 +1,52 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tod (2.0.0)
4
+ tod (3.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- activemodel (4.2.0)
10
- activesupport (= 4.2.0)
11
- builder (~> 3.1)
12
- activerecord (4.2.0)
13
- activemodel (= 4.2.0)
14
- activesupport (= 4.2.0)
15
- arel (~> 6.0)
16
- activesupport (4.2.0)
17
- i18n (~> 0.7)
18
- json (~> 1.7, >= 1.7.7)
19
- minitest (~> 5.1)
20
- thread_safe (~> 0.3, >= 0.3.4)
21
- tzinfo (~> 1.1)
22
- arel (6.0.0)
23
- builder (3.2.2)
24
- coderay (1.1.0)
25
- i18n (0.7.0)
26
- json (1.8.2)
27
- method_source (0.8.2)
28
- minitest (5.5.1)
29
- pry (0.10.1)
30
- coderay (~> 1.1.0)
31
- method_source (~> 0.8.1)
32
- slop (~> 3.4)
33
- rake (10.4.2)
34
- slop (3.6.0)
35
- sqlite3 (1.3.10)
36
- thread_safe (0.3.4)
37
- tzinfo (1.2.2)
38
- thread_safe (~> 0.1)
9
+ activemodel (6.1.3)
10
+ activesupport (= 6.1.3)
11
+ activerecord (6.1.3)
12
+ activemodel (= 6.1.3)
13
+ activesupport (= 6.1.3)
14
+ activesupport (6.1.3)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (>= 1.6, < 2)
17
+ minitest (>= 5.1)
18
+ tzinfo (~> 2.0)
19
+ zeitwerk (~> 2.3)
20
+ byebug (11.1.3)
21
+ coderay (1.1.3)
22
+ concurrent-ruby (1.1.8)
23
+ i18n (1.8.9)
24
+ concurrent-ruby (~> 1.0)
25
+ method_source (1.0.0)
26
+ minitest (5.14.4)
27
+ pry (0.13.1)
28
+ coderay (~> 1.1)
29
+ method_source (~> 1.0)
30
+ pry-byebug (3.9.0)
31
+ byebug (~> 11.0)
32
+ pry (~> 0.13.0)
33
+ rake (13.0.3)
34
+ sqlite3 (1.4.2)
35
+ tzinfo (2.0.4)
36
+ concurrent-ruby (~> 1.0)
37
+ zeitwerk (2.4.2)
39
38
 
40
39
  PLATFORMS
41
40
  ruby
42
41
 
43
42
  DEPENDENCIES
44
- activerecord (>= 3.0.0)
43
+ activerecord (>= 6.0.0)
45
44
  minitest
46
- pry
45
+ pry-byebug
47
46
  rake
48
47
  sqlite3
49
48
  tod!
50
49
  tzinfo
50
+
51
+ BUNDLED WITH
52
+ 2.0.2
data/README.markdown CHANGED
@@ -54,6 +54,12 @@ parsable.
54
54
  Tod::TimeOfDay.try_parse "3:30pm" # => 15:30:00
55
55
  Tod::TimeOfDay.try_parse "foo" # => nil
56
56
 
57
+ You can also give a block to parse to handle special input with your own logic.
58
+
59
+ Tod::TimeOfDay.parse "25" do |time_string|
60
+ Tod::TimeOfDay.new(time_string.to_i % 24)
61
+ end # => 01:00:00
62
+
57
63
  Values can be tested with Tod::TimeOfDay.parsable? to see if they can be parsed.
58
64
 
59
65
  Tod::TimeOfDay.parsable? "3:30pm" # => true
@@ -62,7 +68,7 @@ Values can be tested with Tod::TimeOfDay.parsable? to see if they can be parsed.
62
68
  Adding or subtracting time
63
69
  -----------------------------
64
70
 
65
- Seconds can be added to or subtracted Tod::TimeOfDay objects. Time correctly wraps
71
+ Seconds can be added to or subtracted from Tod::TimeOfDay objects. Time correctly wraps
66
72
  around midnight.
67
73
 
68
74
  Tod::TimeOfDay.new(8) + 3600 # => 09:00:00
@@ -89,10 +95,33 @@ Format strings are passed to Time#strftime.
89
95
  Tod::TimeOfDay.new(17,15).strftime("%I:%M %p") # => "05:15 PM"
90
96
  Tod::TimeOfDay.new(22,5,15).strftime("%I:%M:%S %p") # => "10:05:15 PM"
91
97
 
98
+ Or a Rails style `to_formatted_s` is aliased to `to_s`.
99
+
100
+ Tod::TimeOfDay.new(8,30).to_s(:short) # => "8:30 am"
101
+
102
+ Or [i18n](https://github.com/svenfuchs/i18n) in a Rails ERB view.
103
+
104
+ <%= l Tod::TimeOfDay.new(8, 30), format: :short %>
105
+
106
+ Add new formatters to `Tod::TimeOfDay::FORMATS`.
107
+
108
+ Tod::TimeOfDay::FORMATS[:seconds_only] = "%S"
109
+ Tod::TimeOfDay.new(8,30,57).to_s(:seconds_only) # => "57"
110
+
111
+ Rounding
112
+ ----------
113
+
114
+ Round to the given nearest number of seconds.
115
+
116
+ Tod::TimeOfDay.new(8,15,31).round(5) # => "08:15:30"
117
+ Tod::TimeOfDay.new(8,15,34).round(60) # => "08:16:00"
118
+ Tod::TimeOfDay.new(8,02,29).round(300) # => "08:00:00"
119
+
92
120
  Convenience methods for dates and times
93
121
  ---------------------------------------
94
122
 
95
- Pass a date to Tod::TimeOfDay#on and it will return a time with that date and time.
123
+ Pass a date to Tod::TimeOfDay#on and it will return a time with that date and time,
124
+ in the time zone of the ruby runtime (`Time.now.zone`).
96
125
 
97
126
  tod = Tod::TimeOfDay.new 8, 30 # => 08:30:00
98
127
  tod.on Date.today # => 2010-12-29 08:30:00 -0600
@@ -184,16 +213,29 @@ Contains?
184
213
  Rails Time Zone Support
185
214
  =======================
186
215
 
187
- If Rails time zone support is loaded, Date#on and Tod::TimeOfDay#at will automatically use Time.zone.
216
+ If Rails time zone support is loaded, Date#on and Tod::TimeOfDay#at (when given a Date) will automatically use Time.zone.
188
217
 
189
- Active Record Serializable Attribute Support
218
+ When Tod::TimeOfDay#on is given a `Time` or `Time`-like object like `ActiveSupport::TimeWithZone`,
219
+ Tod will ignore the specified timezone and return the time on that date in UTC. In order to
220
+ produce an object with the correct time and time zone, pass in an
221
+ `ActiveSupport::TimeZone` object. Date#at has analogous behavior.
222
+
223
+ time = Time.now.in_time_zone("US/Eastern") # => Mon, 24 Sep 2018 05:07:23 EDT -04:00
224
+ tod.on time # => Mon, 24 Sep 2018 08:30:00 UTC +00:00
225
+ tod.on time, time.time_zone # => Mon, 24 Sep 2018 08:30:00 EDT -04:00
226
+ tod.on time, Time.find_zone!("US/Mountain") # => Mon, 24 Sep 2018 08:30:00 MDT -06:00
227
+ Date.tomorrow.at tod, Time.find_zone!("US/Mountain") # => Tue, 25 Sep 2018 08:30:00 MDT -06:00
228
+
229
+ ActiveRecord Attribute Support
190
230
  =======================
191
- Tod::TimeOfDay implements a custom serialization contract for ActiveRecord serialize which allows to store Tod::TimeOfDay directly
231
+ Tod::TimeOfDay can be used as an ActiveRecord attribute to store Tod::TimeOfDay directly
192
232
  in a column of the time type.
233
+
193
234
  Example:
235
+
194
236
  ```ruby
195
237
  class Order < ActiveRecord::Base
196
- serialize :time, Tod::TimeOfDay
238
+ attribute :time, :time_only
197
239
  end
198
240
  order = Order.create(time: Tod::TimeOfDay.new(9,30))
199
241
  order.time # => 09:30:00
@@ -241,10 +283,10 @@ Compatibility
241
283
 
242
284
  [![Build Status](https://travis-ci.org/jackc/tod.png)](https://travis-ci.org/jackc/tod)
243
285
 
244
- Tod is compatible with Ruby 1.9.3, 2.0.0, 2.1.8, and 2.2.0. It is tested against Rails 3.2, 4.0, 4.1, 4.2.
286
+ Tod is tested against Ruby 2.6.x and Rails 6.x.
245
287
 
246
288
 
247
289
  License
248
290
  =======
249
291
 
250
- Copyright (c) 2010-2015 Jack Christensen, released under the MIT license
292
+ Copyright (c) 2010-2021 Jack Christensen, released under the MIT license
data/lib/tod.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  require 'tod/time_of_day'
2
2
  require 'tod/shift'
3
3
  require 'tod/conversions'
4
+
5
+ require 'tod/railtie' if defined?(Rails)
@@ -1,5 +1,5 @@
1
1
  module Tod
2
- def TimeOfDay(obj_or_string)
2
+ def TimeOfDay(obj_or_string, &block)
3
3
  if obj_or_string.is_a?(TimeOfDay)
4
4
  obj_or_string
5
5
  elsif obj_or_string.respond_to?(:to_time_of_day)
@@ -9,7 +9,7 @@ module Tod
9
9
  elsif obj_or_string.is_a?(Date)
10
10
  TimeOfDay.new 0
11
11
  else
12
- TimeOfDay.parse(obj_or_string)
12
+ TimeOfDay.parse(obj_or_string, &block)
13
13
  end
14
14
  end
15
15
 
@@ -1,3 +1,5 @@
1
+ require 'date'
2
+
1
3
  module Tod
2
4
  module DateExtensions
3
5
  # Returns a local Time instance with this date and time_of_day
@@ -0,0 +1,12 @@
1
+ require "active_model/type"
2
+ require "active_record/type"
3
+ require "tod/time_of_day_type"
4
+
5
+ module Tod
6
+ class Railtie < Rails::Railtie
7
+ initializer "tod.register_active_model_type" do
8
+ ActiveModel::Type.register(:time_only, Tod::TimeOfDayType)
9
+ ActiveRecord::Type.register(:time_only, Tod::TimeOfDayType)
10
+ end
11
+ end
12
+ end
data/lib/tod/shift.rb CHANGED
@@ -33,9 +33,40 @@ module Tod
33
33
 
34
34
  # Returns true if ranges overlap, false otherwise.
35
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)
36
+ a, b = [self, other].map(&:range)
37
+ #
38
+ # Although a Shift which passes through midnight is stored
39
+ # internally as lasting more than TimeOfDay::NUM_SECONDS_IN_DAY
40
+ # seconds from midnight, that's not how it is meant to be
41
+ # handled. Rather, it consists of two chunks:
42
+ #
43
+ # range.first => Midnight
44
+ # Midnight => range.last
45
+ #
46
+ # The second one is *before* the first. None of it is more than
47
+ # TimeOfDay::NUM_SECONDS_IN_DAY after midnight. We thus need to shift
48
+ # each of our ranges to cover all overlapping possibilities.
49
+ #
50
+ one_day = TimeOfDay::NUM_SECONDS_IN_DAY
51
+ ashifted =
52
+ Range.new(a.first + one_day, a.last + one_day, a.exclude_end?)
53
+ bshifted =
54
+ Range.new(b.first + one_day, b.last + one_day, b.exclude_end?)
55
+ #
56
+ # For exclusive ranges we need:
57
+ #
58
+ # a.ending > b.beginning && b.ending > a.beginning
59
+ #
60
+ # and for inclusive we need:
61
+ #
62
+ # a.ending >= b.beginning && b.ending >= a.beginning
63
+ #
64
+ aop = a.exclude_end? ? :> : :>=
65
+ bop = b.exclude_end? ? :> : :>=
66
+ #
67
+ (a.last.send(aop, b.first) && b.last.send(bop, a.first)) ||
68
+ (ashifted.last.send(aop, b.first) && b.last.send(bop, ashifted.first)) ||
69
+ (a.last.send(aop, bshifted.first) && bshifted.last.send(bop, a.first))
39
70
  end
40
71
 
41
72
  def contains?(shift)
@@ -51,5 +82,22 @@ module Tod
51
82
  def exclude_end?
52
83
  @exclude_end
53
84
  end
85
+
86
+ def ==(other)
87
+ @range == other.range
88
+ end
89
+
90
+ def eql?(other)
91
+ @range.eql?(other.range)
92
+ end
93
+
94
+ def hash
95
+ @range.hash
96
+ end
97
+
98
+ # Move start and end by a number of seconds and return new shift.
99
+ def slide(seconds)
100
+ self.class.new(beginning + seconds, ending + seconds, exclude_end?)
101
+ end
54
102
  end
55
103
  end
@@ -9,7 +9,7 @@ module Tod
9
9
 
10
10
  PARSE_24H_REGEX = /
11
11
  \A
12
- ([01]?\d|2[0-3])
12
+ ([01]?\d|2[0-4])
13
13
  :?
14
14
  ([0-5]\d)?
15
15
  :?
@@ -34,20 +34,29 @@ module Tod
34
34
  /x
35
35
 
36
36
  WORDS = {
37
- "noon" => "12pm",
38
- "midnight" => "12am"
37
+ "noon" => "12pm".freeze,
38
+ "midnight" => "12am".freeze
39
39
  }
40
40
 
41
41
  NUM_SECONDS_IN_DAY = 86400
42
42
  NUM_SECONDS_IN_HOUR = 3600
43
43
  NUM_SECONDS_IN_MINUTE = 60
44
44
 
45
+ FORMATS = {
46
+ short: "%-l:%M %P".freeze,
47
+ medium: "%-l:%M:%S %P".freeze,
48
+ time: "%H:%M".freeze
49
+ }
50
+
45
51
  def initialize(h, m=0, s=0)
46
52
  @hour = Integer(h)
47
53
  @minute = Integer(m)
48
54
  @second = Integer(s)
49
55
 
50
- raise ArgumentError, "hour must be between 0 and 23" unless (0..23).include?(@hour)
56
+ raise ArgumentError, "hour must be between 0 and 24" unless (0..24).include?(@hour)
57
+ if @hour == 24 && (@minute != 0 || @second != 0)
58
+ raise ArgumentError, "hour can only be 24 when minute and second are 0"
59
+ end
51
60
  raise ArgumentError, "minute must be between 0 and 59" unless (0..59).include?(@minute)
52
61
  raise ArgumentError, "second must be between 0 and 59" unless (0..59).include?(@second)
53
62
 
@@ -61,13 +70,44 @@ module Tod
61
70
  @second_of_day <=> other.second_of_day
62
71
  end
63
72
 
73
+ # Rounding to the given nearest number of seconds
74
+ def round(round_sec = 1)
75
+ down = self - (self.to_i % round_sec)
76
+ up = down + round_sec
77
+
78
+ difference_down = self - down
79
+ difference_up = up - self
80
+
81
+ if (difference_down < difference_up)
82
+ return down
83
+ else
84
+ return up
85
+ end
86
+ end
87
+
64
88
  # Formats identically to Time#strftime
65
89
  def strftime(format_string)
90
+ # Special case 2400 because strftime will load TimeOfDay into Time which
91
+ # will convert 24 to 0
92
+ format_string = format_string.gsub(/%H|%k/, '24') if @hour == 24
66
93
  Time.local(2000,1,1, @hour, @minute, @second).strftime(format_string)
67
94
  end
68
95
 
69
- def to_s
70
- strftime "%H:%M:%S"
96
+ def to_formatted_s(format = :default)
97
+ if formatter = FORMATS[format]
98
+ if formatter.respond_to?(:call)
99
+ formatter.call(self).to_s
100
+ else
101
+ strftime(formatter)
102
+ end
103
+ else
104
+ strftime "%H:%M:%S"
105
+ end
106
+ end
107
+ alias_method :to_s, :to_formatted_s
108
+
109
+ def value_for_database
110
+ to_s
71
111
  end
72
112
 
73
113
  # Return a new TimeOfDay num_seconds greater than self. It will wrap around
@@ -78,8 +118,12 @@ module Tod
78
118
 
79
119
  # Return a new TimeOfDay num_seconds less than self. It will wrap around
80
120
  # at midnight.
81
- def -(num_seconds)
82
- TimeOfDay.from_second_of_day @second_of_day - num_seconds
121
+ def -(other)
122
+ if other.instance_of?(TimeOfDay)
123
+ TimeOfDay.from_second_of_day @second_of_day - other.second_of_day
124
+ else
125
+ TimeOfDay.from_second_of_day @second_of_day - other
126
+ end
83
127
  end
84
128
 
85
129
  # Returns a Time instance on date using self as the time of day
@@ -92,6 +136,8 @@ module Tod
92
136
  #
93
137
  # TimeOfDay.from_second_of_day(3600) == TimeOfDay.new(1) # => true
94
138
  def self.from_second_of_day(second_of_day)
139
+ second_of_day = Integer(second_of_day)
140
+ return new 24 if second_of_day == NUM_SECONDS_IN_DAY
95
141
  remaining_seconds = second_of_day % NUM_SECONDS_IN_DAY
96
142
  hour = remaining_seconds / NUM_SECONDS_IN_HOUR
97
143
  remaining_seconds -= hour * NUM_SECONDS_IN_HOUR
@@ -118,8 +164,10 @@ module Tod
118
164
  # TimeOfDay.parse "3:25:58" # => 03:25:58
119
165
  # TimeOfDay.parse "515p" # => 17:15:00
120
166
  # TimeOfDay.parse "151253" # => 15:12:53
167
+ # You can give a block, that is called with the input if the string is not parsable.
168
+ # If no block is given an ArgumentError is raised if try_parse returns nil.
121
169
  def self.parse(tod_string)
122
- try_parse(tod_string) || (raise ArgumentError, "Invalid time of day string")
170
+ try_parse(tod_string) || (block_given? ? yield(tod_string) : raise(ArgumentError, "Invalid time of day string"))
123
171
  end
124
172
 
125
173
  # Same as parse(), but return nil if not parsable (instead of raising an error)
@@ -156,21 +204,5 @@ module Tod
156
204
  def self.time_zone
157
205
  (Time.respond_to?(:zone) && Time.zone) || Time
158
206
  end
159
-
160
- def self.dump(time_of_day)
161
- if time_of_day.to_s == ''
162
- nil
163
- else
164
- time_of_day.to_s
165
- end
166
- end
167
-
168
- def self.load(time)
169
- if time.respond_to?(:to_time_of_day)
170
- time.to_time_of_day
171
- else
172
- TimeOfDay.parse(time) if time && !time.empty?
173
- end
174
- end
175
207
  end
176
208
  end
@@ -0,0 +1,18 @@
1
+ module Tod
2
+ class TimeOfDayType < ActiveModel::Type::Value
3
+ def cast(value)
4
+ if value.is_a? Hash
5
+ # rails multiparam attribute
6
+ # get hour, minute and second and construct new TimeOfDay object
7
+ ::Tod::TimeOfDay.new(value[4], value[5], value[6])
8
+ else
9
+ # return nil, if input is not parsable
10
+ Tod::TimeOfDay(value){}
11
+ end
12
+ end
13
+
14
+ def serialize(value)
15
+ value.to_s if value.present?
16
+ end
17
+ end
18
+ end
data/lib/tod/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Tod
2
- VERSION = "2.0.1"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
1
+ require_relative '../test_helper'
2
2
 
3
3
  describe "TimeOfDay()" do
4
4
  it "handles Tod::TimeOfDay" do
@@ -81,4 +81,11 @@ describe "TimeOfDay()" do
81
81
 
82
82
  assert_equal(tod, Tod::TimeOfDay.new(0, 00, 00))
83
83
  end
84
+
85
+ it "parses 24:00:00" do
86
+ t = "24:00:00"
87
+ tod = Tod::TimeOfDay(t)
88
+
89
+ assert_equal(tod, Tod::TimeOfDay.new(24, 00, 00))
90
+ end
84
91
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
1
+ require_relative '../test_helper'
2
2
 
3
3
  describe "Date extensions" do
4
4
  describe "#at" do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
1
+ require_relative '../test_helper'
2
2
 
3
3
  describe "Shift" do
4
4
  describe "#initialize" do
@@ -43,12 +43,49 @@ describe "Shift" do
43
43
  shift1 = Tod::Shift.new(Tod::TimeOfDay.new(12), Tod::TimeOfDay.new(18))
44
44
  shift2 = Tod::Shift.new(Tod::TimeOfDay.new(13), Tod::TimeOfDay.new(15))
45
45
  assert shift1.overlaps?(shift2)
46
+
47
+ # Additional Testing for Shifts that span from one day to another
48
+ cases = [
49
+ [5, 8, 7, 2],
50
+ [7, 2, 1, 8],
51
+ [7, 2, 5, 8],
52
+ [4, 8, 1, 5],
53
+ [1, 5, 4, 8],
54
+ [7, 2, 1, 4],
55
+ [1, 4, 7, 2],
56
+ [1, 4, 3, 2],
57
+ [5, 8, 7, 2],
58
+ [7, 2, 8, 3],
59
+ [7, 2, 6, 3],
60
+ [7, 2, 1, 8]
61
+ ]
62
+
63
+ cases.each do |c|
64
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(c[0]), Tod::TimeOfDay.new(c[1]))
65
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(c[2]), Tod::TimeOfDay.new(c[3]))
66
+ assert shift1.overlaps?(shift2), "Failed with args: #{c}"
67
+ end
46
68
  end
47
69
 
48
70
  it "is false when shifts don't overlap" do
49
71
  shift1 = Tod::Shift.new(Tod::TimeOfDay.new(1), Tod::TimeOfDay.new(5))
50
72
  shift2 = Tod::Shift.new(Tod::TimeOfDay.new(9), Tod::TimeOfDay.new(12))
51
73
  refute shift1.overlaps?(shift2)
74
+
75
+ # Additional Testing for Shifts that span from one day to another
76
+ cases = [
77
+ [7, 8, 1, 5],
78
+ [1, 5, 7, 8],
79
+ [7, 2, 3, 4],
80
+ [3, 4, 5, 2],
81
+ [1, 5, 9, 12]
82
+ ]
83
+
84
+ cases.each do |c|
85
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(c[0]), Tod::TimeOfDay.new(c[1]))
86
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(c[2]), Tod::TimeOfDay.new(c[3]))
87
+ refute shift1.overlaps?(shift2), "Failed with args: #{c}"
88
+ end
52
89
  end
53
90
 
54
91
  it "is true when shifts touch with inclusive end" do
@@ -62,6 +99,49 @@ describe "Shift" do
62
99
  shift2 = Tod::Shift.new(Tod::TimeOfDay.new(5), Tod::TimeOfDay.new(12), true)
63
100
  refute shift1.overlaps?(shift2)
64
101
  end
102
+
103
+ it "copes correctly with mixed shifts" do
104
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(1), Tod::TimeOfDay.new(5))
105
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(5), Tod::TimeOfDay.new(12), true)
106
+ assert shift1.overlaps?(shift2)
107
+ assert shift2.overlaps?(shift1)
108
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(1), Tod::TimeOfDay.new(5), true)
109
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(5), Tod::TimeOfDay.new(12))
110
+ refute shift1.overlaps?(shift2)
111
+ refute shift2.overlaps?(shift1)
112
+ end
113
+
114
+ it "copes correctly with zero length inclusive end shifts" do
115
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(9), Tod::TimeOfDay.new(17))
116
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(10), Tod::TimeOfDay.new(10))
117
+ shift3 = Tod::Shift.new(Tod::TimeOfDay.new(9), Tod::TimeOfDay.new(9))
118
+ shift4 = Tod::Shift.new(Tod::TimeOfDay.new(17), Tod::TimeOfDay.new(17))
119
+ assert shift1.overlaps?(shift2)
120
+ assert shift2.overlaps?(shift1)
121
+
122
+ assert shift1.overlaps?(shift3)
123
+ assert shift3.overlaps?(shift1)
124
+
125
+ assert shift1.overlaps?(shift4)
126
+ assert shift4.overlaps?(shift1)
127
+
128
+ end
129
+
130
+ it "copes correctly with zero length exclusive end shifts" do
131
+ shift1 = Tod::Shift.new(Tod::TimeOfDay.new(9), Tod::TimeOfDay.new(17), true)
132
+ shift2 = Tod::Shift.new(Tod::TimeOfDay.new(10), Tod::TimeOfDay.new(10), true)
133
+ shift3 = Tod::Shift.new(Tod::TimeOfDay.new(9), Tod::TimeOfDay.new(9), true)
134
+ shift4 = Tod::Shift.new(Tod::TimeOfDay.new(17), Tod::TimeOfDay.new(17), true)
135
+ assert shift1.overlaps?(shift2)
136
+ assert shift2.overlaps?(shift1)
137
+
138
+ refute shift1.overlaps?(shift3)
139
+ refute shift3.overlaps?(shift1)
140
+
141
+ refute shift1.overlaps?(shift4)
142
+ refute shift4.overlaps?(shift1)
143
+
144
+ end
65
145
  end
66
146
 
67
147
  describe "contains?" do
@@ -166,4 +246,153 @@ describe "Shift" do
166
246
  assert shift.include?(value)
167
247
  end
168
248
  end
249
+
250
+ describe "#==" do
251
+ it "is true when the beginning time, end time, and exclude end are the same" do
252
+ tod1 = Tod::TimeOfDay.new 8,30
253
+ tod2 = Tod::TimeOfDay.new 13,00,30
254
+ shift1 = Tod::Shift.new tod1, tod2
255
+ shift2 = Tod::Shift.new tod1, tod2
256
+ assert shift1 == shift2
257
+ end
258
+
259
+ it "is false when the beginning time is different" do
260
+ tod1 = Tod::TimeOfDay.new 8,30
261
+ tod2 = Tod::TimeOfDay.new 13,00,30
262
+ shift1 = Tod::Shift.new tod1, tod2
263
+ shift2 = Tod::Shift.new tod1, Tod::TimeOfDay.new(14,00)
264
+ assert !(shift1 == shift2)
265
+ end
266
+
267
+ it "is false when the ending time is different" do
268
+ tod1 = Tod::TimeOfDay.new 8,30
269
+ tod2 = Tod::TimeOfDay.new 13,00,30
270
+ shift1 = Tod::Shift.new tod1, tod2
271
+ shift2 = Tod::Shift.new Tod::TimeOfDay.new(9,30), tod2
272
+ assert !(shift1 == shift2)
273
+ end
274
+
275
+ it "is false when exclude end is different" do
276
+ tod1 = Tod::TimeOfDay.new 8,30
277
+ tod2 = Tod::TimeOfDay.new 13,00,30
278
+ shift1 = Tod::Shift.new tod1, tod2
279
+ shift2 = Tod::Shift.new tod1, tod2, true
280
+ assert !(shift1 == shift2)
281
+ end
282
+ end
283
+
284
+ describe "#eql?" do
285
+ it "is true when the beginning time, end time, and exclude end are the same" do
286
+ tod1 = Tod::TimeOfDay.new 8,30
287
+ tod2 = Tod::TimeOfDay.new 13,00,30
288
+ shift1 = Tod::Shift.new tod1, tod2
289
+ shift2 = Tod::Shift.new tod1, tod2
290
+ assert shift1.eql?(shift2)
291
+ end
292
+
293
+ it "is false when the beginning time is different" do
294
+ tod1 = Tod::TimeOfDay.new 8,30
295
+ tod2 = Tod::TimeOfDay.new 13,00,30
296
+ shift1 = Tod::Shift.new tod1, tod2
297
+ shift2 = Tod::Shift.new tod1, Tod::TimeOfDay.new(14,00)
298
+ assert !shift1.eql?(shift2)
299
+ end
300
+
301
+ it "is false when the ending time is different" do
302
+ tod1 = Tod::TimeOfDay.new 8,30
303
+ tod2 = Tod::TimeOfDay.new 13,00,30
304
+ shift1 = Tod::Shift.new tod1, tod2
305
+ shift2 = Tod::Shift.new Tod::TimeOfDay.new(9,30), tod2
306
+ assert !shift1.eql?(shift2)
307
+ end
308
+
309
+ it "is false when exclude end is different" do
310
+ tod1 = Tod::TimeOfDay.new 8,30
311
+ tod2 = Tod::TimeOfDay.new 13,00,30
312
+ shift1 = Tod::Shift.new tod1, tod2
313
+ shift2 = Tod::Shift.new tod1, tod2, true
314
+ assert !shift1.eql?(shift2)
315
+ end
316
+ end
317
+
318
+ describe "#hash" do
319
+ it "is the same when the beginning time, end time, and exclude end are the same" do
320
+ tod1 = Tod::TimeOfDay.new 8,30
321
+ tod2 = Tod::TimeOfDay.new 13,00,30
322
+ shift1 = Tod::Shift.new tod1, tod2
323
+ shift2 = Tod::Shift.new tod1, tod2
324
+ assert_equal shift1.hash, shift2.hash
325
+ end
326
+
327
+ it "is usually different when the beginning time is different" do
328
+ tod1 = Tod::TimeOfDay.new 8,30
329
+ tod2 = Tod::TimeOfDay.new 13,00,30
330
+ shift1 = Tod::Shift.new tod1, tod2
331
+ shift2 = Tod::Shift.new tod1, Tod::TimeOfDay.new(14,00)
332
+ assert shift1.hash != shift2.hash
333
+ end
334
+
335
+ it "is usually different when the ending time is different" do
336
+ tod1 = Tod::TimeOfDay.new 8,30
337
+ tod2 = Tod::TimeOfDay.new 13,00,30
338
+ shift1 = Tod::Shift.new tod1, tod2
339
+ shift2 = Tod::Shift.new Tod::TimeOfDay.new(9,30), tod2
340
+ assert shift1.hash != shift2.hash
341
+ end
342
+
343
+ it "is usually different when exclude end is different" do
344
+ tod1 = Tod::TimeOfDay.new 8,30
345
+ tod2 = Tod::TimeOfDay.new 13,00,30
346
+ shift1 = Tod::Shift.new tod1, tod2
347
+ shift2 = Tod::Shift.new tod1, tod2, true
348
+ assert shift1.hash != shift2.hash
349
+ end
350
+ end
351
+
352
+ describe "slide" do
353
+ it "handles positive numbers" do
354
+ slide = 30 * 60 # 30 minutes in seconds
355
+
356
+ beginning_expected = Tod::TimeOfDay.new 10, 30
357
+ ending_expected = Tod::TimeOfDay.new 16, 30
358
+
359
+ beginning = Tod::TimeOfDay.new 10
360
+ ending = Tod::TimeOfDay.new 16
361
+ shift = Tod::Shift.new(beginning, ending, false).slide(slide)
362
+
363
+ assert_equal beginning_expected, shift.beginning
364
+ assert_equal ending_expected, shift.ending
365
+ refute shift.exclude_end?
366
+ end
367
+
368
+ it "handles negative numbers" do
369
+ slide = -30 * 60 # -30 minutes in seconds
370
+
371
+ beginning_expected = Tod::TimeOfDay.new 9, 30
372
+ ending_expected = Tod::TimeOfDay.new 15, 30
373
+
374
+ beginning = Tod::TimeOfDay.new 10
375
+ ending = Tod::TimeOfDay.new 16
376
+ shift = Tod::Shift.new(beginning, ending, false).slide(slide)
377
+
378
+ assert_equal beginning_expected, shift.beginning
379
+ assert_equal ending_expected, shift.ending
380
+ refute shift.exclude_end?
381
+ end
382
+
383
+ it "handles ActiveSupport::Duration" do
384
+ slide = 30.minutes
385
+
386
+ beginning_expected = Tod::TimeOfDay.new 10, 30
387
+ ending_expected = Tod::TimeOfDay.new 16, 30
388
+
389
+ beginning = Tod::TimeOfDay.new 10
390
+ ending = Tod::TimeOfDay.new 16
391
+ shift = Tod::Shift.new(beginning, ending, false).slide(slide)
392
+
393
+ assert_equal beginning_expected, shift.beginning
394
+ assert_equal ending_expected, shift.ending
395
+ refute shift.exclude_end?
396
+ end
397
+ end
169
398
  end
@@ -0,0 +1,74 @@
1
+ require_relative '../test_helper'
2
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','support/active_record'))
3
+
4
+ require 'tod/time_of_day_type'
5
+
6
+ ActiveModel::Type.register(:time_only, Tod::TimeOfDayType)
7
+ ActiveRecord::Type.register(:time_only, Tod::TimeOfDayType)
8
+
9
+ class Order < ActiveRecord::Base
10
+ attribute :time, :time_only
11
+ end
12
+
13
+ describe "TimeOfDay with ActiveRecord Attribute" do
14
+ it "sets time of day" do
15
+ Order.create!(time: Tod::TimeOfDay.new(9, 30))
16
+ end
17
+
18
+ it "sets nil as value" do
19
+ Order.create!(time: nil)
20
+ end
21
+
22
+ it "works with multiparam time arguments" do
23
+ order = Order.create!({"time(4i)" => "8", "time(5i)" => "6", "time(6i)" => "5"})
24
+ assert_equal Tod::TimeOfDay.new(8,6,5), order.time
25
+ end
26
+
27
+ it "should not raise Exception on access of unparsable values" do
28
+ order = Order.new(time: 'unparsable')
29
+ order.time
30
+ assert order.valid?
31
+ end
32
+
33
+ it "should dump unparsable values to nil" do
34
+ assert_nil Order.new(time: '').time
35
+ assert_nil Order.new(time: 'unparsable').time
36
+ assert_nil Order.new(time: nil).time
37
+ end
38
+
39
+ it "loads set Tod::TimeOfDay" do
40
+ time_of_day = Tod::TimeOfDay.new(9, 30)
41
+ order = Order.create!(time: time_of_day)
42
+ order.reload
43
+ assert_equal order.time, time_of_day
44
+ end
45
+
46
+ it "loads set Time" do
47
+ time_of_day = Time.new(2015, 10, 21, 16, 29, 0, "-07:00")
48
+ order = Order.create!(time: time_of_day)
49
+ order.reload
50
+ assert_equal order.time, Tod::TimeOfDay.new(16, 29)
51
+ end
52
+
53
+ it "returns nil if time is not set" do
54
+ order = Order.create!(time: nil)
55
+ order.reload
56
+ assert_nil order.time
57
+ end
58
+
59
+ it "dump 24:00:00 and get it back" do
60
+ time_of_day = Tod::TimeOfDay.new(24, 0, 0)
61
+ order = Order.create!(time: time_of_day)
62
+ order.reload
63
+ assert_equal Tod::TimeOfDay.new(24), order.time
64
+ end
65
+
66
+ describe "Order.where" do
67
+ it "handles TimeOfDay as a parameter" do
68
+ tod = Tod::TimeOfDay.new(11, 11)
69
+ expected = Order.create!(time: tod)
70
+ actual = Order.where(time: tod).first
71
+ assert_equal expected, actual
72
+ end
73
+ end
74
+ end
@@ -1,10 +1,10 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
1
+ require_relative '../test_helper'
2
2
 
3
3
  describe "TimeOfDay" do
4
4
  describe "#initialize" do
5
5
  it "blocks invalid hours" do
6
- assert_raises(ArgumentError) { Tod::TimeOfDay.new -1 }
7
- assert_raises(ArgumentError) { Tod::TimeOfDay.new 24 }
6
+ assert_raises(ArgumentError) { Tod::TimeOfDay.new(-1) }
7
+ assert_raises(ArgumentError) { Tod::TimeOfDay.new 25 }
8
8
  end
9
9
 
10
10
  it "blocks invalid minutes" do
@@ -31,6 +31,10 @@ describe "TimeOfDay" do
31
31
  assert_equal 86399, Tod::TimeOfDay.new(23,59,59).second_of_day
32
32
  end
33
33
 
34
+ it "is 86400 at beginning of next day" do
35
+ assert_equal 86400, Tod::TimeOfDay.new(24,0,0).second_of_day
36
+ end
37
+
34
38
  it "have alias to_i" do
35
39
  tod = Tod::TimeOfDay.new(0,0,0)
36
40
  assert_equal tod.method(:second_of_day), tod.method(:to_i)
@@ -50,7 +54,7 @@ describe "TimeOfDay" do
50
54
  def self.should_not_parse(parse_string)
51
55
  it "does not parse '#{parse_string}'" do
52
56
  assert_equal false, Tod::TimeOfDay.parsable?(parse_string)
53
- assert_equal nil, Tod::TimeOfDay.try_parse(parse_string)
57
+ assert_nil Tod::TimeOfDay.try_parse(parse_string)
54
58
  assert_raises(ArgumentError) { Tod::TimeOfDay.parse(parse_string) }
55
59
  end
56
60
  end
@@ -84,9 +88,12 @@ describe "TimeOfDay" do
84
88
  should_parse "12a", 0, 0, 0
85
89
  should_parse "12p", 12, 0, 0
86
90
 
91
+ should_parse "24:00:00", 24, 0, 0
92
+ should_parse "24:00", 24, 0, 0
93
+ should_parse "24", 24, 0, 0
94
+ should_parse "2400", 24, 0, 0
95
+
87
96
  should_not_parse "-1:30"
88
- should_not_parse "24:00:00"
89
- should_not_parse "24"
90
97
  should_not_parse "00:60"
91
98
  should_not_parse "00:00:60"
92
99
  should_not_parse "13a"
@@ -98,12 +105,17 @@ describe "TimeOfDay" do
98
105
 
99
106
  it "does not parse 'nil'" do
100
107
  assert_equal false, Tod::TimeOfDay.parsable?(nil)
101
- assert_equal nil, Tod::TimeOfDay.try_parse(nil)
108
+ assert_nil Tod::TimeOfDay.try_parse(nil)
102
109
  assert_raises(ArgumentError) { Tod::TimeOfDay.parse(nil) }
103
110
  end
104
111
 
112
+ it "executes block on parsing failure and return result instead" do
113
+ assert_equal Tod::TimeOfDay.new(1), Tod::TimeOfDay.parse('25:00:00') { Tod::TimeOfDay.new(1) }
114
+ assert_equal Tod::TimeOfDay.new(1), Tod::TimeOfDay.parse('25:00:00') { |time_string| Tod::TimeOfDay.parse(time_string.sub('25', '01')) }
115
+ end
116
+
105
117
  it "provides spaceship operator" do
106
- assert_equal -1, Tod::TimeOfDay.new(8,0,0) <=> Tod::TimeOfDay.new(9,0,0)
118
+ assert_equal(-1, Tod::TimeOfDay.new(8,0,0) <=> Tod::TimeOfDay.new(9,0,0))
107
119
  assert_equal 0, Tod::TimeOfDay.new(9,0,0) <=> Tod::TimeOfDay.new(9,0,0)
108
120
  assert_equal 1, Tod::TimeOfDay.new(10,0,0) <=> Tod::TimeOfDay.new(9,0,0)
109
121
  end
@@ -112,6 +124,20 @@ describe "TimeOfDay" do
112
124
  assert_equal Tod::TimeOfDay.new(8,0,0), Tod::TimeOfDay.new(8,0,0)
113
125
  end
114
126
 
127
+ describe "round_nearest" do
128
+ it "rounds to the given nearest number of seconds" do
129
+ assert_equal Tod::TimeOfDay.new(8,15,30), Tod::TimeOfDay.new(8,15,31).round(5)
130
+ assert_equal Tod::TimeOfDay.new(8,15,35), Tod::TimeOfDay.new(8,15,33).round(5)
131
+ assert_equal Tod::TimeOfDay.new(8,16,0), Tod::TimeOfDay.new(8,15,34).round(60)
132
+ assert_equal Tod::TimeOfDay.new(8,15,0), Tod::TimeOfDay.new(8,15,15).round(60)
133
+ assert_equal Tod::TimeOfDay.new(8,15,0), Tod::TimeOfDay.new(8,17,15).round(300)
134
+ assert_equal Tod::TimeOfDay.new(8,20,0), Tod::TimeOfDay.new(8,18,15).round(300)
135
+ assert_equal Tod::TimeOfDay.new(8,20,0), Tod::TimeOfDay.new(8,20,00).round(300)
136
+ assert_equal Tod::TimeOfDay.new(9,0,0), Tod::TimeOfDay.new(8,58,00).round(300)
137
+ assert_equal Tod::TimeOfDay.new(8,0,0), Tod::TimeOfDay.new(8,02,29).round(300)
138
+ assert_equal Tod::TimeOfDay.new(24,0,0), Tod::TimeOfDay.new(23,58,29).round(300)
139
+ end
140
+ end
115
141
 
116
142
  describe "strftime" do
117
143
  it "accepts standard strftime format codes" do
@@ -119,10 +145,48 @@ describe "TimeOfDay" do
119
145
  end
120
146
  end
121
147
 
148
+ describe "to_formatted_s" do
149
+ it "has a default format" do
150
+ assert_equal "08:15:30", Tod::TimeOfDay.new(8,15,30).to_formatted_s
151
+ assert_equal "22:10:45", Tod::TimeOfDay.new(22,10,45).to_formatted_s
152
+ end
153
+
154
+ it "has a short format" do
155
+ assert_equal "8:15 am", Tod::TimeOfDay.new(8,15,30).to_formatted_s(:short)
156
+ assert_equal "10:10 pm", Tod::TimeOfDay.new(22,10,45).to_formatted_s(:short)
157
+ end
158
+
159
+ it "has a medium format" do
160
+ assert_equal "8:15:30 am", Tod::TimeOfDay.new(8,15,30).to_formatted_s(:medium)
161
+ assert_equal "10:10:45 pm", Tod::TimeOfDay.new(22,10,45).to_formatted_s(:medium)
162
+ end
163
+
164
+ it "has an ActiveSupport compatible time format" do
165
+ assert_equal "08:15", Tod::TimeOfDay.new(8,15,30).to_formatted_s(:time)
166
+ assert_equal "22:10", Tod::TimeOfDay.new(22,10,45).to_formatted_s(:time)
167
+ end
168
+
169
+ it "evaluates custom lambda lambda formats" do
170
+ begin
171
+ Tod::TimeOfDay::FORMATS[:lambda] = -> (t) { t.strftime("%H%M 😎") }
172
+ assert_equal "1337 😎", Tod::TimeOfDay.new(13,37).to_formatted_s(:lambda)
173
+ ensure
174
+ Tod::TimeOfDay::FORMATS.delete(:lambda)
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "value_for_database" do
180
+ it "returns a formatted value for database query serialization" do
181
+ t = Tod::TimeOfDay.new(12,15,05)
182
+ assert_equal "12:15:05", t.value_for_database
183
+ end
184
+ end
185
+
122
186
  describe "to_s" do
123
- it "formats to HH:MM:SS" do
124
- assert_equal "08:15:30", Tod::TimeOfDay.new(8,15,30).to_s
125
- assert_equal "22:10:45", Tod::TimeOfDay.new(22,10,45).to_s
187
+ it "is aliased to to_formatted_s" do
188
+ t = Tod::TimeOfDay.new(8,15,30)
189
+ assert_equal t.to_formatted_s, t.to_s
126
190
  end
127
191
  end
128
192
 
@@ -151,6 +215,12 @@ describe "TimeOfDay" do
151
215
  result = original + 15
152
216
  refute_equal original.object_id, result.object_id
153
217
  end
218
+
219
+ it "handles ActiveSupport::Duration" do
220
+ original = Tod::TimeOfDay.new(8,0,0)
221
+ result = original + 10.minutes
222
+ assert_equal Tod::TimeOfDay.new(8,10,0), result
223
+ end
154
224
  end
155
225
 
156
226
  describe "subtraction" do
@@ -171,6 +241,19 @@ describe "TimeOfDay" do
171
241
  result = original - 15
172
242
  refute_equal original.object_id, result.object_id
173
243
  end
244
+
245
+ it "handles ActiveSupport::Duration" do
246
+ original = Tod::TimeOfDay.new(8,0,0)
247
+ result = original - 10.minutes
248
+ assert_equal Tod::TimeOfDay.new(7,50,0), result
249
+ end
250
+
251
+ it "subtracts Tod::TimeOfDay object" do
252
+ right_side = Tod::TimeOfDay.new(10,0,0)
253
+ left_side = Tod::TimeOfDay.new(12,0,30)
254
+ result = right_side - left_side
255
+ assert_equal Tod::TimeOfDay.new(21,59,30), result
256
+ end
174
257
  end
175
258
 
176
259
  describe "from_second_of_day" do
@@ -182,7 +265,7 @@ describe "TimeOfDay" do
182
265
  end
183
266
 
184
267
  it "handles positive numbers a day or more away" do
185
- assert_equal Tod::TimeOfDay.new(0,0,0), Tod::TimeOfDay.from_second_of_day(86400)
268
+ assert_equal Tod::TimeOfDay.new(24,0,0), Tod::TimeOfDay.from_second_of_day(86400)
186
269
  assert_equal Tod::TimeOfDay.new(0,0,30), Tod::TimeOfDay.from_second_of_day(86430)
187
270
  assert_equal Tod::TimeOfDay.new(0,1,30), Tod::TimeOfDay.from_second_of_day(86490)
188
271
  assert_equal Tod::TimeOfDay.new(1,1,5), Tod::TimeOfDay.from_second_of_day(90065)
@@ -200,6 +283,10 @@ describe "TimeOfDay" do
200
283
  it "has alias from_i" do
201
284
  assert_equal Tod::TimeOfDay.method(:from_second_of_day), Tod::TimeOfDay.method(:from_i)
202
285
  end
286
+
287
+ it "handles floats" do
288
+ assert_equal Tod::TimeOfDay.new(15,30,0), Tod::TimeOfDay.from_second_of_day(55800.0)
289
+ end
203
290
  end
204
291
 
205
292
  describe "on" do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
1
+ require_relative '../test_helper'
2
2
 
3
3
  describe "TimeOfDay with ActiveSupport" do
4
4
  describe ".time_zone" do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
1
+ require_relative '../test_helper'
2
2
 
3
3
  describe "Time extensions" do
4
4
  describe "#to_time_of_day" do
data/tod.gemspec CHANGED
@@ -16,9 +16,9 @@ Gem::Specification.new do |s|
16
16
  s.add_development_dependency "minitest"
17
17
  s.add_development_dependency "tzinfo"
18
18
  s.add_development_dependency "rake"
19
- s.add_development_dependency "activerecord", ">= 3.0.0"
19
+ s.add_development_dependency "activerecord", ">= 6.0.0"
20
20
  s.add_development_dependency "sqlite3"
21
- s.add_development_dependency "pry"
21
+ s.add_development_dependency "pry-byebug"
22
22
 
23
23
  s.files = `git ls-files`.split("\n")
24
24
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tod
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jack Christensen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-08 00:00:00.000000000 Z
11
+ date: 2021-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 3.0.0
61
+ version: 6.0.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 3.0.0
68
+ version: 6.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: pry
84
+ name: pry-byebug
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -110,25 +110,23 @@ files:
110
110
  - MIT-LICENSE
111
111
  - README.markdown
112
112
  - Rakefile
113
- - gemfiles/3.2.gemfile
114
- - gemfiles/4.0.gemfile
115
- - gemfiles/4.1.gemfile
116
- - gemfiles/4.2.gemfile
117
113
  - lib/tod.rb
118
114
  - lib/tod/conversions.rb
119
115
  - lib/tod/core_extensions.rb
120
116
  - lib/tod/date_extensions.rb
121
117
  - lib/tod/mongoization.rb
118
+ - lib/tod/railtie.rb
122
119
  - lib/tod/shift.rb
123
120
  - lib/tod/time_extensions.rb
124
121
  - lib/tod/time_of_day.rb
122
+ - lib/tod/time_of_day_type.rb
125
123
  - lib/tod/version.rb
126
124
  - test/support/active_record.rb
127
125
  - test/test_helper.rb
128
126
  - test/tod/conversion_test.rb
129
127
  - test/tod/date_test.rb
130
128
  - test/tod/shift_test.rb
131
- - test/tod/time_of_day_serializable_attribute_test.rb
129
+ - test/tod/time_of_day_attribute_test.rb
132
130
  - test/tod/time_of_day_test.rb
133
131
  - test/tod/time_of_day_time_zone_with_active_support_test.rb
134
132
  - test/tod/time_test.rb
@@ -137,7 +135,7 @@ homepage: https://github.com/JackC/tod
137
135
  licenses:
138
136
  - MIT
139
137
  metadata: {}
140
- post_install_message:
138
+ post_install_message:
141
139
  rdoc_options: []
142
140
  require_paths:
143
141
  - lib
@@ -152,9 +150,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
150
  - !ruby/object:Gem::Version
153
151
  version: '0'
154
152
  requirements: []
155
- rubyforge_project:
156
- rubygems_version: 2.4.5
157
- signing_key:
153
+ rubygems_version: 3.0.6
154
+ signing_key:
158
155
  specification_version: 4
159
156
  summary: Supplies TimeOfDay and Shift class
160
157
  test_files:
@@ -163,7 +160,7 @@ test_files:
163
160
  - test/tod/conversion_test.rb
164
161
  - test/tod/date_test.rb
165
162
  - test/tod/shift_test.rb
166
- - test/tod/time_of_day_serializable_attribute_test.rb
163
+ - test/tod/time_of_day_attribute_test.rb
167
164
  - test/tod/time_of_day_test.rb
168
165
  - test/tod/time_of_day_time_zone_with_active_support_test.rb
169
166
  - test/tod/time_test.rb
data/gemfiles/3.2.gemfile DELETED
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "activerecord", "~> 3.2.13"
4
-
5
- gemspec :path=>"../"
data/gemfiles/4.0.gemfile DELETED
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "activerecord", "4.0.0"
4
-
5
- gemspec :path=>"../"
data/gemfiles/4.1.gemfile DELETED
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "activerecord", "~> 4.1.8"
4
-
5
- gemspec :path=>"../"
data/gemfiles/4.2.gemfile DELETED
@@ -1,5 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "activerecord", "~> 4.2.0"
4
-
5
- gemspec :path=>"../"
@@ -1,31 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__),'..','test_helper'))
2
- require File.expand_path(File.join(File.dirname(__FILE__),'..','support/active_record'))
3
-
4
- class Order < ActiveRecord::Base
5
- serialize :time, Tod::TimeOfDay
6
- end
7
-
8
- describe "TimeOfDay with ActiveRecord Serializable Attribute" do
9
- describe ".dump" do
10
- it "sets time of day" do
11
- Order.create(time: Tod::TimeOfDay.new(9, 30))
12
- end
13
-
14
- it "sets nil as value" do
15
- Order.create(time: nil)
16
- end
17
- end
18
-
19
- describe ".load" do
20
- it "loads set time" do
21
- time_of_day = Tod::TimeOfDay.new(9, 30)
22
- order = Order.create(time: time_of_day)
23
- assert_equal order.time, time_of_day
24
- end
25
-
26
- it "returns nil if time is not set" do
27
- order = Order.create(time: nil)
28
- assert_equal order.time, nil
29
- end
30
- end
31
- end