If you have something like

  class Foo
    # …
    # …
    class Bar
      # …
      def voice
    end # "private" class Foo::Bar
  end # ordinary class Foo

you don’t have a private class. Any code that can see Foo can do something like

[1] pry(main)> require 'foo'
=> true
[2] pry(main)> Foo::Bar.new.voice
=> "quack"

You haven’t really hidden anything at all. All that you’ve done, by nesting Bar within Foo and sticking that private declaration above it, is telling the next poor soul to come read your code that Bar is intended as an internal implementation detail of Foo and should not be used directly.

You, by going to that trouble, have given yourself the responsibility to ensure that knowledge of Foo::Bar never leaks out of Foo (e.g., by way of a method return value). I don’t always (often?) agree with Joel Spolsky, but The Law of Leaky Abstractions, nearly twelve years on, is a classic.

Jeff Dickey

Software and Web developer. Tamer of deadlines. Enchanter of stakeholders.