subroutine 4.1.3 → 4.1.5

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
2
  SHA256:
3
- metadata.gz: c4fef2991f9d46da2fdbe6447c7e128042e8f60d6696a562f29b38e7cab2755d
4
- data.tar.gz: 4bd93645f7a6efbbaccfe2fd3c2049b0f6b4310cd959a9f75fc6c4d7a23d8e25
3
+ metadata.gz: 12ff37dae5fd328aaa0299e09ff2fe4827b98a3f59e0b4b6545a4b1176f834cf
4
+ data.tar.gz: 95609b587580e37a859ca906dc9a7c767dc589a32a58a3a86f9c2b9e70a2c27c
5
5
  SHA512:
6
- metadata.gz: cc3b421c2c645c7ca205efa89104d16805320c3a9407ad3aa34330545d62e6037f713998bb483da8bf59934b3e2b090e5add1254fe19f04f888457d4ac12aa38
7
- data.tar.gz: ee0734400bd7df20adadbbed1e565419995dca36f66e4f7d65664dac5c9ffb0a03041dc658842e307d3520825464cae6019b0e29fa843d01641e99eb35fc3bb2
6
+ metadata.gz: 8d29b8e4f5cb1511974c339f28552f85da427bd146a273783abab7951a059b402d96e3fb53c52f8aa64d50bc1f174b103f5c183b4b35f94fc7f570de8e2330ba
7
+ data.tar.gz: c144a73f6ff5dd51ad70ae3b1bc3d11aee020e9bc78a69805c40f1809e4597a9d51470d6974ef3259ac5975cde33d1c2beb5437985be12c116493d135b1e23a6
data/CHANGELOG.MD CHANGED
@@ -1,3 +1,13 @@
1
+ ## Subroutine 4.1.4
2
+
3
+ Fields using the time/timestamp/datetime caster will now default back to the old behavior, and use a `precision:` option to opt-in to the new behavior introduced in `v4.1.1`.
4
+
5
+ `precision: :seconds` will retain the old behavior of always parsing to a new Time object
6
+ with floored sub-second precision, but applied more forcefully than before as it would have parsed whatever you passed to it. (This is the default, now.)
7
+
8
+ `precision: :high` will now use the new functionality of re-using Time objects when they
9
+ are passed in, or if not parsing exactly the provided string as to a Time object.
10
+
1
11
  ## Subroutine 4.1.1
2
12
 
3
13
  Fields using the time/timestamp/datetime caster will now return exactly the passed in value
@@ -4,11 +4,15 @@ require 'date'
4
4
  require 'time'
5
5
  require 'bigdecimal'
6
6
  require 'securerandom'
7
+ require 'active_support/json'
8
+ require 'active_support/core_ext/date_time/acts_like'
9
+ require 'active_support/core_ext/date_time/calculations'
7
10
  require 'active_support/core_ext/object/acts_like'
8
11
  require 'active_support/core_ext/object/blank'
9
12
  require 'active_support/core_ext/object/try'
10
13
  require 'active_support/core_ext/array/wrap'
11
14
  require 'active_support/core_ext/time/acts_like'
15
+ require 'active_support/core_ext/time/calculations'
12
16
 
13
17
  module Subroutine
14
18
  module TypeCaster
@@ -108,7 +112,7 @@ end
108
112
  t ||= value if value.is_a?(::Time)
109
113
  t ||= value if value.try(:acts_like?, :time)
110
114
  t ||= ::Time.parse(String(value))
111
- t.utc.iso8601
115
+ t.utc.iso8601(::ActiveSupport::JSON::Encoding.time_precision)
112
116
  end
113
117
 
114
118
  ::Subroutine::TypeCaster.register :date do |value, _options = {}|
@@ -117,14 +121,19 @@ end
117
121
  ::Date.parse(String(value))
118
122
  end
119
123
 
120
- ::Subroutine::TypeCaster.register :time, :timestamp, :datetime do |value, _options = {}|
124
+ ::Subroutine::TypeCaster.register :time, :timestamp, :datetime do |value, options = {}|
121
125
  next nil unless value.present?
122
126
 
123
- if value.try(:acts_like?, :time)
124
- value
127
+ value = if value.try(:acts_like?, :time)
128
+ value.to_time
125
129
  else
126
130
  ::Time.parse(String(value))
127
131
  end
132
+
133
+ # High precision must be opted into. The original implementation is to set usec:0
134
+ next value if options[:precision] == :high || ::Subroutine.preserve_time_precision?
135
+
136
+ value.change(usec: 0)
128
137
  end
129
138
 
130
139
  ::Subroutine::TypeCaster.register :hash, :object, :hashmap, :dict do |value, _options = {}|
@@ -4,7 +4,7 @@ module Subroutine
4
4
 
5
5
  MAJOR = 4
6
6
  MINOR = 1
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
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_model"
4
+ require "active_support"
4
5
  require "active_support/concern"
5
6
  require "active_support/core_ext/hash/indifferent_access"
6
7
  require "active_support/core_ext/module/redefine_method"
@@ -33,4 +34,14 @@ module Subroutine
33
34
  @inheritable_field_options ||= %i[mass_assignable field_reader field_writer groups aka]
34
35
  end
35
36
 
37
+ def self.preserve_time_precision=(bool)
38
+ @preserve_time_precision = !!bool
39
+ end
40
+
41
+ def self.preserve_time_precision?
42
+ return !!@preserve_time_precision if defined?(@preserve_time_precision)
43
+
44
+ false
45
+ end
46
+
36
47
  end
@@ -269,7 +269,7 @@ module Subroutine
269
269
  assert_nil op.date_input
270
270
  end
271
271
 
272
- def test_time_inputs
272
+ def test_time_inputs__with_seconds_precision
273
273
  op.time_input = nil
274
274
  assert_nil op.time_input
275
275
 
@@ -284,22 +284,153 @@ module Subroutine
284
284
  assert_equal 0, op.time_input.min
285
285
  assert_equal 0, op.time_input.sec
286
286
 
287
+ op.time_input = ::DateTime.new(2022, 12, 22)
288
+ assert_equal ::Time, op.time_input.class
289
+ refute_equal ::DateTime, op.time_input.class
290
+
291
+ assert_equal 0, op.time_input.utc_offset
292
+ assert_equal 2022, op.time_input.year
293
+ assert_equal 12, op.time_input.month
294
+ assert_equal 22, op.time_input.day
295
+ assert_equal 0, op.time_input.hour
296
+ assert_equal 0, op.time_input.min
297
+ assert_equal 0, op.time_input.sec
298
+
287
299
  op.time_input = '2023-05-05T10:00:30.123456Z'
288
300
  assert_equal ::Time, op.time_input.class
289
301
  refute_equal ::DateTime, op.time_input.class
290
302
 
303
+ assert_equal 0, op.time_input.utc_offset
291
304
  assert_equal 2023, op.time_input.year
292
305
  assert_equal 5, op.time_input.month
293
306
  assert_equal 5, op.time_input.day
294
307
  assert_equal 10, op.time_input.hour
295
308
  assert_equal 0, op.time_input.min
296
309
  assert_equal 30, op.time_input.sec
297
- assert_equal 123456, op.time_input.usec
310
+ assert_equal 0, op.time_input.usec
298
311
 
299
- time = Time.at(1678741605.123456)
312
+ op.time_input = '2023-05-05T10:00:30Z'
313
+ assert_equal ::Time, op.time_input.class
314
+ assert_equal 0, op.time_input.utc_offset
315
+ assert_equal 2023, op.time_input.year
316
+ assert_equal 5, op.time_input.month
317
+ assert_equal 5, op.time_input.day
318
+ assert_equal 10, op.time_input.hour
319
+ assert_equal 0, op.time_input.min
320
+ assert_equal 30, op.time_input.sec
321
+ assert_equal 0, op.time_input.usec
322
+
323
+ op.time_input = '2024-11-11T16:42:23.246+0100'
324
+ assert_equal ::Time, op.time_input.class
325
+ assert_equal 3600, op.time_input.utc_offset
326
+ assert_equal 2024, op.time_input.year
327
+ assert_equal 11, op.time_input.month
328
+ assert_equal 11, op.time_input.day
329
+ assert_equal 16, op.time_input.hour
330
+ assert_equal 42, op.time_input.min
331
+ assert_equal 23, op.time_input.sec
332
+ assert_equal 0, op.time_input.usec
333
+
334
+ time = Time.at(1678741605.123456).utc
335
+ op.time_input = time
336
+ refute_equal time, op.time_input
337
+ refute_equal time.object_id, op.time_input.object_id
338
+ assert_equal 2023, op.time_input.year
339
+ assert_equal 3, op.time_input.month
340
+ assert_equal 13, op.time_input.day
341
+ assert_equal 21, op.time_input.hour
342
+ assert_equal 6, op.time_input.min
343
+ assert_equal 45, op.time_input.sec
344
+ assert_equal 0, op.time_input.usec
345
+ end
346
+
347
+ def test_time_inputs__with_preserve_time_precision
348
+ Subroutine.stubs(:preserve_time_precision?).returns(true)
349
+
350
+ time = Time.at(1678741605.123456).utc
300
351
  op.time_input = time
301
- assert_equal time, op.time_input
302
- assert_equal time.object_id, op.time_input.object_id
352
+ assert_equal 2023, op.time_input.year
353
+ assert_equal 3, op.time_input.month
354
+ assert_equal 13, op.time_input.day
355
+ assert_equal 21, op.time_input.hour
356
+ assert_equal 6, op.time_input.min
357
+ assert_equal 45, op.time_input.sec
358
+ assert_equal 123456, op.time_input.usec
359
+ end
360
+
361
+ def test_time_inputs__with_high_precision
362
+ op.precise_time_input = nil
363
+ assert_nil op.precise_time_input
364
+
365
+ op.precise_time_input = '2022-12-22'
366
+ assert_equal ::Time, op.precise_time_input.class
367
+ refute_equal ::DateTime, op.precise_time_input.class
368
+
369
+ assert_equal 2022, op.precise_time_input.year
370
+ assert_equal 12, op.precise_time_input.month
371
+ assert_equal 22, op.precise_time_input.day
372
+ assert_equal 0, op.precise_time_input.hour
373
+ assert_equal 0, op.precise_time_input.min
374
+ assert_equal 0, op.precise_time_input.sec
375
+
376
+ op.precise_time_input = ::DateTime.new(2022, 12, 22)
377
+ assert_equal ::Time, op.precise_time_input.class
378
+ refute_equal ::DateTime, op.precise_time_input.class
379
+
380
+ assert_equal 0, op.precise_time_input.utc_offset
381
+ assert_equal 2022, op.precise_time_input.year
382
+ assert_equal 12, op.precise_time_input.month
383
+ assert_equal 22, op.precise_time_input.day
384
+ assert_equal 0, op.precise_time_input.hour
385
+ assert_equal 0, op.precise_time_input.min
386
+ assert_equal 0, op.precise_time_input.sec
387
+
388
+ op.precise_time_input = '2023-05-05T10:00:30.123456Z'
389
+ assert_equal ::Time, op.precise_time_input.class
390
+ refute_equal ::DateTime, op.precise_time_input.class
391
+
392
+ assert_equal 0, op.precise_time_input.utc_offset
393
+ assert_equal 2023, op.precise_time_input.year
394
+ assert_equal 5, op.precise_time_input.month
395
+ assert_equal 5, op.precise_time_input.day
396
+ assert_equal 10, op.precise_time_input.hour
397
+ assert_equal 0, op.precise_time_input.min
398
+ assert_equal 30, op.precise_time_input.sec
399
+ assert_equal 123456, op.precise_time_input.usec
400
+
401
+ op.precise_time_input = '2023-05-05T10:00:30Z'
402
+ assert_equal ::Time, op.precise_time_input.class
403
+ assert_equal 0, op.precise_time_input.utc_offset
404
+ assert_equal 2023, op.precise_time_input.year
405
+ assert_equal 5, op.precise_time_input.month
406
+ assert_equal 5, op.precise_time_input.day
407
+ assert_equal 10, op.precise_time_input.hour
408
+ assert_equal 0, op.precise_time_input.min
409
+ assert_equal 30, op.precise_time_input.sec
410
+ assert_equal 0, op.precise_time_input.usec
411
+
412
+ op.precise_time_input = '2024-11-11T16:42:23.246+0100'
413
+ assert_equal ::Time, op.precise_time_input.class
414
+ assert_equal 3600, op.precise_time_input.utc_offset
415
+ assert_equal 2024, op.precise_time_input.year
416
+ assert_equal 11, op.precise_time_input.month
417
+ assert_equal 11, op.precise_time_input.day
418
+ assert_equal 16, op.precise_time_input.hour
419
+ assert_equal 42, op.precise_time_input.min
420
+ assert_equal 23, op.precise_time_input.sec
421
+ assert_equal 246000, op.precise_time_input.usec
422
+
423
+ time = Time.at(1678741605.123456).utc
424
+ op.precise_time_input = time
425
+ assert_equal time, op.precise_time_input
426
+ assert_equal time.object_id, op.precise_time_input.object_id
427
+ assert_equal 2023, op.precise_time_input.year
428
+ assert_equal 3, op.precise_time_input.month
429
+ assert_equal 13, op.precise_time_input.day
430
+ assert_equal 21, op.precise_time_input.hour
431
+ assert_equal 6, op.precise_time_input.min
432
+ assert_equal 45, op.precise_time_input.sec
433
+ assert_equal 123456, op.precise_time_input.usec
303
434
  end
304
435
 
305
436
  def test_iso_date_inputs
@@ -321,11 +452,11 @@ module Subroutine
321
452
 
322
453
  op.iso_time_input = '2022-12-22T10:30:24Z'
323
454
  assert_equal ::String, op.iso_time_input.class
324
- assert_equal '2022-12-22T10:30:24Z', op.iso_time_input
455
+ assert_equal '2022-12-22T10:30:24.000Z', op.iso_time_input
325
456
 
326
- op.iso_time_input = Time.parse('2022-12-22T10:30:24Z')
457
+ op.iso_time_input = Time.parse('2022-12-22T10:30:24.123456Z')
327
458
  assert_equal ::String, op.iso_time_input.class
328
- assert_equal '2022-12-22T10:30:24Z', op.iso_time_input
459
+ assert_equal '2022-12-22T10:30:24.123Z', op.iso_time_input
329
460
  end
330
461
 
331
462
  def test_file_inputs
data/test/support/ops.rb CHANGED
@@ -173,6 +173,7 @@ class TypeCastOp < ::Subroutine::Op
173
173
  boolean :boolean_input
174
174
  date :date_input
175
175
  time :time_input, default: -> { Time.now }
176
+ time :precise_time_input, precision: :high
176
177
  iso_date :iso_date_input
177
178
  iso_time :iso_time_input
178
179
  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: 4.1.3
4
+ version: 4.1.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
@@ -212,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
212
  - !ruby/object:Gem::Version
213
213
  version: '0'
214
214
  requirements: []
215
- rubygems_version: 3.4.19
215
+ rubygems_version: 3.5.23
216
216
  signing_key:
217
217
  specification_version: 4
218
218
  summary: Feature-driven operation objects.