/
about_hashes.rb
145 lines (119 loc) · 4.15 KB
/
about_hashes.rb
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
require File.expand_path(File.dirname(__FILE__) + '/neo')
class AboutHashes < Neo::Koan
def test_creating_hashes
empty_hash = Hash.new
assert_equal Hash, empty_hash.class
assert_equal({}, empty_hash)
assert_equal 0, empty_hash.size
end
def test_hash_literals
hash = { :one => "uno", :two => "dos" }
assert_equal 2, hash.size
end
def test_accessing_hashes
hash = { :one => "uno", :two => "dos" }
assert_equal 'uno', hash[:one]
assert_equal 'dos', hash[:two]
assert_equal nil, hash[:doesnt_exist]
end
def test_accessing_hashes_with_fetch
hash = { :one => "uno" }
assert_equal 'uno', hash.fetch(:one)
assert_raise(KeyError) do
hash.fetch(:doesnt_exist)
end
# THINK ABOUT IT:
#
# Why might you want to use #fetch instead of #[] when accessing hash keys?
#
# Answer: when you want better control over what happens when the hash
# doesn't contain the key. You can set it to a default, or have it raise
# an exception, or pass in a block that runs and returns a result
end
def test_changing_hashes
hash = { :one => "uno", :two => "dos" }
hash[:one] = "eins"
expected = { :one => 'eins', :two => "dos" }
assert_equal expected, hash
# Bonus Question: Why was "expected" broken out into a variable
# rather than used as a literal?
#
# Answer: There's an argument that expected is more readable than using a
# hash literal, but the real answer is that calling assert_equal with a
# hash literal as its first argument *without using parentheses* causes
# a syntax error. For example, this would be ok:
#
# assert_equal({:one => 'one', :two => 'two'}, hash1)
#
# but this is not:
#
# assert_equal {:one => 'one', :two => 'two'}, hash1
#
# because it interprets the hash literal to be a block.
end
def test_hash_is_unordered
hash1 = { :one => "uno", :two => "dos" }
hash2 = { :two => "dos", :one => "uno" }
assert_equal true, hash1 == hash2
end
# Hash keys and values are returned as arrays
def test_hash_keys
hash = { :one => "uno", :two => "dos" }
assert_equal 2, hash.keys.size
assert_equal true, hash.keys.include?(:one)
assert_equal true, hash.keys.include?(:two)
assert_equal Array, hash.keys.class
end
def test_hash_values
hash = { :one => "uno", :two => "dos" }
assert_equal 2, hash.values.size
assert_equal true, hash.values.include?("uno")
assert_equal true, hash.values.include?("dos")
assert_equal Array, hash.values.class
end
# Calling merge on a hash returns a merged hash but does not alter the
# original hash.
def test_combining_hashes
hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
new_hash = hash.merge({ "jim" => 54, "jenny" => 26 })
assert_equal true, hash != new_hash
expected = { "jim" => 54, "amy" => 20, "dan" => 23, "jenny" => 26 }
assert_equal true, expected == new_hash
end
# You can set up a default value to be returned for all hash accesses with
# unknown keys.
def test_default_value
hash1 = Hash.new
hash1[:one] = 1
assert_equal 1, hash1[:one]
assert_equal nil, hash1[:two]
hash2 = Hash.new("dos")
hash2[:one] = 1
assert_equal 1, hash2[:one]
assert_equal 'dos', hash2[:two]
end
# Note: head asplode! There's only one default object, and any
# reference into the hash with a nonexistent key will return that unique
# default object.
#
# This code below gives strange behavior. After pushing "uno" and "dos",
# the hash is still technically empty, but the default value is now ==
# ['uno', 'dos'].
def test_default_value_is_the_same_object
hash = Hash.new([])
hash[:one] << "uno"
hash[:two] << "dos"
assert_equal ['uno', 'dos'], hash[:one]
assert_equal ['uno', 'dos'], hash[:two]
assert_equal ['uno', 'dos'], hash[:three]
assert_equal true, hash[:one].object_id == hash[:two].object_id
end
def test_default_value_with_block
hash = Hash.new {|hash, key| hash[key] = [] }
hash[:one] << "uno"
hash[:two] << "dos"
assert_equal ['uno'], hash[:one]
assert_equal ['dos'], hash[:two]
assert_equal [], hash[:three]
end
end