summaryrefslogtreecommitdiff
path: root/lib/hashie/extensions/strict_key_access.rb
blob: 0edd698e34041c3b09355687c9163eab63efcfcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
module Hashie
  module Extensions
    # SRP: This extension will fail an error whenever a key is accessed that does not exist in the hash.
    #
    #   EXAMPLE:
    #
    #     class StrictKeyAccessHash < Hash
    #       include Hashie::Extensions::StrictKeyAccess
    #     end
    #
    #     >> hash = StrictKeyAccessHash[foo: "bar"]
    #     => {:foo=>"bar"}
    #     >> hash[:foo]
    #     => "bar"
    #     >> hash[:cow]
    #       KeyError: key not found: :cow
    #
    # NOTE: For googlers coming from Python to Ruby, this extension makes a Hash
    # behave more like a "Dictionary".
    #
    module StrictKeyAccess
      class DefaultError < StandardError
        def initialize
          super(
            'Setting or using a default with Hashie::Extensions::StrictKeyAccess does not make sense'
          )
        end
      end

      # NOTE: Defaults don't make any sense with a StrictKeyAccess.
      # NOTE: When key lookup fails a KeyError is raised.
      #
      # Normal:
      #
      #     >> a = Hash.new(123)
      #     => {}
      #     >> a["noes"]
      #     => 123
      #
      # With StrictKeyAccess:
      #
      #     >> a = StrictKeyAccessHash.new(123)
      #     => {}
      #     >> a["noes"]
      #       KeyError: key not found: "noes"
      #
      def [](key)
        fetch(key)
      end

      def default(_ = nil)
        raise DefaultError
      end

      def default=(_)
        raise DefaultError
      end

      def default_proc
        raise DefaultError
      end

      def default_proc=(_)
        raise DefaultError
      end

      def key(value)
        super.tap do |result|
          if result.nil? && (!key?(result) || self[result] != value)
            raise KeyError, "key not found with value of #{value.inspect}"
          end
        end
      end
    end
  end
end