Skip to content

Commit

Permalink
Decompose Blacklight::Utils
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoyne committed May 12, 2017
1 parent 5b1a46c commit 0bc048d
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 216 deletions.
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions lib/blacklight.rb
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
49 changes: 49 additions & 0 deletions lib/blacklight/open_struct_with_hash_access.rb
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions spec/lib/blacklight/nested_open_struct_with_hash_access_spec.rb
Original file line number Diff line number Diff line change
@@ -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
153 changes: 153 additions & 0 deletions spec/lib/blacklight/open_struct_with_hash_access_spec.rb
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 0bc048d

Please sign in to comment.