Experiment with Hamster
This commit is contained in:
parent
55c5a46440
commit
22ce56492f
|
@ -16,6 +16,6 @@ Source: <%= current_page.source_file[:full_path].sub(root + "/", "") %>
|
|||
|
||||
<% current_page.children.each do |p| %>
|
||||
<% if p.data %>
|
||||
Data: <%= p.data %>
|
||||
Data: <%= p.data.inspect %>
|
||||
<% end %>
|
||||
<% end %>
|
|
@ -16,6 +16,6 @@ Source: <%= current_page.source_file[:full_path].sub(root + "/", "") %>
|
|||
|
||||
<% current_page.children.each do |p| %>
|
||||
<% if p.data %>
|
||||
Data: <%= p.data %>
|
||||
Data: <%= p.data.inspect %>
|
||||
<% end %>
|
||||
<% end %>
|
|
@ -162,8 +162,8 @@ module Middleman
|
|||
# @return [Hash, nil]
|
||||
def method_missing(path)
|
||||
if @local_data.key?(path.to_s)
|
||||
@local_data[path.to_s] = ::Middleman::Util.recursively_enhance(@local_data[path.to_s])
|
||||
return @local_data[path.to_s]
|
||||
# Any way to cache this?
|
||||
return ::Middleman::Util.recursively_enhance(@local_data[path.to_s])
|
||||
else
|
||||
result = data_for_path(path)
|
||||
return result if result
|
||||
|
|
|
@ -83,7 +83,7 @@ module Middleman::CoreExtensions
|
|||
|
||||
# Get the frontmatter and plain content from a file
|
||||
# @param [String] path
|
||||
# @return [Array<Middleman::Util::HashWithIndifferentAccess, String>]
|
||||
# @return [Array<Middleman::Util::IndifferentHash, String>]
|
||||
Contract Pathname => [Hash, Maybe[String]]
|
||||
def frontmatter_and_content(full_path)
|
||||
data = {}
|
||||
|
|
|
@ -87,10 +87,9 @@ module Middleman
|
|||
end
|
||||
|
||||
# Data about this resource, populated from frontmatter or extensions.
|
||||
# @return [HashWithIndifferentAccess]
|
||||
Contract IsA['Middleman::Util::HashWithIndifferentAccess']
|
||||
# @return [IndifferentHash]
|
||||
Contract IsA['Middleman::Util::IndifferentHash']
|
||||
def data
|
||||
# TODO: Should this really be a HashWithIndifferentAccess?
|
||||
::Middleman::Util.recursively_enhance(metadata[:page])
|
||||
end
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
# For instrumenting
|
||||
require 'active_support/notifications'
|
||||
|
||||
# Indifferent hash access
|
||||
require 'middleman-core/util/hash_with_indifferent_access'
|
||||
|
||||
# Core Pathname library used for traversal
|
||||
require 'pathname'
|
||||
|
||||
|
@ -14,6 +11,9 @@ require 'rack/mime'
|
|||
# DbC
|
||||
require 'middleman-core/contracts'
|
||||
|
||||
# Immutable Data
|
||||
require 'hamster'
|
||||
|
||||
# For URI templating
|
||||
require 'addressable/uri'
|
||||
require 'addressable/template'
|
||||
|
@ -76,27 +76,48 @@ module Middleman
|
|||
end
|
||||
end
|
||||
|
||||
# Recursively convert a normal Hash into a HashWithIndifferentAccess
|
||||
class IndifferentHash < ::Hamster::Hash
|
||||
def get(key)
|
||||
key?(key.to_s) ? super(key.to_s) : super(key.to_sym)
|
||||
end
|
||||
|
||||
alias_method :method_missing, :get
|
||||
end
|
||||
|
||||
# Recursively convert a normal Hash into a IndifferentHash
|
||||
#
|
||||
# @private
|
||||
# @param [Hash] data Normal hash
|
||||
# @return [Middleman::Util::HashWithIndifferentAccess]
|
||||
FrozenDataStructure = Frozen[Or[HashWithIndifferentAccess, Array, String, TrueClass, FalseClass, Fixnum]]
|
||||
Contract Maybe[Or[String, Array, Hash, HashWithIndifferentAccess]] => Maybe[FrozenDataStructure]
|
||||
def recursively_enhance(data)
|
||||
if data.is_a? HashWithIndifferentAccess
|
||||
data
|
||||
elsif data.is_a? Hash
|
||||
HashWithIndifferentAccess.new(data)
|
||||
elsif data.is_a? Array
|
||||
data.map(&method(:recursively_enhance)).freeze
|
||||
elsif data.frozen? || data.nil? || [::TrueClass, ::FalseClass, ::Fixnum].include?(data.class)
|
||||
data
|
||||
# @return [Middleman::Util::IndifferentHash]
|
||||
FrozenDataStructure = Frozen[Or[IndifferentHash, Array, String, TrueClass, FalseClass, Fixnum]]
|
||||
Contract Maybe[Or[String, Array, Hash, IndifferentHash]] => Maybe[FrozenDataStructure]
|
||||
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
|
||||
obj
|
||||
else
|
||||
data.dup.freeze
|
||||
obj.dup.freeze
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Normalize a path to not include a leading slash
|
||||
# @param [String] path
|
||||
# @return [String]
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
require 'middleman-core/contracts'
|
||||
|
||||
module Middleman
|
||||
module Util
|
||||
# A hash with indifferent access and magic predicates.
|
||||
# Copied from Thor
|
||||
#
|
||||
# hash = Middleman::Util::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
|
||||
#
|
||||
# hash[:foo] #=> 'bar'
|
||||
# hash['foo'] #=> 'bar'
|
||||
# hash.foo? #=> true
|
||||
#
|
||||
class HashWithIndifferentAccess < ::Hash #:nodoc:
|
||||
include Contracts
|
||||
|
||||
Contract Hash => Any
|
||||
def initialize(hash={})
|
||||
super()
|
||||
|
||||
hash.each do |key, val|
|
||||
self[key] = Util.recursively_enhance(val)
|
||||
end
|
||||
|
||||
freeze
|
||||
end
|
||||
|
||||
def [](key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
super(convert_key(key), value)
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def values_at(*indices)
|
||||
indices.map { |key| self[convert_key(key)] }
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
dup.merge!(other)
|
||||
end
|
||||
|
||||
def merge!(other)
|
||||
other.each do |key, value|
|
||||
self[convert_key(key)] = value
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Convert to a Hash with String keys.
|
||||
def to_hash
|
||||
Hash.new(default).merge!(self)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def convert_key(key)
|
||||
key.is_a?(Symbol) ? key.to_s : key
|
||||
end
|
||||
|
||||
# Magic predicates. For instance:
|
||||
#
|
||||
# options.force? # => !!options['force']
|
||||
# options.shebang # => "/usr/lib/local/ruby"
|
||||
# options.test_framework?(:rspec) # => options[:test_framework] == :rspec
|
||||
# rubocop:disable DoubleNegation
|
||||
def method_missing(method, *args)
|
||||
method = method.to_s
|
||||
if method =~ /^(\w+)\?$/
|
||||
if args.empty?
|
||||
!!self[$1]
|
||||
else
|
||||
self[$1] == args.first
|
||||
end
|
||||
else
|
||||
self[method]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -52,4 +52,7 @@ Gem::Specification.new do |s|
|
|||
|
||||
# Testing
|
||||
s.add_dependency('contracts', ['~> 0.9.0'])
|
||||
|
||||
# Immutability
|
||||
s.add_dependency('hamster', ['~> 1.0'])
|
||||
end
|
||||
|
|
|
@ -54,30 +54,30 @@ describe Middleman::Util do
|
|||
end
|
||||
|
||||
describe "::recursively_enhance" do
|
||||
it "returns HashWithIndifferentAccess if given one" do
|
||||
input = Middleman::Util::HashWithIndifferentAccess.new({test: "subject"})
|
||||
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::HashWithIndifferentAccess
|
||||
expect( subject ).to be_a Middleman::Util::IndifferentHash
|
||||
expect( subject.test ).to eq "subject"
|
||||
end
|
||||
|
||||
it "returns HashWithIndifferentAccess if given a hash" do
|
||||
it "returns IndifferentHash if given a hash" do
|
||||
input = {test: "subject"}
|
||||
subject = Middleman::Util.recursively_enhance input
|
||||
|
||||
expect( subject ).to be_a Middleman::Util::HashWithIndifferentAccess
|
||||
expect( subject ).to be_a Middleman::Util::IndifferentHash
|
||||
expect( subject.test ).to eq "subject"
|
||||
end
|
||||
|
||||
it "returns Array with strings, or HashWithIndifferentAccess, true, false" do
|
||||
indifferent_hash = Middleman::Util::HashWithIndifferentAccess.new({test: "subject"})
|
||||
it "returns Array with strings, or IndifferentHash, true, false" do
|
||||
indifferent_hash = Middleman::Util::IndifferentHash.new({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::HashWithIndifferentAccess
|
||||
expect( subject[1] ).to be_a Middleman::Util::HashWithIndifferentAccess
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue