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| %>
|
<% current_page.children.each do |p| %>
|
||||||
<% if p.data %>
|
<% if p.data %>
|
||||||
Data: <%= p.data %>
|
Data: <%= p.data.inspect %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
|
@ -16,6 +16,6 @@ Source: <%= current_page.source_file[:full_path].sub(root + "/", "") %>
|
||||||
|
|
||||||
<% current_page.children.each do |p| %>
|
<% current_page.children.each do |p| %>
|
||||||
<% if p.data %>
|
<% if p.data %>
|
||||||
Data: <%= p.data %>
|
Data: <%= p.data.inspect %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
|
@ -162,8 +162,8 @@ module Middleman
|
||||||
# @return [Hash, nil]
|
# @return [Hash, nil]
|
||||||
def method_missing(path)
|
def method_missing(path)
|
||||||
if @local_data.key?(path.to_s)
|
if @local_data.key?(path.to_s)
|
||||||
@local_data[path.to_s] = ::Middleman::Util.recursively_enhance(@local_data[path.to_s])
|
# Any way to cache this?
|
||||||
return @local_data[path.to_s]
|
return ::Middleman::Util.recursively_enhance(@local_data[path.to_s])
|
||||||
else
|
else
|
||||||
result = data_for_path(path)
|
result = data_for_path(path)
|
||||||
return result if result
|
return result if result
|
||||||
|
|
|
@ -83,7 +83,7 @@ module Middleman::CoreExtensions
|
||||||
|
|
||||||
# Get the frontmatter and plain content from a file
|
# Get the frontmatter and plain content from a file
|
||||||
# @param [String] path
|
# @param [String] path
|
||||||
# @return [Array<Middleman::Util::HashWithIndifferentAccess, String>]
|
# @return [Array<Middleman::Util::IndifferentHash, String>]
|
||||||
Contract Pathname => [Hash, Maybe[String]]
|
Contract Pathname => [Hash, Maybe[String]]
|
||||||
def frontmatter_and_content(full_path)
|
def frontmatter_and_content(full_path)
|
||||||
data = {}
|
data = {}
|
||||||
|
|
|
@ -87,10 +87,9 @@ module Middleman
|
||||||
end
|
end
|
||||||
|
|
||||||
# Data about this resource, populated from frontmatter or extensions.
|
# Data about this resource, populated from frontmatter or extensions.
|
||||||
# @return [HashWithIndifferentAccess]
|
# @return [IndifferentHash]
|
||||||
Contract IsA['Middleman::Util::HashWithIndifferentAccess']
|
Contract IsA['Middleman::Util::IndifferentHash']
|
||||||
def data
|
def data
|
||||||
# TODO: Should this really be a HashWithIndifferentAccess?
|
|
||||||
::Middleman::Util.recursively_enhance(metadata[:page])
|
::Middleman::Util.recursively_enhance(metadata[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
# For instrumenting
|
# For instrumenting
|
||||||
require 'active_support/notifications'
|
require 'active_support/notifications'
|
||||||
|
|
||||||
# Indifferent hash access
|
|
||||||
require 'middleman-core/util/hash_with_indifferent_access'
|
|
||||||
|
|
||||||
# Core Pathname library used for traversal
|
# Core Pathname library used for traversal
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
|
|
||||||
|
@ -14,6 +11,9 @@ require 'rack/mime'
|
||||||
# DbC
|
# DbC
|
||||||
require 'middleman-core/contracts'
|
require 'middleman-core/contracts'
|
||||||
|
|
||||||
|
# Immutable Data
|
||||||
|
require 'hamster'
|
||||||
|
|
||||||
# For URI templating
|
# For URI templating
|
||||||
require 'addressable/uri'
|
require 'addressable/uri'
|
||||||
require 'addressable/template'
|
require 'addressable/template'
|
||||||
|
@ -76,27 +76,48 @@ module Middleman
|
||||||
end
|
end
|
||||||
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
|
# @private
|
||||||
# @param [Hash] data Normal hash
|
# @param [Hash] data Normal hash
|
||||||
# @return [Middleman::Util::HashWithIndifferentAccess]
|
# @return [Middleman::Util::IndifferentHash]
|
||||||
FrozenDataStructure = Frozen[Or[HashWithIndifferentAccess, Array, String, TrueClass, FalseClass, Fixnum]]
|
FrozenDataStructure = Frozen[Or[IndifferentHash, Array, String, TrueClass, FalseClass, Fixnum]]
|
||||||
Contract Maybe[Or[String, Array, Hash, HashWithIndifferentAccess]] => Maybe[FrozenDataStructure]
|
Contract Maybe[Or[String, Array, Hash, IndifferentHash]] => Maybe[FrozenDataStructure]
|
||||||
def recursively_enhance(data)
|
def recursively_enhance(obj)
|
||||||
if data.is_a? HashWithIndifferentAccess
|
case obj
|
||||||
data
|
when ::Hash
|
||||||
elsif data.is_a? Hash
|
res = obj.map { |key, value| [recursively_enhance(key), recursively_enhance(value)] }
|
||||||
HashWithIndifferentAccess.new(data)
|
IndifferentHash.new(res)
|
||||||
elsif data.is_a? Array
|
when IndifferentHash
|
||||||
data.map(&method(:recursively_enhance)).freeze
|
obj.map { |key, value| [recursively_enhance(key), recursively_enhance(value)] }
|
||||||
elsif data.frozen? || data.nil? || [::TrueClass, ::FalseClass, ::Fixnum].include?(data.class)
|
when ::Array
|
||||||
data
|
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
|
else
|
||||||
data.dup.freeze
|
obj.dup.freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Normalize a path to not include a leading slash
|
# Normalize a path to not include a leading slash
|
||||||
# @param [String] path
|
# @param [String] path
|
||||||
# @return [String]
|
# @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
|
# Testing
|
||||||
s.add_dependency('contracts', ['~> 0.9.0'])
|
s.add_dependency('contracts', ['~> 0.9.0'])
|
||||||
|
|
||||||
|
# Immutability
|
||||||
|
s.add_dependency('hamster', ['~> 1.0'])
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,30 +54,30 @@ describe Middleman::Util do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "::recursively_enhance" do
|
describe "::recursively_enhance" do
|
||||||
it "returns HashWithIndifferentAccess if given one" do
|
it "returns IndifferentHash if given one" do
|
||||||
input = Middleman::Util::HashWithIndifferentAccess.new({test: "subject"})
|
input = Middleman::Util::IndifferentHash.new({test: "subject"})
|
||||||
subject = Middleman::Util.recursively_enhance input
|
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"
|
expect( subject.test ).to eq "subject"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns HashWithIndifferentAccess if given a hash" do
|
it "returns IndifferentHash if given a hash" do
|
||||||
input = {test: "subject"}
|
input = {test: "subject"}
|
||||||
subject = Middleman::Util.recursively_enhance input
|
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"
|
expect( subject.test ).to eq "subject"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns Array with strings, or HashWithIndifferentAccess, true, false" do
|
it "returns Array with strings, or IndifferentHash, true, false" do
|
||||||
indifferent_hash = Middleman::Util::HashWithIndifferentAccess.new({test: "subject"})
|
indifferent_hash = Middleman::Util::IndifferentHash.new({test: "subject"})
|
||||||
regular_hash = {regular: "hash"}
|
regular_hash = {regular: "hash"}
|
||||||
input = [ indifferent_hash, regular_hash, true, false ]
|
input = [ indifferent_hash, regular_hash, true, false ]
|
||||||
subject = Middleman::Util.recursively_enhance input
|
subject = Middleman::Util.recursively_enhance input
|
||||||
|
|
||||||
expect( subject[0] ).to be_a Middleman::Util::HashWithIndifferentAccess
|
expect( subject[0] ).to be_a Middleman::Util::IndifferentHash
|
||||||
expect( subject[1] ).to be_a Middleman::Util::HashWithIndifferentAccess
|
expect( subject[1] ).to be_a Middleman::Util::IndifferentHash
|
||||||
expect( subject[1].regular ).to eq "hash"
|
expect( subject[1].regular ).to eq "hash"
|
||||||
expect( subject[2] ).to eq true
|
expect( subject[2] ).to eq true
|
||||||
expect( subject[3] ).to eq false
|
expect( subject[3] ).to eq false
|
||||||
|
|
Loading…
Reference in a new issue