<commit_before>module ROXML
  class RequiredElementMissing < Exception # :nodoc:
  end
  
  #
  # Internal base class that represents an XML - Class binding.
  #
  class XMLRef # :nodoc:
    delegate :required?, :array?, :blocks, :accessor, :default, :to => :opts

    def initialize(opts, instance)
      @opts = opts
      @instance = instance
    end

    def to_xml
      val = @instance.__send__(accessor)
      opts.to_xml.respond_to?(:call) ? opts.to_xml.call(val) : val
    end

    def update_xml(xml, value)
      returning wrap(xml) do |xml|
        write_xml(xml, value)
      end
    end

    def name
      opts.name_explicit? ? opts.name : conventionize(opts.name)
    end

    def xpath_name
      opts.name_explicit? ? name : namespacify(name)
    end

    def value_in(xml)
      xml = XML::Node.from(xml)
      value = fetch_value(xml)
      value = default if value.nil?

      freeze(apply_blocks(value))
    end

  private
    attr_reader :opts

    def conventionize(what)
      convention ||= @instance.class.respond_to?(:roxml_naming_convention) && @instance.class.roxml_naming_convention
      if !what.blank? && convention.respond_to?(:call)
        URI.unescape(convention.call(URI.escape(what, /\/|::/)))
      else
        what
      end
    end

    def namespacify(what)
      if what.present? && namespace = @instance.class.roxml_namespace
        "#{namespace}:#{what}"
      else
        what
      end
    end

    def wrapper
      namespacify(conventionize(opts.wrapper))
    end

    def apply_blocks(val)
      begin
        blocks.inject(val) {|val, block| block.call(val) }
      rescue Exception => ex
        raise ex, "#{accessor}: #{ex.message}"
      end
    end

    def freeze(val)
      if opts.frozen?
        val.each(&:freeze) if val.is_a?(Enumerable)
        val.freeze
      else
        val
      end
    end

    def xpath
      wrapper ? "#{wrapper}/#{xpath_name}" : xpath_name.to_s
    end

    def auto_xpath
      "#{namespacify(conventionize(opts.name.pluralize))}/#{xpath_name}" if array?
    end

    def wrap(xml)
      return xml if !wrapper || xml.name == wrapper
      if child = xml.children.find {|c| c.name == wrapper }
       return child
      end
      xml.add_child(XML::Node.create(wrapper.to_s))
    end

    def nodes_in(xml)
      vals = xml.search(xpath)

      if (opts.hash? || opts.array?) && vals.empty? && !wrapper && auto_xpath
        vals = xml.search(auto_xpath)
        @auto_vals = !vals.empty?
      end

      if vals.empty?
        raise RequiredElementMissing, "#{name} from #{xml} for #{accessor}" if required?
        default
      else<commit_msg>Much like we don't conventionize or namespace explicit names, don't do so with wrappers<commit_after>module ROXML
  class RequiredElementMissing < Exception # :nodoc:
  end
  
  #
  # Internal base class that represents an XML - Class binding.
  #
  class XMLRef # :nodoc:
    delegate :required?, :array?, :blocks, :accessor, :default, :wrapper, :to => :opts

    def initialize(opts, instance)
      @opts = opts
      @instance = instance
    end

    def to_xml
      val = @instance.__send__(accessor)
      opts.to_xml.respond_to?(:call) ? opts.to_xml.call(val) : val
    end

    def update_xml(xml, value)
      returning wrap(xml) do |xml|
        write_xml(xml, value)
      end
    end

    def name
      opts.name_explicit? ? opts.name : conventionize(opts.name)
    end

    def xpath_name
      opts.name_explicit? ? name : namespacify(name)
    end

    def value_in(xml)
      xml = XML::Node.from(xml)
      value = fetch_value(xml)
      value = default if value.nil?

      freeze(apply_blocks(value))
    end

  private
    attr_reader :opts

    def conventionize(what)
      convention ||= @instance.class.respond_to?(:roxml_naming_convention) && @instance.class.roxml_naming_convention
      if !what.blank? && convention.respond_to?(:call)
        URI.unescape(convention.call(URI.escape(what, /\/|::/)))
      else
        what
      end
    end

    def namespacify(what)
      if what.present? && namespace = @instance.class.roxml_namespace
        "#{namespace}:#{what}"
      else
        what
      end
    end

    def apply_blocks(val)
      begin
        blocks.inject(val) {|val, block| block.call(val) }
      rescue Exception => ex
        raise ex, "#{accessor}: #{ex.message}"
      end
    end

    def freeze(val)
      if opts.frozen?
        val.each(&:freeze) if val.is_a?(Enumerable)
        val.freeze
      else
        val
      end
    end

    def xpath
      opts.wrapper ? "#{opts.wrapper}/#{xpath_name}" : xpath_name.to_s
    end

    def auto_xpath
      "#{namespacify(conventionize(opts.name.pluralize))}/#{xpath_name}" if array?
    end

    def wrap(xml)
      return xml if !wrapper || xml.name == wrapper
      if child = xml.children.find {|c| c.name == wrapper }
       return child
      end
      xml.add_child(XML::Node.create(wrapper.to_s))
    end

    def nodes_in(xml)
      vals = xml.search(xpath)

      if (opts.hash? || opts.array?) && vals.empty? && !wrapper && auto_xpath
        vals = xml.search(auto_xpath)
        @auto_vals = !vals.empty?
      end

      if vals.empty?
        raise RequiredElementMissing, "#{name} from #{xml} for #{accessor}" if required?
        default
      else
{'fraction_non_alphanumeric': 0.11634036144578314, 'fraction_numerical': 0.0, 'mean_word_length': 2.35205047318612, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 50}, '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': '1332470', 'n_tokens_mistral': 1756, 'n_tokens_neox': 1726, 'n_words': 401}