How do you know that it isn’t able to add :email?
ratdog:tmp mike$ pry
[1] pry(main)> require ‘ostruct’
=> false
[2] pry(main)> contact = OpenStruct.new(first_name: “John”, last_name:
“Smith”, phone: “XXXXXXX”)
=> #<OpenStruct first_name=“John”, last_name=“Smith”, phone=“XXXXXXX”>
[3] pry(main)> ls contact
OpenStruct#methods:
== []= each_pair hash marshal_dump method_missing
to_s
[] delete_field eql? inspect marshal_load to_h
self.methods: first_name first_name= last_name last_name= phone
phone=
instance variables: @table
We see that contact’s methods unique to itself are the expected
setters/getters for first_name, last_name, and phone. Let’s send the
new_ostruct_member message:
[4] pry(main)> contact.send(:new_ostruct_member ,:email)
=> :email
[5] pry(main)> ls contact
OpenStruct#methods:
== []= each_pair hash marshal_dump method_missing
to_s
[] delete_field eql? inspect marshal_load to_h
self.methods:
email email= first_name first_name= last_name last_name= phone
phone=
instance variables: @table
Now we wee that contact’s methods include email and email= so it looks
like new_ostruct_member did its metaprogramming (see
for the docs).
Maybe it was the lack of an email=nil or something in the output of p
which made you suspect nothing had happened? If so we can look at the
implementation of inspect to see how it works:
[6] pry(main)> $ contact.inspect
From: /Users/mike/.rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/ostruct.rb @
line 23
Owner: OpenStruct
Visibility: public
Number of lines: 21
def inspect
str = “#<#{self.class}”
ids = (Thread.current[InspectKey] ||= [])
if ids.include?(object_id)
return str << ’ …>’
end
ids << object_id
begin
first = true
for k,v in @table
str << “,” unless first
first = false
str << " #{k}=#{v.inspect}"
end
return str << ‘>’
ensure
ids.pop
end
end
So it looks like email will not show up until it has been added to
@table - looking at email= we can see how it works, going through
modifiable:
[7] pry(main)> $ contact.email=
From: /Users/mike/.rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/ostruct.rb @
line 170:
Owner: #<Class:#OpenStruct:0x007fbe0e567470>
Visibility: public
Number of lines: 1
define_singleton_method(“#{name}=”) { |x| modifiable[name] = x }
[8] pry(main)> $ contact.modifiable
From: /Users/mike/.rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/ostruct.rb @
line 151:
Owner: OpenStruct
Visibility: protected
Number of lines: 8
def modifiable
begin
@modifiable = true
rescue
raise TypeError, “can’t modify frozen #{self.class}”, caller(3)
end
@table
end
So we can cheat and manually add an “illegal” (i.e. no getter or setter
defined) entry to contact’s @table to see if affects the output of
inspect:
[9] pry(main)> cd contact
[10] pry(#):1> @table
=> {:first_name=>“John”, :last_name=>“Smith”, :phone=>“XXXXXXX”}
[11] pry(#):1> @table[:foo] = ‘bar’
=> “bar”
[12] pry(#):1> cd …
[13] pry(main)> p contact
#<OpenStruct first_name=“John”, last_name=“Smith”, phone=“XXXXXXX”,
foo=“bar”>
=> #<OpenStruct first_name=“John”, last_name=“Smith”, phone=“XXXXXXX”,
foo=“bar”>
So we can see that for an attribute to show up in the output of inspect
it needs to have been put in the OpenStruct instance’s @table.
I’ll leave it to you to have a look at contact’s method_missing to see
how OpenStruct attributes might be set and retrieved so you can see the
context in which new_ostruct_member is called.
pry is a great tool.
Hope this helps,
Mike
On 2013-06-20, at 6:09 AM, Love U Ruby [email protected] wrote:
Why the #new_ostruct_member
not being able to add the :email
?
–
Posted via http://www.ruby-forum.com/.
–
Mike S. [email protected]
http://www.stok.ca/~mike/
The “`Stok’ disclaimers” apply.