twitter/twitter-cldr-rb

View on GitHub
lib/twitter_cldr/transforms/conversions/parser.rb

Summary

Maintainability
A
1 hr
Test Coverage
# encoding: UTF-8

# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0

module TwitterCldr
  module Transforms
    module Conversions

      class Parser < TwitterCldr::Parsers::Parser
        private

        def do_parse(options)
          first_side = side
          direction = get_direction_from(current_token)
          next_token(:direction)
          second_side = side

          first_side, second_side = rearrange_sides(
            direction, first_side, second_side
          )

          ConversionRule.new(
            direction, first_side, second_side,
            options[:original_rule_text],
            options[:index]
          )
        end

        def rearrange_sides(direction, first_side, second_side)
          case direction
            when :backward
              [second_side, first_side]
            else
              [first_side, second_side]
          end
        end

        # a { b | c } d <> e { f | g } h ;
        def side
          prev_cluster = next_token_cluster
          before_context = nil
          after_context = nil
          key = nil
          cursor_offset = 0

          until current_token.type == :direction || current_token.type == :semicolon
            case current_token.type
              when :before_context
                before_context = prev_cluster
                next_token(:before_context)
                prev_cluster = next_token_cluster
              when :cursor
                next_token(:cursor)
                cur_cluster = next_token_cluster
                key = prev_cluster + cur_cluster
                prev_cluster = cur_cluster
                cursor_offset = -cur_cluster.size
              when :after_context
                next_token(:after_context)
                after_context = next_token_cluster
            end
          end

          key ||= prev_cluster

          Side.new(
            join_values(before_context),
            key,
            join_values(after_context),
            cursor_offset
          )
        end

        def join_values(tokens)
          Array(tokens).map(&:value).join
        end

        def next_token_cluster
          tokens = []

          until is_operator?(current_token) || current_token.type == :semicolon
            tokens << current_token
            next_token(current_token.type)
          end

          tokens
        end

        def is_operator?(token)
          case token.type
            when :direction, :after_context, :before_context, :cursor
              true
            else
              false
          end
        end

        def get_direction_from(token)
          case token.value
            when '>'
              :forward
            when '<'
              :backward
            when '<>'
              :bidirectional
          end
        end
      end

    end
  end
end