edtf 4.0.0 → 4.1.0

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.
data/lib/edtf/parser.y CHANGED
@@ -56,7 +56,10 @@ rule
56
56
  ;
57
57
 
58
58
  year : positive_year
59
- | '-' positive_year { result = -val[1] }
59
+ | '-' positive_year {
60
+ result = -val[1]
61
+ deprecate :negative_zero if result.zero?
62
+ }
60
63
 
61
64
  positive_year : digit digit digit digit {
62
65
  result = val.zip([1000,100,10,1]).reduce(0) { |s,(a,b)| s += a * b }
@@ -67,7 +70,7 @@ rule
67
70
 
68
71
  year_month : year '-' month { result = [val[0], val[2]] }
69
72
 
70
- # We raise an exception if there are two many days for the month, but
73
+ # We raise an exception if there are too many days for the month, but
71
74
  # do not consider leap years, as the EDTF BNF did not either.
72
75
  # NB: an exception will be raised regardless, because the Ruby Date
73
76
  # implementation calculates leap years.
@@ -91,7 +94,10 @@ rule
91
94
  # NB: Uncertain/approximate Dates are covered by the Level 2 rules
92
95
  level_1_expression : unknown | unspecified | level_1_interval | long_year_simple | season
93
96
 
94
- unknown : U U U U { result = EDTF::Unknown.new }
97
+ unknown : U U U U {
98
+ result = EDTF::Unknown.new
99
+ deprecate :unknown_date
100
+ }
95
101
 
96
102
  # uncertain_or_approximate_date : date UA { result = uoa(val[0], val[1]) }
97
103
 
@@ -483,12 +489,38 @@ require 'strscan'
483
489
 
484
490
  @defaults = {
485
491
  :level => 2,
486
- :debug => false
492
+ :debug => false,
493
+ :warn => true
494
+ }.freeze
495
+
496
+ # Input that EDTF-Ruby 5.0 parses differently.
497
+ # Legacy syntax will be accepted only in legacy mode;
498
+ # lossy legacy syntax has no ISO 8601-2 equivalent.
499
+ LEGACY = {
500
+ combined_qualifier: '`?~` is legacy syntax, use `%`',
501
+ parentheses: 'parentheses are legacy syntax, ' \
502
+ 'EDTF-Ruby 5.0 qualifies parts from the left instead, e.g. `2004-?06-11`',
503
+ open: '`open` is legacy syntax, use `..`',
504
+ unknown: '`unknown` is legacy syntax, leave the interval end empty',
505
+ unspecified: '`u` is legacy syntax, use `X`',
506
+ masked: 'masked precision (`198x`) is legacy syntax, ' \
507
+ 'EDTF-Ruby 5.0 reads it as a decade (`198`) or century (`19`)',
508
+ lowercase_y: '`y` is legacy syntax, use `Y`',
509
+ lowercase_e: '`e` is legacy syntax, use `E`',
510
+ negative_zero: '`-0000` is legacy syntax, use `0000`',
511
+ caret: 'calendars and season qualifiers (`^…`) are legacy syntax, ' \
512
+ 'EDTF-Ruby 5.0 converts hemispheres to seasons, e.g. `2001-21^southern` ' \
513
+ 'to `2001-29`, and drops the rest'
514
+ }.freeze
515
+
516
+ CHANGED = {
517
+ unknown_date: 'EDTF-Ruby 5.0 parses this as a date ' \
518
+ 'with an unspecified year instead of EDTF::Unknown'
487
519
  }.freeze
488
520
 
489
521
  class << self; attr_reader :defaults; end
490
522
 
491
- attr_reader :options
523
+ attr_reader :options, :deprecations
492
524
 
493
525
  def initialize(options = {})
494
526
  @options = Parser.defaults.merge(options)
@@ -508,7 +540,16 @@ require 'strscan'
508
540
  def parse!(input)
509
541
  @yydebug = debug?
510
542
  @src = StringScanner.new(input)
511
- do_parse
543
+ @deprecations = []
544
+ result = do_parse
545
+ @deprecations.uniq!
546
+ warn_deprecations(input) if options[:warn]
547
+ result
548
+ end
549
+
550
+ # Returns true if the last successful parse used legacy syntax.
551
+ def legacy?
552
+ deprecations.any? { |d| LEGACY.key?(d) }
512
553
  end
513
554
 
514
555
  def on_error(tid, value, stack)
@@ -516,6 +557,16 @@ require 'strscan'
516
557
  "failed to parse date: unexpected '#{value}' at #{stack.inspect}"
517
558
  end
518
559
 
560
+ def deprecate(name)
561
+ @deprecations << name
562
+ end
563
+
564
+ def warn_deprecations(input)
565
+ return if deprecations.empty?
566
+ messages = deprecations.map { |d| LEGACY[d] || CHANGED[d] }
567
+ warn "EDTF #{input.inspect}: #{messages.join('; ')}", category: :deprecated
568
+ end
569
+
519
570
  def apply_uncertainty(date, uncertainty, scope = nil)
520
571
  uncertainty.each do |u|
521
572
  scope.nil? ? date.send(u) : date.send(u, scope)
@@ -532,6 +583,7 @@ require 'strscan'
532
583
  # when @src.scan(/\s+/)
533
584
  # ignore whitespace
534
585
  when @src.scan(/\(/)
586
+ deprecate :parentheses
535
587
  ['(', @src.matched]
536
588
  # when @src.scan(/\)\?~-/)
537
589
  # [:PUA, [:uncertain!, :approximate!]]
@@ -554,6 +606,7 @@ require 'strscan'
554
606
  when @src.scan(/Z/)
555
607
  [:Z, @src.matched]
556
608
  when @src.scan(/\?~/)
609
+ deprecate :combined_qualifier
557
610
  [:UA, [:uncertain!, :approximate!]]
558
611
  when @src.scan(/%/)
559
612
  [:UA, [:uncertain!, :approximate!]]
@@ -562,22 +615,29 @@ require 'strscan'
562
615
  when @src.scan(/~/)
563
616
  [:UA, [:approximate!]]
564
617
  when @src.scan(/open/i)
618
+ deprecate :open
565
619
  [:OPEN, :open]
566
620
  when @src.scan(/unkn?own/i) # matches 'unkown' typo too
621
+ deprecate :unknown
567
622
  [:UNKNOWN, :unknown]
568
623
  when @src.scan(/u/)
624
+ deprecate :unspecified
569
625
  [:U, @src.matched]
570
626
  when @src.scan(/X/)
571
627
  [:U, @src.matched]
572
628
  when @src.scan(/x/)
629
+ deprecate :masked
573
630
  [:X, @src.matched]
574
631
  when @src.scan(/y/i)
632
+ deprecate :lowercase_y if @src.matched == 'y'
575
633
  [:LONGYEAR, @src.matched]
576
634
  when @src.scan(/e/i)
635
+ deprecate :lowercase_e if @src.matched == 'e'
577
636
  [:E, @src.matched]
578
637
  when @src.scan(/\+/)
579
638
  ['+', @src.matched]
580
639
  when @src.scan(/-\(/)
640
+ deprecate :parentheses
581
641
  ['-(', @src.matched]
582
642
  when @src.scan(/-/)
583
643
  ['-', @src.matched]
@@ -590,6 +650,7 @@ require 'strscan'
590
650
  when @src.scan(/\s*,\s*/)
591
651
  [',', ',']
592
652
  when @src.scan(/\^\w+/)
653
+ deprecate :caret
593
654
  ['^', @src.matched[1..-1]]
594
655
  when @src.scan(/\d/)
595
656
  [@src.matched, @src.matched.to_i]
data/lib/edtf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module EDTF
2
- VERSION = '4.0.0'.freeze
2
+ VERSION = '4.1.0'.freeze
3
3
  end
data/lib/edtf.rb CHANGED
@@ -1,33 +1,3 @@
1
- #--
2
- # EDTF-Ruby
3
- # Copyright 2011 Sylvester Keil. All rights reserved.
4
- #
5
- # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions are met:
7
- #
8
- # 1. Redistributions of source code must retain the above copyright notice,
9
- # this list of conditions and the following disclaimer.
10
- #
11
- # 2. Redistributions in binary form must reproduce the above copyright
12
- # notice, this list of conditions and the following disclaimer in the
13
- # documentation and/or other materials provided with the distribution.
14
- #
15
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
16
- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
- # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
18
- # NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
19
- # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
- # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
- # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
- # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
- # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
- #
26
- # The views and conclusions contained in the software and documentation are
27
- # those of the authors and should not be interpreted as representing official
28
- # policies, either expressed or implied, of the copyright holder.
29
- #++
30
-
31
1
  require 'date'
32
2
  require 'time'
33
3
 
@@ -64,7 +34,7 @@ require 'edtf/extensions'
64
34
  # Date/Time Format (EDTF). See the `EDTF::ExtendedDate` module for an
65
35
  # overview of the features added to the Ruby `Date` class.
66
36
  #
67
- # To parse EDTF strings use either `Date.edtf` of `EDTF.parse`.
37
+ # To parse EDTF strings use `EDTF.parse` or `EDTF()`.
68
38
  #
69
39
  module EDTF
70
40
 
@@ -77,7 +47,31 @@ module EDTF
77
47
  end
78
48
 
79
49
  def parse!(input, options = {})
80
- ::Date.edtf!(input, options)
50
+ Parser.new(options).parse!(input)
51
+ end
52
+
53
+ def legacy?(input)
54
+ parser = Parser.new(warn: false)
55
+ !parser.parse(input).nil? && parser.legacy?
56
+ end
57
+ end
58
+
59
+ module Kernel
60
+ private
61
+
62
+ # Converts value to an EDTF object:
63
+ # strings are parsed, times become date-times,
64
+ # dates and other EDTF objects are returned unchanged.
65
+ def EDTF(value)
66
+ case value
67
+ when String
68
+ EDTF.parse!(value)
69
+ when Time
70
+ value.to_datetime
71
+ when Date, EDTF::Season, EDTF::Epoch, EDTF::Interval, EDTF::Set, EDTF::Unknown
72
+ value
73
+ else
74
+ raise TypeError, "can't convert #{value.class} into EDTF"
75
+ end
81
76
  end
82
-
83
77
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: edtf
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvester Keil
@@ -95,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  requirements: []
98
- rubygems_version: 4.0.22
98
+ rubygems_version: 4.0.3
99
99
  specification_version: 4
100
100
  summary: Extended Date/Time Format for Ruby.
101
101
  test_files: []