Class: Hashie::Rash

Inherits:
Object
  • Object
show all
Defined in:
lib/hashie/rash.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(initial = {}) ⇒ Rash

Returns a new instance of Rash



26
27
28
29
30
31
32
33
34
35
# 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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*args, &block) ⇒ Object



127
128
129
# File 'lib/hashie/rash.rb', line 127

def method_missing(*args, &block)
  @hash.send(*args, &block)
end

Instance Attribute Details

#optimize_everyObject

Returns the value of attribute optimize_every



24
25
26
# File 'lib/hashie/rash.rb', line 24

def optimize_every
  @optimize_every
end

Instance Method Details

#[](key) ⇒ Object

Return the first thing that matches the key.



59
60
61
# File 'lib/hashie/rash.rb', line 59

def [](key)
  all(key).first
end

#[]=(key, value) ⇒ Object



45
46
47
48
49
50
51
52
53
54
# 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) ⇒ Object

Return everything that matches the query.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# 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) ⇒ Object

Raise (or yield) unless something matches the key.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/hashie/rash.rb', line 66

def fetch(*args)
  fail 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
    fail KeyError, "key not found: #{key.inspect}"
  end
end

#respond_to_missing?(*args) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/hashie/rash.rb', line 131

def respond_to_missing?(*args)
  @hash.respond_to?(*args)
end

#update(other) ⇒ Object



37
38
39
40
41
42
43
# File 'lib/hashie/rash.rb', line 37

def update(other)
  other.each do |key, value|
    self[key] = value
  end

  self
end