Ruby Notes
Objects
- objects are collections of instance variables and a link to their class
Classes
- Classes are instances of Class which is a subclass of Module
- CamelCased
Instance Variables
- Objects of the same class can have different sets of instance variables as they only exist upon assignment
Method calls
- The object that the method is called on is referred to as the reciever
- “one step to the right and then up” rule, go over to the right (into the object’s class) and then up the ancestery chain looking for the method
- To get a Class’s ancestery chain do:
MyClass.ancestors
- Modules are above the including class in the ancestery chain
- self starts as “main”. When a method is called on an object that object becomes self. From that point forward, any method call on a different object results in transfer of self to that other object.
- private methods can only be called by an implicit reciever
#This will fail:
class MyClass
def test_private()
self.tested()
end
private
def tested
puts "tested!"
end
end
MyClass.new.test_private
#This will work:
class MyClass
def test_private()
tested()
end
private
def tested
puts "tested!"
end
end
MyClass.new.test_private
Bindings
Bindings are essentially scopes without code. They are packaged scopes that you can be used with eval later on to evaluate code within a given context. Example:
class BinderTest
def this_is_a_binding_method()
@insider_variable = 4
binding
end
end
bound = BinderTest.new.this_is_a_binding_method()
eval "puts 2 + @insider_variable", bound
#=> 6
TOPLEVEL_BINDING
allows you to access the top-level scope from anywhere.
Tainted Strings and Safe Levels
In Ruby, tainted strings are those that Ruby marks as coming from an external source (not clear on how it makes this designation). Calling tainted? will allow you to determine if an object is from or mixed with an external source. This helps when deciding on whether to use eval() on a string. Further, setting the ruby value $SAFE sets the safe level, which allows or disallows certain operations. The range is 0..4 and anything other than 0 disallows evaluating tainted strings.
Singleton Methods
Singleton methods are those which are defined on a single object:
class TestSingle
end
object = TestSingle.new
def object.singleton_method
puts "method on a single object"
end
object.singleton_method #=> "method on a single object"
TestSingle.respond_to? :singleton_method #=> false
Class methods are a type of singleton object. When defining a class method, you are actual using a self to refrence the Class object you are working on.
class ClassMethods
def self.this_is_a_class_method
"class method"
end
end
def ClassMethod.this_is_another_class_method
"defined similar to a more singleton looking way"
end
Ghost Method
class GhostMethod
def method_missing(name, *args)
puts name.capitalize
end
end
Pattern Dispatch
Call methods based on their name
#Call methods in object that start with "test"
object.methods.each do |method|
object.send(method) if method.to_s =~ /^test/
end
Dynamic Method
Dynamically create methods at runtime
class Empty
end
Empty.class_eval do
define_method :method_name do
puts "This method was defined at runtime"
end
end
object = Empty.new
object.method_name # => "This method was defined at runtime"
Dynamic Proxy
Dynamic Proxies (e.g. ActiveRecord) forwards [ghost method][3] calls to another object (e.g. a database). Be mindful of:
- Name collisions with real methods. Use either a [blank slate][4] or make the class inherit from BasicObject.
- Infinite loops from missing method bugs within the patched missing_method
- Use “super” to call Object’s method_missing if your wrapped object doesn’t respond to your method name.
class DP
def initialize(database)
@database = database
end
def method_missing(name, *args)
super if !@database.respond_to?("get_#{name}")
info = @database.send("get_#{name}")
end
end
Blank slate
remove methods from Object to prevent method name collisions
class BlankSlate
instance_methods.each do |m|
undef_method m unless m.to_s /^method_missing$|^respond_to\?$|^__/
end
end