Reading notes from the fifth chapter (The default object (self), scope, and visibility) of The Well-Grounded Rubyist by David A. Black.
Self
puts "Top Level"
puts "self is #{self}"
class C
puts "Class definition block:"
puts "self is #{self}"
def self.x
puts "Class method x of class C"
puts "self is #{self}"
end
def m
puts "Instance method m of class C:"
puts "self is #{self}"
end
end
C.x
c = C.new
c.m
Output:
Top Level
self is main
Class definition block:
self is C
Class method x of class C
self is C
Instance method m of class C:
self is #<C:0x6172c8>
Note: #<C:0x6172c8> is the hexadecimal number representing the memory-location reference of the object instance.
Implicit self
class Person
attr_accessor :first_name, :middle_name, :last_name
def whole_name
n = first_name + " "
n << "#{middle_name} " if middle_name
n << last_name
end
end
tbf = Person.new
tbf.first_name = "The"
tbf.last_name = "Frog"
puts "Name: #{tbf.whole_name}"
tbf.middle_name = "Boolean"
puts "Full Name: #{tbf.whole_name}"
Output:
Name: The Frog
Full Name: The Boolean Frog
Global variables
$gvar = "I'm global!"
class C
def print_global_var
puts $gvar
end
end
c = C.new
c.print_global_var
Global variables start with $.
Built-in global variables
The friendly names for the built-in global variables can be found in the English.rb file (in the “lib\ruby\1.9.1” folder of the directory where Ruby is installed).
Some examples together with the explanation found in the English.rb file:
|
$!
|
The exception object passed to raise.
|
$ERROR_INFO
|
|
$@
|
The stack backtrace generated by the last exception.
|
$ERROR_POSITION
|
|
$;
|
The default separator pattern used by String.split.
|
$FS or $FIELD_SEPARATOR
|
|
$,
|
The separator string output between the parameters to methods such as Kernel.print and Array.join. Defaults to nil, which adds no text.
|
$OFS
$OUTPUT_FIELD_SEPARATOR
|
|
$/
|
The input record separator (newline by default). This is the value that routines such as Kernel.gets use to determine record boundaries. If set to nil, gets will read the entire file.
|
$RS
$INPUT_RECORD_SEPARATOR
|
|
$\
|
The string appended to the output of every call to methods such as Kernel.print and IO.write. The default value is nil.
|
$ORS
$OUTPUT_RECORD_SEPARATOR
|
|
$.
|
The number of the last line read from the current input file.
|
$INPUT_LINE_NUMBER or $NR
|
|
$_
|
The last line read by Kernel.gets or Kernel.readline. Many string-related functions in the Kernel module operate on $_ by default. The variable is local to the current scope.
|
$LAST_READ_LINE
|
|
$>
|
The destination of output for Kernel.print and Kernel.printf. The default value is $stdout.
|
$DEFAULT_OUTPUT
|
|
$<
|
An object that provides access to the concatenation of the contents of all the files given as command-line arguments.
|
$DEFAULT_INPUT
|
|
$$
|
The process number of the program being executed. Read only.
|
$PID or $PROCESS_ID
|
|
$?
|
The exit status of the last child process to terminate. Read only.
|
$CHILD_STATUS
|
|
$~
|
A MatchData object that encapsulates the results of a successful pattern match. The variables $&, $`, $', and $1 to $9 are all derived from $~. Assigning to $~ changes the values of these derived variables. This variable is local to the current scope.
|
$LAST_MATCH_INFO
|
|
$*
|
An array of strings containing the command-line options from the invocation of the program. Options used by the Ruby interpreter will have been removed. Read only. Also known simply as ARGV.
|
$ARGV
|
|
$&
|
The string matched by the last successful pattern match. This variable is local to the current scope. Read only.
|
$MATCH
|
|
$`
|
The string preceding the match in the last successful pattern match. This variable is local to the current scope. Read only.
|
$PREMATCH
|
|
$'
|
The string following the match in the last successful pattern match. This variable is local to the current scope. Read only.
|
$POSTMATCH
|
|
$+
|
The contents of the highest-numbered group matched in the last successful pattern match. Thus, in "cat" =~ /(c|a)(t|z)/, $+ will be set to "t". This variable is local to the current scope. Read only.
|
$LAST_PAREN_MATCH
|
Constant Lookup
Relative Path
module M
class C
class D
module N
X = 1
end
end
puts D::N::X
end
end
Constant Path
module S
# Name clashes with name of built-in String class
class String
attr_accessor :count
def initialize(count)
@count = count
end
end
# Use :: to refer to the top level (in this case the built-in) String type.
puts ::String.new("TEST")
end
str = S::String.new(10)
puts str.count
Output:
TEST
10
Class variables
Class variables start with @@ and are only visible to the class itself and instances of the class.
Example:
class Population
@@countries = []
@@count = {} # key-value pair dictionary
attr_reader :country
def self.total_count
@@total_count ||= 0
end
def self.total_count= (n)
@total_count = n
end
def self.add_country(country)
unless @@countries.include?(country)
@@countries << country
@@count[country] = 0
end
end
def initialize(country)
if @@countries.include?(country)
puts "Incrementing #{country} population..."
@country = country
@@count[country] += 1
self.class.total_count += 1
else
raise "No such country as '#{country}'"
end
end
def find_countrymen
@@count[self.country]
end
end
Population.add_country("UK")
Population.add_country("France")
u = Population.new("UK")
f = Population.new("France")
u2 = Population.new("UK")
puts "Counting population of #{u2.country} (same country as u2)..."
puts "There are #{u2.find_countrymen} people."
puts "Counting total population..."
puts "There are #{Population.total_count} people."
x = Population.new("Lalaland")
Output:
Incrementing France population...
Incrementing UK population...
Counting population of UK (same country as u2)...
There are 2 people.
Counting total population...
There are 3 people.
: No such country as 'Lalaland' (RuntimeError)
The code snippet above is effectively similar to Listing 5.7 in The Well-Grounded Rubyist with only the class and method names changed.
Private Methods
To make a method private, simply mark it as private.
class Dictionary
attr_reader :translation
def translation= (translation)
@translation = translation
end
def lookup(word)
translate(word)
end
def translate(word)
if word == "Hello"
self.translation = "Bonjour"
else
@translation = "Not in the dictionary"
end
end
private :translation=, :translate
end
dictionary = Dictionary.new
dictionary.lookup("Hello")
puts "Hello is #{dictionary.translation}."
dictionary.lookup("Hola")
puts "Hola is #{dictionary.translation}."
Calling the private methods out-of scope results in a fatal error:
dictionary.translate("Hello")
Output:
private method `translate' called for #<Dictionary:0x436e90> (NoMethodError)
dictionary.translation = "TEST"
Output:
private method `translation=' called for #<Dictionary:0x24b6e50> (NoMethodError)
Protected Methods
To make a method protected, simply mark it as protected.
Note that a protected method can be called by the object itself and also by another instance of the same class or subclass.
class Person
def initialize(age)
@age = age
end
def age
@age
end
def compare(other)
if other.age > age
puts "The other person is older."
else
puts "The other person is the same age or younger."
end
end
protected :age
end
p1 = Person.new(20)
p2 = Person.new(50)
p1.compare(p2)
Kernel built-in methods
ruby -e 'print Kernel.private_instance_methods(false).sort'
Output:
[:Array, :Complex, :Float, :Integer, :Rational, :String, :__callee__, :__method__, :`, :abort, :at_exit, :autoload, :autoload?, :binding, :block_given?, :caller, :catch, :eval, :exec, :exit, :exit!, :fail, :fork, :format, :gem, :gem_original_require, :gets, :global_variables, :initialize_copy, :iterator?, :lambda, :load, :local_variables, :loop, :open, :p, :print, :printf, :proc, :putc, :puts, :raise, :rand, :readline, :readlines, :remove_instance_variable, :require, :require_relative, :select, :set_trace_func, :sleep, :spawn, :sprintf, :srand, :syscall, :system, :test, :throw, :trace_var, :trap, :untrace_var, :warn]