File: casting_hash.rb

package info (click to toggle)
ruby-hashery 2.1.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 404 kB
  • sloc: ruby: 2,997; makefile: 7
file content (164 lines) | stat: -rw-r--r-- 3,346 bytes parent folder | download | duplicates (4)
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
77
78
79
80
81
82
83
84
85
86
87
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
require 'hashery/crud_hash'

module Hashery

  # CastingHash is just like CRUDHash, except that both keys and values
  # can be passed through casting procedures.
  #
  class CastingHash < CRUDHash

    #
    # Like `#new` but can take a priming Hash or Array-pairs.
    #
    # hash - Hash-like object.
    #
    # Examples
    #
    #   CastingHash[:a,1,:b,2]
    #
    # Returns `CastingHash`.
    #
    def self.[](hash)
      s = new
      hash.each{ |k,v| s[k] = v }
      s
    end

    #
    # Unlike traditional Hash a CastingHash's block argument
    # coerces key/value pairs when #store is called.
    #
    # default   - Default value.
    # cast_proc - Casting procedure.
    #
    def initialize(default=nil, &cast_proc)
      @cast_proc = cast_proc
      super(default, &nil)
    end

    #
    # The cast procedure.
    #
    # proc - Casting procedure.
    #
    # Returns `Proc` used for casting.
    #
    def cast_proc(&proc)
      @cast_proc = proc if proc
      @cast_proc
    end

    #
    # Set `cast_proc`. This procedure must take two arguments (`key, value`)
    # and return the same.
    #
    # proc - Casting procedure.
    #
    # Returns +proc+.
    #
    def cast_proc=(proc)
      raise ArgumentError unless Proc === proc or NilClass === proc
      @cast_proc = proc
    end

    #
    # CRUD method for create and update. Unlike the parent class
    # the key, value pair are passed threw the cast_proc before
    # being set in the underlying hash table.
    #
    # key   - Key of entry.
    # value - Value of entry.
    #
    # Returns the +value+.
    #
    def store(key, value)
      super(*cast_pair(key, value))
    end

    #
    # Replace current entries with those from another Hash,
    # or Hash-like object. Each entry is run through the
    # casting procedure as it is added.
    #
    # other - Hash-like object.
    #
    # Returns +self+.
    # 
    def replace(other)
      super cast(other)
    end

    #
    # Convert the CastingHash to a regular Hash.
    #
    # Returns an ordinary `Hash`.
    #
    def to_hash
      h = {}; each{ |k,v| h[k] = v }; h
    end

    #
    # Returns an ordinary `Hash`.
    #
    alias_method :to_h, :to_hash

    #
    # Recast all entries via the cast procedure.
    #
    # TODO: Isn't this the same as `#rehash`?
    #
    # Returns +self+.
    #
    def recast!
      replace self
    end

  private

    #
    # If `cast_proc` is defined then use it to process key-value pair,
    # otherwise return them as is.
    #
    # key   - Key of entry.
    # value - Value of entry.
    #
    # Returns `Array` of key-value pair.
    #
    def cast_pair(key, value)
      if cast_proc
        return cast_proc.call(key, value)
      else
        return key, value
      end
    end

    #
    # Cast a given +hash+ according to the `#key_proc` and `#value_proc`.
    #
    # hash - A `Hash` or anything the responds to `#each` like a hash.
    #
    # Returns a recasted `Hash`.
    #
    def cast(hash)
      h = {}
      hash.each do |k,v|
        k, v = cast_pair(k, v)
        h[k] = v
      end
      h
    end

  end

end

# TODO: Should we add #to_casting_hash to Hash classs?

#class Hash
#
#  # Convert a Hash to a CastingHash.
#  def to_casting_hash(value_cast=nil, &key_cast)
#    CastingHash.new(self, value_cast, &key_cast)
#  end
#
#end