From 0bc048d25d15853a942098360bd940f9b0f7fe64 Mon Sep 17 00:00:00 2001 From: Justin Coyne Date: Fri, 12 May 2017 11:21:58 -0500 Subject: [PATCH] Decompose Blacklight::Utils --- .rubocop.yml | 2 +- lib/blacklight.rb | 4 +- ...=> nested_open_struct_with_hash_access.rb} | 46 ----- .../open_struct_with_hash_access.rb | 49 +++++ ...ested_open_struct_with_hash_access_spec.rb | 17 ++ .../open_struct_with_hash_access_spec.rb | 153 ++++++++++++++++ spec/lib/blacklight/utils_spec.rb | 167 ------------------ 7 files changed, 222 insertions(+), 216 deletions(-) rename lib/blacklight/{utils.rb => nested_open_struct_with_hash_access.rb} (65%) create mode 100644 lib/blacklight/open_struct_with_hash_access.rb create mode 100644 spec/lib/blacklight/nested_open_struct_with_hash_access_spec.rb create mode 100644 spec/lib/blacklight/open_struct_with_hash_access_spec.rb delete mode 100644 spec/lib/blacklight/utils_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index aa297ecb83..8879584048 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -32,7 +32,7 @@ Rails/OutputSafety: Style/MethodMissing: Exclude: - - 'lib/blacklight/utils.rb' + - 'lib/blacklight/nested_open_struct_with_hash_access.rb' # engine_cart block includes conditional, not duplication Bundler/DuplicatedGem: diff --git a/lib/blacklight.rb b/lib/blacklight.rb index 242e0cd280..f365bc3308 100644 --- a/lib/blacklight.rb +++ b/lib/blacklight.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true require 'kaminari' require 'deprecation' -require 'blacklight/utils' -require 'active_support/hash_with_indifferent_access' +require 'blacklight/open_struct_with_hash_access' +require 'blacklight/nested_open_struct_with_hash_access' module Blacklight autoload :AbstractRepository, 'blacklight/abstract_repository' diff --git a/lib/blacklight/utils.rb b/lib/blacklight/nested_open_struct_with_hash_access.rb similarity index 65% rename from lib/blacklight/utils.rb rename to lib/blacklight/nested_open_struct_with_hash_access.rb index dd6b20c800..e9cf33e965 100644 --- a/lib/blacklight/utils.rb +++ b/lib/blacklight/nested_open_struct_with_hash_access.rb @@ -1,52 +1,6 @@ # frozen_string_literal: true require 'ostruct' module Blacklight - ## - # An OpenStruct that responds to common Hash methods - class OpenStructWithHashAccess < OpenStruct - delegate :keys, :each, :map, :has_key?, :key?, :include?, :empty?, :length, :delete, :delete_if, :keep_if, :clear, :reject!, :select!, :replace, :fetch, :to_json, :as_json, :any?, to: :to_h - - ## - # Expose the internal hash - # @return [Hash] - def to_h - @table - end - - def select *args, &block - self.class.new to_h.select(*args, &block) - end - - def sort_by *args, &block - self.class.new Hash[to_h.sort_by(*args, &block)] - end - - def sort_by! *args, &block - replace Hash[to_h.sort_by(*args, &block)] - self - end - - ## - # Merge the values of this OpenStruct with another OpenStruct or Hash - # @param [Hash,#to_h] other_hash - # @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess - def merge other_hash - self.class.new to_h.merge((other_hash if other_hash.is_a? Hash) || other_hash.to_h) - end - - ## - # Merge the values of another OpenStruct or Hash into this object - # @param [Hash,#to_h] other_hash - # @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess - def merge! other_hash - @table.merge!((other_hash if other_hash.is_a? Hash) || other_hash.to_h) - end - - def deep_dup - self.class.new @table.deep_dup - end - end - ## # An OpenStruct refinement that converts any hash-keys into # additional instances of NestedOpenStructWithHashAccess diff --git a/lib/blacklight/open_struct_with_hash_access.rb b/lib/blacklight/open_struct_with_hash_access.rb new file mode 100644 index 0000000000..7a2be0541a --- /dev/null +++ b/lib/blacklight/open_struct_with_hash_access.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +require 'ostruct' +module Blacklight + ## + # An OpenStruct that responds to common Hash methods + class OpenStructWithHashAccess < OpenStruct + delegate :keys, :each, :map, :has_key?, :key?, :include?, :empty?, :length, :delete, :delete_if, :keep_if, :clear, :reject!, :select!, :replace, :fetch, :to_json, :as_json, :any?, to: :to_h + + ## + # Expose the internal hash + # @return [Hash] + def to_h + @table + end + + def select *args, &block + self.class.new to_h.select(*args, &block) + end + + def sort_by *args, &block + self.class.new Hash[to_h.sort_by(*args, &block)] + end + + def sort_by! *args, &block + replace Hash[to_h.sort_by(*args, &block)] + self + end + + ## + # Merge the values of this OpenStruct with another OpenStruct or Hash + # @param [Hash,#to_h] other_hash + # @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess + def merge other_hash + self.class.new to_h.merge((other_hash if other_hash.is_a? Hash) || other_hash.to_h) + end + + ## + # Merge the values of another OpenStruct or Hash into this object + # @param [Hash,#to_h] other_hash + # @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess + def merge! other_hash + @table.merge!((other_hash if other_hash.is_a? Hash) || other_hash.to_h) + end + + def deep_dup + self.class.new @table.deep_dup + end + end +end diff --git a/spec/lib/blacklight/nested_open_struct_with_hash_access_spec.rb b/spec/lib/blacklight/nested_open_struct_with_hash_access_spec.rb new file mode 100644 index 0000000000..0733cddc65 --- /dev/null +++ b/spec/lib/blacklight/nested_open_struct_with_hash_access_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +RSpec.describe Blacklight::NestedOpenStructWithHashAccess do + describe "#deep_dup" do + it "preserves the current class" do + expect(described_class.new(described_class).deep_dup).to be_a_kind_of described_class + end + + it "preserves the default proc" do + nested = described_class.new Hash + + copy = nested.deep_dup + copy.a[:b] = 1 + expect(copy.a[:b]).to eq 1 + end + end +end diff --git a/spec/lib/blacklight/open_struct_with_hash_access_spec.rb b/spec/lib/blacklight/open_struct_with_hash_access_spec.rb new file mode 100644 index 0000000000..46cd2c51a3 --- /dev/null +++ b/spec/lib/blacklight/open_struct_with_hash_access_spec.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +RSpec.describe Blacklight::OpenStructWithHashAccess do + it "provides hash-like accessors for OpenStruct data" do + a = described_class.new :foo => :bar, :baz => 1 + + expect(a[:foo]).to eq :bar + expect(a[:baz]).to eq 1 + expect(a[:asdf]).to be_nil + end + + it "provides hash-like writers for OpenStruct data" do + a = described_class.new :foo => :bar, :baz => 1 + + a[:asdf] = 'qwerty' + expect(a.asdf).to eq 'qwerty' + + end + + it "treats symbols and strings interchangeably in hash access" do + h = described_class.new + + h["string"] = "value" + expect(h[:string]).to eq "value" + expect(h.string).to eq "value" + + h[:symbol] = "value" + expect(h["symbol"]).to eq "value" + expect(h.symbol).to eq "value" + end + + describe "internal hash table" do + before do + @h = described_class.new + @h[:a] = 1 + @h[:b] = 2 + end + + it "exposes the internal hash table" do + expect(@h.to_h).to be_a_kind_of(Hash) + expect(@h.to_h[:a]).to eq 1 + end + + it "exposes keys" do + expect(@h.keys).to include(:a, :b) + end + + end + + describe "#key?" do + subject do + h = described_class.new + h[:a] = 1 + h[:b] = 2 + h + end + + it "is true if the key exists" do + expect(subject.key? :a).to eq true + end + + it "is false if the key does not exist" do + expect(subject.key? :c).to eq false + end + end + + describe "#replace" do + subject { described_class.new a: 1 } + + it "can use #replace to reorder the hash" do + subject.replace b: 1 + expect(subject.b).to eq 1 + end + end + + describe "#sort_by" do + subject { described_class.new c: 3, b:1, a: 2 } + + it "sorts the underlying hash" do + sorted = subject.sort_by { |k,v| v } + expect(sorted.keys).to match_array [:b, :a, :c] + end + end + + describe "#sort_by!" do + subject { described_class.new c: 3, b:1, a: 2 } + + it "sorts the underlying hash" do + subject.sort_by! { |k,v| v } + expect(subject.keys).to match_array [:b, :a, :c] + end + end + + describe "#merge" do + + before do + @h = described_class.new + @h[:a] = 1 + @h[:b] = 2 + end + + it "merges the object with a hash" do + expect(@h.merge(:a => 'a')[:a]).to eq 'a' + end + + it "merges the object with another struct" do + expect(@h.merge(described_class.new(:a => 'a'))[:a]).to eq 'a' + end + end + + + describe "#merge!" do + + before do + @h = described_class.new + @h[:a] = 1 + @h[:b] = 2 + end + + it "merges the object with a hash" do + @h.merge!(:a => 'a') + expect(@h[:a]).to eq 'a' + end + + it "merges the object with another struct" do + @h.merge!(described_class.new(:a => 'a')) + expect(@h[:a]).to eq 'a' + end + end + + describe "#to_json" do + subject { described_class.new a: 1, b: 2} + + it "serializes as json" do + expect(subject.to_json).to eq ({a: 1, b:2}).to_json + end + end + + describe "#deep_dup" do + subject { described_class.new a: 1, b: { c: 1} } + + it "duplicates nested hashes" do + copy = subject.deep_dup + copy.a = 2 + copy.b[:c] = 2 + + expect(subject.a).to eq 1 + expect(subject.b[:c]).to eq 1 + expect(copy.a).to eq 2 + expect(copy.b[:c]).to eq 2 + end + end +end diff --git a/spec/lib/blacklight/utils_spec.rb b/spec/lib/blacklight/utils_spec.rb deleted file mode 100644 index d994f0e8f4..0000000000 --- a/spec/lib/blacklight/utils_spec.rb +++ /dev/null @@ -1,167 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe 'Blacklight::Utils' do - describe Blacklight::OpenStructWithHashAccess do - it "provides hash-like accessors for OpenStruct data" do - a = Blacklight::OpenStructWithHashAccess.new :foo => :bar, :baz => 1 - - expect(a[:foo]).to eq :bar - expect(a[:baz]).to eq 1 - expect(a[:asdf]).to be_nil - end - - it "provides hash-like writers for OpenStruct data" do - a = Blacklight::OpenStructWithHashAccess.new :foo => :bar, :baz => 1 - - a[:asdf] = 'qwerty' - expect(a.asdf).to eq 'qwerty' - - end - - it "treats symbols and strings interchangeably in hash access" do - h = Blacklight::OpenStructWithHashAccess.new - - h["string"] = "value" - expect(h[:string]).to eq "value" - expect(h.string).to eq "value" - - h[:symbol] = "value" - expect(h["symbol"]).to eq "value" - expect(h.symbol).to eq "value" - end - - describe "internal hash table" do - before do - @h = Blacklight::OpenStructWithHashAccess.new - @h[:a] = 1 - @h[:b] = 2 - end - - it "exposes the internal hash table" do - expect(@h.to_h).to be_a_kind_of(Hash) - expect(@h.to_h[:a]).to eq 1 - end - - it "exposes keys" do - expect(@h.keys).to include(:a, :b) - end - - end - - describe "#key?" do - subject do - h = Blacklight::OpenStructWithHashAccess.new - h[:a] = 1 - h[:b] = 2 - h - end - - it "is true if the key exists" do - expect(subject.key? :a).to eq true - end - - it "is false if the key does not exist" do - expect(subject.key? :c).to eq false - end - end - - describe "#replace" do - subject { Blacklight::OpenStructWithHashAccess.new a: 1 } - - it "can use #replace to reorder the hash" do - subject.replace b: 1 - expect(subject.b).to eq 1 - end - end - - describe "#sort_by" do - subject { Blacklight::OpenStructWithHashAccess.new c: 3, b:1, a: 2 } - - it "sorts the underlying hash" do - sorted = subject.sort_by { |k,v| v } - expect(sorted.keys).to match_array [:b, :a, :c] - end - end - - describe "#sort_by!" do - subject { Blacklight::OpenStructWithHashAccess.new c: 3, b:1, a: 2 } - - it "sorts the underlying hash" do - subject.sort_by! { |k,v| v } - expect(subject.keys).to match_array [:b, :a, :c] - end - end - - describe "#merge" do - - before do - @h = Blacklight::OpenStructWithHashAccess.new - @h[:a] = 1 - @h[:b] = 2 - end - - it "merges the object with a hash" do - expect(@h.merge(:a => 'a')[:a]).to eq 'a' - end - - it "merges the object with another struct" do - expect(@h.merge(Blacklight::OpenStructWithHashAccess.new(:a => 'a'))[:a]).to eq 'a' - end - end - - - describe "#merge!" do - - before do - @h = Blacklight::OpenStructWithHashAccess.new - @h[:a] = 1 - @h[:b] = 2 - end - - it "merges the object with a hash" do - @h.merge!(:a => 'a') - expect(@h[:a]).to eq 'a' - end - - it "merges the object with another struct" do - @h.merge!(Blacklight::OpenStructWithHashAccess.new(:a => 'a')) - expect(@h[:a]).to eq 'a' - end - end - - describe "#to_json" do - subject { Blacklight::OpenStructWithHashAccess.new a: 1, b: 2} - - it "serializes as json" do - expect(subject.to_json).to eq ({a: 1, b:2}).to_json - end - end - - describe "#deep_dup" do - subject { Blacklight::OpenStructWithHashAccess.new a: 1, b: { c: 1} } - - it "duplicates nested hashes" do - copy = subject.deep_dup - copy.a = 2 - copy.b[:c] = 2 - - expect(subject.a).to eq 1 - expect(subject.b[:c]).to eq 1 - expect(copy.a).to eq 2 - expect(copy.b[:c]).to eq 2 - end - - it "preserves the current class" do - expect(Blacklight::NestedOpenStructWithHashAccess.new(Blacklight::NestedOpenStructWithHashAccess).deep_dup).to be_a_kind_of Blacklight::NestedOpenStructWithHashAccess - end - - it "preserves the default proc" do - nested = Blacklight::NestedOpenStructWithHashAccess.new Hash - - copy = nested.deep_dup - copy.a[:b] = 1 - expect(copy.a[:b]).to eq 1 - end - end - end -end