lib/configdsl.rb in configdsl-1.0.0 vs lib/configdsl.rb in configdsl-1.1.0

- old
+ new

@@ -2,18 +2,55 @@ require "active_support/concern" require "forwardable" module ConfigDSL module Memory + class MemoryLayer < Hash + def self.make_alias_method(meth) + "original_#{meth}".to_sym + end + + ALIASED_METHODS = [ + :[], :fetch + ] + + ALIASED_METHODS.each do |meth| + original_method = make_alias_method(meth) + + begin + alias_method original_method, meth + + define_method meth do |*args, &block| + lazy_value = __send__(original_method, *args, &block) + lazy_value = lazy_value.value if lazy_value.kind_of?(LazyValue) + lazy_value + end + rescue NameError + end + end + + # Give a more handy name + alias_method :original_reader, make_alias_method(:[]) + + # Allow methods invocation to read values + def method_missing(meth, *args, &block) + return self[meth] if has_key?(meth) + super + end + + # Allow methods invocation to read values, second part + def respond_to?(meth) + return true if has_key?(meth) + super + end + end + class << self # Creates a new layer-level storage element def layers_factory - # Try to use Hashie::Mash if defined (see hashie gem) - return Hashie::Mash.new if defined?(Hashie::Mash) - - # Fallback to standart ruby Hash - Hash.new + @factory_base_class ||= MemoryLayer + @factory_base_class.new end # Main data container def data @data ||= layers_factory @@ -59,21 +96,29 @@ module DSL extend ActiveSupport::Concern def self.debug? - false + @debug ||= false end + def self.debug!(value = true) + @debug = value + end + def context @@context ||= [] end def debug(text) puts text if DSL.debug? end + def lazy!(*args, &block) + LazyValue.new(block, args) + end + def varibales_hook(meth, *args, &block) debug "Hooked #{meth}" debug "Context is #{context}" if block_given? # Add list @@ -158,8 +203,48 @@ def respond_to?(meth) super_value = super return super_value if super_value != false data.respond_to?(meth) + end + end + + class LazyValue + def self.default_options + { + caching: true + } + end + + attr_reader :block, :args, :options + + def initialize(block, args = [], options = {}) + @block = block + @args = args + @options = self.class.default_options.merge(options) + @cached = false + end + + def value(new_args = nil) + return @cache if caching? && cached? + value = block.call(*(new_args ? new_args : args)) + if caching? + @cache = value + @cached = true + end + value + end + + def caching? + !!options[:caching] + end + + def flush_cache! + @cache = nil # clean pointer so that GC can do it's work immediately + @cached = true + end + + def cached? + @cached end end end