class UKPostcode::Tree

Public Class Methods

new(tree = {}) click to toggle source
# File lib/uk_postcode/tree.rb, line 3
def initialize(tree = {})
  @root = tree
end

Public Instance Methods

compress() click to toggle source
# File lib/uk_postcode/tree.rb, line 11
def compress
  self.class.new(compress_node(@root))
end
filter(leaf_value) click to toggle source
# File lib/uk_postcode/tree.rb, line 15
def filter(leaf_value)
  self.class.new(filter_node(@root, leaf_value))
end
insert(path, value) click to toggle source
# File lib/uk_postcode/tree.rb, line 7
def insert(path, value)
  path[0..-2].inject(@root) { |n, p| n[p] ||= {} }[path.last] = value
end
regexp() click to toggle source
# File lib/uk_postcode/tree.rb, line 19
def regexp
  Regexp.new('^' + node_regexp(@root))
end
to_h() click to toggle source
# File lib/uk_postcode/tree.rb, line 23
def to_h
  @root
end

Private Instance Methods

compress_node(node) click to toggle source
# File lib/uk_postcode/tree.rb, line 37
def compress_node(node)
  if leaf?(node)
    node
  else
    comp = Hash[node.map { |k, v| [k, compress_node(v)] }]
    contains_identical_leaves?(comp) ? comp.values.first : comp
  end
end
contains_identical_leaves?(node) click to toggle source
# File lib/uk_postcode/tree.rb, line 33
def contains_identical_leaves?(node)
  node.values.all? { |t| leaf?(t) } && node.values.uniq.length == 1
end
filter_node(node, leaf_value) click to toggle source
# File lib/uk_postcode/tree.rb, line 46
def filter_node(node, leaf_value)
  if node == leaf_value
    node
  elsif leaf?(node)
    nil
  else
    h = Hash[node.map { |k, v| [k, filter_node(v, leaf_value)] }.
             select { |_, v| v }]
    h.empty? ? nil : h
  end
end
leaf?(node) click to toggle source
# File lib/uk_postcode/tree.rb, line 29
def leaf?(node)
  node.is_a?(Symbol)
end
node_regexp(node) click to toggle source
# File lib/uk_postcode/tree.rb, line 58
def node_regexp(node)
  if leaf?(node)
    ''
  else
    segments = node.map { |k, v| k + node_regexp(v) }
    if segments.length > 1
      if segments.all? { |s| s.length == 1 }
        '[' + segments.join('') + ']'
      else
        '(?:' + segments.join('|') + ')'
      end
    else
      segments.first
    end
  end
end