There's a lot of similarity between Ruby and Java by virtue of them being object-oriented, but their family tree is different. Ruby leans very heavily on Smalltalk while Java inherits from the C++ school of thinking.
The difference here is that Ruby's concept of public/private/protected is a lot weaker, they're more suggestions than rules, and things like static methods or constants are more of a pattern than a construct in the language.
Global variables are frowned on quite heavily, they can cause chaos if used liberally. The Ruby way is to namespace things:
$ugly_global = 0 # Not recommended, could conflict with other code
# Ownership of this variable isn't made clear.
$ugly_global += 1 # Works, but again, it's without context.
module UglyCounter # Defines a module/namespace to live in
def self.current # Defines a clear interface to this value
@counter ||= 0 # Initializes a local instance variable
end
def self.current=(v) # Allow modification of this value
@counter = v.to_i # A chance to perform any casting/cleaning
end
end
UglyCounter.current += 1 # Modifies the state of a variable, but
# the context is made clear.
Even a thin layer like this module gives you the ability to intercept read/write operations from this variable and alter the behaviour. Maybe you want to default to a particular value or convert values into a normalized form. With a bare global you have to repeat this code everywhere. Here you can consolidate it.
Class variables are a whole different thing. They're also best avoided because sharing data between the class and instances of this class can be messy. They're two different contexts and that separation should be respected.
class MessyClass
@@shared = 0
def counter
@@shared
end
def counter=(v)
@@shared = v
end
end
This is a pretty rough take on how to use a shared class-level instance variable. The problem here is each instance is directly modifying it, bypassing the class context, which means the class is helpless. This is fundamentally rude, the instance is over-extending its authority. A better approach is this:
class CleanerClass
def self.counter
@counter ||= 0
end
def self.counter=(v)
@counter = v.to_i
end
# These are reduced to simple bridge methods, nothing more. Because
# they simply forward calls there's no breach of authority.
def counter
self.class.counter
end
def counter=(v)
self.class.counter = v
end
end
In many languages a static class method becomes available in the scope of an instance automatically, but this is not the case in Ruby. You must write bridge/proxy/delegate methods, the terminology here varying depending on what you're used to.