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 the `start` index for `length` elements, or replaces a subarray specified by the `range` 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`, or `nil` 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` and `rdf: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
#canonicalize, #canonicalize!, #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?, #object?, #objects, #predicate?, #predicates, #project_graph, #quad?, #quads, #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.
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/rdf/model/list.rb', line 438 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.
480 481 482 |
# File 'lib/rdf/model/list.rb', line 480 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).
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/rdf/model/list.rb', line 332 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`.
596 597 598 599 |
# File 'lib/rdf/model/list.rb', line 596 def at(index) each.with_index { |v, i| return v if i == index } return nil end |
#clear ⇒ RDF::List
Empties this list
422 423 424 425 426 427 |
# File 'lib/rdf/model/list.rb', line 422 def clear until empty? shift end return self end |
#each ⇒ Enumerator
Yields each element in this list.
813 814 815 816 817 818 819 820 821 |
# File 'lib/rdf/model/list.rb', line 813 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.
833 834 835 836 837 838 839 |
# File 'lib/rdf/model/list.rb', line 833 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.
790 791 792 793 794 795 796 797 798 799 800 801 |
# File 'lib/rdf/model/list.rb', line 790 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.
687 688 689 |
# File 'lib/rdf/model/list.rb', line 687 def eighth at(7) end |
#empty? ⇒ Boolean
Returns ‘true` if this list is empty.
493 494 495 |
# File 'lib/rdf/model/list.rb', line 493 def empty? graph.query({subject: subject, predicate: RDF.first}).empty? end |
#eql?(other) ⇒ Integer
Compares this list to ‘other` using eql? on each component.
465 466 467 |
# File 'lib/rdf/model/list.rb', line 465 def eql?(other) to_a.eql? Array(other) end |
#fetch(index, default = UNSET) ⇒ RDF::Term?
Returns element at ‘index` with default.
576 577 578 579 580 581 582 583 584 585 |
# File 'lib/rdf/model/list.rb', line 576 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.
654 655 656 |
# File 'lib/rdf/model/list.rb', line 654 def fifth at(4) end |
#first ⇒ RDF::Term
Returns the first element in this list.
610 611 612 |
# File 'lib/rdf/model/list.rb', line 610 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`.
756 757 758 |
# File 'lib/rdf/model/list.rb', line 756 def first_subject subject end |
#fourth ⇒ RDF::Term
Returns the fourth element in this list.
643 644 645 |
# File 'lib/rdf/model/list.rb', line 643 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.
523 524 525 526 527 528 |
# File 'lib/rdf/model/list.rb', line 523 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.
960 961 962 963 964 965 966 |
# File 'lib/rdf/model/list.rb', line 960 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`.
853 854 855 |
# File 'lib/rdf/model/list.rb', line 853 def join(sep = $,) map(&:to_s).join(sep) end |
#last ⇒ RDF::Term
Returns the last element in this list.
721 722 723 |
# File 'lib/rdf/model/list.rb', line 721 def last graph.first_object(subject: last_subject, predicate: RDF.first) end |
#last_subject ⇒ RDF::Resource
Returns the last subject term constituting this list.
776 777 778 |
# File 'lib/rdf/model/list.rb', line 776 def last_subject each_subject.to_a.last # TODO: optimize this end |
#length ⇒ Integer Also known as: size
Returns the length of this list.
506 507 508 |
# File 'lib/rdf/model/list.rb', line 506 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.
698 699 700 |
# File 'lib/rdf/model/list.rb', line 698 def ninth at(8) end |
#rest ⇒ RDF::List
Returns a list containing all but the first element of this list.
732 733 734 |
# File 'lib/rdf/model/list.rb', line 732 def rest (subject = rest_subject).eql?(RDF.nil) ? nil : self.class.new(subject: subject, graph: graph) end |
#rest_subject ⇒ RDF::Resource
765 766 767 |
# File 'lib/rdf/model/list.rb', line 765 def rest_subject graph.first_object(subject: subject, predicate: RDF.rest) end |
#reverse ⇒ RDF::List
Returns the elements in this list in reversed order.
865 866 867 |
# File 'lib/rdf/model/list.rb', line 865 def reverse self.class.new(values: to_a.reverse) end |
#second ⇒ RDF::Term
Returns the second element in this list.
621 622 623 |
# File 'lib/rdf/model/list.rb', line 621 def second at(1) end |
#seventh ⇒ RDF::Term
Returns the seventh element in this list.
676 677 678 |
# File 'lib/rdf/model/list.rb', line 676 def seventh at(6) end |
#shift ⇒ RDF::Term
Removes and returns the element at the head of this list.
401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/rdf/model/list.rb', line 401 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.
665 666 667 |
# File 'lib/rdf/model/list.rb', line 665 def sixth at(5) end |
#slice(*args) ⇒ RDF::Term Also known as: []
Returns a slice of a list.
540 541 542 543 544 545 546 547 |
# File 'lib/rdf/model/list.rb', line 540 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.
877 878 879 |
# File 'lib/rdf/model/list.rb', line 877 def sort(&block) self.class.new(values: super) end |
#sort_by(&block) ⇒ RDF::List
Returns the elements in this list in sorted order.
889 890 891 |
# File 'lib/rdf/model/list.rb', line 889 def sort_by(&block) self.class.new(values: super) end |
#tail ⇒ RDF::List
Returns a list containing the last element of this list.
743 744 745 |
# File 'lib/rdf/model/list.rb', line 743 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.
709 710 711 |
# File 'lib/rdf/model/list.rb', line 709 def tenth at(9) end |
#third ⇒ RDF::Term
Returns the third element in this list.
632 633 634 |
# File 'lib/rdf/model/list.rb', line 632 def third at(2) end |
#to_a ⇒ Array
Returns the elements in this list as an array.
913 914 915 |
# File 'lib/rdf/model/list.rb', line 913 def to_a each.to_a end |
#to_s ⇒ String
Returns a string representation of this list.
949 950 951 |
# File 'lib/rdf/model/list.rb', line 949 def to_s 'RDF::List[' + join(', ') + ']' end |
#to_set ⇒ Set
Returns the elements in this list as a set.
924 925 926 927 |
# File 'lib/rdf/model/list.rb', line 924 def to_set require 'set' unless defined?(::Set) each.to_set end |
#to_term ⇒ RDF::Resource
Returns the subject of the list.
937 938 939 |
# File 'lib/rdf/model/list.rb', line 937 def to_term subject end |
#uniq ⇒ RDF::List
Returns a new list with the duplicates in this list removed.
901 902 903 |
# File 'lib/rdf/model/list.rb', line 901 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.
380 381 382 383 384 385 386 387 388 389 390 391 |
# File 'lib/rdf/model/list.rb', line 380 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` and `rdf:rest`.
-
The value of ‘rdf:rest` must be either a BNode or `rdf: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 |