New Rexx like data structure

This is just something that I have been playing with for some time but I
thought a structure like this might be cool.

a = Hash.new
a.b = 12

This behaves the same as a[‘b’] = 12, and this …

a.c.d = 42

behaves like this …

a[‘c’][‘d’] = 42

The syntax looks cleaner to me if a little Rexxish (or Lua like). Here’s
how I implemented it

class Hash
def method_missing(m, *args, &block)
key = m.to_s

if key =~ /(.*)=$/
  self.store($1, args.first)
elsif self[key] == nil
  self.store(key, Hash.new)
else
  self[key]
end

end
end

There is just one little wrinkle in this plan

a.j => Hash

Given that a.j has not beed defined, that is there has been no “a.j =
19”
for example, I would prefer that a.j return nil but can’t for the life
of
me think how to get this to work.

Any suggestions?

How about this?

class Hash
def method_missing(m, args, &block)
key = m.to_s
if key =~ /(.
)=$/
self.store($1, args.first)
elsif self[key] == nil && key =~ /(.*)=$/
self.store(key, Hash.new)
else
self[key]
end
end
end

Oh, I see the problem.

As far as I know you can’t “know” that there’s another method chained on
the end of the current one

I think you’d have to settle for:
a.c = {}
a.c.d = 42
a.j => nil

On Mon, Apr 29, 2013 at 5:07 PM, Peter H. <
[email protected]> wrote:

behaves like this …
if key =~ /(.*)=$/

a.j => Hash

Given that a.j has not beed defined, that is there has been no “a.j = 19”
for example, I would prefer that a.j return nil but can’t for the life of
me think how to get this to work.

There is no way because a getter method cannot know whether the result
is
used as is or whether it is part of a chain and another setter is
invoked.
In other words:

x = a.c # case 1
a.c.d = 9 # case 2

Here, no implementation of method c can detect whether we have case 1 or
2.

This reminds me of OpenStruct…

Kind regards

robert

You might enjoy reading the code of GitHub - ahoward/map: the ruby container you've always wanted: an ordered string/symbol indifferent hash

BTW, nice to see someone mention REXX. I taught myself to code in REXX
:slight_smile:

On Mon, Apr 29, 2013 at 11:07 AM, Peter H. <

On 29 April 2013 16:23, Joel P. [email protected] wrote:

  self[key]
end

end
end

Unfortunately is breaks

a.c.d = 12

NoMethodError: undefined method `d=’ for nil:NilClass

I suspect that ‘c’ has been turned into a nil

On 29 April 2013 16:33, Robert K. [email protected]
wrote:

=> #
irb(main):016:0> o.foo.bar=123
=> 123
irb(main):017:0> o
=> #<OpenStruct foo=#>

Hmm. That doesn’t seem to work for me in 1.8.7 or 1.9.2

ruby-1.9.2-p290 :001 > class OpenStruct
ruby-1.9.2-p290 :002?> alias _method_missing method_missing
ruby-1.9.2-p290 :003?> def method_missing(*a,&b)
x=_method_missing(*a,&b); x.nil? ? send(“#{a.first}=”, self.class.new) :
x
end
ruby-1.9.2-p290 :004?> end
=> nil
ruby-1.9.2-p290 :005 >
ruby-1.9.2-p290 :006 > o=OpenStruct.new
=> #OpenStruct:0x00000100a9c3a0
ruby-1.9.2-p290 :007 > o.foo.bar=123
NoMethodError: undefined method foo' for #<OpenStruct:0x00000100a9c3a0> from (irb):3:in method_missing’
from (irb):7
from /Users/peterhickman/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in
`’
ruby-1.9.2-p290 :008 > o
=> #OpenStruct:0x00000100a9c3a0

Same error in both

On Mon, Apr 29, 2013 at 5:29 PM, Robert K.
[email protected]wrote:

This reminds me of OpenStruct…

We can only make it work if you accept always getting an OpenStruct in
return

irb(main):011:0> class OpenStruct
irb(main):012:1> alias _method_missing method_missing
irb(main):013:1> def method_missing(*a,&b) x=_method_missing(*a,&b);
x.nil?
? send(“#{a.first}=”, self.class.new) : x end
irb(main):014:1> end
=> nil
irb(main):015:0> o=OpenStruct.new
=> #
irb(main):016:0> o.foo.bar=123
=> 123
irb(main):017:0> o
=> #<OpenStruct foo=#>

Kind regards

robert

On Mon, Apr 29, 2013 at 5:43 PM, Peter H. <
[email protected]> wrote:

=> nil
ruby-1.9.2-p290 :001 > class OpenStruct
NoMethodError: undefined method foo' for #<OpenStruct:0x00000100a9c3a0> from (irb):3:inmethod_missing’
from (irb):7
from /Users/peterhickman/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in
`’
ruby-1.9.2-p290 :008 > o
=> #OpenStruct:0x00000100a9c3a0

Same error in both

Just to be sure: you did require “ostruct” did you?

robert@fussel:~$ irb -r ostruct
irb(main):001:0> class OpenStruct
irb(main):002:1> alias _method_missing method_missing
irb(main):003:1> def method_missing(*a,&b) x=_method_missing(a,&b);
x.nil? ? send("#{a.first}=", self.class.new) : x end
irb(main):004:1> end
=> nil
irb(main):005:0>
irb(main):006:0
o = OpenStruct.new
=> #
irb(main):007:0> o.foo.bar = 123
=> 123
irb(main):008:0> RUBY_VERSION
=> “1.9.3”

Cheers

robert

On Tue, Apr 30, 2013 at 10:17 AM, Peter H. <
[email protected]> wrote:

Yeah I did that. My output showed that in my post

ruby-1.9.2-p290 :006 > o=OpenStruct.new
=> #OpenStruct:0x00000100a9c3a0

The problem here is that even if it was to work it is just changing the
problem by returning an OpenStruct rather than a Hash. But what I really
wanted was a nil so nothing really changes.

As I said before: this is not possible.

Cheers

robert

Yeah I did that. My output showed that in my post

ruby-1.9.2-p290 :006 > o=OpenStruct.new
=> #OpenStruct:0x00000100a9c3a0

The problem here is that even if it was to work it is just changing the
problem by returning an OpenStruct rather than a Hash. But what I really
wanted was a nil so nothing really changes.