Skip to content

Commit 23525be

Browse files
authored
Merge pull request #128 from github/kpaulisse-utility-class
Create and implement utility class
2 parents b706d69 + 583be77 commit 23525be

File tree

3 files changed

+138
-4
lines changed

3 files changed

+138
-4
lines changed

lib/octocatalog-diff/facts.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require_relative 'facts/json'
55
require_relative 'facts/yaml'
66
require_relative 'facts/puppetdb'
7+
require_relative 'util/util'
78
require_relative 'external/pson/pure'
89

910
module OctocatalogDiff
@@ -19,8 +20,7 @@ def initialize(options = {}, facts = nil)
1920
@timestamp = false
2021
@options = options.dup
2122
if facts
22-
@facts = {}
23-
facts.each { |k, v| @facts[k] = v.dup }
23+
@facts = OctocatalogDiff::Util::Util.deep_dup(facts)
2424
else
2525
case options[:backend]
2626
when :json
@@ -32,8 +32,7 @@ def initialize(options = {}, facts = nil)
3232
else
3333
raise ArgumentError, 'Invalid fact source backend'
3434
end
35-
@facts = {}
36-
@orig_facts.each { |k, v| @facts[k] = v.dup }
35+
@facts = OctocatalogDiff::Util::Util.deep_dup(@orig_facts)
3736
end
3837
end
3938

lib/octocatalog-diff/util/util.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# frozen_string_literal: true
2+
3+
# Handy methods that are not tied to one particular class
4+
5+
module OctocatalogDiff
6+
module Util
7+
# Helper class to construct catalogs, performing all necessary steps such as
8+
# bootstrapping directories, installing facts, and running puppet.
9+
class Util
10+
# Utility Method!
11+
# `is_a?(class)` only allows one method, but this uses an array
12+
# @param object [?] Object to consider
13+
# @param classes [Array] Classes to determine if object is a member of
14+
# @return [Boolean] True if object is_a any of the classes, false otherwise
15+
def self.object_is_any_of?(object, classes)
16+
classes.each { |clazz| return true if object.is_a? clazz }
17+
false
18+
end
19+
20+
# Utility Method!
21+
# `.dup` can't be called on certain objects (Fixnum for example). This
22+
# method returns the original object if it can't be duplicated.
23+
# @param object [?] Object to consider
24+
# @return [?] Duplicated object if possible, otherwise the original object
25+
def self.safe_dup(object)
26+
object.dup
27+
rescue TypeError
28+
object
29+
end
30+
31+
# Utility Method!
32+
# This does a "deep" duplication via recursion. Handles hashes and arrays.
33+
# @param object [?] Object to consider
34+
# @return [?] Duplicated object
35+
def self.deep_dup(object)
36+
if object.is_a?(Hash)
37+
result = {}
38+
object.each { |k, v| result[k] = deep_dup(v) }
39+
result
40+
elsif object.is_a?(Array)
41+
object.map { |ele| deep_dup(ele) }
42+
else
43+
safe_dup(object)
44+
end
45+
end
46+
end
47+
end
48+
end
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../spec_helper'
4+
require 'ostruct'
5+
require OctocatalogDiff::Spec.require_path('/util/util')
6+
7+
describe OctocatalogDiff::Util::Util do
8+
describe '#object_is_any_of?' do
9+
it 'should return true when object is one of the classes' do
10+
object = 42
11+
classes = [String, Hash, Integer]
12+
expect(described_class.object_is_any_of?(object, classes)).to eq(true)
13+
end
14+
15+
it 'should return false when object is not one of the classes' do
16+
object = :chickens
17+
classes = [String, Hash, Integer]
18+
expect(described_class.object_is_any_of?(object, classes)).to eq(false)
19+
end
20+
end
21+
22+
describe '#safe_dup' do
23+
it 'should work with nil' do
24+
object = nil
25+
result = described_class.safe_dup(object)
26+
expect(object).to eq(result)
27+
end
28+
29+
it 'should work with a string' do
30+
object = 'boots and cats'
31+
result = described_class.safe_dup(object)
32+
expect(object).to eq(result)
33+
end
34+
35+
it 'should work with a symbol' do
36+
object = :chickens
37+
result = described_class.safe_dup(object)
38+
expect(object).to eq(result)
39+
end
40+
41+
it 'should work with an integer' do
42+
object = 42
43+
result = described_class.safe_dup(object)
44+
expect(object).to eq(result)
45+
end
46+
47+
it 'should work with a hash' do
48+
object = { 'foo' => 'bar', 'baz' => 'buzz' }
49+
result = described_class.safe_dup(object)
50+
expect(object).to eq(result)
51+
expect(object.object_id).not_to eq(result.object_id)
52+
end
53+
54+
it 'should work with an array' do
55+
object = %w[foo bar baz buzz]
56+
result = described_class.safe_dup(object)
57+
expect(object).to eq(result)
58+
expect(object.object_id).not_to eq(result.object_id)
59+
end
60+
end
61+
62+
describe '#deep_dup' do
63+
it 'should dupe a hash' do
64+
hash1 = { 'foo' => 'bar' }
65+
hash2 = { 'baz' => hash1 }
66+
hash3 = { 'xxx' => hash2 }
67+
result = described_class.deep_dup(hash3)
68+
expect(result['xxx']).to eq(hash2)
69+
expect(result['xxx'].object_id).not_to eq(hash2.object_id)
70+
end
71+
72+
it 'should dupe an array' do
73+
array1 = %w[foo bar baz]
74+
array2 = ['foo', array1, 'baz']
75+
array3 = ['foo', array2, 'baz']
76+
result = described_class.deep_dup(array3)
77+
expect(result[1]).to eq(array2)
78+
expect(result[1].object_id).not_to eq(array2.object_id)
79+
end
80+
81+
it 'should dupe a string' do
82+
obj = 'Hello there'
83+
result = described_class.deep_dup(obj)
84+
expect(result).to eq(obj)
85+
end
86+
end
87+
end

0 commit comments

Comments
 (0)