Module: Moxml::Node

Constant Summary

Constants included from NodeBehavior

Moxml::NodeBehavior::TYPES

Constants included from XmlUtils

XmlUtils::VALID_ELEMENT_NAMES

Instance Attribute Summary

Attributes included from NodeBehavior

#context, #native, #parent_node

Class Method Summary collapse

Methods included from NodeBehavior

#==, #adapter, #add_child, #add_next_sibling, #add_previous_sibling, #after, #ancestors, #at_xpath, #before, #blank?, #children, #clear_native_memo!, #content, #descendants, #digest, #document, #dup, #each, #each_node, #entity_bearing?, #find, #find_all, #first_child, #following_siblings, #has_children?, #identifier, #initialize, #invalidate_namespace_cache!, #last_child, #line_number, #materialize, #materialize_fields, #namespace, #namespaces, #next_sibling, #outer_xml, #parent, #path, #preceding_siblings, #previous_sibling, #prime_contract, #refresh_native!, #remove, #replace, #source_position, #text, #to_xml, #xpath

Methods included from XmlUtils

#encode_entities, #normalize_xml_value, #validate_comment_content, #validate_declaration_encoding, #validate_declaration_standalone, #validate_declaration_version, #validate_element_name, #validate_entity_reference_name, #validate_pi_target, #validate_prefix, #validate_uri

Class Method Details

.adapter(context) ⇒ Object



634
635
636
# File 'lib/moxml/node.rb', line 634

def self.adapter(context)
  context.config.adapter
end

.contract_module(type) ⇒ Object

The contract module for a type — what an in-place extended native carries instead of a wrapper shell.



565
566
567
# File 'lib/moxml/node.rb', line 565

def self.contract_module(type)
  contract_modules[type]
end

.contract_modules ⇒ Object



569
570
571
572
573
574
575
576
577
578
579
580
581
582
# File 'lib/moxml/node.rb', line 569

def self.contract_modules
  @contract_modules ||= {
    element: Element,
    text: Text,
    cdata: Cdata,
    comment: Comment,
    processing_instruction: ProcessingInstruction,
    document: Document,
    declaration: Declaration,
    doctype: Doctype,
    attribute: Attribute,
    entity_reference: EntityReference,
  }.freeze
end

.node_type_map ⇒ Object

Instantiation shells per type — the contract constants (Element, Text, ...) are modules since issue #230, so wrappers mint through Wrappers::*.



548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/moxml/node.rb', line 548

def self.node_type_map
  @node_type_map ||= {
    element: Wrappers::Element,
    text: Wrappers::Text,
    cdata: Wrappers::Cdata,
    comment: Wrappers::Comment,
    processing_instruction: Wrappers::ProcessingInstruction,
    document: Wrappers::Document,
    declaration: Wrappers::Declaration,
    doctype: Wrappers::Doctype,
    attribute: Wrappers::Attribute,
    entity_reference: Wrappers::EntityReference,
  }.freeze
end

.wrap(node, context) ⇒ Object



584
585
586
# File 'lib/moxml/node.rb', line 584

def self.wrap(node, context)
  wrap_with(node, context, adapter(context))
end

.wrap_with(node, context, adapter) ⇒ Object

The wrap path with the adapter already resolved — walk entry points know the adapter (it is self); one config-chain hop saved per wrapped node.



591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
# File 'lib/moxml/node.rb', line 591

def self.wrap_with(node, context, adapter)
  return nil if node.nil?

  # Cache-stable binding nodes carry their wrapper directly
  # (#312): the binding's document-owned cache hands the SAME
  # node object for the engine node's whole lifetime, so an
  # ivar is the identity map — one ivar read beats the WeakMap
  # round trip, and the wrapper dies with the node (document
  # scope) exactly like the binding's own wrappers.
  cached = if node.instance_variable_defined?(:@moxml_wrapper)
             node.instance_variable_get(:@moxml_wrapper)
           else
             context.wrapper_for(node)
           end
  return cached if cached

  type = adapter.node_type(node)

  # Extend-in-place (issue #230): adapters whose natives can
  # carry the contract modules directly (leptris TypedData) mint
  # the native itself as the wrapper — @native is self. The
  # minted wrapper primes with ITSELF (not the input native):
  # adapter calls then receive the contract-bearing receiver,
  # which klass-propagating reads (#246) dispatch on — and the
  # input native keeps its registration so later wraps of the
  # same base object hit the cache instead of re-minting.
  if (extended = adapter.wrap_native(node, type, context))
    extended.prime_contract(extended, context, adapter, type)
    context.register_wrapper(node, extended)
    context.register_wrapper(extended, extended) unless extended.equal?(node)
    return extended
  end

  klass = node_type_map[type] || Wrappers::Node
  wrapper = klass.new(node, context, adapter, type)
  if node.instance_variable_defined?(:@c_address)
    node.instance_variable_set(:@moxml_wrapper, wrapper)
  else
    context.register_wrapper(node, wrapper)
  end
  wrapper
end