module MicroMicro
class Property
PROPERTY_PARSERS_MAP = {
'dt' => Parsers::DateTimePropertyParser,
'e' => Parsers::EmbeddedMarkupPropertyParser,
'p' => Parsers::PlainTextPropertyParser,
'u' => Parsers::UrlPropertyParser
}.freeze
attr_accessor :collection
attr_reader :name, :node, :prefix
# @param node [Nokogiri::XML::Element]
# @param name [String]
# @param prefix [String
]
def initialize(node, name:, prefix:)
@node = node
@name = name
@prefix = prefix
end
# @return [Boolean]
def implied?
false
end
# @return [String]
def inspect
format(%(#<#{self.class.name}:%#0x name: #{name.inspect}, prefix: #{prefix.inspect}, value: #{value.inspect}>), object_id)
end
# @return [Boolean]
def item_node?
@item_node ||= Item.item_node?(node)
end
# @return [String, Hash, MicroMicro::Item]
def value
@value ||= begin
return parser.value unless item_node?
item.value = item_value
item
end
end
# @return [Boolean]
def value?
value.present?
end
# @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
# @param node_set [Nokogiri::XML::NodeSet]
# @return [Nokogiri::XML::NodeSet]
def self.nodes_from(context, node_set = Nokogiri::XML::NodeSet.new(context.document, []))
context.each { |node| nodes_from(node, node_set) } if context.is_a?(Nokogiri::XML::NodeSet)
if context.is_a?(Nokogiri::XML::Element) && !Document.ignore_node?(context)
node_set << context if property_node?(context)
nodes_from(context.element_children, node_set) unless Item.item_node?(context)
end
node_set
end
# @param context [Nokogiri::XML::NodeSet, Nokogiri::XML::Element]
# @return [Array]
def self.properties_from(context)
nodes_from(context).map do |node|
types_from(node).map { |prefix, name| new(node, name: name, prefix: prefix) }
end.flatten
end
# @param node [Nokogiri::XML::Element]
# @return [Boolean]
def self.property_node?(node)
types_from(node).any?
end
# @param node [Nokogiri::XML::Element]
# @return [Array]
#
# @example
# node = Nokogiri::HTML('Jason Garber').at_css('a')
# MicroMicro::Property.types_from(node) #=> [['p', 'name'], ['u', 'url']]
def self.types_from(node)
node.classes.select { |token| token.match?(/^(?:dt|e|p|u)(?:\-[0-9a-z]+)?(?:\-[a-z]+)+$/) }.map { |token| token.split(/\-/, 2) }.uniq
end
private
# @return [MicroMicro::Item, nil]
def item
@item ||= Item.new(node) if item_node?
end
# @reutrn [String, nil]
def item_value
return unless item_node?
obj_by_prefix = case prefix
when 'e' then item
when 'p' then item.properties.find { |property| property.name == 'name' }
when 'u' then item.properties.find { |property| property.name == 'url' }
end
(obj_by_prefix || parser).value
end
def parser
@parser ||= PROPERTY_PARSERS_MAP[prefix].new(self)
end
end
end