Class: Hour
- Inherits:
-
Object
- Object
- Hour
- Defined in:
- lib/hour.rb
Defined Under Namespace
Classes: HourUnit, MinuteUnit, SecondUnit, Unit
Instance Attribute Summary collapse
-
#h ⇒ Object
readonly
Returns the value of attribute h.
-
#m ⇒ Object
readonly
Returns the value of attribute m.
-
#s ⇒ Object
readonly
Returns the value of attribute s.
Class Method Summary collapse
-
.from(minutes: 0, seconds: 0) ⇒ Object
Build an hour instance from either minutes or seconds.
-
.from_time(time, s: true) ⇒ Object
TODO: document and write tests.
-
.now(**opts) ⇒ Object
TODO: Test me and document me.
-
.parse(serialised_hour, s: true) ⇒ Object
Build an hour instance from an hour string.
Instance Method Summary collapse
- #*(integer) ⇒ Object
-
#+(other) ⇒ Object
Returns a new Hour instance returning the total time of the two hour instances.
- #-(other) ⇒ Object
-
#hours ⇒ Object
Returns a decorator providing convenience methods for working with hours.
-
#initialize(*args) ⇒ Hour
constructor
Build an hour instance from h, m and s.
-
#minutes ⇒ Object
Returns a decorator providing convenience methods for working with minutes.
-
#seconds ⇒ Object
Returns a decorator providing convenience methods for working with seconds.
-
#to_decimal ⇒ Object
Provisional.
-
#to_s(format = nil) ⇒ Object
(also: #inspect)
Returns string representation of the hour instance.
- #to_time(today = Time.now) ⇒ Object
Constructor Details
#initialize(*args) ⇒ Hour
Build an hour instance from h, m and s. Raises an argument error if m or s is a value over 60.
For instantiating this class from a minutes or seconds value over 60, use ‘.from`.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/hour.rb', line 111 def initialize(*args) if args.length == 1 && args.first.is_a?(Hash) initialize_from_keyword_args(**args.first) else # Pad with 0s. args = args + Array.new(3 - args.length, 0) @h, @m, @s = args end if @m > 60 raise ArgumentError.new("Minutes must be a number between 0 and 60.") end if @s.respond_to?(:round) && @s > 60 raise ArgumentError.new("Seconds must be a number between 0 and 60.") end end |
Instance Attribute Details
#h ⇒ Object (readonly)
Returns the value of attribute h.
105 106 107 |
# File 'lib/hour.rb', line 105 def h @h end |
#m ⇒ Object (readonly)
Returns the value of attribute m.
105 106 107 |
# File 'lib/hour.rb', line 105 def m @m end |
#s ⇒ Object (readonly)
Returns the value of attribute s.
105 106 107 |
# File 'lib/hour.rb', line 105 def s @s end |
Class Method Details
.from(minutes: 0, seconds: 0) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/hour.rb', line 93 def self.from(minutes: 0, seconds: 0) if minutes != 0 && seconds != 0 raise ArgumentError.new("Use either minutes OR seconds, not both.") end if minutes > 0 || (minutes == 0 && seconds == 0) self.new(h: minutes / 60, m: minutes % 60) else self.from(minutes: seconds / 60) + self.new(s: seconds % 60) end end |
.from_time(time, s: true) ⇒ Object
TODO: document and write tests.
64 65 66 |
# File 'lib/hour.rb', line 64 def self.from_time(time, s: true) self.new(time.hour, time.min, s ? time.sec : false) end |
.now(**opts) ⇒ Object
TODO: Test me and document me.
59 60 61 |
# File 'lib/hour.rb', line 59 def self.now(**opts) self.from_time(Time.now, **opts) end |
.parse(serialised_hour, s: true) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/hour.rb', line 74 def self.parse(serialised_hour, s: true) args = serialised_hour.split(':').map(&:to_i) if args.length == 3 && s self.new(*args) elsif args.length == 2 && !s self.new(*(args << false)) elsif ((0..2).include?(args.length) && s) || ((0..1).include?(args.length) && !s) raise ArgumentError, "Too few segments (#{args.inspect})." elsif ((4..Float::INFINITY).include?(args.length) && s) || ((3..Float::INFINITY).include?(args.length) && !s) raise ArgumentError, "Too many segments (#{args.inspect})." end end |
Instance Method Details
#*(integer) ⇒ Object
166 167 168 169 |
# File 'lib/hour.rb', line 166 def *(integer) raise ArgumentError, "must be an integer" unless integer.integer? self.class.from(seconds: (@h * integer * 3600) + (@m * integer * 60) + (@s * integer)) end |
#+(other) ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/hour.rb', line 132 def +(other) hours = @h + other.h + (@m + other.m + ((@s + other.s) / 60)) / 60 minutes = (@m + other.m + ((@s + other.s) / 60)) % 60 if @s && other.s seconds = (@s + other.s) % 60 elsif (!@s) && (!other.s) seconds = false else raise "TODO: how to resolve this?" end self.class.new(hours, minutes, seconds) end |
#-(other) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/hour.rb', line 147 def -(other) if other.to_decimal > self.to_decimal raise ArgumentError, "Negative hours not supported" end hours = @h - other.h - (@m - other.m - ((@s - other.s) / 60)) / 60 minutes = (@m - other.m - ((@s - other.s) / 60)) % 60 if @s && other.s seconds = (@s - other.s) % 60 elsif (!@s) && (!other.s) seconds = false else raise "TODO: how to resolve this?" end self.class.new(hours, minutes, seconds) end |
#seconds ⇒ Object
193 194 195 |
# File 'lib/hour.rb', line 193 def seconds SecondUnit.new(self) if @s end |
#to_decimal ⇒ Object
Provisional.
210 211 212 213 214 |
# File 'lib/hour.rb', line 210 def to_decimal decimal = (@m / 60.0) + (@s / 3600.0) "#{@h}.#{decimal}" @h + decimal end |
#to_s(format = nil) ⇒ Object Also known as: inspect
203 204 205 |
# File 'lib/hour.rb', line 203 def to_s(format = nil) [(@h unless @h.zero?), format('%02d', @m), (format('%02d', @s) if @s)].compact.join(':') end |
#to_time(today = Time.now) ⇒ Object
216 217 218 |
# File 'lib/hour.rb', line 216 def to_time(today = Time.now) Time.new(today.year, today.month, today.day, self.hours, self.minutes_over_the_hour) end |