solis 0.103.0 → 0.104.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 +193 -0
- data/lib/solis/model.rb +7 -0
- data/lib/solis/overlay_fs.rb +1093 -0
- data/lib/solis/query/run.rb +3 -0
- data/lib/solis/rdf_edtf_literal.rb +143 -0
- data/lib/solis/shape/data_types.rb +87 -0
- data/lib/solis/shape/reader/sheet.rb +2 -0
- data/lib/solis/shape.rb +4 -1
- data/lib/solis/version.rb +1 -1
- data/lib/solis.rb +1 -0
- data/solis.gemspec +1 -1
- metadata +17 -1
data/lib/solis/query/run.rb
CHANGED
|
@@ -207,6 +207,9 @@ class Solis::Query::Runner
|
|
|
207
207
|
ISO8601::TimeInterval.parse(literal.value).to_s
|
|
208
208
|
when "http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON"
|
|
209
209
|
JSON.parse(literal.value) rescue literal.value
|
|
210
|
+
when /datatypes\/edtf/, /edtf$/i
|
|
211
|
+
# Return EDTF string representation
|
|
212
|
+
literal.value.to_s
|
|
210
213
|
else
|
|
211
214
|
# Handle language-tagged strings
|
|
212
215
|
if literal.respond_to?(:language) && literal.language
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
require 'rdf'
|
|
2
|
+
require 'edtf'
|
|
3
|
+
|
|
4
|
+
module RDF
|
|
5
|
+
class Literal
|
|
6
|
+
##
|
|
7
|
+
# Extended Date/Time Format (EDTF) literal for RDF 3.x
|
|
8
|
+
#
|
|
9
|
+
# This class provides RDF literal support for EDTF dates, implementing
|
|
10
|
+
# the Library of Congress Extended Date/Time Format specification.
|
|
11
|
+
#
|
|
12
|
+
# @see https://www.loc.gov/standards/datetime/
|
|
13
|
+
# @see https://github.com/inukshuk/edtf-ruby
|
|
14
|
+
class EDTF < Literal
|
|
15
|
+
DATATYPE = RDF::URI('http://id.loc.gov/datatypes/edtf')
|
|
16
|
+
|
|
17
|
+
# Grammar pattern for EDTF validation
|
|
18
|
+
# Supports Level 0, 1, and 2 expressions
|
|
19
|
+
# This is a simplified pattern - the edtf gem handles full validation
|
|
20
|
+
GRAMMAR = /^[\d\-\/\?\~\.\[\]\{\}XuU\^%\,\+\:\s]+$/
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# @param [Object] value
|
|
24
|
+
# @param [Hash{Symbol => Object}] options
|
|
25
|
+
# @option options [String] :lexical (nil)
|
|
26
|
+
def initialize(value, datatype: nil, lexical: nil, **options)
|
|
27
|
+
@edtf_value = parse_edtf(value)
|
|
28
|
+
|
|
29
|
+
# Use EDTF string representation as the lexical form
|
|
30
|
+
lexical_value = @edtf_value.respond_to?(:edtf) ? @edtf_value.edtf : value.to_s
|
|
31
|
+
|
|
32
|
+
super(lexical_value, datatype: DATATYPE, lexical: lexical, **options)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Returns the EDTF object value
|
|
37
|
+
#
|
|
38
|
+
# @return [EDTF::Date, EDTF::Interval, EDTF::Season, EDTF::Set, etc.]
|
|
39
|
+
def object
|
|
40
|
+
@edtf_value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
alias_method :to_edtf, :object
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# Validates the EDTF literal
|
|
47
|
+
#
|
|
48
|
+
# @return [Boolean]
|
|
49
|
+
def valid?
|
|
50
|
+
return false if @edtf_value.nil?
|
|
51
|
+
# EDTF values are valid if they were successfully parsed
|
|
52
|
+
true
|
|
53
|
+
rescue
|
|
54
|
+
false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Returns the canonical string representation
|
|
59
|
+
#
|
|
60
|
+
# @return [String]
|
|
61
|
+
def canonicalize
|
|
62
|
+
return self if @edtf_value.nil?
|
|
63
|
+
self.class.new(@edtf_value.edtf)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
##
|
|
67
|
+
# Converts to a human-readable string
|
|
68
|
+
#
|
|
69
|
+
# @return [String]
|
|
70
|
+
def humanize
|
|
71
|
+
return to_s unless @edtf_value.respond_to?(:humanize)
|
|
72
|
+
@edtf_value.humanize
|
|
73
|
+
rescue
|
|
74
|
+
to_s
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
# Returns true if this is an uncertain date
|
|
79
|
+
#
|
|
80
|
+
# @return [Boolean]
|
|
81
|
+
def uncertain?
|
|
82
|
+
@edtf_value.respond_to?(:uncertain?) && @edtf_value.uncertain?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
# Returns true if this is an approximate date
|
|
87
|
+
#
|
|
88
|
+
# @return [Boolean]
|
|
89
|
+
def approximate?
|
|
90
|
+
@edtf_value.respond_to?(:approximate?) && @edtf_value.approximate?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# Returns true if this is an interval
|
|
95
|
+
#
|
|
96
|
+
# @return [Boolean]
|
|
97
|
+
def interval?
|
|
98
|
+
@edtf_value.is_a?(::EDTF::Interval)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
##
|
|
102
|
+
# Returns true if this is a season
|
|
103
|
+
#
|
|
104
|
+
# @return [Boolean]
|
|
105
|
+
def season?
|
|
106
|
+
@edtf_value.is_a?(::EDTF::Season)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
##
|
|
110
|
+
# Returns true if this is a set
|
|
111
|
+
#
|
|
112
|
+
# @return [Boolean]
|
|
113
|
+
def set?
|
|
114
|
+
@edtf_value.is_a?(::EDTF::Set)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# Parses input value to EDTF object
|
|
121
|
+
#
|
|
122
|
+
# @param [Object] value
|
|
123
|
+
# @return [EDTF::Date, EDTF::Interval, EDTF::Season, EDTF::Set, etc.]
|
|
124
|
+
def parse_edtf(value)
|
|
125
|
+
case value
|
|
126
|
+
when ::EDTF::Interval, ::EDTF::Season, ::EDTF::Set, ::EDTF::Epoch
|
|
127
|
+
value
|
|
128
|
+
when ::Date, ::DateTime, ::Time
|
|
129
|
+
# For Ruby Date/DateTime/Time, try to parse as EDTF
|
|
130
|
+
::Date.edtf(value.to_s) || value
|
|
131
|
+
when String
|
|
132
|
+
# Parse EDTF string
|
|
133
|
+
::Date.edtf(value) || ::EDTF.parse(value)
|
|
134
|
+
else
|
|
135
|
+
::EDTF.parse(value.to_s)
|
|
136
|
+
end
|
|
137
|
+
rescue StandardError => e
|
|
138
|
+
Solis::LOGGER.warn("Failed to parse EDTF value '#{value}': #{e.message}") if defined?(Solis::LOGGER)
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -277,4 +277,91 @@ Graphiti::Types[:array_of_temporal_coverages] = {
|
|
|
277
277
|
write: Dry::Types["strict.array"].of(Graphiti::Types[:temporal_coverage][:write]),
|
|
278
278
|
kind: "array",
|
|
279
279
|
description: "contains a list of temporal coverage"
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
uri_definition = Dry::Types['strict.string']
|
|
283
|
+
read_uri_type = uri_definition.constructor do |i|
|
|
284
|
+
if i.is_a?(RDF::URI)
|
|
285
|
+
i.to_s
|
|
286
|
+
elsif i.is_a?(String)
|
|
287
|
+
i
|
|
288
|
+
else
|
|
289
|
+
i.to_s
|
|
290
|
+
end
|
|
291
|
+
rescue StandardError => e
|
|
292
|
+
Solis::LOGGER.error(e.message)
|
|
293
|
+
raise Solis::Error::InvalidDatatypeError, e.message
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
write_uri_type = uri_definition.constructor do |i|
|
|
297
|
+
i.to_s
|
|
298
|
+
rescue StandardError => e
|
|
299
|
+
Solis::LOGGER.error(e.message)
|
|
300
|
+
raise Solis::Error::InvalidDatatypeError, e.message
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
Graphiti::Types[:anyuri] = {
|
|
304
|
+
canonical_name: :anyuri,
|
|
305
|
+
params: read_uri_type,
|
|
306
|
+
read: read_uri_type,
|
|
307
|
+
write: write_uri_type,
|
|
308
|
+
kind: "scalar",
|
|
309
|
+
description: "contains a URI"
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
Graphiti::Types[:array_of_anyuris] = {
|
|
313
|
+
canonical_name: :anyuri,
|
|
314
|
+
params: Dry::Types["strict.array"].of(Graphiti::Types[:anyuri][:params]),
|
|
315
|
+
read: Dry::Types["strict.array"].of(Graphiti::Types[:anyuri][:read]),
|
|
316
|
+
write: Dry::Types["strict.array"].of(Graphiti::Types[:anyuri][:write]),
|
|
317
|
+
kind: "array",
|
|
318
|
+
description: "contains a list of URIs"
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
edtf_definition = Dry::Types['strict.string']
|
|
322
|
+
read_edtf_type = edtf_definition.constructor do |i|
|
|
323
|
+
if i.respond_to?(:edtf)
|
|
324
|
+
# EDTF object - convert to string representation
|
|
325
|
+
i.edtf
|
|
326
|
+
elsif i.is_a?(RDF::Literal::EDTF)
|
|
327
|
+
# RDF EDTF Literal - get the lexical value
|
|
328
|
+
i.value
|
|
329
|
+
elsif i.is_a?(String)
|
|
330
|
+
# Validate and return as-is
|
|
331
|
+
parsed = Date.edtf(i)
|
|
332
|
+
parsed ? parsed.edtf : i
|
|
333
|
+
else
|
|
334
|
+
i.to_s
|
|
335
|
+
end
|
|
336
|
+
rescue StandardError => e
|
|
337
|
+
Solis::LOGGER.error("EDTF read error: #{e.message}")
|
|
338
|
+
raise Solis::Error::InvalidDatatypeError, e.message
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
write_edtf_type = edtf_definition.constructor do |i|
|
|
342
|
+
# Validate by parsing
|
|
343
|
+
parsed = Date.edtf(i.to_s)
|
|
344
|
+
raise "Invalid EDTF format" unless parsed && parsed.valid?
|
|
345
|
+
parsed.edtf
|
|
346
|
+
rescue StandardError => e
|
|
347
|
+
Solis::LOGGER.error("EDTF write error: #{e.message}")
|
|
348
|
+
raise Solis::Error::InvalidDatatypeError, "Invalid EDTF format: #{e.message}"
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
Graphiti::Types[:edtf] = {
|
|
352
|
+
canonical_name: :edtf,
|
|
353
|
+
params: read_edtf_type,
|
|
354
|
+
read: read_edtf_type,
|
|
355
|
+
write: write_edtf_type,
|
|
356
|
+
kind: "scalar",
|
|
357
|
+
description: "Extended Date/Time Format (EDTF) - supports uncertain, approximate, and interval dates"
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
Graphiti::Types[:array_of_edtfs] = {
|
|
361
|
+
canonical_name: :edtf,
|
|
362
|
+
params: Dry::Types["strict.array"].of(Graphiti::Types[:edtf][:params]),
|
|
363
|
+
read: Dry::Types["strict.array"].of(Graphiti::Types[:edtf][:read]),
|
|
364
|
+
write: Dry::Types["strict.array"].of(Graphiti::Types[:edtf][:write]),
|
|
365
|
+
kind: "array",
|
|
366
|
+
description: "contains a list of EDTF dates"
|
|
280
367
|
}
|
|
@@ -511,6 +511,8 @@ hide empty members
|
|
|
511
511
|
{ "type" => "string", "format" => "date-time" }
|
|
512
512
|
when /anyURI$/
|
|
513
513
|
{ "type" => "string", "format" => "uri" }
|
|
514
|
+
when /datatypes\/edtf/, /edtf$/i
|
|
515
|
+
{ "type" => "string", "format" => "edtf" }
|
|
514
516
|
else
|
|
515
517
|
{ "type" => "string" }
|
|
516
518
|
end
|
data/lib/solis/shape.rb
CHANGED
|
@@ -24,7 +24,7 @@ module Solis
|
|
|
24
24
|
if datatype =~ /^http:\/\/www.w3.org\/2001\/XMLSchema#/
|
|
25
25
|
case datatype
|
|
26
26
|
when /^http:\/\/www.w3.org\/2001\/XMLSchema#anyURI/
|
|
27
|
-
:
|
|
27
|
+
:anyuri
|
|
28
28
|
when /http:\/\/www.w3.org\/2001\/XMLSchema#duration/
|
|
29
29
|
:duration
|
|
30
30
|
when /http:\/\/www.w3.org\/2001\/XMLSchema#integer/
|
|
@@ -72,6 +72,9 @@ module Solis
|
|
|
72
72
|
# normalize ex."https://data.q.odis.be/person#Name" to Name
|
|
73
73
|
#node.value.split('/').last.gsub(/Shape$/, '').split('#').last.to_sym
|
|
74
74
|
#node.value.split('/').last.gsub(/Shape$/, '').gsub('#','').camelize.to_sym
|
|
75
|
+
elsif datatype =~ /datatypes\/edtf/ || datatype =~ /edtf$/i
|
|
76
|
+
# Library of Congress EDTF datatype
|
|
77
|
+
:edtf
|
|
75
78
|
elsif datatype =~ /^http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns/
|
|
76
79
|
case datatype
|
|
77
80
|
when /http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#langString/
|
data/lib/solis/version.rb
CHANGED
data/lib/solis.rb
CHANGED
data/solis.gemspec
CHANGED
|
@@ -43,7 +43,7 @@ Gem::Specification.new do |spec|
|
|
|
43
43
|
spec.add_runtime_dependency 'csv', '~> 3.2'
|
|
44
44
|
spec.add_runtime_dependency 'mutex_m', '~> 0.1'
|
|
45
45
|
spec.add_runtime_dependency 'ostruct', '~> 0.5'
|
|
46
|
-
|
|
46
|
+
spec.add_runtime_dependency 'edtf', '~> 3.0'
|
|
47
47
|
|
|
48
48
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
49
49
|
spec.add_development_dependency 'minitest', '~> 5.19'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.104.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mehmet Celik
|
|
@@ -233,6 +233,20 @@ dependencies:
|
|
|
233
233
|
- - "~>"
|
|
234
234
|
- !ruby/object:Gem::Version
|
|
235
235
|
version: '0.5'
|
|
236
|
+
- !ruby/object:Gem::Dependency
|
|
237
|
+
name: edtf
|
|
238
|
+
requirement: !ruby/object:Gem::Requirement
|
|
239
|
+
requirements:
|
|
240
|
+
- - "~>"
|
|
241
|
+
- !ruby/object:Gem::Version
|
|
242
|
+
version: '3.0'
|
|
243
|
+
type: :runtime
|
|
244
|
+
prerelease: false
|
|
245
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
246
|
+
requirements:
|
|
247
|
+
- - "~>"
|
|
248
|
+
- !ruby/object:Gem::Version
|
|
249
|
+
version: '3.0'
|
|
236
250
|
- !ruby/object:Gem::Dependency
|
|
237
251
|
name: rake
|
|
238
252
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -296,10 +310,12 @@ files:
|
|
|
296
310
|
- lib/solis/model.rb
|
|
297
311
|
- lib/solis/model.rb.ok
|
|
298
312
|
- lib/solis/options.rb
|
|
313
|
+
- lib/solis/overlay_fs.rb
|
|
299
314
|
- lib/solis/query.rb
|
|
300
315
|
- lib/solis/query/construct.rb
|
|
301
316
|
- lib/solis/query/filter.rb
|
|
302
317
|
- lib/solis/query/run.rb
|
|
318
|
+
- lib/solis/rdf_edtf_literal.rb
|
|
303
319
|
- lib/solis/resource.rb
|
|
304
320
|
- lib/solis/shape.rb
|
|
305
321
|
- lib/solis/shape/data_types.rb
|