1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
# encoding: utf-8
module Adamantium
# Abstract base class for freezers
#
# TODO: Use dkubb/abstract_class?
#
# Better pattern for singleton inheritance/shared code
class Freezer
private_class_method :new
# Attempt to freeze an object
#
# @example using a value object
# Adamantium.freeze_object(12345) # => noop
#
# @example using a normal object
# Adamantium.freeze_object({}) # => duplicate & freeze object
#
# @param [Object] object
# the object to freeze
#
# @return [Object]
# if supported, the frozen object, otherwise the object directly
#
# @api public
def self.call(object)
case object
when Numeric, TrueClass, FalseClass, NilClass, Symbol, Class, Module, UnboundMethod, Method
object
else
freeze_value(object)
end
end
private_class_method :call
# Returns a frozen value
#
# @param [Object] value
# a value to freeze
#
# @return [Object]
# if frozen, the value directly, otherwise a frozen copy of the value
#
# @api private
def self.freeze_value(value)
value.frozen? ? value : freeze(value.dup)
end
private_class_method :freeze_value
# Freezer that does not deep freeze
class Flat < self
# Freeze value
#
# @param [Object] value
#
# @return [undefined]
#
# @api private
def self.freeze(value)
value.freeze
end
public_class_method :call
end
# Freezer that does deep freeze
class Deep < self
# Deep freeze value
#
# @param [Object] value
#
# @return [undefined]
#
# @api private
def self.freeze(value)
IceNine.deep_freeze!(value)
end
public_class_method :call
end
Noop = ->(object) { object }.freeze
# Error raised when freezer cannot be found
class UnknownFreezerError < RuntimeError; end
# Error raised when memoizer options contain unknown keys
class OptionError < RuntimeError; end
@freezers = {
noop: Noop,
deep: Deep,
flat: Flat,
}.freeze
# Return freezer for name
#
# @param [Symbol] name
# a freezer name
#
# @return [#call]
#
# @api private
def self.get(name)
@freezers.fetch(name) do
fail UnknownFreezerError, "Freezer with name #{name.inspect} is unknown"
end
end
# Parse freezer options
#
# @param [Hash] options
# an options hash
#
# @return [#call]
# if freezer option was present
#
# @return [nil]
# otherwise
#
# @api private
#
def self.parse(options)
keys = options.keys - [:freezer]
unless keys.empty?
fail OptionError, "Unknown option key(s) for memoizer #{keys.inspect}"
end
get(options.fetch(:freezer)) if options.key?(:freezer)
end
end
end
|