Some immutability tweaks

This commit is contained in:
Thomas Reynolds 2015-05-03 17:11:49 -07:00
parent e64954fbff
commit 69e66b04df
6 changed files with 42 additions and 41 deletions

View file

@ -1,5 +1,6 @@
if ENV['TEST'] || ENV['CONTRACTS'] == 'true' if ENV['TEST'] || ENV['CONTRACTS'] == 'true'
require 'contracts' require 'contracts'
require 'hamster'
module Contracts module Contracts
class IsA class IsA
@ -27,21 +28,7 @@ if ENV['TEST'] || ENV['CONTRACTS'] == 'true'
end end
end end
# class MethodDefined VectorOf = Contracts::CollectionOf::Factory.new(::Hamster::Vector)
# def self.[](val)
# @lookup ||= {}
# @lookup[val] ||= new(val)
# end
# def initialize(val)
# @val = val
# end
# def valid?(val)
# val.method_defined? @val
# end
# end
ResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']] ResourceList = Contracts::ArrayOf[IsA['Middleman::Sitemap::Resource']]
end end
else else
@ -125,8 +112,8 @@ else
class Frozen < Callable class Frozen < Callable
end end
# class MethodDefined < Callable class VectorOf < Callable
# end end
end end
end end

View file

@ -1,3 +1,5 @@
require 'hamster'
module Middleman module Middleman
module CoreExtensions module CoreExtensions
module Collections module Collections
@ -9,13 +11,13 @@ module Middleman
attr_reader :descriptors attr_reader :descriptors
def initialize def initialize
@descriptors = [] @descriptors = ::Hamster.set
end end
def method_missing(name, *args, &block) def method_missing(name, *args, &block)
internal = :"_internal_#{name}" internal = :"_internal_#{name}"
if respond_to?(internal) if respond_to?(internal)
@descriptors << send(internal, *args, &block) @descriptors = @descriptors.add(send(internal, *args, &block))
else else
super super
end end

View file

@ -12,7 +12,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
def initialize(*) def initialize(*)
super super
require 'i18n' require 'i18n'
# Don't fail on invalid locale, that's not what our current # Don't fail on invalid locale, that's not what our current

View file

@ -179,15 +179,15 @@ module Middleman
http_opts[:SSLEnable] = true http_opts[:SSLEnable] = true
if ssl_certificate || ssl_private_key if ssl_certificate || ssl_private_key
raise "You must provide both :ssl_certificate and :ssl_private_key" unless ssl_private_key && ssl_certificate raise 'You must provide both :ssl_certificate and :ssl_private_key' unless ssl_private_key && ssl_certificate
http_opts[:SSLCertificate] = OpenSSL::X509::Certificate.new File.read ssl_certificate http_opts[:SSLCertificate] = OpenSSL::X509::Certificate.new File.read ssl_certificate
http_opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new File.read ssl_private_key http_opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new File.read ssl_private_key
else else
# use a generated self-signed cert # use a generated self-signed cert
http_opts[:SSLCertName] = [ http_opts[:SSLCertName] = [
%w(CN localhost), %w(CN localhost),
%w(CN #{host}) %w(CN #{host})
].uniq ].uniq
end end
end end

View file

@ -1,6 +1,7 @@
# Used for merging results of metadata callbacks # Used for merging results of metadata callbacks
require 'active_support/core_ext/hash/deep_merge' require 'active_support/core_ext/hash/deep_merge'
require 'monitor' require 'monitor'
require 'hamster'
# Ignores # Ignores
Middleman::Extensions.register :sitemap_ignore, auto_activate: :before_configuration do Middleman::Extensions.register :sitemap_ignore, auto_activate: :before_configuration do
@ -37,6 +38,8 @@ require 'middleman-core/contracts'
module Middleman module Middleman
# Sitemap namespace # Sitemap namespace
module Sitemap module Sitemap
ManipulatorDescriptor = Struct.new :name, :manipulator, :priority, :custom_name
# The Store class # The Store class
# #
# The Store manages a collection of Resource objects, which represent # The Store manages a collection of Resource objects, which represent
@ -46,20 +49,21 @@ module Middleman
class Store class Store
include Contracts include Contracts
# @return [Middleman::Application] Contract IsA['Middleman::Application']
attr_reader :app attr_reader :app
Contract Num
attr_reader :update_count attr_reader :update_count
# Initialize with parent app # Initialize with parent app
# @param [Middleman::Application] app # @param [Middleman::Application] app
Contract IsA['Middleman::Application'] => Any
def initialize(app) def initialize(app)
@app = app @app = app
@resources = [] @resources = []
@update_count = 0 @update_count = 0
# TODO: Should this be a set or hash? @resource_list_manipulators = ::Hamster.vector
@resource_list_manipulators = []
@needs_sitemap_rebuild = true @needs_sitemap_rebuild = true
@lock = Monitor.new @lock = Monitor.new
@ -76,24 +80,29 @@ module Middleman
# @param [Numeric] priority Sets the order of this resource list manipulator relative to the rest. By default this is 50, and manipulators run in the order they are registered, but if a priority is provided then this will run ahead of or behind other manipulators. # @param [Numeric] priority Sets the order of this resource list manipulator relative to the rest. By default this is 50, and manipulators run in the order they are registered, but if a priority is provided then this will run ahead of or behind other manipulators.
# @param [Symbol] custom_name The method name to execute. # @param [Symbol] custom_name The method name to execute.
# @return [void] # @return [void]
Contract Symbol, RespondTo['manipulate_resource_list'], Maybe[Num], Maybe[Symbol] => Any Contract Symbol, RespondTo[:manipulate_resource_list], Maybe[Num], Maybe[Symbol] => Any
def register_resource_list_manipulator(name, manipulator, priority=50, custom_name=nil) def register_resource_list_manipulator(name, manipulator, priority=50, custom_name=nil)
# The third argument used to be a boolean - handle those who still pass one # The third argument used to be a boolean - handle those who still pass one
priority = 50 unless priority.is_a? Numeric priority = 50 unless priority.is_a? Numeric
@resource_list_manipulators << [name, manipulator, priority, custom_name] @resource_list_manipulators = @resource_list_manipulators.push(
ManipulatorDescriptor.new(name, manipulator, priority, custom_name)
)
# The index trick is used so that the sort is stable - manipulators with the same priority # The index trick is used so that the sort is stable - manipulators with the same priority
# will always be ordered in the same order as they were registered. # will always be ordered in the same order as they were registered.
n = 0 n = 0
@resource_list_manipulators = @resource_list_manipulators.sort_by do |m| @resource_list_manipulators = @resource_list_manipulators.sort_by do |m|
n += 1 n += 1
[m[2], n] [m[:priority], n]
end end
rebuild_resource_list!(:registered_new) rebuild_resource_list!(:registered_new)
end end
# Rebuild the list of resources from scratch, using registed manipulators # Rebuild the list of resources from scratch, using registed manipulators
# @return [void] # @return [void]
def rebuild_resource_list!(_=nil) Contract Maybe[Symbol] => Any
def rebuild_resource_list!(_name=nil)
@lock.synchronize do @lock.synchronize do
@needs_sitemap_rebuild = true @needs_sitemap_rebuild = true
end end
@ -178,11 +187,13 @@ module Middleman
@app.logger.debug '== Rebuilding resource list' @app.logger.debug '== Rebuilding resource list'
@resources = @resource_list_manipulators.reduce([]) do |result, (_, manipulator, _, custom_name)| @resources = @resource_list_manipulators.reduce([]) do |result, m|
newres = manipulator.send(custom_name || :manipulate_resource_list, result) newres = m[:manipulator].send(m[:custom_name] || :manipulate_resource_list, result)
# Reset lookup cache # Reset lookup cache
reset_lookup_cache! reset_lookup_cache!
# Rebuild cache
newres.each do |resource| newres.each do |resource|
@_lookup_by_path[resource.path] = resource @_lookup_by_path[resource.path] = resource
@_lookup_by_destination_path[resource.destination_path] = resource @_lookup_by_destination_path[resource.destination_path] = resource

View file

@ -1,3 +1,4 @@
require 'hamster'
require 'middleman-core/contracts' require 'middleman-core/contracts'
require 'backports/2.0.0/enumerable/lazy' require 'backports/2.0.0/enumerable/lazy'
@ -47,10 +48,10 @@ module Middleman
@options = options @options = options
# Set of procs wanting to be notified of changes # Set of procs wanting to be notified of changes
@on_change_callbacks = [] @on_change_callbacks = ::Hamster.vector
# Global ignores # Global ignores
@ignores = {} @ignores = ::Hamster.hash
# Whether we're "running", which means we're in a stable # Whether we're "running", which means we're in a stable
# watch state after all initialization and config. # watch state after all initialization and config.
@ -72,7 +73,8 @@ module Middleman
# @return [void] # @return [void]
Contract Symbol, Symbol, Or[Regexp, Proc] => Any Contract Symbol, Symbol, Or[Regexp, Proc] => Any
def ignore(name, type, regex=nil, &block) def ignore(name, type, regex=nil, &block)
@ignores[name] = { type: type, validator: (block_given? ? block : regex) } @ignores = @ignores.put(name, type: type,
validator: (block_given? ? block : regex))
bump_count bump_count
find_new_files! if @running find_new_files! if @running
@ -238,11 +240,10 @@ module Middleman
# Add callback to be run on file change or deletion # Add callback to be run on file change or deletion
# #
# @param [Symbol] type The change type. # @param [Symbol] type The change type.
# @return [Set<CallbackDescriptor>] # @return [void]
Contract Symbol, Proc => ArrayOf[CallbackDescriptor] Contract Symbol, Proc => Any
def on_change(type, &block) def on_change(type, &block)
@on_change_callbacks << CallbackDescriptor.new(type, block) @on_change_callbacks = @on_change_callbacks.push(CallbackDescriptor.new(type, block))
@on_change_callbacks
end end
# Backwards compatible change handler. # Backwards compatible change handler.
@ -328,7 +329,7 @@ module Middleman
# @param [Set] callback_descriptors The registered callbacks. # @param [Set] callback_descriptors The registered callbacks.
# @param [Array<Middleman::SourceFile>] files The files that were changed. # @param [Array<Middleman::SourceFile>] files The files that were changed.
# @return [void] # @return [void]
Contract ArrayOf[CallbackDescriptor], ArrayOf[SourceFile], ArrayOf[SourceFile] => Any Contract VectorOf[CallbackDescriptor], ArrayOf[SourceFile], ArrayOf[SourceFile] => Any
def run_callbacks(callback_descriptors, updated_files, removed_files) def run_callbacks(callback_descriptors, updated_files, removed_files)
callback_descriptors.each do |callback| callback_descriptors.each do |callback|
if callback[:type] == :all if callback[:type] == :all