edtf 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/edtf/parser.y CHANGED
@@ -4,6 +4,7 @@ class EDTF::Parser
4
4
 
5
5
  token T Z E X PLUS MINUS COLON SLASH D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 LP RP
6
6
  UNCERTAIN APPROXIMATE UNSPECIFIED UNKNOWN OPEN LONGYEAR CARET UNMATCHED
7
+ DOTS COMMA LBRACE RBRACE LSQUARE RSQUARE
7
8
 
8
9
  expect 0
9
10
 
@@ -24,11 +25,11 @@ rule
24
25
  date : positive_date
25
26
  | negative_date
26
27
 
27
- positive_date : year { result = Date.new(val[0]) }
28
- | year_month { result = Date.new(*val.flatten) }
29
- | year_month_day { result = Date.new(*val.flatten) }
28
+ positive_date : year { result = Date.new(val[0]); result.precision = :year }
29
+ | year_month { result = Date.new(*val.flatten); result.precision = :month }
30
+ | year_month_day { result = Date.new(*val.flatten); result.precision = :day }
30
31
 
31
- negative_date : MINUS positive_date { result = Date.new(-1 * val[1].year, val[1].month, val[1].day) }
32
+ negative_date : MINUS positive_date { result = -val[1] }
32
33
 
33
34
 
34
35
  date_time : date T time { result = DateTime.new(val[0].year, val[0].month, val[0].day, *val[2]) }
@@ -90,15 +91,15 @@ rule
90
91
  | UNCERTAIN APPROXIMATE { result = [:uncertain!, :approximate!] }
91
92
 
92
93
 
93
- unspecified : unspecified_year
94
+ unspecified : unspecified_year { result = Date.new(val[0][0]); result.unspecified.year[2,2] = val[0][1]; result.precision = :year }
94
95
  | unspecified_month
95
96
  | unspecified_day
96
97
  | unspecified_day_and_month
97
98
 
98
- unspecified_year : digit digit digit UNSPECIFIED { result = Date.new(val[0,3].zip([1000,100,10]).reduce(0) { |s,(a,b)| s += a * b }); result.unspecified.year[3] = true }
99
- | digit digit UNSPECIFIED UNSPECIFIED { result = Date.new(val[0,2].zip([1000,100]).reduce(0) { |s,(a,b)| s += a * b }); result.unspecified.year[2,2] = [true, true] }
99
+ unspecified_year : digit digit digit UNSPECIFIED { result = [val[0,3].zip([1000,100,10]).reduce(0) { |s,(a,b)| s += a * b }, [false,true]] }
100
+ | digit digit UNSPECIFIED UNSPECIFIED { result = [val[0,2].zip([1000,100]).reduce(0) { |s,(a,b)| s += a * b }, [true, true]] }
100
101
 
101
- unspecified_month : year MINUS UNSPECIFIED UNSPECIFIED { result = Date.new(val[0]).unspecified!(:month) }
102
+ unspecified_month : year MINUS UNSPECIFIED UNSPECIFIED { result = Date.new(val[0]).unspecified!(:month); result.precision = :month }
102
103
 
103
104
  unspecified_day : year_month MINUS UNSPECIFIED UNSPECIFIED { result = Date.new(*val[0]).unspecified!(:day) }
104
105
 
@@ -115,14 +116,14 @@ rule
115
116
  | OPEN { result = :open }
116
117
 
117
118
 
118
- long_year_simple : LONGYEAR long_year { result = Date.new(val[1]) }
119
- | LONGYEAR MINUS long_year { result = Date.new(-1 * val[2]) }
119
+ long_year_simple : LONGYEAR long_year { result = Date.new(val[1]); result.precision = :year }
120
+ | LONGYEAR MINUS long_year { result = Date.new(-1 * val[2]); result.precision = :year }
120
121
 
121
122
  long_year : positive_digit digit digit digit digit { result = val.zip([10000,1000,100,10,1]).reduce(0) { |s,(a,b)| s += a * b } }
122
123
  | long_year digit { result = 10 * val[0] + val[1] }
123
124
 
124
125
 
125
- season : year MINUS season_number { result = Date.new(val[0]); result.season = val[2] }
126
+ season : year MINUS season_number { result = Date.new(val[0]); result.season = val[2]; result.precision = :year }
126
127
 
127
128
  season_number : D2 D1 { result = 21 }
128
129
  | D2 D2 { result = 22 }
@@ -134,9 +135,9 @@ rule
134
135
 
135
136
  level_2_expression : season_qualified
136
137
  # | internal_uncertain_or_approximate
137
- # | internal_unspecified
138
- # | choice_list
139
- # | inclusive_list
138
+ | internal_unspecified
139
+ | choice_list
140
+ | inclusive_list
140
141
  | masked_precision
141
142
  # | level_2_interval
142
143
  | date_and_calendar
@@ -146,9 +147,9 @@ rule
146
147
  season_qualified : season CARET { result = val[0]; result.qualifier = val[1] }
147
148
 
148
149
 
149
- long_year_scientific : long_year_simple E integer { result = Date.new(val[0].year * 10 ** val[2]) }
150
- | LONGYEAR int1_4 E integer { result = Date.new(val[1] * 10 ** val[3]) }
151
- | LONGYEAR MINUS int1_4 E integer { result = Date.new(-1 * val[2] * 10 ** val[4]) }
150
+ long_year_scientific : long_year_simple E integer { result = Date.new(val[0].year * 10 ** val[2]); result.precision = :year }
151
+ | LONGYEAR int1_4 E integer { result = Date.new(val[1] * 10 ** val[3]); result.precision = :year }
152
+ | LONGYEAR MINUS int1_4 E integer { result = Date.new(-1 * val[2] * 10 ** val[4]); result.precision = :year }
152
153
 
153
154
 
154
155
  date_and_calendar : date CARET { result = val[0]; result.calendar = val[1] }
@@ -157,6 +158,46 @@ rule
157
158
  masked_precision : digit digit digit X { d = val[0,3].zip([1000,100,10]).reduce(0) { |s,(a,b)| s += a * b }; result = Date.new(d) ... Date.new(d+10) }
158
159
  | digit digit X X { d = val[0,2].zip([1000,100]).reduce(0) { |s,(a,b)| s += a * b }; result = Date.new(d) ... Date.new(d+100) }
159
160
 
161
+
162
+ choice_list : LSQUARE list RSQUARE { result = val[1] }
163
+
164
+ inclusive_list : LBRACE list RBRACE { result = val[1] }
165
+
166
+ list : earlier { result = [val[0]] }
167
+ | earlier COMMA list_elements COMMA later { result = [val[0]] + val[2] + [val[4]] }
168
+ | earlier COMMA list_elements { result = [val[0]] + val[2] }
169
+ | earlier COMMA later { result = [val[0]] + [val[2]] }
170
+ | list_elements COMMA later { result = val[0] + [val[2]] }
171
+ | list_elements
172
+ | later { result = [val[0]] }
173
+
174
+ list_elements : list_element { result = [val[0]].flatten }
175
+ | list_elements COMMA list_element { result = val[0] + [val[2]].flatten }
176
+
177
+ list_element : date
178
+ # | date_with_internal_uncertainty
179
+ | uncertain_or_approximate_date
180
+ | unspecified
181
+ | consecutives { result = val[0].map { |d| Date.new(*d) } }
182
+
183
+ earlier : DOTS date { result = val[1] }
184
+
185
+ later : year_month_day DOTS { result = Date.new(*val[0]); result.precision = :day }
186
+ | year_month DOTS { result = Date.new(*val[0]); result.precision = :month }
187
+ | year DOTS { result = Date.new(val[0]); result.precision = :year }
188
+
189
+ consecutives : year_month_day DOTS year_month_day
190
+ | year_month DOTS year_month
191
+ | year DOTS year { result = (val[0]..val[2]).to_a.map }
192
+
193
+
194
+ internal_unspecified : unspecified_year MINUS month MINUS d01_31 { result = Date.new(val[0][0], val[2], val[4]); result.unspecified.year[2,2] = val[0][1] }
195
+ | unspecified_year MINUS UNSPECIFIED UNSPECIFIED MINUS d01_31 { result = Date.new(val[0][0], 1, val[5]); result.unspecified.year[2,2] = val[0][1]; result.unspecified!(:month) }
196
+ | unspecified_year MINUS UNSPECIFIED UNSPECIFIED MINUS UNSPECIFIED UNSPECIFIED { result = Date.new(val[0][0], 1, 1); result.unspecified.year[2,2] = val[0][1]; result.unspecified!([:month, :day]) }
197
+ | unspecified_year MINUS month MINUS UNSPECIFIED UNSPECIFIED { result = Date.new(val[0][0], val[2], 1); result.unspecified.year[2,2] = val[0][1]; result.unspecified!(:day) }
198
+ | year MINUS UNSPECIFIED UNSPECIFIED MINUS d01_31 { result = Date.new(val[0], 1, val[5]); result.unspecified!(:month) }
199
+
200
+
160
201
  # ---- Auxiliary Rules ----
161
202
 
162
203
  digit : D0 { result = 0 }
@@ -265,10 +306,20 @@ require 'strscan'
265
306
  def tokenize
266
307
  until @src.eos?
267
308
  case
309
+ # when @src.scan(/\s+/)
310
+ # ignore whitespace
268
311
  when @src.scan(/\(/)
269
312
  @stack << [:LP, @src.matched]
270
313
  when @src.scan(/\)/)
271
314
  @stack << [:RP, @src.matched]
315
+ when @src.scan(/\[/)
316
+ @stack << [:LSQUARE, @src.matched]
317
+ when @src.scan(/\]/)
318
+ @stack << [:RSQUARE, @src.matched]
319
+ when @src.scan(/\{/)
320
+ @stack << [:LBRACE, @src.matched]
321
+ when @src.scan(/\}/)
322
+ @stack << [:RBRACE, @src.matched]
272
323
  when @src.scan(/T/)
273
324
  @stack << [:T, @src.matched]
274
325
  when @src.scan(/Z/)
@@ -297,6 +348,10 @@ require 'strscan'
297
348
  @stack << [:COLON, @src.matched]
298
349
  when @src.scan(/\//)
299
350
  @stack << [:SLASH, @src.matched]
351
+ when @src.scan(/\s*\.\.\s*/)
352
+ @stack << [:DOTS, '..']
353
+ when @src.scan(/\s*,\s*/)
354
+ @stack << [:COMMA, ',']
300
355
  when @src.scan(/\^\w+/)
301
356
  @stack << [:CARET, @src.matched[1..-1]]
302
357
  when @src.scan(/\d/)
data/lib/edtf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module EDTF
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.3'.freeze
3
3
  end
data/lib/edtf.rb CHANGED
@@ -39,6 +39,7 @@ require 'edtf/version'
39
39
  require 'edtf/uncertainty'
40
40
  require 'edtf/seasons'
41
41
  require 'edtf/date'
42
+ require 'edtf/date_time'
42
43
  require 'edtf/interval'
43
44
  require 'edtf/parser'
44
45
  require 'edtf/extensions'
@@ -0,0 +1,171 @@
1
+ module EDTF
2
+ describe Parser do
3
+ describe '#parse' do
4
+
5
+ it 'parses simple dates' do
6
+ Parser.new.parse('2001-02-03').to_s.should == '2001-02-03'
7
+ end
8
+
9
+ it 'parses negative years' do
10
+ Parser.new.parse('-2323').to_s.should == '-2323-01-01'
11
+ end
12
+
13
+ it 'parses year zero' do
14
+ Parser.new.parse('0000').to_s.should == '0000-01-01'
15
+ end
16
+
17
+ it 'parses date/time with time zones' do
18
+ Parser.new.parse('2011-08-15T11:19:00+01:00').to_s.should == '2011-08-15T11:19:00+01:00'
19
+ end
20
+
21
+ it 'parses simple intervals like "2007/2008"' do
22
+ Parser.new.parse('2007/2008').should include(Date.new(2007,12,24))
23
+ Parser.new.parse('2007/2008').should_not include(Date.new(2008,1,2))
24
+ end
25
+
26
+ it 'parses uncertain dates' do
27
+ Parser.new.parse('1984?').should be_uncertain
28
+ Parser.new.parse('1984').should be_certain
29
+ end
30
+
31
+ it 'parses approximate dates' do
32
+ Parser.new.parse('1984-01~').should be_approximate
33
+ Parser.new.parse('1984-01').should be_precise
34
+ end
35
+
36
+ it 'parses uncertain approximate dates' do
37
+ Parser.new.parse('1984?~').should be_uncertain
38
+ Parser.new.parse('1984?~').should be_approximate
39
+ end
40
+
41
+ it 'parses unspecified dates' do
42
+ Parser.new.parse('199u').should be_unspecified
43
+ Parser.new.parse('1999-uu-uu').should be_unspecified
44
+ end
45
+
46
+ it 'parses open intervals' do
47
+ Parser.new.parse('2004-01-01/open').should be_open
48
+ end
49
+
50
+ it 'parses unknown intervals' do
51
+ Parser.new.parse('2004-01-01/unknown').should be_unknown_end
52
+ Parser.new.parse('unknown/2004-01-01').should be_unknown_start
53
+ end
54
+
55
+ it 'parses intervals with uncertain or approximate dates' do
56
+ Parser.new.parse('1984-06-02?/2004-08-08~').from.should be_uncertain
57
+ Parser.new.parse('1984-06-02?/2004-08-08~').to.should be_approximate
58
+ end
59
+
60
+ it 'should parse positive long years' do
61
+ Parser.new.parse('y170000002').year.should == 170000002
62
+ end
63
+
64
+ it 'should parse negative long years' do
65
+ Parser.new.parse('y-170000002').year.should == -170000002
66
+ end
67
+
68
+ it 'should parse season codes' do
69
+ Parser.new.parse('2003-23').should be_autumn
70
+ end
71
+
72
+ it 'should parse calendar names' do
73
+ Parser.new.parse('2001-02-03^xyz').calendar.should == 'xyz'
74
+ end
75
+
76
+ it 'should parse season qualifiers' do
77
+ d = Parser.new.parse('2003-23^european')
78
+ d.should be_autumn
79
+ d.should be_qualified
80
+ d.qualifier.should == 'european'
81
+ end
82
+
83
+ it 'should parse positive scientific long years' do
84
+ Parser.new.parse('y17e7').year.should == 170000000
85
+ end
86
+
87
+ it 'should parse negative scientific long years' do
88
+ Parser.new.parse('y-17e7').year.should == -170000000
89
+ end
90
+
91
+ it 'parses masked precision date strings (decades)' do
92
+ d = Parser.new.parse('198x')
93
+ d.should include(Date.new(1983,3,12))
94
+ d.should_not include(Date.new(1990,1,1))
95
+ end
96
+
97
+ it 'parses masked precision date strings (centuries)' do
98
+ d = Parser.new.parse('18xx')
99
+ d.should include(Date.new(1848,1,14))
100
+ d.should_not include(Date.new(1799,12,31))
101
+ end
102
+
103
+ it 'parses multiple dates (years)' do
104
+ d = Parser.new.parse('{1667,1668, 1670..1672}')
105
+ d.map(&:year).should == [1667,1668,1670,1671,1672]
106
+ end
107
+
108
+ it 'parses multiple dates (mixed years and months)' do
109
+ d = Parser.new.parse('{1960, 1961-12}')
110
+ d.map { |x| [x.year,x.month] }.should == [[1960,1],[1961,12]]
111
+ end
112
+
113
+ it 'parses choice lists (One of the years 1667, 1668, 1670, 1671, 1672)' do
114
+ d = Parser.new.parse('[1667,1668, 1670..1672]')
115
+ d.map(&:year).should == [1667,1668,1670,1671,1672]
116
+ end
117
+
118
+ it 'parses choice lists (December 3, 1760 or some earlier date)' do
119
+ d = Parser.new.parse('[..1760-12-03]')
120
+ d.map(&:to_s).should == ['1760-12-03']
121
+ end
122
+
123
+ it 'parses choice lists (December 1760 or some later month)' do
124
+ d = Parser.new.parse('[1760-12..]')
125
+ d.map { |x| [x.year,x.month] }.should == [[1760,12]]
126
+ end
127
+
128
+ it 'parses choice lists (January or February of 1760 or December 1760 or some later month)' do
129
+ d = Parser.new.parse('[1760-01, 1760-02, 1760-12..]')
130
+ d.length.should == 3
131
+ end
132
+
133
+ it 'parses intern unspecified "199u-01-01"' do
134
+ Parser.new.parse('199u-01-01').unspecified.to_s.should == 'sssu-ss-ss'
135
+ end
136
+
137
+ it 'parses intern unspecified "19uu-01-01"' do
138
+ Parser.new.parse('19uu-01-01').unspecified.to_s.should == 'ssuu-ss-ss'
139
+ end
140
+
141
+ it 'parses intern unspecified "199u-uu-01"' do
142
+ Parser.new.parse('199u-uu-01').unspecified.to_s.should == 'sssu-uu-ss'
143
+ end
144
+
145
+ it 'parses intern unspecified "19uu-uu-01"' do
146
+ Parser.new.parse('19uu-uu-01').unspecified.to_s.should == 'ssuu-uu-ss'
147
+ end
148
+
149
+ it 'parses intern unspecified "199u-uu-uu"' do
150
+ Parser.new.parse('199u-uu-uu').unspecified.to_s.should == 'sssu-uu-uu'
151
+ end
152
+
153
+ it 'parses intern unspecified "19uu-uu-uu"' do
154
+ Parser.new.parse('19uu-uu-uu').unspecified.to_s.should == 'ssuu-uu-uu'
155
+ end
156
+
157
+ it 'parses intern unspecified "199u-01-uu"' do
158
+ Parser.new.parse('199u-01-uu').unspecified.to_s.should == 'sssu-ss-uu'
159
+ end
160
+
161
+ it 'parses intern unspecified "19uu-01-uu"' do
162
+ Parser.new.parse('19uu-01-uu').unspecified.to_s.should == 'ssuu-ss-uu'
163
+ end
164
+
165
+ it 'parses intern unspecified "1999-uu-01"' do
166
+ Parser.new.parse('1999-uu-01').unspecified.to_s.should == 'ssss-uu-ss'
167
+ end
168
+
169
+ end
170
+ end
171
+ 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: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2011-08-15 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &2157415200 !ruby/object:Gem::Requirement
16
+ requirement: &2157012300 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0.9'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2157415200
24
+ version_requirements: *2157012300
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: racc
27
- requirement: &2157414020 !ruby/object:Gem::Requirement
27
+ requirement: &2156999280 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '1.4'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2157414020
35
+ version_requirements: *2156999280
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: cucumber
38
- requirement: &2157413420 !ruby/object:Gem::Requirement
38
+ requirement: &2156998780 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '1.0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2157413420
46
+ version_requirements: *2156998780
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &2157412820 !ruby/object:Gem::Requirement
49
+ requirement: &2156998280 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '2.6'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2157412820
57
+ version_requirements: *2156998280
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: ZenTest
60
- requirement: &2157412220 !ruby/object:Gem::Requirement
60
+ requirement: &2156997760 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '4.6'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2157412220
68
+ version_requirements: *2156997760
69
69
  description: An Extended Date/Time Format (EDTF) Parser for Ruby.
70
70
  email:
71
71
  - http://sylvester.keil.or.at
@@ -75,6 +75,7 @@ extra_rdoc_files:
75
75
  - README.md
76
76
  - LICENSE
77
77
  files:
78
+ - .autotest
78
79
  - .gitignore
79
80
  - .rspec
80
81
  - Gemfile
@@ -92,13 +93,14 @@ files:
92
93
  - lib/edtf.rb
93
94
  - lib/edtf/compatibility.rb
94
95
  - lib/edtf/date.rb
96
+ - lib/edtf/date_time.rb
95
97
  - lib/edtf/extensions.rb
96
98
  - lib/edtf/interval.rb
97
99
  - lib/edtf/parser.y
98
100
  - lib/edtf/seasons.rb
99
101
  - lib/edtf/uncertainty.rb
100
102
  - lib/edtf/version.rb
101
- - spec/edtf/extensions_spec.rb
103
+ - spec/edtf/parser_spec.rb
102
104
  - spec/edtf/seasons_spec.rb
103
105
  - spec/edtf/uncertainty_spec.rb
104
106
  - spec/spec_helper.rb
@@ -143,7 +145,7 @@ test_files:
143
145
  - features/parser/unspecified.feature
144
146
  - features/step_definitions/edtf_steps.rb
145
147
  - features/support/env.rb
146
- - spec/edtf/extensions_spec.rb
148
+ - spec/edtf/parser_spec.rb
147
149
  - spec/edtf/seasons_spec.rb
148
150
  - spec/edtf/uncertainty_spec.rb
149
151
  - spec/spec_helper.rb
@@ -1,44 +0,0 @@
1
- describe DateTime do
2
-
3
- let(:date) { DateTime.new }
4
-
5
- describe 'class methods' do
6
- it 'responds to edtf' do
7
- DateTime.respond_to?(:edtf).should == true
8
- end
9
- end
10
-
11
- describe 'instance methods' do
12
- [:uncertain?, :approximate?, :unspecified?, :uncertain, :approximate, :unspecified].each do |method|
13
- it "responds to #{method}" do
14
- DateTime.new.respond_to?(method).should == true
15
- end
16
- end
17
- end
18
-
19
- describe '#uncertain?' do
20
-
21
- it { should_not be_uncertain }
22
-
23
- [:year, :month, :day].each do |part|
24
- it "should not be uncertain by default (#{part})" do
25
- DateTime.new.uncertain?(part).should == false
26
- end
27
-
28
- it "should be uncertain if set to uncertain (#{part})" do
29
- date.uncertain.send("#{part}=", true)
30
- date.uncertain?(part).should == true
31
- end
32
-
33
- ([:year, :month, :day] - [part]).each do |other|
34
- it "#{other} should not be uncertain if #{part} is uncertain" do
35
- date.uncertain.send("#{part}=", true)
36
- date.uncertain?(other).should == false
37
- end
38
- end
39
-
40
- end
41
-
42
- end
43
-
44
- end