Skip to content

Instantly share code, notes, and snippets.

@elgalu
Created December 6, 2012 04:00
Show Gist options
  • Save elgalu/4221679 to your computer and use it in GitHub Desktop.
Save elgalu/4221679 to your computer and use it in GitHub Desktop.
My quiz on: Metaprogramming Ruby: Program Like the Ruby Pros by Paolo Perrotta
- Returns?
module Module
def const_missing(name)
"sorry i don't have #{name} yet"
end
end
Untitled #=> ?
Monkeys #=> ?
=>
You get `TypeError: Module is not a module` before reaching Untitled code
Because you must use `class Module` to open the class
- How to?
cad = 'stuff'
class << cad
def uno() 'uno' end
def self.dos() 'dos' end
end
??? #=> 'uno'
??? #=> 'dos'
=>
cad.uno #=> 'uno'
cad.singleton_class.dos #=> 'dos'
- Diffs bt `undef` `undef_method` `remove_method`
=>
undef
is a keyword
accepts method names or symbols or strings
available for any object
can not be overridden
undef_method
defined for Module
accepts symbols or strings
prevent any calls to the method affecting the ancestor chain
remove_method
same as undef_method but only removes it from current self
allowing the method to be found on the ancestors if defined
- Show the file and line number where some method is defined
=>
method(:irb_exit).source_location # 1.9
#=> ["c:/.../1.9.1/irb/extend-command.rb", 22]
- Returns?
def leo(uno, dos=2, *params)
'hola'
end
method(:leo).parameters #=> ?
=>
[[:req, :uno], [:opt, :dos], [:rest, :params]]
- Diff bt is_a? and instance_of?
=>
obj.instance_of?(klass)
returns true if obj is a instance of klass and klass only
obj.is_a?(klass) or obj.kind_of?(klass)
same and also true if obj is an instance of one of klass ascendants
- Returns?
module Mod
def tres() end
end
class B
def B.cuatro() end
end
a = B.new
def a.uno() end
class << a
include Mod
def dos()
end
end
B.singleton_methods #=> ?
a.singleton_methods(false) #=> ?
a.singleton_methods #=> ?
=>
# singleton_methods(all=true)
# Public and protected. all: include methods in modules included in obj
B.singleton_methods #=> [:cuatro]
a.singleton_methods(false) #=> [:uno, :dos]
a.singleton_methods #=> [:uno, :dos, :tres]
- Returns?
cad1, cad2 = 'abc', 'leo'
cad1.instance_eval { def rev; reverse; end }
cad1.rev #=> ?
cad2.rev #=> ?
=>
cad1.rev #=> "cba"
cad2.rev #=> NoMethodError
# instance_eval makes current self cad1 and current class cad1.singleton_class
# Given `def` works on current class and creates instance methods
# And given the instance methods of cad1 singleton class are cad1 methods
# Then cad1.rev is possible
- Returns?
Math.singleton_class #=> ?
Mike = Module.new
Mike.singleton_class #=> ?
=>
Math.singleton_class #=> #<Class:Math>
Mike.singleton_class #=> #<Class:Mike>
- Returns?
class Module
def self.const_missing(name)
"sorry i don't have #{name} yet"
end
end
Untitled #=> ?
Monkeys #=> ?
=>
Untitled #=> NameError: uninitialized constant Untitled
Monkeys #=> NameError: uninitialized constant Monkeys
# In this case your const_missing method is never executed
# because `self.` is not meant to be used here.
# Untitled & Monkey are instances of Module so re-define const_missing as a Module instance method
- Returns?
class A
def self.mattr; self; end
mattr
end #=> ?
class B < A
mattr
end #=> ?
=>
class A ... end #=> A
class B ... end #=> B
# remember B is not an instance of A, is an instance of Class
# that inherites from A
- Where is extend() defined? describe what it does.
=>
Object#extend(*mods) <public>
Adds to obj the instance methods from each module
It is a shortcut for opening the singleton class and using `include` there
- Returns?
z = Object.new
class << z
instance_eval do
def foo() "test" end
end
end
z.foo #=> ?
=>
NoMethodError: undefined method `foo`
z.singleton_methods #=> []
`foo` is defined as an singleton method of the singleton class of `z`
z.singleton_class.singleton_methods #=> [:foo]
z.singleton_class.foo #=> "test"
- By whom can protected methods be called?
=>
# Protected methods can only be called if the the caller of the method
# (the receiver) is of the same class (or subclass) of that method.
- Which are the 2/3/4 most common ways to generate methods dynamically?
=>
def meth() "hello" end
Class#define_method(name, *params) {proc}
Class#define_method(name, method)
# The method parameter can be a Proc, a Method or an UnboundMethod object.
thing.class.send(:define_method, name) do |*args| {proc}
class_eval { def meth; "hello"; end }
- What the `ancestors` method does? Where is defined?
=>
Module#ancestors returns all the modules where methods called will be searched for,
in that order [Module1, Module2, ..., Object, Kernel, BasicObject]
starting first place with the module//class in question
- Given:
module Mod
def mono() "works" end
end
class Foo
include Mod
end
class Bar
extend Mod
end
# Returns?
Foo.new.mono #=> ?
Foo.mono #=> ?
Bar.new.mono #=> ?
Bar.mono #=> ?
=>
Foo.new.mono #=> "works"
Foo.mono #=> NoMethodError `mono` for Foo:Class
Bar.new.mono #=> NoMethodError `mono` for #<Bar:0x33>
Bar.mono #=> "works"
- Get the list of class variables and the class instance variables.
Where are the methods defined?
How the result look in 1.8 vs 1.9?
=>
Object#instance_variables
Module#class_variables
sample_output #=> [:@ivar] / [:@@cvar]
Diff bt 1.8 and 1.9 is that 1.8 returns strings instead of symbols
- What techniques can be used to call private methods?
=>
c = "stuff"
c.upcase #=> "STUFF"
c.singleton_class.send :private, :upcase
=> #<Class:#<String:0x2a1a250>>
c.upcase #=> NoMethodError: private method `upcase`
# Besides `send` these also works:
c.instance_eval { upcase }
c.instance_eval "upcase"
- What are the things that can change the value of self?
=>
# An explicit reciever
`class` keyword
`def` keyword
Object#instance_eval
Module#class_eval
- Is it true that ruby creates a singleton class to store the method in this example?
class Foo
def self.meth
"things"
end
end
=>
Yes, class methods are actually stored as instance methods of the class singleton
- Modules can be used in many ways or purposes, describe them.
=>
+ As namespace constants organization for classes or global methods
+ As collections of methods to be mixed in later using include//extend
+ As scope separators for security reasons
- Returns?
arr = %w(c b a)
module Sor
def sor
self.sort
end
end
# What's the diff bt
arr.extend Sor
# vs
class << arr
include Sor
end
=>
No diff, Object#extend is actually a shortcut for doing
an include() within the singleton of the object in question
This technique is called a Class Extension
- Diff bt class_eval and instance_eval
=>
class_eval only works for Class types and
when `def` is evaluated in this context, instance methods are created
instance_eval works for any object and
when used on a Class//Module `def` defines class methods
- Returns?
class Module
def const_missing(name)
if name.to_s =~ /^U/
"starts with U"
else
super(name)
end
end
end
Untitled #=> ?
Monkeys #=> ?
=>
Untitled #=> "starts with U"
Monkeys #=> NoMethodError: super: no superclass method `const_missing' for Object:Class
- Returns?
class Object
def meth() self end
end
Object.meth #=> ?
Module.meth #=> ?
Class.meth #=> ?
(A = Class.new).meth #=> ?
A.new.meth #=> ?
=>
Object.meth #=> Object
Module.meth #=> Module
Class.meth #=> Class
(A = Class.new).meth #=> A
A.new.meth #=> #<A:0x01>
- Describe `super` behaviour when called without arguments
=>
If called without arguments it invokes the ancestor method
with the arguments received by the current method.
Modifications made locally to the params will be sent.
To explicitly invoke the ancestor method without any arguments use super()
- How to delete a variable or constant?
=>
private Object::remove_const(*syms)
public Object#remove_instance_variable(*syms)
# Samples:
Object.send(:remove_const, :Foo)
remove_instance_variable :@name
var = nil # all you can do about scope variables
- Returns?
method(:test) #=> ?
Kernel.method(:test) #=> ?
=>
method(:test) #=> #<Method: Object(Kernel)#test>
Kernel.method(:test) #=> #<Method: Kernel.test>
- Define Object#tap to explain what it does
=>
# tap is used to split a call chain specially for debugging purposes
# or to get better error messages in cause of failure
class Object
def tap
yield self
self
end unless Object.respond_to?(tap)
end
- Returns?
class << Class
def mattr
self
end
end
Class.mattr #=> ?
class Test1
mattr
end #=> ?
=>
Class.mattr #=> Class
class Test1; mattr; end #=> NameError
# cause mattr() is a class method of Class, not an instance method of Class
- Non existing globals returns?
$asfdasfd #=> ?
=>
nil
- Returns?
"cad".instance_methods
=>
NoMethodError: undefined `instance_methods` for "cad":String
Because is Module#instance_methods and only mods and classes can have instance methods
While objects like "cad" have public_methods() or its alias methods()
- Returns?
def meth
x = 1
yield 2
end
meth {|y| x + y} #=? ?
=>
NameError cause it will look for `x` where the Proc was defined
not where the Proc is called (within meth)
The block creates a closure where is defined, not where is yielded
class Module
def meth() self end
end
Object.meth #=> ?
Module.meth #=> ?
Class.meth #=> ?
(A = Class.new).meth #=> ?
A.new.meth #=> ?
=>
Object.meth #=> Object
Module.meth #=> Module
Class.meth #=> Class
(A = Class.new).meth #=> A
A.new.meth #=> NoMethodError cause meth is available for classes only
- Returns?
Module.new
=>
#<Module#0x01>
- Give a sample of a memoized accessor
=>
def account
@account ||= Account.find(@data[:account_id])
end
- Find a better way to write this:
def foo
begin
do_it
rescue
handle_it
end
end
=>
# Every method in Ruby is implicitly a begin block
def foo
do_it
rescue
handle_it
end
- What is TOPLEVEL_BINDING ?
=>
Is a Ruby constant of the top-level scope bindings
eval "self", TOPLEVEL_BINDING #=> main
- How can you tell which classes or modules where added after doing some require?
=>
# With Module.constants you can get the ones defined in the system
before = Module.constants.dup
require 'securerandom'
newones = Module.constants - before
#=> [:OpenSSL, :Digest, :StringIO, :Fcntl, :SecureRandom]
- Returns?
class Class
def meth() self end
end
Object.meth #=> Object
Module.meth #=> Module
Class.meth #=> Class
(A = Class.new).meth #=> A
A.new.meth #=> NoMethodError
- Implement Symbol#to_proc and also:
:inspect.to_proc.call(self) #=> ?
class Fixnum
def printmyself()
print "#{self} "
end
end
3.times &(:printmyself.to_proc) #=> ?
[1, 2, 5].inject(0) {|memo, obj| memo + obj } #=> ?
# Improve that last one using Symbol#to_proc
=>
# Is a proc that takes an argument and calls the method (named the symbol) on the argument
:inspect.to_proc.call(self) #=> "main" , i.e. self.inspect #=> "main"
class Symbol
def to_proc
Proc.new {|x| x.send(self) }
end
end
# Remember that with `&` on a proc you can convert the proc into a block:
3.times &(:printmyself.to_proc) #=> prints: 0 1 2 returns: 3
# Note the & operator will auto convert that obj to a Proc by calling to_proc
3.times &(:printmyself)
# Samea as
3.times &:printmyself
# And thanks to all that you can do:
%w(el ga lu).map(&:upcase) #=> ["EL", "GA", "LU"]
# Symbol#to_proc also supports blocks with more than 1 argument, e.g. |memo, obj|
[1, 2, 5].inject(0, &:+) #=> 8
- Returns?
class MyClass
attr_accessor :my_attr
def initialize_attributes
my_attr = 10
end
end
obj = MyClass.new
obj.initialize_attributes
obj.my_attr #=> ?
=>
returns nil because my_attr looks like local-variable assignment
instead use self.my_attr or @my_attr
- Improve this code using a Nil Guard
class C
def initialize
@a = []
end
def elements
@a
end
end
=>
def elements
@a ||= []
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment