Hash <<

So, unless you count merge! and update, there doesn't seem to be a way
to shove stuff into a hash and get the resulting updated hash back.
Now, I know merge and update make it real easy:

  h = {}
  h.update(:a => :b).update(:c => :d).update(:e => :f)

but this some how feels unnatural to me. maybe the following is
better for me and others?

---code---
require 'ext/singleton_class'

class Hash
  def <<(k)
    if @shift_value.nil? then
      @shift_value = Object.new.singleton_def(:key) {k}
    else
      key, @shift_value = @shift_value.key, nil
      self[key] = k
    end
    self
  end
end
---end code---

---usage---
h = {}
h << :language << :ruby << :creator << :matz << :users << :"comp.lang.ruby"
p h
---result---
{:language=>:ruby, :creator=>:matz, :users=>:"comp.lang.ruby"}

···

-------------

Just a question of flavour, really.

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.

Why use this over:

h.update(:a => :b, :c => :d, :e => :f)

?

James Edward Gray II

···

On Oct 20, 2004, at 9:04 AM, Matt Maycock wrote:

So, unless you count merge! and update, there doesn't seem to be a way
to shove stuff into a hash and get the resulting updated hash back.
Now, I know merge and update make it real easy:

  h = {}
  h.update(:a => :b).update(:c => :d).update(:e => :f)

---usage---
h = {}
h << :language << :ruby << :creator << :matz << :users << :"comp.lang.ruby"
p h
---result---
{:language=>:ruby, :creator=>:matz, :users=>:"comp.lang.ruby"}
-------------

Ugh. Toggling internal state like that will leave you in mutex hell if
you're trying to write thread-safe code.

I suppose I wouldn't object to:

  class Hash
    def <<(kv)
      self[kv[0]] = kv[1]
      self
    end
  end

  h << [:language,:ruby] << [:creator,:matz] << [:users,:"comp.lang.ruby"]

but I've never felt the need.

Regards,

Brian.

"Matt Maycock" <ummaycoc@gmail.com> schrieb im Newsbeitrag
news:e86cebfb04102007046b2c189c@mail.gmail.com...

So, unless you count merge! and update, there doesn't seem to be a way
to shove stuff into a hash and get the resulting updated hash back.
Now, I know merge and update make it real easy:

  h = {}
  h.update(:a => :b).update(:c => :d).update(:e => :f)

but this some how feels unnatural to me. maybe the following is
better for me and others?

---code---
require 'ext/singleton_class'

class Hash
  def <<(k)
    if @shift_value.nil? then
      @shift_value = Object.new.singleton_def(:key) {k}
    else
      key, @shift_value = @shift_value.key, nil
      self[key] = k
    end
    self
  end
end
---end code---

---usage---
h = {}
h << :language << :ruby << :creator << :matz << :users <<

:"comp.lang.ruby"

p h
---result---
{:language=>:ruby, :creator=>:matz, :users=>:"comp.lang.ruby"}
-------------

Just a question of flavour, really.

I don't like this solution because you have to store state in the Hash
that is solely connected to the appending. That's bad because this state
solely belongs to the operation, not to the Hash. This will have
surprising effects:

h = {}
h << :key1 << :val1 << :key2 # forgot :val2
# many lines later
h << :key3 << :val3

Also, as James wrote already, you can use update with multiple pairs.

If you want to have << then I'd do any of the following:

Opt 1:

class Hash
  def <<(pair)
    self[ pair[0] ]= pair[1]
    self
  end
end

h = {}
h << [:key, :val] << [:key2, :val2]

Opt 2.

class HashAdder < Struct.new(:hash, :key)
  def <<(val)
    self.hash[ self.key ] = val
    self.hash
  end
end

class Hash
  def <<(key) HashAdder.new( self, key ) end
end

h = {}
h << :key << :val << :key2 << :val2

Opt 3:

Like opt 2 but reuse a single HashAdder instance toggling between key and
value much like you suggested in your post.

However, these options are far worse than simply using Hash.update(:key1
=> :val1, :key2 => :val2).

Regards

    robert

Matt Maycock wrote:

So, unless you count merge! and update, there doesn't seem to be a way
to shove stuff into a hash and get the resulting updated hash back.

I'm not sure, but maybe KeyedList could help here. It is a Hash that has list-style insert operations:

Struct.new("Hero", :name, :reason)

# Create a KeyedList which will be keyed by the names
# of its heroic elements.
list = KeyedList.new { |hero| hero.name }
# Adds elements to the KeyedList.
list << Struct::Hero.new("Yukihiro Matsumoto", "Ruby")
list << Struct::Hero.new("Larry Wall", "Enhanced regular expressions")
list << Struct::Hero.new("Randal Schwartz", "Schwartzian transform")
   list.size # => 3
list["Yukihiro Matsumoto"].reason # => "Ruby"

It is both available as a Gem and from RPA.

Regards,
Florian Gross

I know I'm late to the party here, but would you be happy with:

    class Hash
        alias << update
        end

with which you could write:

  h << {:a => :b} << {:c => :d} << {:e => :f}

   -- Markus

P.S. I still maintain the canonical refutation of your sig is "hug."

···

On Wed, 2004-10-20 at 07:04, Matt Maycock wrote:

So, unless you count merge! and update, there doesn't seem to be a way
to shove stuff into a hash and get the resulting updated hash back.
Now, I know merge and update make it real easy:

  h = {}
  h.update(:a => :b).update(:c => :d).update(:e => :f)

but this some how feels unnatural to me. maybe the following is
better for me and others?

---code---
require 'ext/singleton_class'

class Hash
  def <<(k)
    if @shift_value.nil? then
      @shift_value = Object.new.singleton_def(:key) {k}
    else
      key, @shift_value = @shift_value.key, nil
      self[key] = k
    end
    self
  end
end
---end code---

---usage---
h = {}
h << :language << :ruby << :creator << :matz << :users << :"comp.lang.ruby"
p h
---result---
{:language=>:ruby, :creator=>:matz, :users=>:"comp.lang.ruby"}
-------------

Just a question of flavour, really.

I really just wanted to show the chaining thing - but there may be
other methods in between that give issues with doing it all at once.

~Me!

···

On Wed, 20 Oct 2004 23:17:35 +0900, James Edward Gray II <james@grayproductions.net> wrote:

On Oct 20, 2004, at 9:04 AM, Matt Maycock wrote:

> So, unless you count merge! and update, there doesn't seem to be a way
> to shove stuff into a hash and get the resulting updated hash back.
> Now, I know merge and update make it real easy:
>
> h = {}
> h.update(:a => :b).update(:c => :d).update(:e => :f)

Why use this over:

h.update(:a => :b, :c => :d, :e => :f)

?

James Edward Gray II

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.

P.S. I still maintain the canonical refutation of your sig is "hug."

The undead would still be chasing you - just with a mixed drink... :slight_smile:

···

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.

[double post]

of course, mine isn't much better if you're doing

hash.update(...).foo.meow.update(...)

as opposed to

((hash << ... <<).foo.meow << ...)...

so maybe it is a bad idea... :slight_smile:

My main use is in cases with:
a = enum.inject(Hash.new) {|h, f|
  h.update(k(f) => v(f))
}

for some odd reason,
  a = enum.inject(Hash.new) {|h, f|
    h << k(f) << v(f)
  }
just `feels' better to me.

···

On Wed, 20 Oct 2004 10:22:10 -0400, Matt Maycock <ummaycoc@gmail.com> wrote:

I really just wanted to show the chaining thing - but there may be
other methods in between that give issues with doing it all at once.

~Me!

On Wed, 20 Oct 2004 23:17:35 +0900, James Edward Gray II > <james@grayproductions.net> wrote:
> On Oct 20, 2004, at 9:04 AM, Matt Maycock wrote:
>
> > So, unless you count merge! and update, there doesn't seem to be a way
> > to shove stuff into a hash and get the resulting updated hash back.
> > Now, I know merge and update make it real easy:
> >
> > h = {}
> > h.update(:a => :b).update(:c => :d).update(:e => :f)
>
> Why use this over:
>
> h.update(:a => :b, :c => :d, :e => :f)
>
> ?
>
> James Edward Gray II
>
>

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.

for some odd reason,
  a = enum.inject(Hash.new) {|h, f|
    h << k(f) << v(f)
  }
just `feels' better to me.

Feels better than

    h[k(f)] = v(f)

?

You'd have to make that
  a = enum.inject(Hash.new) {|h, f|
    h[k(f)] = v(f)
    h
  }
-- my general desire is to have code be a single expression when I
write code. just the way I work :slight_smile:

~Me!

···

On Wed, 20 Oct 2004 23:35:25 +0900, Brian Candler <b.candler@pobox.com> wrote:

> for some odd reason,
> a = enum.inject(Hash.new) {|h, f|
> h << k(f) << v(f)
> }
> just `feels' better to me.

Feels better than

    h[k(f)] = v(f)

?

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.