lib/twitter_cldr/transforms/transformer.rb (141 lines of code) (raw):
# encoding: UTF-8
# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0
module TwitterCldr
module Transforms
class InvalidTransformRuleError < StandardError; end
class Transformer
RULE_CLASSES = [
CommentRule,
VariableRule,
Transforms::TransformRule,
Filters::FilterRule,
Conversions::ConversionRule,
]
class << self
def exists?(transform_id_or_str)
!!get(transform_id_or_str)
rescue => e
false
end
def get(transform_id_or_str)
id = parse_id(transform_id_or_str)
if resource_exists?(id)
load(id).forward_rule_set
else
reversed_id = id.reverse
if resource_exists?(reversed_id)
load(reversed_id).backward_rule_set
end
end
end
def each_transform
if block_given?
TransformId.transform_id_map.each do |aliass, _|
yield aliass
end
else
to_enum(__method__)
end
end
private
def parse_id(transform_id)
case transform_id
when TransformId
transform_id
else
TransformId.parse(transform_id)
end
end
def load(transform_id)
transformers[transform_id.to_s] ||= begin
resource = resource_for(transform_id)
direction = direction_from(resource)
new(parse_resource(resource), direction, transform_id)
end
end
def build(rule_list, direction)
rules = parse_rules(rule_list)
new(rules, direction)
end
def direction_from(resource)
case transform_from(resource)[:direction]
when 'both'
:bidirectional
else
:forward
end
end
def transformers
@transformers ||= {}
end
def parse_resource(resource)
parse_rules(rules_from(resource))
end
def parse_rules(rule_list)
symbol_table = {}
rules = []
parse_each_rule(rule_list, symbol_table) do |rule|
if rule.is_variable?
symbol_table[rule.name] = rule
elsif !rule.is_comment?
rules << rule
end
end
rules
end
def parse_each_rule(rule_list, symbol_table)
rule_list.each_with_index do |rule_text, idx|
if klass = identify_class(rule_text)
rule = klass.parse(
rule_text, symbol_table, idx
)
yield rule
else
raise InvalidTransformRuleError,
"Invalid rule: '#{rule_text}'"
end
end
end
def identify_class(rule_text)
RULE_CLASSES.find do |klass|
klass.accepts?(rule_text)
end
end
def rules_from(resource)
transform_from(resource)[:rules]
end
def transform_from(resource)
resource[:transforms].first
end
def resource_for(transform_id)
TwitterCldr.get_resource(
'shared', 'transforms', transform_id.file_name
)
end
def resource_exists?(transform_id)
TwitterCldr.resource_exists?(
'shared', 'transforms', transform_id.file_name
)
end
end
attr_reader :rules, :direction, :transform_id
def initialize(rules, direction, transform_id)
@rules = rules
@direction = direction
@transform_id = transform_id
end
# all rules are either forward or bidirectional
def bidirectional?
direction == :bidirectional
end
def forward_rule_set
@forward_rule_set ||= RuleSet.new(rules, transform_id)
end
def backward_rule_set
if bidirectional?
@backward_rule_set ||= forward_rule_set.invert
else
raise NotInvertibleError,
"cannot invert this #{self.class.name}"
end
end
end
end
end