class Hashie::Rash
setting: ‘rash.optimize_every = n`
If this is too low or too high, you can tune it by
(Regexps get sorted by how often they get matched).
Note: The Rash is automatically optimized every 500 accesses
greeting[“Mrs. Steve Austin”] #=> “Evening, madame.”
greeting[“Mr. Steve Austin”] #=> “Hello sir!”
greeting = Hashie::Rash.new( /^Mr./ => “Hello sir!”, /^Mrs./ => “Evening, madame.” )
Usage example:
block arguments.
will be automatically called with the regexp’s matched groups as
which can handle the URL. When the Rash’s value is proc, the proc
The Rash’s keys match URL patterns, and the values specify actions
A good use case for this class is routing URLs in a web framework.
match many input keys.
Rash is a Hash whose keys can be Regexps, or Ranges, which will
def [](key)
Return the first thing that matches the key.
def [](key) all(key).first end
def []=(key, value)
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
def all(query)
Return everything that matches the query.
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 string keys matching the regexp @hash.each do |key, val| yield val if key.is_a?(String) && query =~ key end end end
def fetch(*args)
Raise (or yield) unless something matches the key.
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
def initialize(initial = {})
def initialize(initial = {}) @hash = {} @regexes = [] @ranges = [] @regex_counts = Hash.new(0) @optimize_every = 500 @lookups = 0 update(initial) end
def method_missing(*args, &block)
def method_missing(*args, &block) @hash.send(*args, &block) || super end
def optimize_if_necessary!
def optimize_if_necessary! return unless (@lookups += 1) >= @optimize_every @regexes = @regexes.sort_by { |regex| -@regex_counts[regex] } @lookups = 0 end
def respond_to_missing?(method_name, _include_private = false)
def respond_to_missing?(method_name, _include_private = false) @hash.respond_to?(method_name) end
def update(other)
def update(other) other.each do |key, value| self[key] = value end self end