2 Objects, methods, and local variables
This chapter orients you to Ruby’s object-first mindset: everything you do is done by sending messages (calling methods) to objects. You can create generic objects and “teach” them behaviors with methods, including singleton methods defined on a single object. Method calls may take arguments, and a call always returns a value (by default, the last evaluated expression). Ruby favors readable code: parentheses are often optional, and string interpolation helps compose output succinctly. Predicate methods that end with a question mark communicate Boolean queries cleanly, and Ruby’s truthiness rules are simple—only false and nil are treated as false.
It also shows how to explore and leverage built-in capabilities and flexible calling conventions. Objects come with innate methods you can inspect, and tools like object_id (identity), respond_to? (capability checks), and send/__send__/public_send (dynamic message dispatch) enable introspection and safe, dynamic behavior—especially when validating user input. Method parameters are covered in depth: required arguments, optional defaults, and variable-length “splat” parameters can be mixed; required parameters on either end get priority, splat gathers the rest, and defaults live in the middle. You learn the ordering rules, what combinations are invalid, and that every call binds parameters to local variables and returns a value.
Finally, the chapter clarifies local variables, scope, and references. Local variables are scoped (a method’s x is not another method’s x), and most variables hold references to objects rather than the objects themselves—so in-place mutations are visible through all references, while reassignment retargets only the reassigned variable. Because arguments are passed as references, called methods can mutate passed objects; you can protect data with dup/clone and freeze (noting that freezing a collection doesn’t freeze its elements). The chapter closes with how Ruby resolves bare identifiers—keyword, local variable, or method call—and how unresolved names raise informative errors, preparing you to move on to class-based object construction.
Anatomy of a method definition.
Argument assignment logic in action.
Summary
- Create a new object and define methods for it.
- The basics of the message-sending mechanism by which you send requests to objects for information or action.
- The process of mapping elements of a domain (even a modest one-entity domain like “a ticket to an event”) onto a system of objects so that those objects can store information and perform relevant tasks.
- Several of the important built-in methods that every Ruby object comes with: object_id, respond_to?, and send.
- Details of the syntax for method argument lists, including the use of required, optional, and default-valued arguments.
- How local variables and variable assignment work.
- Ruby’s use of references to objects and how references play out when multiple variables refer to the same object.
- The role of “real world” modeling in the process of thinking about object-oriented program design—and why it’s important not to overemphasize real-world parallels and analogies.
- The language offers lots of facilities for developing program structure. Creating objects one by one, as we’ve done in this chapter, is little more than the tip of the iceberg.
FAQ
What is an object in Ruby and how do I create one?
In Ruby, almost everything is an object. You create a generic object withobj = Object.new. You then interact with it by sending messages (calling methods) to perform work or provide information.What does it mean to “send a message” to an object?
Sending a message is calling a method on a receiver using the dot operator:receiver.message. The object on the left is the receiver; the name on the right is usually a method. If no such method exists, Ruby raises a NoMethodError.How do I define a method for a single object (a singleton method)?
You can add behavior to just one object with syntax likedef obj.talk; puts "Hi"; end. Now only that object responds to talk. Ruby also supports “endless” method definitions for single-expression bodies, for example def obj.c2f(c) = c * 9.0 / 5 + 32.What’s the difference between parameters and arguments, and are parentheses required?
Parameters are the named variables in a method definition; arguments are the values you pass when calling the method. Parentheses are often optional in Ruby (both in definitions and calls), but using them improves clarity—especially in chained calls or when parsing could be ambiguous.How is a method’s return value determined, and when should I use return?
A method returns the value of its last evaluated expression. Thereturn keyword is optional but useful for early exits or when returning multiple values (e.g., return a, b). Even an empty method body returns nil.What kinds of method arguments can I use, and in what order?
Ruby supports required arguments, default-valued (optional) arguments, and variable-length arguments via the splat (*args). Required parameters can appear on either end; optional/defaulted and splat parameters go in the middle. You can’t place a splat parameter before a default-valued parameter (e.g., def m(x, *y, z=1) is invalid).How can I check what an object can do and safely call methods by name?
Userespond_to?(:method_name) to ask an object if it handles a message. To invoke a method dynamically, use public_send (preferred for safety) or __send__/send: obj.public_send(name). Always validate or allowlist user-provided method names before calling them.What is object_id and how does it relate to equality?
object_id returns a unique identifier for an object’s identity. Two objects can be “equal” in value (==) yet be different objects with different IDs (e.g., two distinct strings with the same content). Use equal? (or comparing object_id) to test identity; use == to test value equality.How do local variable scope and bareword resolution work?
Local variables are scoped to their defining context (e.g., a method) and the same name can be reused in different scopes without conflict. When Ruby sees a bareword, it classifies it as a keyword, a local variable (if assigned), or a method call (especially if followed by parentheses). If Ruby can’t resolve it as a local variable or method, it raises aNameError.What are object references, and how do dup, clone, and freeze affect mutation?
Variables (except for immediate values like small integers, symbols,true/false/nil) hold references to objects. Assigning one variable to another copies the reference, so in-place changes (e.g., str.replace) are visible through all references. Use dup to pass a shallow copy, clone to copy including frozen state, and freeze to prevent further mutation (note that freezing a collection doesn’t freeze its elements).
The Well-Grounded Rubyist, Fourth Edition ebook for free