Leo Le Leo Le - 1 month ago 6
Ruby Question

Struct with and without member

I'm a new Rubyist, currently I'm going to use the Struct in class in order to create a temporary object. However, I encounter a question when I use a member in Struct like this:

class A
attr_accessor :b
B = Struct.new(:name, :print_name) do
def print_name
p "Hello #{name}"
end
end

def initialize(input_name)
@b = B.new(input_name)
end
end

a = A.new('Leo')
a.b.print_name # Hello Leo


But I also receive the same result when my Struct B params don't include
:print_name
.

B = Struct.new(:name) do
...
end


So what is the different ? And when should I use the member param and when I'm not ?

Thanks

Answer

In first case you define a class which's initializer takes two arguments - name and print_name.

In second case you define a class which's initializer takes single argument - name.

These has nothing to do with the fact, that you are defining an instance method called print_name.

So instances of both classes (with and without print_name argument) have print_name method defined, thus both examples work identically.

The difference will be visible when you inspect created objects:

# first case with two arguments
foo = B.new(:a, :b)
foo.inspect
=> "#<struct B name=:a, print_name=:b>"

# second case with single argument
foo = B.new(:a)
foo.inspect
=> "#<struct B name=:a>"

Also, when you'll check instance methods of B class for both cases, you can see the difference:

# first case with two arguments
B.instance_methods false
#=> [:name, :name=, :print_name, :print_name=]

# second case with single argument
B.instance_methods false
#=> [:name, :name=, :print_name]

But I also receive the same result when my Struct B params don't include :print_name

The difference, is that in first case you are able to do the following:

a.b.print_name = 'new print name'
a.b.inspect
#=> "#<struct B name='Leo', print_name='new print name'>"

Whereas in second case it will fail:

a.b.print_name = 'new print name'
#=> NoMethodError: undefined method 'print_name=' for #<struct B name='Leo'>