<commit_before>module DiasporaFederation
  module WebFinger
    ##
    # This class implements basic handling of XRD documents as far as it is
    # necessary in the context of the protocols used with Diaspora* federation.
    #
    # @note {http://tools.ietf.org/html/rfc6415 RFC 6415} recommends that servers
    #   should also offer the JRD format in addition to the XRD representation.
    #   Implementing +XrdDocument#to_json+ and +XrdDocument.json_data+ should
    #   be almost trivial due to the simplicity of the format and the way the data
    #   is stored internally already. See
    #   {http://tools.ietf.org/html/rfc6415#appendix-A RFC 6415, Appendix A}
    #   for a description of the JSON format.
    #
    # @example Creating a XrdDocument
    #   doc = XrdDocument.new
    #   doc.expires = DateTime.new(2020, 1, 15, 0, 0, 1)
    #   doc.subject = "http://example.tld/articles/11""
    #   doc.aliases << "http://example.tld/cool_article"
    #   doc.aliases << "http://example.tld/authors/2/articles/3"
    #   doc.properties["http://x.example.tld/ns/version"] = "1.3"
    #   doc.links << { rel: "author", type: "text/html", href: "http://example.tld/authors/2" }
    #   doc.links << { rel: "copyright", template: "http://example.tld/copyright?id={uri}" }
    #
    #   doc.to_xml
    #
    # @example Parsing a XrdDocument
    #   data = XrdDocument.xml_data(xml_string)
    #
    # @see http://docs.oasis-open.org/xri/xrd/v1.0/xrd-1.0.html Extensible Resource Descriptor (XRD) Version 1.0
    class XrdDocument
      # xml namespace url
      XMLNS = "http://docs.oasis-open.org/ns/xri/xrd-1.0"

      # +Link+ element attributes
      LINK_ATTRS = %i(rel type href template)

      # format string for datetime (+Expires+ element)
      DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"

      attr_writer :expires, :subject

      # @return [Array<String>] list of alias URIs
      attr_reader :aliases

      # @return [Hash<String => mixed>] list of properties. Hash key represents the
      #   +type+ attribute, and the value is the element content
      attr_reader :properties

      # @return [Array<Hash<attr => val>>] list of +Link+ element hashes. Each
      #   hash contains the attributesa and their associated values for the +Link+
      #   element.
      attr_reader :links

      def initialize
        @aliases = []
        @links = []
        @properties = {}
      end

      ##
      # Generates an XML document from the current instance and returns it as string
      # @return [String] XML document
      def to_xml
        builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
          xml.XRD("xmlns" => XMLNS) {
            if !@expires.nil? && @expires.instance_of?(DateTime)
              xml.Expires(@expires.strftime(DATETIME_FORMAT))
            end

            xml.Subject(@subject) if !@subject.nil? && !@subject.empty?

            @aliases.each do |a|
              next if !a.instance_of?(String) || a.empty?
              xml.Alias(a.to_s)
            end

            @properties.each do |type, val|
              xml.Property(val.to_s, type: type)
            end

            @links.each do |l|
              attrs = {}
              LINK_ATTRS.each do |attr|
                attrs[attr.to_s] = l[attr] if l.key?(attr)
              end
              xml.Link(attrs)
            end
          }
        end
        builder.to_xml
      end

      ##
      # Parse the XRD document from the given string and create a hash containing
      # the extracted data.
      #
      # Small bonus: the hash structure that comes out of this method is the same
      # as the one used to produce a JRD (JSON Resource Descriptor) or parsing it.
      #
      # @param [String] xrd_doc XML string
      # @return [Hash] extracted data
      # @raise [InvalidDocument] if the XRD is malformed
      def self.xml_data(xrd_doc)
        raise ArgumentError unless xrd_doc.instance_of?(String)

        doc = Nokogiri::XML::Document.parse(xrd_doc)
        raise InvalidDocument, "Not an XRD document" if !doc.root || doc.root.name != "XRD"

        data = {}
        ns = {xrd: XMLNS}

        exp_elem = doc.at_xpath("xrd:XRD/xrd:Expires", ns)
        unless exp_elem.nil?
          data[:expires] = DateTime.strptime(exp_elem.content, DATETIME_FORMAT)
        end

        subj_elem = doc.at_xpath("xrd:XRD/xrd:Subject", ns)
        data[:subject] = subj_elem.content unless subj_elem.nil?

        aliases = []
        doc.xpath("xrd:XRD/xrd:Alias", ns).each do |node|
          aliases << node.content
        end
        data[:aliases] = aliases unless aliases.empty?

        properties = {}
        doc.xpath("xrd:XRD/xrd:Property", ns).each do |node|
          properties[node[:type]] = node.children.empty? ? nil : node.content
        end
        data[:properties] = properties unless properties.empty?

        links = []
        doc.xpath("xrd:XRD/xrd:Link", ns).each do |node|
          link = {}
          LINK_ATTRS.each do |attr|
            link[attr] = node[attr.to_s] if node.key?(attr.to_s)
          end
          links << link
        end
        data[:links] = links unless links.empty?

        data
      end

      # Raised, if the XML structure is invalid
      class InvalidDocument < RuntimeError
      end
    end
  end
end<commit_msg>extract aliasses, properties and links to own methods<commit_after>module DiasporaFederation
  module WebFinger
    ##
    # This class implements basic handling of XRD documents as far as it is
    # necessary in the context of the protocols used with Diaspora* federation.
    #
    # @note {http://tools.ietf.org/html/rfc6415 RFC 6415} recommends that servers
    #   should also offer the JRD format in addition to the XRD representation.
    #   Implementing +XrdDocument#to_json+ and +XrdDocument.json_data+ should
    #   be almost trivial due to the simplicity of the format and the way the data
    #   is stored internally already. See
    #   {http://tools.ietf.org/html/rfc6415#appendix-A RFC 6415, Appendix A}
    #   for a description of the JSON format.
    #
    # @example Creating a XrdDocument
    #   doc = XrdDocument.new
    #   doc.expires = DateTime.new(2020, 1, 15, 0, 0, 1)
    #   doc.subject = "http://example.tld/articles/11""
    #   doc.aliases << "http://example.tld/cool_article"
    #   doc.aliases << "http://example.tld/authors/2/articles/3"
    #   doc.properties["http://x.example.tld/ns/version"] = "1.3"
    #   doc.links << { rel: "author", type: "text/html", href: "http://example.tld/authors/2" }
    #   doc.links << { rel: "copyright", template: "http://example.tld/copyright?id={uri}" }
    #
    #   doc.to_xml
    #
    # @example Parsing a XrdDocument
    #   data = XrdDocument.xml_data(xml_string)
    #
    # @see http://docs.oasis-open.org/xri/xrd/v1.0/xrd-1.0.html Extensible Resource Descriptor (XRD) Version 1.0
    class XrdDocument
      # xml namespace url
      XMLNS = "http://docs.oasis-open.org/ns/xri/xrd-1.0"

      # +Link+ element attributes
      LINK_ATTRS = %i(rel type href template)

      # format string for datetime (+Expires+ element)
      DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"

      attr_writer :expires, :subject

      # @return [Array<String>] list of alias URIs
      attr_reader :aliases

      # @return [Hash<String => mixed>] list of properties. Hash key represents the
      #   +type+ attribute, and the value is the element content
      attr_reader :properties

      # @return [Array<Hash<attr => val>>] list of +Link+ element hashes. Each
      #   hash contains the attributesa and their associated values for the +Link+
      #   element.
      attr_reader :links

      def initialize
        @aliases = []
        @links = []
        @properties = {}
      end

      ##
      # Generates an XML document from the current instance and returns it as string
      # @return [String] XML document
      def to_xml
        builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
          xml.XRD("xmlns" => XMLNS) {
            xml.Expires(@expires.strftime(DATETIME_FORMAT)) if @expires.instance_of?(DateTime)

            xml.Subject(@subject) if !@subject.nil? && !@subject.empty?

            add_aliases_to(xml)
            add_properties_to(xml)
            add_links_to(xml)
          }
        end
        builder.to_xml
      end

      ##
      # Parse the XRD document from the given string and create a hash containing
      # the extracted data.
      #
      # Small bonus: the hash structure that comes out of this method is the same
      # as the one used to produce a JRD (JSON Resource Descriptor) or parsing it.
      #
      # @param [String] xrd_doc XML string
      # @return [Hash] extracted data
      # @raise [InvalidDocument] if the XRD is malformed
      def self.xml_data(xrd_doc)
        doc = parse_xrd_document(xrd_doc)
        data = {}

        exp_elem = doc.at_xpath("xrd:XRD/xrd:Expires", NS)
        data[:expires] = DateTime.strptime(exp_elem.content, DATETIME_FORMAT) unless exp_elem.nil?

        subj_elem = doc.at_xpath("xrd:XRD/xrd:Subject", NS)
        data[:subject] = subj_elem.content unless subj_elem.nil?

        parse_aliases_from_xml_doc(doc, data)
        parse_properties_from_xml_doc(doc, data)
        parse_links_from_xml_doc(doc, data)

        data
      end

      private

      NS = {xrd: XMLNS}

      def add_aliases_to(xml)
        @aliases.each do |a|
          next if !a.instance_of?(String) || a.empty?
          xml.Alias(a.to_s)
        end
      end

      def add_properties_to(xml)
        @properties.each do |type, val|
          xml.Property(val.to_s, type: type)
        end
      end

      def add_links_to(xml)
        @links.each do |l|
          attrs = {}
          LINK_ATTRS.each do |attr|
            attrs[attr.to_s] = l[attr] if l.key?(attr)
          end
          xml.Link(attrs)
        end
      end

      def self.parse_xrd_document(xrd_doc)
        raise ArgumentError unless xrd_doc.instance_of?(String)

        doc = Nokogiri::XML::Document.parse(xrd_doc)
        raise InvalidDocument, "Not an XRD document" if !doc.root || doc.root.name != "XRD"
        doc
      end

      def self.parse_aliases_from_xml_doc(doc, data)
        aliases = []
        doc.xpath("xrd:XRD/xrd:Alias", NS).each do |node|
          aliases << node.content
        end
        data[:aliases] = aliases unless aliases.empty?
      end

      def self.parse_properties_from_xml_doc(doc, data)
        properties = {}
        doc.xpath("xrd:XRD/xrd:Property", NS).each do |node|
          properties[node[:type]] = node.children.empty? ? nil : node.content
        end
        data[:properties] = properties unless properties.empty?
      end

      def self.parse_links_from_xml_doc(doc, data)
        links = []
        doc.xpath("xrd:XRD/xrd:Link", NS).each do |node|
          link = {}
          LINK_ATTRS.each do |attr|
            link[attr] = node[attr.to_s] if node.key?(attr.to_s)
          end
          links << link
        end
        data[:links] = links unless links.empty?
      end

      # Raised, if the XML structure is invalid
      class InvalidDocument < RuntimeError
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.11051693404634581, 'fraction_numerical': 0.0074866310160427805, 'mean_word_length': 2.2087503574492424, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 42}, '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': '2552691', 'n_tokens_mistral': 3664, 'n_tokens_neox': 3527, 'n_words': 932}