rdf-tabular 0.4.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/VERSION +1 -1
- data/lib/rdf/tabular/format.rb +2 -2
- data/lib/rdf/tabular/metadata.rb +7 -26
- data/lib/rdf/tabular/uax35.rb +143 -38
- data/spec/format_spec.rb +4 -3
- data/spec/metadata_spec.rb +8 -8
- data/spec/suite_spec.rb +1 -1
- data/spec/uax35_spec.rb +239 -0
- data/spec/w3c-csvw +1 -0
- metadata +12 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fd3ba26034d83ae78387e86545e7020a2299141
|
4
|
+
data.tar.gz: 79494794a8a96f1799c0ecf7e28891f230a97f70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: def477f7bc65c716906f2e5bf75afde8e79a8abb5304cffc4cb5624f9dc412ae936a5ef4308e3555c865e1b0562d7b398b4706927df632ef47f1b706ea8fc66b
|
7
|
+
data.tar.gz: c61c6772c207e44062e6a92726e64e07a28ab18149f18b564403fd15e6f85badb96f0eb5e39fe253547f9c6837c4538b9a5db52881011d521f51217a2682bcf6
|
data/README.md
CHANGED
@@ -248,7 +248,7 @@ Full documentation available on [RubyDoc](http://rubydoc.info/gems/rdf-tabular/f
|
|
248
248
|
* {RDF::Tabular::Reader}
|
249
249
|
|
250
250
|
## Dependencies
|
251
|
-
* [Ruby](http://ruby-lang.org/) (>= 2.
|
251
|
+
* [Ruby](http://ruby-lang.org/) (>= 2.2.2)
|
252
252
|
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 2.0)
|
253
253
|
* [JSON](https://rubygems.org/gems/json) (>= 1.5)
|
254
254
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/lib/rdf/tabular/format.rb
CHANGED
@@ -24,10 +24,10 @@ module RDF::Tabular
|
|
24
24
|
#
|
25
25
|
# @see http://www.w3.org/TR/rdf-testcases/#ntriples
|
26
26
|
class Format < RDF::Format
|
27
|
-
content_type 'text/csv',
|
27
|
+
content_type 'text/csv;q=0.4',
|
28
28
|
extensions: [:csv, :tsv],
|
29
29
|
alias: %w{
|
30
|
-
text/tab-separated-values
|
30
|
+
text/tab-separated-values;q=0.4
|
31
31
|
application/csvm+json
|
32
32
|
}
|
33
33
|
content_encoding 'utf-8'
|
data/lib/rdf/tabular/metadata.rb
CHANGED
@@ -2171,33 +2171,13 @@ module RDF::Tabular
|
|
2171
2171
|
decimalChar = format["decimalChar"] || '.'
|
2172
2172
|
pattern = format["pattern"]
|
2173
2173
|
|
2174
|
-
|
2174
|
+
begin
|
2175
|
+
value = datatype.parse_uax35_number(pattern, value, groupChar || ",", decimalChar)
|
2176
|
+
rescue UAX35::ParseError
|
2175
2177
|
value_errors << "#{value} does not match numeric pattern #{pattern ? pattern.inspect : 'default'}"
|
2176
2178
|
end
|
2177
2179
|
|
2178
|
-
# pattern facet failed
|
2179
|
-
value_errors << "#{value} has repeating #{groupChar.inspect}" if groupChar && value.include?(groupChar*2)
|
2180
|
-
value = value.gsub(groupChar || ',', '')
|
2181
|
-
value = value.sub(decimalChar, '.')
|
2182
|
-
|
2183
|
-
# Extract percent or per-mille sign
|
2184
|
-
percent = permille = false
|
2185
|
-
case value
|
2186
|
-
when /%/
|
2187
|
-
value = value.sub('%', '')
|
2188
|
-
percent = true
|
2189
|
-
when /‰/
|
2190
|
-
value = value.sub('‰', '')
|
2191
|
-
permille = true
|
2192
|
-
end
|
2193
|
-
|
2194
2180
|
lit = RDF::Literal(value, datatype: expanded_dt)
|
2195
|
-
if percent || permille
|
2196
|
-
o = lit.object
|
2197
|
-
o = o / 100 if percent
|
2198
|
-
o = o / 1000 if permille
|
2199
|
-
lit = RDF::Literal(o, datatype: expanded_dt)
|
2200
|
-
end
|
2201
2181
|
|
2202
2182
|
if !lit.plain? && datatype.minimum && lit < datatype.minimum
|
2203
2183
|
value_errors << "#{value} < minimum #{datatype.minimum}"
|
@@ -2238,10 +2218,11 @@ module RDF::Tabular
|
|
2238
2218
|
end
|
2239
2219
|
end
|
2240
2220
|
when :date, :time, :dateTime, :dateTimeStamp, :datetime
|
2241
|
-
|
2221
|
+
begin
|
2222
|
+
value = datatype.parse_uax35_date(format, value)
|
2242
2223
|
lit = RDF::Literal(value, datatype: expanded_dt)
|
2243
|
-
|
2244
|
-
value_errors << "#{
|
2224
|
+
rescue UAX35::ParseError
|
2225
|
+
value_errors << "#{value} does not match format #{format}"
|
2245
2226
|
end
|
2246
2227
|
when :duration, :dayTimeDuration, :yearMonthDuration
|
2247
2228
|
# SPEC CONFUSION: surely format also includes that for other duration types?
|
data/lib/rdf/tabular/uax35.rb
CHANGED
@@ -7,50 +7,99 @@ module RDF::Tabular
|
|
7
7
|
module UAX35
|
8
8
|
|
9
9
|
##
|
10
|
-
# Parse the date
|
11
|
-
# Otherwise, validate
|
10
|
+
# Parse the date pattern (if provided), and match against the value (if provided)
|
11
|
+
# Otherwise, validate pattern and raise an error.
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# Supported patterns are:
|
14
|
+
#
|
15
|
+
# * yyyy-MM-dd
|
16
|
+
# * yyyyMMdd
|
17
|
+
# * dd-MM-yyyy
|
18
|
+
# * d-M-yyyy
|
19
|
+
# * d-M-yy
|
20
|
+
# * d-M-y
|
21
|
+
# * MM-dd-yyyy
|
22
|
+
# * M-d-yyyy
|
23
|
+
# * M-d-yy
|
24
|
+
# * M-d-y
|
25
|
+
# * dd/MM/yyyy
|
26
|
+
# * d/M/yyyy
|
27
|
+
# * d/M/yy
|
28
|
+
# * d/M/y
|
29
|
+
# * MM/dd/yyyy
|
30
|
+
# * M/d/yyyy
|
31
|
+
# * M/d/yy
|
32
|
+
# * M/d/y
|
33
|
+
# * dd.MM.yyyy
|
34
|
+
# * d.M.yyyy
|
35
|
+
# * d.M.yy
|
36
|
+
# * d.M.y
|
37
|
+
# * MM.dd.yyyy
|
38
|
+
# * M.d.yyyy
|
39
|
+
# * M.d.yy
|
40
|
+
# * M.d.y
|
41
|
+
# * yyyy-MM-ddTHH:mm
|
42
|
+
# * yyyy-MM-ddTHH:mm:ss
|
43
|
+
# * yyyy-MM-ddTHH:mm:ss.S+
|
44
|
+
#
|
45
|
+
# Year comonents less than four digits are normalized to 1900 or 2000 based on if the value is <= 99 or >= 70, it is considered to be in the 1900 range, otherwise, based on 2000.
|
46
|
+
#
|
47
|
+
# @param [String] pattern
|
14
48
|
# @param [String] value
|
15
49
|
# @return [String] XMLSchema version of value
|
16
|
-
# @raise [ArgumentError] if
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
value
|
50
|
+
# @raise [ArgumentError] if pattern is not valid, or nil
|
51
|
+
# @raise [ParseError] if value does not match
|
52
|
+
def parse_uax35_date(pattern, value)
|
53
|
+
date_pattern, time_pattern = nil, nil
|
54
|
+
return value unless pattern
|
55
|
+
orig_value = value ||= ""
|
56
|
+
orig_pattern = pattern
|
21
57
|
|
22
58
|
# Extract tz info
|
23
|
-
if md =
|
24
|
-
|
59
|
+
if md = pattern.match(/^(.*[dyms])+(\s*[xX]+)$/)
|
60
|
+
pattern, tz_pattern = md[1], md[2]
|
25
61
|
end
|
26
62
|
|
27
|
-
|
28
|
-
|
63
|
+
date_pattern, time_pattern = pattern.split(' ')
|
64
|
+
# Snuff out if this is a Time pattern
|
65
|
+
date_pattern, time_pattern = nil, date_pattern if time_pattern.nil? && !date_pattern.match(/[TyMd]/)
|
29
66
|
|
30
67
|
# Extract date, of specified
|
31
|
-
date_part = case
|
68
|
+
date_part = case date_pattern
|
32
69
|
when 'yyyy-MM-dd' then value.match(/^(?<yr>\d{4})-(?<mo>\d{2})-(?<da>\d{2})/)
|
33
70
|
when 'yyyyMMdd' then value.match(/^(?<yr>\d{4})(?<mo>\d{2})(?<da>\d{2})/)
|
34
71
|
when 'dd-MM-yyyy' then value.match(/^(?<da>\d{2})-(?<mo>\d{2})-(?<yr>\d{4})/)
|
35
72
|
when 'd-M-yyyy' then value.match(/^(?<da>\d{1,2})-(?<mo>\d{1,2})-(?<yr>\d{4})/)
|
73
|
+
when 'd-M-yy' then value.match(/^(?<da>\d{1,2})-(?<mo>\d{1,2})-(?<yr>\d{2})/)
|
74
|
+
when 'd-M-y' then value.match(/^(?<da>\d{1,2})-(?<mo>\d{1,2})-(?<yr>\d{1,4})/)
|
36
75
|
when 'MM-dd-yyyy' then value.match(/^(?<mo>\d{2})-(?<da>\d{2})-(?<yr>\d{4})/)
|
37
76
|
when 'M-d-yyyy' then value.match(/^(?<mo>\d{1,2})-(?<da>\d{1,2})-(?<yr>\d{4})/)
|
38
|
-
when '
|
77
|
+
when 'M-d-yy' then value.match(/^(?<mo>\d{1,2})-(?<da>\d{1,2})-(?<yr>\d{2})/)
|
78
|
+
when 'M-d-y' then value.match(/^(?<mo>\d{1,2})-(?<da>\d{1,2})-(?<yr>\d{1,4})/)
|
79
|
+
when 'dd/MM/yyyy' then value.match(/^(?<da>\d{2})\/(?<mo>\d{2})\/(?<yr>\d{1,4})/)
|
39
80
|
when 'd/M/yyyy' then value.match(/^(?<da>\d{1,2})\/(?<mo>\d{1,2})\/(?<yr>\d{4})/)
|
40
|
-
when '
|
81
|
+
when 'd/M/yy' then value.match(/^(?<da>\d{1,2})\/(?<mo>\d{1,2})\/(?<yr>\d{2})/)
|
82
|
+
when 'd/M/y' then value.match(/^(?<da>\d{1,2})\/(?<mo>\d{1,2})\/(?<yr>\d{1,4})/)
|
83
|
+
when 'MM/dd/yyyy' then value.match(/^(?<mo>\d{2})\/(?<da>\d{2})\/(?<yr>\d{1,4})/)
|
41
84
|
when 'M/d/yyyy' then value.match(/^(?<mo>\d{1,2})\/(?<da>\d{1,2})\/(?<yr>\d{4})/)
|
85
|
+
when 'M/d/yy' then value.match(/^(?<mo>\d{1,2})\/(?<da>\d{1,2})\/(?<yr>\d{2})/)
|
86
|
+
when 'M/d/y' then value.match(/^(?<mo>\d{1,2})\/(?<da>\d{1,2})\/(?<yr>\d{1,4})/)
|
42
87
|
when 'dd.MM.yyyy' then value.match(/^(?<da>\d{2})\.(?<mo>\d{2})\.(?<yr>\d{4})/)
|
43
88
|
when 'd.M.yyyy' then value.match(/^(?<da>\d{1,2})\.(?<mo>\d{1,2})\.(?<yr>\d{4})/)
|
89
|
+
when 'd.M.yy' then value.match(/^(?<da>\d{1,2})\.(?<mo>\d{1,2})\.(?<yr>\d{2})/)
|
90
|
+
when 'd.M.y' then value.match(/^(?<da>\d{1,2})\.(?<mo>\d{1,2})\.(?<yr>\d{1,4})/)
|
44
91
|
when 'MM.dd.yyyy' then value.match(/^(?<mo>\d{2})\.(?<da>\d{2})\.(?<yr>\d{4})/)
|
45
92
|
when 'M.d.yyyy' then value.match(/^(?<mo>\d{1,2})\.(?<da>\d{1,2})\.(?<yr>\d{4})/)
|
93
|
+
when 'M.d.yy' then value.match(/^(?<mo>\d{1,2})\.(?<da>\d{1,2})\.(?<yr>\d{2})/)
|
94
|
+
when 'M.d.y' then value.match(/^(?<mo>\d{1,2})\.(?<da>\d{1,2})\.(?<yr>\d{1,4})/)
|
46
95
|
when 'yyyy-MM-ddTHH:mm' then value.match(/^(?<yr>\d{4})-(?<mo>\d{2})-(?<da>\d{2})T(?<hr>\d{2}):(?<mi>\d{2})(?<se>(?<ms>))/)
|
47
96
|
when 'yyyy-MM-ddTHH:mm:ss' then value.match(/^(?<yr>\d{4})-(?<mo>\d{2})-(?<da>\d{2})T(?<hr>\d{2}):(?<mi>\d{2}):(?<se>\d{2})(?<ms>)/)
|
48
97
|
when /yyyy-MM-ddTHH:mm:ss\.S+/
|
49
98
|
md = value.match(/^(?<yr>\d{4})-(?<mo>\d{2})-(?<da>\d{2})T(?<hr>\d{2}):(?<mi>\d{2}):(?<se>\d{2})\.(?<ms>\d+)/)
|
50
|
-
num_ms =
|
99
|
+
num_ms = date_pattern.match(/S+/).to_s.length
|
51
100
|
md if md && md[:ms].length <= num_ms
|
52
101
|
else
|
53
|
-
raise ArgumentError, "unrecognized date/time
|
102
|
+
raise ArgumentError, "unrecognized date/time pattern #{date_pattern}" if date_pattern
|
54
103
|
nil
|
55
104
|
end
|
56
105
|
|
@@ -61,25 +110,25 @@ module RDF::Tabular
|
|
61
110
|
end
|
62
111
|
|
63
112
|
# Extract time, of specified
|
64
|
-
time_part = case
|
113
|
+
time_part = case time_pattern
|
65
114
|
when 'HH:mm:ss' then value.match(/^(?<hr>\d{2}):(?<mi>\d{2}):(?<se>\d{2})(?<ms>)/)
|
66
115
|
when 'HHmmss' then value.match(/^(?<hr>\d{2})(?<mi>\d{2})(?<se>\d{2})(?<ms>)/)
|
67
116
|
when 'HH:mm' then value.match(/^(?<hr>\d{2}):(?<mi>\d{2})(?<se>)(?<ms>)/)
|
68
117
|
when 'HHmm' then value.match(/^(?<hr>\d{2})(?<mi>\d{2})(?<se>)(?<ms>)/)
|
69
118
|
when /HH:mm:ss\.S+/
|
70
119
|
md = value.match(/^(?<hr>\d{2}):(?<mi>\d{2}):(?<se>\d{2})\.(?<ms>\d+)/)
|
71
|
-
num_ms =
|
120
|
+
num_ms = time_pattern.match(/S+/).to_s.length
|
72
121
|
md if md && md[:ms].length <= num_ms
|
73
122
|
else
|
74
|
-
raise ArgumentError, "unrecognized date/time
|
123
|
+
raise ArgumentError, "unrecognized date/time pattern #{pattern}" if time_pattern
|
75
124
|
nil
|
76
125
|
end
|
77
126
|
|
78
|
-
# If there's a
|
79
|
-
|
127
|
+
# If there's a date_pattern but no date_part, match fails
|
128
|
+
raise ParseError, "#{orig_value} does not match pattern #{orig_pattern}" if !orig_value.empty? && date_pattern && date_part.nil?
|
80
129
|
|
81
|
-
# If there's a
|
82
|
-
|
130
|
+
# If there's a time_pattern but no time_part, match fails
|
131
|
+
raise ParseError, "#{orig_value} does not match pattern #{orig_pattern}" if !orig_value.empty? && time_pattern && time_part.nil?
|
83
132
|
|
84
133
|
# Forward past time part
|
85
134
|
value = value[time_part.to_s.length..-1] if time_part
|
@@ -88,8 +137,8 @@ module RDF::Tabular
|
|
88
137
|
time_part = date_part if date_part && date_part.names.include?("hr")
|
89
138
|
|
90
139
|
# If there's a timezone, it may optionally start with whitespace
|
91
|
-
value = value.lstrip if
|
92
|
-
tz_part = case
|
140
|
+
value = value.lstrip if tz_pattern.to_s.start_with?(' ')
|
141
|
+
tz_part = case tz_pattern.to_s.lstrip
|
93
142
|
when 'x' then value.match(/^(?:(?<hr>[+-]\d{2})(?<mi>\d{2})?)$/)
|
94
143
|
when 'X' then value.match(/^(?:(?:(?<hr>[+-]\d{2})(?<mi>\d{2})?)|(?<z>Z))$/)
|
95
144
|
when 'xx' then value.match(/^(?:(?<hr>[+-]\d{2})(?<mi>\d{2}))|$/)
|
@@ -97,15 +146,30 @@ module RDF::Tabular
|
|
97
146
|
when 'xxx' then value.match(/^(?:(?<hr>[+-]\d{2}):(?<mi>\d{2}))$/)
|
98
147
|
when 'XXX' then value.match(/^(?:(?:(?<hr>[+-]\d{2}):(?<mi>\d{2}))|(?<z>Z))$/)
|
99
148
|
else
|
100
|
-
raise ArgumentError, "unrecognized timezone
|
149
|
+
raise ArgumentError, "unrecognized timezone pattern #{tz_pattern.to_s.lstrip}" if tz_pattern
|
101
150
|
nil
|
102
151
|
end
|
103
152
|
|
104
|
-
# If there's a
|
105
|
-
|
153
|
+
# If there's a tz_pattern but no time_part, match fails
|
154
|
+
raise ParseError, "#{orig_value} does not match pattern #{orig_pattern}" if !orig_value.empty? && tz_pattern && tz_part.nil?
|
106
155
|
|
107
156
|
# Compose normalized value
|
108
|
-
vd =
|
157
|
+
vd = if date_part
|
158
|
+
yr, mo, da = [date_part[:yr], date_part[:mo], date_part[:da]].map(&:to_i)
|
159
|
+
|
160
|
+
if date_part[:yr].length < 4
|
161
|
+
# Make sure that yr makes sense, if given
|
162
|
+
yr = case yr
|
163
|
+
when 0..69 then yr + 2000
|
164
|
+
when 100..999 then yr + 2000
|
165
|
+
when 70..99 then yr + 1900
|
166
|
+
else yr
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
("%04d-%02d-%02d" % [yr, mo, da])
|
171
|
+
end
|
172
|
+
|
109
173
|
vt = ("%02d:%02d:%02d" % [time_part[:hr].to_i, time_part[:mi].to_i, time_part[:se].to_i]) if time_part
|
110
174
|
|
111
175
|
# Add milliseconds, if matched
|
@@ -117,37 +181,74 @@ module RDF::Tabular
|
|
117
181
|
end
|
118
182
|
|
119
183
|
##
|
120
|
-
# Parse the date
|
121
|
-
# Otherwise, validate
|
184
|
+
# Parse the date pattern (if provided), and match against the value (if provided)
|
185
|
+
# Otherwise, validate pattern and raise an error
|
122
186
|
#
|
123
187
|
# @param [String] pattern
|
124
188
|
# @param [String] value
|
125
189
|
# @param [String] groupChar
|
126
190
|
# @param [String] decimalChar
|
127
191
|
# @return [String] XMLSchema version of value or nil, if value does not match
|
128
|
-
# @raise [ArgumentError] if
|
192
|
+
# @raise [ArgumentError] if pattern is not valid
|
129
193
|
def parse_uax35_number(pattern, value, groupChar=",", decimalChar=".")
|
130
194
|
value ||= ""
|
131
195
|
|
132
196
|
re = build_number_re(pattern, groupChar, decimalChar)
|
133
197
|
|
198
|
+
raise ParseError, "#{value} has repeating #{groupChar.inspect}" if groupChar.length == 1 && value.include?(groupChar*2)
|
199
|
+
|
134
200
|
# Upcase value and remove internal spaces
|
135
201
|
value = value.upcase
|
136
202
|
|
137
203
|
if value =~ re
|
138
|
-
|
139
204
|
# Upcase value and remove internal spaces
|
140
205
|
value = value.
|
141
|
-
upcase.
|
142
206
|
gsub(/\s+/, '').
|
143
207
|
gsub(groupChar, '').
|
144
208
|
gsub(decimalChar, '.')
|
145
209
|
|
146
210
|
# result re-assembles parts removed from value
|
147
211
|
value
|
148
|
-
|
212
|
+
elsif !value.empty?
|
149
213
|
# no match
|
150
|
-
|
214
|
+
raise ParseError, "#{value.inspect} does not match #{pattern.inspect}"
|
215
|
+
end
|
216
|
+
|
217
|
+
# Extract percent or per-mille sign
|
218
|
+
case value
|
219
|
+
when /%/
|
220
|
+
value = value.sub('%', '')
|
221
|
+
lhs, rhs = value.split('.')
|
222
|
+
|
223
|
+
# Shift decimal
|
224
|
+
value = case lhs.length
|
225
|
+
when 0 then "0.00#{rhs}".sub('E', 'e')
|
226
|
+
when 1 then "0.0#{lhs}#{rhs}".sub('E', 'e')
|
227
|
+
when 2 then "0.#{lhs}#{rhs}".sub('E', 'e')
|
228
|
+
else
|
229
|
+
ll, lr = lhs[0..lhs.length-3], lhs[-2..-1]
|
230
|
+
ll = ll + "0" unless ll =~ /\d+/
|
231
|
+
"#{ll}.#{lr}#{rhs}".sub('E', 'e')
|
232
|
+
end
|
233
|
+
when /‰/
|
234
|
+
value = value.sub('‰', '')
|
235
|
+
lhs, rhs = value.split('.')
|
236
|
+
|
237
|
+
# Shift decimal
|
238
|
+
value = case lhs.length
|
239
|
+
when 0 then "0.000#{rhs}".sub('E', 'e')
|
240
|
+
when 1 then "0.00#{lhs}#{rhs}".sub('E', 'e')
|
241
|
+
when 2 then "0.0#{lhs}#{rhs}".sub('E', 'e')
|
242
|
+
when 3 then "0.#{lhs}#{rhs}".sub('E', 'e')
|
243
|
+
else
|
244
|
+
ll, lr = lhs[0..lhs.length-4], lhs[-3..-1]
|
245
|
+
ll = ll + "0" unless ll =~ /\d+/
|
246
|
+
"#{ll}.#{lr}#{rhs}".sub('E', 'e')
|
247
|
+
end
|
248
|
+
when /NAN/ then value.sub('NAN', 'NaN')
|
249
|
+
when /E/ then value.sub('E', 'e')
|
250
|
+
else
|
251
|
+
value
|
151
252
|
end
|
152
253
|
end
|
153
254
|
|
@@ -157,9 +258,10 @@ module RDF::Tabular
|
|
157
258
|
# @param [String] groupChar
|
158
259
|
# @param [String] decimalChar
|
159
260
|
# @return [Regexp] Regular expression matching value
|
160
|
-
# @raise [ArgumentError] if
|
261
|
+
# @raise [ArgumentError] if pattern is not valid
|
161
262
|
def build_number_re(pattern, groupChar, decimalChar)
|
162
263
|
# pattern must be composed of only 0, #, decimalChar, groupChar, E, %, and ‰
|
264
|
+
|
163
265
|
ge = Regexp.escape groupChar
|
164
266
|
de = Regexp.escape decimalChar
|
165
267
|
|
@@ -320,5 +422,8 @@ module RDF::Tabular
|
|
320
422
|
|
321
423
|
Regexp.new("^(?<prefix>#{prefix})(?<numeric_part>#{integer_str}#{fractional_str}#{exponent_str})(?<suffix>#{suffix})$")
|
322
424
|
end
|
425
|
+
|
426
|
+
# ParseError is raised when a value does not match the pattern
|
427
|
+
class ParseError < RuntimeError; end
|
323
428
|
end
|
324
429
|
end
|
data/spec/format_spec.rb
CHANGED
@@ -54,13 +54,14 @@ describe RDF::Tabular::Format do
|
|
54
54
|
end
|
55
55
|
})
|
56
56
|
end
|
57
|
-
after(:each) {|example| puts logger.to_s if example.exception}
|
58
57
|
|
59
58
|
require 'rdf/cli'
|
60
|
-
let(:input) {
|
59
|
+
let(:input) {"http://example.org/data/countries.json"}
|
61
60
|
describe "#tabular-json" do
|
62
61
|
it "serializes to JSON" do
|
63
|
-
expect {
|
62
|
+
expect {
|
63
|
+
RDF::CLI.exec(["tabular-json", input], format: :tabular)
|
64
|
+
}.to write.to(:output)
|
64
65
|
end
|
65
66
|
end
|
66
67
|
end
|
data/spec/metadata_spec.rb
CHANGED
@@ -1136,7 +1136,7 @@ describe RDF::Tabular::Metadata do
|
|
1136
1136
|
format: {"groupChar" => ";"},
|
1137
1137
|
value: "123;;456.789",
|
1138
1138
|
result: "123;;456.789",
|
1139
|
-
errors: [/
|
1139
|
+
errors: [/does not match numeric pattern/]
|
1140
1140
|
},
|
1141
1141
|
"decimal with explicit decimalChar" => {
|
1142
1142
|
base: "decimal",
|
@@ -1184,19 +1184,19 @@ describe RDF::Tabular::Metadata do
|
|
1184
1184
|
"invalid nonPositiveInteger" => {base: "nonPositiveInteger", value: "1", errors: ["1 is not a valid nonPositiveInteger"]},
|
1185
1185
|
"valid nonNegativeInteger" => {base: "nonNegativeInteger", value: "0"},
|
1186
1186
|
"invalid nonNegativeInteger" => {base: "nonNegativeInteger", value: "-1", errors: ["-1 is not a valid nonNegativeInteger"]},
|
1187
|
-
"valid double" => {base: "double", value: "1234.
|
1187
|
+
"valid double" => {base: "double", value: "1234.456e789"},
|
1188
1188
|
"invalid double" => {base: "double", value: "1z", errors: ["1z is not a valid double"]},
|
1189
|
-
"NaN double" => {base: "double", value: "NaN"},
|
1189
|
+
"NaN double" => {base: "double", value: "NaN", result: "NaN"},
|
1190
1190
|
"INF double" => {base: "double", value: "INF"},
|
1191
1191
|
"-INF double" => {base: "double", value: "-INF"},
|
1192
|
-
"valid number" => {base: "number", value: "1234.
|
1192
|
+
"valid number" => {base: "number", value: "1234.456e789"},
|
1193
1193
|
"invalid number" => {base: "number", value: "1z", errors: ["1z is not a valid number"]},
|
1194
|
-
"NaN number" => {base: "number", value: "NaN"},
|
1194
|
+
"NaN number" => {base: "number", value: "NaN", result: "NaN"},
|
1195
1195
|
"INF number" => {base: "number", value: "INF"},
|
1196
1196
|
"-INF number" => {base: "number", value: "-INF"},
|
1197
|
-
"valid float" => {base: "float", value: "1234.
|
1197
|
+
"valid float" => {base: "float", value: "1234.456e7"},
|
1198
1198
|
"invalid float" => {base: "float", value: "1z", errors: ["1z is not a valid float"]},
|
1199
|
-
"NaN float" => {base: "float", value: "NaN"},
|
1199
|
+
"NaN float" => {base: "float", value: "NaN", result: "NaN"},
|
1200
1200
|
"INF float" => {base: "float", value: "INF"},
|
1201
1201
|
"-INF float" => {base: "float", value: "-INF"},
|
1202
1202
|
|
@@ -1327,7 +1327,7 @@ describe RDF::Tabular::Metadata do
|
|
1327
1327
|
"valid NMTOKEN" => {base: "NMTOKEN", value: "someThing", result: RDF::Literal("someThing", datatype: RDF::XSD.NMTOKEN)},
|
1328
1328
|
|
1329
1329
|
# Aliases
|
1330
|
-
"number is alias for double" => {base: "number", value: "1234.
|
1330
|
+
"number is alias for double" => {base: "number", value: "1234.456e789", result: RDF::Literal("1234.456e789", datatype: RDF::XSD.double)},
|
1331
1331
|
"binary is alias for base64Binary" => {base: "binary", value: "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g", result: RDF::Literal("Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g", datatype: RDF::XSD.base64Binary)},
|
1332
1332
|
"datetime is alias for dateTime" => {base: "dateTime", value: "15-3-2015 1502", format: "d-M-yyyy HHmm", result: RDF::Literal("2015-03-15T15:02:00", datatype: RDF::XSD.dateTime)},
|
1333
1333
|
"any is alias for anyAtomicType" => {base: "any", value: "some thing", result: RDF::Literal("some thing", datatype: RDF::XSD.anyAtomicType)},
|
data/spec/suite_spec.rb
CHANGED
@@ -18,7 +18,7 @@ describe RDF::Tabular::Reader do
|
|
18
18
|
m.entries.each do |t|
|
19
19
|
next if t.approval =~ /Rejected/
|
20
20
|
specify "#{t.id.split("/").last}: #{t.name} - #{t.comment}" do
|
21
|
-
pending "rdf#
|
21
|
+
pending "rdf#test283 literal normalization" if t.id.include?("rdf#test283")
|
22
22
|
t.logger = RDF::Spec.logger
|
23
23
|
t.logger.formatter = lambda {|severity, datetime, progname, msg| "#{severity}: #{msg}\n"}
|
24
24
|
t.logger.info t.inspect
|
data/spec/uax35_spec.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
$:.unshift "."
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe RDF::Tabular::UAX35 do
|
6
|
+
subject {"".extend(RDF::Tabular::UAX35)}
|
7
|
+
|
8
|
+
describe "parse_uax35_date" do
|
9
|
+
{
|
10
|
+
# Dates
|
11
|
+
"valid date yyyy-MM-dd" => {value: "2015-03-22", pattern: "yyyy-MM-dd", result: "2015-03-22"},
|
12
|
+
"valid date yyyyMMdd" => {value: "20150322", pattern: "yyyyMMdd", result: "2015-03-22"},
|
13
|
+
"valid date dd-MM-yyyy" => {value: "22-03-2015", pattern: "dd-MM-yyyy", result: "2015-03-22"},
|
14
|
+
"valid date d-M-yyyy" => {value: "22-3-2015", pattern: "d-M-yyyy", result: "2015-03-22"},
|
15
|
+
"valid date d-M-yy" => {value: "22-3-15", pattern: "d-M-yy", result: "2015-03-22"},
|
16
|
+
"valid date d-M-y" => {value: "22-3-15", pattern: "d-M-y", result: "2015-03-22"},
|
17
|
+
"valid date MM-dd-yyyy" => {value: "03-22-2015", pattern: "MM-dd-yyyy", result: "2015-03-22"},
|
18
|
+
"valid date M-d-yyyy" => {value: "3-22-2015", pattern: "M-d-yyyy", result: "2015-03-22"},
|
19
|
+
"valid date M-d-yy" => {value: "3-22-70", pattern: "M-d-yy", result: "1970-03-22"},
|
20
|
+
"valid date M-d-y" => {value: "3-22-70", pattern: "M-d-y", result: "1970-03-22"},
|
21
|
+
"valid date dd/MM/yyyy" => {value: "22/03/2015", pattern: "dd/MM/yyyy", result: "2015-03-22"},
|
22
|
+
"valid date d/M/yyyy" => {value: "22/3/2015", pattern: "d/M/yyyy", result: "2015-03-22"},
|
23
|
+
"valid date d/M/yy" => {value: "22/3/15", pattern: "d/M/yy", result: "2015-03-22"},
|
24
|
+
"valid date d/M/y" => {value: "22/3/15", pattern: "d/M/y", result: "2015-03-22"},
|
25
|
+
"valid date MM/dd/yyyy" => {value: "03/22/2015", pattern: "MM/dd/yyyy", result: "2015-03-22"},
|
26
|
+
"valid date M/d/yyyy" => {value: "3/22/2015", pattern: "M/d/yyyy", result: "2015-03-22"},
|
27
|
+
"valid date M/d/yy" => {value: "3/22/15", pattern: "M/d/yy", result: "2015-03-22"},
|
28
|
+
"valid date M/d/y" => {value: "3/22/15", pattern: "M/d/y", result: "2015-03-22"},
|
29
|
+
"valid date dd.MM.yyyy" => {value: "22.03.2015", pattern: "dd.MM.yyyy", result: "2015-03-22"},
|
30
|
+
"valid date d.M.yyyy" => {value: "22.3.2015", pattern: "d.M.yyyy", result: "2015-03-22"},
|
31
|
+
"valid date d.M.yy" => {value: "22.3.15", pattern: "d.M.yy", result: "2015-03-22"},
|
32
|
+
"valid date d.M.y" => {value: "22.3.15", pattern: "d.M.y", result: "2015-03-22"},
|
33
|
+
"valid date MM.dd.yyyy" => {value: "03.22.2015", pattern: "MM.dd.yyyy", result: "2015-03-22"},
|
34
|
+
"valid date M.d.yyyy" => {value: "3.22.2015", pattern: "M.d.yyyy", result: "2015-03-22"},
|
35
|
+
"valid date M.d.yy" => {value: "3.22.15", pattern: "M.d.yy", result: "2015-03-22"},
|
36
|
+
"valid date M.d.y" => {value: "3.22.15", pattern: "M.d.y", result: "2015-03-22"},
|
37
|
+
|
38
|
+
# Times
|
39
|
+
"valid time HH:mm:ss.S" => {value: "15:02:37.1", pattern: "HH:mm:ss.S", result: "15:02:37.1"},
|
40
|
+
"valid time HH:mm:ss" => {value: "15:02:37", pattern: "HH:mm:ss", result: "15:02:37"},
|
41
|
+
"valid time HHmmss" => {value: "150237", pattern: "HHmmss", result: "15:02:37"},
|
42
|
+
"valid time HH:mm" => {value: "15:02", pattern: "HH:mm", result: "15:02:00"},
|
43
|
+
"valid time HHmm" => {value: "1502", pattern: "HHmm", result: "15:02:00"},
|
44
|
+
|
45
|
+
# DateTimes
|
46
|
+
"valid dateTime yyyy-MM-ddTHH:mm:ss" => {value: "2015-03-15T15:02:37", pattern: "yyyy-MM-ddTHH:mm:ss", result: "2015-03-15T15:02:37"},
|
47
|
+
"valid dateTime yyyy-MM-ddTHH:mm:ss.S"=> {value: "2015-03-15T15:02:37.1", pattern: "yyyy-MM-ddTHH:mm:ss.S", result: "2015-03-15T15:02:37.1"},
|
48
|
+
"valid dateTime yyyy-MM-dd HH:mm:ss" => {value: "2015-03-15 15:02:37", pattern: "yyyy-MM-dd HH:mm:ss", result: "2015-03-15T15:02:37"},
|
49
|
+
"valid dateTime yyyyMMdd HHmmss" => {value: "20150315 150237", pattern: "yyyyMMdd HHmmss", result: "2015-03-15T15:02:37"},
|
50
|
+
"valid dateTime dd-MM-yyyy HH:mm" => {value: "15-03-2015 15:02", pattern: "dd-MM-yyyy HH:mm", result: "2015-03-15T15:02:00"},
|
51
|
+
"valid dateTime d-M-yyyy HHmm" => {value: "15-3-2015 1502", pattern: "d-M-yyyy HHmm", result: "2015-03-15T15:02:00"},
|
52
|
+
"valid dateTime yyyy-MM-ddTHH:mm" => {value: "2015-03-15T15:02", pattern: "yyyy-MM-ddTHH:mm", result: "2015-03-15T15:02:00"},
|
53
|
+
"valid dateTimeStamp d-M-yyyy HHmm X" => {value: "15-3-2015 1502 Z", pattern: "d-M-yyyy HHmm X", result: "2015-03-15T15:02:00Z"},
|
54
|
+
"valid datetime yyyy-MM-ddTHH:mm:ss" => {value: "2015-03-15T15:02:37", pattern: "yyyy-MM-ddTHH:mm:ss", result: "2015-03-15T15:02:37"},
|
55
|
+
"valid datetime yyyy-MM-dd HH:mm:ss" => {value: "2015-03-15 15:02:37", pattern: "yyyy-MM-dd HH:mm:ss", result: "2015-03-15T15:02:37"},
|
56
|
+
"valid datetime yyyyMMdd HHmmss" => {value: "20150315 150237", pattern: "yyyyMMdd HHmmss", result: "2015-03-15T15:02:37"},
|
57
|
+
"valid datetime dd-MM-yyyy HH:mm" => {value: "15-03-2015 15:02", pattern: "dd-MM-yyyy HH:mm", result: "2015-03-15T15:02:00"},
|
58
|
+
"valid datetime d-M-yyyy HHmm" => {value: "15-3-2015 1502", pattern: "d-M-yyyy HHmm", result: "2015-03-15T15:02:00"},
|
59
|
+
"valid datetime yyyy-MM-ddTHH:mm" => {value: "2015-03-15T15:02", pattern: "yyyy-MM-ddTHH:mm", result: "2015-03-15T15:02:00"},
|
60
|
+
|
61
|
+
# Timezones
|
62
|
+
"valid w/TZ yyyy-MM-ddX" => {value: "2015-03-22Z", pattern: "yyyy-MM-ddX", result: "2015-03-22Z"},
|
63
|
+
"valid w/TZ HH:mm:ssX" => {value: "15:02:37-05", pattern: "HH:mm:ssX", result: "15:02:37-05:00"},
|
64
|
+
"valid w/TZ yyyy-MM-dd HH:mm:ss X" => {value: "2015-03-15 15:02:37 +0800", pattern: "yyyy-MM-dd HH:mm:ss X", result: "2015-03-15T15:02:37+08:00"},
|
65
|
+
"valid w/TZ HHmm XX" => {value: "1502 +0800", pattern: "HHmm XX", result: "15:02:00+08:00"},
|
66
|
+
"valid w/TZ yyyy-MM-dd HH:mm:ss XX" => {value: "2015-03-15 15:02:37 -0800", pattern: "yyyy-MM-dd HH:mm:ss XX", result: "2015-03-15T15:02:37-08:00"},
|
67
|
+
"valid w/TZ HHmm XXX" => {value: "1502 +08:00", pattern: "HHmm XXX", result: "15:02:00+08:00"},
|
68
|
+
"valid w/TZ yyyy-MM-ddTHH:mm:ssXXX" => {value: "2015-03-15T15:02:37-05:00", pattern: "yyyy-MM-ddTHH:mm:ssXXX", result: "2015-03-15T15:02:37-05:00"},
|
69
|
+
"invalid w/TZ HH:mm:ssX" => {value: "15:02:37-05:00", pattern: "HH:mm:ssX", error: "15:02:37-05:00 does not match pattern HH:mm:ssX"},
|
70
|
+
"invalid w/TZ HH:mm:ssXX" => {value: "15:02:37-05", pattern: "HH:mm:ssXX", error: "15:02:37-05 does not match pattern HH:mm:ssXX"},
|
71
|
+
}.each do |name, props|
|
72
|
+
context name do
|
73
|
+
let(:base) {props[:base]}
|
74
|
+
let(:pattern) {props[:pattern]}
|
75
|
+
let(:value) {props[:value]}
|
76
|
+
let(:result) {props.fetch(:result, value)}
|
77
|
+
if props[:error]
|
78
|
+
it "finds error" do
|
79
|
+
expect {subject.parse_uax35_date(pattern, value)}.to raise_error(RDF::Tabular::UAX35::ParseError, props[:error])
|
80
|
+
end
|
81
|
+
else
|
82
|
+
it "generates #{props[:result] || props[:value]}" do
|
83
|
+
expect(subject.parse_uax35_date(pattern, value)).to eql result
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "parse_uax35_number" do
|
91
|
+
{
|
92
|
+
# Numbers
|
93
|
+
"default no constraints" => {valid: %w(4)},
|
94
|
+
"default matching pattern" => {pattern: "000", valid: %w(123)},
|
95
|
+
"default explicit groupChar" => {groupChar: ";", valid: {"123;456.789" => "123456.789"}},
|
96
|
+
"default repeated groupChar" => {groupChar: ";", invalid: %w(123;;456.789)},
|
97
|
+
"default explicit decimalChar" => {decimalChar: ";", valid: {"123456;789" => "123456.789"}},
|
98
|
+
"default percent" => {groupChar: ",", valid: {"123456.789%" => "1234.56789"}},
|
99
|
+
"default per-mille" => {groupChar: ",", valid: {"123456.789‰" => "123.456789"}},
|
100
|
+
|
101
|
+
"0" => {pattern: "0", valid: %w(1 -1 12), invalid: %w(1.2)},
|
102
|
+
"00" => {pattern: "00", valid: %w(12 123), invalid: %w(1 1,2)},
|
103
|
+
"#" => {pattern: "#", valid: %w(1 12 123), invalid: %w(1.2)},
|
104
|
+
"##" => {pattern: "##", valid: %w(1 12 123), invalid: %w(1.2)},
|
105
|
+
"#0" => {pattern: "#0", valid: %w(1 12 123), invalid: %w(1.2)},
|
106
|
+
'0.0' => {pattern: "0.0", valid: %w(1.1 -1.1 12.1), invalid: %w(1.12)},
|
107
|
+
'0.00' => {pattern: '0.00', valid: %w(1.12 +1.12 12.12), invalid: %w(1.1 1.123)},
|
108
|
+
'0.#' => {pattern: '0.#', valid: %w(1 1.1 12.1), invalid: %w(1.12)},
|
109
|
+
'-0' => {pattern: '-0', valid: %w(-1 -10), invalid: %w(1 +1)},
|
110
|
+
'%000' => {pattern: '%000', valid: {"%123" => "1.23", "%+123" => "+1.23", "%1234" => "12.34"}, invalid: %w(%12 123%)},
|
111
|
+
'‰000' => {pattern: '‰000', valid: {"‰123" => "0.123", "‰+123" => "+0.123", "‰1234" => "1.234"}, invalid: %w(‰12 123‰)},
|
112
|
+
'000%' => {pattern: '000%', valid: {"123%" => "1.23", "+123%" => "+1.23", "1234%" => "12.34"}, invalid: %w(12% %123)},
|
113
|
+
'000‰' => {pattern: '000‰', valid: {"123‰" => "0.123", "+123‰" => "+0.123", "1234‰" => "1.234"}, invalid: %w(12‰ ‰123)},
|
114
|
+
'000.0%' => {pattern: '000.0%', valid: {"123.4%" => "1.234", "+123.4%" => "+1.234"}, invalid: %w(123.4‰ 123.4 1.234% 12.34% 123.45%)},
|
115
|
+
|
116
|
+
'###0.#####' => {pattern: '###0.#####', valid: %w(1 1.1 12345.12345), invalid: %w(1,234.1 1.123456)},
|
117
|
+
'###0.0000#' => {pattern: '###0.0000#', valid: %w(1.1234 1.12345 12345.12345), invalid: %w(1,234.1234 1.12)},
|
118
|
+
'00000.0000' => {pattern: '00000.0000', valid: %w(12345.1234), invalid: %w(1.2 1,234.123,4)},
|
119
|
+
|
120
|
+
'#0.0#E#0' => {pattern: '#0.0#E#0', valid: %w(1.2e3 12.34e56)},
|
121
|
+
'#0.0#E+#0' => {pattern: '#0.0#E+#0', valid: %w(1.2e+3 12.34e+56), invalid: %w(1.2e3 12.34e56)},
|
122
|
+
'#0.0#E#0%' => {pattern: '#0.0#E#0%', valid: {"1.2e3%" => "0.012e3", "12.34e56%" => "0.1234e56"}, invalid: %w(1.2e+3 12.34e+56 1.2e3 12.34e56)},
|
123
|
+
|
124
|
+
# Grouping
|
125
|
+
'#,##,##0' => {pattern: '#,##,##0', valid: {"1" => "1", "12" => "12", "123" => "123", "1,234" => "1234", "12,345" => "12345", "1,23,456" => "123456"}, invalid: %w(1,2 12,34)},
|
126
|
+
'#,##,#00' => {pattern: '#,##,#00', valid: {"12" => "12", "123" => "123", "1,234" => "1234", "12,345" => "12345"}, invalid: %w(1)},
|
127
|
+
'#,##,000' => {pattern: '#,##,000', valid: {"123" => "123", "1,234" => "1234", "12,345" => "12345"}, invalid: %w(1 12)},
|
128
|
+
'#,#0,000' => {pattern: '#,#0,000', valid: {"1,234" => "1234", "12,345" => "12345"}, invalid: %w(1 12 123)},
|
129
|
+
'#,00,000' => {pattern: '#,00,000', valid: {"12,345" => "12345"}, invalid: %w(1 12 123 1,234)},
|
130
|
+
'0,00,000' => {pattern: '0,00,000'},
|
131
|
+
|
132
|
+
'0.0##,###' => {pattern: '0.0##,###'},
|
133
|
+
'0.00#,###' => {pattern: '0.00#,###'},
|
134
|
+
'0.000,###' => {pattern: '0.000,###'},
|
135
|
+
'0.000,0##' => {pattern: '0.000,0##'},
|
136
|
+
'0.000,00#' => {pattern: '0.000,00#'},
|
137
|
+
'0.000,000' => {pattern: '0.000,000'},
|
138
|
+
|
139
|
+
# Jeni's
|
140
|
+
'##0' => {pattern: '##0', valid: %w(1 12 123 1234), invalid: %w(1,234 123.4)},
|
141
|
+
'#,#00' => {pattern: '#,#00', valid: {"12" => "12", "123" => "123", "1,234" => "1234", "1,234,567" => "1234567"}, invalid: %w(1 1234 12,34 12,34,567)},
|
142
|
+
'#0.#' => {pattern: '#0.#', valid: %w(1 1.2 1234.5), invalid: %w(12.34 1,234.5)},
|
143
|
+
'#0.0#,#' => {pattern: '#0.0#,#', valid: {"12.3" => "12.3", "12.34" => "12.34", "12.34,5" => "12.345"}, invalid: %w(1 12.345 12.34,56,7 12.34,567)},
|
144
|
+
}.each do |name, props|
|
145
|
+
context name do
|
146
|
+
let(:pattern) {props[:pattern]}
|
147
|
+
let(:groupChar) {props.fetch(:groupChar, ',')}
|
148
|
+
let(:decimalChar) {props.fetch(:decimalChar, '.')}
|
149
|
+
|
150
|
+
describe "valid" do
|
151
|
+
case props[:valid]
|
152
|
+
when Hash
|
153
|
+
props[:valid].each do |value, result|
|
154
|
+
it "with #{props[:pattern].inspect} #{value.inspect} => #{result.inspect}" do
|
155
|
+
expect(subject.parse_uax35_number(pattern, value, groupChar, decimalChar)).to eql result
|
156
|
+
end
|
157
|
+
end
|
158
|
+
when Array
|
159
|
+
props[:valid].each do |value|
|
160
|
+
it "with #{props[:pattern].inspect} #{value.inspect} => #{value.inspect}" do
|
161
|
+
expect(subject.parse_uax35_number(pattern, value, groupChar, decimalChar)).to eql value
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
describe "invalid" do
|
167
|
+
Array(props[:invalid]).each do |value|
|
168
|
+
it "with #{props[:pattern].inspect} #{value.inspect} invalid" do
|
169
|
+
expect {subject.parse_uax35_number(pattern, value, groupChar, decimalChar)}.to raise_error RDF::Tabular::UAX35::ParseError
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
it "recognizes bad pattern #{pattern.inspect}" do
|
175
|
+
expect{subject.parse_uax35_number(pattern, "", groupChar, decimalChar)}.to raise_error(ArgumentError)
|
176
|
+
end if props[:exception]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "#build_number_re" do
|
182
|
+
{
|
183
|
+
'0' => {valid: %w(1 -1 +1 12), invalid: %w(1.2), base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,})(?<suffix>)$/},
|
184
|
+
'00' => {valid: %w(12 123), invalid: %w(1 1,2), base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{2,})(?<suffix>)$/},
|
185
|
+
'#' => {valid: %w(1 12 123), invalid: %w(1.2), base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{0,})(?<suffix>)$/},
|
186
|
+
'##' => {re: /^(?<prefix>[+-]?)(?<numeric_part>\d{0,})(?<suffix>)$/},
|
187
|
+
'#0' => {re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,})(?<suffix>)$/},
|
188
|
+
|
189
|
+
'0.0' => {valid: %w(1.1 -1.1 12.1), invalid: %w(1.12), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{1})(?<suffix>)$/},
|
190
|
+
'0.00' => {valid: %w(1.12 +1.12 12.12), invalid: %w(1.1 1.123), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{2})(?<suffix>)$/},
|
191
|
+
'0.#' => {valid: %w(1 1.1 12.1), invalid: %w(1.12), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}(?:\.\d{0,1})?)(?<suffix>)$/},
|
192
|
+
'-0' => {valid: %w(-1 -10), invalid: %w(1 +1), base: "decimal", re: /^(?<prefix>\-)(?<numeric_part>\d{1,})(?<suffix>)$/},
|
193
|
+
'%000' => {valid: %w(%123 %+123 %-123 %1234), invalid: %w(%12 123%), base: "decimal", re: /^(?<prefix>%[+-]?)(?<numeric_part>\d{3,})(?<suffix>)$/},
|
194
|
+
'‰000' => {valid: %w(‰123 ‰+123 ‰-123 ‰1234), invalid: %w(‰12 123‰), base: "decimal", re: /^(?<prefix>‰[+-]?)(?<numeric_part>\d{3,})(?<suffix>)$/},
|
195
|
+
'000%' => {valid: %w(123% +123% -123% 1234%), invalid: %w(12% %123), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{3,})(?<suffix>%)$/},
|
196
|
+
'000‰' => {valid: %w(123‰ +123‰ -123‰ 1234‰), invalid: %w(12‰ ‰123), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{3,})(?<suffix>‰)$/},
|
197
|
+
'000.0%' => {base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{3,}\.\d{1})(?<suffix>%)$/},
|
198
|
+
|
199
|
+
'###0.#####' => {valid: %w(1 1.1 12345.12345), invalid: %w(1,234.1 1.123456), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}(?:\.\d{0,5})?)(?<suffix>)$/},
|
200
|
+
'###0.0000#' => {valid: %w(1.1234 1.12345 12345.12345), invalid: %w(1,234.1234 1.12), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{4,5})(?<suffix>)$/},
|
201
|
+
'00000.0000' => {valid: %w(12345.1234), invalid: %w(1.2 1,234.123,4), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{5,}\.\d{4})(?<suffix>)$/},
|
202
|
+
|
203
|
+
'#0.0#E#0' => {base: "double", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{1,2}E[+-]?\d{1,2})(?<suffix>)$/},
|
204
|
+
'#0.0#E+#0' => {base: "double", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{1,2}E\+\d{1,2})(?<suffix>)$/},
|
205
|
+
'#0.0#E#0%' => {base: "double", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{1,2}E[+-]?\d{1,2})(?<suffix>%)$/},
|
206
|
+
|
207
|
+
# Grouping
|
208
|
+
'#,##,##0' => {base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>(?:(?:(?:\d{1,2},)?(?:\d{2},)*\d)?\d)?\d{1})(?<suffix>)$/},
|
209
|
+
'#,##,#00' => {base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>(?:(?:\d{1,2},)?(?:\d{2},)*\d)?\d{2})(?<suffix>)$/},
|
210
|
+
'#,##,000' => {base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>(?:\d{1,2},)?(?:\d{2},)*\d{3})(?<suffix>)$/},
|
211
|
+
'#,#0,000' => {base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>(?:(?:\d{1,2},)?(?:\d{2},)*\d)?\d{1},\d{3})(?<suffix>)$/},
|
212
|
+
'#,00,000' => {base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>(?:\d{1,2},)?(?:\d{2},)*\d{2},\d{3})(?<suffix>)$/},
|
213
|
+
'0,00,000' => {base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>(?:(?:\d{1,2},)?(?:\d{2},)*\d)?\d{1},\d{2},\d{3})(?<suffix>)$/},
|
214
|
+
|
215
|
+
'0.0##,###' => {base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{1}(?:\d(?:\d(?:,\d(?:\d(?:\d)?)?)?)?)?)(?<suffix>)$/},
|
216
|
+
'0.00#,###' => {base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{2}(?:\d(?:,\d(?:\d(?:\d)?)?)?)?)(?<suffix>)$/},
|
217
|
+
'0.000,###' => {base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{3}(?:,\d(?:\d(?:\d)?)?)?)(?<suffix>)$/},
|
218
|
+
'0.000,0##' => {base: "decimal", re:/^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{3},\d{1}(?:\d(?:\d)?)?)(?<suffix>)$/},
|
219
|
+
'0.000,00#' => {base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{3},\d{2}(?:\d)?)(?<suffix>)$/},
|
220
|
+
'0.000,000' => {base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{3},\d{3})(?<suffix>)$/},
|
221
|
+
|
222
|
+
# Jeni's
|
223
|
+
'##0' => {valid: %w(1 12 123 1234), invalid: %w(1,234 123.4), base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,})(?<suffix>)$/},
|
224
|
+
'#,#00' => {valid: %w(12 123 1,234 1,234,567), invalid: %w(1 1234 12,34 12,34,567), base: "integer", re: /^(?<prefix>[+-]?)(?<numeric_part>(?:(?:\d{1,3},)?(?:\d{3},)*\d)?\d{2})(?<suffix>)$/},
|
225
|
+
'#0.#' => {valid: %w(1 1.2 1234.5), invalid: %w(12.34 1,234.5), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}(?:\.\d{0,1})?)(?<suffix>)$/},
|
226
|
+
'#0.0#,#' => {valid: %w(12.3 12.34 12.34,5), invalid: %w(1 12.345 12.34,56,7 12.34,567), base: "decimal", re: /^(?<prefix>[+-]?)(?<numeric_part>\d{1,}\.\d{1}(?:\d(?:,\d)?)?)(?<suffix>)$/},
|
227
|
+
}.each do |pattern, props|
|
228
|
+
context pattern do
|
229
|
+
it "generates #{props[:re]} for #{pattern}" do
|
230
|
+
expect(subject.build_number_re(pattern, ",", ".")).to eql props[:re]
|
231
|
+
end if props[:re].is_a?(Regexp)
|
232
|
+
|
233
|
+
it "recognizes bad pattern #{pattern}" do
|
234
|
+
expect{subject.build_number_re(pattern, ",", ".")}.to raise_error(ArgumentError)
|
235
|
+
end if props[:re] == ArgumentError
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
data/spec/w3c-csvw
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
spec/../../w3c-csvw
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdf-tabular
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregg Kellogg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bcp47
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '2.
|
39
|
+
version: '2.1'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '2.
|
46
|
+
version: '2.1'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rdf-vocab
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,14 +204,14 @@ dependencies:
|
|
204
204
|
requirements:
|
205
205
|
- - "~>"
|
206
206
|
- !ruby/object:Gem::Version
|
207
|
-
version: '
|
207
|
+
version: '2.3'
|
208
208
|
type: :development
|
209
209
|
prerelease: false
|
210
210
|
version_requirements: !ruby/object:Gem::Requirement
|
211
211
|
requirements:
|
212
212
|
- - "~>"
|
213
213
|
- !ruby/object:Gem::Version
|
214
|
-
version: '
|
214
|
+
version: '2.3'
|
215
215
|
- !ruby/object:Gem::Dependency
|
216
216
|
name: yard
|
217
217
|
requirement: !ruby/object:Gem::Requirement
|
@@ -263,6 +263,8 @@ files:
|
|
263
263
|
- spec/spec_helper.rb
|
264
264
|
- spec/suite_helper.rb
|
265
265
|
- spec/suite_spec.rb
|
266
|
+
- spec/uax35_spec.rb
|
267
|
+
- spec/w3c-csvw
|
266
268
|
homepage: http://github.com/ruby-rdf/rdf-tabular
|
267
269
|
licenses:
|
268
270
|
- Unlicense
|
@@ -275,7 +277,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
275
277
|
requirements:
|
276
278
|
- - ">="
|
277
279
|
- !ruby/object:Gem::Version
|
278
|
-
version:
|
280
|
+
version: 2.2.2
|
279
281
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
280
282
|
requirements:
|
281
283
|
- - ">="
|
@@ -283,7 +285,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
283
285
|
version: '0'
|
284
286
|
requirements: []
|
285
287
|
rubyforge_project:
|
286
|
-
rubygems_version: 2.
|
288
|
+
rubygems_version: 2.6.8
|
287
289
|
signing_key:
|
288
290
|
specification_version: 4
|
289
291
|
summary: Tabular Data RDF Reader and JSON serializer.
|
@@ -295,4 +297,5 @@ test_files:
|
|
295
297
|
- spec/spec_helper.rb
|
296
298
|
- spec/suite_helper.rb
|
297
299
|
- spec/suite_spec.rb
|
298
|
-
|
300
|
+
- spec/uax35_spec.rb
|
301
|
+
- spec/w3c-csvw
|