Replace Hamster hash for user-accessible data with Hashie Indifferent access

This commit is contained in:
Thomas Reynolds 2015-08-12 15:24:35 -07:00
parent fb6bca234f
commit bb6b8c7f13
7 changed files with 23 additions and 83 deletions

View file

@ -18,16 +18,6 @@ if ENV['TEST'] || ENV['CONTRACTS'] == 'true'
end
end
class Frozen < CallableClass
def initialize(contract)
@contract = contract
end
def valid?(val)
(val.frozen? || val.nil? || [::TrueClass, ::FalseClass, ::Fixnum].include?(val.class)) && Contract.valid?(val, @contract)
end
end
VectorOf = Contracts::CollectionOf::Factory.new(::Hamster::Vector)
ResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']]
end

View file

@ -87,8 +87,8 @@ module Middleman
end
# Data about this resource, populated from frontmatter or extensions.
# @return [IndifferentHash]
Contract IsA['Middleman::Util::IndifferentHash']
# @return [Hash]
Contract RespondTo[:indifferent_access?]
def data
::Middleman::Util.recursively_enhance(metadata[:page])
end

View file

@ -11,8 +11,8 @@ require 'rack/mime'
# DbC
require 'middleman-core/contracts'
# Immutable Data
require 'hamster'
# Indifferent Access
require 'hashie'
# For URI templating
require 'addressable/uri'
@ -76,56 +76,25 @@ module Middleman
end
end
class IndifferentHash < ::Hamster::Hash
def [](key)
if key?(key.to_sym)
super(key.to_sym)
elsif key?(key.to_s)
super(key.to_s)
else
super
end
class EnhancedHash < ::Hash
include ::Hashie::Extensions::MergeInitializer
include ::Hashie::Extensions::MethodReader
include ::Hashie::Extensions::IndifferentAccess
end
def method_missing(key, *_args)
if key?(key.to_sym)
self[key.to_sym]
elsif key?(key.to_s)
self[key.to_s]
end
end
end
# Recursively convert a normal Hash into a IndifferentHash
# Recursively convert a normal Hash into a EnhancedHash
#
# @private
# @param [Hash] data Normal hash
# @return [Middleman::Util::IndifferentHash]
FrozenDataStructure = Frozen[Or[IndifferentHash, Array, String, TrueClass, FalseClass, Fixnum, NilClass]]
Contract Maybe[Or[String, Array, Hash, IndifferentHash]] => Maybe[FrozenDataStructure]
# @return [Hash]
Contract Maybe[Hash] => Maybe[Or[Array, EnhancedHash]]
def recursively_enhance(obj)
case obj
when ::Hash
res = obj.map { |key, value| [recursively_enhance(key), recursively_enhance(value)] }
IndifferentHash.new(res)
when IndifferentHash
obj.map { |key, value| [recursively_enhance(key), recursively_enhance(value)] }
when ::Array
res = obj.map { |element| recursively_enhance(element) }
Hamster::Vector.new(res)
when ::SortedSet
# This clause must go before ::Set clause, since ::SortedSet is a ::Set.
res = obj.map { |element| recursively_enhance(element) }
Hamster::SortedSet.new(res)
when ::Set
res = obj.map { |element| recursively_enhance(element) }
Hamster::Set.new(res)
when Hamster::Vector, Hamster::Set, Hamster::SortedSet
obj.map { |element| recursively_enhance(element) }
when ::TrueClass, ::FalseClass, ::Fixnum, ::Symbol, ::NilClass, ::Float
obj
if obj.is_a? ::Array
obj.map { |e| recursively_enhance(e) }.freeze
elsif obj.is_a? ::Hash
EnhancedHash.new(obj).freeze
else
obj.dup.freeze
obj
end
end

View file

@ -29,7 +29,7 @@ module Middleman
# Get the frontmatter and plain content from a file
# @param [String] path
# @return [Array<Middleman::Util::IndifferentHash, String>]
# @return [Array<Hash, String>]
Contract Pathname, Maybe[Symbol] => [Hash, Maybe[String]]
def parse(full_path, known_type=nil)
data = {}

View file

@ -1,5 +1,5 @@
module Middleman
# Current Version
# @return [String]
VERSION = '4.0.0.beta.2' unless const_defined?(:VERSION)
VERSION = '4.0.0.beta.3' unless const_defined?(:VERSION)
end

View file

@ -52,6 +52,7 @@ Gem::Specification.new do |s|
# Testing
s.add_dependency('contracts', ['~> 0.9.0'])
# Immutability
# Hash stuff
s.add_dependency('hashie', ['~> 3.4'])
s.add_dependency('hamster', ['~> 1.0'])
end

View file

@ -54,43 +54,23 @@ describe Middleman::Util do
end
describe "::recursively_enhance" do
it "returns IndifferentHash if given one" do
input = Middleman::Util::IndifferentHash.new({test: "subject"})
subject = Middleman::Util.recursively_enhance input
expect( subject ).to be_a Middleman::Util::IndifferentHash
expect( subject.test ).to eq "subject"
end
it "returns IndifferentHash if given a hash" do
it "returns Hashie extended Hash if given a hash" do
input = {test: "subject"}
subject = Middleman::Util.recursively_enhance input
expect( subject ).to be_a Middleman::Util::IndifferentHash
expect( subject.test ).to eq "subject"
end
it "returns Array with strings, or IndifferentHash, true, false" do
indifferent_hash = Middleman::Util::IndifferentHash.new({test: "subject"})
indifferent_hash = {test: "subject"}
regular_hash = {regular: "hash"}
input = [ indifferent_hash, regular_hash, true, false ]
subject = Middleman::Util.recursively_enhance input
expect( subject[0] ).to be_a Middleman::Util::IndifferentHash
expect( subject[1] ).to be_a Middleman::Util::IndifferentHash
expect( subject[1].regular ).to eq "hash"
expect( subject[2] ).to eq true
expect( subject[3] ).to eq false
end
it "returns duplicated & frozen original object if not special cased" do
input = "foo"
subject = Middleman::Util.recursively_enhance input
expect( subject ).to eq input
expect( subject.object_id ).not_to eq input.object_id
expect( subject ).to be_frozen
end
end
end