subroutine 3.0.3 → 3.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2dedf592996ae8331d333379af49033a3f5a3e74a4c8dd8d8cf5fbe7c878258
4
- data.tar.gz: ab33d0b731a9f28b52e4661fdcb6626d6eda2f2e8883a8f05ecfa2b529f2961a
3
+ metadata.gz: e7441c613353cda046900b7165d787576d3cb757943496fb7b4ccc65a9f5faf1
4
+ data.tar.gz: b154f7ab48dc32c391be450bc684ee34d59451d6e327d90f463654d53e8f0a55
5
5
  SHA512:
6
- metadata.gz: 26617e51aeb874dbabb64ad62add32903ad734014ed09e4b0c59f81829bb9bbf728726ab4c7690d82ce1280967b59507c689a58464c13216ad46df87b99c0ff5
7
- data.tar.gz: 3a45d5cbac6d68660c875e0c7163b403276b360a7d37efb86199d2b593c04876060e6f83b99cef3e0dd2c144cba2c75c11a2eeb51a17253bfff49cb6657c55c7
6
+ metadata.gz: 9da5a1f35f9888ebc970e23c60e53871258d837767b6baf3597fb216c64eca039171d993f4abc8c02627b678623e47df35defe5a79799a6c166ff7aebc2cb712
7
+ data.tar.gz: 5df7cc84df8ec5b19f60f9101fb66abeee95b578b474d956d378857132a60881a039c55ddecc4b8e6405b1ef9c95fb69f5b3d2d3ffc3fd5cb02bdce0aba8da4d
@@ -4,11 +4,16 @@ require 'date'
4
4
  require 'time'
5
5
  require 'bigdecimal'
6
6
  require 'securerandom'
7
+ require 'active_support'
8
+ require 'active_support/json'
9
+ require 'active_support/core_ext/date_time/acts_like'
10
+ require 'active_support/core_ext/date_time/calculations'
7
11
  require 'active_support/core_ext/object/acts_like'
8
12
  require 'active_support/core_ext/object/blank'
9
13
  require 'active_support/core_ext/object/try'
10
14
  require 'active_support/core_ext/array/wrap'
11
15
  require 'active_support/core_ext/time/acts_like'
16
+ require 'active_support/core_ext/time/calculations'
12
17
 
13
18
  module Subroutine
14
19
  module TypeCaster
@@ -108,7 +113,7 @@ end
108
113
  t ||= value if value.is_a?(::Time)
109
114
  t ||= value if value.try(:acts_like?, :time)
110
115
  t ||= ::Time.parse(String(value))
111
- t.utc.iso8601
116
+ t.utc.iso8601(::ActiveSupport::JSON::Encoding.time_precision)
112
117
  end
113
118
 
114
119
  ::Subroutine::TypeCaster.register :date do |value, _options = {}|
@@ -117,14 +122,19 @@ end
117
122
  ::Date.parse(String(value))
118
123
  end
119
124
 
120
- ::Subroutine::TypeCaster.register :time, :timestamp, :datetime do |value, _options = {}|
125
+ ::Subroutine::TypeCaster.register :time, :timestamp, :datetime do |value, options = {}|
121
126
  next nil unless value.present?
122
127
 
123
- if value.try(:acts_like?, :time)
124
- value
128
+ value = if value.try(:acts_like?, :time)
129
+ value.to_time
125
130
  else
126
131
  ::Time.parse(String(value))
127
132
  end
133
+
134
+ # High precision must be opted into. The original implementation is to set usec:0
135
+ next value if options[:precision] == :high || ::Subroutine.preserve_time_precision?
136
+
137
+ value.change(usec: 0)
128
138
  end
129
139
 
130
140
  ::Subroutine::TypeCaster.register :hash, :object, :hashmap, :dict do |value, _options = {}|
@@ -4,7 +4,7 @@ module Subroutine
4
4
 
5
5
  MAJOR = 3
6
6
  MINOR = 0
7
- PATCH = 3
7
+ PATCH = 5
8
8
  PRE = nil
9
9
 
10
10
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
data/lib/subroutine.rb CHANGED
@@ -3,3 +3,17 @@
3
3
  require "subroutine/version"
4
4
  require "subroutine/fields"
5
5
  require "subroutine/op"
6
+
7
+ module Subroutine
8
+
9
+ def self.preserve_time_precision=(bool)
10
+ @preserve_time_precision = !!bool
11
+ end
12
+
13
+ def self.preserve_time_precision?
14
+ return !!@preserve_time_precision if defined?(@preserve_time_precision)
15
+
16
+ false
17
+ end
18
+
19
+ end
@@ -241,7 +241,7 @@ module Subroutine
241
241
  assert_nil op.date_input
242
242
  end
243
243
 
244
- def test_time_inputs
244
+ def test_time_inputs__with_seconds_precision
245
245
  op.time_input = nil
246
246
  assert_nil op.time_input
247
247
 
@@ -256,22 +256,153 @@ module Subroutine
256
256
  assert_equal 0, op.time_input.min
257
257
  assert_equal 0, op.time_input.sec
258
258
 
259
+ op.time_input = ::DateTime.new(2022, 12, 22)
260
+ assert_equal ::Time, op.time_input.class
261
+ refute_equal ::DateTime, op.time_input.class
262
+
263
+ assert_equal 0, op.time_input.utc_offset
264
+ assert_equal 2022, op.time_input.year
265
+ assert_equal 12, op.time_input.month
266
+ assert_equal 22, op.time_input.day
267
+ assert_equal 0, op.time_input.hour
268
+ assert_equal 0, op.time_input.min
269
+ assert_equal 0, op.time_input.sec
270
+
259
271
  op.time_input = '2023-05-05T10:00:30.123456Z'
260
272
  assert_equal ::Time, op.time_input.class
261
273
  refute_equal ::DateTime, op.time_input.class
262
274
 
275
+ assert_equal 0, op.time_input.utc_offset
263
276
  assert_equal 2023, op.time_input.year
264
277
  assert_equal 5, op.time_input.month
265
278
  assert_equal 5, op.time_input.day
266
279
  assert_equal 10, op.time_input.hour
267
280
  assert_equal 0, op.time_input.min
268
281
  assert_equal 30, op.time_input.sec
269
- assert_equal 123456, op.time_input.usec
282
+ assert_equal 0, op.time_input.usec
270
283
 
271
- time = Time.at(1678741605.123456)
284
+ op.time_input = '2023-05-05T10:00:30Z'
285
+ assert_equal ::Time, op.time_input.class
286
+ assert_equal 0, op.time_input.utc_offset
287
+ assert_equal 2023, op.time_input.year
288
+ assert_equal 5, op.time_input.month
289
+ assert_equal 5, op.time_input.day
290
+ assert_equal 10, op.time_input.hour
291
+ assert_equal 0, op.time_input.min
292
+ assert_equal 30, op.time_input.sec
293
+ assert_equal 0, op.time_input.usec
294
+
295
+ op.time_input = '2024-11-11T16:42:23.246+0100'
296
+ assert_equal ::Time, op.time_input.class
297
+ assert_equal 3600, op.time_input.utc_offset
298
+ assert_equal 2024, op.time_input.year
299
+ assert_equal 11, op.time_input.month
300
+ assert_equal 11, op.time_input.day
301
+ assert_equal 16, op.time_input.hour
302
+ assert_equal 42, op.time_input.min
303
+ assert_equal 23, op.time_input.sec
304
+ assert_equal 0, op.time_input.usec
305
+
306
+ time = Time.at(1678741605.123456).utc
307
+ op.time_input = time
308
+ refute_equal time, op.time_input
309
+ refute_equal time.object_id, op.time_input.object_id
310
+ assert_equal 2023, op.time_input.year
311
+ assert_equal 3, op.time_input.month
312
+ assert_equal 13, op.time_input.day
313
+ assert_equal 21, op.time_input.hour
314
+ assert_equal 6, op.time_input.min
315
+ assert_equal 45, op.time_input.sec
316
+ assert_equal 0, op.time_input.usec
317
+ end
318
+
319
+ def test_time_inputs__with_preserve_time_precision
320
+ Subroutine.stubs(:preserve_time_precision?).returns(true)
321
+
322
+ time = Time.at(1678741605.123456).utc
272
323
  op.time_input = time
273
- assert_equal time, op.time_input
274
- assert_equal time.object_id, op.time_input.object_id
324
+ assert_equal 2023, op.time_input.year
325
+ assert_equal 3, op.time_input.month
326
+ assert_equal 13, op.time_input.day
327
+ assert_equal 21, op.time_input.hour
328
+ assert_equal 6, op.time_input.min
329
+ assert_equal 45, op.time_input.sec
330
+ assert_equal 123456, op.time_input.usec
331
+ end
332
+
333
+ def test_time_inputs__with_high_precision
334
+ op.precise_time_input = nil
335
+ assert_nil op.precise_time_input
336
+
337
+ op.precise_time_input = '2022-12-22'
338
+ assert_equal ::Time, op.precise_time_input.class
339
+ refute_equal ::DateTime, op.precise_time_input.class
340
+
341
+ assert_equal 2022, op.precise_time_input.year
342
+ assert_equal 12, op.precise_time_input.month
343
+ assert_equal 22, op.precise_time_input.day
344
+ assert_equal 0, op.precise_time_input.hour
345
+ assert_equal 0, op.precise_time_input.min
346
+ assert_equal 0, op.precise_time_input.sec
347
+
348
+ op.precise_time_input = ::DateTime.new(2022, 12, 22)
349
+ assert_equal ::Time, op.precise_time_input.class
350
+ refute_equal ::DateTime, op.precise_time_input.class
351
+
352
+ assert_equal 0, op.precise_time_input.utc_offset
353
+ assert_equal 2022, op.precise_time_input.year
354
+ assert_equal 12, op.precise_time_input.month
355
+ assert_equal 22, op.precise_time_input.day
356
+ assert_equal 0, op.precise_time_input.hour
357
+ assert_equal 0, op.precise_time_input.min
358
+ assert_equal 0, op.precise_time_input.sec
359
+
360
+ op.precise_time_input = '2023-05-05T10:00:30.123456Z'
361
+ assert_equal ::Time, op.precise_time_input.class
362
+ refute_equal ::DateTime, op.precise_time_input.class
363
+
364
+ assert_equal 0, op.precise_time_input.utc_offset
365
+ assert_equal 2023, op.precise_time_input.year
366
+ assert_equal 5, op.precise_time_input.month
367
+ assert_equal 5, op.precise_time_input.day
368
+ assert_equal 10, op.precise_time_input.hour
369
+ assert_equal 0, op.precise_time_input.min
370
+ assert_equal 30, op.precise_time_input.sec
371
+ assert_equal 123456, op.precise_time_input.usec
372
+
373
+ op.precise_time_input = '2023-05-05T10:00:30Z'
374
+ assert_equal ::Time, op.precise_time_input.class
375
+ assert_equal 0, op.precise_time_input.utc_offset
376
+ assert_equal 2023, op.precise_time_input.year
377
+ assert_equal 5, op.precise_time_input.month
378
+ assert_equal 5, op.precise_time_input.day
379
+ assert_equal 10, op.precise_time_input.hour
380
+ assert_equal 0, op.precise_time_input.min
381
+ assert_equal 30, op.precise_time_input.sec
382
+ assert_equal 0, op.precise_time_input.usec
383
+
384
+ op.precise_time_input = '2024-11-11T16:42:23.246+0100'
385
+ assert_equal ::Time, op.precise_time_input.class
386
+ assert_equal 3600, op.precise_time_input.utc_offset
387
+ assert_equal 2024, op.precise_time_input.year
388
+ assert_equal 11, op.precise_time_input.month
389
+ assert_equal 11, op.precise_time_input.day
390
+ assert_equal 16, op.precise_time_input.hour
391
+ assert_equal 42, op.precise_time_input.min
392
+ assert_equal 23, op.precise_time_input.sec
393
+ assert_equal 246000, op.precise_time_input.usec
394
+
395
+ time = Time.at(1678741605.123456).utc
396
+ op.precise_time_input = time
397
+ assert_equal time, op.precise_time_input
398
+ assert_equal time.object_id, op.precise_time_input.object_id
399
+ assert_equal 2023, op.precise_time_input.year
400
+ assert_equal 3, op.precise_time_input.month
401
+ assert_equal 13, op.precise_time_input.day
402
+ assert_equal 21, op.precise_time_input.hour
403
+ assert_equal 6, op.precise_time_input.min
404
+ assert_equal 45, op.precise_time_input.sec
405
+ assert_equal 123456, op.precise_time_input.usec
275
406
  end
276
407
 
277
408
  def test_iso_date_inputs
@@ -293,11 +424,11 @@ module Subroutine
293
424
 
294
425
  op.iso_time_input = '2022-12-22T10:30:24Z'
295
426
  assert_equal ::String, op.iso_time_input.class
296
- assert_equal '2022-12-22T10:30:24Z', op.iso_time_input
427
+ assert_equal '2022-12-22T10:30:24.000Z', op.iso_time_input
297
428
 
298
- op.iso_time_input = Time.parse('2022-12-22T10:30:24Z')
429
+ op.iso_time_input = Time.parse('2022-12-22T10:30:24.123456Z')
299
430
  assert_equal ::String, op.iso_time_input.class
300
- assert_equal '2022-12-22T10:30:24Z', op.iso_time_input
431
+ assert_equal '2022-12-22T10:30:24.123Z', op.iso_time_input
301
432
  end
302
433
 
303
434
  def test_file_inputs
data/test/support/ops.rb CHANGED
@@ -177,6 +177,7 @@ class TypeCastOp < ::Subroutine::Op
177
177
  boolean :boolean_input
178
178
  date :date_input
179
179
  time :time_input, default: -> { Time.now }
180
+ time :precise_time_input, precision: :high
180
181
  iso_date :iso_date_input
181
182
  iso_time :iso_time_input
182
183
  object :object_input
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subroutine
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-05 00:00:00.000000000 Z
11
+ date: 2024-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel