rdf-tabular 0.4.0 → 1.0.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.
- 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
|