emery 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/emery/tod.rb CHANGED
@@ -25,238 +25,236 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
25
 
26
26
  =end
27
27
 
28
- module Emery
29
- class TimeOfDay
30
- include Comparable
28
+ class TimeOfDay
29
+ include Comparable
31
30
 
32
- def self.jsoner_deserialize(json_value)
33
- TimeOfDay.parse(T.check(String, json_value))
34
- end
35
- def self.jsoner_serialize(value)
36
- T.check(TimeOfDay, value).to_s
37
- end
31
+ def self.jsoner_deserialize(json_value)
32
+ TimeOfDay.parse(T.check(String, json_value))
33
+ end
34
+ def self.jsoner_serialize(value)
35
+ T.check(TimeOfDay, value).to_s
36
+ end
38
37
 
39
- attr_reader :hour, :minute, :second, :second_of_day
40
- alias_method :min, :minute
41
- alias_method :sec, :second
42
- alias_method :to_i, :second_of_day
43
-
44
- PARSE_24H_REGEX = /
45
- \A
46
- ([01]?\d|2[0-4])
47
- :?
48
- ([0-5]\d)?
49
- :?
50
- ([0-5]\d)?
51
- \z
52
- /x
53
-
54
- PARSE_12H_REGEX = /
55
- \A
56
- (0?\d|1[0-2])
57
- :?
58
- ([0-5]\d)?
59
- :?
60
- ([0-5]\d)?
61
- \s*
62
- ([ap])
63
- \.?
64
- \s*
65
- m?
66
- \.?
67
- \z
68
- /x
69
-
70
- WORDS = {
71
- "noon" => "12pm".freeze,
72
- "midnight" => "12am".freeze
73
- }
74
-
75
- NUM_SECONDS_IN_DAY = 86400
76
- NUM_SECONDS_IN_HOUR = 3600
77
- NUM_SECONDS_IN_MINUTE = 60
78
-
79
- FORMATS = {
80
- short: "%-l:%M %P".freeze,
81
- medium: "%-l:%M:%S %P".freeze,
82
- time: "%H:%M".freeze
83
- }
84
-
85
- def initialize(h, m=0, s=0)
86
- @hour = Integer(h)
87
- @minute = Integer(m)
88
- @second = Integer(s)
89
-
90
- raise ArgumentError, "hour must be between 0 and 24" unless (0..24).include?(@hour)
91
- if @hour == 24 && (@minute != 0 || @second != 0)
92
- raise ArgumentError, "hour can only be 24 when minute and second are 0"
93
- end
94
- raise ArgumentError, "minute must be between 0 and 59" unless (0..59).include?(@minute)
95
- raise ArgumentError, "second must be between 0 and 59" unless (0..59).include?(@second)
38
+ attr_reader :hour, :minute, :second, :second_of_day
39
+ alias_method :min, :minute
40
+ alias_method :sec, :second
41
+ alias_method :to_i, :second_of_day
42
+
43
+ PARSE_24H_REGEX = /
44
+ \A
45
+ ([01]?\d|2[0-4])
46
+ :?
47
+ ([0-5]\d)?
48
+ :?
49
+ ([0-5]\d)?
50
+ \z
51
+ /x
52
+
53
+ PARSE_12H_REGEX = /
54
+ \A
55
+ (0?\d|1[0-2])
56
+ :?
57
+ ([0-5]\d)?
58
+ :?
59
+ ([0-5]\d)?
60
+ \s*
61
+ ([ap])
62
+ \.?
63
+ \s*
64
+ m?
65
+ \.?
66
+ \z
67
+ /x
68
+
69
+ WORDS = {
70
+ "noon" => "12pm".freeze,
71
+ "midnight" => "12am".freeze
72
+ }
73
+
74
+ NUM_SECONDS_IN_DAY = 86400
75
+ NUM_SECONDS_IN_HOUR = 3600
76
+ NUM_SECONDS_IN_MINUTE = 60
77
+
78
+ FORMATS = {
79
+ short: "%-l:%M %P".freeze,
80
+ medium: "%-l:%M:%S %P".freeze,
81
+ time: "%H:%M".freeze
82
+ }
83
+
84
+ def initialize(h, m=0, s=0)
85
+ @hour = Integer(h)
86
+ @minute = Integer(m)
87
+ @second = Integer(s)
88
+
89
+ raise ArgumentError, "hour must be between 0 and 24" unless (0..24).include?(@hour)
90
+ if @hour == 24 && (@minute != 0 || @second != 0)
91
+ raise ArgumentError, "hour can only be 24 when minute and second are 0"
92
+ end
93
+ raise ArgumentError, "minute must be between 0 and 59" unless (0..59).include?(@minute)
94
+ raise ArgumentError, "second must be between 0 and 59" unless (0..59).include?(@second)
96
95
 
97
- @second_of_day = @hour * 60 * 60 + @minute * 60 + @second
96
+ @second_of_day = @hour * 60 * 60 + @minute * 60 + @second
98
97
 
99
- freeze # TimeOfDay instances are value objects
100
- end
98
+ freeze # TimeOfDay instances are value objects
99
+ end
101
100
 
102
- def <=>(other)
103
- return unless other.respond_to?(:second_of_day)
104
- @second_of_day <=> other.second_of_day
105
- end
101
+ def <=>(other)
102
+ return unless other.respond_to?(:second_of_day)
103
+ @second_of_day <=> other.second_of_day
104
+ end
106
105
 
107
- # Rounding to the given nearest number of seconds
108
- def round(round_sec = 1)
109
- down = self - (self.to_i % round_sec)
110
- up = down + round_sec
106
+ # Rounding to the given nearest number of seconds
107
+ def round(round_sec = 1)
108
+ down = self - (self.to_i % round_sec)
109
+ up = down + round_sec
111
110
 
112
- difference_down = self - down
113
- difference_up = up - self
111
+ difference_down = self - down
112
+ difference_up = up - self
114
113
 
115
- if (difference_down < difference_up)
116
- return down
117
- else
118
- return up
119
- end
114
+ if (difference_down < difference_up)
115
+ return down
116
+ else
117
+ return up
120
118
  end
119
+ end
121
120
 
122
- # Formats identically to Time#strftime
123
- def strftime(format_string)
124
- # Special case 2400 because strftime will load TimeOfDay into Time which
125
- # will convert 24 to 0
126
- format_string = format_string.gsub(/%H|%k/, '24') if @hour == 24
127
- Time.local(2000,1,1, @hour, @minute, @second).strftime(format_string)
128
- end
121
+ # Formats identically to Time#strftime
122
+ def strftime(format_string)
123
+ # Special case 2400 because strftime will load TimeOfDay into Time which
124
+ # will convert 24 to 0
125
+ format_string = format_string.gsub(/%H|%k/, '24') if @hour == 24
126
+ Time.local(2000,1,1, @hour, @minute, @second).strftime(format_string)
127
+ end
129
128
 
130
- def to_formatted_s(format = :default)
131
- if formatter = FORMATS[format]
132
- if formatter.respond_to?(:call)
133
- formatter.call(self).to_s
134
- else
135
- strftime(formatter)
136
- end
129
+ def to_formatted_s(format = :default)
130
+ if formatter = FORMATS[format]
131
+ if formatter.respond_to?(:call)
132
+ formatter.call(self).to_s
137
133
  else
138
- strftime "%H:%M:%S"
134
+ strftime(formatter)
139
135
  end
136
+ else
137
+ strftime "%H:%M:%S"
140
138
  end
141
- alias_method :to_s, :to_formatted_s
142
-
143
- def value_for_database
144
- to_s
145
- end
139
+ end
140
+ alias_method :to_s, :to_formatted_s
146
141
 
147
- # Return a new TimeOfDay num_seconds greater than self. It will wrap around
148
- # at midnight.
149
- def +(num_seconds)
150
- TimeOfDay.from_second_of_day @second_of_day + num_seconds
151
- end
142
+ def value_for_database
143
+ to_s
144
+ end
152
145
 
153
- # Return a new TimeOfDay num_seconds less than self. It will wrap around
154
- # at midnight.
155
- def -(other)
156
- if other.instance_of?(TimeOfDay)
157
- TimeOfDay.from_second_of_day @second_of_day - other.second_of_day
158
- else
159
- TimeOfDay.from_second_of_day @second_of_day - other
160
- end
161
- end
146
+ # Return a new TimeOfDay num_seconds greater than self. It will wrap around
147
+ # at midnight.
148
+ def +(num_seconds)
149
+ TimeOfDay.from_second_of_day @second_of_day + num_seconds
150
+ end
162
151
 
163
- # Returns a Time instance on date using self as the time of day
164
- # Optional time_zone will build time in that zone
165
- def on(date, time_zone=Tod::TimeOfDay.time_zone)
166
- time_zone.local date.year, date.month, date.day, @hour, @minute, @second
152
+ # Return a new TimeOfDay num_seconds less than self. It will wrap around
153
+ # at midnight.
154
+ def -(other)
155
+ if other.instance_of?(TimeOfDay)
156
+ TimeOfDay.from_second_of_day @second_of_day - other.second_of_day
157
+ else
158
+ TimeOfDay.from_second_of_day @second_of_day - other
167
159
  end
160
+ end
168
161
 
169
- # Build a new TimeOfDay instance from second_of_day
170
- #
171
- # TimeOfDay.from_second_of_day(3600) == TimeOfDay.new(1) # => true
172
- def self.from_second_of_day(second_of_day)
173
- second_of_day = Integer(second_of_day)
174
- return new 24 if second_of_day == NUM_SECONDS_IN_DAY
175
- remaining_seconds = second_of_day % NUM_SECONDS_IN_DAY
176
- hour = remaining_seconds / NUM_SECONDS_IN_HOUR
177
- remaining_seconds -= hour * NUM_SECONDS_IN_HOUR
178
- minute = remaining_seconds / NUM_SECONDS_IN_MINUTE
179
- remaining_seconds -= minute * NUM_SECONDS_IN_MINUTE
180
- new hour, minute, remaining_seconds
181
- end
182
- class << self
183
- alias :from_i :from_second_of_day
184
- end
162
+ # Returns a Time instance on date using self as the time of day
163
+ # Optional time_zone will build time in that zone
164
+ def on(date, time_zone=Tod::TimeOfDay.time_zone)
165
+ time_zone.local date.year, date.month, date.day, @hour, @minute, @second
166
+ end
185
167
 
186
- # Build a TimeOfDay instance from string
187
- #
188
- # Strings only need to contain an hour. Minutes, seconds, AM or PM, and colons
189
- # are all optional.
190
- # TimeOfDay.parse "8" # => 08:00:00
191
- # TimeOfDay.parse "8am" # => 08:00:00
192
- # TimeOfDay.parse "8pm" # => 20:00:00
193
- # TimeOfDay.parse "8p" # => 20:00:00
194
- # TimeOfDay.parse "9:30" # => 09:30:00
195
- # TimeOfDay.parse "15:30" # => 15:30:00
196
- # TimeOfDay.parse "3:30pm" # => 15:30:00
197
- # TimeOfDay.parse "1230" # => 12:30:00
198
- # TimeOfDay.parse "3:25:58" # => 03:25:58
199
- # TimeOfDay.parse "515p" # => 17:15:00
200
- # TimeOfDay.parse "151253" # => 15:12:53
201
- # You can give a block, that is called with the input if the string is not parsable.
202
- # If no block is given an ArgumentError is raised if try_parse returns nil.
203
- def self.parse(tod_string)
204
- try_parse(tod_string) || (block_given? ? yield(tod_string) : raise(ArgumentError, "Invalid time of day string"))
205
- end
168
+ # Build a new TimeOfDay instance from second_of_day
169
+ #
170
+ # TimeOfDay.from_second_of_day(3600) == TimeOfDay.new(1) # => true
171
+ def self.from_second_of_day(second_of_day)
172
+ second_of_day = Integer(second_of_day)
173
+ return new 24 if second_of_day == NUM_SECONDS_IN_DAY
174
+ remaining_seconds = second_of_day % NUM_SECONDS_IN_DAY
175
+ hour = remaining_seconds / NUM_SECONDS_IN_HOUR
176
+ remaining_seconds -= hour * NUM_SECONDS_IN_HOUR
177
+ minute = remaining_seconds / NUM_SECONDS_IN_MINUTE
178
+ remaining_seconds -= minute * NUM_SECONDS_IN_MINUTE
179
+ new hour, minute, remaining_seconds
180
+ end
181
+ class << self
182
+ alias :from_i :from_second_of_day
183
+ end
206
184
 
207
- # Same as parse(), but return nil if not parsable (instead of raising an error)
208
- # TimeOfDay.try_parse "8am" # => 08:00:00
209
- # TimeOfDay.try_parse "" # => nil
210
- # TimeOfDay.try_parse "abc" # => nil
211
- def self.try_parse(tod_string)
212
- tod_string = tod_string.to_s
213
- tod_string = tod_string.strip
214
- tod_string = tod_string.downcase
215
- tod_string = WORDS[tod_string] || tod_string
216
- if PARSE_24H_REGEX =~ tod_string || PARSE_12H_REGEX =~ tod_string
217
- hour, minute, second, a_or_p = $1.to_i, $2.to_i, $3.to_i, $4
218
- if hour == 12 && a_or_p == "a"
219
- hour = 0
220
- elsif hour < 12 && a_or_p == "p"
221
- hour += 12
222
- end
185
+ # Build a TimeOfDay instance from string
186
+ #
187
+ # Strings only need to contain an hour. Minutes, seconds, AM or PM, and colons
188
+ # are all optional.
189
+ # TimeOfDay.parse "8" # => 08:00:00
190
+ # TimeOfDay.parse "8am" # => 08:00:00
191
+ # TimeOfDay.parse "8pm" # => 20:00:00
192
+ # TimeOfDay.parse "8p" # => 20:00:00
193
+ # TimeOfDay.parse "9:30" # => 09:30:00
194
+ # TimeOfDay.parse "15:30" # => 15:30:00
195
+ # TimeOfDay.parse "3:30pm" # => 15:30:00
196
+ # TimeOfDay.parse "1230" # => 12:30:00
197
+ # TimeOfDay.parse "3:25:58" # => 03:25:58
198
+ # TimeOfDay.parse "515p" # => 17:15:00
199
+ # TimeOfDay.parse "151253" # => 15:12:53
200
+ # You can give a block, that is called with the input if the string is not parsable.
201
+ # If no block is given an ArgumentError is raised if try_parse returns nil.
202
+ def self.parse(tod_string)
203
+ try_parse(tod_string) || (block_given? ? yield(tod_string) : raise(ArgumentError, "Invalid time of day string"))
204
+ end
223
205
 
224
- new hour, minute, second
225
- else
226
- nil
206
+ # Same as parse(), but return nil if not parsable (instead of raising an error)
207
+ # TimeOfDay.try_parse "8am" # => 08:00:00
208
+ # TimeOfDay.try_parse "" # => nil
209
+ # TimeOfDay.try_parse "abc" # => nil
210
+ def self.try_parse(tod_string)
211
+ tod_string = tod_string.to_s
212
+ tod_string = tod_string.strip
213
+ tod_string = tod_string.downcase
214
+ tod_string = WORDS[tod_string] || tod_string
215
+ if PARSE_24H_REGEX =~ tod_string || PARSE_12H_REGEX =~ tod_string
216
+ hour, minute, second, a_or_p = $1.to_i, $2.to_i, $3.to_i, $4
217
+ if hour == 12 && a_or_p == "a"
218
+ hour = 0
219
+ elsif hour < 12 && a_or_p == "p"
220
+ hour += 12
227
221
  end
228
- end
229
222
 
230
- # Determine if a string is parsable into a TimeOfDay instance
231
- # TimeOfDay.parsable? "8am" # => true
232
- # TimeOfDay.parsable? "abc" # => false
233
- def self.parsable?(tod_string)
234
- !!try_parse(tod_string)
223
+ new hour, minute, second
224
+ else
225
+ nil
235
226
  end
227
+ end
236
228
 
237
- # If ActiveSupport TimeZone is available and set use current time zone else return Time
238
- def self.time_zone
239
- (Time.respond_to?(:zone) && Time.zone) || Time
240
- end
229
+ # Determine if a string is parsable into a TimeOfDay instance
230
+ # TimeOfDay.parsable? "8am" # => true
231
+ # TimeOfDay.parsable? "abc" # => false
232
+ def self.parsable?(tod_string)
233
+ !!try_parse(tod_string)
234
+ end
241
235
 
242
- def self.dump(time_of_day)
243
- time_of_day =
244
- if time_of_day.is_a? Hash
245
- # rails multiparam attribute
246
- # get hour, minute and second and construct new TimeOfDay object
247
- ::Tod::TimeOfDay.new(time_of_day[4], time_of_day[5], time_of_day[6])
248
- else
249
- # return nil, if input is not parsable
250
- Tod::TimeOfDay(time_of_day){}
251
- end
252
- time_of_day.to_s if time_of_day
253
- end
236
+ # If ActiveSupport TimeZone is available and set use current time zone else return Time
237
+ def self.time_zone
238
+ (Time.respond_to?(:zone) && Time.zone) || Time
239
+ end
254
240
 
255
- def self.load(time)
256
- if time && !time.to_s.empty?
257
- return ::Tod::TimeOfDay.new(24) if time.respond_to?(:day) && time.day == 2 && time.hour == 0 && time.min == 0 && time.sec == 0
258
- ::Tod::TimeOfDay(time)
259
- end
241
+ def self.dump(time_of_day)
242
+ time_of_day =
243
+ if time_of_day.is_a? Hash
244
+ # rails multiparam attribute
245
+ # get hour, minute and second and construct new TimeOfDay object
246
+ ::Tod::TimeOfDay.new(time_of_day[4], time_of_day[5], time_of_day[6])
247
+ else
248
+ # return nil, if input is not parsable
249
+ Tod::TimeOfDay(time_of_day){}
250
+ end
251
+ time_of_day.to_s if time_of_day
252
+ end
253
+
254
+ def self.load(time)
255
+ if time && !time.to_s.empty?
256
+ return ::Tod::TimeOfDay.new(24) if time.respond_to?(:day) && time.day == 2 && time.hour == 0 && time.min == 0 && time.sec == 0
257
+ ::Tod::TimeOfDay(time)
260
258
  end
261
259
  end
262
260
  end