Skip to content

Commit 70f172c

Browse files
committed
Wrap Api#attributes with indifferent key access
A number of bugs have been introduced or missed due to the way attributes are exposed by fog. Fog transforms the top level of attributes from the JSON sources (String) to Symbols, but does not act recursively. This results in accessing nested structures with a mix of Symbol and String keys which inevitably is missed or incorrectly specced out. This adds a simple wrapper around `Api#attributes` that takes the fog attributes and allows indifferent access with Symbols or Strings.
1 parent 50c3986 commit 70f172c

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

lib/brightbox-cli/api.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ def initialize(model = nil)
5252
Brightbox.config.cache_id(@id) if Brightbox.config.respond_to?(:cache_id)
5353
end
5454

55+
def attributes
56+
IndifferentAccessHash.new(fog_model.attributes)
57+
end
58+
5559
def fog_model
5660
@fog_model ||= self.class.find(@id)
5761
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# A simpler wrapper to allows either String or Symbol keys to be used
2+
# when accessing attributes since fog applies a change on the top
3+
# level resulting in a mix of both which has introduced issues.
4+
class IndifferentAccessHash
5+
def initialize(hash)
6+
@hash = hash
7+
end
8+
9+
# @param key [String, Symbol] the key to look up
10+
# @return [Object] the value of the key
11+
def [](key)
12+
value = @hash[key.to_s] || @hash[key.to_sym]
13+
wrap(value)
14+
end
15+
16+
# @param key [String, Symbol] the key to set
17+
# @param value [Object] the value to set
18+
# @return [Object] the value of the key
19+
def []=(key, value)
20+
@hash[key.to_s] = value
21+
end
22+
23+
# @param other [Object] the object to compare
24+
# @return [Object] the result of the comparison
25+
def ==(other)
26+
@hash == (other.is_a?(IndifferentAccessHash) ? other.to_h : other)
27+
end
28+
29+
def method_missing(method, *args, &block)
30+
@hash.send(method, *args, &block)
31+
end
32+
33+
def to_h
34+
@hash
35+
end
36+
37+
private
38+
39+
# This is to handle nested hashes to avoid the original issue again
40+
def wrap(value)
41+
case value
42+
when Hash
43+
IndifferentAccessHash.new(value)
44+
when Array
45+
value.map { |v| wrap(v) }
46+
else
47+
value
48+
end
49+
end
50+
end

lib/brightbox_cli.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ module Config
7171
require_relative "brightbox-cli/connection_manager"
7272
require_relative "brightbox-cli/tables"
7373
require_relative "brightbox-cli/logging"
74+
require_relative "brightbox-cli/indifferent_access_hash"
7475
require_relative "brightbox-cli/api"
7576
require_relative "brightbox-cli/config/cache"
7677
require_relative "brightbox-cli/config/gpg_encrypted_passwords"

0 commit comments

Comments
 (0)