<commit_before>require 'active_support/core_ext/class/attribute'

module RubySpeech
  module GenericElement

    def self.included(klass)
      klass.class_attribute :registered_ns, :registered_name, :defaults
      klass.extend ClassMethods
    end

    module ClassMethods
      @@registrations = {}

      # Register a new stanza class to a name and/or namespace
      #
      # This registers a namespace that is used when looking
      # up the class name of the object to instantiate when a new
      # stanza is received
      #
      # @param [#to_s] name the name of the node
      #
      def register(name)
        self.registered_name = name.to_s
        self.registered_ns = namespace
        @@registrations[[self.registered_name, self.registered_ns]] = self
      end

      # Find the class to use given the name and namespace of a stanza
      #
      # @param [#to_s] name the name to lookup
      #
      # @return [Class, nil] the class appropriate for the name
      def class_from_registration(name)
        @@registrations[[name.to_s, namespace]]
      end

      # Import an XML::Node to the appropriate class
      #
      # Looks up the class the node should be then creates it based on the
      # elements of the XML::Node
      # @param [XML::Node] node the node to import
      # @return the appropriate object based on the node name and namespace
      def import(node)
        node = Nokogiri::XML.parse(node, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root unless node.is_a?(Nokogiri::XML::Node)
        return node.content if node.is_a?(Nokogiri::XML::Text)
        klass = class_from_registration node.node_name
        if klass && klass != self
          klass.import node
        else
          new.inherit node
        end
      end

      def new(atts = {}, &block)
        super(self.registered_name, nil, self.namespace) do |new_node|
          (self.defaults || {}).merge(atts).each_pair { |k, v| new_node.send :"#{k}=", v }
          block_return = new_node.eval_dsl_block &block
          new_node.string block_return if block_return.is_a?(String) && block_return.present?
        end
      end
    end

    attr_writer :parent

    def parent
      @parent || super
    end

    def inherit(node)
      self.parent = node.parent
      super
    end

    def version
      read_attr :version
    end

    def version=(other)
      self[:version] = other
    end

    ##
    # @return [String] the base URI to which relative URLs are resolved
    #
    def base_uri
      read_attr 'xml:base'
    end

    ##
    # @param [String] uri the base URI to which relative URLs are resolved
    #
    def base_uri=(uri)
      self['xml:base'] = uri
    end

    def +(other)
      self.class.new(:base_uri => base_uri).tap do |new_element|
        (self.children + other.children).each do |child|
          new_element << child
        end
      end
    end

    def eval_dsl_block(&block)
      return unless block_given?
      @block_binding = eval "self", block.binding
      instance_eval &block
    end

    def children(type = nil, attributes = nil)
      if type
        expression = type.to_s

        expression << '[' << attributes.inject([]) do |h, (key, value)|
          h << "@#{key}='#{value}'"
        end.join(',') << ']' if attributes

        if namespace_href
          xpath "ns:#{expression}", :ns => namespace_href
        else
          xpath expression
        end
      else
        super()
      end.map { |c| self.class.import c }
    end<commit_msg>[BUGFIX] On JRuby Nokogiri requires attribute namespace prefixes in XPath<commit_after>require 'active_support/core_ext/class/attribute'

module RubySpeech
  module GenericElement

    def self.included(klass)
      klass.class_attribute :registered_ns, :registered_name, :defaults
      klass.extend ClassMethods
    end

    module ClassMethods
      @@registrations = {}

      # Register a new stanza class to a name and/or namespace
      #
      # This registers a namespace that is used when looking
      # up the class name of the object to instantiate when a new
      # stanza is received
      #
      # @param [#to_s] name the name of the node
      #
      def register(name)
        self.registered_name = name.to_s
        self.registered_ns = namespace
        @@registrations[[self.registered_name, self.registered_ns]] = self
      end

      # Find the class to use given the name and namespace of a stanza
      #
      # @param [#to_s] name the name to lookup
      #
      # @return [Class, nil] the class appropriate for the name
      def class_from_registration(name)
        @@registrations[[name.to_s, namespace]]
      end

      # Import an XML::Node to the appropriate class
      #
      # Looks up the class the node should be then creates it based on the
      # elements of the XML::Node
      # @param [XML::Node] node the node to import
      # @return the appropriate object based on the node name and namespace
      def import(node)
        node = Nokogiri::XML.parse(node, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root unless node.is_a?(Nokogiri::XML::Node)
        return node.content if node.is_a?(Nokogiri::XML::Text)
        klass = class_from_registration node.node_name
        if klass && klass != self
          klass.import node
        else
          new.inherit node
        end
      end

      def new(atts = {}, &block)
        super(self.registered_name, nil, self.namespace) do |new_node|
          (self.defaults || {}).merge(atts).each_pair { |k, v| new_node.send :"#{k}=", v }
          block_return = new_node.eval_dsl_block &block
          new_node.string block_return if block_return.is_a?(String) && block_return.present?
        end
      end
    end

    attr_writer :parent

    def parent
      @parent || super
    end

    def inherit(node)
      self.parent = node.parent
      super
    end

    def version
      read_attr :version
    end

    def version=(other)
      self[:version] = other
    end

    ##
    # @return [String] the base URI to which relative URLs are resolved
    #
    def base_uri
      read_attr 'xml:base'
    end

    ##
    # @param [String] uri the base URI to which relative URLs are resolved
    #
    def base_uri=(uri)
      self['xml:base'] = uri
    end

    def +(other)
      self.class.new(:base_uri => base_uri).tap do |new_element|
        (self.children + other.children).each do |child|
          new_element << child
        end
      end
    end

    def eval_dsl_block(&block)
      return unless block_given?
      @block_binding = eval "self", block.binding
      instance_eval &block
    end

    def children(type = nil, attributes = nil)
      if type
        expression = namespace_href ? 'ns:' : ''
        expression << type.to_s

        expression << '[' << attributes.inject([]) do |h, (key, value)|
          h << "@#{namespace_href && Nokogiri.jruby? ? 'ns:' : ''}#{key}='#{value}'"
        end.join(',') << ']' if attributes

        xpath expression, :ns => namespace_href
      else
        super()
      end.map { |c| self.class.import c }
    end
{'fraction_non_alphanumeric': 0.09632963015047111, 'fraction_numerical': 0.0, 'mean_word_length': 2.2744014732965008, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6593756', 'n_tokens_mistral': 2138, 'n_tokens_neox': 2085, 'n_words': 648}