qa 4.1.1 → 4.2.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/app/controllers/qa/linked_data_terms_controller.rb +4 -0
- data/app/models/qa/linked_data/config/context_property_map.rb +7 -0
- data/app/services/qa/linked_data/ldpath_service.rb +3 -0
- data/app/services/qa/linked_data/mapper/context_mapper_service.rb +4 -0
- data/config/authorities/linked_data/loc.json +17 -18
- data/lib/generators/qa/install/templates/config/initializers/qa.rb +5 -0
- data/lib/qa.rb +3 -0
- data/lib/qa/authorities/linked_data/config/term_config.rb +42 -11
- data/lib/qa/authorities/linked_data/find_term.rb +42 -18
- data/lib/qa/authorities/linked_data/search_query.rb +8 -2
- data/lib/qa/configuration.rb +10 -1
- data/lib/qa/version.rb +1 -1
- data/spec/controllers/linked_data_terms_controller_spec.rb +21 -3
- data/spec/fixtures/lod_loc_term_bad_id.rdf.xml +68 -0
- data/spec/fixtures/lod_oclc_term_bad_id.nt +4 -0
- data/spec/lib/authorities/linked_data/find_term_spec.rb +125 -68
- data/spec/lib/authorities/linked_data/search_query_spec.rb +3 -1
- data/spec/lib/authorities/linked_data/term_config_spec.rb +23 -9
- data/spec/lib/configuration_spec.rb +40 -2
- data/spec/models/linked_data/config/context_property_map_spec.rb +37 -0
- data/spec/services/linked_data/ldpath_service_spec.rb +9 -0
- data/spec/services/linked_data/mapper/context_mapper_service_spec.rb +30 -2
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb0e94ad762c71e5dd0bf2a7b99e03ee71b348e8
|
4
|
+
data.tar.gz: c8d21f4c0379b3035439e39a6b085faa314bf602
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1b33787d92489239f1530cc05b4ea3e912e7ae913ed0197a0fb1e58e13e3bf75a701e3ec5d93a15c49288a3cca0f06647ec11380bb48d3eefb0917d3f594390
|
7
|
+
data.tar.gz: 2a6613d06be5b77c2709bc95d0dfe3d78814c3271e3399578726fe1e9bb2ecd533ae9533cf92e30c02345ff09624c705a8f3895f08986f104dd2baf0124e56b1
|
@@ -80,6 +80,10 @@ class Qa::LinkedDataTermsController < ::ApplicationController
|
|
80
80
|
"was not identified as a valid RDF format. You may need to include the linkeddata gem."
|
81
81
|
logger.warn msg
|
82
82
|
render json: { errors: msg }, status: :internal_server_error
|
83
|
+
rescue Qa::DataNormalizationError => e
|
84
|
+
msg = "Data Normalization Error - #{e.message}"
|
85
|
+
logger.warn msg
|
86
|
+
render json: { errors: msg }, status: :internal_server_error
|
83
87
|
end
|
84
88
|
|
85
89
|
# Return all the information for a given term given a URI
|
@@ -37,6 +37,7 @@ module Qa
|
|
37
37
|
@ldpath = Qa::LinkedData::Config::Helper.fetch_required(property_map, :ldpath, false)
|
38
38
|
@selectable = Qa::LinkedData::Config::Helper.fetch_boolean(property_map, :selectable, false)
|
39
39
|
@drillable = Qa::LinkedData::Config::Helper.fetch_boolean(property_map, :drillable, false)
|
40
|
+
@optional = Qa::LinkedData::Config::Helper.fetch_boolean(property_map, :optional, Qa.config.property_map_default_for_optional)
|
40
41
|
@expansion_label_ldpath = Qa::LinkedData::Config::Helper.fetch(property_map, :expansion_label_ldpath, nil)
|
41
42
|
@expansion_id_ldpath = Qa::LinkedData::Config::Helper.fetch(property_map, :expansion_id_ldpath, nil)
|
42
43
|
@prefixes = prefixes
|
@@ -54,6 +55,12 @@ module Qa
|
|
54
55
|
@drillable
|
55
56
|
end
|
56
57
|
|
58
|
+
# Should this property always be included in the extended context or is it optional (i.e. only shown if it has a value)
|
59
|
+
# @return [Boolean] true if this property is optional and will only be included in extended context if it has a value; otherwise, false
|
60
|
+
def optional?
|
61
|
+
@optional
|
62
|
+
end
|
63
|
+
|
57
64
|
def group?
|
58
65
|
group_id.present?
|
59
66
|
end
|
@@ -6,6 +6,9 @@ module Qa
|
|
6
6
|
class LdpathService
|
7
7
|
VALUE_ON_ERROR = [].freeze
|
8
8
|
|
9
|
+
class_attribute :predefined_prefixes
|
10
|
+
self.predefined_prefixes = Ldpath::Transform.default_prefixes.with_indifferent_access
|
11
|
+
|
9
12
|
# Create the ldpath program for a given ldpath.
|
10
13
|
# @param ldpath [String] ldpath to follow to get a value from a graph (documation: http://marmotta.apache.org/ldpath/language.html)
|
11
14
|
# @param prefixes [Hash] shortcut names for URI prefixes with key = part of predicate that is the same for all terms (e.g. { "madsrdf": "http://www.loc.gov/mads/rdf/v1#" })
|
@@ -37,7 +37,11 @@ module Qa
|
|
37
37
|
values = Qa::LinkedData::Config::ContextPropertyMap::VALUE_ON_ERROR
|
38
38
|
error = e.message
|
39
39
|
end
|
40
|
+
return {} if values.blank? && property_map.optional?
|
41
|
+
property_info(values, error, context_map, property_map)
|
42
|
+
end
|
40
43
|
|
44
|
+
def property_info(values, error, context_map, property_map)
|
41
45
|
property_info = {}
|
42
46
|
property_info["group"] = context_map.group_label(property_map.group_id) if property_map.group?
|
43
47
|
property_info["property"] = property_map.label
|
@@ -1,30 +1,28 @@
|
|
1
1
|
{
|
2
2
|
"QA_CONFIG_VERSION": "2.1",
|
3
3
|
"prefixes": {
|
4
|
-
"loc":
|
5
|
-
"
|
6
|
-
"madsrdf": "http://www.loc.gov/mads/rdf/v1#",
|
7
|
-
"owl": "http://www.w3.org/2002/07/owl#"
|
4
|
+
"loc": "http://id.loc.gov/vocabulary/identifiers/",
|
5
|
+
"madsrdf": "http://www.loc.gov/mads/rdf/v1#"
|
8
6
|
},
|
9
7
|
"term": {
|
10
8
|
"url": {
|
11
9
|
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
|
12
|
-
"@type":
|
10
|
+
"@type": "IriTemplate",
|
13
11
|
"template": "http://id.loc.gov/authorities/{subauth}/{term_id}",
|
14
12
|
"variableRepresentation": "BasicRepresentation",
|
15
13
|
"mapping": [
|
16
14
|
{
|
17
|
-
"@type":
|
15
|
+
"@type": "IriTemplateMapping",
|
18
16
|
"variable": "term_id",
|
19
17
|
"property": "hydra:freetextQuery",
|
20
18
|
"required": true
|
21
19
|
},
|
22
20
|
{
|
23
|
-
"@type":
|
21
|
+
"@type": "IriTemplateMapping",
|
24
22
|
"variable": "subauth",
|
25
23
|
"property": "hydra:freetextQuery",
|
26
24
|
"required": false,
|
27
|
-
"default":
|
25
|
+
"default": "names"
|
28
26
|
}
|
29
27
|
]
|
30
28
|
},
|
@@ -35,20 +33,21 @@
|
|
35
33
|
"term_id": "ID",
|
36
34
|
"language": ["en"],
|
37
35
|
"results": {
|
38
|
-
"id_ldpath":
|
39
|
-
"label_ldpath":
|
36
|
+
"id_ldpath": "loc:lccn | madsrdf:code",
|
37
|
+
"label_ldpath": "skos:prefLabel :: xsd:string",
|
40
38
|
"altlabel_ldpath": "skos:altLabel :: xsd:string",
|
41
|
-
"sameas_ldpath":
|
39
|
+
"sameas_ldpath": "skos:exactMatch | owl:sameAs :: xsd:anyURI",
|
42
40
|
"narrower_ldpath": "madsrdf:hasNarrowerAuthority :: xsd:anyURI",
|
43
|
-
"broader_ldpath":
|
41
|
+
"broader_ldpath": "madsrdf:hasBroaderAuthority :: xsd:anyURI"
|
44
42
|
},
|
45
43
|
"subauthorities": {
|
46
|
-
"subjects":
|
47
|
-
"names":
|
48
|
-
"classification":
|
49
|
-
"child_subject":
|
50
|
-
"genre":
|
51
|
-
"demographic":
|
44
|
+
"subjects": "subjects",
|
45
|
+
"names": "names",
|
46
|
+
"classification": "classification",
|
47
|
+
"child_subject": "childrensSubjects",
|
48
|
+
"genre": "genreForms",
|
49
|
+
"demographic": "demographicTerms",
|
50
|
+
"music_performance": "performanceMediums"
|
52
51
|
}
|
53
52
|
},
|
54
53
|
"search": {}
|
@@ -18,4 +18,9 @@ Qa.config do |config|
|
|
18
18
|
# When true, prevents ldpath requests from making additional network calls. All values will come from the context graph
|
19
19
|
# passed to the ldpath request.
|
20
20
|
# config.limit_ldpath_to_context = true
|
21
|
+
|
22
|
+
# Define default behavior for property_map.optional? when it is not defined in the configuration for a property.
|
23
|
+
# When false, properties that do not override default optional behavior will be shown whether or not the property has a value in the graph.
|
24
|
+
# When true, properties that do not override default optional behavior will not be shown whn the property does not have a value in the graph.
|
25
|
+
# config.property_map_default_for_optional = false
|
21
26
|
end
|
data/lib/qa.rb
CHANGED
@@ -70,13 +70,30 @@ module Qa::Authorities
|
|
70
70
|
Config.config_value(term_results, :id_ldpath)
|
71
71
|
end
|
72
72
|
|
73
|
+
# Return results id_predicates
|
74
|
+
# @return [Array<String>] the configured predicate to use to extract the id from the results
|
75
|
+
def term_results_id_predicates
|
76
|
+
@pred_ids ||=
|
77
|
+
begin
|
78
|
+
pred = Config.predicate_uri(term_results, :id_predicate)
|
79
|
+
pred ? [pred] : id_predicates_from_ldpath
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
73
83
|
# Return results id_predicate
|
74
84
|
# @return [String] the configured predicate to use to extract the id from the results
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
85
|
+
# NOTE: Customizations using this method should be updated to use `term_results_id_predicates` which returns [Array<String>] of
|
86
|
+
# id predicates. This method remains for backward compatibility only but may cause issues if used in places expecting an Array
|
87
|
+
def term_results_id_predicate(suppress_deprecation_warning: false)
|
88
|
+
unless suppress_deprecation_warning
|
89
|
+
Qa.deprecation_warning(
|
90
|
+
in_msg: 'Qa::Authorities::LinkedData::TermConfig',
|
91
|
+
msg: "`term_results_id_predicate` is deprecated; use `term_results_id_ldpath` by updating linked data " \
|
92
|
+
"term config results in authority #{authority_name} to specify as `id_ldpath`"
|
93
|
+
)
|
94
|
+
end
|
95
|
+
id_predicates = term_results_id_predicates
|
96
|
+
id_predicates.first
|
80
97
|
end
|
81
98
|
|
82
99
|
# Return results label_ldpath
|
@@ -222,16 +239,30 @@ module Qa::Authorities
|
|
222
239
|
|
223
240
|
private
|
224
241
|
|
225
|
-
|
226
|
-
|
227
|
-
|
242
|
+
# Parse ldpath into an array of predicates.
|
243
|
+
# Gets ldpath (e.g. 'loc:lccn | madsrdf:code :: xsd:string') using config accessor for results id ldpath.
|
244
|
+
# Multiple paths are delineated by | which is used to split the ldpath into an array of paths.
|
245
|
+
# @return [Array<String>] the predicate for each path in the ldpath
|
246
|
+
def id_predicates_from_ldpath
|
228
247
|
id_ldpath = term_results_id_ldpath
|
229
|
-
return
|
230
|
-
|
248
|
+
return [] if id_ldpath.blank?
|
249
|
+
id_ldpath.split('|').map(&:strip).map do |path|
|
250
|
+
predicate = parse_predicate_from_single_path(path)
|
251
|
+
predicate.present? ? RDF::URI.new(predicate) : nil
|
252
|
+
end.compact
|
253
|
+
end
|
254
|
+
|
255
|
+
# Parse a single path (e.g. 'loc:lccn' where 'loc' is the ontology prefix and 'lccn' is the property name)
|
256
|
+
# Gets prefixes (e.g. { "loc": "http://id.loc.gov/vocabulary/identifiers/", "madsrdf": "http://www.loc.gov/mads/rdf/v1#" }) from authority config
|
257
|
+
# @return [String] the predicate constructed by combining the expanded prefix with the property name
|
258
|
+
def parse_predicate_from_single_path(path)
|
259
|
+
tokens = path.split(':')
|
231
260
|
return nil if tokens.size < 2
|
232
261
|
prefix = tokens.first.to_sym
|
233
262
|
prefix_path = prefixes[prefix]
|
234
|
-
prefix_path
|
263
|
+
prefix_path = Qa::LinkedData::LdpathService.predefined_prefixes[prefix] if prefix_path.blank?
|
264
|
+
raise Qa::InvalidConfiguration, "Prefix '#{prefix}' is not defined in term configuration for authority #{authority_name}" if prefix_path.blank?
|
265
|
+
"#{prefix_path}#{tokens.second.strip}"
|
235
266
|
end
|
236
267
|
|
237
268
|
def summary_without_subauthority(auth_name, language)
|
@@ -15,8 +15,8 @@ module Qa::Authorities
|
|
15
15
|
@term_config = term_config
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :term_config, :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s
|
19
|
-
private :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s
|
18
|
+
attr_reader :term_config, :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
19
|
+
private :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
20
20
|
|
21
21
|
delegate :term_subauthority?, :prefixes, :authority_name, to: :term_config
|
22
22
|
|
@@ -60,6 +60,7 @@ module Qa::Authorities
|
|
60
60
|
|
61
61
|
access_end_dt = Time.now.utc
|
62
62
|
@access_time_s = access_end_dt - access_start_dt
|
63
|
+
@fetched_size = full_graph.triples.to_s.size if performance_data?
|
63
64
|
Rails.logger.info("Time to receive data from authority: #{access_time_s}s")
|
64
65
|
end
|
65
66
|
|
@@ -70,8 +71,9 @@ module Qa::Authorities
|
|
70
71
|
json = perform_normalization
|
71
72
|
|
72
73
|
@normalize_time_s = normalize_end_dt - normalize_start_dt
|
74
|
+
@normalized_size = json.to_s.size if performance_data?
|
73
75
|
Rails.logger.info("Time to convert data to json: #{normalize_time_s}s")
|
74
|
-
json = append_performance_data(json) if performance_data?
|
76
|
+
json = append_performance_data(json) if performance_data?
|
75
77
|
json
|
76
78
|
end
|
77
79
|
|
@@ -108,13 +110,15 @@ module Qa::Authorities
|
|
108
110
|
ldpath_map: ldpaths_for_term, predicate_map: preds_for_term)
|
109
111
|
end
|
110
112
|
|
111
|
-
#
|
113
|
+
# Special processing for loc ids for backward compatibility. IDs may be in the form 'n123' or 'n 123'. URIs do not
|
114
|
+
# have a blank. This removes the <blank> from the ID.
|
112
115
|
def normalize_id
|
113
116
|
return id if expects_uri?
|
114
117
|
loc? ? id.delete(' ') : id
|
115
118
|
end
|
116
119
|
|
117
|
-
#
|
120
|
+
# Special processing for loc ids for backward compatibility. IDs may be in the form 'n123' or 'n 123'. This adds
|
121
|
+
# the <blank> into the ID to allow it to be found as the object of a triple in the graph.
|
118
122
|
def loc_id
|
119
123
|
loc_id = URI.unescape(id)
|
120
124
|
digit_idx = loc_id.index(/\d/)
|
@@ -124,7 +128,7 @@ module Qa::Authorities
|
|
124
128
|
|
125
129
|
# determine if the current authority is LOC which may require special processing of its ids for backward compatibility
|
126
130
|
def loc?
|
127
|
-
|
131
|
+
term_config.url_config.template.starts_with? 'http://id.loc.gov/authorities/'
|
128
132
|
end
|
129
133
|
|
130
134
|
def expects_uri?
|
@@ -133,16 +137,31 @@ module Qa::Authorities
|
|
133
137
|
|
134
138
|
def extract_uri
|
135
139
|
return @uri = RDF::URI.new(id) if expects_uri?
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
@uri = graph_service.subjects_for_object_value(graph: @filtered_graph, predicate: RDF::URI.new(term_config.term_results_id_predicate), object_value: loc_id).first
|
140
|
-
if @uri.present?
|
141
|
-
Qa.deprecation_warning(
|
142
|
-
in_msg: 'Qa::Authorities::LinkedData::FindTerm',
|
143
|
-
msg: 'Special processing of LOC ids is deprecated; id should be an exact match of the id in the graph'
|
144
|
-
)
|
140
|
+
term_config.term_results_id_predicates.each do |id_predicate|
|
141
|
+
extract_uri_by_id(id_predicate)
|
142
|
+
break if @uri.present?
|
145
143
|
end
|
144
|
+
raise Qa::DataNormalizationError, "Unable to extract URI based on ID: #{id}" if @uri.blank?
|
145
|
+
@uri
|
146
|
+
end
|
147
|
+
|
148
|
+
def extract_uri_by_id(id_predicate)
|
149
|
+
@uri = graph_service.subjects_for_object_value(graph: @filtered_graph,
|
150
|
+
predicate: id_predicate,
|
151
|
+
object_value: URI.unescape(id)).first
|
152
|
+
return if @uri.present? || !loc?
|
153
|
+
|
154
|
+
# NOTE: Second call to try and extract using the loc_id allows for special processing on the id for LOC authorities.
|
155
|
+
# LOC URIs do not include a blank (e.g. ends with 'n123'), but the ID in the data might (e.g. 'n 123'). If
|
156
|
+
# the ID is provided without the <blank>, this tries a second time to find it with the <blank>.
|
157
|
+
@uri = graph_service.subjects_for_object_value(graph: @filtered_graph,
|
158
|
+
predicate: id_predicate,
|
159
|
+
object_value: URI.unescape(loc_id)).first
|
160
|
+
return if @uri.blank? # only show the depercation warning if the loc_id was used
|
161
|
+
Qa.deprecation_warning(
|
162
|
+
in_msg: 'Qa::Authorities::LinkedData::FindTerm',
|
163
|
+
msg: 'Special processing of LOC ids is deprecated; id should be an exact match of the id in the graph'
|
164
|
+
)
|
146
165
|
@uri
|
147
166
|
end
|
148
167
|
|
@@ -168,7 +187,7 @@ module Qa::Authorities
|
|
168
187
|
end
|
169
188
|
|
170
189
|
def performance_data?
|
171
|
-
@performance_data == true
|
190
|
+
@performance_data == true && !jsonld?
|
172
191
|
end
|
173
192
|
|
174
193
|
def preds_for_term
|
@@ -181,7 +200,7 @@ module Qa::Authorities
|
|
181
200
|
def optional_preds
|
182
201
|
opt_preds = {}
|
183
202
|
opt_preds[:altlabel] = term_config.term_results_altlabel_predicate
|
184
|
-
opt_preds[:id] = term_config.
|
203
|
+
opt_preds[:id] = term_config.term_results_id_predicates
|
185
204
|
opt_preds[:narrower] = term_config.term_results_narrower_predicate
|
186
205
|
opt_preds[:broader] = term_config.term_results_broader_predicate
|
187
206
|
opt_preds[:sameas] = term_config.term_results_sameas_predicate
|
@@ -240,9 +259,14 @@ module Qa::Authorities
|
|
240
259
|
end
|
241
260
|
|
242
261
|
def append_performance_data(results)
|
243
|
-
|
262
|
+
pred_count = results['predicates'].present? ? results['predicates'].size : 0
|
263
|
+
performance = { predicate_count: pred_count,
|
244
264
|
fetch_time_s: access_time_s,
|
245
265
|
normalization_time_s: normalize_time_s,
|
266
|
+
fetched_bytes: fetched_size,
|
267
|
+
normalized_bytes: normalized_size,
|
268
|
+
fetch_bytes_per_s: fetched_size / access_time_s,
|
269
|
+
normalization_bytes_per_s: normalized_size / normalize_time_s,
|
246
270
|
total_time_s: (access_time_s + normalize_time_s) }
|
247
271
|
{ performance: performance, results: results }
|
248
272
|
end
|
@@ -15,8 +15,8 @@ module Qa::Authorities
|
|
15
15
|
@search_config = search_config
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :search_config, :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s
|
19
|
-
private :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s
|
18
|
+
attr_reader :search_config, :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
19
|
+
private :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
20
20
|
|
21
21
|
delegate :subauthority?, :supports_sort?, :prefixes, :authority_name, to: :search_config
|
22
22
|
|
@@ -52,6 +52,7 @@ module Qa::Authorities
|
|
52
52
|
|
53
53
|
access_end_dt = Time.now.utc
|
54
54
|
@access_time_s = access_end_dt - access_start_dt
|
55
|
+
@fetched_size = full_graph.triples.to_s.size if performance_data?
|
55
56
|
Rails.logger.info("Time to receive data from authority: #{access_time_s}s")
|
56
57
|
end
|
57
58
|
|
@@ -64,6 +65,7 @@ module Qa::Authorities
|
|
64
65
|
|
65
66
|
normalize_end_dt = Time.now.utc
|
66
67
|
@normalize_time_s = normalize_end_dt - normalize_start_dt
|
68
|
+
@normalized_size = json.to_s.size if performance_data?
|
67
69
|
Rails.logger.info("Time to convert data to json: #{normalize_time_s}s")
|
68
70
|
json = append_performance_data(json) if performance_data?
|
69
71
|
json
|
@@ -171,6 +173,10 @@ module Qa::Authorities
|
|
171
173
|
performance = { result_count: results.size,
|
172
174
|
fetch_time_s: access_time_s,
|
173
175
|
normalization_time_s: normalize_time_s,
|
176
|
+
fetched_bytes: fetched_size,
|
177
|
+
normalized_bytes: normalized_size,
|
178
|
+
fetch_bytes_per_s: fetched_size / access_time_s,
|
179
|
+
normalization_bytes_per_s: normalized_size / normalize_time_s,
|
174
180
|
total_time_s: (access_time_s + normalize_time_s) }
|
175
181
|
{ performance: performance, results: results }
|
176
182
|
end
|
data/lib/qa/configuration.rb
CHANGED
@@ -42,8 +42,17 @@ module Qa
|
|
42
42
|
# passed to the ldpath request.
|
43
43
|
attr_writer :limit_ldpath_to_context
|
44
44
|
def limit_ldpath_to_context?
|
45
|
-
|
45
|
+
@limit_ldpath_to_context = true if @limit_ldpath_to_context.nil?
|
46
46
|
@limit_ldpath_to_context
|
47
47
|
end
|
48
|
+
|
49
|
+
# Define default behavior for property_map.optional? when it is not defined in the configuration for a property.
|
50
|
+
# When false, properties that do not override default optional behavior will be shown whether or not the property has a value in the graph.
|
51
|
+
# When true, properties that do not override default optional behavior will not be shown whn the property does not have a value in the graph.
|
52
|
+
attr_writer :property_map_default_for_optional
|
53
|
+
def property_map_default_for_optional
|
54
|
+
@property_map_default_for_optional = false if @property_map_default_for_optional.nil?
|
55
|
+
@property_map_default_for_optional
|
56
|
+
end
|
48
57
|
end
|
49
58
|
end
|
data/lib/qa/version.rb
CHANGED
@@ -307,7 +307,9 @@ describe Qa::LinkedDataTermsController, type: :controller do
|
|
307
307
|
results = JSON.parse(response.body)
|
308
308
|
expect(results).to be_kind_of Hash
|
309
309
|
expect(results.keys).to match_array ['performance', 'results']
|
310
|
-
expect(results['performance'].keys).to match_array ['result_count', 'fetch_time_s', 'normalization_time_s',
|
310
|
+
expect(results['performance'].keys).to match_array ['result_count', 'fetch_time_s', 'normalization_time_s',
|
311
|
+
'fetched_bytes', 'normalized_bytes', 'fetch_bytes_per_s',
|
312
|
+
'normalization_bytes_per_s', 'total_time_s']
|
311
313
|
expect(results['performance']['total_time_s']).to eq results['performance']['fetch_time_s'] + results['performance']['normalization_time_s']
|
312
314
|
expect(results['performance']['result_count']).to eq 3
|
313
315
|
expect(results['results'].count).to eq 3
|
@@ -336,6 +338,18 @@ describe Qa::LinkedDataTermsController, type: :controller do
|
|
336
338
|
end
|
337
339
|
end
|
338
340
|
|
341
|
+
context 'when data normalization error' do
|
342
|
+
before do
|
343
|
+
stub_request(:get, 'http://id.worldcat.org/fast/530369')
|
344
|
+
.to_return(status: 200, body: webmock_fixture('lod_oclc_term_bad_id.nt'), headers: { 'Content-Type' => 'application/ntriples' })
|
345
|
+
end
|
346
|
+
it 'returns 500' do
|
347
|
+
expect(Rails.logger).to receive(:warn).with("Data Normalization Error - Unable to extract URI based on ID: 530369")
|
348
|
+
get :show, params: { id: '530369', vocab: 'OCLC_FAST' }
|
349
|
+
expect(response.code).to eq('500')
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
339
353
|
context 'when rdf format error' do
|
340
354
|
before do
|
341
355
|
stub_request(:get, 'http://id.worldcat.org/fast/530369').to_return(status: 200)
|
@@ -463,7 +477,9 @@ describe Qa::LinkedDataTermsController, type: :controller do
|
|
463
477
|
results = JSON.parse(response.body)
|
464
478
|
expect(results).to be_kind_of Hash
|
465
479
|
expect(results.keys).to match_array ['performance', 'results']
|
466
|
-
expect(results['performance'].keys).to match_array ['predicate_count', 'fetch_time_s', 'normalization_time_s',
|
480
|
+
expect(results['performance'].keys).to match_array ['predicate_count', 'fetch_time_s', 'normalization_time_s',
|
481
|
+
'fetched_bytes', 'normalized_bytes', 'fetch_bytes_per_s',
|
482
|
+
'normalization_bytes_per_s', 'total_time_s']
|
467
483
|
expect(results['performance']['total_time_s']).to eq results['performance']['fetch_time_s'] + results['performance']['normalization_time_s']
|
468
484
|
expect(results['performance']['predicate_count']).to eq 15
|
469
485
|
expect(results['results']['predicates'].count).to eq 15
|
@@ -619,7 +635,9 @@ describe Qa::LinkedDataTermsController, type: :controller do
|
|
619
635
|
results = JSON.parse(response.body)
|
620
636
|
expect(results).to be_kind_of Hash
|
621
637
|
expect(results.keys).to match_array ['performance', 'results']
|
622
|
-
expect(results['performance'].keys).to match_array ['predicate_count', 'fetch_time_s', 'normalization_time_s',
|
638
|
+
expect(results['performance'].keys).to match_array ['predicate_count', 'fetch_time_s', 'normalization_time_s',
|
639
|
+
'fetched_bytes', 'normalized_bytes', 'fetch_bytes_per_s',
|
640
|
+
'normalization_bytes_per_s', 'total_time_s']
|
623
641
|
expect(results['performance']['total_time_s']).to eq results['performance']['fetch_time_s'] + results['performance']['normalization_time_s']
|
624
642
|
expect(results['performance']['predicate_count']).to eq 7
|
625
643
|
expect(results['results']['predicates'].count).to eq 7
|
@@ -0,0 +1,68 @@
|
|
1
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
2
|
+
<madsrdf:Topic rdf:about="http://id.loc.gov/authorities/subjects/sh1234" xmlns:madsrdf="http://www.loc.gov/mads/rdf/v1#">
|
3
|
+
<rdf:type rdf:resource="http://www.loc.gov/mads/rdf/v1#Authority"/>
|
4
|
+
<madsrdf:authoritativeLabel xml:lang="en">More Science</madsrdf:authoritativeLabel>
|
5
|
+
<madsrdf:elementList rdf:parseType="Collection">
|
6
|
+
<madsrdf:TopicElement>
|
7
|
+
<madsrdf:elementValue xml:lang="en">More Science</madsrdf:elementValue>
|
8
|
+
</madsrdf:TopicElement>
|
9
|
+
</madsrdf:elementList>
|
10
|
+
<madsrdf:hasVariant>
|
11
|
+
<madsrdf:Topic>
|
12
|
+
<rdf:type rdf:resource="http://www.loc.gov/mads/rdf/v1#Variant"/>
|
13
|
+
<madsrdf:variantLabel xml:lang="en">More Natural science</madsrdf:variantLabel>
|
14
|
+
<madsrdf:elementList rdf:parseType="Collection">
|
15
|
+
<madsrdf:TopicElement>
|
16
|
+
<madsrdf:elementValue xml:lang="en">More Natural science</madsrdf:elementValue>
|
17
|
+
</madsrdf:TopicElement>
|
18
|
+
</madsrdf:elementList>
|
19
|
+
</madsrdf:Topic>
|
20
|
+
</madsrdf:hasVariant>
|
21
|
+
<madsrdf:hasVariant>
|
22
|
+
<madsrdf:Topic>
|
23
|
+
<rdf:type rdf:resource="http://www.loc.gov/mads/rdf/v1#Variant"/>
|
24
|
+
<madsrdf:variantLabel xml:lang="en">More Science of science</madsrdf:variantLabel>
|
25
|
+
<madsrdf:elementList rdf:parseType="Collection">
|
26
|
+
<madsrdf:TopicElement>
|
27
|
+
<madsrdf:elementValue xml:lang="en">More Science of science</madsrdf:elementValue>
|
28
|
+
</madsrdf:TopicElement>
|
29
|
+
</madsrdf:elementList>
|
30
|
+
</madsrdf:Topic>
|
31
|
+
</madsrdf:hasVariant>
|
32
|
+
<madsrdf:hasVariant>
|
33
|
+
<madsrdf:Topic>
|
34
|
+
<rdf:type rdf:resource="http://www.loc.gov/mads/rdf/v1#Variant"/>
|
35
|
+
<madsrdf:variantLabel xml:lang="en">More Sciences</madsrdf:variantLabel>
|
36
|
+
<madsrdf:elementList rdf:parseType="Collection">
|
37
|
+
<madsrdf:TopicElement>
|
38
|
+
<madsrdf:elementValue xml:lang="en">More Sciences</madsrdf:elementValue>
|
39
|
+
</madsrdf:TopicElement>
|
40
|
+
</madsrdf:elementList>
|
41
|
+
</madsrdf:Topic>
|
42
|
+
</madsrdf:hasVariant>
|
43
|
+
<identifiers:lccn xmlns:identifiers="http://id.loc.gov/vocabulary/identifiers/">BAD ID sh 1234</identifiers:lccn>
|
44
|
+
<rdf:type rdf:resource="http://www.w3.org/2004/02/skos/core#Concept"/>
|
45
|
+
<skos:prefLabel xml:lang="en" xmlns:skos="http://www.w3.org/2004/02/skos/core#">More Science</skos:prefLabel>
|
46
|
+
<skosxl:altLabel xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#">
|
47
|
+
<rdf:Description>
|
48
|
+
<rdf:type rdf:resource="http://www.w3.org/2008/05/skos-xl#Label"/>
|
49
|
+
<skosxl:literalForm xml:lang="en">More Natural science</skosxl:literalForm>
|
50
|
+
</rdf:Description>
|
51
|
+
</skosxl:altLabel>
|
52
|
+
<skosxl:altLabel xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#">
|
53
|
+
<rdf:Description>
|
54
|
+
<rdf:type rdf:resource="http://www.w3.org/2008/05/skos-xl#Label"/>
|
55
|
+
<skosxl:literalForm xml:lang="en">More Science of science</skosxl:literalForm>
|
56
|
+
</rdf:Description>
|
57
|
+
</skosxl:altLabel>
|
58
|
+
<skosxl:altLabel xmlns:skosxl="http://www.w3.org/2008/05/skos-xl#">
|
59
|
+
<rdf:Description>
|
60
|
+
<rdf:type rdf:resource="http://www.w3.org/2008/05/skos-xl#Label"/>
|
61
|
+
<skosxl:literalForm xml:lang="en">More Sciences</skosxl:literalForm>
|
62
|
+
</rdf:Description>
|
63
|
+
</skosxl:altLabel>
|
64
|
+
<skos:altLabel xml:lang="en" xmlns:skos="http://www.w3.org/2004/02/skos/core#">More Natural science</skos:altLabel>
|
65
|
+
<skos:altLabel xml:lang="en" xmlns:skos="http://www.w3.org/2004/02/skos/core#">More Science of science</skos:altLabel>
|
66
|
+
<skos:altLabel xml:lang="en" xmlns:skos="http://www.w3.org/2004/02/skos/core#">More Sciences</skos:altLabel>
|
67
|
+
</madsrdf:Topic>
|
68
|
+
</rdf:RDF>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<http://id.worldcat.org/fast/530369> <http://purl.org/dc/terms/identifier> "BAD_ID 530369" .
|
2
|
+
<http://id.worldcat.org/fast/530369> <http://www.w3.org/2004/02/skos/core#prefLabel> "Cornell University" .
|
3
|
+
<http://id.worldcat.org/fast/530369> <http://www.w3.org/2004/02/skos/core#altLabel> "Ithaca (N.Y.). Cornell University" .
|
4
|
+
<http://id.worldcat.org/fast/530369> <http://www.w3.org/2004/02/skos/core#sameAs> <http://id.loc.gov/authorities/names/n79021621> .
|
@@ -28,7 +28,9 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
28
28
|
end
|
29
29
|
it 'includes performance in return hash' do
|
30
30
|
expect(results.keys).to match_array [:performance, :results]
|
31
|
-
expect(results[:performance].keys).to match_array [:predicate_count, :fetch_time_s, :normalization_time_s,
|
31
|
+
expect(results[:performance].keys).to match_array [:predicate_count, :fetch_time_s, :normalization_time_s,
|
32
|
+
:fetched_bytes, :normalized_bytes, :fetch_bytes_per_s,
|
33
|
+
:normalization_bytes_per_s, :total_time_s]
|
32
34
|
expect(results[:performance][:predicate_count]).to eq 7
|
33
35
|
expect(results[:performance][:total_time_s]).to eq results[:performance][:fetch_time_s] + results[:performance][:normalization_time_s]
|
34
36
|
end
|
@@ -90,90 +92,145 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
90
92
|
.to include('Cornell University', 'Ithaca (N.Y.). Cornell University', "Kornel\\xCA\\xB9skii universitet",
|
91
93
|
"K\\xCA\\xBBang-nai-erh ta hs\\xC3\\xBCeh")
|
92
94
|
end
|
95
|
+
|
96
|
+
context "ID in graph doesn't match ID in request URI" do
|
97
|
+
before do
|
98
|
+
stub_request(:get, 'http://id.worldcat.org/fast/530369')
|
99
|
+
.to_return(status: 200, body: webmock_fixture('lod_oclc_term_bad_id.nt'), headers: { 'Content-Type' => 'application/ntriples' })
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'raises DataNormalizationError' do
|
103
|
+
expect { lod_oclc.find('530369') }.to raise_error Qa::DataNormalizationError, "Unable to extract URI based on ID: 530369"
|
104
|
+
end
|
105
|
+
end
|
93
106
|
end
|
94
107
|
end
|
95
108
|
|
96
109
|
context 'in LOC authority' do
|
97
110
|
context 'term found' do
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
111
|
+
context 'when id requires special processing for <blank> in id' do
|
112
|
+
before do
|
113
|
+
stub_request(:get, 'http://id.loc.gov/authorities/subjects/sh85118553')
|
114
|
+
.to_return(status: 200, body: webmock_fixture('lod_loc_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
115
|
+
end
|
104
116
|
|
105
|
-
|
106
|
-
let(:second_results) { lod_loc.find('sh 1234', subauth: 'subjects') }
|
107
|
-
let(:results_without_blank) { lod_loc.find('sh85118553', subauth: 'subjects') }
|
117
|
+
let(:results) { lod_loc.find('sh 85118553', subauth: 'subjects') }
|
108
118
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
119
|
+
it 'has correct primary predicate values' do
|
120
|
+
expect(results[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
121
|
+
expect(results[:uri]).to be_kind_of String
|
122
|
+
expect(results[:id]).to eq 'sh 85118553'
|
123
|
+
expect(results[:label]).to eq ['Science']
|
124
|
+
expect(results[:altlabel]).to include('Natural science', 'Science of science', 'Sciences')
|
125
|
+
expect(results[:narrower]).to include('http://id.loc.gov/authorities/subjects/sh92004048')
|
126
|
+
expect(results[:narrower].first).to be_kind_of String
|
127
|
+
end
|
118
128
|
|
119
|
-
|
120
|
-
|
121
|
-
|
129
|
+
it 'has correct number of predicates in pred-obj list' do
|
130
|
+
expect(results['predicates'].count).to eq 15
|
131
|
+
end
|
122
132
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
133
|
+
it 'has primary predicates in pred-obj list' do
|
134
|
+
expect(results['predicates']['http://id.loc.gov/vocabulary/identifiers/lccn']).to eq ['sh 85118553']
|
135
|
+
expect(results['predicates']['http://www.loc.gov/mads/rdf/v1#authoritativeLabel']).to eq ['Science']
|
136
|
+
expect(results['predicates']['http://www.w3.org/2004/02/skos/core#prefLabel']).to eq ['Science']
|
137
|
+
expect(results['predicates']['http://www.w3.org/2004/02/skos/core#altLabel']).to include('Natural science', 'Science of science', 'Sciences')
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'has loc mads predicate values' do
|
141
|
+
expect(results['predicates']['http://www.loc.gov/mads/rdf/v1#classification']).to eq ['Q']
|
142
|
+
expect(results['predicates']['http://www.loc.gov/mads/rdf/v1#isMemberOfMADSCollection'])
|
143
|
+
.to include('http://id.loc.gov/authorities/subjects/collection_LCSHAuthorizedHeadings',
|
144
|
+
'http://id.loc.gov/authorities/subjects/collection_LCSH_General',
|
145
|
+
'http://id.loc.gov/authorities/subjects/collection_SubdivideGeographically')
|
146
|
+
expect(results['predicates']['http://www.loc.gov/mads/rdf/v1#hasCloseExternalAuthority'])
|
147
|
+
.to include('http://data.bnf.fr/ark:/12148/cb12321484k', 'http://data.bnf.fr/ark:/12148/cb119673416',
|
148
|
+
'http://data.bnf.fr/ark:/12148/cb119934236', 'http://data.bnf.fr/ark:/12148/cb12062047t',
|
149
|
+
'http://data.bnf.fr/ark:/12148/cb119469567', 'http://data.bnf.fr/ark:/12148/cb11933232c',
|
150
|
+
'http://data.bnf.fr/ark:/12148/cb122890536', 'http://data.bnf.fr/ark:/12148/cb121155321',
|
151
|
+
'http://data.bnf.fr/ark:/12148/cb15556043g', 'http://data.bnf.fr/ark:/12148/cb123662513',
|
152
|
+
'http://d-nb.info/gnd/4066562-8', 'http://data.bnf.fr/ark:/12148/cb120745812',
|
153
|
+
'http://data.bnf.fr/ark:/12148/cb11973101n', 'http://data.bnf.fr/ark:/12148/cb13328497r')
|
154
|
+
expect(results['predicates']['http://www.loc.gov/mads/rdf/v1#isMemberOfMADSScheme'])
|
155
|
+
.to eq ['http://id.loc.gov/authorities/subjects']
|
156
|
+
expect(results['predicates']['http://www.loc.gov/mads/rdf/v1#editorialNote'])
|
157
|
+
.to eq ['headings beginning with the word [Scientific;] and subdivision [Science] under ethnic groups and individual wars, e.g. [World War, 1939-1945--Science]']
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'has more unspecified predicate values' do
|
161
|
+
expect(results['predicates']['http://www.w3.org/1999/02/22-rdf-syntax-ns#type']).to include('http://www.loc.gov/mads/rdf/v1#Topic', 'http://www.loc.gov/mads/rdf/v1#Authority', 'http://www.w3.org/2004/02/skos/core#Concept')
|
162
|
+
expect(results['predicates']['http://www.w3.org/2002/07/owl#sameAs']).to include('info:lc/authorities/sh85118553', 'http://id.loc.gov/authorities/sh85118553#concept')
|
163
|
+
expect(results['predicates']['http://www.w3.org/2004/02/skos/core#closeMatch'])
|
164
|
+
.to include('http://data.bnf.fr/ark:/12148/cb12321484k', 'http://data.bnf.fr/ark:/12148/cb119673416',
|
165
|
+
'http://data.bnf.fr/ark:/12148/cb119934236', 'http://data.bnf.fr/ark:/12148/cb12062047t',
|
166
|
+
'http://data.bnf.fr/ark:/12148/cb119469567', 'http://data.bnf.fr/ark:/12148/cb11933232c',
|
167
|
+
'http://data.bnf.fr/ark:/12148/cb122890536', 'http://data.bnf.fr/ark:/12148/cb121155321',
|
168
|
+
'http://data.bnf.fr/ark:/12148/cb15556043g', 'http://data.bnf.fr/ark:/12148/cb123662513',
|
169
|
+
'http://d-nb.info/gnd/4066562-8', 'http://data.bnf.fr/ark:/12148/cb120745812',
|
170
|
+
'http://data.bnf.fr/ark:/12148/cb11973101n', 'http://data.bnf.fr/ark:/12148/cb13328497r')
|
171
|
+
expect(results['predicates']['http://www.w3.org/2004/02/skos/core#editorial'])
|
172
|
+
.to eq ['headings beginning with the word [Scientific;] and subdivision [Science] under ethnic groups and individual wars, e.g. [World War, 1939-1945--Science]']
|
173
|
+
expect(results['predicates']['http://www.w3.org/2004/02/skos/core#inScheme']).to eq ['http://id.loc.gov/authorities/subjects']
|
174
|
+
end
|
128
175
|
end
|
129
176
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
.to eq
|
146
|
-
|
147
|
-
.to
|
177
|
+
context 'when multiple requests are made' do
|
178
|
+
before do
|
179
|
+
stub_request(:get, 'http://id.loc.gov/authorities/subjects/sh85118553')
|
180
|
+
.to_return(status: 200, body: webmock_fixture('lod_loc_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
181
|
+
stub_request(:get, 'http://id.loc.gov/authorities/subjects/sh1234')
|
182
|
+
.to_return(status: 200, body: webmock_fixture('lod_loc_second_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
183
|
+
end
|
184
|
+
|
185
|
+
let(:results) { lod_loc.find('sh 85118553', subauth: 'subjects') }
|
186
|
+
let(:second_results) { lod_loc.find('sh 1234', subauth: 'subjects') }
|
187
|
+
|
188
|
+
it 'has correct primary predicate values for second request' do
|
189
|
+
expect(results[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
190
|
+
expect(second_results[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh1234'
|
191
|
+
expect(second_results[:uri]).to be_kind_of String
|
192
|
+
expect(second_results[:id]).to eq 'sh 1234'
|
193
|
+
expect(second_results[:label]).to eq ['More Science']
|
194
|
+
expect(second_results[:altlabel]).to include('More Natural science', 'More Science of science', 'More Sciences')
|
195
|
+
end
|
148
196
|
end
|
149
197
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
expect(results['predicates']['http://www.w3.org/2004/02/skos/core#editorial'])
|
162
|
-
.to eq ['headings beginning with the word [Scientific;] and subdivision [Science] under ethnic groups and individual wars, e.g. [World War, 1939-1945--Science]']
|
163
|
-
expect(results['predicates']['http://www.w3.org/2004/02/skos/core#inScheme']).to eq ['http://id.loc.gov/authorities/subjects']
|
198
|
+
context 'when id does not have a <blank>' do
|
199
|
+
before do
|
200
|
+
stub_request(:get, 'http://id.loc.gov/authorities/subjects/sh85118553')
|
201
|
+
.to_return(status: 200, body: webmock_fixture('lod_loc_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
202
|
+
end
|
203
|
+
|
204
|
+
let(:results_without_blank) { lod_loc.find('sh85118553', subauth: 'subjects') }
|
205
|
+
|
206
|
+
it 'extracts correct uri' do
|
207
|
+
expect(results_without_blank[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
208
|
+
end
|
164
209
|
end
|
165
210
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
211
|
+
context "ID in graph doesn't match ID in request URI" do
|
212
|
+
before do
|
213
|
+
stub_request(:get, 'http://id.loc.gov/authorities/subjects/sh85118553')
|
214
|
+
.to_return(status: 200, body: webmock_fixture('lod_loc_term_bad_id.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'raises DataNormalizationError' do
|
218
|
+
expect { lod_loc.find('sh85118553', subauth: 'subjects') }.to raise_error Qa::DataNormalizationError, "Unable to extract URI based on ID: sh85118553"
|
219
|
+
end
|
173
220
|
end
|
174
221
|
|
175
|
-
|
176
|
-
|
222
|
+
context 'when alternate authority name is used to access loc' do
|
223
|
+
before do
|
224
|
+
stub_request(:get, 'http://id.loc.gov/authorities/subjects/sh85118553')
|
225
|
+
.to_return(status: 200, body: webmock_fixture('lod_loc_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
226
|
+
allow(lod_loc.term_config).to receive(:authority_name).and_return('ALT_LOC_AUTHORITY')
|
227
|
+
end
|
228
|
+
|
229
|
+
let(:results) { lod_loc.find('sh 85118553', subauth: 'subjects') }
|
230
|
+
|
231
|
+
it 'does special processing to remove blank from id' do
|
232
|
+
expect(results[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
233
|
+
end
|
177
234
|
end
|
178
235
|
end
|
179
236
|
end
|
@@ -16,7 +16,9 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
16
16
|
it 'includes performance in return hash' do
|
17
17
|
expect(results).to be_kind_of Hash
|
18
18
|
expect(results.keys).to match_array [:performance, :results]
|
19
|
-
expect(results[:performance].keys).to match_array [:result_count, :fetch_time_s, :normalization_time_s,
|
19
|
+
expect(results[:performance].keys).to match_array [:result_count, :fetch_time_s, :normalization_time_s,
|
20
|
+
:fetched_bytes, :normalized_bytes, :fetch_bytes_per_s,
|
21
|
+
:normalization_bytes_per_s, :total_time_s]
|
20
22
|
expect(results[:performance][:total_time_s]).to eq results[:performance][:fetch_time_s] + results[:performance][:normalization_time_s]
|
21
23
|
expect(results[:performance][:result_count]).to eq 3
|
22
24
|
expect(results[:results].count).to eq 3
|
@@ -6,6 +6,7 @@ describe Qa::Authorities::LinkedData::TermConfig do
|
|
6
6
|
let(:min_config) { Qa::Authorities::LinkedData::Config.new(:LOD_MIN_CONFIG).term }
|
7
7
|
let(:search_only_config) { Qa::Authorities::LinkedData::Config.new(:LOD_SEARCH_ONLY_CONFIG).term }
|
8
8
|
let(:encoding_config) { Qa::Authorities::LinkedData::Config.new(:LOD_ENCODING_CONFIG).term }
|
9
|
+
let(:loc_config) { Qa::Authorities::LinkedData::Config.new(:LOC).term }
|
9
10
|
|
10
11
|
let(:ldpath_results_config) do
|
11
12
|
{
|
@@ -201,17 +202,30 @@ describe Qa::Authorities::LinkedData::TermConfig do
|
|
201
202
|
it 'returns nil if only search configuration is defined' do
|
202
203
|
expect(search_only_config.term_results).to eq nil
|
203
204
|
end
|
204
|
-
it 'returns hash of predicates' do
|
205
|
+
it 'returns hash of predicates or ldpaths' do
|
205
206
|
expect(full_config.term_results).to eq results_config
|
206
207
|
end
|
207
208
|
end
|
208
209
|
|
209
|
-
describe '#
|
210
|
+
describe '#term_results_id_predicates' do
|
210
211
|
it 'returns nil if only search configuration is defined' do
|
211
|
-
expect(search_only_config.
|
212
|
+
expect(search_only_config.term_results_id_predicates).to eq []
|
212
213
|
end
|
213
|
-
it 'returns
|
214
|
-
expect(full_config.
|
214
|
+
it 'returns array of one predicates when only one defined' do
|
215
|
+
expect(full_config.term_results_id_predicates).to eq [RDF::URI('http://purl.org/dc/terms/identifier')]
|
216
|
+
end
|
217
|
+
it 'returns array of multiple predicates when ldpath specifies more than one path' do
|
218
|
+
expect(loc_config.term_results_id_predicates).to match_array [RDF::URI('http://id.loc.gov/vocabulary/identifiers/lccn'),
|
219
|
+
RDF::URI('http://www.loc.gov/mads/rdf/v1#code')]
|
220
|
+
end
|
221
|
+
it 'returns array of predicates when prefix is one of the ldpath gem predefined prefixes' do
|
222
|
+
allow(full_config).to receive(:prefixes).and_return({})
|
223
|
+
allow(full_config).to receive(:term_results).and_return(id_ldpath: 'dc:identifier')
|
224
|
+
expect(full_config.term_results_id_predicates).to eq [RDF::URI('http://purl.org/dc/elements/1.1/identifier')]
|
225
|
+
end
|
226
|
+
it 'raises an error if predicate prefix is not defined' do
|
227
|
+
allow(loc_config).to receive(:prefixes).and_return({})
|
228
|
+
expect { loc_config.term_results_id_predicates }.to raise_error Qa::InvalidConfiguration, "Prefix 'loc' is not defined in term configuration for authority LOC"
|
215
229
|
end
|
216
230
|
end
|
217
231
|
|
@@ -266,7 +280,7 @@ describe Qa::Authorities::LinkedData::TermConfig do
|
|
266
280
|
it 'returns nil if only search configuration is defined' do
|
267
281
|
expect(search_only_config.term_results_altlabel_ldpath).to eq nil
|
268
282
|
end
|
269
|
-
it 'return nil if altlabel
|
283
|
+
it 'return nil if altlabel ldpath is not defined' do
|
270
284
|
expect(min_config.term_results_altlabel_ldpath).to eq nil
|
271
285
|
end
|
272
286
|
|
@@ -294,7 +308,7 @@ describe Qa::Authorities::LinkedData::TermConfig do
|
|
294
308
|
it 'returns nil if only search configuration is defined' do
|
295
309
|
expect(search_only_config.term_results_broader_ldpath).to eq nil
|
296
310
|
end
|
297
|
-
it 'return nil if broader
|
311
|
+
it 'return nil if broader ldpath is not defined' do
|
298
312
|
expect(min_config.term_results_broader_ldpath).to eq nil
|
299
313
|
end
|
300
314
|
|
@@ -322,7 +336,7 @@ describe Qa::Authorities::LinkedData::TermConfig do
|
|
322
336
|
it 'returns nil if only search configuration is defined' do
|
323
337
|
expect(search_only_config.term_results_narrower_ldpath).to eq nil
|
324
338
|
end
|
325
|
-
it 'return nil if narrower
|
339
|
+
it 'return nil if narrower ldpath is not defined' do
|
326
340
|
expect(min_config.term_results_narrower_ldpath).to eq nil
|
327
341
|
end
|
328
342
|
|
@@ -350,7 +364,7 @@ describe Qa::Authorities::LinkedData::TermConfig do
|
|
350
364
|
it 'returns nil if only search configuration is defined' do
|
351
365
|
expect(search_only_config.term_results_sameas_ldpath).to eq nil
|
352
366
|
end
|
353
|
-
it 'return nil if sameas
|
367
|
+
it 'return nil if sameas ldpath is not defined' do
|
354
368
|
expect(min_config.term_results_sameas_ldpath).to eq nil
|
355
369
|
end
|
356
370
|
|
@@ -76,14 +76,52 @@ RSpec.describe Qa::Configuration do
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
context 'when configured' do
|
79
|
+
context 'when configured as true' do
|
80
|
+
before do
|
81
|
+
subject.limit_ldpath_to_context = true
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'returns true' do
|
85
|
+
expect(subject.limit_ldpath_to_context?).to be true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when configured as false' do
|
80
90
|
before do
|
81
91
|
subject.limit_ldpath_to_context = false
|
82
92
|
end
|
83
93
|
|
84
|
-
it 'returns
|
94
|
+
it 'returns false' do
|
85
95
|
expect(subject.limit_ldpath_to_context?).to be false
|
86
96
|
end
|
87
97
|
end
|
88
98
|
end
|
99
|
+
|
100
|
+
describe '#property_map_default_for_optional' do
|
101
|
+
context 'when NOT configured' do
|
102
|
+
it 'returns false' do
|
103
|
+
expect(subject.property_map_default_for_optional).to be false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when configured as true' do
|
108
|
+
before do
|
109
|
+
subject.property_map_default_for_optional = true
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'returns the true' do
|
113
|
+
expect(subject.property_map_default_for_optional).to be true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when configured as false' do
|
118
|
+
before do
|
119
|
+
subject.property_map_default_for_optional = false
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns false' do
|
123
|
+
expect(subject.property_map_default_for_optional).to be false
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
89
127
|
end
|
@@ -109,6 +109,43 @@ RSpec.describe Qa::LinkedData::Config::ContextPropertyMap do
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
+
describe '#optional?' do
|
113
|
+
context 'when map has optional: true' do
|
114
|
+
before { property_map[:optional] = true }
|
115
|
+
|
116
|
+
it 'returns true' do
|
117
|
+
expect(subject.optional?).to be true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when map has optional: false' do
|
122
|
+
before { property_map[:optional] = false }
|
123
|
+
|
124
|
+
it 'returns false' do
|
125
|
+
expect(subject.optional?).to be false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when optional: is not defined in the map' do
|
130
|
+
before { property_map.delete(:optional) }
|
131
|
+
|
132
|
+
context 'and property_map_default_for_optional is true' do
|
133
|
+
before { allow(Qa.config).to receive(:property_map_default_for_optional).and_return(true) }
|
134
|
+
it 'returns true' do
|
135
|
+
Qa.config.property_map_default_for_optional = true
|
136
|
+
expect(subject.optional?).to be true
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'and property_map_default_for_optional is false' do
|
141
|
+
before { allow(Qa.config).to receive(:property_map_default_for_optional).and_return(false) }
|
142
|
+
it 'returns false' do
|
143
|
+
expect(subject.optional?).to be false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
112
149
|
describe '#label' do
|
113
150
|
context 'when map defines property_label_i18n key' do
|
114
151
|
context 'and i18n translation is defined in locales' do
|
@@ -58,4 +58,13 @@ RSpec.describe Qa::LinkedData::LdpathService do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
61
|
+
|
62
|
+
describe '.predefined_prefixes' do
|
63
|
+
subject { described_class.predefined_prefixes }
|
64
|
+
it 'includes prefixes defined by ldpath' do
|
65
|
+
# only checking for a few prefixes as opposed to the entire list since the gem may expand the list
|
66
|
+
expect(subject.keys).to include("rdf", "rdfs", "owl", "skos", "dc")
|
67
|
+
expect(subject[:rdf]).to be_present
|
68
|
+
end
|
69
|
+
end
|
61
70
|
end
|
@@ -7,17 +7,19 @@ RSpec.describe Qa::LinkedData::Mapper::ContextMapperService do
|
|
7
7
|
let(:context_map) { instance_double(Qa::LinkedData::Config::ContextMap) }
|
8
8
|
let(:subject_uri) { instance_double(RDF::URI) }
|
9
9
|
|
10
|
-
let(:context_properties) { [birth_date_property_map, death_date_property_map, occupation_property_map] }
|
10
|
+
let(:context_properties) { [birth_date_property_map, death_date_property_map, occupation_property_map, missing_property_map] }
|
11
11
|
|
12
12
|
let(:birth_date_property_map) { instance_double(Qa::LinkedData::Config::ContextPropertyMap) }
|
13
13
|
let(:death_date_property_map) { instance_double(Qa::LinkedData::Config::ContextPropertyMap) }
|
14
14
|
let(:occupation_property_map) { instance_double(Qa::LinkedData::Config::ContextPropertyMap) }
|
15
|
+
let(:missing_property_map) { instance_double(Qa::LinkedData::Config::ContextPropertyMap) }
|
15
16
|
|
16
17
|
let(:group_id) { 'dates' }
|
17
18
|
|
18
19
|
let(:birth_date_values) { ['10/15/1943'] }
|
19
20
|
let(:death_date_values) { ['12/17/2018'] }
|
20
21
|
let(:occupation_values) { ['Actress', 'Director', 'Producer'] }
|
22
|
+
let(:missing_values) { [] }
|
21
23
|
|
22
24
|
before do
|
23
25
|
allow(context_map).to receive(:properties).and_return(context_properties)
|
@@ -29,6 +31,7 @@ RSpec.describe Qa::LinkedData::Mapper::ContextMapperService do
|
|
29
31
|
allow(birth_date_property_map).to receive(:selectable?).and_return(false)
|
30
32
|
allow(birth_date_property_map).to receive(:drillable?).and_return(false)
|
31
33
|
allow(birth_date_property_map).to receive(:expand_uri?).and_return(false)
|
34
|
+
allow(birth_date_property_map).to receive(:optional?).and_return(false)
|
32
35
|
|
33
36
|
allow(death_date_property_map).to receive(:label).and_return('Death')
|
34
37
|
allow(death_date_property_map).to receive(:values).with(graph, subject_uri).and_return(death_date_values)
|
@@ -36,6 +39,7 @@ RSpec.describe Qa::LinkedData::Mapper::ContextMapperService do
|
|
36
39
|
allow(death_date_property_map).to receive(:selectable?).and_return(false)
|
37
40
|
allow(death_date_property_map).to receive(:drillable?).and_return(false)
|
38
41
|
allow(death_date_property_map).to receive(:expand_uri?).and_return(false)
|
42
|
+
allow(death_date_property_map).to receive(:optional?).and_return(false)
|
39
43
|
|
40
44
|
allow(occupation_property_map).to receive(:label).and_return('Occupation')
|
41
45
|
allow(occupation_property_map).to receive(:values).with(graph, subject_uri).and_return(occupation_values)
|
@@ -43,6 +47,15 @@ RSpec.describe Qa::LinkedData::Mapper::ContextMapperService do
|
|
43
47
|
allow(occupation_property_map).to receive(:selectable?).and_return(false)
|
44
48
|
allow(occupation_property_map).to receive(:drillable?).and_return(false)
|
45
49
|
allow(occupation_property_map).to receive(:expand_uri?).and_return(false)
|
50
|
+
allow(occupation_property_map).to receive(:optional?).and_return(false)
|
51
|
+
|
52
|
+
allow(missing_property_map).to receive(:label).and_return('Property with NO values')
|
53
|
+
allow(missing_property_map).to receive(:values).with(graph, subject_uri).and_return(missing_values)
|
54
|
+
allow(missing_property_map).to receive(:group?).and_return(false)
|
55
|
+
allow(missing_property_map).to receive(:selectable?).and_return(false)
|
56
|
+
allow(missing_property_map).to receive(:drillable?).and_return(false)
|
57
|
+
allow(missing_property_map).to receive(:expand_uri?).and_return(false)
|
58
|
+
allow(missing_property_map).to receive(:optional?).and_return(true)
|
46
59
|
end
|
47
60
|
|
48
61
|
describe '.map_context' do
|
@@ -115,6 +128,21 @@ RSpec.describe Qa::LinkedData::Mapper::ContextMapperService do
|
|
115
128
|
end
|
116
129
|
end
|
117
130
|
|
131
|
+
context 'when optional? is false' do
|
132
|
+
before { allow(missing_property_map).to receive(:optional?).and_return(false) }
|
133
|
+
it 'includes property with blank values' do
|
134
|
+
result = find_property_to_test(subject, 'Property with NO values')
|
135
|
+
expect(result['values']).to eq []
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when optional? is true' do
|
140
|
+
before { allow(missing_property_map).to receive(:optional?).and_return(true) }
|
141
|
+
it 'property with blank values is not added to results' do
|
142
|
+
expect { find_property_to_test(subject, 'Property with NO values') }.to raise_error StandardError, "property 'Property with NO values' not found"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
118
146
|
context 'when error occurs' do
|
119
147
|
let(:cause) { I18n.t('qa.linked_data.ldpath.parse_error') }
|
120
148
|
before { allow(occupation_property_map).to receive(:values).with(graph, subject_uri).and_raise(cause) }
|
@@ -132,6 +160,6 @@ RSpec.describe Qa::LinkedData::Mapper::ContextMapperService do
|
|
132
160
|
next unless r['property'] == label
|
133
161
|
return r
|
134
162
|
end
|
135
|
-
raise "property
|
163
|
+
raise StandardError, "property '#{label}' not found"
|
136
164
|
end
|
137
165
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Anderson
|
@@ -16,7 +16,7 @@ authors:
|
|
16
16
|
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date: 2019-
|
19
|
+
date: 2019-06-08 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: activerecord-import
|
@@ -488,10 +488,12 @@ files:
|
|
488
488
|
- spec/fixtures/lod_lang_term_enfrde.rdf.xml
|
489
489
|
- spec/fixtures/lod_lang_term_fr.rdf.xml
|
490
490
|
- spec/fixtures/lod_loc_second_term_found.rdf.xml
|
491
|
+
- spec/fixtures/lod_loc_term_bad_id.rdf.xml
|
491
492
|
- spec/fixtures/lod_loc_term_found.rdf.xml
|
492
493
|
- spec/fixtures/lod_oclc_all_query_3_results.rdf.xml
|
493
494
|
- spec/fixtures/lod_oclc_personalName_query_3_results.rdf.xml
|
494
495
|
- spec/fixtures/lod_oclc_query_no_results.rdf.xml
|
496
|
+
- spec/fixtures/lod_oclc_term_bad_id.nt
|
495
497
|
- spec/fixtures/lod_oclc_term_found.rdf.xml
|
496
498
|
- spec/fixtures/lod_search_with_blanknode_subjects.nt
|
497
499
|
- spec/fixtures/lod_term_with_blanknode_objects.nt
|
@@ -627,6 +629,7 @@ test_files:
|
|
627
629
|
- spec/fixtures/oclcts-response-mesh-3.txt
|
628
630
|
- spec/fixtures/loc-names-response.txt
|
629
631
|
- spec/fixtures/oclcts-response-mesh-2.txt
|
632
|
+
- spec/fixtures/lod_loc_term_bad_id.rdf.xml
|
630
633
|
- spec/fixtures/aat-response.txt
|
631
634
|
- spec/fixtures/journals-result.json
|
632
635
|
- spec/fixtures/discogs-search-response-no-subauth.json
|
@@ -696,6 +699,7 @@ test_files:
|
|
696
699
|
- spec/fixtures/geonames-response.json
|
697
700
|
- spec/fixtures/tgn-response.txt
|
698
701
|
- spec/fixtures/lod_oclc_term_found.rdf.xml
|
702
|
+
- spec/fixtures/lod_oclc_term_bad_id.nt
|
699
703
|
- spec/fixtures/lod_search_with_blanknode_subjects.nt
|
700
704
|
- spec/fixtures/assign-fast-noheader.json
|
701
705
|
- spec/fixtures/lod_loc_second_term_found.rdf.xml
|