Setter return self method does not work, is this a mistake?

I want to iterate over an array of strings and assign each of them a new instance of the User class, and I expect that I will have an array of User objects:

class User def name=(name) @name = name self end end original_array = ["aaa", "bbb", "bbb"] result = original_array.collect { |str| User.new.name = str } 

but the result is an array of strings!

 puts result.inspect # => ["aaa", "bbb", "bbb"] puts result === original_array # => true 

I do not know where I was wrong?

+6
source share
1 answer

It is incorrect here that User.new.name = str returns str , so it gets the value str .

Why does it return str ? Because, against any other Ruby method, each set Ruby method returns the passed value, regardless of the return value in the method . For more information about this behavior, you can check out this other SO answer .

Below is IRB-ready proof of concept:

 def name=(name) @name = 'another value' end returned_value = (self.name = 'a value') returned_value #=> 'a value' @name #=> 'another value' 

What you want can be done as follows:

  • This syntax is valid for any Ruby object, as it uses Object#tap :

     User.new.tap { |v| v.name = str } 
  • If User is an ActiveRecord model, I assume you can use one of these slightly shorter syntaxes:

     User.new name: str User.new { |v| v.name = str } 
+5
source

All Articles