On Sun, Dec 9, 2012 at 7:19 PM, Intransition <[email protected]> wrote:
> The note `TODO: Improve Hash#rekey code!!!` has been in my docs for too
> long. I could use other's insights and thought others might enjoy the
> challenge. So here's the code:

I think the problem is in the API.  That's what makes it too complex.
There are too many cases of specific handling and options (see below):

>   require 'facets/na'
>
>   class Hash
>
>     # Rekey a hash:
>     #
>     #   rekey()
>     #   rekey(from_key => to_key, ...)
>     #   rekey{|from_key| to_key}
>     #   rekey{|from_key, value| to_key}
>     #
>     # If a key map is given, then the first key is changed to the second
> key.
>     #
>     #   foo = { :a=>1, :b=>2 }
>     #   foo.rekey(:a=>'a')       #=> { 'a'=>1, :b=>2 }
>     #   foo.rekey(:b=>:x)        #=> { :a =>1, :x=>2 }
>     #   foo.rekey('foo'=>'bar')  #=> { :a =>1, :b=>2 }
>     #
>     # If a block is given, converts all keys in the Hash accroding to the
>     # given block procedure. If the block returns +NA+ for a given key,
>     # then that key will be left intact.

1. Unnecessary option: if the key is supposed to stay intact the block
should just return the original key.

>     #
>     #   foo = { :name=>'Gavin', :wife=>:Lisa }
>     #   foo.rekey{ |k| k.to_s }  #=>  { "name"=>"Gavin", "wife"=>:Lisa }
>     #   foo                      #=>  { :name =>"Gavin", :wife=>:Lisa }
>     #
>     # If no key map or block is given, then all keys are converted
>     # to Symbols.

2. Why that default?  In my mind this is too much implicit logic.
Also this can be easily achieved with

hash.rekey(&:to_sym)

>     #
>     # Note that if both a +key_map+ and a block are given, the +key_map+ is
>     # applied first then the block.

3. I would change that to EITHER block OR map argument, but not both.

> Not the use of `facets/na`. That is defined as:
>
>     class << NA = ArgumentError.new
>       def inspect ; 'N/A' ; end
>       def method_missing(*); self; end
>     end
>
> But it is really nothing more than a dummy object used to mean Not
> Applicable. So in the case of #rekey, if the block returns NA then the key
> goes unchanged. Thinking about it again now, it's probably unnecessary, but
> I had wanted a way to say "leave it alone" while also making sure that `nil`
> could still be used as a key (even if that's rare). Feel free to remove the
> NA business, but if you do please explain why you think its not needed.

If one needs a special key one can use a Symbol for that as
efficiently as nil.  nil is the value return if something is absent
and I believe it does not make for a good key in a Hash.

> Best solution will get their name put in front of CREDITs for the next
> release of Facets.

:-)

class Hash
  def rekey(mapping = nil, &convert)
    c = convert || mapping
    dup.tap do |h| # preserve type and defaults
      h.clear
      each_pair {|k, v| h[c[k] || k] = v}
    end
  end
end

Kind regards

robert


--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

-- You received this message because you are subscribed to the Google Groups 
ruby-talk-google group. To post to this group, send email to 
[email protected]. To unsubscribe from this group, send email 
to [email protected]. For more options, visit this 
group at https://groups.google.com/d/forum/ruby-talk-google?hl=en

Reply via email to