diff --git a/lib/buff/extensions/hash.rb b/lib/buff/extensions/hash.rb index b69a9c5..ff20281 100644 --- a/lib/buff/extensions/hash.rb +++ b/lib/buff/extensions/hash.rb @@ -1,5 +1,12 @@ -require_relative 'hash/dotted_paths' -require_relative 'hash/except' -require_relative 'hash/key_transforms' -require_relative 'hash/reverse_merge' -require_relative 'hash/slice' +module Buff::Extensions + module Hash + require_relative 'hash/dotted_paths' + require_relative 'hash/except' + require_relative 'hash/key_transforms' + require_relative 'hash/reverse_merge' + require_relative 'hash/slice' + + extend Slice + extend ReverseMerge + end +end diff --git a/lib/buff/extensions/hash/reverse_merge.rb b/lib/buff/extensions/hash/reverse_merge.rb index 9f7f1f1..b30d845 100644 --- a/lib/buff/extensions/hash/reverse_merge.rb +++ b/lib/buff/extensions/hash/reverse_merge.rb @@ -1,23 +1,43 @@ module Buff module Extensions::Hash module ReverseMerge + class << self + def extended(base) + base.extend(ClassMethods) + end + end + + module ClassMethods + # @param [Hash] other + # + # @return [Hash] + def reverse_merge(one, two) + two.merge(one) + end + + # @param [Hash] other + # + # @return [Hash] + def reverse_merge!(one, two) + one.merge!(two) { |key, old, new| old } + end + + extend self + end + # @param [Hash] other # # @return [Hash] def reverse_merge(other) - other.merge(self) + ClassMethods.merge(self, other) end # @param [Hash] other # # @return [Hash] def reverse_merge!(other) - merge!(other) { |key, old, new| old } + ClassMethods.reverse_merge!(self, other) end end end end - -class Hash - include Buff::Extensions::Hash::ReverseMerge -end diff --git a/lib/buff/extensions/hash/slice.rb b/lib/buff/extensions/hash/slice.rb index 4bdef86..7fb8392 100644 --- a/lib/buff/extensions/hash/slice.rb +++ b/lib/buff/extensions/hash/slice.rb @@ -3,22 +3,37 @@ module Extensions::Hash # Borrowd and modified from # {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/hash/slice.rb} module Slice + class << self + def extended(base) + base.extend(ClassMethods) + end + end + + module ClassMethods + def slice(obj, *keys) + obj.keys.map! { |key| obj.convert_key(key) } if obj.respond_to?(:convert_key, true) + obj.keys.each_with_object(obj.class.new) { |k, hash| hash[k] = obj[k] if obj.has_key?(k) } + end + + def slice!(obj, *keys) + obj.keys.map! { |key| obj.convert_key(key) } if obj.respond_to?(:convert_key, true) + omit = obj.slice(*obj.keys - keys) + hash = obj.slice(*keys) + obj.replace(hash) + omit + end + + def extract!(obj, *keys) + obj.keys.each_with_object(obj.class.new) { |key, result| result[key] = obj.delete(key) if obj.has_key?(key) } + end + + extend self + end + # Slice a hash to include only the given keys. This is useful for - # limiting an options hash to valid keys before passing to a method: - # - # def search(criteria = {}) - # criteria.assert_valid_keys(:mass, :velocity, :time) - # end - # - # search(options.slice(:mass, :velocity, :time)) - # - # If you have an array of keys you want to limit to, you should splat them: - # - # valid_keys = [:mass, :velocity, :time] - # search(options.slice(*valid_keys)) + # limiting an options hash to valid keys before passing to a method def slice(*keys) - keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) - keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) } + ClassMethods.slice(self, *keys) end # Replaces the hash with only the given keys. @@ -27,11 +42,7 @@ def slice(*keys) # { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b) # # => {:c=>3, :d=>4} def slice!(*keys) - keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) - omit = slice(*self.keys - keys) - hash = slice(*keys) - replace(hash) - omit + ClassMethods.slice!(self, *keys) end # Removes and returns the key/value pairs matching the given keys. @@ -39,12 +50,8 @@ def slice!(*keys) # { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2} # { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1} def extract!(*keys) - keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) } + ClassMethods.extract!(self, *keys) end end end end - -class Hash - include Buff::Extensions::Hash::Slice -end