lib/configdsl.rb in configdsl-1.2.0 vs lib/configdsl.rb in configdsl-1.2.1

- old
+ new

@@ -1,255 +1,255 @@ -require "configdsl/version" -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 - @factory_base_class ||= MemoryLayer - @factory_base_class.new - end - - # Main data container - def data - @data ||= layers_factory - end - - # Stores a value in specified key for specified context - def store(key, value, context = []) - layer = expand_context(context) - layer[key] = value - end - - # Fetches a specified key for a specified context - # Allows to provide a default value - def fetch(key, defaul_value = nil, context = []) - fetch!(key, context) - rescue KeyError => e - defaul_value - end - - # Fetches a specified key for a specified context - # Raises exception if something goes wrong - def fetch!(key, context = []) - layer = expand_context(context) - raise KeyError, "In context #{context} key not found: #{key.inspect}" unless layer.has_key?(key) - layer[key] - end - - # Return a layer described by context or rises an exception - # if any of parent layers is undefined - def expand_context(context) - context.inject(data) do |hash, level| - hash[level] - end - end - - # Adds a new layer if it does not exist - def add_layer(new_layer, context) - current_layer = expand_context(context) - current_layer[new_layer] ||= layers_factory - end - end - end - - module DSL - extend ActiveSupport::Concern - - def self.debug? - @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 assign!(sym, value = nil, &block) - return sym.each { |key, val| assign!(key, val) } if sym.kind_of? Hash - varibales_hook(sym, value, &block) - end - - def varibales_hook(meth, *args, &block) - debug "Hooked #{meth}" - debug "Context is #{context}" - if block_given? - # Add list - debug "Adding list #{meth}" - evaluate_within_layer(meth, block, args) - else - if args.empty? - # Read variable - debug "Reading variable #{meth}" - Memory.fetch!(meth, context) - else - # Add variable - debug "Adding variable #{meth}" - value = args.size == 1 ? args.first : args.dup - Memory.store(meth, value, context) - end - end - end - - def evaluate_within_layer(new_layer, block, args = []) - Memory.add_layer(new_layer, context) - begin - context.push new_layer - block.call(*args) - ensure - context.pop - end - end - - def method_missing(meth, *args, &block) - if respond_to?(meth) - super - else - varibales_hook(meth, *args, &block) - end - end - - end - - module Processor - class Sandbox - include DSL - end - - def self.process(filename) - sandbox = Sandbox.new - sandbox.instance_eval(File.read(filename), filename) - sandbox - end - - def self.execute(&block) - sandbox = Sandbox.new - sandbox.instance_eval(&block) - sandbox - end - - def self.add_module(module_const) - Sandbox.extend module_const - end - end - - class << self - def read(filename) - Processor.process(filename) - end - - def execute(&block) - Processor.execute(&block) - end - - def data - Memory.data - end - - def method_missing(meth, *args, &block) - if data.respond_to?(meth) - data.send(meth, *args, &block) - else - super - end - end - - 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 +require "configdsl/version" +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 + @factory_base_class ||= MemoryLayer + @factory_base_class.new + end + + # Main data container + def data + @data ||= layers_factory + end + + # Stores a value in specified key for specified context + def store(key, value, context = []) + layer = expand_context(context) + layer[key] = value + end + + # Fetches a specified key for a specified context + # Allows to provide a default value + def fetch(key, defaul_value = nil, context = []) + fetch!(key, context) + rescue KeyError => e + defaul_value + end + + # Fetches a specified key for a specified context + # Raises exception if something goes wrong + def fetch!(key, context = []) + layer = expand_context(context) + raise KeyError, "In context #{context} key not found: #{key.inspect}" unless layer.has_key?(key) + layer[key] + end + + # Return a layer described by context or rises an exception + # if any of parent layers is undefined + def expand_context(context) + context.inject(data) do |hash, level| + hash[level] + end + end + + # Adds a new layer if it does not exist + def add_layer(new_layer, context) + current_layer = expand_context(context) + current_layer[new_layer] ||= layers_factory + end + end + end + + module DSL + extend ActiveSupport::Concern + + def self.debug? + @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 assign!(sym, value = nil, &block) + return sym.each { |key, val| assign!(key, val) } if sym.kind_of? Hash + varibales_hook(sym, value, &block) + end + + def varibales_hook(meth, *args, &block) + debug "Hooked #{meth}" + debug "Context is #{context}" + if block_given? + # Add list + debug "Adding list #{meth}" + evaluate_within_layer(meth, block, args) + else + if args.empty? + # Read variable + debug "Reading variable #{meth}" + Memory.fetch!(meth, context) + else + # Add variable + debug "Adding variable #{meth}" + value = args.size == 1 ? args.first : args.dup + Memory.store(meth, value, context) + end + end + end + + def evaluate_within_layer(new_layer, block, args = []) + Memory.add_layer(new_layer, context) + begin + context.push new_layer + block.call(*args) + ensure + context.pop + end + end + + def method_missing(meth, *args, &block) + if respond_to?(meth) + super + else + varibales_hook(meth, *args, &block) + end + end + + end + + module Processor + class Sandbox + include DSL + end + + def self.process(filename) + sandbox = Sandbox.new + sandbox.instance_eval(File.read(filename), filename) + sandbox + end + + def self.execute(&block) + sandbox = Sandbox.new + sandbox.instance_eval(&block) + sandbox + end + + def self.add_module(module_const) + Sandbox.extend module_const + end + end + + class << self + def read(filename) + Processor.process(filename) + end + + def execute(&block) + Processor.execute(&block) + end + + def data + Memory.data + end + + def method_missing(meth, *args, &block) + if data.respond_to?(meth) + data.send(meth, *args, &block) + else + super + end + end + + 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