Class: RDF::N3::List
Overview
Sub-class of RDF::List which uses a native representation of values and allows recursive lists.
Also serves as the vocabulary URI for expanding other methods
Constant Summary collapse
- URI =
RDF::URI("http://www.w3.org/2000/10/swap/list#")
Class Method Summary collapse
-
.method_missing(property, *args, &block) ⇒ Object
Returns a vocubulary term.
-
.to_uri ⇒ URI
Returns the base URI for this vocabulary.
-
.try_list(subject, graph) ⇒ RDF::List, RDF::Resource
Attempts to create an RDF::N3::List from subject, or returns the node as is, if unable.
Instance Method Summary collapse
-
#<<(value) ⇒ RDF::List
Appends an element to the tail of this list.
- #==(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?
Returns the element at ‘index`.
-
#clear ⇒ RDF::List
Empties this list.
-
#each(&block) ⇒ Enumerator
Yields each element in this list.
-
#each_descendant {|term| ... } ⇒ Enumerator
Enumerate via depth-first recursive descent over list members, yielding each member.
-
#each_statement(&block) ⇒ Enumerator
Yields each statement constituting this list.
-
#each_subject(&block) ⇒ Enumerator
Yields each subject term constituting this list along with sub-lists.
-
#empty? ⇒ Boolean
Returns ‘true` if this list is empty.
-
#eql?(other) ⇒ Boolean
Checks pattern equality against another list, considering nesting.
-
#evaluate(bindings, formulae: {}, **options) ⇒ RDF::N3::List
Evaluates the list using the given variable ‘bindings`.
-
#fetch(*args, &block) ⇒ RDF::Term?
Returns element at ‘index` with default.
-
#first ⇒ RDF::Term
Returns the first element in this list.
-
#has_nodes? ⇒ Boolean
Does this list, or any recusive list have any blank node members?.
-
#hash ⇒ Object
The list hash is the hash of it’s members.
-
#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) {|list| ... } ⇒ List
constructor
Initializes a newly-constructed list.
-
#last ⇒ RDF::Term
Returns the last element in this list.
-
#length ⇒ Integer
Returns the length of this list.
-
#rest ⇒ RDF::List
Returns a list containing all but the first element of this list.
-
#shift ⇒ RDF::Term
Removes and returns the element at the head of this list.
-
#solution(list) ⇒ RDF::Query::Solution
Returns a query solution constructed by binding any variables in this list with the corresponding terms in the given ‘list`.
-
#tail ⇒ RDF::List
Returns a list containing the last element of this list.
-
#to_a ⇒ Array
Returns the elements in this list as an array.
-
#to_base ⇒ Sring
Returns the base representation of this term.
-
#to_ndvar(scope) ⇒ RDF::N3::List
Substitutes blank node members with existential variables, recusively.
-
#to_sxp_bin ⇒ Array
Transform Statement into an SXP.
-
#transform(&block) ⇒ RDF::N3::list
Creates a new list by recusively mapping the values of the list.
-
#unshift(value) ⇒ RDF::List
Appends an element to the head of this list.
-
#valid? ⇒ Boolean
Lists are valid, unless established via RDF::List, in which case they are only valid if the RDF::List is valid.
-
#var_values(var, list) ⇒ Array<RDF::Term>
Returns all values the list in the same pattern position.
-
#variable? ⇒ Boolean
A list is variable if any of its members are variable?.
-
#variable_count ⇒ Integer
Returns the number of variables in this list, recursively.
-
#variables ⇒ Hash{Symbol => Variable}
Returns all variables in this list.
-
#vars ⇒ Array<RDF::Query::Variable>
Return the variables contained this list.
Methods included from Term
#as_datetime, #as_number, #sameTerm?
Methods inherited from List
Constructor Details
#initialize(subject: nil, graph: nil, values: nil) {|list| ... } ⇒ List
Initializes a newly-constructed list.
Instantiates a new list based at ‘subject`, which must be an RDF::Node. List may be initialized using passed `values`.
If values is not provided, but subject and graph are, then will attempt to recursively represent lists.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/rdf/n3/list.rb', line 64 def initialize(subject: nil, graph: nil, values: nil, &block) @subject = subject || (Array(values).empty? ? RDF.nil : RDF::Node.new) @graph = graph @valid = true @values = case when values values.map do |v| # Convert values, as necessary. case v when RDF::Value then v.to_term when Symbol then RDF::Node.intern(v) when Array then RDF::N3::List.new(values: v) when nil then RDF.nil else RDF::Literal.new(v) end end when subject && graph ln = RDF::List.new(subject: subject, graph: graph) @valid = ln.valid? ln.to_a.map {|li| self.class.try_list(li, graph)} else [] end end |
Class Method Details
.method_missing(property, *args, &block) ⇒ Object
Returns a vocubulary term
13 14 15 16 17 18 19 20 |
# File 'lib/rdf/n3/list.rb', line 13 def self.method_missing(property, *args, &block) property = RDF::Vocabulary.camelize(property.to_s) if args.empty? && !to_s.empty? RDF::Vocabulary::Term.intern("#{URI}#{property}", attributes: {}) else super end end |
.to_uri ⇒ URI
Returns the base URI for this vocabulary.
26 27 28 |
# File 'lib/rdf/n3/list.rb', line 26 def self.to_uri URI end |
.try_list(subject, graph) ⇒ RDF::List, RDF::Resource
Attempts to create an RDF::N3::List from subject, or returns the node as is, if unable.
35 36 37 38 39 40 41 42 43 |
# File 'lib/rdf/n3/list.rb', line 35 def self.try_list(subject, graph) return subject unless subject && (subject.node? || subject.uri? && subject == RDF.nil) ln = RDF::List.new(subject: subject, graph: graph) return subject unless ln.valid? # Return a new list, outside of this queryable, with any embedded lists also expanded values = ln.to_a.map {|li| try_list(li, graph)} RDF::N3::List.new(subject: subject, graph: graph, values: values) end |
Instance Method Details
#<<(value) ⇒ RDF::List
Appends an element to the tail of this list.
240 241 242 243 244 245 |
# File 'lib/rdf/n3/list.rb', line 240 def <<(value) value = normalize_value(value) @subject = nil @values << value self end |
#==(other) ⇒ Object
98 99 100 101 102 103 104 |
# File 'lib/rdf/n3/list.rb', line 98 def ==(other) case other when Array, RDF::List then to_a == other.to_a else false end 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.
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 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/rdf/n3/list.rb', line 141 def []=(*args) value = case args.last when Array then args.last when RDF::List then args.last.to_a else [args.last] end.map do |v| # Convert values, as necessary. case v when RDF::Value then v.to_term when Symbol then RDF::Node.intern(v) when Array then RDF::N3::List.new(values: v) when nil then RDF.nil else RDF::Literal.new(v) end end ret = case args.length when 3 start, length = args[0], args[1] @subject = nil if start == 0 @values[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) @values[args.first] = value.first when Range @values[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 # Fill any nil entries in @values with rdf:nil @values.map! {|v| v || RDF.nil} @subject = RDF.nil if @values.empty? @subject ||= RDF::Node.new ret # Returns inserted values end |
#at(index) ⇒ RDF::Term?
Returns the element at ‘index`.
312 313 314 |
# File 'lib/rdf/n3/list.rb', line 312 def at(index) @values.at(index) end |
#clear ⇒ RDF::List
Empties this list
225 226 227 228 229 |
# File 'lib/rdf/n3/list.rb', line 225 def clear @values.clear @subject = nil self end |
#each(&block) ⇒ Enumerator
Yields each element in this list.
371 372 373 374 375 |
# File 'lib/rdf/n3/list.rb', line 371 def each(&block) return to_enum unless block_given? @values.each(&block) end |
#each_descendant {|term| ... } ⇒ Enumerator
Enumerate via depth-first recursive descent over list members, yielding each member
434 435 436 437 438 439 440 441 442 |
# File 'lib/rdf/n3/list.rb', line 434 def each_descendant(&block) if block_given? each do |term| term.each_descendant(&block) if term.list? block.call(term) end end enum_for(:each_descendant) end |
#each_statement(&block) ⇒ Enumerator
Yields each statement constituting this list. Uses actual statements if a graph was set, otherwise, the saved values.
This will recursively get statements for sub-lists as well.
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
# File 'lib/rdf/n3/list.rb', line 389 def each_statement(&block) return enum_statement unless block_given? if graph RDF::List.new(subject: subject, graph: graph).each_statement(&block) elsif @values.length > 0 # Create a subject for each entry based on the subject bnode subjects = (0..(@values.count-1)).map {|ndx| ndx > 0 ? RDF::Node.intern("#{subject.id}_#{ndx}") : subject} *values, last = @values while !values.empty? subj = subjects.shift value = values.shift block.call(RDF::Statement(subj, RDF.first, value.list? ? value.subject : value)) block.call(RDF::Statement(subj, RDF.rest, subjects.first)) end subj = subjects.shift block.call(RDF::Statement(subj, RDF.first, last.list? ? last.subject : last)) block.call(RDF::Statement(subj, RDF.rest, RDF.nil)) end # If a graph was used, also get statements from sub-lists @values.select(&:list?).each {|li| li.each_statement(&block)} end |
#each_subject(&block) ⇒ Enumerator
Yields each subject term constituting this list along with sub-lists.
423 424 425 426 427 |
# File 'lib/rdf/n3/list.rb', line 423 def each_subject(&block) return enum_subject unless block_given? each_statement {|st| block.call(st.subject) if st.predicate == RDF.rest} end |
#empty? ⇒ Boolean
Returns ‘true` if this list is empty.
256 257 258 |
# File 'lib/rdf/n3/list.rb', line 256 def empty? @values.empty? end |
#eql?(other) ⇒ Boolean
Checks pattern equality against another list, considering nesting.
485 486 487 488 489 490 491 492 493 494 495 496 497 |
# File 'lib/rdf/n3/list.rb', line 485 def eql?(other) other = RDF::N3::List[*other] if other.is_a?(Array) return false if !other.is_a?(RDF::List) || count != other.count @values.each_with_index do |li, ndx| case li when RDF::Query::Pattern, RDF::N3::List return false unless li.eql?(other.at(ndx)) else return false unless li == other.at(ndx) end end true end |
#evaluate(bindings, formulae: {}, **options) ⇒ RDF::N3::List
Evaluates the list using the given variable ‘bindings`.
559 560 561 562 563 564 565 566 567 568 569 |
# File 'lib/rdf/n3/list.rb', line 559 def evaluate(bindings, formulae: {}, **) # if values are constant, simply return ourselves return self if to_a.none? {|li| li.node? || li.variable?} bindings = bindings.to_h unless bindings.is_a?(Hash) # Create a new list subject using a combination of the current subject and a hash of the binding values subj = "#{subject.id}_#{bindings.values.sort.hash}" values = to_a.map do |o| o = o.evaluate(bindings, formulae: formulae, **) || o end RDF::N3::List.new(subject: RDF::Node.intern(subj), values: values) end |
#fetch(*args, &block) ⇒ RDF::Term?
Returns element at ‘index` with default.
299 300 301 |
# File 'lib/rdf/n3/list.rb', line 299 def fetch(*args, &block) @values.fetch(*args, &block) end |
#first ⇒ RDF::Term
Returns the first element in this list.
323 324 325 |
# File 'lib/rdf/n3/list.rb', line 323 def first @values.first end |
#has_nodes? ⇒ Boolean
Does this list, or any recusive list have any blank node members?
448 449 450 |
# File 'lib/rdf/n3/list.rb', line 448 def has_nodes? @values.any? {|e| e.node? || e.list? && e.has_nodes?} end |
#hash ⇒ Object
The list hash is the hash of it’s members.
110 111 112 |
# File 'lib/rdf/n3/list.rb', line 110 def hash to_a.hash end |
#index(value) ⇒ Integer
Returns the index of the first element equal to ‘value`, or `nil` if no match was found.
284 285 286 |
# File 'lib/rdf/n3/list.rb', line 284 def index(value) @values.index(value) end |
#last ⇒ RDF::Term
Returns the last element in this list.
335 336 337 |
# File 'lib/rdf/n3/list.rb', line 335 def last @values.last end |
#length ⇒ Integer
Returns the length of this list.
269 270 271 |
# File 'lib/rdf/n3/list.rb', line 269 def length @values.length end |
#rest ⇒ RDF::List
Returns a list containing all but the first element of this list.
346 347 348 |
# File 'lib/rdf/n3/list.rb', line 346 def rest self.class.new(values: @values[1..-1]) end |
#shift ⇒ RDF::Term
Removes and returns the element at the head of this list.
211 212 213 214 215 |
# File 'lib/rdf/n3/list.rb', line 211 def shift return nil if empty? @subject = nil @values.shift end |
#solution(list) ⇒ RDF::Query::Solution
Returns a query solution constructed by binding any variables in this list with the corresponding terms in the given ‘list`.
578 579 580 581 582 583 584 585 586 587 588 |
# File 'lib/rdf/n3/list.rb', line 578 def solution(list) RDF::Query::Solution.new do |solution| @values.each_with_index do |li, ndx| if li.respond_to?(:solution) solution.merge!(li.solution(list[ndx])) elsif li.is_a?(RDF::Query::Variable) solution[li.to_sym] = list[ndx] end end end end |
#tail ⇒ RDF::List
Returns a list containing the last element of this list.
357 358 359 |
# File 'lib/rdf/n3/list.rb', line 357 def tail self.class.new(values: @values[-1..-1]) end |
#to_a ⇒ Array
Returns the elements in this list as an array.
476 477 478 |
# File 'lib/rdf/n3/list.rb', line 476 def to_a @values end |
#to_base ⇒ Sring
Returns the base representation of this term.
594 595 596 |
# File 'lib/rdf/n3/list.rb', line 594 def to_base "(#{@values.map(&:to_base).join(' ')})" end |
#to_ndvar(scope) ⇒ RDF::N3::List
Substitutes blank node members with existential variables, recusively.
457 458 459 460 461 462 463 464 465 466 |
# File 'lib/rdf/n3/list.rb', line 457 def to_ndvar(scope) values = @values.map do |e| case e when RDF::Node then e.to_ndvar(scope) when RDF::N3::List then e.to_ndvar(scope) else e end end RDF::N3::List.new(values: values) end |
#to_sxp_bin ⇒ Array
Transform Statement into an SXP
600 601 602 |
# File 'lib/rdf/n3/list.rb', line 600 def to_sxp_bin to_a.to_sxp_bin end |
#transform(&block) ⇒ RDF::N3::list
Creates a new list by recusively mapping the values of the list
608 609 610 611 |
# File 'lib/rdf/n3/list.rb', line 608 def transform(&block) values = self.to_a.map {|v| v.list? ? v.map(&block) : block.call(v)} RDF::N3::List.new(values: values) 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.
195 196 197 198 199 200 201 |
# File 'lib/rdf/n3/list.rb', line 195 def unshift(value) value = normalize_value(value) @values.unshift(value) @subject = nil return self end |
#valid? ⇒ Boolean
Lists are valid, unless established via RDF::List, in which case they are only valid if the RDF::List is valid.
94 |
# File 'lib/rdf/n3/list.rb', line 94 def valid?; @valid; end |
#var_values(var, list) ⇒ Array<RDF::Term>
Returns all values the list in the same pattern position
540 541 542 543 544 545 546 547 548 |
# File 'lib/rdf/n3/list.rb', line 540 def var_values(var, list) results = [] @values.each_index do |ndx| maybe_var = @values[ndx] next unless maybe_var.respond_to?(:var_values) results.push(*Array(maybe_var.var_values(var, list.at(ndx)))) end results.flatten.compact end |
#variable? ⇒ Boolean
A list is variable if any of its members are variable?
503 504 505 |
# File 'lib/rdf/n3/list.rb', line 503 def variable? @values.any?(&:variable?) end |
#variable_count ⇒ Integer
Returns the number of variables in this list, recursively.
530 531 532 |
# File 'lib/rdf/n3/list.rb', line 530 def variable_count variables.length end |
#variables ⇒ Hash{Symbol => Variable}
Returns all variables in this list.
Note: this returns a hash containing distinct variables only.
520 521 522 523 524 |
# File 'lib/rdf/n3/list.rb', line 520 def variables @values.inject({}) do |hash, li| li.respond_to?(:variables) ? hash.merge(li.variables) : hash end end |
#vars ⇒ Array<RDF::Query::Variable>
Return the variables contained this list
510 511 512 |
# File 'lib/rdf/n3/list.rb', line 510 def vars @values.vars end |