rdf_context 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +3 -0
- data/VERSION +1 -1
- data/lib/rdf_context/conjunctive_graph.rb +1 -1
- data/lib/rdf_context/graph.rb +2 -2
- data/lib/rdf_context/rdfxmlparser.rb +0 -5
- data/lib/rdf_context/store/abstract_sql_store.rb +13 -7
- data/lib/rdf_context/store/abstract_store.rb +9 -0
- data/lib/rdf_context/store/list_store.rb +1 -5
- data/spec/conjunctive_graph_spec.rb +6 -0
- data/spec/graph_spec.rb +5 -0
- data/spec/list_store_spec.rb +1 -2
- data/spec/literal_spec.rb +17 -20
- data/spec/memory_store_spec.rb +1 -12
- data/spec/rdfxml_spec.rb +2 -2
- data/spec/sqlite3_store_spec.rb +26 -8
- data/spec/store_helper.rb +59 -29
- metadata +1 -1
data/History.txt
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.3
|
@@ -15,7 +15,7 @@ module RdfContext
|
|
15
15
|
# Store for ConjunctiveGraph must support contexts.
|
16
16
|
def initialize(options = {})
|
17
17
|
unless options[:store] && options[:store].context_aware?
|
18
|
-
raise GraphException.new("
|
18
|
+
raise GraphException.new("ConjunctiveGraph requires store supporting contexts")
|
19
19
|
end
|
20
20
|
|
21
21
|
super(:identifier => options[:store].identifier, :store => options[:store])
|
data/lib/rdf_context/graph.rb
CHANGED
@@ -72,8 +72,8 @@ module RdfContext
|
|
72
72
|
#
|
73
73
|
# Might be necessary for stores that require opening a connection to a
|
74
74
|
# database or acquiring some resource.
|
75
|
-
def open(configuration
|
76
|
-
@store.open(configuration
|
75
|
+
def open(configuration = {})
|
76
|
+
@store.open(configuration)
|
77
77
|
end
|
78
78
|
|
79
79
|
# Close the graph store
|
@@ -149,11 +149,6 @@ module RdfContext
|
|
149
149
|
end
|
150
150
|
|
151
151
|
private
|
152
|
-
# Is the node rdf:RDF?
|
153
|
-
def is_rdf_root? (node)
|
154
|
-
node.name == "RDF" && node.namespace.href == RDF_NS.uri.to_s
|
155
|
-
end
|
156
|
-
|
157
152
|
# XML nodeElement production
|
158
153
|
#
|
159
154
|
# @param [XML Element] el:: XMl Element to parse
|
@@ -39,9 +39,6 @@ module RdfContext
|
|
39
39
|
@bnodeCache = {}
|
40
40
|
@uriCache = {}
|
41
41
|
|
42
|
-
@context_aware = true
|
43
|
-
@formula_aware = true
|
44
|
-
@transaction_aware = true
|
45
42
|
@autocommit_default = true
|
46
43
|
|
47
44
|
raise StoreException.new("Identifier must be nil or a URIRef") if identifier && !identifier.is_a?(URIRef)
|
@@ -51,6 +48,15 @@ module RdfContext
|
|
51
48
|
|
52
49
|
@db = configuration.empty? ? nil : open(configuration)
|
53
50
|
end
|
51
|
+
|
52
|
+
# Supports contexts
|
53
|
+
def context_aware?; true; end
|
54
|
+
|
55
|
+
# Supports formulae
|
56
|
+
def formula_aware?; true; end
|
57
|
+
|
58
|
+
# Supports transactions
|
59
|
+
def transaction_aware?; true; end
|
54
60
|
|
55
61
|
def close(commit_pending_transactions = false)
|
56
62
|
@db.commit if commit_pending_transactions && @db.transaction_active?
|
@@ -525,9 +531,9 @@ module RdfContext
|
|
525
531
|
|
526
532
|
# List of namespace bindings, as a hash
|
527
533
|
def nsbinding
|
528
|
-
namespaces =
|
534
|
+
namespaces = {}
|
529
535
|
executeSQL("SELECT prefix, uri FROM #{namespace_binds}") do |row|
|
530
|
-
namespaces
|
536
|
+
namespaces[row[0]] = Namespace.new(row[1], row[0])
|
531
537
|
end
|
532
538
|
namespaces
|
533
539
|
end
|
@@ -727,11 +733,11 @@ module RdfContext
|
|
727
733
|
end
|
728
734
|
|
729
735
|
def buildLitDTypeClause(obj,tableName)
|
730
|
-
"#{tableName}.objDatatype='#{obj.encoding.value}'" if obj.is_a?(Literal) && obj.encoding
|
736
|
+
["#{tableName}.objDatatype='#{obj.encoding.value}'"] if obj.is_a?(Literal) && obj.encoding
|
731
737
|
end
|
732
738
|
|
733
739
|
def buildLitLanguageClause(obj,tableName)
|
734
|
-
"#{tableName}.objDatatype='#{obj.lang}'" if obj.is_a?(Literal) && obj.lang
|
740
|
+
["#{tableName}.objDatatype='#{obj.lang}'"] if obj.is_a?(Literal) && obj.lang
|
735
741
|
end
|
736
742
|
|
737
743
|
# Stubs for Clause Functions that are overridden by specific implementations (MySQL vs SQLite for instance)
|
@@ -11,6 +11,10 @@ module RdfContext
|
|
11
11
|
@identifier = identifier || BNode.new
|
12
12
|
end
|
13
13
|
|
14
|
+
def context_aware?; false; end
|
15
|
+
def formula_aware?; false; end
|
16
|
+
def transaction_aware?; false; end
|
17
|
+
|
14
18
|
# Interfaces that must be implemented
|
15
19
|
def triples(triple, context = nil) # :yields: triple, context
|
16
20
|
raise StoreException, "not implemented"
|
@@ -22,6 +26,11 @@ module RdfContext
|
|
22
26
|
def inspect
|
23
27
|
"#{self.class}[identifier=#{identifier.inspect}]"
|
24
28
|
end
|
29
|
+
|
30
|
+
def destroy(configuration = {}); end
|
31
|
+
def open(configuration = {}); end
|
32
|
+
def commit; end
|
33
|
+
def rollback; end
|
25
34
|
|
26
35
|
# Bind namespace to store, returns bound namespace
|
27
36
|
def bind(namespace)
|
@@ -25,11 +25,7 @@ module RdfContext
|
|
25
25
|
# If the triple does not provide a context attribute, removes the triple
|
26
26
|
# from all contexts.
|
27
27
|
def remove(triple, context, quoted = false)
|
28
|
-
|
29
|
-
@triples.delete(triple)
|
30
|
-
else
|
31
|
-
@triples = []
|
32
|
-
end
|
28
|
+
@triples.delete(triple)
|
33
29
|
end
|
34
30
|
|
35
31
|
# Check to see if this graph contains the specified triple
|
@@ -9,6 +9,12 @@ describe "ConjunctiveGraph" do
|
|
9
9
|
|
10
10
|
subject { ConjunctiveGraph.new(:store => @store)}
|
11
11
|
|
12
|
+
it "should require store supporting contexts" do
|
13
|
+
lambda do
|
14
|
+
ConjunctiveGraph.new(:store => ListStore.new)
|
15
|
+
end.should raise_error(GraphException, "ConjunctiveGraph requires store supporting contexts")
|
16
|
+
end
|
17
|
+
|
12
18
|
it "should should have same identifier as store" do
|
13
19
|
subject.identifier.should == @identifier
|
14
20
|
end
|
data/spec/graph_spec.rb
CHANGED
@@ -76,6 +76,11 @@ describe "Graphs" do
|
|
76
76
|
subject.add(Triple.new(@ex.a, @ex.b, @ex.c), Triple.new(@ex.a, @ex.b, @ex.d))
|
77
77
|
subject.size.should == 2
|
78
78
|
end
|
79
|
+
|
80
|
+
it "should freeze when destroyed" do
|
81
|
+
subject.destroy
|
82
|
+
subject.frozen?.should be_true
|
83
|
+
end
|
79
84
|
|
80
85
|
describe "with identifier" do
|
81
86
|
before(:all) { @identifier = URIRef.new("http://foo.bar") }
|
data/spec/list_store_spec.rb
CHANGED
@@ -3,8 +3,7 @@ require File.join(File.dirname(__FILE__), 'store_helper')
|
|
3
3
|
|
4
4
|
describe "List Store" do
|
5
5
|
before(:all) do
|
6
|
-
|
7
|
-
@ctx = @identifier
|
6
|
+
@identifier = URIRef.new("http://identifier")
|
8
7
|
end
|
9
8
|
|
10
9
|
subject { ListStore.new(@identifier) }
|
data/spec/literal_spec.rb
CHANGED
@@ -290,25 +290,22 @@ describe "Literals: " do
|
|
290
290
|
end
|
291
291
|
end
|
292
292
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
# lang.hash.class.should == Fixnum
|
311
|
-
# end
|
312
|
-
# end
|
293
|
+
describe "Encodings" do
|
294
|
+
specify "integer" do
|
295
|
+
Literal::Encoding.integer.should == Literal::Encoding.new("http://www.w3.org/2001/XMLSchema#int")
|
296
|
+
end
|
297
|
+
specify "float" do
|
298
|
+
Literal::Encoding.float.should == Literal::Encoding.new("http://www.w3.org/2001/XMLSchema#float")
|
299
|
+
end
|
300
|
+
specify "string" do
|
301
|
+
Literal::Encoding.string.should == Literal::Encoding.new("http://www.w3.org/2001/XMLSchema#string")
|
302
|
+
end
|
303
|
+
specify "xmlliteral" do
|
304
|
+
Literal::Encoding.xmlliteral.should == Literal::XMLLiteral.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral")
|
305
|
+
end
|
306
|
+
specify "null" do
|
307
|
+
Literal::Encoding.the_null_encoding.should == Literal::Null.new(nil)
|
308
|
+
end
|
309
|
+
end
|
313
310
|
|
314
311
|
end
|
data/spec/memory_store_spec.rb
CHANGED
@@ -3,21 +3,10 @@ require File.join(File.dirname(__FILE__), 'store_helper')
|
|
3
3
|
|
4
4
|
describe "Memory Store" do
|
5
5
|
before(:all) do
|
6
|
-
|
7
|
-
@ctx = @identifier
|
6
|
+
@identifier = URIRef.new("http://identifier")
|
8
7
|
end
|
9
8
|
|
10
9
|
subject { MemoryStore.new(@identifier) }
|
11
10
|
it_should_behave_like "Store"
|
12
11
|
it_should_behave_like "Context Aware Store"
|
13
|
-
|
14
|
-
|
15
|
-
describe "with context" do
|
16
|
-
before(:all) do
|
17
|
-
@ctx = URIRef.new("http://context")
|
18
|
-
end
|
19
|
-
|
20
|
-
it_should_behave_like "Store"
|
21
|
-
it_should_behave_like "Context Aware Store"
|
22
|
-
end
|
23
12
|
end
|
data/spec/rdfxml_spec.rb
CHANGED
@@ -321,11 +321,11 @@ EOF
|
|
321
321
|
include RdfXMLHelper
|
322
322
|
|
323
323
|
def self.positive_tests
|
324
|
-
|
324
|
+
RdfXMLHelper::TestCase.positive_parser_tests rescue []
|
325
325
|
end
|
326
326
|
|
327
327
|
def self.negative_tests
|
328
|
-
|
328
|
+
RdfXMLHelper::TestCase.negative_parser_tests rescue []
|
329
329
|
end
|
330
330
|
|
331
331
|
# Negative parser tests should raise errors.
|
data/spec/sqlite3_store_spec.rb
CHANGED
@@ -6,7 +6,6 @@ describe "SQLite3 Store" do
|
|
6
6
|
Dir.mkdir(File.dirname(__FILE__) + "/tmp")
|
7
7
|
@dbfile = File.join(File.dirname(__FILE__), "tmp", "sqlite3.db")
|
8
8
|
@identifier = URIRef.new("http://identifier")
|
9
|
-
@ctx = @identifier
|
10
9
|
end
|
11
10
|
|
12
11
|
before(:each) do
|
@@ -30,12 +29,31 @@ describe "SQLite3 Store" do
|
|
30
29
|
File.exists?(@dbfile).should be_false
|
31
30
|
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
it "should close db" do
|
33
|
+
subject.close
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should find contexts with type" do
|
37
|
+
triple = Triple.new("http://foo", RDF_TYPE, "http://baz")
|
38
|
+
subject.add(triple, nil)
|
39
|
+
subject.contexts(triple).length.should == 1
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should find triples with typed literal" do
|
43
|
+
triple = Triple.new("http://foo", RDF_TYPE, Literal.build_from(1.1))
|
44
|
+
subject.add(triple, nil)
|
45
|
+
subject.contexts(triple).length.should == 1
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should find triples with untyped literal and lang" do
|
49
|
+
triple = Triple.new("http://foo", RDF_TYPE, Literal.untyped("foo", "en-US"))
|
50
|
+
subject.add(triple, nil)
|
51
|
+
subject.contexts(triple).length.should == 1
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should find contexts patern triple" do
|
55
|
+
triple = Triple.new("http://foo", RDF_TYPE, "http://baz")
|
56
|
+
subject.add(triple, nil)
|
57
|
+
subject.contexts(Triple.new(nil, nil, nil)).length.should == 1
|
40
58
|
end
|
41
59
|
end
|
data/spec/store_helper.rb
CHANGED
@@ -9,8 +9,8 @@ shared_examples_for "Store" do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should allow you to add a triple" do
|
12
|
-
subject.add(Triple.new(@ex.a, @ex.b, @ex.c),
|
13
|
-
subject.add(Triple.new(@ex.a, @ex.b, @ex.d),
|
12
|
+
subject.add(Triple.new(@ex.a, @ex.b, @ex.c), nil)
|
13
|
+
subject.add(Triple.new(@ex.a, @ex.b, @ex.d), nil)
|
14
14
|
subject.size.should == 2
|
15
15
|
end
|
16
16
|
|
@@ -23,16 +23,38 @@ shared_examples_for "Store" do
|
|
23
23
|
subject.identifier.should == @identifier
|
24
24
|
end
|
25
25
|
|
26
|
+
describe "namespaces" do
|
27
|
+
before(:each) do
|
28
|
+
subject.bind(@ex)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return namespace by prefix" do
|
32
|
+
subject.namespace(@ex.prefix).should == @ex
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return prefix by uri" do
|
36
|
+
subject.prefix(@ex.uri).should == @ex.prefix
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should bind namespace" do
|
40
|
+
subject.bind(@foaf).should == @foaf
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return all namespaces" do
|
44
|
+
subject.nsbinding.should == { @ex.prefix => @ex}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
26
48
|
describe "with triples" do
|
27
49
|
before(:each) do
|
28
|
-
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.jane),
|
29
|
-
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.rick),
|
30
|
-
subject.add(Triple.new(@ex.jane, @foaf.knows, @ex.rick),
|
50
|
+
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.jane), nil)
|
51
|
+
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.rick), nil)
|
52
|
+
subject.add(Triple.new(@ex.jane, @foaf.knows, @ex.rick), nil)
|
31
53
|
subject.bind(@foaf)
|
32
54
|
end
|
33
55
|
|
34
56
|
it "should detect included triple" do
|
35
|
-
subject.contains?(Triple.new(@ex.john, @foaf.knows, @ex.jane),
|
57
|
+
subject.contains?(Triple.new(@ex.john, @foaf.knows, @ex.jane), nil).should be_true
|
36
58
|
end
|
37
59
|
|
38
60
|
it "should contain different triple paterns" do
|
@@ -46,8 +68,8 @@ shared_examples_for "Store" do
|
|
46
68
|
Triple.new(URIRef.new("http://foo"),URIRef.new("http://bar"),Literal.typed("gregg", "http://www.w3.org/2001/XMLSchema#string")),
|
47
69
|
Triple.new(URIRef.new("http://foo"),URIRef.new("http://bar"),"gregg"),
|
48
70
|
].each do |t|
|
49
|
-
subject.add(t,
|
50
|
-
subject.contains?(t,
|
71
|
+
subject.add(t, nil)
|
72
|
+
subject.contains?(t, nil)
|
51
73
|
end
|
52
74
|
end
|
53
75
|
|
@@ -56,12 +78,12 @@ shared_examples_for "Store" do
|
|
56
78
|
end
|
57
79
|
|
58
80
|
it "should allow you to select resources" do
|
59
|
-
subject.triples(Triple.new(@ex.john, nil, nil),
|
81
|
+
subject.triples(Triple.new(@ex.john, nil, nil), nil).size.should == 2
|
60
82
|
end
|
61
83
|
|
62
84
|
it "should allow iteration" do
|
63
85
|
count = 0
|
64
|
-
subject.triples(Triple.new(nil, nil, nil),
|
86
|
+
subject.triples(Triple.new(nil, nil, nil), nil) do |t, context|
|
65
87
|
count = count + 1
|
66
88
|
t.class.should == Triple
|
67
89
|
end
|
@@ -70,7 +92,7 @@ shared_examples_for "Store" do
|
|
70
92
|
|
71
93
|
it "should allow iteration over a particular subject" do
|
72
94
|
count = 0
|
73
|
-
subject.triples(Triple.new(@ex.john, nil, nil),
|
95
|
+
subject.triples(Triple.new(@ex.john, nil, nil), nil) do |t, context|
|
74
96
|
count = count + 1
|
75
97
|
t.class.should == Triple
|
76
98
|
end
|
@@ -79,7 +101,7 @@ shared_examples_for "Store" do
|
|
79
101
|
|
80
102
|
it "should allow iteration over a particular predicate" do
|
81
103
|
count = 0
|
82
|
-
subject.triples(Triple.new(nil, @foaf.knows, nil),
|
104
|
+
subject.triples(Triple.new(nil, @foaf.knows, nil), nil) do |t, context|
|
83
105
|
count = count + 1
|
84
106
|
t.class.should == Triple
|
85
107
|
end
|
@@ -88,7 +110,7 @@ shared_examples_for "Store" do
|
|
88
110
|
|
89
111
|
it "should allow iteration over a particular object" do
|
90
112
|
count = 0
|
91
|
-
subject.triples(Triple.new(nil, nil, @ex.jane),
|
113
|
+
subject.triples(Triple.new(nil, nil, @ex.jane), nil) do |t, context|
|
92
114
|
count = count + 1
|
93
115
|
t.class.should == Triple
|
94
116
|
end
|
@@ -96,9 +118,9 @@ shared_examples_for "Store" do
|
|
96
118
|
end
|
97
119
|
|
98
120
|
it "should find combinations" do
|
99
|
-
subject.triples(Triple.new(@ex.john, @foaf.knows, nil),
|
100
|
-
subject.triples(Triple.new(@ex.john, nil, @ex.jane),
|
101
|
-
subject.triples(Triple.new(nil, @foaf.knows, @ex.jane),
|
121
|
+
subject.triples(Triple.new(@ex.john, @foaf.knows, nil), nil).length.should == 2
|
122
|
+
subject.triples(Triple.new(@ex.john, nil, @ex.jane), nil).length.should == 1
|
123
|
+
subject.triples(Triple.new(nil, @foaf.knows, @ex.jane), nil).length.should == 1
|
102
124
|
end
|
103
125
|
|
104
126
|
it "should retrieve indexed item" do
|
@@ -113,20 +135,19 @@ shared_examples_for "Store" do
|
|
113
135
|
|
114
136
|
describe "with typed triples" do
|
115
137
|
before(:each) do
|
116
|
-
subject.add(Triple.new(@ex.john, RDF_TYPE, @foaf.Person),
|
117
|
-
subject.add(Triple.new(@ex.jane, RDF_TYPE, @foaf.Person),
|
118
|
-
subject.add(Triple.new(@ex.rick, RDF_TYPE, @foaf.Person),
|
119
|
-
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.jane),
|
120
|
-
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.
|
121
|
-
subject.add(Triple.new(@ex.
|
122
|
-
subject.add(Triple.new(@ex.jane, @foaf.knows, @ex.rick), @ctx)
|
138
|
+
subject.add(Triple.new(@ex.john, RDF_TYPE, @foaf.Person), nil)
|
139
|
+
subject.add(Triple.new(@ex.jane, RDF_TYPE, @foaf.Person), nil)
|
140
|
+
subject.add(Triple.new(@ex.rick, RDF_TYPE, @foaf.Person), nil)
|
141
|
+
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.jane), nil)
|
142
|
+
subject.add(Triple.new(@ex.john, @foaf.knows, @ex.rick), nil)
|
143
|
+
subject.add(Triple.new(@ex.jane, @foaf.knows, @ex.rick), nil)
|
123
144
|
subject.bind(@foaf)
|
124
145
|
subject.bind(@ex)
|
125
146
|
end
|
126
147
|
|
127
148
|
it "should find subjects by type" do
|
128
149
|
count = 0
|
129
|
-
subject.triples(Triple.new(nil, RDF_TYPE, nil),
|
150
|
+
subject.triples(Triple.new(nil, RDF_TYPE, nil), nil) do |triple, ctx|
|
130
151
|
count += 1
|
131
152
|
[@ex.john, @ex.jane, @ex.rick].should include(triple.subject)
|
132
153
|
triple.predicate.should == RDF_TYPE
|
@@ -134,15 +155,19 @@ shared_examples_for "Store" do
|
|
134
155
|
end
|
135
156
|
count.should == 3
|
136
157
|
end
|
158
|
+
|
159
|
+
it "should remove types" do
|
160
|
+
subject.remove(Triple.new(nil, RDF_TYPE, nil), nil)
|
161
|
+
subject.size.should == 3
|
162
|
+
end
|
137
163
|
end
|
138
164
|
|
139
165
|
it "should remove a triple" do
|
140
|
-
subject.add(Triple.new(@ex.john, RDF_TYPE, @foaf.Person),
|
141
|
-
subject.size
|
142
|
-
subject.remove(Triple.new(@ex.john, RDF_TYPE, @foaf.Person),
|
143
|
-
subject.size
|
166
|
+
subject.add(Triple.new(@ex.john, RDF_TYPE, @foaf.Person), nil)
|
167
|
+
subject.size.should == 1
|
168
|
+
subject.remove(Triple.new(@ex.john, RDF_TYPE, @foaf.Person), nil)
|
169
|
+
subject.size.should == 0
|
144
170
|
end
|
145
|
-
|
146
171
|
end
|
147
172
|
|
148
173
|
shared_examples_for "Context Aware Store" do
|
@@ -189,6 +214,11 @@ shared_examples_for "Context Aware Store" do
|
|
189
214
|
subject.contexts.length.should == 2
|
190
215
|
end
|
191
216
|
|
217
|
+
it "should find contexts containing triple" do
|
218
|
+
subject.add(@triple, @ctx1)
|
219
|
+
subject.contexts(@triple).should == [@ctx1]
|
220
|
+
end
|
221
|
+
|
192
222
|
it "should remove from specific context" do
|
193
223
|
subject.add(@triple, @ctx1)
|
194
224
|
subject.add(@triple, @ctx2)
|