This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
This is from Ruby on Rails Tutorial, 2nd ed., chapter 6, by Michael Hartl:
I've been studying Ruby syntax for the past month, but I'm still baffled by a lot of it. Let's start with has_secure_password on line 4. What is that? It's not a method definition, because those start with "def". So that means it's a method call? When would that call be executed though? It's not in an initialize method, or any other method for that matter. That's blowing my Java-trained mind. It's just code sitting in the middle of a class definition, and not only is it not flagged as an error, it somehow is adding an authenticate method to the User class, ensuring that the password meets some standards of security (defined where?), validating that password and password_confirmation match, and a bunch of other stuff. Cool magic, but, as I said, baffling.
In Ruby, a code that appears inside the class definition is executed once the class definition is processed. And since Ruby classes can be modified at runtime, it can do anything with the class. See also the question on SO.
By the way, attr_accessor works the same way. I had thought it is a special declaration, but it is actually a method call too. I've found a nice example of how it could look like here.
Thanks, those links were really helpful! So the free-standing stuff in the class definition acts like a static initialization block in Java, but also has the ability to change the class definition. That's starting to make sense now.
Speaking of attr_accessor, RubyMine flags :password and :password_confirmation, with the message, "Unexpected parameter value for Rails specific call." Why just those two? Did a miss a configuration step, or is it because the database table backing the User class doesn't contain those fields? (It just has password_digest.) How does RubyMine even know that?
Greg Charles wrote:So the free-standing stuff in the class definition acts like a static initialization block in Java
Not entirely. It doesn't run in a static context, but in the context of the object representing the class the code is included in. If you use an instance variable in that context, it will be stored in the class object. So, for example, this code initializes neither class variable, nor instance variable to 3:
Frankly, I don't even know how to (easily) access that variable created on line 4. I'm still trying to wrap my head around the metaprogramming in Ruby.
As for the other question, I've found this link which might be relevant. Or not. I'm still wrestling terribly with all the magic that happens behind the scenes in Rails.
Interesting. I sort of halfway understand your point about Ruby's class body code being different from Java's static context. Both are really working with an object of type class, but Ruby has a lot more complicated class loading and mixing going on, so it's not an exact parallel. It's probably going to take me some more trial and error before I really grok that. That link is useful in explaining the difference between attr_accessible and attr_accessor. It doesn't really go into why RubyMine is flagging two params in attr_accessible and not the other two, but I'm 90% sure it's because those two params aren't in the database representation of the class. I don't know how RubyMine knows that, but it probably has its ways.