Deep freeze IndifferentAccess.
This commit is contained in:
parent
332ce2bebc
commit
1f3e2043cb
|
@ -17,6 +17,16 @@ if ENV['TEST'] || ENV['CONTRACTS'] == 'true'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Frozen < CallableClass
|
||||||
|
def initialize(contract)
|
||||||
|
@contract = contract
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?(val)
|
||||||
|
val.frozen? && Contract.valid?(val, @contract)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class ArrayOf
|
class ArrayOf
|
||||||
def initialize(contract)
|
def initialize(contract)
|
||||||
@contract = contract.is_a?(String) ? IsA[contract] : contract
|
@contract = contract.is_a?(String) ? IsA[contract] : contract
|
||||||
|
@ -128,6 +138,9 @@ else
|
||||||
|
|
||||||
class SetOf < Callable
|
class SetOf < Callable
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Frozen < Callable
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -97,11 +97,11 @@ module Middleman
|
||||||
|
|
||||||
path = data_path.to_s.split(File::SEPARATOR)[0..-2]
|
path = data_path.to_s.split(File::SEPARATOR)[0..-2]
|
||||||
path.each do |dir|
|
path.each do |dir|
|
||||||
data_branch[dir] ||= ::Middleman::Util.recursively_enhance({})
|
data_branch[dir] ||= {}
|
||||||
data_branch = data_branch[dir]
|
data_branch = data_branch[dir]
|
||||||
end
|
end
|
||||||
|
|
||||||
data_branch[basename] = data && ::Middleman::Util.recursively_enhance(data)
|
data_branch[basename] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove a given file from the internal cache
|
# Remove a given file from the internal cache
|
||||||
|
@ -132,14 +132,13 @@ module Middleman
|
||||||
# @return [Hash, nil]
|
# @return [Hash, nil]
|
||||||
Contract Or[String, Symbol] => Maybe[Hash]
|
Contract Or[String, Symbol] => Maybe[Hash]
|
||||||
def data_for_path(path)
|
def data_for_path(path)
|
||||||
response = nil
|
response = if store.key?(path.to_s)
|
||||||
|
store[path.to_s]
|
||||||
if store.key?(path.to_s)
|
|
||||||
response = store[path.to_s]
|
|
||||||
elsif callbacks.key?(path.to_s)
|
elsif callbacks.key?(path.to_s)
|
||||||
response = callbacks[path.to_s].call
|
callbacks[path.to_s].call
|
||||||
end
|
end
|
||||||
|
|
||||||
|
response = ::Middleman::Util.recursively_enhance(response)
|
||||||
response
|
response
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,10 +148,11 @@ 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])
|
||||||
return @local_data[path.to_s]
|
return @local_data[path.to_s]
|
||||||
else
|
else
|
||||||
result = data_for_path(path)
|
result = data_for_path(path)
|
||||||
return ::Middleman::Util.recursively_enhance(result) if result
|
return result if result
|
||||||
end
|
end
|
||||||
|
|
||||||
super
|
super
|
||||||
|
|
|
@ -51,7 +51,7 @@ module Middleman
|
||||||
|
|
||||||
# Merge per-extension options from config
|
# Merge per-extension options from config
|
||||||
extension = File.extname(path)
|
extension = File.extname(path)
|
||||||
options = opts.dup.merge(options_for_ext(extension))
|
options = opts.merge(options_for_ext(extension))
|
||||||
options[:outvar] ||= '@_out_buf'
|
options[:outvar] ||= '@_out_buf'
|
||||||
options.delete(:layout)
|
options.delete(:layout)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ module Middleman
|
||||||
# Start an instance of Middleman::Application
|
# Start an instance of Middleman::Application
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def start(opts={})
|
def start(opts={})
|
||||||
@options = opts
|
@options = opts.dup.freeze
|
||||||
@host = @options[:host] || '0.0.0.0'
|
@host = @options[:host] || '0.0.0.0'
|
||||||
@port = @options[:port] || DEFAULT_PORT
|
@port = @options[:port] || DEFAULT_PORT
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ module Middleman
|
||||||
private
|
private
|
||||||
|
|
||||||
def new_app
|
def new_app
|
||||||
opts = @options.dup
|
opts = @options
|
||||||
|
|
||||||
::Middleman::Logger.singleton(
|
::Middleman::Logger.singleton(
|
||||||
opts[:debug] ? 0 : 1,
|
opts[:debug] ? 0 : 1,
|
||||||
|
|
|
@ -79,7 +79,7 @@ module Middleman
|
||||||
Contract None => IsA['Middleman::Util::HashWithIndifferentAccess']
|
Contract None => IsA['Middleman::Util::HashWithIndifferentAccess']
|
||||||
def data
|
def data
|
||||||
# TODO: Should this really be a HashWithIndifferentAccess?
|
# TODO: Should this really be a HashWithIndifferentAccess?
|
||||||
::Middleman::Util.recursively_enhance(metadata[:page]).freeze
|
::Middleman::Util.recursively_enhance(metadata[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Options about how this resource is rendered, such as its :layout,
|
# Options about how this resource is rendered, such as its :layout,
|
||||||
|
|
|
@ -30,10 +30,10 @@ module Middleman
|
||||||
# @param [Middleman::Application] app
|
# @param [Middleman::Application] app
|
||||||
# @param [Hash] locs
|
# @param [Hash] locs
|
||||||
# @param [Hash] opts
|
# @param [Hash] opts
|
||||||
def initialize(app, locs={}, opts={})
|
def initialize(app, locs={}.freeze, opts={}.freeze)
|
||||||
@app = app
|
@app = app
|
||||||
@locs = locs.dup.freeze
|
@locs = locs
|
||||||
@opts = opts.dup.freeze
|
@opts = opts
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return the current buffer to the caller and clear the value internally.
|
# Return the current buffer to the caller and clear the value internally.
|
||||||
|
|
|
@ -31,16 +31,19 @@ module Middleman
|
||||||
Contract Hash, Hash => String
|
Contract Hash, Hash => String
|
||||||
def render(locs={}, opts={})
|
def render(locs={}, opts={})
|
||||||
path = @path.dup
|
path = @path.dup
|
||||||
|
locals = locs.dup.freeze
|
||||||
|
options = opts.dup
|
||||||
|
|
||||||
extension = File.extname(path)
|
extension = File.extname(path)
|
||||||
engine = extension[1..-1].to_sym
|
engine = extension[1..-1].to_sym
|
||||||
|
|
||||||
if defined?(::I18n)
|
if defined?(::I18n)
|
||||||
old_locale = ::I18n.locale
|
old_locale = ::I18n.locale
|
||||||
::I18n.locale = opts[:lang] if opts[:lang]
|
::I18n.locale = options[:lang] if options[:lang]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sandboxed class for template eval
|
# Sandboxed class for template eval
|
||||||
context = @app.template_context_class.new(@app, locs, opts)
|
context = @app.template_context_class.new(@app, locals, options)
|
||||||
|
|
||||||
# TODO: Only for HAML files
|
# TODO: Only for HAML files
|
||||||
context.init_haml_helpers if context.respond_to?(:init_haml_helpers)
|
context.init_haml_helpers if context.respond_to?(:init_haml_helpers)
|
||||||
|
@ -50,10 +53,10 @@ module Middleman
|
||||||
content = nil
|
content = nil
|
||||||
while ::Tilt[path]
|
while ::Tilt[path]
|
||||||
begin
|
begin
|
||||||
opts[:template_body] = content if content
|
options[:template_body] = content if content
|
||||||
|
|
||||||
content_renderer = ::Middleman::FileRenderer.new(@app, path)
|
content_renderer = ::Middleman::FileRenderer.new(@app, path)
|
||||||
content = content_renderer.render(locs, opts, context)
|
content = content_renderer.render(locals, options, context)
|
||||||
|
|
||||||
path = File.basename(path, File.extname(path))
|
path = File.basename(path, File.extname(path))
|
||||||
rescue LocalJumpError
|
rescue LocalJumpError
|
||||||
|
@ -62,9 +65,9 @@ module Middleman
|
||||||
end
|
end
|
||||||
|
|
||||||
# If we need a layout and have a layout, use it
|
# If we need a layout and have a layout, use it
|
||||||
if layout_path = fetch_layout(engine, opts)
|
if layout_path = fetch_layout(engine, options)
|
||||||
layout_renderer = ::Middleman::FileRenderer.new(@app, layout_path)
|
layout_renderer = ::Middleman::FileRenderer.new(@app, layout_path)
|
||||||
content = layout_renderer.render(locs, opts, context) { content }
|
content = layout_renderer.render(locals, options, context) { content }
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return result
|
# Return result
|
||||||
|
|
|
@ -15,11 +15,11 @@ require 'rack/mime'
|
||||||
require 'middleman-core/contracts'
|
require 'middleman-core/contracts'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
|
|
||||||
module Util
|
module Util
|
||||||
extend self
|
|
||||||
include Contracts
|
include Contracts
|
||||||
|
|
||||||
|
module_function
|
||||||
|
|
||||||
# Whether the source file is binary.
|
# Whether the source file is binary.
|
||||||
#
|
#
|
||||||
# @param [String] filename The file to check.
|
# @param [String] filename The file to check.
|
||||||
|
@ -74,32 +74,16 @@ module Middleman
|
||||||
# @private
|
# @private
|
||||||
# @param [Hash] data Normal hash
|
# @param [Hash] data Normal hash
|
||||||
# @return [Middleman::Util::HashWithIndifferentAccess]
|
# @return [Middleman::Util::HashWithIndifferentAccess]
|
||||||
Contract Or[Hash, Array] => Or[HashWithIndifferentAccess, Array]
|
Contract Maybe[Or[Array, Hash, HashWithIndifferentAccess]] => Maybe[Frozen[Or[HashWithIndifferentAccess, Array]]]
|
||||||
def recursively_enhance(data)
|
def recursively_enhance(data)
|
||||||
if data.is_a? Hash
|
if data.is_a? HashWithIndifferentAccess
|
||||||
enhanced = ::Middleman::Util::HashWithIndifferentAccess.new(data)
|
data
|
||||||
|
elsif data.is_a? Hash
|
||||||
enhanced.each do |key, val|
|
HashWithIndifferentAccess.new(data)
|
||||||
enhanced[key] = if val.is_a?(Hash) || val.is_a?(Array)
|
|
||||||
recursively_enhance(val)
|
|
||||||
else
|
|
||||||
val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
enhanced
|
|
||||||
elsif data.is_a? Array
|
elsif data.is_a? Array
|
||||||
enhanced = data.dup
|
data.map(&method(:recursively_enhance))
|
||||||
|
|
||||||
enhanced.each_with_index do |val, i|
|
|
||||||
enhanced[i] = if val.is_a?(Hash) || val.is_a?(Array)
|
|
||||||
recursively_enhance(val)
|
|
||||||
else
|
else
|
||||||
val
|
nil
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
enhanced
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'middleman-core/contracts'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
module Util
|
module Util
|
||||||
# A hash with indifferent access and magic predicates.
|
# A hash with indifferent access and magic predicates.
|
||||||
|
@ -10,11 +12,17 @@ module Middleman
|
||||||
# hash.foo? #=> true
|
# hash.foo? #=> true
|
||||||
#
|
#
|
||||||
class HashWithIndifferentAccess < ::Hash #:nodoc:
|
class HashWithIndifferentAccess < ::Hash #:nodoc:
|
||||||
|
include Contracts
|
||||||
|
|
||||||
|
Contract Hash => Any
|
||||||
def initialize(hash={})
|
def initialize(hash={})
|
||||||
super()
|
super()
|
||||||
hash.each do |key, value|
|
|
||||||
self[convert_key(key)] = value
|
hash.each do |key, val|
|
||||||
|
self[key] = recursively_enhance(val)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](key)
|
def [](key)
|
||||||
|
@ -73,6 +81,23 @@ module Middleman
|
||||||
self[method]
|
self[method]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
Contract Any => Frozen[Any]
|
||||||
|
def recursively_enhance(data)
|
||||||
|
if data.is_a? HashWithIndifferentAccess
|
||||||
|
data
|
||||||
|
elsif data.is_a? Hash
|
||||||
|
self.class.new(data)
|
||||||
|
elsif data.is_a? Array
|
||||||
|
data.map(&method(:recursively_enhance)).freeze
|
||||||
|
elsif data.frozen?
|
||||||
|
data
|
||||||
|
else
|
||||||
|
data.dup.freeze
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue