ldpath 0.3.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,48 @@
1
1
  module Ldpath
2
2
  class Selector
3
3
  def evaluate(program, uris, context)
4
- Array(uris).map do |uri|
4
+ return to_enum(:evaluate, program, uris, context) unless block_given?
5
+ enum_wrap(uris).map do |uri|
5
6
  loading program, uri, context
6
- evaluate_one uri, context
7
- end.flatten.compact
7
+ enum_flatten_one(evaluate_one(uri, context)).each do |x|
8
+ yield x unless x.nil?
9
+ end
10
+ end
8
11
  end
9
12
 
10
13
  def loading(program, uri, context)
11
14
  program.loading uri, context
12
15
  end
16
+
17
+ protected
18
+
19
+ def enum_wrap(object)
20
+ if object.nil?
21
+ []
22
+ elsif object.respond_to?(:to_ary)
23
+ object.to_ary || [object]
24
+ elsif object.is_a? Hash
25
+ [object]
26
+ elsif object.is_a? Enumerable
27
+ object
28
+ else
29
+ [object]
30
+ end
31
+ end
32
+
33
+ def enum_flatten_one(object)
34
+ return to_enum(:enum_flatten_one, object) unless block_given?
35
+
36
+ enum_wrap(object).each do |e|
37
+ enum_wrap(e).each do |v|
38
+ yield v
39
+ end
40
+ end
41
+ end
13
42
  end
14
43
 
15
44
  class SelfSelector < Selector
16
- def evaluate_one(uri, context)
45
+ def evaluate_one(uri, _context)
17
46
  uri
18
47
  end
19
48
  end
@@ -27,7 +56,9 @@ module Ldpath
27
56
  end
28
57
 
29
58
  def evaluate(program, uris, context)
30
- Array(uris).map do |uri|
59
+ return to_enum(:evaluate, program, uris, context) unless block_given?
60
+
61
+ enum_wrap(uris).map do |uri|
31
62
  loading program, uri, context
32
63
  args = arguments.map do |i|
33
64
  case i
@@ -37,8 +68,10 @@ module Ldpath
37
68
  i
38
69
  end
39
70
  end
40
- program.func_call fname, uri, context, *args
41
- end.flatten.compact
71
+ enum_flatten_one(program.func_call(fname, uri, context, *args)).each do |x|
72
+ yield x unless x.nil?
73
+ end
74
+ end
42
75
  end
43
76
  end
44
77
 
@@ -49,7 +82,7 @@ module Ldpath
49
82
  end
50
83
 
51
84
  def evaluate_one(uri, context)
52
- context.query([uri, property, nil]).map(&:object)
85
+ context.query([uri, property, nil]).lazy.map(&:object)
53
86
  end
54
87
  end
55
88
 
@@ -62,15 +95,28 @@ module Ldpath
62
95
  def evaluate_one(uri, context)
63
96
  return PropertySelector.new(property).evaluate_one(uri_context) unless defined? RDF::Reasoner
64
97
 
65
- context.query([uri, nil, nil]).select do |result|
98
+ context.query([uri, nil, nil]).lazy.select do |result|
66
99
  result.predicate.entail(:subPropertyOf).include? property
67
100
  end.map(&:object)
68
101
  end
69
102
  end
70
103
 
104
+ class NegatedPropertySelector < Selector
105
+ attr_reader :properties
106
+ def initialize(*properties)
107
+ @properties = properties
108
+ end
109
+
110
+ def evaluate_one(uri, context)
111
+ context.query([uri, nil, nil]).lazy.reject do |result|
112
+ properties.include? result.predicate
113
+ end.map(&:object)
114
+ end
115
+ end
116
+
71
117
  class WildcardSelector < Selector
72
118
  def evaluate_one(uri, context)
73
- context.query([uri, nil, nil]).map(&:object)
119
+ context.query([uri, nil, nil]).lazy.map(&:object)
74
120
  end
75
121
  end
76
122
 
@@ -81,7 +127,7 @@ module Ldpath
81
127
  end
82
128
 
83
129
  def evaluate_one(uri, context)
84
- context.query([nil, property, uri]).map(&:subject)
130
+ context.query([nil, property, uri]).lazy.map(&:subject)
85
131
  end
86
132
  end
87
133
 
@@ -93,19 +139,20 @@ module Ldpath
93
139
  end
94
140
 
95
141
  def evaluate(program, uris, context)
96
- result = []
97
- input = Array(uris)
142
+ return to_enum(:evaluate, program, uris, context) unless block_given?
98
143
 
99
- Range.new(0, repeat.min, true).each do
100
- input = property.evaluate program, input, context
101
- end
144
+ input = enum_wrap(uris)
102
145
 
103
- repeat.each_with_index do |i, idx|
104
- break if input.empty? || idx > 25 # we're probably lost..
146
+ (0..repeat.max).each_with_index do |i, idx|
147
+ break if input.none? || (repeat.max == Ldpath::Transform::Infinity && idx > 25) # we're probably lost..
105
148
  input = property.evaluate program, input, context
106
- result |= input
149
+
150
+ next unless idx >= repeat.min
151
+
152
+ enum_wrap(input).each do |x|
153
+ yield x
154
+ end
107
155
  end
108
- result.flatten.compact
109
156
  end
110
157
  end
111
158
 
@@ -118,21 +165,47 @@ module Ldpath
118
165
  end
119
166
 
120
167
  class PathSelector < CompoundSelector
121
- def evaluate(program, uris, context)
168
+ def evaluate(program, uris, context, &block)
169
+ return to_enum(:evaluate, program, uris, context) unless block_given?
170
+
122
171
  output = left.evaluate(program, uris, context)
123
- right.evaluate(program, output, context)
172
+ right.evaluate(program, output, context, &block)
124
173
  end
125
174
  end
126
175
 
127
176
  class UnionSelector < CompoundSelector
128
177
  def evaluate(program, uris, context)
129
- left.evaluate(program, uris, context) | right.evaluate(program, uris, context)
178
+ return to_enum(:evaluate, program, uris, context) unless block_given?
179
+
180
+ enum_union(left.evaluate(program, uris, context), right.evaluate(program, uris, context)).each do |x|
181
+ yield x
182
+ end
183
+ end
184
+
185
+ private
186
+
187
+ def enum_union(left, right)
188
+ return to_enum(:enum_union, left, right) unless block_given?
189
+
190
+ enum_wrap(left).each do |e|
191
+ yield e
192
+ end
193
+
194
+ enum_wrap(right).each do |e|
195
+ yield e
196
+ end
130
197
  end
131
198
  end
132
199
 
133
200
  class IntersectionSelector < CompoundSelector
134
201
  def evaluate(program, uris, context)
135
- left.evaluate(program, uris, context) & right.evaluate(program, uris, context)
202
+ return to_enum(:evaluate, program, uris, context) unless block_given?
203
+
204
+ result = left.evaluate(program, uris, context).to_a & right.evaluate(program, uris, context).to_a
205
+
206
+ result.each do |x|
207
+ yield x
208
+ end
136
209
  end
137
210
  end
138
211
 
@@ -144,15 +217,19 @@ module Ldpath
144
217
  end
145
218
 
146
219
  def evaluate(program, uris, context)
220
+ return to_enum(:evaluate, program, uris, context) unless block_given?
221
+
147
222
  program.meta[identifier] = tap.evaluate(program, uris, context).map { |x| RDF::Literal.new(x.to_s).canonicalize.object }
148
223
 
149
- Array(uris).map do |uri|
224
+ enum_wrap(uris).map do |uri|
150
225
  loading program, uri, context
151
- evaluate_one uri, context
152
- end.flatten.compact
226
+ enum_flatten_one(evaluate_one(uri, context)).each do |x|
227
+ yield x unless x.nil?
228
+ end
229
+ end
153
230
  end
154
231
 
155
- def evaluate_one(uri, context)
232
+ def evaluate_one(uri, _context)
156
233
  uri
157
234
  end
158
235
  end
data/lib/ldpath/tests.rb CHANGED
@@ -10,7 +10,7 @@ module Ldpath
10
10
  def evaluate(program, uris, context)
11
11
  entries = delegate.evaluate program, uris, context
12
12
  entries.select do |uri|
13
- Array(test.evaluate(program, uri, context)).any? do |x|
13
+ enum_wrap(test.evaluate(program, uri, context)).any? do |x|
14
14
  x
15
15
  end
16
16
  end
@@ -23,11 +23,10 @@ module Ldpath
23
23
  @lang = lang
24
24
  end
25
25
 
26
- def evaluate(program, uri, context)
26
+ def evaluate(_program, uri, _context)
27
27
  return unless uri.literal?
28
- if (lang == "none" && !uri.has_language?) || uri.language == lang
29
- uri
30
- end
28
+
29
+ uri if (lang == "none" && !uri.has_language?) || uri.language == lang
31
30
  end
32
31
  end
33
32
 
@@ -37,11 +36,10 @@ module Ldpath
37
36
  @type = type
38
37
  end
39
38
 
40
- def evaluate(program, uri, context)
39
+ def evaluate(program, uri, _context)
41
40
  return unless uri.literal?
42
- if uri.has_datatype? && uri.datatype == type
43
- uri
44
- end
41
+
42
+ uri if uri.has_datatype? && uri.datatype == type
45
43
  end
46
44
  end
47
45
 
@@ -53,7 +51,7 @@ module Ldpath
53
51
  end
54
52
 
55
53
  def evaluate(program, uri, context)
56
- !Array(delegate.evaluate(program, uri, context)).any? { |x| x }
54
+ !enum_wrap(delegate.evaluate(program, uri, context)).any? { |x| x }
57
55
  end
58
56
  end
59
57
 
@@ -79,8 +77,8 @@ module Ldpath
79
77
  end
80
78
 
81
79
  def evaluate(program, uri, context)
82
- left.evaluate(program, uri, context).compact.any? &&
83
- right.evaluate(program, uri, context).compact.any?
80
+ left.evaluate(program, uri, context).any? &&
81
+ right.evaluate(program, uri, context).any?
84
82
  end
85
83
  end
86
84
 
@@ -93,7 +91,7 @@ module Ldpath
93
91
  end
94
92
 
95
93
  def evaluate(program, uri, context)
96
- left.evaluate(program, uri, context).compact.include?(right)
94
+ left.evaluate(program, uri, context).include?(right)
97
95
  end
98
96
  end
99
97
  end
@@ -15,7 +15,7 @@ module Ldpath
15
15
  "fn" => RDF::Vocabulary.new("http://www.newmedialab.at/lmf/functions/1.0/"), # (LMF index functions)
16
16
  "foaf" => RDF::Vocabulary.new("http://xmlns.com/foaf/0.1/"),
17
17
  "info" => RDF::Vocabulary.new("info:"),
18
- "urn" => RDF::Vocabulary.new("urn:"),
18
+ "urn" => RDF::Vocabulary.new("urn:")
19
19
  }
20
20
  end
21
21
  end
@@ -71,7 +71,7 @@ module Ldpath
71
71
  # Mappings
72
72
 
73
73
  rule(mapping: subtree(:mapping)) do
74
- FieldMapping.new mapping[:name].to_s, mapping[:selector], mapping[:field_type]
74
+ FieldMapping.new mapping
75
75
  end
76
76
 
77
77
  ## Selectors
@@ -106,18 +106,13 @@ module Ldpath
106
106
  end
107
107
 
108
108
  rule(range: subtree(:range)) do
109
- case range
110
- when "*"
111
- 0..Infinity
112
- when "+"
113
- 1..Infinity
114
- when "?"
115
- 0..1
116
- else
117
- range.fetch(:min, 0).to_i..range.fetch(:max, Infinity).to_f
118
- end
109
+ range.fetch(:min, 0).to_i..range.fetch(:max, Infinity).to_f
119
110
  end
120
111
 
112
+ rule(range: '*') { 0..Infinity }
113
+ rule(range: '+') { 1..Infinity }
114
+ rule(range: '?') { 0..1 }
115
+
121
116
  rule(delegate: subtree(:delegate), repeat: simple(:repeat)) do
122
117
  RecursivePathSelector.new delegate, repeat
123
118
  end
@@ -126,6 +121,10 @@ module Ldpath
126
121
  TapSelector.new identifier.to_s, tap
127
122
  end
128
123
 
124
+ rule(not: simple(:not), property: sequence(:property)) do
125
+ NegatedPropertySelector.new(*property)
126
+ end
127
+
129
128
  ### Test Selectors
130
129
 
131
130
  rule(delegate: subtree(:delegate), test: subtree(:test)) do
@@ -144,16 +143,16 @@ module Ldpath
144
143
  TypeTest.new type
145
144
  end
146
145
 
147
- rule(not: subtree(:not_op)) do
148
- NotTest.new not_op[:delegate]
146
+ rule(not: simple(:not_op), delegate: simple(:delegate)) do
147
+ NotTest.new delegate
149
148
  end
150
149
 
151
- rule(and: subtree(:op)) do
152
- AndTest.new op[:left], op[:right]
150
+ rule(op: '|', left_test: subtree(:left_test), right_test: subtree(:right_test)) do
151
+ OrTest.new left_test, right_test
153
152
  end
154
153
 
155
- rule(or: subtree(:op)) do
156
- OrTest.new op[:left], op[:right]
154
+ rule(op: '&', left_test: subtree(:left_test), right_test: subtree(:right_test)) do
155
+ AndTest.new left_test, right_test
157
156
  end
158
157
 
159
158
  rule(is: subtree(:is)) do
@@ -165,15 +164,17 @@ module Ldpath
165
164
  end
166
165
 
167
166
  ### Compound Selectors
168
- rule(left: subtree(:left), op: simple(:op), right: subtree(:right)) do
169
- case op
170
- when "/"
171
- PathSelector.new left, right
172
- when "|"
173
- UnionSelector.new left, right
174
- when "&"
175
- IntersectionSelector.new left, right
176
- end
167
+
168
+ rule(op: '/', left: subtree(:left), right: subtree(:right)) do
169
+ PathSelector.new left, right
170
+ end
171
+
172
+ rule(op: '|', left: subtree(:left), right: subtree(:right)) do
173
+ UnionSelector.new left, right
174
+ end
175
+
176
+ rule(op: '&', left: subtree(:left), right: subtree(:right)) do
177
+ IntersectionSelector.new left, right
177
178
  end
178
179
 
179
180
  Infinity = 1.0 / 0.0
@@ -1,3 +1,3 @@
1
1
  module Ldpath
2
- VERSION = "0.3.1"
2
+ VERSION = '1.0.0'.freeze
3
3
  end
data/lib/ldpath.rb CHANGED
@@ -10,8 +10,11 @@ module Ldpath
10
10
  require 'ldpath/transform'
11
11
  require 'ldpath/functions'
12
12
  require 'ldpath/program'
13
+ require 'ldpath/result'
13
14
 
14
15
  class << self
16
+ attr_writer :logger
17
+
15
18
  def evaluate(program, uri, context)
16
19
  Ldpath::Program.parse(program).evaluate(uri, context)
17
20
  end
@@ -25,9 +28,5 @@ module Ldpath
25
28
  end
26
29
  end
27
30
  end
28
-
29
- def logger=(logger)
30
- @logger = logger
31
- end
32
31
  end
33
32
  end
@@ -0,0 +1,4 @@
1
+ <http://www.bbc.co.uk/programmes/b0081dq5> <http://xmlns.com/foaf/0.1/primaryTopic> <_:b0> .
2
+ <_:b0> <http://purl.org/ontology/po/pid> "b0081dq5" .
3
+ <_:b0> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/primaryTopic> .
4
+ <_:b0> <http://purl.org/dc/elements/1.1/title> "Huw Stephens" .
@@ -0,0 +1,3 @@
1
+ <http://id.loc.gov/authorities/names/n79021164> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.loc.gov/mads/rdf/v1#PersonalName> .
2
+ <http://id.loc.gov/authorities/names/n79021164> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.loc.gov/mads/rdf/v1#Authority> .
3
+ <http://id.loc.gov/authorities/names/n79021164> <http://www.loc.gov/mads/rdf/v1#authoritativeLabel> "Twain, Mark, 1835-1910 (network call to LOC)"@en .
@@ -200,12 +200,30 @@ describe Ldpath::Parser do
200
200
  end
201
201
 
202
202
  it "tap_selector" do
203
- subject.selector.parse('?<a><info:a>')
203
+ subject.selector.parse('?<__autocomplete>fn:predicates()')
204
204
  end
205
205
 
206
206
  it "loose_selector" do
207
207
  subject.selector.parse('~<info:a>')
208
208
  end
209
+
210
+ it "negated property selector" do
211
+ subject.selector.parse('!<info:a>')
212
+ end
213
+ end
214
+
215
+ describe "tests" do
216
+ it "should pass a simple property test" do
217
+ subject.selector.parse('.[info:a]')
218
+ end
219
+
220
+ it "should pass a property test with '&'" do
221
+ subject.selector.parse('.[info:a & info:b]')
222
+ end
223
+
224
+ it "should pass a property test with '|'" do
225
+ subject.selector.parse('.[info:a | info:b]')
226
+ end
209
227
  end
210
228
 
211
229
  describe "integration tests" do
@@ -36,19 +36,19 @@ EOF
36
36
  end
37
37
 
38
38
  it "should work" do
39
- graph << [object, RDF::DC.title, "Hello, world!"]
40
- graph << [object, RDF::DC.isPartOf, parent]
41
- graph << [object, RDF::DC.description, RDF::Literal.new("English!", language: "en")]
42
- graph << [object, RDF::DC.description, RDF::Literal.new("French!", language: "fr")]
39
+ graph << [object, RDF::Vocab::DC.title, "Hello, world!"]
40
+ graph << [object, RDF::Vocab::DC.isPartOf, parent]
41
+ graph << [object, RDF::Vocab::DC.description, RDF::Literal.new("English!", language: "en")]
42
+ graph << [object, RDF::Vocab::DC.description, RDF::Literal.new("French!", language: "fr")]
43
43
  graph << [object, RDF::URI.new("info:intProperty"), 1]
44
44
  graph << [object, RDF::URI.new("info:intProperty"), "garbage"]
45
45
  graph << [object, RDF::URI.new("info:numericProperty"), "1"]
46
- graph << [parent, RDF::DC.title, "Parent title"]
47
- graph << [child, RDF::DC.isPartOf, object]
48
- graph << [child, RDF::DC.title, "Child title"]
49
- graph << [parent, RDF::DC.isPartOf, grandparent]
46
+ graph << [parent, RDF::Vocab::DC.title, "Parent title"]
47
+ graph << [child, RDF::Vocab::DC.isPartOf, object]
48
+ graph << [child, RDF::Vocab::DC.title, "Child title"]
49
+ graph << [parent, RDF::Vocab::DC.isPartOf, grandparent]
50
50
 
51
- result = subject.evaluate object, graph
51
+ result = subject.evaluate object, context: graph
52
52
 
53
53
  expect(result["title"]).to match_array "Hello, world!"
54
54
  expect(result["parent_title"]).to match_array "Parent title"
@@ -97,17 +97,17 @@ EOF
97
97
 
98
98
  let(:graph) do
99
99
  graph = RDF::Graph.new
100
- graph << [object, RDF::DC.title, "Hello, world!"]
101
- graph << [object, RDF::DC.description, "Description"]
102
- graph << [object, RDF::DC.hasPart, "a"]
103
- graph << [object, RDF::DC.hasPart, "b"]
104
- graph << [object, RDF::DC.hasPart, "c"]
100
+ graph << [object, RDF::Vocab::DC.title, "Hello, world!"]
101
+ graph << [object, RDF::Vocab::DC.description, "Description"]
102
+ graph << [object, RDF::Vocab::DC.hasPart, "a"]
103
+ graph << [object, RDF::Vocab::DC.hasPart, "b"]
104
+ graph << [object, RDF::Vocab::DC.hasPart, "c"]
105
105
 
106
106
  graph
107
107
  end
108
108
 
109
109
  subject do
110
- program.evaluate object, graph
110
+ program.evaluate object, context: graph
111
111
  end
112
112
 
113
113
  describe "concat" do
@@ -191,8 +191,13 @@ title = foaf:primaryTopic / dc:title :: xsd:string ;
191
191
  EOF
192
192
  end
193
193
 
194
+ before do
195
+ stub_request(:get, 'http://www.bbc.co.uk/programmes/b0081dq5')
196
+ .to_return(status: 200, body: webmock_fixture('bbc_b0081dq5.nt'), headers: { 'Content-Type' => 'application/n-triples' })
197
+ end
198
+
194
199
  it "should work" do
195
- result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5.rdf")
200
+ result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5")
196
201
  expect(result["title"]).to match_array "Huw Stephens"
197
202
  end
198
203
  end
@@ -205,9 +210,16 @@ predicates = <http://xmlns.com/foaf/0.1/primaryTopic> / fn:predicates() :: xsd:s
205
210
  EOF
206
211
  end
207
212
 
213
+ before do
214
+ stub_request(:get, 'http://www.bbc.co.uk/programmes/b0081dq5')
215
+ .to_return(status: 200, body: webmock_fixture('bbc_b0081dq5.nt'), headers: { 'Content-Type' => 'application/n-triples' })
216
+ end
217
+
208
218
  it "should work" do
209
- result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5.rdf")
210
- expect(result["predicates"]).to include "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "http://purl.org/ontology/po/pid", "http://purl.org/dc/elements/1.1/title"
219
+ result = subject.evaluate RDF::URI.new("http://www.bbc.co.uk/programmes/b0081dq5")
220
+ expect(result["predicates"]).to include "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
221
+ "http://purl.org/ontology/po/pid",
222
+ "http://purl.org/dc/elements/1.1/title"
211
223
  end
212
224
  end
213
225
 
@@ -219,9 +231,9 @@ EOF
219
231
  let(:graph) do
220
232
  graph = RDF::Graph.new
221
233
 
222
- graph << [object, RDF::DC.title, "Object"]
223
- graph << [child, RDF::DC.title, "Child"]
224
- graph << [object, RDF::DC.hasPart, child]
234
+ graph << [object, RDF::Vocab::DC.title, "Object"]
235
+ graph << [child, RDF::Vocab::DC.title, "Child"]
236
+ graph << [object, RDF::Vocab::DC.hasPart, child]
225
237
 
226
238
  graph
227
239
  end
@@ -236,7 +248,7 @@ child_title_with_tap = dcterms:hasPart / ?<tap>fn:predicates() / dcterms:title :
236
248
  end
237
249
 
238
250
  it "should work" do
239
- result = subject.evaluate object, graph
251
+ result = subject.evaluate object, context: graph
240
252
  expect(result["child_title_with_tap"]).to eq result["child_title"]
241
253
  expect(result["tap"]).to eq ["http://purl.org/dc/terms/title"]
242
254
  end
@@ -250,9 +262,9 @@ child_title_with_tap = dcterms:hasPart / ?<tap>fn:predicates() / dcterms:title :
250
262
  let(:graph) do
251
263
  graph = RDF::Graph.new
252
264
 
253
- graph << [object, RDF::DC.title, "Object"]
254
- graph << [child, RDF::DC.title, "Child"]
255
- graph << [object, RDF::DC.hasPart, child]
265
+ graph << [object, RDF::Vocab::DC.title, "Object"]
266
+ graph << [child, RDF::Vocab::DC.title, "Child"]
267
+ graph << [object, RDF::Vocab::DC.hasPart, child]
256
268
 
257
269
  graph
258
270
  end
@@ -267,7 +279,7 @@ title_with_loose = ~dc:title :: xsd:string ;
267
279
  end
268
280
 
269
281
  it "should work" do
270
- result = subject.evaluate object, graph
282
+ result = subject.evaluate object, context: graph
271
283
  expect(result["title_with_loose"]).to eq result["title"]
272
284
  end
273
285
  end
@@ -288,27 +300,70 @@ title_with_loose = ~dc:title :: xsd:string ;
288
300
  let(:graph) do
289
301
  graph = RDF::Graph.new
290
302
 
291
- graph << [object, RDF.type, RDF::DC.Agent]
292
- graph << [object, RDF::DC.title, "Title"]
293
- graph << [other_object, RDF::DC.title, "Other Title"]
303
+ graph << [object, RDF.type, RDF::Vocab::DC.Agent]
304
+ graph << [object, RDF::Vocab::DC.title, "Title"]
305
+ graph << [other_object, RDF::Vocab::DC.title, "Other Title"]
294
306
 
295
307
  graph
296
308
  end
297
309
 
298
310
  it "should work" do
299
- result = subject.evaluate object, graph
311
+ result = subject.evaluate object, context: graph
300
312
  expect(result["title"]).to eq ["Title"]
301
313
  end
302
314
 
303
315
  it "filters objects that don't match" do
304
- result = subject.evaluate other_object, graph
316
+ result = subject.evaluate other_object, context: graph
305
317
  expect(result).to be_empty
306
318
  end
307
319
  end
308
320
 
309
321
  describe "error handling" do
310
322
  it "should provide a reasonable exception" do
311
- expect { Ldpath::Program.parse "title .= <oops> ;" }.to raise_error /Expected "=", but got "."/
323
+ expect { Ldpath::Program.parse "title .= <oops> ;" }.to raise_error(/Expected "=", but got "."/)
324
+ end
325
+ end
326
+
327
+ describe '#evaluate' do
328
+ context 'when passing limit_to_context' do
329
+ subject do
330
+ Ldpath::Program.parse <<-EOF
331
+ @prefix madsrdf : <http://www.loc.gov/mads/rdf/v1#> ;
332
+ @prefix schema: <http://www.w3.org/2000/01/rdf-schema#> ;
333
+ property = madsrdf:authoritativeLabel :: xsd:string ;
334
+ EOF
335
+ end
336
+
337
+ let(:subject_uri) { RDF::URI('http://id.loc.gov/authorities/names/n79021164') }
338
+
339
+ let(:graph) do
340
+ graph = RDF::Graph.new
341
+ graph << [subject_uri, RDF::Vocab::MADS.authoritativeLabel, 'Mark Twain (passed in context)']
342
+ graph
343
+ end
344
+
345
+ before do
346
+ stub_request(:get, 'http://id.loc.gov/authorities/names/n79021164')
347
+ .to_return(status: 200, body: webmock_fixture('loc_n79021164.nt'), headers: { 'Content-Type' => 'application/n-triples' })
348
+ end
349
+
350
+ context 'as false' do
351
+ let(:expected_values) { ['Mark Twain (passed in context)', 'Twain, Mark, 1835-1910 (network call to LOC)'] }
352
+
353
+ it 'returns values from context and network call' do
354
+ result = subject.evaluate subject_uri, context: graph
355
+ expect(result['property']).to match_array expected_values
356
+ end
357
+ end
358
+
359
+ context 'as true' do
360
+ let(:expected_values) { ['Mark Twain (passed in context)'] }
361
+
362
+ it 'returns values from context only' do
363
+ result = subject.evaluate(subject_uri, context: graph, limit_to_context: true)
364
+ expect(result['property']).to match_array expected_values
365
+ end
366
+ end
312
367
  end
313
368
  end
314
369
  end