qa 4.1.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|