lib/saxon/xdm/value.rb
require_relative '../s9api'
require_relative 'sequence_like'
module Saxon
module XDM
# An XPath Data Model Value object, representing a Sequence.
class Value
include XDM::SequenceLike
include Enumerable
class << self
# Create a new XDM::Value sequence containing the items passed in as a Ruby enumerable.
#
# @param items [Enumerable] A list of members
# @return [Saxon::XDM::Value] The XDM value
def create(*items)
items = items.flatten
case items.size
when 0
XDM.EmptySequence()
when 1
if value = maybe_xdm_value(items.first)
return value
end
XDM.Item(items.first)
else
new(Saxon::S9API::XdmValue.new(wrap_items(items)))
end
end
private
def maybe_xdm_value(value)
return value if value.is_a?(self)
return value if value === XDM.EmptySequence()
return XDM.EmptySequence() if value.instance_of?(Saxon::S9API::XdmEmptySequence)
return check_for_empty_or_single_item_value(value) if value.instance_of?(Saxon::S9API::XdmValue)
false
end
def check_for_empty_or_single_item_value(s9_value)
case s9_value.size
when 0
XDM.EmptySequence()
when 1
XDM.Item(s9_value.item_at(0))
else
new(s9_value)
end
end
def wrap_items(items)
result = []
items.map { |item|
wrap_item(item, result)
}
result
end
def wrap_item(item, result)
if item.respond_to?(:sequence_enum)
item.sequence_enum.each do |item|
result << item.to_java
end
elsif item.respond_to?(:each)
item.each do |item|
result << XDM.Item(item).to_java
end
else
result << XDM.Item(item).to_java
end
end
end
attr_reader :s9_xdm_value
private :s9_xdm_value
# @api private
def initialize(s9_xdm_value)
@s9_xdm_value = s9_xdm_value
end
# @return [Fixnum] The size of the sequence
def size
s9_xdm_value.size
end
# Calls the given block once for each Item in the sequence, passing that
# item as a parameter. Returns the value itself.
#
# If no block is given, an Enumerator is returned.
#
# @overload
# @yield [item] The current XDM Item
# @yieldparam item [Saxon::XDM::AtomicValue, Saxon::XDM::Node] the item.
def each(&block)
to_enum.each(&block)
end
# @return [Saxon::S9API::XdmValue] The underlying Saxon Java XDM valuee object.
def to_java
@s9_xdm_value
end
# Compare this XDM::Value with another. Currently this requires iterating
# across the sequence, and the other sequence and comparing each member
# with the corresponding member in the other sequence.
#
# @param other [Saxon::XDM::Value] The XDM::Value to be compare against
# @return [Boolean] whether the two XDM::Values are equal
def ==(other)
return false unless other.is_a?(XDM::Value)
return false unless other.size == size
not_okay = to_enum.zip(other.to_enum).find { |mine, theirs|
mine != theirs
}
not_okay.nil? || !not_okay
end
alias_method :eql?, :==
# The hash code for the XDM::Value
# @return [Fixnum] The hash code
def hash
@hash ||= to_a.hash
end
# Returns a lazy Enumerator over the sequence
# @return [Enumerator::Lazy] the enumerator
def to_enum
s9_xdm_value.enum_for(:each).lazy.map { |s9_xdm_item|
XDM.Item(s9_xdm_item)
}.each
end
alias_method :enum_for, :to_enum
# Returns an enumerator over the Sequence
def sequence_enum
to_enum
end
# @return [Integer] the size of the sequence
def sequence_size
s9_xdm_value.size
end
end
# Placeholder class for Saxon Items that we haven't gotten to yet
class XDM::UnhandledItem
def initialize(s9_xdm_item)
@s9_xdm_item = s9_xdm_item
end
# Return the underlying s9api XdmItem
def to_java
@s9_xdm_item
end
end
end
end