gregbeech/xenon

View on GitHub
xenon-http/lib/xenon/headers/accept_language.rb

Summary

Maintainability
A
2 hrs
Test Coverage
require 'xenon/headers'
require 'xenon/parsers/header_rules'

module Xenon
  class LanguageRange
    attr_reader :language, :q

    DEFAULT_Q = 1.0

    def initialize(language, q = DEFAULT_Q)
      @language = language
      @q = Float(q) || DEFAULT_Q
    end

    def <=>(other)
      @q <=> other.q
    end

    def to_s
      s = @language.dup
      s << "; q=#{@q}" if @q != DEFAULT_Q
      s
    end
  end

  class Headers
    # http://tools.ietf.org/html/rfc7231#section-5.3.5
    class AcceptLanguage < ListHeader 'Accept-Language'
      def initialize(*language_ranges)
        super(language_ranges.sort_by.with_index { |mr, i| [mr, -i] }.reverse)
      end

      alias_method :language_ranges, :values

      def self.parse(s)
        tree = Parsers::AcceptLanguageHeader.new.parse(s)
        Parsers::AcceptLanguageHeaderTransform.new.apply(tree)
      end
    end
  end

  module Parsers
    class AcceptLanguageHeader < Parslet::Parser
      include HeaderRules
      rule(:language) { (alpha.repeat(1, 8) >> (str('-') >> alphanum.repeat(1, 8)).maybe).as(:language) >> sp? }
      rule(:wildcard) { str('*').as(:language) >> sp? }
      rule(:language_range) { (language | wildcard) >> weight.maybe }
      rule(:accept_language) { (language_range >> (list_sep >> language_range).repeat).as(:accept_language) }
      root(:accept_language)
    end

    class AcceptLanguageHeaderTransform < HeaderTransform
      rule(language: simple(:e), q: simple(:q)) { LanguageRange.new(e, q) }
      rule(language: simple(:e)) { LanguageRange.new(e) }
      rule(accept_language: sequence(:lr)) { Headers::AcceptLanguage.new(*lr) }
      rule(accept_language: simple(:lr)) { Headers::AcceptLanguage.new(lr) }
    end
  end
end