lib/hash_mapper.rb in ismasan-hash_mapper-0.0.5 vs lib/hash_mapper.rb in ismasan-hash_mapper-0.0.6

- old
+ new

@@ -1,22 +1,46 @@ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) +begin + require 'active_support' +rescue LoadError + require 'rubygems' + require 'active_support' +end + + + # This allows us to call blah(&:some_method) instead of blah{|i| i.some_method } unless Symbol.instance_methods.include?('to_proc') class Symbol def to_proc Proc.new {|obj| obj.send(self) } end end end +# http://rpheath.com/posts/341-ruby-inject-with-index +unless Array.instance_methods.include?("inject_with_index") + module Enumerable + def inject_with_index(injected) + each_with_index{ |obj, index| injected = yield(injected, obj, index) } + injected + end + end +end + module HashMapper - VERSION = '0.0.5' + VERSION = '0.0.6' - def maps - @maps ||= [] + # we need this for inheritable mappers, which is annoying because it needs ActiveSupport, kinda overkill. + # + def self.extended(base) + base.class_eval do + write_inheritable_attribute :maps, [] + class_inheritable_accessor :maps + end end def map(from, to, using=nil, &filter) self.maps << Map.new(from, to, using) to.filter = filter if block_given? # Useful if just one block given @@ -39,19 +63,44 @@ end def denormalize(a_hash) perform_hash_mapping a_hash, :denormalize end + + def before_normalize(&blk) + @before_normalize = blk + end + def before_denormalize(&blk) + @before_denormalize = blk + end + + def after_normalize(&blk) + @after_normalize = blk + end + + def after_denormalize(&blk) + @after_denormalize = blk + end + protected + def perform_hash_mapping(a_hash, meth) output = {} + # Before filter + before_filter = instance_eval "@before_#{meth}" + a_hash = before_filter.call(a_hash, output) if before_filter + # Do the mapping a_hash = symbolize_keys(a_hash) maps.each do |m| m.process_into(output, a_hash, meth) end + # After filter + after_filter = instance_eval "@after_#{meth}" + output = after_filter.call(a_hash, output) if after_filter + # Return output end # from http://www.geekmade.co.uk/2008/09/ruby-tip-normalizing-hash-keys-as-symbols/ # @@ -83,54 +132,39 @@ protected def get_value_from_input(output, input, path, meth) value = path.inject(input) do |h,e| - throw :no_value unless h.has_key?(e[0].to_sym) - e[1].nil? ? h[e[0].to_sym] : h[e[0].to_sym][e[1].to_i] - #h[e[0].to_sym] + throw :no_value if h[e].nil?#.has_key?(e) + h[e] end - value = delegate_to_nested_mapper(value, meth) if delegated_mapper - value + delegated_mapper ? delegate_to_nested_mapper(value, meth) : value end def delegate_to_nested_mapper(value, meth) - v = if value.kind_of?(Array) + case value + when Array value.map {|h| delegated_mapper.send(meth, h)} + when nil + throw :no_value else delegated_mapper.send(meth, value) end end def add_value_to_hash!(hash, path, value) - path.inject(hash) do |h,e| - if contained?(h,e) - if e[1].nil? - h[e[0].to_sym] - else - if e == path.last - h[e[0].to_sym][e[1].to_i] = value - end - h[e[0].to_sym][e[1].to_i] - end + path.inject_with_index(hash) do |h,e,i| + if h[e] + h[e] else - if e[1].nil? - h[e[0].to_sym] = (e == path.last ? path.apply_filter(value) : {}) - else - h[e[0].to_sym] = [] - h[e[0].to_sym][e[1].to_i] = (e == path.last ? path.apply_filter(value) : {}) - end + h[e] = (i == path.size-1 ? path.apply_filter(value) : {}) end end + end - def contained?(h,e) - e[1].nil? ? h[e[0].to_sym] : h[e[0].to_sym][e[1].to_i].nil? - rescue - false - end end # contains array of path segments # class PathMap @@ -151,23 +185,26 @@ def each(&blk) @segments.each(&blk) end + def first + @segments.first + end + def last @segments.last end + def size + @segments.size + end + private def parse(path) - #path.sub(/^\//,'').split('/').map(&:to_sym) - path.sub(/^\//,'').split('/').map{ |p| key_index p } + path.sub(/^\//,'').split('/').map(&:to_sym) end - def key_index(p) - p =~ /\[[0-9]+\]$/ ? p.sub(/\[([0-9]+)\]$/,' \1').split(' ') : [p,nil] - end - end -end \ No newline at end of file +end