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