liveBook · Manning

BasicObject

As explained in The Well-Grounded Rubyist, Fourth Edition

A basic object is an instance of BasicObject with only the minimal set of methods provided by that class.

Try `BasicObject.new.methods` and you get a `NoMethodError`: unlike an ordinary `Object.new`, a basic object has no `methods` method. Even `p BasicObject.new` fails because the instance lacks `inspect`. BasicObject is Ruby’s nearly blank-slate class, intended for objects that need very little behavior of their own. section 2.3 section 3.5.3 section 13.3

BasicObject sits above Object at the top of the usual class ancestry chain. A new BasicObject instance has fewer than ten instance methods, compared with roughly sixty on a new Object instance; the counts can vary by Ruby release. To inspect that small method set, ask the class with `BasicObject.instance_methods(false)`, rather than asking an instance to list its methods. section 3.5.3 section 13.3

Why start with so little? Method lookup can climb through a class’s ancestors as far as BasicObject. Ordinary objects also gain many familiar methods through Object and its included Kernel module. Those inherited names may accidentally intercept a message that a domain-specific object meant to interpret itself. Subclassing BasicObject reduces such clashes; defining `method_missing` then lets the object assign meaning to messages it does not recognize. section 4.2.1 section 13.3.1

Turning calls into an indented list

A `Lister < BasicObject` can treat each missing method name as a list heading. Its `method_missing` appends the name, increases an indentation counter, yields to a supplied block for nested entries, then decreases the counter. Calls named `freeze`, `inspect`, `sleep`, and `print` can therefore become headings instead of invoking familiar object methods. This works precisely because a BasicObject instance does not already recognize those names. section 13.3.2

Listing 13.2 Lister class: Generating indented lists from a BasicObject subclass
class Lister < BasicObject
  attr_reader :list
  def initialize      1
    @list = ""
    @level = 0
  end
  def indent(string)         2
    " " * @level + string.to_s
  end
  def method_missing(m, &block)    3
    @list << indent(m) + ":"         4
    @list << "\n"
    @level += 2       5
    @list << indent(yield(self)) if block     6
    @level -= 2
    @list << "\n"
    return ""          7
  end
end

The complete Lister implementation shows how `method_missing` accumulates output and uses a block to control indentation. section 13.3.2

The blank slate has costs. Lister checks whether its captured block is present instead of calling `block_given?`, which BasicObject instances lack. It also returns an empty string from `method_missing` so nested calls do not append the accumulating list to itself. A larger example is the Builder XML-writing library: it turns missing method calls into XML tags, with blocks expressing nesting. BasicObject is useful for this kind of deliberately controlled message vocabulary, not something most classes need to inherit from. section 13.3.2 section 13.3.1 section 3.5.3

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Explains ancestry, sparse methods, and a worked subclass, including block and return-value pitfalls.
Examples
Uses failed method inspection, an XML-writing Builder example, and an indented-list subclass whose calls become headings.
What it assumes
Builds on Ruby classes, method calls, and blocks while demonstrating how a BasicObject subclass handles missing methods.
What you can do after
Build it from scratch: subclass BasicObject and route unmatched calls through method_missing to generate structured output.
How it connects
Connects BasicObject to inheritance, method lookup, Object, Kernel, and method_missing.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.