class Hashie::Rash

Rash is a Hash whose keys can be Regexps, or Ranges, which will match many input keys.

A good use case for this class is routing URLs in a web framework. The Rash's keys match URL patterns, and the values specify actions which can handle the URL. When the Rash's value is proc, the proc will be automatically called with the regexp's matched groups as block arguments.

Usage example:

greeting = Hashie::Rash.new( /^Mr./ => "Hello sir!", /^Mrs./ => "Evening, madame." )
greeting["Mr. Steve Austin"] #=> "Hello sir!"
greeting["Mrs. Steve Austin"] #=> "Evening, madame."

Note: The Rash is automatically optimized every 500 accesses

(Regexps get sorted by how often they get matched).
If this is too low or too high, you can tune it by
setting: `rash.optimize_every = n`

Attributes

optimize_every[RW]

Public Class Methods

new(initial = {}) click to toggle source
# File lib/hashie/rash.rb, line 26
def initialize(initial = {})
  @hash           = {}
  @regexes        = []
  @ranges         = []
  @regex_counts   = Hash.new(0)
  @optimize_every = 500
  @lookups        = 0

  update(initial)
end

Public Instance Methods

[](key) click to toggle source

Return the first thing that matches the key.

# File lib/hashie/rash.rb, line 59
def [](key)
  all(key).first
end
[]=(key, value) click to toggle source
# File lib/hashie/rash.rb, line 45
def []=(key, value)
  case key
  when Regexp
    # key = normalize_regex(key)  # this used to just do: /#{regexp}/
    @regexes << key
  when Range
    @ranges << key
  end
  @hash[key] = value
end
all(query) { |hash| ... } click to toggle source

Return everything that matches the query.

# File lib/hashie/rash.rb, line 88
def all(query)
  return to_enum(:all, query) unless block_given?

  if @hash.include? query
    yield @hash[query]
    return
  end

  case query
  when String
    optimize_if_necessary!

    # see if any of the regexps match the string
    @regexes.each do |regex|
      match = regex.match(query)
      next unless match
      @regex_counts[regex] += 1
      value = @hash[regex]
      if value.respond_to? :call
        yield value.call(match)
      else
        yield value
      end
    end

  when Numeric
    # see if any of the ranges match the integer
    @ranges.each do |range|
      yield @hash[range] if range.cover? query
    end

  when Regexp
    # Reverse operation: `rash[/regexp/]` returns all the hash's string keys which match the regexp
    @hash.each do |key, val|
      yield val if key.is_a?(String) && query =~ key
    end
  end
end
fetch(*args) { |key| ... } click to toggle source

Raise (or yield) unless something matches the key.

# File lib/hashie/rash.rb, line 66
def fetch(*args)
  raise ArgumentError, "Expected 1-2 arguments, got #{args.length}"          unless (1..2).cover?(args.length)

  key, default = args

  all(key) do |value|
    return value
  end

  if block_given?
    yield key
  elsif default
    default
  else
    raise KeyError, "key not found: #{key.inspect}"
  end
end
method_missing(*args, &block) click to toggle source
Calls superclass method
# File lib/hashie/rash.rb, line 127
def method_missing(*args, &block)
  @hash.send(*args, &block) || super
end
respond_to_missing?(method_name, _include_private = false) click to toggle source
# File lib/hashie/rash.rb, line 131
def respond_to_missing?(method_name, _include_private = false)
  @hash.respond_to?(method_name)
end
update(other) click to toggle source
# File lib/hashie/rash.rb, line 37
def update(other)
  other.each do |key, value|
    self[key] = value
  end

  self
end

Private Instance Methods

optimize_if_necessary!() click to toggle source
# File lib/hashie/rash.rb, line 137
def optimize_if_necessary!
  return unless (@lookups += 1) >= @optimize_every
  @regexes = @regexes.sort_by { |regex| -@regex_counts[regex] }
  @lookups = 0
end