diff --git a/lib/anyway/config.rb b/lib/anyway/config.rb index 74ed93d..be89fee 100644 --- a/lib/anyway/config.rb +++ b/lib/anyway/config.rb @@ -2,11 +2,13 @@ require 'anyway/ext/class' require 'anyway/ext/deep_dup' +require 'anyway/ext/deep_freeze' require 'anyway/ext/hash' module Anyway # :nodoc: using Anyway::Ext::Class using Anyway::Ext::DeepDup + using Anyway::Ext::DeepFreeze using Anyway::Ext::Hash # Base config class @@ -95,6 +97,12 @@ def load_from_env(config) config end + def to_h + self.class.config_attributes.each_with_object({}) do |key, obj| + obj[key.to_sym] = send(key) + end.deep_dup.deep_freeze + end + private def set_value(key, val) diff --git a/lib/anyway/ext/deep_freeze.rb b/lib/anyway/ext/deep_freeze.rb new file mode 100644 index 0000000..66aebcd --- /dev/null +++ b/lib/anyway/ext/deep_freeze.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Anyway + module Ext + # Add #deep_freeze to hashes and arrays + module DeepFreeze + refine ::Hash do + def deep_freeze + freeze + each_value do |value| + value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array) + end + end + end + + refine ::Array do + def deep_freeze + freeze + each do |value| + value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array) + end + end + end + end + end +end diff --git a/spec/config_spec.rb b/spec/config_spec.rb index 7e8b6ba..1ffd2d2 100644 --- a/spec/config_spec.rb +++ b/spec/config_spec.rb @@ -26,6 +26,25 @@ expect(conf).to respond_to(:user) end + describe "#to_h" do + subject(:config) { CoolConfig.new } + + it "returns deeply frozen hash" do + hashed = config.to_h + + expect(hashed).to be_a(Hash) + expect(hashed).to be_frozen + expect(hashed[:user]).to be_frozen + end + + it "returns new hash every time" do + hashed = config.to_h + hashed2 = config.to_h + + expect(hashed).to be_eql(hashed2) + end + end + describe "load from files" do it "set defaults" do expect(conf.port).to eq 8080 diff --git a/spec/ext/deep_freeze_spec.rb b/spec/ext/deep_freeze_spec.rb new file mode 100644 index 0000000..729bc9a --- /dev/null +++ b/spec/ext/deep_freeze_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'anyway/ext/deep_freeze' + +describe Anyway::Ext::DeepFreeze do + using Anyway::Ext::DeepFreeze + + it "freezes nested arrays and hashes", :aggregate_failures do + source = { + a: 1, + b: 'hello', + c: { + id: 1, + list: [1, 2, { name: 'John' }] + }, + d: [{ id: 1 }, { id: 2 }] + } + + dup = source.deep_freeze + + expect(dup).to be_frozen + expect(dup[:c]).to be_frozen + expect(dup[:d]).to be_frozen + + expect(dup[:c][:list]).to be_frozen + expect(dup[:c][:list].last).to be_frozen + + expect(dup[:d].first).to be_frozen + expect(dup[:d].last).to be_frozen + end +end