emery 0.0.2 → 0.0.8
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.
- checksums.yaml +4 -4
- data/lib/emery.rb +1 -3
- data/lib/emery/dataclass.rb +67 -65
- data/lib/emery/enum.rb +73 -75
- data/lib/emery/jsoner.rb +169 -164
- data/lib/emery/type.rb +149 -151
- data/test/dataclass_test.rb +80 -83
- data/test/enum_test.rb +29 -33
- data/test/jsoner_test.rb +217 -192
- data/test/type_test.rb +153 -155
- metadata +2 -4
- data/lib/emery/tod.rb +0 -262
- data/test/tod_test.rb +0 -41
data/test/type_test.rb
CHANGED
@@ -1,220 +1,218 @@
|
|
1
1
|
require "test/unit/runner/junitxml"
|
2
2
|
require "date"
|
3
3
|
|
4
|
-
require 'emery
|
4
|
+
require 'emery'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
6
|
+
class TypeEquality < Test::Unit::TestCase
|
7
|
+
def test_plain_equals
|
8
|
+
assert_true Integer == Integer
|
9
|
+
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def test_plain_not_equals
|
12
|
+
assert_false Integer == String
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
def test_uuid_equals
|
16
|
+
assert_true UUID == UUID
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
def test_boolean_equals
|
20
|
+
assert_true Boolean == Boolean
|
21
|
+
end
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
def test_untyped_equals
|
24
|
+
assert_true Untyped == Untyped
|
25
|
+
end
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
def test_nilable_equals
|
28
|
+
assert_true T.nilable(Integer) == T.nilable(Integer)
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
def test_nilable_not_equals
|
32
|
+
assert_false T.nilable(Integer) == T.nilable(String)
|
33
|
+
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
def test_array_equals
|
36
|
+
assert_true T.array(Integer) == T.array(Integer)
|
37
|
+
end
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
def test_array_not_equals
|
40
|
+
assert_false T.array(Integer) == Integer
|
41
|
+
end
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
def test_array_other_item_type
|
44
|
+
assert_false T.array(Integer) == T.array(String)
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
def test_hash_equals
|
48
|
+
assert_true T.hash(String, Integer) == T.hash(String, Integer)
|
49
|
+
end
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
def test_hash_not_equals
|
52
|
+
assert_false T.hash(String, Integer) == String
|
53
|
+
end
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
def test_hash_other_value_type
|
56
|
+
assert_false T.hash(String, Integer) == T.hash(String, String)
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
def test_any_equals
|
60
|
+
assert_true T.any(String, Integer) == T.any(String, Integer)
|
61
|
+
end
|
63
62
|
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
def test_any_equals_other_order
|
64
|
+
assert_true T.any(String, Integer) == T.any(Integer, String)
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
67
|
+
def test_any_of_other_type
|
68
|
+
assert_false T.any(String, Integer) == T.any(Integer, Float)
|
71
69
|
end
|
70
|
+
end
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
class TypeToString < Test::Unit::TestCase
|
73
|
+
def test_nilable
|
74
|
+
assert_equal "Nilable[Integer]", T.nilable(Integer).to_s
|
75
|
+
end
|
77
76
|
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
def test_array
|
78
|
+
assert_equal "Array[Integer]", T.array(Integer).to_s
|
79
|
+
end
|
81
80
|
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
def test_hash
|
82
|
+
assert_equal "Hash[String, Integer]", T.hash(String, Integer).to_s
|
83
|
+
end
|
85
84
|
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
def test_any
|
86
|
+
assert_equal "Any[String, Integer]", T.any(String, Integer).to_s
|
87
|
+
end
|
89
88
|
|
90
|
-
|
91
|
-
|
92
|
-
end
|
89
|
+
def test_union
|
90
|
+
assert_equal "Union[str: String, int: Integer]", T.union(str: String, int: Integer).to_s
|
93
91
|
end
|
92
|
+
end
|
94
93
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
class TypeCheck < Test::Unit::TestCase
|
95
|
+
def test_nil
|
96
|
+
assert_equal nil, T.check(NilClass, nil)
|
97
|
+
end
|
99
98
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
99
|
+
def test_nil_string
|
100
|
+
assert_raise TypeError do
|
101
|
+
T.check(String, nil)
|
104
102
|
end
|
103
|
+
end
|
105
104
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
105
|
+
def test_types_mismatch
|
106
|
+
assert_raise TypeError do
|
107
|
+
T.check(String, 123)
|
110
108
|
end
|
109
|
+
end
|
111
110
|
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
def test_string
|
112
|
+
assert_equal "the string", T.check(String, "the string"), "Plain String type should allow String value"
|
113
|
+
end
|
115
114
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
120
|
-
assert_match "Type String does not allow nil value", err.message
|
115
|
+
def test_string_nil
|
116
|
+
err = assert_raise TypeError do
|
117
|
+
T.check(String, nil)
|
121
118
|
end
|
119
|
+
assert_match "Type String does not allow nil value", err.message
|
120
|
+
end
|
122
121
|
|
123
|
-
|
124
|
-
|
125
|
-
|
122
|
+
def test_boolean
|
123
|
+
assert_equal true, T.check(Boolean, true), "Artificial Boolean type should allow true value"
|
124
|
+
end
|
126
125
|
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
def test_date
|
127
|
+
assert_equal Date.new(2020, 5, 24), T.check(Date, Date.new(2020, 5, 24)), "Date type should pass validation"
|
128
|
+
end
|
130
129
|
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
def test_datetime
|
131
|
+
assert_equal DateTime.new(2020, 5, 24, 14, 30, 30), T.check(Date, DateTime.new(2020, 5, 24, 14, 30, 30)), "DateTime type should pass validation"
|
132
|
+
end
|
134
133
|
|
135
|
-
|
136
|
-
|
137
|
-
|
134
|
+
def test_time
|
135
|
+
assert_equal Time.new(2007,11,5,13,45,0, "-05:00"), T.check(Time, Time.new(2007, 11, 5, 13, 45, 0, "-05:00")), "Time type should pass validation"
|
136
|
+
end
|
138
137
|
|
139
|
-
|
140
|
-
|
141
|
-
|
138
|
+
def test_uuid
|
139
|
+
assert_equal "123e4567-e89b-12d3-a456-426655440000", T.check(UUID, "123e4567-e89b-12d3-a456-426655440000"), "UUID type should pass validation on correctly formatted string"
|
140
|
+
end
|
142
141
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
142
|
+
def test_uuid_fail
|
143
|
+
assert_raise TypeError do
|
144
|
+
T.check(UUID, "really not the uuid")
|
147
145
|
end
|
146
|
+
end
|
148
147
|
|
149
|
-
|
150
|
-
|
151
|
-
|
148
|
+
def test_untyped_success
|
149
|
+
assert_equal "bla", T.check(Untyped, "bla"), "Untyped should accept strings"
|
150
|
+
end
|
152
151
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
end
|
152
|
+
def test_untyped_nil
|
153
|
+
assert_raise TypeError do
|
154
|
+
T.check(Untyped, nil)
|
157
155
|
end
|
156
|
+
end
|
158
157
|
|
159
|
-
|
160
|
-
|
161
|
-
|
158
|
+
def test_nilable_nil
|
159
|
+
assert_equal nil, T.check(T.nilable(String), nil), "Nilable type should allow nil value"
|
160
|
+
end
|
162
161
|
|
163
|
-
|
164
|
-
|
165
|
-
end
|
162
|
+
def test_nilable
|
163
|
+
assert_equal "the string", T.check(T.nilable(String), "the string"), "Nilable String type should allow String value"
|
166
164
|
end
|
165
|
+
end
|
167
166
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
167
|
+
class TypeCheckArray < Test::Unit::TestCase
|
168
|
+
def test_array_string
|
169
|
+
assert_equal ["the string"], T.check(T.array(String), ["the string"]), "Array of String should allow String value"
|
170
|
+
end
|
172
171
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
end
|
172
|
+
def test_array_fail
|
173
|
+
ex = assert_raise TypeError do
|
174
|
+
T.check(T.array(String), "the string")
|
177
175
|
end
|
176
|
+
puts ex
|
177
|
+
end
|
178
178
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
end
|
179
|
+
def test_array_wrong_item_type
|
180
|
+
assert_raise TypeError do
|
181
|
+
T.check(T.array(String), ["the string", 123])
|
183
182
|
end
|
184
183
|
end
|
184
|
+
end
|
185
185
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
186
|
+
class TypeCheckHash < Test::Unit::TestCase
|
187
|
+
def test_hash_string_to_string
|
188
|
+
assert_equal({"key" => "the value"}, T.check(T.hash(String, String), {"key" => "the value"}), "Hash of String -> String should allow String -> String value")
|
189
|
+
end
|
190
190
|
|
191
|
-
|
192
|
-
|
193
|
-
end
|
191
|
+
def test_hash_string_to_untyped
|
192
|
+
assert_equal({"key" => "the value"}, T.check(T.hash(String, Untyped), {"key" => "the value"}), "Hash of String -> Untyped should allow String -> String value")
|
194
193
|
end
|
194
|
+
end
|
195
195
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
196
|
+
class TypeCheckAny < Test::Unit::TestCase
|
197
|
+
def test_success
|
198
|
+
assert_equal(123, T.check(T.any(String, Integer), 123), "Any of String, Integer should allow Integer value")
|
199
|
+
end
|
200
200
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
201
|
+
def test_fail
|
202
|
+
assert_raise TypeError do
|
203
|
+
T.check(T.any(String, Integer), true)
|
205
204
|
end
|
206
205
|
end
|
206
|
+
end
|
207
207
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
208
|
+
class TypeCheckUnion < Test::Unit::TestCase
|
209
|
+
def test_success
|
210
|
+
assert_equal(123, T.check(T.union(str: String, int: Integer), 123))
|
211
|
+
end
|
212
212
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
end
|
213
|
+
def test_fail
|
214
|
+
assert_raise TypeError do
|
215
|
+
T.check(T.union(str: String, int: Integer), true)
|
217
216
|
end
|
218
217
|
end
|
219
|
-
|
220
218
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: emery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Sapronov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -34,12 +34,10 @@ files:
|
|
34
34
|
- lib/emery/dataclass.rb
|
35
35
|
- lib/emery/enum.rb
|
36
36
|
- lib/emery/jsoner.rb
|
37
|
-
- lib/emery/tod.rb
|
38
37
|
- lib/emery/type.rb
|
39
38
|
- test/dataclass_test.rb
|
40
39
|
- test/enum_test.rb
|
41
40
|
- test/jsoner_test.rb
|
42
|
-
- test/tod_test.rb
|
43
41
|
- test/type_test.rb
|
44
42
|
homepage: https://github.com/vsapronov/emery
|
45
43
|
licenses:
|
data/lib/emery/tod.rb
DELETED
@@ -1,262 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
|
3
|
-
source: https://github.com/jackc/tod
|
4
|
-
|
5
|
-
Copyright (c) 2010-2015 Jack Christensen
|
6
|
-
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
-
a copy of this software and associated documentation files (the
|
9
|
-
"Software"), to deal in the Software without restriction, including
|
10
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
-
permit persons to whom the Software is furnished to do so, subject to
|
13
|
-
the following conditions:
|
14
|
-
|
15
|
-
The above copyright notice and this permission notice shall be
|
16
|
-
included in all copies or substantial portions of the Software.
|
17
|
-
|
18
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
-
|
26
|
-
=end
|
27
|
-
|
28
|
-
module Emery
|
29
|
-
class TimeOfDay
|
30
|
-
include Comparable
|
31
|
-
|
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
|
38
|
-
|
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)
|
96
|
-
|
97
|
-
@second_of_day = @hour * 60 * 60 + @minute * 60 + @second
|
98
|
-
|
99
|
-
freeze # TimeOfDay instances are value objects
|
100
|
-
end
|
101
|
-
|
102
|
-
def <=>(other)
|
103
|
-
return unless other.respond_to?(:second_of_day)
|
104
|
-
@second_of_day <=> other.second_of_day
|
105
|
-
end
|
106
|
-
|
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
|
111
|
-
|
112
|
-
difference_down = self - down
|
113
|
-
difference_up = up - self
|
114
|
-
|
115
|
-
if (difference_down < difference_up)
|
116
|
-
return down
|
117
|
-
else
|
118
|
-
return up
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
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
|
129
|
-
|
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
|
137
|
-
else
|
138
|
-
strftime "%H:%M:%S"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
alias_method :to_s, :to_formatted_s
|
142
|
-
|
143
|
-
def value_for_database
|
144
|
-
to_s
|
145
|
-
end
|
146
|
-
|
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
|
152
|
-
|
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
|
162
|
-
|
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
|
167
|
-
end
|
168
|
-
|
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
|
185
|
-
|
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
|
206
|
-
|
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
|
223
|
-
|
224
|
-
new hour, minute, second
|
225
|
-
else
|
226
|
-
nil
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
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)
|
235
|
-
end
|
236
|
-
|
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
|
241
|
-
|
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
|
254
|
-
|
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
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|