Class: RDF::List
- Inherits:
-
Object
- Object
- RDF::List
- Includes:
- Comparable, Enumerable, Value
- Defined in:
- lib/rdf/model/list.rb
Overview
An RDF list.
Constant Summary collapse
Instance Attribute Summary collapse
-
#graph ⇒ RDF::Graph
readonly
The underlying graph storing the statements that constitute this list.
-
#subject ⇒ RDF::Resource
readonly
The subject term of this list.
Class Method Summary collapse
-
.[](*values) ⇒ RDF::List
Constructs a new list from the given
values
.
Instance Method Summary collapse
-
#&(other) ⇒ RDF::List
Returns the set intersection of this list and
other
. -
#*(int_or_str) ⇒ RDF::List
Returns either a repeated list or a string concatenation of the elements in this list.
-
#+(other) ⇒ RDF::List
Returns the concatenation of this list and
other
. -
#-(other) ⇒ RDF::List
Returns the difference between this list and
other
, removing any elements that appear in both lists. -
#<<(value) ⇒ RDF::List
Appends an element to the tail of this list.
-
#<=>(other) ⇒ Integer
Compares this list to
other
for sorting purposes. - #==(other) ⇒ Object
-
#[]=(*args) ⇒ Object
Element Assignment — Sets the element at
index
, or replaces a subarray from thestart
index forlength
elements, or replaces a subarray specified by therange
of indices. -
#at(index) ⇒ RDF::Term?
(also: #nth)
Returns the element at
index
. -
#clear ⇒ RDF::List
Empties this list.
-
#each ⇒ Enumerator
Yields each element in this list.
-
#each_statement(&block) ⇒ Enumerator
(also: #to_rdf)
Yields each statement constituting this list.
-
#each_subject {|subject| ... } ⇒ Enumerator
Yields each subject term constituting this list.
-
#eighth ⇒ RDF::Term
Returns the eighth element in this list.
-
#empty? ⇒ Boolean
Returns
true
if this list is empty. -
#eql?(other) ⇒ Integer
Compares this list to
other
using eql? on each component. -
#fetch(index, default = UNSET) ⇒ RDF::Term?
Returns element at
index
with default. -
#fifth ⇒ RDF::Term
Returns the fifth element in this list.
-
#first ⇒ RDF::Term
Returns the first element in this list.
-
#first_subject ⇒ RDF::Resource
Returns the first subject term constituting this list.
-
#fourth ⇒ RDF::Term
Returns the fourth element in this list.
-
#index(value) ⇒ Integer
Returns the index of the first element equal to
value
, ornil
if no match was found. -
#initialize(subject: nil, graph: nil, values: nil, wrap_transaction: false) {|list| ... } ⇒ List
constructor
Initializes a newly-constructed list.
-
#inspect ⇒ String
Returns a developer-friendly representation of this list.
-
#join(sep = $,) ⇒ String
Returns a string created by converting each element of this list into a string, separated by
sep
. -
#last ⇒ RDF::Term
Returns the last element in this list.
-
#last_subject ⇒ RDF::Resource
Returns the last subject term constituting this list.
-
#length ⇒ Integer
(also: #size)
Returns the length of this list.
-
#list? ⇒ Boolean
Is this a List?.
-
#ninth ⇒ RDF::Term
Returns the ninth element in this list.
-
#rest ⇒ RDF::List
Returns a list containing all but the first element of this list.
- #rest_subject ⇒ RDF::Resource
-
#reverse ⇒ RDF::List
Returns the elements in this list in reversed order.
-
#second ⇒ RDF::Term
Returns the second element in this list.
-
#seventh ⇒ RDF::Term
Returns the seventh element in this list.
-
#shift ⇒ RDF::Term
Removes and returns the element at the head of this list.
-
#sixth ⇒ RDF::Term
Returns the sixth element in this list.
-
#slice(*args) ⇒ RDF::Term
(also: #[])
Returns a slice of a list.
-
#sort(&block) ⇒ RDF::List
Returns the elements in this list in sorted order.
-
#sort_by(&block) ⇒ RDF::List
Returns the elements in this list in sorted order.
-
#tail ⇒ RDF::List
Returns a list containing the last element of this list.
-
#tenth ⇒ RDF::Term
Returns the tenth element in this list.
-
#third ⇒ RDF::Term
Returns the third element in this list.
-
#to_a ⇒ Array
Returns the elements in this list as an array.
-
#to_s ⇒ String
Returns a string representation of this list.
-
#to_set ⇒ Set
Returns the elements in this list as a set.
-
#to_term ⇒ RDF::Resource
Returns the subject of the list.
-
#uniq ⇒ RDF::List
Returns a new list with the duplicates in this list removed.
-
#unshift(value) ⇒ RDF::List
Appends an element to the head of this list.
-
#valid? ⇒ Boolean
Validate the list ensuring that * each node is referenced exactly once (except for the head, which may have no reference) * rdf:rest values are all BNodes are nil * each subject has exactly one value for
rdf:first
andrdf:rest
. -
#|(other) ⇒ RDF::List
Returns the set union of this list and
other
.
Methods included from Value
#anonymous?, #canonicalize, #canonicalize!, #constant?, #graph?, #inspect!, #invalid?, #iri?, #literal?, #node?, #resource?, #start_with?, #statement?, #term?, #to_nquads, #to_ntriples, #type_error, #uri?, #validate!, #variable?
Methods included from Enumerable
#dump, #each_graph, #each_object, #each_predicate, #each_quad, #each_term, #each_triple, #enum_graph, #enum_object, #enum_predicate, #enum_quad, #enum_statement, #enum_subject, #enum_term, #enum_triple, #graph?, #graph_names, #invalid?, #method_missing, #object?, #objects, #predicate?, #predicates, #project_graph, #quad?, #quads, #respond_to_missing?, #statement?, #statements, #subject?, #subjects, #supports?, #term?, #terms, #to_h, #triple?, #triples, #validate!
Methods included from Util::Aliasing::LateBound
Methods included from Countable
Constructor Details
#initialize(subject: nil, graph: nil, values: nil, wrap_transaction: false) {|list| ... } ⇒ List
Initializes a newly-constructed list.
Instantiates a new list based at subject
, which should be an RDF::Node. List may be initialized using passed values
.
If a values
initializer is set with an empty list, subject
will be used as the first element in the list. Otherwise,
if the list is not empty, subject
identifies the first element
of the list to which values
are prepended yielding a new subject
.
Otherwise, if there are no initial values
, and subject
does
not identify an existing list in graph
, the list remains
identified by subject
, but will be invalid.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/rdf/model/list.rb', line 68 def initialize(subject: nil, graph: nil, values: nil, wrap_transaction: false, &block) @subject = subject || RDF.nil @graph = graph || RDF::Graph.new is_empty = @graph.query({subject: subject, predicate: RDF.first}).empty? if subject && is_empty # An empty list with explicit subject and value initializers @subject = RDF.nil first, *values = Array(values) if first || values.length > 0 # Intantiate the list from values, and insert the first value using subject. values.reverse_each {|value| self.unshift(value)} @graph.insert RDF::Statement(subject, RDF.first, first || RDF.nil) @graph.insert RDF::Statement(subject, RDF.rest, @subject) end @subject = subject else # Otherwise, prepend any values, which resets @subject Array(values).reverse_each {|value| self.unshift(value)} end if block_given? if wrap_transaction old_graph = @graph begin Transaction.begin(@graph, graph_name: @graph.graph_name, mutable: @graph.mutable?) do |trans| @graph = trans case block.arity when 1 then block.call(self) else instance_eval(&block) end trans.execute if trans.mutated? end ensure @graph = old_graph end else case block.arity when 1 then block.call(self) else instance_eval(&block) end end end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class RDF::Enumerable
Instance Attribute Details
#graph ⇒ RDF::Graph (readonly)
Returns the underlying graph storing the statements that constitute this list.
179 180 181 |
# File 'lib/rdf/model/list.rb', line 179 def graph @graph end |
#subject ⇒ RDF::Resource (readonly)
Returns the subject term of this list.
175 176 177 |
# File 'lib/rdf/model/list.rb', line 175 def subject @subject end |
Class Method Details
.[](*values) ⇒ RDF::List
Constructs a new list from the given values
.
The list will be identified by a new autogenerated blank node, and backed by an initially empty in-memory graph.
30 31 32 |
# File 'lib/rdf/model/list.rb', line 30 def self.[](*values) self.new(subject: nil, graph: nil, values: values) end |
Instance Method Details
#&(other) ⇒ RDF::List
Returns the set intersection of this list and other
.
The resulting list contains the elements common to both lists, with no duplicates.
202 203 204 |
# File 'lib/rdf/model/list.rb', line 202 def &(other) self.class.new(values: (to_a & other.to_a)) end |
#*(times) ⇒ RDF::List #*(sep) ⇒ RDF::List
Returns either a repeated list or a string concatenation of the elements in this list.
276 277 278 279 280 281 |
# File 'lib/rdf/model/list.rb', line 276 def *(int_or_str) case int_or_str when Integer then self.class.new(values: (to_a * int_or_str)) else join(int_or_str.to_s) end end |
#+(other) ⇒ RDF::List
Returns the concatenation of this list and other
.
233 234 235 |
# File 'lib/rdf/model/list.rb', line 233 def +(other) self.class.new(values: (to_a + other.to_a)) end |
#-(other) ⇒ RDF::List
Returns the difference between this list and other
, removing any
elements that appear in both lists.
247 248 249 |
# File 'lib/rdf/model/list.rb', line 247 def -(other) self.class.new(values: (to_a - other.to_a)) end |
#<<(value) ⇒ RDF::List
Appends an element to the tail of this list.
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
# File 'lib/rdf/model/list.rb', line 451 def <<(value) value = normalize_value(value) if empty? @subject = new_subject = RDF::Node.new else old_subject, new_subject = last_subject, RDF::Node.new graph.delete([old_subject, RDF.rest, RDF.nil]) graph.insert([old_subject, RDF.rest, new_subject]) end graph.insert([new_subject, RDF.first, value.is_a?(RDF::List) ? value.subject : value]) graph.insert([new_subject, RDF.rest, RDF.nil]) self end |
#<=>(other) ⇒ Integer
Compares this list to other
for sorting purposes.
493 494 495 |
# File 'lib/rdf/model/list.rb', line 493 def <=>(other) to_a <=> Array(other) end |
#==(other) ⇒ Object
183 184 185 186 |
# File 'lib/rdf/model/list.rb', line 183 def ==(other) return false if other.is_a?(RDF::Value) && !other.list? super end |
#[]=(index, term) ⇒ RDF::Term #[]=(start, length, value) ⇒ RDF::Term, RDF::List #[]=(range, value) ⇒ RDF::Term, RDF::List
Element Assignment — Sets the element at index
, or replaces a subarray from the start
index for length
elements, or replaces a subarray specified by the range
of indices.
If indices are greater than the current capacity of the array, the array grows automatically. Elements are inserted into the array at start
if length is zero.
Negative indices will count backward from the end of the array. For start
and range
cases the starting index is just before an element.
An IndexError
is raised if a negative index points past the beginning of the array.
(see #unshift).
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'lib/rdf/model/list.rb', line 345 def []=(*args) start, length = 0, 0 ary = self.to_a value = case args.last when Array then args.last when RDF::List then args.last.to_a else [args.last] end ret = case args.length when 3 start, length = args[0], args[1] ary[start, length] = value when 2 case args.first when Integer raise ArgumentError, "Index form of []= takes a single term" if args.last.is_a?(Array) ary[args.first] = args.last.is_a?(RDF::List) ? args.last.subject : args.last when Range ary[args.first] = value else raise ArgumentError, "Index form of must use an integer or range" end else raise ArgumentError, "List []= takes one or two index values" end # Clear the list and create a new list using the existing subject subject = @subject unless ary.empty? || @subject == RDF.nil self.clear new_list = RDF::List.new(subject: subject, graph: @graph, values: ary) @subject = new_list.subject ret # Returns inserted values end |
#at(index) ⇒ RDF::Term? Also known as: nth
Returns the element at index
.
609 610 611 612 |
# File 'lib/rdf/model/list.rb', line 609 def at(index) each.with_index { |v, i| return v if i == index } return nil end |
#clear ⇒ RDF::List
Empties this list
435 436 437 438 439 440 |
# File 'lib/rdf/model/list.rb', line 435 def clear until empty? shift end return self end |
#each ⇒ Enumerator
Yields each element in this list.
826 827 828 829 830 831 832 833 834 |
# File 'lib/rdf/model/list.rb', line 826 def each return to_enum unless block_given? each_subject do |subject| if value = graph.first_object(subject: subject, predicate: RDF.first) yield value # FIXME end end end |
#each_statement(&block) ⇒ Enumerator Also known as: to_rdf
Yields each statement constituting this list.
846 847 848 849 850 851 852 |
# File 'lib/rdf/model/list.rb', line 846 def each_statement(&block) return enum_statement unless block_given? each_subject do |subject| graph.query({subject: subject}, &block) end end |
#each_subject {|subject| ... } ⇒ Enumerator
Yields each subject term constituting this list.
803 804 805 806 807 808 809 810 811 812 813 814 |
# File 'lib/rdf/model/list.rb', line 803 def each_subject return enum_subject unless block_given? subject = self.subject yield subject loop do rest = graph.first_object(subject: subject, predicate: RDF.rest) break if rest.nil? || rest.eql?(RDF.nil) yield subject = rest end end |
#eighth ⇒ RDF::Term
Returns the eighth element in this list.
700 701 702 |
# File 'lib/rdf/model/list.rb', line 700 def eighth at(7) end |
#empty? ⇒ Boolean
Returns true
if this list is empty.
506 507 508 |
# File 'lib/rdf/model/list.rb', line 506 def empty? graph.query({subject: subject, predicate: RDF.first}).empty? end |
#eql?(other) ⇒ Integer
Compares this list to other
using eql? on each component.
478 479 480 |
# File 'lib/rdf/model/list.rb', line 478 def eql?(other) to_a.eql? Array(other) end |
#fetch(index, default = UNSET) ⇒ RDF::Term?
Returns element at index
with default.
589 590 591 592 593 594 595 596 597 598 |
# File 'lib/rdf/model/list.rb', line 589 def fetch(index, default = UNSET) val = at(index) return val unless val.nil? case when block_given? then yield index when !default.eql?(UNSET) then default else raise IndexError, "index #{index} not in the list #{self.inspect}" end end |
#fifth ⇒ RDF::Term
Returns the fifth element in this list.
667 668 669 |
# File 'lib/rdf/model/list.rb', line 667 def fifth at(4) end |
#first ⇒ RDF::Term
Returns the first element in this list.
623 624 625 |
# File 'lib/rdf/model/list.rb', line 623 def first graph.first_object(subject: first_subject, predicate: RDF.first) end |
#first_subject ⇒ RDF::Resource
Returns the first subject term constituting this list.
This is equivalent to subject
.
769 770 771 |
# File 'lib/rdf/model/list.rb', line 769 def first_subject subject end |
#fourth ⇒ RDF::Term
Returns the fourth element in this list.
656 657 658 |
# File 'lib/rdf/model/list.rb', line 656 def fourth at(3) end |
#index(value) ⇒ Integer
Returns the index of the first element equal to value
, or nil
if
no match was found.
536 537 538 539 540 541 |
# File 'lib/rdf/model/list.rb', line 536 def index(value) each.with_index do |v, i| return i if v == value end return nil end |
#inspect ⇒ String
Returns a developer-friendly representation of this list.
973 974 975 976 977 978 979 |
# File 'lib/rdf/model/list.rb', line 973 def inspect if self.equal?(NIL) 'RDF::List::NIL' else sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, join(', ')) end end |
#join(sep = $,) ⇒ String
Returns a string created by converting each element of this list into
a string, separated by sep
.
866 867 868 |
# File 'lib/rdf/model/list.rb', line 866 def join(sep = $,) map(&:to_s).join(sep) end |
#last ⇒ RDF::Term
Returns the last element in this list.
734 735 736 |
# File 'lib/rdf/model/list.rb', line 734 def last graph.first_object(subject: last_subject, predicate: RDF.first) end |
#last_subject ⇒ RDF::Resource
Returns the last subject term constituting this list.
789 790 791 |
# File 'lib/rdf/model/list.rb', line 789 def last_subject each_subject.to_a.last # TODO: optimize this end |
#length ⇒ Integer Also known as: size
Returns the length of this list.
519 520 521 |
# File 'lib/rdf/model/list.rb', line 519 def length each.count end |
#list? ⇒ Boolean
Is this a RDF::List?
122 123 124 |
# File 'lib/rdf/model/list.rb', line 122 def list? true end |
#ninth ⇒ RDF::Term
Returns the ninth element in this list.
711 712 713 |
# File 'lib/rdf/model/list.rb', line 711 def ninth at(8) end |
#rest ⇒ RDF::List
Returns a list containing all but the first element of this list.
745 746 747 |
# File 'lib/rdf/model/list.rb', line 745 def rest (subject = rest_subject).eql?(RDF.nil) ? nil : self.class.new(subject: subject, graph: graph) end |
#rest_subject ⇒ RDF::Resource
778 779 780 |
# File 'lib/rdf/model/list.rb', line 778 def rest_subject graph.first_object(subject: subject, predicate: RDF.rest) end |
#reverse ⇒ RDF::List
Returns the elements in this list in reversed order.
878 879 880 |
# File 'lib/rdf/model/list.rb', line 878 def reverse self.class.new(values: to_a.reverse) end |
#second ⇒ RDF::Term
Returns the second element in this list.
634 635 636 |
# File 'lib/rdf/model/list.rb', line 634 def second at(1) end |
#seventh ⇒ RDF::Term
Returns the seventh element in this list.
689 690 691 |
# File 'lib/rdf/model/list.rb', line 689 def seventh at(6) end |
#shift ⇒ RDF::Term
Removes and returns the element at the head of this list.
414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'lib/rdf/model/list.rb', line 414 def shift return nil if empty? value = first old_subject, new_subject = subject, rest_subject graph.delete([old_subject, RDF.type, RDF.List]) graph.delete([old_subject, RDF.first, value]) graph.delete([old_subject, RDF.rest, new_subject]) @subject = new_subject return value end |
#sixth ⇒ RDF::Term
Returns the sixth element in this list.
678 679 680 |
# File 'lib/rdf/model/list.rb', line 678 def sixth at(5) end |
#slice(*args) ⇒ RDF::Term Also known as: []
Returns a slice of a list.
553 554 555 556 557 558 559 560 |
# File 'lib/rdf/model/list.rb', line 553 def slice(*args) case argc = args.size when 2 then slice_with_start_and_length(*args) when 1 then (arg = args.first).is_a?(Range) ? slice_with_range(arg) : at(arg) when 0 then raise ArgumentError, "wrong number of arguments (0 for 1)" else raise ArgumentError, "wrong number of arguments (#{argc} for 2)" end end |
#sort(&block) ⇒ RDF::List
Returns the elements in this list in sorted order.
890 891 892 |
# File 'lib/rdf/model/list.rb', line 890 def sort(&block) self.class.new(values: super) end |
#sort_by(&block) ⇒ RDF::List
Returns the elements in this list in sorted order.
902 903 904 |
# File 'lib/rdf/model/list.rb', line 902 def sort_by(&block) self.class.new(values: super) end |
#tail ⇒ RDF::List
Returns a list containing the last element of this list.
756 757 758 |
# File 'lib/rdf/model/list.rb', line 756 def tail (subject = last_subject).eql?(RDF.nil) ? nil : self.class.new(subject: subject, graph: graph) end |
#tenth ⇒ RDF::Term
Returns the tenth element in this list.
722 723 724 |
# File 'lib/rdf/model/list.rb', line 722 def tenth at(9) end |
#third ⇒ RDF::Term
Returns the third element in this list.
645 646 647 |
# File 'lib/rdf/model/list.rb', line 645 def third at(2) end |
#to_a ⇒ Array
Returns the elements in this list as an array.
926 927 928 |
# File 'lib/rdf/model/list.rb', line 926 def to_a each.to_a end |
#to_s ⇒ String
Returns a string representation of this list.
962 963 964 |
# File 'lib/rdf/model/list.rb', line 962 def to_s 'RDF::List[' + join(', ') + ']' end |
#to_set ⇒ Set
Returns the elements in this list as a set.
937 938 939 940 |
# File 'lib/rdf/model/list.rb', line 937 def to_set require 'set' unless defined?(::Set) each.to_set end |
#to_term ⇒ RDF::Resource
Returns the subject of the list.
950 951 952 |
# File 'lib/rdf/model/list.rb', line 950 def to_term subject end |
#uniq ⇒ RDF::List
Returns a new list with the duplicates in this list removed.
914 915 916 |
# File 'lib/rdf/model/list.rb', line 914 def uniq self.class.new(values: to_a.uniq) end |
#unshift(value) ⇒ RDF::List
Appends an element to the head of this list. Existing references are not updated, as the list subject changes as a side-effect.
393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'lib/rdf/model/list.rb', line 393 def unshift(value) value = normalize_value(value) new_subject, old_subject = RDF::Node.new, subject graph.insert([new_subject, RDF.first, value.is_a?(RDF::List) ? value.subject : value]) graph.insert([new_subject, RDF.rest, old_subject]) @subject = new_subject return self end |
#valid? ⇒ Boolean
Validate the list ensuring that
- each node is referenced exactly once (except for the head, which may have no reference)
- rdf:rest values are all BNodes are nil
- each subject has exactly one value for
rdf:first
andrdf:rest
. - The value of
rdf:rest
must be either a BNode orrdf:nil
. - only the list head may have any other properties
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/rdf/model/list.rb', line 135 def valid? li = subject list_nodes = [] while li != RDF.nil do return false if list_nodes.include?(li) list_nodes << li rest = nil firsts = rests = 0 @graph.query({subject: li}) do |st| return false unless st.subject.node? case st.predicate when RDF.first firsts += 1 when RDF.rest rest = st.object return false unless rest.node? || rest == RDF.nil rests += 1 when RDF.type else # It may have no other properties return false unless li == subject end end return false unless firsts == 1 && rests == 1 li = rest end # All elements other than the head must be referenced exactly once return list_nodes.all? do |li| refs = @graph.query({object: li}).count case refs when 0 then li == subject when 1 then true else false end end end |
#|(other) ⇒ RDF::List
Returns the set union of this list and other
.
The resulting list contains the elements from both lists, with no duplicates.
220 221 222 |
# File 'lib/rdf/model/list.rb', line 220 def |(other) self.class.new(values: (to_a | other.to_a)) end |