fugit 1.11.0 → 1.11.2

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: 85c52688755255cf02f4dde422a66df260a9e9b1e13d7aebc08ff48e4c3fd158
4
- data.tar.gz: bf29e925bda6258e55e25208cfacff5ad82dfd9bd28683bb65c79ec95c5e37f1
3
+ metadata.gz: c0951fa769cae432ad6e27c721a2abd80464c0d664a9254ba034de7dfcaaef23
4
+ data.tar.gz: 27bf22062b2e54764ae30cf68d39e8f514a5e5fdb43034a33b738ae3be9326b8
5
5
  SHA512:
6
- metadata.gz: 6754049a51e4886bd806fe7d97ea64e5e0fc74851c579a7e8d46b7b42dedaa08aea04a9a8bec2f6c560df8a5cf57977dfdc6f8f33a73675dad885ad95b22c73f
7
- data.tar.gz: 03b507d208bee88cae70f7d85875e931600576a2e048fd8523d8c7ed58b8d34ea40423ff93be04cab42e73bb67ed5580e41e89e0bae1363c9a624a8865979d4f
6
+ metadata.gz: 5ceb6ff8033f80397465ddbb2b0d8ba17739208c7d0ecf3ce594fde86912c7d6ef8cccbff4b1f4e094bfa4fee6eeedbf9a3e136ba7732894e810c63a584442b8
7
+ data.tar.gz: 24ad8e57d86132aac3231e56f162abc5454d608bab8fa61d90c22ea9af334b30a3b32d072db72fa425cce244f38da18dfbb814a2b0e23bd588b5d86006ff5f4e
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
+ ## fugit 1.11.2 released 2025-08-22
6
+
7
+ * Fix "every day at midnight America/Los_Angeles", gh-113, Mark R. James
8
+ * Avoid Hash#partition https://bugs.ruby-lang.org/issues/16252
9
+ * Fix Fugit::Nat "zero dark forty", gh-107
10
+ * Ensure @yearly and other specials accept a timezone
11
+
12
+
13
+ ## fugit 1.11.1 released 2024-08-15
14
+
15
+ * Prevent nat parsing chocking on long input (> 256 chars), gh-104
16
+
17
+
5
18
  ## fugit 1.11.0 released 2024-04-24
6
19
 
7
20
  * Revert gh-86 ban on `every 27 hours` / `* */27 * * *` for gh-103
data/CREDITS.md CHANGED
@@ -1,6 +1,11 @@
1
1
 
2
2
  # fugit credits
3
3
 
4
+ * Mark R. James, https://github.com/mrj, AM vs America/Los_Angeles, gh-113
5
+ * Tejas Bubane, https://github.com/tejasbubane, r3.4 in test matrix, gh-109
6
+ * Luis Castillo, https://github.com/lekastillo, nice_hash gh-108
7
+ * Geremia Taglialatela, https://github.com/tagliala, gh-105 gh-107
8
+ * https://github.com/personnumber3377, gh-104 Fugit.parse choke on long input
4
9
  * Michael Scrivo, https://github.com/mscrivo, gh-103
5
10
  * Benjamin Darcet, https://github.com/bdarcet gh-95 gh-96 et-orbi #rweek
6
11
  * https://github.com/franckduche gh-95 gh-96 et-orbi #rweek
data/LICENSE.txt CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- Copyright (c) 2017-2024, John Mettraux, jmettraux+flor@gmail.com
2
+ Copyright (c) 2017-2025, John Mettraux, jmettraux+flor@gmail.com
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -17,31 +17,33 @@ Fugit is a core dependency of [rufus-scheduler](https://github.com/jmettraux/ruf
17
17
 
18
18
  The intersection of those two projects is where fugit is born:
19
19
 
20
- * [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) - a cron/at/in/every/interval in-process scheduler, in fact, it's the father project to this fugit project
21
- * [flor](https://github.com/floraison/flor) - a Ruby workflow engine, fugit provides the foundation for its time scheduling capabilities
20
+ * [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) a cron/at/in/every/interval in-process scheduler, in fact, it's the father project to this fugit project
21
+ * [flor](https://github.com/floraison/flor) a Ruby workflow engine, fugit provides the foundation for its time scheduling capabilities
22
22
 
23
23
  ### Similar, sometimes overlapping projects
24
24
 
25
- * [chronic](https://github.com/mojombo/chronic) - a pure Ruby natural language date parser
26
- * [parse-cron](https://github.com/siebertm/parse-cron) - parses cron expressions and calculates the next occurrence after a given date
27
- * [ice_cube](https://github.com/seejohnrun/ice_cube) - Ruby date recurrence library
28
- * [ISO8601](https://github.com/arnau/ISO8601) - Ruby parser to work with ISO8601 dateTimes and durations
29
- * [chrono](https://github.com/r7kamura/chrono) - a chain of logics about chronology
30
- * [CronCalc](https://github.com/mizinsky/cron_calc) - calculates cron job occurrences
31
- * [Recurrence](https://github.com/fnando/recurrence) - a simple library to handle recurring events
25
+ * [chronic](https://github.com/mojombo/chronic) a pure Ruby natural language date parser
26
+ * [parse-cron](https://github.com/siebertm/parse-cron) parses cron expressions and calculates the next occurrence after a given date
27
+ * [ice_cube](https://github.com/seejohnrun/ice_cube) Ruby date recurrence library
28
+ * [ISO8601](https://github.com/arnau/ISO8601) Ruby parser to work with ISO8601 dateTimes and durations
29
+ * [chrono](https://github.com/r7kamura/chrono) a chain of logics about chronology
30
+ * [CronCalc](https://github.com/mizinsky/cron_calc) calculates cron job occurrences
31
+ * [Recurrence](https://github.com/fnando/recurrence) a simple library to handle recurring events
32
+ * [CronConfigParser](https://github.com/madogiwa0124/cron_config_parser) — parse the cron configuration for readability
32
33
  * ...
33
34
 
34
35
  ### Projects using fugit
35
36
 
36
- * [arask](https://github.com/Ebbe/arask) - "Automatic RAils taSKs" uses fugit to parse cron strings
37
- * [sidekiq-cron](https://github.com/ondrejbartas/sidekiq-cron) - uses fugit to parse cron strings since version 1.0.0, it was using rufus-scheduler previously
38
- * [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) - as seen above
39
- * [flor](https://github.com/floraison/flor) - used in the [cron](https://github.com/floraison/flor/blob/master/doc/procedures/cron.md) procedure
40
- * [que-scheduler](https://github.com/hlascelles/que-scheduler) - a reliable job scheduler for [que](https://github.com/chanks/que)
41
- * [serial_scheduler](https://github.com/grosser/serial_scheduler) - ruby task scheduler without threading
42
- * [delayed_cron_job](https://github.com/codez/delayed_cron_job) - an extension to Delayed::Job that allows you to set cron expressions for your jobs
43
- * [GoodJob](https://github.com/bensheldon/good_job) - a multithreaded, Postgres-based, Active Job backend for Ruby on Rails
44
- * [Solid Queue](https://github.com/rails/solid_queue) - a DB-based queuing backend for Active Job, designed with simplicity and performance in mind
37
+ * [arask](https://github.com/Ebbe/arask) "Automatic RAils taSKs" uses fugit to parse cron strings
38
+ * [sidekiq-cron](https://github.com/ondrejbartas/sidekiq-cron) uses fugit to parse cron strings since version 1.0.0, it was using rufus-scheduler previously
39
+ * [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) as seen above
40
+ * [flor](https://github.com/floraison/flor) used in the [cron](https://github.com/floraison/flor/blob/master/doc/procedures/cron.md) procedure
41
+ * [que-scheduler](https://github.com/hlascelles/que-scheduler) a reliable job scheduler for [que](https://github.com/chanks/que)
42
+ * [serial_scheduler](https://github.com/grosser/serial_scheduler) ruby task scheduler without threading
43
+ * [delayed_cron_job](https://github.com/codez/delayed_cron_job) an extension to Delayed::Job that allows you to set cron expressions for your jobs
44
+ * [GoodJob](https://github.com/bensheldon/good_job) a multithreaded, Postgres-based, Active Job backend for Ruby on Rails
45
+ * [Solid Queue](https://github.com/rails/solid_queue) a DB-based queuing backend for Active Job, designed with simplicity and performance in mind
46
+ * [qron](https://github.com/floraison/qron) — stupid cron thread that wakes up from time to time to do what's in its crontab
45
47
  * ...
46
48
 
47
49
  ## `Fugit.parse(s)`
@@ -112,6 +114,7 @@ Fugit.parse_cronish('12y12M') # ==> nil
112
114
 
113
115
  Introduced in fugit 1.8.0.
114
116
 
117
+
115
118
  ## `Fugit::Cron`
116
119
 
117
120
  A class `Fugit::Cron` to parse cron strings and then `#next_time` and `#previous_time` to compute the next or the previous occurrence respectively.
@@ -204,13 +207,28 @@ Example of cron strings understood by fugit:
204
207
 
205
208
  Please note that `'15/30 * * * *'` is interpreted as `'15-59/30 * * * *'` since fugit 1.4.6.
206
209
 
210
+ ### time zones
211
+
212
+ Fugit accepts a IANA timezone identifier right after a cron string:
213
+ ```ruby
214
+ '5 0 * * * Europe/Rome' # 5 minutes after midnight, every day, Rome tz
215
+ '0 22 * * 1-5 Asia/Tbilisi' # at 2200 on weekdays in Georgia
216
+
217
+ '@yearly Asia/Kuala_Lumpur' # turns into '0 0 1 1 * Asia/Kuala_Lumpur'
218
+ '@monthly Asia/Jakarta' # turns into '0 0 1 * * Asia/Jakarta'
219
+ #
220
+ # those two "ats" and friends since fugit 1.11.2...
221
+ ```
222
+
223
+ When no time zone is specified, fugit uses Ruby's provided timezone.
224
+
207
225
  ### the first Monday of the month
208
226
 
209
227
  Fugit tries to follow the `man 5 crontab` documentation.
210
228
 
211
229
  There is a surprising thing about this canon, all the columns are joined by ANDs, except for monthday and weekday which are joined together by OR if they are both set (they are not `*`).
212
230
 
213
- Many people (me included) [are suprised](https://superuser.com/questions/428807/run-a-cron-job-on-the-first-monday-of-every-month) when they try to specify "at 05:00 on the first Monday of the month" as `0 5 1-7 * 1` or `0 5 1-7 * mon` and the results are off.
231
+ Many people (me included) [are surprised](https://superuser.com/questions/428807/run-a-cron-job-on-the-first-monday-of-every-month) when they try to specify "at 05:00 on the first Monday of the month" as `0 5 1-7 * 1` or `0 5 1-7 * mon` and the results are off.
214
232
 
215
233
  The man page says:
216
234
 
@@ -286,7 +304,7 @@ For odd Sundays, one can write `9 0 * * sun%2+1`.
286
304
 
287
305
  It can be combined, as in `9 0 * * sun%2,tue%3+2`
288
306
 
289
- But what does it reference to? It starts at 1 on 2019-01-01.
307
+ But what does it reference to? It starts at 1 on 2019-01-01 (in the EtOrbi instance timezone, not the UTC "timezone").
290
308
 
291
309
  ```ruby
292
310
  require 'et-orbi' # >= 1.1.8
@@ -329,89 +347,6 @@ c = Fugit.parse('5 * * * * *') # every minute at second 5
329
347
  ```
330
348
 
331
349
 
332
- ## `Fugit::Duration`
333
-
334
- A class `Fugit::Duration` to parse duration strings (vanilla [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) ones and [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) ones).
335
-
336
- Provides duration arithmetic tools.
337
-
338
- ```ruby
339
- require 'fugit'
340
-
341
- d = Fugit::Duration.parse('1y2M1d4h')
342
-
343
- p d.to_plain_s # => "1Y2M1D4h"
344
- p d.to_iso_s # => "P1Y2M1DT4H" ISO 8601 duration
345
- p d.to_long_s # => "1 year, 2 months, 1 day, and 4 hours"
346
-
347
- d += Fugit::Duration.parse('1y1h')
348
-
349
- p d.to_long_s # => "2 years, 2 months, 1 day, and 5 hours"
350
-
351
- d += 3600
352
-
353
- p d.to_plain_s # => "2Y2M1D5h3600s"
354
-
355
- p Fugit::Duration.parse('1y2M1d4h').to_sec # => 36820800
356
- ```
357
-
358
- There is a `#deflate` method
359
-
360
- ```ruby
361
- Fugit::Duration.parse(1000).to_plain_s # => "1000s"
362
- Fugit::Duration.parse(3600).to_plain_s # => "3600s"
363
- Fugit::Duration.parse(1000).deflate.to_plain_s # => "16m40s"
364
- Fugit::Duration.parse(3600).deflate.to_plain_s # => "1h"
365
-
366
- # or event shorter
367
- Fugit.parse(1000).deflate.to_plain_s # => "16m40s"
368
- Fugit.parse(3600).deflate.to_plain_s # => "1h"
369
- ```
370
-
371
- There is also an `#inflate` method
372
-
373
- ```ruby
374
- Fugit::Duration.parse('1h30m12').inflate.to_plain_s # => "5412s"
375
- Fugit.parse('1h30m12').inflate.to_plain_s # => "5412s"
376
-
377
- Fugit.parse('1h30m12').to_sec # => 5412
378
- Fugit.parse('1h30m12').to_sec.to_s + 's' # => "5412s"
379
- ```
380
-
381
- The `to_*_s` methods are also available as class methods:
382
- ```ruby
383
- p Fugit::Duration.to_plain_s('1y2M1d4h')
384
- # => "1Y2M1D4h"
385
- p Fugit::Duration.to_iso_s('1y2M1d4h')
386
- # => "P1Y2M1DT4H" ISO 8601 duration
387
- p Fugit::Duration.to_long_s('1y2M1d4h')
388
- # => "1 year, 2 months, 1 day, and 4 hours"
389
- ```
390
-
391
- ## `Fugit::At`
392
-
393
- Points in time are parsed and given back as EtOrbi::EoTime instances.
394
-
395
- ```ruby
396
- Fugit::At.parse('2017-12-12').to_s
397
- # ==> "2017-12-12 00:00:00 +0900" (at least here in Hiroshima)
398
-
399
- Fugit::At.parse('2017-12-12 12:00:00 America/New_York').to_s
400
- # ==> "2017-12-12 12:00:00 -0500"
401
- ```
402
-
403
- Directly with `Fugit.parse_at(s)` is OK too:
404
- ```ruby
405
- Fugit.parse_at('2017-12-12 12:00:00 America/New_York').to_s
406
- # ==> "2017-12-12 12:00:00 -0500"
407
- ```
408
-
409
- Directly with `Fugit.parse(s)` is OK too:
410
- ```ruby
411
- Fugit.parse('2017-12-12 12:00:00 America/New_York').to_s
412
- # ==> "2017-12-12 12:00:00 -0500"
413
- ```
414
-
415
350
  ## `Fugit::Nat`
416
351
 
417
352
  Fugit understand some kind of "natural" language:
@@ -474,6 +409,8 @@ Fugit::Nat.parse('every day at 16:15 nada 18:30', multi: true)
474
409
 
475
410
  `multi: false` is the default behaviour, return a single `Fugit::Cron` instance or nil when it cannot parse.
476
411
 
412
+ Please note that "nat" input is limited to 256 characters (fugit 1.11.1).
413
+
477
414
  ### Nat Midnight
478
415
 
479
416
  `"Every day at midnight"` is supported, but `"Every monday at midnight"` will be interpreted (as of Fugit <= 1.4.x) as `"Every monday at 00:00"`. Sorry about that.
@@ -509,6 +446,96 @@ p Fugit.parse('every day at 12:15 midnight').original # ==> "15 24 * * *"
509
446
  ```
510
447
 
511
448
 
449
+ ## `Fugit::Duration`
450
+
451
+ A class `Fugit::Duration` to parse duration strings (vanilla [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) ones and [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) ones).
452
+
453
+ Provides duration arithmetic tools.
454
+
455
+ ```ruby
456
+ require 'fugit'
457
+
458
+ d = Fugit::Duration.parse('1y2M1d4h')
459
+
460
+ p d.to_plain_s # => "1Y2M1D4h"
461
+ p d.to_iso_s # => "P1Y2M1DT4H" ISO 8601 duration
462
+ p d.to_long_s # => "1 year, 2 months, 1 day, and 4 hours"
463
+
464
+ d += Fugit::Duration.parse('1y1h')
465
+
466
+ p d.to_long_s # => "2 years, 2 months, 1 day, and 5 hours"
467
+
468
+ d += 3600
469
+
470
+ p d.to_plain_s # => "2Y2M1D5h3600s"
471
+
472
+ p Fugit::Duration.parse('1y2M1d4h').to_sec # => 36820800
473
+ ```
474
+
475
+ There is a `#deflate` method
476
+
477
+ ```ruby
478
+ Fugit::Duration.parse(1000).to_plain_s # => "1000s"
479
+ Fugit::Duration.parse(3600).to_plain_s # => "3600s"
480
+ Fugit::Duration.parse(1000).deflate.to_plain_s # => "16m40s"
481
+ Fugit::Duration.parse(3600).deflate.to_plain_s # => "1h"
482
+
483
+ # or event shorter
484
+ Fugit.parse(1000).deflate.to_plain_s # => "16m40s"
485
+ Fugit.parse(3600).deflate.to_plain_s # => "1h"
486
+ ```
487
+
488
+ There is also an `#inflate` method
489
+
490
+ ```ruby
491
+ Fugit::Duration.parse('1h30m12').inflate.to_plain_s # => "5412s"
492
+ Fugit.parse('1h30m12').inflate.to_plain_s # => "5412s"
493
+
494
+ Fugit.parse('1h30m12').to_sec # => 5412
495
+ Fugit.parse('1h30m12').to_sec.to_s + 's' # => "5412s"
496
+ ```
497
+
498
+ The `to_*_s` methods are also available as class methods:
499
+ ```ruby
500
+ p Fugit::Duration.to_plain_s('1y2M1d4h')
501
+ # => "1Y2M1D4h"
502
+ p Fugit::Duration.to_iso_s('1y2M1d4h')
503
+ # => "P1Y2M1DT4H" ISO 8601 duration
504
+ p Fugit::Duration.to_long_s('1y2M1d4h')
505
+ # => "1 year, 2 months, 1 day, and 4 hours"
506
+ ```
507
+
508
+
509
+ ## `Fugit::At`
510
+
511
+ Points in time are parsed and given back as EtOrbi::EoTime instances.
512
+
513
+ ```ruby
514
+ Fugit::At.parse('2017-12-12').to_s
515
+ # ==> "2017-12-12 00:00:00 +0900" (at least here in Hiroshima)
516
+
517
+ Fugit::At.parse('2017-12-12 12:00:00 America/New_York').to_s
518
+ # ==> "2017-12-12 12:00:00 -0500"
519
+ ```
520
+
521
+ Directly with `Fugit.parse_at(s)` is OK too:
522
+ ```ruby
523
+ Fugit.parse_at('2017-12-12 12:00:00 America/New_York').to_s
524
+ # ==> "2017-12-12 12:00:00 -0500"
525
+ ```
526
+
527
+ Directly with `Fugit.parse(s)` is OK too:
528
+ ```ruby
529
+ Fugit.parse('2017-12-12 12:00:00 America/New_York').to_s
530
+ # ==> "2017-12-12 12:00:00 -0500"
531
+ ```
532
+
533
+
534
+ ## KNOWN ISSUES
535
+
536
+ The gem [nice_hash](https://github.com/MarioRuiz/nice_hash) gets in the way of `fugit`, as seen in [issue 108](https://github.com/floraison/fugit/issues/108). It prevents `fugit` from correctly parsing cron strings.
537
+
538
+
512
539
  ## LICENSE
513
540
 
514
541
  MIT, see [LICENSE.txt](LICENSE.txt)
data/fugit.gemspec CHANGED
@@ -20,18 +20,18 @@ Time tools for flor and the floraison project. Cron parsing and occurrence compu
20
20
 
21
21
  s.metadata = {
22
22
  'changelog_uri' => s.homepage + '/blob/master/CHANGELOG.md',
23
- 'documentation_uri' => s.homepage,
24
23
  'bug_tracker_uri' => s.homepage + '/issues',
25
- #'mailing_list_uri' => 'https://groups.google.com/forum/#!forum/floraison',
24
+ 'documentation_uri' => s.homepage,
26
25
  'homepage_uri' => s.homepage,
27
26
  'source_code_uri' => s.homepage,
27
+ #'mailing_list_uri' => 'https://groups.google.com/forum/#!forum/floraison',
28
28
  #'wiki_uri' => s.homepage + '/wiki',
29
+ 'rubygems_mfa_required' => 'true',
29
30
  }
30
31
 
31
32
  #s.files = `git ls-files`.split("\n")
32
33
  s.files = Dir[
33
- 'README.{md,txt}',
34
- 'CHANGELOG.{md,txt}', 'CREDITS.{md,txt}', 'LICENSE.{md,txt}',
34
+ '{README,CHANGELOG,CREDITS,LICENSE}.{md,txt}',
35
35
  #'Makefile',
36
36
  'lib/**/*.rb', #'spec/**/*.rb', 'test/**/*.rb',
37
37
  "#{s.name}.gemspec",
data/lib/fugit/cron.rb CHANGED
@@ -32,21 +32,42 @@ module Fugit
32
32
  def parse(s)
33
33
 
34
34
  return s if s.is_a?(self)
35
+ return nil unless s.is_a?(String)
35
36
 
36
- s = SPECIALS[s] || s
37
+ s0 = s
38
+ s = s.strip
37
39
 
38
- return nil unless s.is_a?(String)
40
+ s =
41
+ if s[0, 1] == '@'
42
+ ss = s.split(/\s+/, 2)
43
+ [ SPECIALS[ss[0]] || ss, *ss[1..-1] ].join(' ')
44
+ else
45
+ s
46
+ end
39
47
 
40
48
  #p s; Raabro.pp(Parser.parse(s, debug: 3), colors: true)
41
- h = Parser.parse(s.strip)
49
+ h = Parser.parse(s)
42
50
 
43
- self.allocate.send(:init, s, h)
51
+ self.allocate.send(:init, s0, h)
44
52
  end
45
53
 
46
54
  def do_parse(s)
47
55
 
48
56
  parse(s) ||
49
- fail(ArgumentError.new("invalid cron string #{s.inspect}"))
57
+ fail(ArgumentError.new("invalid cron string #{trunc(s)}"))
58
+ end
59
+
60
+ protected
61
+
62
+ def trunc(s)
63
+
64
+ if s.is_a?(String)
65
+ r = s.length > 28 ? s[0, 28] + "... len #{s.length}" : s
66
+ r.inspect
67
+ else
68
+ r = s.inspect
69
+ r.length > 35 ? s[0, 35] + '...' : r
70
+ end
50
71
  end
51
72
  end
52
73
 
@@ -67,11 +67,20 @@ module Fugit
67
67
  day: { a: 'D', r: 'd', i: 'D', s: DAY_S, I: true, l: 'day' },
68
68
  hou: { a: 'h', r: 'h', i: 'H', s: 3600, I: true, l: 'hour' },
69
69
  min: { a: 'm', r: 'm', i: 'M', s: 60, I: true, l: 'minute' },
70
- sec: { a: 's', r: 's', i: 'S', s: 1, I: true, l: 'second' } }.freeze
71
-
72
- INFLA_KEYS, NON_INFLA_KEYS = KEYS
73
- .partition { |k, v| v[:I] }
74
- .collect(&:freeze)
70
+ sec: { a: 's', r: 's', i: 'S', s: 1, I: true, l: 'second' }
71
+ }.freeze
72
+
73
+ #INFLA_KEYS, NON_INFLA_KEYS = KEYS
74
+ # .partition { |k, v| v[:I] }
75
+ # .collect(&:freeze)
76
+ #
77
+ # https://bugs.ruby-lang.org/issues/16252
78
+ #
79
+ kes = KEYS.entries
80
+ INFLA_KEYS,
81
+ NON_INFLA_KEYS =
82
+ kes.select { |_, v| v[:I] }.freeze,
83
+ kes.select { |_, v| ! v[:I] }.freeze
75
84
 
76
85
  def _to_s(key)
77
86
 
data/lib/fugit/nat.rb CHANGED
@@ -7,6 +7,8 @@ module Fugit
7
7
  #
8
8
  module Nat
9
9
 
10
+ MAX_INPUT_LENGTH = 256
11
+
10
12
  class << self
11
13
 
12
14
  def parse(s, opts={})
@@ -17,6 +19,16 @@ module Fugit
17
19
 
18
20
  s = s.strip
19
21
 
22
+ if s.length > MAX_INPUT_LENGTH
23
+
24
+ fail ArgumentError.new(
25
+ "input too long for a nat string, " +
26
+ "#{s.length} > #{MAX_INPUT_LENGTH}"
27
+ ) if opts[:do_parse]
28
+
29
+ return nil
30
+ end
31
+
20
32
  #p s; Raabro.pp(Parser.parse(s, debug: 3), colours: true)
21
33
  #(p s; Raabro.pp(Parser.parse(s, debug: 1), colours: true)) rescue nil
22
34
 
@@ -29,7 +41,7 @@ module Fugit
29
41
 
30
42
  def do_parse(s, opts={})
31
43
 
32
- parse(s, opts) ||
44
+ parse(s, opts.merge(do_parse: true)) ||
33
45
  fail(ArgumentError.new("could not parse a nat #{s.inspect}"))
34
46
  end
35
47
  end
@@ -42,7 +54,7 @@ module Fugit
42
54
  %w[ zero ] + one_to_nine +
43
55
  %w[ ten eleven twelve thirteen fourteen fifteen sixteen seventeen
44
56
  eighteen nineteen ] +
45
- %w[ twenty thirty fourty fifty ]
57
+ %w[ twenty thirty forty fifty ]
46
58
  .collect { |a|
47
59
  ([ nil ] + one_to_nine)
48
60
  .collect { |b| [ a, b ].compact.join('-') } }
@@ -198,7 +210,7 @@ module Fugit
198
210
  end
199
211
 
200
212
  def ampm(i)
201
- rex(:ampm, i, /[ \t]*(am|pm|noon|midday|midnight)/i)
213
+ rex(:ampm, i, /[ \t]*(am|AM|pm|PM|[Nn]oon|[Mm]idday|[Mm]idnight)/)
202
214
  end
203
215
  def dark(i)
204
216
  rex(:dark, i, /[ \t]*dark/i)
data/lib/fugit/parse.rb CHANGED
@@ -20,10 +20,10 @@ module Fugit
20
20
 
21
21
  opts[:at] = opts[:in] if opts.has_key?(:in)
22
22
 
23
- (opts[:cron] != false && parse_cron(s)) ||
24
- (opts[:duration] != false && parse_duration(s)) ||
25
- (opts[:nat] != false && parse_nat(s, opts)) ||
26
- (opts[:at] != false && parse_at(s)) ||
23
+ (opts[:cron] != false && parse_cron(s)) || # 542ms 616ms
24
+ (opts[:duration] != false && parse_duration(s)) || # 645ms # 534ms
25
+ (opts[:nat] != false && parse_nat(s, opts)) || # 2s # 35s
26
+ (opts[:at] != false && parse_at(s)) || # 568ms 622ms
27
27
  nil
28
28
  end
29
29
 
@@ -63,6 +63,24 @@ module Fugit
63
63
  fail(ArgumentError.new("not cron or 'natural' cron string: #{s.inspect}"))
64
64
  end
65
65
 
66
+ def parse_max(s, opts={})
67
+
68
+ s0 = s.lines.first
69
+
70
+ (0..[ ::Fugit::Nat::MAX_INPUT_LENGTH, s0.length - 1 ].min).each do |i|
71
+
72
+ s1 =
73
+ s0[0, s0.length - i].rstrip
74
+ f =
75
+ opts[:cronish] ? parse_cronish(s1, opts) :
76
+ parse(s1, opts)
77
+
78
+ return [ s1, f ] if f
79
+ end
80
+
81
+ nil
82
+ end
83
+
66
84
  def determine_type(s)
67
85
 
68
86
  case self.parse(s)
data/lib/fugit.rb CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Fugit
5
5
 
6
- VERSION = '1.11.0'
6
+ VERSION = '1.11.2'
7
7
  end
8
8
 
9
9
  require 'time'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fugit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.0
4
+ version: 1.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-24 00:00:00.000000000 Z
11
+ date: 2025-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: raabro
@@ -97,10 +97,11 @@ licenses:
97
97
  - MIT
98
98
  metadata:
99
99
  changelog_uri: https://github.com/floraison/fugit/blob/master/CHANGELOG.md
100
- documentation_uri: https://github.com/floraison/fugit
101
100
  bug_tracker_uri: https://github.com/floraison/fugit/issues
101
+ documentation_uri: https://github.com/floraison/fugit
102
102
  homepage_uri: https://github.com/floraison/fugit
103
103
  source_code_uri: https://github.com/floraison/fugit
104
+ rubygems_mfa_required: 'true'
104
105
  post_install_message:
105
106
  rdoc_options: []
106
107
  require_paths:
@@ -116,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
117
  - !ruby/object:Gem::Version
117
118
  version: '0'
118
119
  requirements: []
119
- rubygems_version: 3.4.10
120
+ rubygems_version: 3.4.19
120
121
  signing_key:
121
122
  specification_version: 4
122
123
  summary: time tools for flor