Ruby Flashcards

1
Q

Singleton

A

Ensures that only one instance of Class can be created.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is the difference between a block, lambda, and proc

A

lambda and procs are objects, block is not.

lambda’s return does not effect the output when called. procs can.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Metaprogramming: Class Instance Variables

A

Inside a method, we can set an instance variable of the current object. This is what we do inside the initialize instance method.

When an instance variable is stored on a class, it is sometimes called a class instance variable. Don’t let the name wow you though; we’re just using a typical instance variable. This is similar to how class methods are merely methods that are called on a Class object.

However, class instance variables don’t interact very nicely with inheritance.

Class variables (not class instance variables) are shared between super-class and subclass. Let’s see this:

class Dog
  def self.all
    @@dogs ||= []
  end
  def initialize(name)
    @name = name
self.class.all << self   end end
class Husky < Dog
end

h = Husky.new(“Rex”)

Dog.all # => #

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Why should we avoid global variables?

A

The reason is that since global variables live outside any class, they aren’t very object oriented. Data is normally stored in one of two places:

Inside an object (instance, class instance, and class variables)
Inside a local variable; the local variable lives as long as the current method call.
If you need to access an object inside a method, it is typical to pass the object into the method. If you need to return a result from a method, it is typical to use return to pass it back. There is seldom a reason to store things globally.

There are occasionally exceptions: sometimes an object will be useful throughout your entire program, in which case you may want to make it globally accessible. One classic example is the $stdin and $stdout variables, which contain File objects (technically, IO objects, but they’re very similar) that you can use to read/write to the user.

Here’s how puts and gets are defined:

def puts(*args)
  $stdout.puts(*args)
end

def gets(args)
$stdin.gets(
args)
end
This eliminates most of the need to use these variables explicitly. However, say you wanted to write your output differently depending on whether the user was reading your output in a terminal or dumping your output to a file. In Bash, they can specify this by either:

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is Reflection?

A

The ability for a program to examine itself.
EX:
obj = Object.new
obj.methods
=> [:nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, …]
Object#methods returns an array of symbols, each the name of a method that can be sent to the object. This is helpful for debugging, but not super useful in production code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Metaprogramming: What is send?

A

“send” sends a message to an object instance and its ancestors in class hierarchy until some method reacts (because its name matches the first argument).

Practically speaking, those lines are equivalent:

1.send ‘+’, 2
1.+(2)
1 + 2
Note that send bypasses visibility checks, so that you can call private methods, too (useful for unit testing).

If there is really no variable before send, that means that the global Object is used:

send :to_s # “main”
send :class # Object

When is something like send useful? Why not just call the method the normal way? Well, using send lets us write methods like this:

def do_three_times(object, method_name)
  3.times { object.send(method_name) }
end
class Dog
  def bark
    puts "Woof"
  end
end
dog = Dog.new
do_three_times(dog, :bark)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Metaprogramming: What is define_method?

A

Defines an instance method in the receiver. The method parameter can be a Proc, a Method or an UnboundMethod object. If a block is specified, it is used as the method body. This block is evaluated using instance_eval, a point that is tricky to demonstrate because define_method is private. (This is why we resort to the send hack in this example.)

class Dog
  # defines a class method that will define more methods; this is
  # called a **macro**.
  def self.makes_sound(name)
    define_method(name) { puts "#{name}!" }
  end

makes_sound(:woof)
makes_sound(:bark)
makes_sound(:grr)
end

dog = Dog.new

dog. woof
dog. bark
dog. grr

common examples:
We don’t write macros every single day, but they are frequently quite useful. Some of the most famous macro methods are:

attr_accessor: defines getter/setter methods given an instance variable name.
belongs_to/has_many: defines a method to perform a SQL query to fetch associated objects.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Metaprogramming: What is method_missing?

A

When a method is called on an object, Ruby first looks for an existing method with that name. If no such method exists, then it calls the Object#method_missing method. It passes the method name (as a symbol) and any arguments to #method_missing.

The default version simply raises an exception about the missing method, but you may override #method_missing for your own purposes:

class T
  def method_missing(*args)
    p args
  end
end
T.new.adfasdfa(:a, :b, :c) # => [:adfasdfa, :a, :b, :c]
Here's a simple example:

class Cat
def say(anything)
puts anything
end

  def method_missing(method_name)
    method_name = method_name.to_s
    if method_name.start_with?("say_")
      text = method_name[("say_".length)..-1]
      say(text)
    else
      # do the usual thing when a method is missing (i.e., raise an
      # error)
      super
    end
  end
end

earl = Cat.new
earl.say_hello # puts “hello”
earl.say_goodbye # puts “goodbye”
Using method_missing, we are able to “define” an infinite number of methods; we allow the user to call any method prefixed say_ on a Cat. This is very powerful; it isn’t possible to do this using define_method itself.

However, overriding method_missing can result in difficult to understand/debug to code, and should not be your first resort when attempting metaprogramming. Only if you want this infinite expressability should you use method_missing; prefer a macro if the user just wants to define a small set of methods.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Metaprogramming: What are dynamic finders?

A

An Advanced Example: Dynamic Finders
What if we overrode #method_missing in ActiveRecord::Base to work for #find_by_* methods, so we could do the following:

User.find_by_first_name_and_last_name(“Ned”, “Ruggeri”)
User.find_by_username_and_state(“ruggeri”, “California”)
We could do this by parsing the “missing” method name and combining the column names (separated by ands) with the given arguments. It might look something like this:

class ActiveRecord::Base
  def method_missing(method_name, *args)
    method_name = method_name.to_s
    if method_name.start_with?("find_by_")
      # attributes_string is, e.g., "first_name_and_last_name"
      attributes_string = method_name[("find_by_".length)..-1]
      # attribute_names is, e.g., ["first_name", "last_name"]
      attribute_names = attributes_string.split("_and_")
  unless attribute_names.length == args.length
    raise "unexpected # of arguments"
  end

  search_conditions = {}
  attribute_names.length.times do |i|
    search_conditions[attribute_names[i]] = args[i]
  end

  # Imagine search takes a hash of search conditions and finds
  # objects with the given properties.
  self.search(search_conditions)
else
  # complain about the missing method
  super
end   end end NB: Dynamic finders were actually a feature of Rails until just recently. Rails 4.2 deprecated (supported, but didn't recommend) dynamic finders, and as of Rails 5, they are no longer supported. Although, they are quite handy, they tend to lead to overly verbose code and are not very performant. For these reasons we also recommend against using them. Check out this blog post if you'd like to learn more.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Classes

A

Classes are types of Modules (not important), which are Objects. In Ruby everything is an Object, even Classes!

To summarize: Object is of type Class, which is a subclass of Object itself. Whoa!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How would we create a hand rolled attr_accessor?

A
class AttrAccessorObject
  def self.my_attr_accessor(*names)
    names.each do |name|
      define_method(name) do
        instance_variable_get("@#{name}")
      end
  define_method("#{name}=") do |value|
    instance_variable_set("@#{name}", value)
  end
end   end end
How well did you know this?
1
Not at all
2
3
4
5
Perfectly