lib/nugrant/bag.rb in nugrant-2.0.0.pre2 vs lib/nugrant/bag.rb in nugrant-2.0.0.rc1
- old
+ new
@@ -1,5 +1,7 @@
+require 'nugrant/config'
+
module Nugrant
class Bag < Hash
##
# Create a new Bag object which holds key/value pairs.
@@ -25,19 +27,35 @@
super()
@__config = Config::convert(config)
(elements || {}).each do |key, value|
- self[key] = value.kind_of?(Hash) ? Bag.new(value, config) : value
+ self[key] = value
end
end
+ def config=(config)
+ @__config = Config::convert(config)
+ end
+
def method_missing(method, *args, &block)
self[method]
end
##
+ ### Enumerable Overridden Methods (for string & symbol indifferent access)
+ ##
+
+ def count(item)
+ super(__try_convert_item(item))
+ end
+
+ def find_index(item = nil, &block)
+ block_given? ? super(&block) : super(__try_convert_item(item))
+ end
+
+ ##
### Hash Overridden Methods (for string & symbol indifferent access)
##
def [](input)
key = __convert_key(input)
@@ -45,40 +63,80 @@
super(key)
end
def []=(input, value)
- super(__convert_key(input), value)
+ super(__convert_key(input), __convert_value(value))
end
+ def assoc(key)
+ super(__convert_key(key))
+ end
+
+ def delete(key)
+ super(__convert_key(key))
+ end
+
+ def fetch(key, default = nil)
+ super(__convert_key(key), default)
+ end
+
+ def has_key?(key)
+ super(__convert_key(key))
+ end
+
+ def include?(item)
+ super(__try_convert_item(item))
+ end
+
def key?(key)
super(__convert_key(key))
end
- ##
- # This method deeply merge two instance together
- #
- #
- def merge!(input)
- input.each do |key, value|
+ def member?(item)
+ super(__try_convert_item(item))
+ end
+
+ def dup()
+ self.class.new(self, @__config.dup())
+ end
+
+ def merge(other, options = {})
+ result = dup()
+ result.merge!(other)
+ end
+
+ def merge!(other, options = {})
+ other.each do |key, value|
current = __get(key)
case
when current == nil
self[key] = value
when current.kind_of?(Hash) && value.kind_of?(Hash)
- current.merge!(value)
+ current.merge!(value, options)
when current.kind_of?(Array) && value.kind_of?(Array)
- self[key] = send("__#{@__config.array_merge_strategy}_array_merge", current, value)
+ strategy = options[:array_merge_strategy]
+ if not Nugrant::Config.supported_array_merge_strategy(strategy)
+ strategy = @__config.array_merge_strategy
+ end
+ self[key] = send("__#{strategy}_array_merge", current, value)
+
when value != nil
self[key] = value
end
end
+
+ self
end
+ def store(key, value)
+ self[key] = value
+ end
+
def to_hash(options = {})
return {} if empty?()
use_string_key = options[:use_string_key]
@@ -88,14 +146,19 @@
[key, value]
end]
end
- ##
- ### Aliases
- ##
+ def walk(path = [], &block)
+ each do |key, value|
+ nested_bag = value.kind_of?(Nugrant::Bag)
+ value.walk(path + [key], &block) if nested_bag
+ yield path + [key], key, value if not nested_bag
+ end
+ end
+
alias_method :to_ary, :to_a
##
### Private Methods
##
@@ -106,23 +169,51 @@
return key.to_sym() if key.respond_to?(:to_sym)
raise ArgumentError, "Key cannot be converted to symbol, current value [#{key}] (#{key.class.name})"
end
+ ##
+ # This function change value convertible to Bag into actual Bag.
+ # This trick enable deeply using all Bag functionalities and also
+ # ensures at the same time a deeply preventive copy since a new
+ # instance is created for this nested structure.
+ #
+ # @param value The value to convert to bag if necessary
+ # @return The converted value
+ #
+ def __convert_value(value)
+ value.kind_of?(Hash) ? Bag.new(value, @__config) : value
+ end
+
def __get(key)
# Calls Hash method [__convert_key(key)], used internally to retrieve value without raising Undefined parameter
self.class.superclass.instance_method(:[]).bind(self).call(__convert_key(key))
end
+ ##
+ # The concat order is the reversed compared to others
+ # because we assume that new values have precedence
+ # over current ones. Hence, the are prepended to
+ # current values. This is also logical for parameters
+ # because of the order in which bags are merged.
+ #
def __concat_array_merge(current_array, new_array)
- current_array + new_array
+ new_array + current_array
end
def __extend_array_merge(current_array, new_array)
current_array | new_array
end
def __replace_array_merge(current_array, new_array)
new_array
+ end
+
+ def __try_convert_item(args)
+ return [__convert_key(args[0]), args[1]] if args.kind_of?(Array)
+
+ __convert_key(args)
+ rescue
+ args
end
end
end