Class: Krikri::Parser::ValueArray

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/krikri/parser.rb

Overview

A specialized Array object for containing Parser::Values. Provides methods for accessing and filtering values that can be chained.

Methods defined on this class should return another ValueArray, an Array of literal values (retrieved from Parser::Value#value), or a single literal value.

Uses ‘#bindings` to track variables for recovery via `#else`, `#from`, and `#back`. Methods that return a `ValueArray` pass `#bindings` down to the new instance.

Examples:

chaining methods to select values


my_value_array.field('dc:creator', 'foaf:name')
  .match_attribute('first_name').values

my_value_array.field('dc:creator').bind(:creator)

‘#if` sets `bindings`, `#else` recoveres if empty


my_value_array.field('dc:creator', 'foaf:name').if.field('empty:field')
  .else { |vs| vs.field('some:otherField') }

Defined Under Namespace

Classes: InvalidParserValueError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(array = [], bindings = {}) ⇒ ValueArray

Returns a new instance of ValueArray.

Parameters:

  • array (Array) (defaults to: [])

    an array of values to delegate array operations to

  • bindings (Hash<Symbol, ValueArray] a set of variable bindings This is overloaded to accept an instance of this class to use as a `:top` recovery node in, e.g. `#else`. `:top` to `self` if none is passed.) (defaults to: {})

    indings [Hash<Symbol, ValueArray] a set of variable bindings This is overloaded to accept an instance of this class to use as a ‘:top` recovery node in, e.g. `#else`. `:top` to `self` if none is passed.



190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/krikri/parser.rb', line 190

def initialize(array = [], bindings = {})
  @array = array

  if bindings.is_a?(ValueArray)
    # this way is deprected!
    # how should we handle deprecations?
    @bindings = {}
    @bindings[:top] ||= bindings
  else
    @bindings = bindings
    @bindings[:top] ||= self
  end
end

Instance Attribute Details

#bindingsObject (readonly)

Returns the value of attribute bindings.



179
180
181
# File 'lib/krikri/parser.rb', line 179

def bindings
  @bindings
end

Class Method Details

.build(record) ⇒ ValueArray

Wraps the root node of the given record in this class.

Parameters:

Returns:



504
505
506
# File 'lib/krikri/parser.rb', line 504

def self.build(record)
  new([record.root])
end

Instance Method Details

#<<(value) ⇒ Object

Raises:

See Also:

  • Array#<<


216
217
218
219
220
# File 'lib/krikri/parser.rb', line 216

def <<(value)
  raise InvalidParserValueError unless value.is_a? Value
  @array << value
  value
end

#[]=(index, value) ⇒ Object

Raises:

See Also:

  • Array#[]=


207
208
209
210
211
# File 'lib/krikri/parser.rb', line 207

def []=(index, value)
  raise InvalidParserValueError unless value.is_a? Value
  @array[index] = value
  self
end

#and(from: :top) ⇒ ValueArray

Returns to a bound variable unless the current value is empty. If no variable is given, returns to the top of the call chain.

This allows checking complex conditionals, where mappings depend on data from deep within multiple branches of the tree.

Examples:

use with ‘#bind`

value_array.field(:subject).bind(:subj)
  .field('some', 'subfield')
  .select { |a| condition(a) }
  .and(:subj).field(:label)

Parameters:

  • from (#to_sym) (defaults to: :top)

    a symbol respresenting a bound variable name; default: :top

Returns:

Raises:

  • (ArgumentError)

    when an unbound variable is given as ‘var`



240
241
242
243
244
# File 'lib/krikri/parser.rb', line 240

def and(from: :top)
  return self if self.empty?
  bindings[from.to_sym] or
    raise ArgumentError, "Tried to return to unbound variable: #{from}"
end

#at(idx) ⇒ ValueArray

Returns an array containing the node(s) in the specified index posiition(s).

Parameters:

  • idx (#to_i, Range)

Returns:

  • (ValueArray)

    an array containing the node(s) in the specified index posiition(s).



274
275
276
# File 'lib/krikri/parser.rb', line 274

def at(idx)
  self.class.new(Array(@array[idx]))
end

#bind(var) ⇒ ValueArray

Binds the current array to the variable name given

Parameters:

  • var (#to_sym)

    a symbol respresenting the variable name

Returns:



251
252
253
254
# File 'lib/krikri/parser.rb', line 251

def bind(var)
  bindings[var.to_sym] = self
  self
end

#compactValueArray

Returns:

See Also:

  • Array#compact


392
393
394
# File 'lib/krikri/parser.rb', line 392

def compact
  self.class.new(@array.compact, bindings)
end

#concat(*args, &block) ⇒ ValueArray

Returns:

See Also:

  • Array#concat


259
260
261
# File 'lib/krikri/parser.rb', line 259

def concat(*args, &block)
  self.class.new(@array.concat(*args, &block), bindings)
end

#else {|arry| ... } ⇒ ValueArray

Short circuits if ‘self` is not empty, else passes the top of the call chain (`@bindings`) to the given block.

Examples:

usage with ‘#if`

value_array.if { |arry| arry.field(:a_field) }
  .else { |arry|  arry.field(:alternate_field) }

# use other filters at will
value_array.if.field(:a_field).reject { |v| v == 'SKIP ME' }
  .else { |arry|  arry.field(:alternate_field) }

standalone use; resetting to record root

value_array.field(:a_field).else { |arry| arry.field(:alternate_field) }

Yields:

Yield Parameters:

Returns:

  • (ValueArray)

    ‘self` unless empty; otherwise the result of the block

Raises:

  • (ArgumentError)


361
362
363
364
365
# File 'lib/krikri/parser.rb', line 361

def else(&block)
  raise ArgumentError, 'No block given for `#else`' unless block_given?
  return self unless self.empty?
  yield bindings[:top]
end

#field(*args) ⇒ ValueArray

Accesses a given field. Use multiple arguments to travel down the node hierarchy.

Returns:

  • (ValueArray)

    an array containing the nodes available in a particular field.



284
285
286
287
288
289
# File 'lib/krikri/parser.rb', line 284

def field(*args)
  result = self
  args.each { |name| result = result.get_field(name) }

  result
end

#field_namesValueArray

Lists field names on this node.

This can be useful in cases where the desired value is a key or child node label, rather than a value.

Returns:

  • (ValueArray)

    an array containing the field names.

See Also:

  • #reject_child for methods that filter on these names


312
313
314
# File 'lib/krikri/parser.rb', line 312

def field_names
  self.class.new(flat_map(&:children).uniq, bindings)
end

#fields(*args) ⇒ ValueArray

Accesses the union of multiple specified fields.

given fields.

Returns:

  • (ValueArray)

    an array containing the nodes available in the



296
297
298
299
300
301
# File 'lib/krikri/parser.rb', line 296

def fields(*args)
  results = args.map do |f|
    field(*Array(f))
  end
  self.class.new(results.flatten, bindings)
end

#first_value(*args) ⇒ ValueArray

Retrieves the first element of a ValueArray. Uses an optional argument to specify how many items to return. By design, it behaves similarly to Array#first, but it intentionally doesn’t override it.

Returns:

  • (ValueArray)

    a Krikri::Parser::ValueArray for first n elements



373
374
375
376
# File 'lib/krikri/parser.rb', line 373

def first_value(*args)
  return self.class.new(@array.first(*args)) unless args.empty?
  self.class.new([@array.first].compact, bindings)
end

#flatten(*args, &block) ⇒ ValueArray

Returns:

See Also:

  • Array#concat


399
400
401
# File 'lib/krikri/parser.rb', line 399

def flatten(*args, &block)
  self.class.new(@array.flatten(*args, &block), bindings)
end

#if {|arry| ... } ⇒ ValueArray

Sets the top of the call chain to self and returns or yields self.

This is syntactic sugar for ‘#bind(:top)`, with the addition of block syntax.

Examples:

with method chain syntax

value_array.if.field(:a_field).else do |arry|
   arry.field(:alternate_field)
end

with block syntax

value_array.if { |arry| arry.field(:a_field) }
  .else { |arry|  arry.field(:alternate_field) }

Yields:

  • gives self

Yield Parameters:

Returns:

  • (ValueArray)

    the result of the block, if given; or self with :top set



335
336
337
338
339
# File 'lib/krikri/parser.rb', line 335

def if(&block)
  bind(:top)
  return yield self if block_given?
  self
end

#last_value(*args) ⇒ ValueArray

Retrieves the last element of a ValueArray. Uses an optional argument to specify how many items to return. By design, it behaves similarly to Array#last, but it intentionally doesn’t override it.

Returns:

  • (ValueArray)

    a Krikri::Parser::ValueArray for last n elements



384
385
386
387
# File 'lib/krikri/parser.rb', line 384

def last_value(*args)
  return self.class.new(@array.last(*args)) unless args.empty?
  self.class.new([@array.last].compact, bindings)
end

#map(*args, &block) ⇒ ValueArray

Wraps the result of Array#map in a ValueArray

Returns:

See Also:

  • Array#map


408
409
410
# File 'lib/krikri/parser.rb', line 408

def map(*args, &block)
  self.class.new(@array.map(*args, &block), bindings)
end

#match_attribute(name, other = nil) {|value| ... } ⇒ ValueArray

Returns an array containing nodes for which the specified attribute has a value matching the given attribute name, object, and block.

Examples:

selecting by presence of an attribute; returns all nodes where

`#attribute?(:type)` is true

match_attribute(:type)

selecting by the value of an attribute; returns all nodes with

`#attribute(:type) == other`

match_attribute(:type, other)

selecting by block against an attribute; returns all nodes with

`block.call(attribute(:type))` is true

match_attribute(:type) { |value| value.starts_with? 'blah' }

selecting by block against an attribute; returns all nodes with

`block.call(attribute(:type)) == other` is true

match_attribute(:type, 'moomin') { |value| value.downcase }

Parameters:

  • name (#to_sym)

    an attribute name

  • other (Object) (defaults to: nil)

    an object to check for equality with the values from the given attribute.

Yields:

  • (value)

    yields each value with the attribute in name to the block

Returns:

  • (ValueArray)

    an array containing nodes for which the specified attribute has a value matching the given attribute name, object, and block.



460
461
462
# File 'lib/krikri/parser.rb', line 460

def match_attribute(name, other = nil, &block)
  select(&compare_to_attribute(name, other, &block))
end

#match_child(*children) ⇒ ValueArray

Returns an array containing nodes for which the specified attribute does not have a child node matching the given child name.

Parameters:

  • *children (Array<String>)

Returns:

  • (ValueArray)

    an array containing nodes for which the specified attribute does not have a child node matching the given child name



469
470
471
# File 'lib/krikri/parser.rb', line 469

def match_child(*children)
  select { |v| !(v.children & children).empty? }
end

#reject(*args, &block) ⇒ ValueArray

Wraps the result of Array#reject in a ValueArray

Returns:

See Also:

  • Array#reject


426
427
428
# File 'lib/krikri/parser.rb', line 426

def reject(*args, &block)
  self.class.new(@array.reject(*args, &block), bindings)
end

#reject_attribute(name, other = nil) {|value| ... } ⇒ ValueArray

Returns an array containing nodes for which the specified attribute does not have a value matching the given attribute name, object, and block.

Parameters:

  • name (#to_sym)

    an attribute name

  • other (Object) (defaults to: nil)

    an object to check for equality with the values from the given attribute.

Yields:

  • (value)

    yields each value with the attribute in name to the block

Returns:

  • (ValueArray)

    an array containing nodes for which the specified attribute does not have a value matching the given attribute name, object, and block.

See Also:



486
487
488
# File 'lib/krikri/parser.rb', line 486

def reject_attribute(name, other = nil, &block)
  reject(&compare_to_attribute(name, other, &block))
end

#reject_child(*children) ⇒ ValueArray

Returns an array containing nodes for which the specified attribute does not have a childnode matching the given child name.

Parameters:

  • *children (Array<String>)

Returns:

  • (ValueArray)

    an array containing nodes for which the specified attribute does not have a childnode matching the given child name



495
496
497
# File 'lib/krikri/parser.rb', line 495

def reject_child(*children)
  reject { |v| !(v.children & children).empty? }
end

#select(*args, &block) ⇒ ValueArray

Wraps the result of Array#select in a ValueArray

Returns:

See Also:

  • Array#select


417
418
419
# File 'lib/krikri/parser.rb', line 417

def select(*args, &block)
  self.class.new(@array.select(*args, &block), bindings)
end

#valuesArray

Returns literal values from the objects in this array.

Returns:

  • (Array)

    literal values from the objects in this array.

See Also:



266
267
268
# File 'lib/krikri/parser.rb', line 266

def values
  @array.map { |v| v.respond_to?(:value) ? v.value : v }
end