active-triples 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGES.md +17 -11
- data/README.md +72 -39
- data/lib/active_triples/configurable.rb +6 -1
- data/lib/active_triples/list.rb +1 -4
- data/lib/active_triples/nested_attributes.rb +10 -7
- data/lib/active_triples/persistable.rb +13 -0
- data/lib/active_triples/persistence_strategies/parent_strategy.rb +47 -34
- data/lib/active_triples/persistence_strategies/persistence_strategy.rb +14 -1
- data/lib/active_triples/properties.rb +19 -4
- data/lib/active_triples/property_builder.rb +4 -4
- data/lib/active_triples/rdf_source.rb +142 -189
- data/lib/active_triples/relation.rb +307 -156
- data/lib/active_triples/util/buffered_transaction.rb +126 -0
- data/lib/active_triples/util/extended_bounded_description.rb +75 -0
- data/lib/active_triples/version.rb +1 -1
- data/spec/active_triples/configurable_spec.rb +35 -7
- data/spec/active_triples/identifiable_spec.rb +19 -6
- data/spec/active_triples/list_spec.rb +15 -7
- data/spec/active_triples/nested_attributes_spec.rb +12 -10
- data/spec/active_triples/persistable_spec.rb +0 -4
- data/spec/active_triples/persistence_strategies/parent_strategy_spec.rb +57 -10
- data/spec/active_triples/rdf_source_spec.rb +137 -97
- data/spec/active_triples/relation_spec.rb +436 -132
- data/spec/active_triples/resource_spec.rb +8 -23
- data/spec/active_triples/util/buffered_transaction_spec.rb +187 -0
- data/spec/active_triples/util/extended_bounded_description_spec.rb +98 -0
- data/spec/integration/reciprocal_properties_spec.rb +10 -10
- data/spec/support/matchers.rb +13 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b09ad8aa6210e931834cd37965ea5664d84ef2e3
|
4
|
+
data.tar.gz: 0a33346408aaf322d817c8cb2081a2c7542ef0da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35628f4606ba23ab183d20d2bd6bc67ee39b1285b5c21e1d4d19bc9b3316ed7af3b55fdf2b44b8a431129a2a778f6e7c8c403c934d308dba9fb34843f7fac599
|
7
|
+
data.tar.gz: b8c3662e7f66c4e720e1b8db88314bd6f7b931e8a7b127f393f44e8ce8969ddcd607171abd03505f18fba25972235e6bc7288dd9943b7c2ef7bd385cc9626c73
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,16 +1,22 @@
|
|
1
|
-
0.
|
1
|
+
0.11.0
|
2
2
|
----
|
3
|
-
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
- Reworks ParentStrategy to use an Transaction over a well defined
|
4
|
+
"extended bounded description".
|
5
|
+
- Converts Relation to an Enumerable for more efficient access to
|
6
|
+
property values.
|
7
|
+
- Cleans up .Relation equality and added `#|` & `#&` for Set style
|
8
|
+
comparison.
|
9
|
+
- Deprecates `Relation#first_or_create`.
|
10
|
+
- Removes dependency on the `linkeddata` gem. Users should require
|
11
|
+
individual RDF libraries as needed.
|
12
|
+
- Adds inheritance of configured types when subclassing an
|
13
|
+
`RDFSource`.
|
14
|
+
- Uses `URI#intern` to avoid repeated allocations of common URIs.
|
15
|
+
- Changes handling of language and datatyped Literals in
|
16
|
+
`Relation#each` & `#to_a`;
|
17
|
+
- now returns `RDF::Literal` for lanugage tagged strings and
|
18
|
+
for unknown datatypes.
|
9
19
|
|
10
|
-
0.10.1
|
11
|
-
----
|
12
|
-
- Remove dependency on the `linkeddata` metagem
|
13
|
-
|
14
20
|
0.10.0
|
15
21
|
----
|
16
22
|
- Fix Identifiable for ActiveFedora [Trey Pendragon]
|
data/README.md
CHANGED
@@ -23,36 +23,47 @@ The core module of `ActiveTriples` is `ActiveTriples::RDFSource`. You can use th
|
|
23
23
|
|
24
24
|
|
25
25
|
```ruby
|
26
|
+
require 'rdf/vocab'
|
27
|
+
|
26
28
|
class Thing
|
27
29
|
include ActiveTriples::RDFSource
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
|
31
|
+
configure type: RDF::OWL.Thing, base_uri: 'http://example.org/things#'
|
32
|
+
|
33
|
+
property :title, predicate: RDF::Vocab::DC.title
|
34
|
+
property :description, predicate: RDF::Vocab::DC.description
|
31
35
|
end
|
32
36
|
|
33
|
-
obj
|
34
|
-
obj.title
|
37
|
+
obj = Thing.new('123')
|
38
|
+
obj.title = 'Resource'
|
35
39
|
obj.description = 'A resource.'
|
40
|
+
|
36
41
|
obj.dump :ntriples # => "<http://example.org/things#123> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Thing> .\n<http://example.org/things#123> <http://purl.org/dc/terms/title> \"Resource\" .\n<http://example.org/things#123> <http://purl.org/dc/terms/description> \"A resource.\" .\n"
|
37
42
|
```
|
43
|
+
|
38
44
|
URI and bnode values are built out as generic Resources when accessed. A more specific model class can be configured on individual properties.
|
39
45
|
|
40
46
|
```ruby
|
41
|
-
Thing.property :creator, :
|
47
|
+
Thing.property :creator, predicate: RDF::Vocab::DC.creator, class_name: 'Person'
|
42
48
|
|
43
49
|
class Person
|
44
50
|
include ActiveTriples::RDFSource
|
45
|
-
|
46
|
-
|
51
|
+
|
52
|
+
configure type: RDF::Vocab::FOAF.Person,
|
53
|
+
base_uri: 'http://example.org/people#'
|
54
|
+
|
55
|
+
property :name, predicate: RDF::Vocab::FOAF.name
|
47
56
|
end
|
48
57
|
|
49
|
-
obj_2
|
58
|
+
obj_2 = Thing.new('2')
|
50
59
|
obj_2.creator = Person.new
|
60
|
+
|
51
61
|
obj_2.creator
|
52
62
|
# => [#<Person:0x3fbe84ac9234(default)>]
|
53
63
|
|
54
64
|
obj_2.creator.first.name = 'Herman Melville'
|
55
|
-
|
65
|
+
|
66
|
+
obj_2.dump :ntriples # => "_:g47361345336040 <http://xmlns.com/foaf/0.1/name> \"Herman Melville\" .\n_:g47361345336040 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .\n<http://example.org/things#2> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Thing> .\n<http://example.org/things#2> <http://purl.org/dc/terms/creator> _:g47361345336040 .\n"
|
56
67
|
```
|
57
68
|
|
58
69
|
Open Model
|
@@ -63,23 +74,33 @@ An RDFSource lets you handle data as a graph, independent of whether it is defin
|
|
63
74
|
```ruby
|
64
75
|
related = Thing.new
|
65
76
|
|
66
|
-
related << RDF::Statement(related, RDF::DC.relation, obj)
|
67
|
-
related << RDF::Statement(related, RDF::DC.subject, 'ActiveTriples')
|
77
|
+
related << RDF::Statement(related, RDF::Vocab::DC.relation, obj)
|
78
|
+
related << RDF::Statement(related, RDF::Vocab::DC.subject, 'ActiveTriples')
|
68
79
|
|
69
|
-
related.query(:
|
70
|
-
|
71
|
-
|
80
|
+
related.query(subject: related,
|
81
|
+
predicate: RDF::Vocab::DC.relation).each_statement do |s,p,o|
|
82
|
+
puts o
|
83
|
+
end
|
72
84
|
# => http://example.org/things#123
|
85
|
+
|
86
|
+
related.query(subject: related,
|
87
|
+
predicate: RDF::Vocab::DC.subject).each_statement do |s,p,o|
|
88
|
+
puts o
|
89
|
+
end
|
90
|
+
# => 'ActiveTriples'
|
73
91
|
```
|
74
92
|
|
75
93
|
Any operation you can run against an RDF::Graph works with RDFSources, too. Or you can use generic setters and getters with URI predicates:
|
76
94
|
|
77
95
|
```ruby
|
78
|
-
related.set_value(RDF::DC.relation, obj)
|
79
|
-
related.set_value(RDF::DC.subject,
|
96
|
+
related.set_value(RDF::Vocab::DC.relation, obj)
|
97
|
+
related.set_value(RDF::Vocab::DC.subject, 'ActiveTriples')
|
98
|
+
|
99
|
+
related.get_values(RDF::Vocab::DC.relation)
|
100
|
+
# => [#<Thing:0x3f949c6a2294(default)>]
|
80
101
|
|
81
|
-
related.get_values(RDF::DC.
|
82
|
-
|
102
|
+
related.get_values(RDF::Vocab::DC.subject)
|
103
|
+
# => ["ActiveTriples"]
|
83
104
|
```
|
84
105
|
|
85
106
|
Some convienience methods provide support for handling data from web sources:
|
@@ -89,10 +110,13 @@ Some convienience methods provide support for handling data from web sources:
|
|
89
110
|
```ruby
|
90
111
|
require 'linkeddata' # to support various serializations
|
91
112
|
|
92
|
-
|
113
|
+
uri = 'http://dbpedia.org/resource/Oregon_State_University'
|
114
|
+
|
115
|
+
osu = ActiveTriples::Resource.new uri
|
93
116
|
osu.fetch
|
94
117
|
|
95
|
-
osu.rdf_label
|
118
|
+
osu.rdf_label
|
119
|
+
# => ["Oregon State University", "Oregon State University", "Université d'État de l'Oregon", "Oregon State University", "Oregon State University", "オレゴン州立大学", "Universidad Estatal de Oregón", "Oregon State University", "俄勒岡州立大學", "Universidade do Estado do Oregon"]
|
96
120
|
```
|
97
121
|
|
98
122
|
Typed Data
|
@@ -101,9 +125,9 @@ Typed Data
|
|
101
125
|
Typed literals are handled natively through Ruby types and [RDF::Literal](https://github.com/ruby-rdf/rdf/tree/develop/lib/rdf/model/literal). There is no need to register a specific type for a property, simply pass the setter the appropriate typed data. See the examples in the RDF::Literal documentation for futher information about supported datatypes.
|
102
126
|
|
103
127
|
```ruby
|
104
|
-
Thing.property :date, :
|
128
|
+
Thing.property :date, predicate: RDF::Vocab::DC.date
|
105
129
|
|
106
|
-
my_thing
|
130
|
+
my_thing = Thing.new
|
107
131
|
my_thing.date = Date.today
|
108
132
|
|
109
133
|
puts my_thing.dump :ntriples
|
@@ -143,38 +167,47 @@ Resources can persist to various databases and triplestores though integration w
|
|
143
167
|
# RDF::Repository support persistence to (e.g.) triplestores & NoSQL
|
144
168
|
# databases.
|
145
169
|
ActiveTriples::Repositories.add_repository :default, RDF::Repository.new
|
146
|
-
ActiveTriples::Repositories.add_repository :people,
|
170
|
+
ActiveTriples::Repositories.add_repository :people, RDF::Repository.new
|
147
171
|
|
148
172
|
class Person
|
149
173
|
include ActiveTriples::RDFSource
|
150
|
-
|
151
|
-
|
174
|
+
|
175
|
+
configure type: RDF::Vocab::FOAF.Person,
|
176
|
+
base_uri: 'http://example.org/people#',
|
177
|
+
repository: :people
|
178
|
+
property :name, predicate: RDF::Vocab::FOAF.name
|
152
179
|
end
|
153
180
|
|
154
181
|
class Thing
|
155
182
|
include ActiveTriples::RDFSource
|
156
183
|
|
157
|
-
configure :
|
158
|
-
|
159
|
-
|
160
|
-
|
184
|
+
configure type: RDF::OWL.Thing,
|
185
|
+
base_uri: 'http://example.org/things#',
|
186
|
+
repository: :default
|
187
|
+
|
188
|
+
property :title, predicate: RDF::Vocab::DC.title
|
189
|
+
property :description, predicate: RDF::Vocab::DC.description
|
190
|
+
property :creator, predicate: RDF::Vocab::DC.creator, class_name: 'Person'
|
161
191
|
end
|
162
192
|
|
163
|
-
t
|
164
|
-
t.title
|
193
|
+
t = Thing.new('1')
|
194
|
+
t.title = 'A Thing'
|
165
195
|
t.creator = Person.new('1')
|
196
|
+
|
166
197
|
t.persisted? # => false
|
167
|
-
t.creator.first.name = 'Tove'
|
168
|
-
t.persist!
|
169
198
|
|
170
199
|
ActiveTriples::Repositories.repositories[:default].dump :ntriples
|
171
|
-
# => "
|
200
|
+
# => ""
|
172
201
|
|
173
|
-
t.creator.first.
|
174
|
-
t.
|
202
|
+
t.creator.first.name = 'Tove'
|
203
|
+
t.persist!
|
175
204
|
|
176
|
-
ActiveTriples::Repositories.repositories[:
|
177
|
-
#
|
205
|
+
puts ActiveTriples::Repositories.repositories[:default].dump :ntriples
|
206
|
+
# <http://example.org/things#1> <http://purl.org/dc/terms/title> "A Thing" .
|
207
|
+
# <http://example.org/things#1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Thing> .
|
208
|
+
# <http://example.org/things#1> <http://purl.org/dc/terms/creator> <http://example.org/people#1> .
|
209
|
+
# <http://example.org/people#1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Person> .
|
210
|
+
# <http://example.org/people#1> <http://xmlns.com/foaf/0.1/name> "Tove" .
|
178
211
|
```
|
179
212
|
|
180
213
|
Contributing
|
@@ -14,6 +14,11 @@ module ActiveTriples
|
|
14
14
|
#
|
15
15
|
# Available properties are base_uri, rdf_label, type, and repository
|
16
16
|
module Configurable
|
17
|
+
def inherited(child_class)
|
18
|
+
child_class.configure type: self.type
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
17
22
|
def base_uri
|
18
23
|
configuration[:base_uri]
|
19
24
|
end
|
@@ -62,7 +67,7 @@ module ActiveTriples
|
|
62
67
|
|
63
68
|
def transform_type(values)
|
64
69
|
Array.wrap(values).map do |value|
|
65
|
-
RDF::URI.
|
70
|
+
RDF::URI.intern(value).tap do |uri|
|
66
71
|
RDFSource.type_registry[uri] = self
|
67
72
|
end
|
68
73
|
end
|
data/lib/active_triples/list.rb
CHANGED
@@ -37,15 +37,15 @@ module ActiveTriples
|
|
37
37
|
# { name: 'John' },
|
38
38
|
# { id: '2', _destroy: true }
|
39
39
|
# ])
|
40
|
-
def assign_nested_attributes_for_collection_association(association_name,
|
40
|
+
def assign_nested_attributes_for_collection_association(association_name,
|
41
|
+
attributes_collection)
|
41
42
|
options = self.nested_attributes_options[association_name]
|
42
43
|
|
43
44
|
# TODO
|
44
45
|
#check_record_limit!(options[:limit], attributes_collection)
|
45
46
|
|
46
|
-
|
47
|
-
attributes_collection
|
48
|
-
end
|
47
|
+
attributes_collection = attributes_collection.values if
|
48
|
+
attributes_collection.is_a?(Hash)
|
49
49
|
|
50
50
|
association = self.send(association_name)
|
51
51
|
|
@@ -53,8 +53,9 @@ module ActiveTriples
|
|
53
53
|
attributes = attributes.with_indifferent_access
|
54
54
|
|
55
55
|
if !call_reject_if(association_name, attributes)
|
56
|
-
if attributes['id'] &&
|
57
|
-
|
56
|
+
if attributes['id'] &&
|
57
|
+
existing_record = association.detect { |record| record.rdf_subject.to_s == attributes['id'].to_s }
|
58
|
+
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
|
58
59
|
else
|
59
60
|
association.build(attributes.except(*UNASSIGNABLE_KEYS))
|
60
61
|
end
|
@@ -66,7 +67,9 @@ module ActiveTriples
|
|
66
67
|
# +allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
|
67
68
|
def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
|
68
69
|
record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
|
69
|
-
|
70
|
+
|
71
|
+
record.mark_for_destruction if has_destroy_flag?(attributes) &&
|
72
|
+
allow_destroy
|
70
73
|
end
|
71
74
|
|
72
75
|
def call_reject_if(association_name, attributes)
|
@@ -14,6 +14,19 @@ module ActiveTriples
|
|
14
14
|
include RDF::Enumerable
|
15
15
|
include RDF::Mutable
|
16
16
|
|
17
|
+
##
|
18
|
+
# This gives the {RDF::Graph} which represents the current state of this
|
19
|
+
# resource.
|
20
|
+
#
|
21
|
+
# @return [RDF::Graph] the underlying graph representation of the
|
22
|
+
# `RDFSource`.
|
23
|
+
#
|
24
|
+
# @see http://www.w3.org/TR/2014/REC-rdf11-concepts-20140225/#change-over-time
|
25
|
+
# RDF Concepts and Abstract Syntax comment on "RDF source"
|
26
|
+
def graph
|
27
|
+
persistence_strategy.graph
|
28
|
+
end
|
29
|
+
|
17
30
|
##
|
18
31
|
# @see RDF::Enumerable.each
|
19
32
|
def each(*args)
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'active_triples/util/buffered_transaction'
|
3
|
+
|
2
4
|
module ActiveTriples
|
3
5
|
##
|
4
6
|
# Persistence strategy for projecting `RDFSource`s onto the graph of an owning
|
@@ -17,9 +19,31 @@ module ActiveTriples
|
|
17
19
|
# @param source [RDFSource, RDF::Enumerable] the `RDFSource` (or other
|
18
20
|
# `RDF::Enumerable` to persist with the strategy.
|
19
21
|
def initialize(source)
|
22
|
+
@graph = source.graph
|
20
23
|
@source = source
|
21
24
|
end
|
22
25
|
|
26
|
+
##
|
27
|
+
# @see PeristenceStrategy#graph=
|
28
|
+
def graph=(graph)
|
29
|
+
final_parent.insert(graph || source.to_a)
|
30
|
+
@graph = BufferedTransaction.begin(parent,
|
31
|
+
mutable: true,
|
32
|
+
subject: source.to_term)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# @return [ActiveTriples::BufferedTransaction] a transaction on parent with
|
37
|
+
# buffered changes, with reads projected against an "Extended Bounded
|
38
|
+
# Description" of the strategy's `#source`.
|
39
|
+
#
|
40
|
+
# @see ActiveTriples::ExtendedBoundedDescription
|
41
|
+
def graph
|
42
|
+
@graph ||= BufferedTransaction.begin(parent,
|
43
|
+
mutable: true,
|
44
|
+
subject: source.to_term)
|
45
|
+
end
|
46
|
+
|
23
47
|
##
|
24
48
|
# Resources using this strategy are persisted only if their parent is also
|
25
49
|
# persisted.
|
@@ -29,41 +53,23 @@ module ActiveTriples
|
|
29
53
|
super && parent.persisted?
|
30
54
|
end
|
31
55
|
|
32
|
-
##
|
33
|
-
# Indicates if the resource has been loaded from the repository (used for lazy load)
|
34
|
-
#
|
35
|
-
# @return [Boolean] true if loaded; else false.
|
36
|
-
def loaded?
|
37
|
-
@loaded ||= false
|
38
|
-
end
|
39
|
-
|
40
56
|
##
|
41
57
|
# Destroys the resource by removing it graph and references from the
|
42
58
|
# parent.
|
43
59
|
#
|
44
60
|
# @see PersistenceStrategy#destroy
|
45
61
|
def destroy
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
parent.delete_statement(statement) if
|
50
|
-
statement.subject == source.rdf_subject ||
|
51
|
-
statement.object == source.rdf_subject
|
62
|
+
super do
|
63
|
+
graph.delete [source.to_term, nil, nil]
|
64
|
+
parent.delete [parent, nil, source.to_term]
|
52
65
|
end
|
53
|
-
|
54
|
-
super { source.clear }
|
55
66
|
end
|
56
67
|
|
57
68
|
##
|
58
69
|
# @abstract Clear out any old assertions in the datastore / repository
|
59
|
-
# about this node
|
70
|
+
# about this node or statement thus preparing to receive the updated
|
60
71
|
# assertions.
|
61
|
-
def erase_old_resource
|
62
|
-
final_parent.statements.each do |statement|
|
63
|
-
final_parent.send(:delete_statement, statement) if
|
64
|
-
statement.subject == source.rdf_subject
|
65
|
-
end
|
66
|
-
end
|
72
|
+
def erase_old_resource; end # noop
|
67
73
|
|
68
74
|
##
|
69
75
|
# @return [Enumerator<RDFSource>]
|
@@ -87,7 +93,9 @@ module ActiveTriples
|
|
87
93
|
def parent=(parent)
|
88
94
|
raise UnmutableParentError unless parent.is_a? RDF::Mutable
|
89
95
|
raise UnmutableParentError unless parent.mutable?
|
96
|
+
|
90
97
|
@parent = parent
|
98
|
+
reload
|
91
99
|
end
|
92
100
|
|
93
101
|
##
|
@@ -95,9 +103,16 @@ module ActiveTriples
|
|
95
103
|
#
|
96
104
|
# @return [true] true if the save did not error
|
97
105
|
def persist!
|
106
|
+
raise NilParentError unless parent
|
98
107
|
return false if final_parent.frozen?
|
99
|
-
|
100
|
-
|
108
|
+
|
109
|
+
graph.execute
|
110
|
+
|
111
|
+
parent.persist! if
|
112
|
+
ancestors.find { |a| a.is_a?(ActiveTriples::List::ListResource) }
|
113
|
+
|
114
|
+
reload
|
115
|
+
|
101
116
|
@persisted = true
|
102
117
|
end
|
103
118
|
|
@@ -107,14 +122,12 @@ module ActiveTriples
|
|
107
122
|
# @return [Boolean]
|
108
123
|
def reload
|
109
124
|
return false if source.frozen?
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
@persisted = true unless source.empty?
|
125
|
+
|
126
|
+
final_parent.persistence_strategy.class.new(source).reload
|
127
|
+
self.graph = source.to_a
|
128
|
+
|
129
|
+
@persisted = true unless graph.empty?
|
130
|
+
|
118
131
|
true
|
119
132
|
end
|
120
133
|
|
@@ -132,7 +145,7 @@ module ActiveTriples
|
|
132
145
|
def initialize(source)
|
133
146
|
@source = source
|
134
147
|
end
|
135
|
-
|
148
|
+
|
136
149
|
##
|
137
150
|
# @yield [RDFSource] gives each ancestor to the block
|
138
151
|
# @return [Enumerator<RDFSource>]
|