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