Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
A limited guide to intermediate and
advanced Ruby
- Vysakh Sreenivasan (vysakh0)
Variables store only
references to objects.
So, use dup or clone
scan & match
match returns the first match.
scan returns all matches
(g - global)
gsub and sub
>> "hello".sub('l', '*')
=> "he*lo"
>> "hello".gsub('l', '*')
=> "he**o"
(when working in irb or pry)
semicolon ;
[82] pry(main)> a = [1, 2, 3]
=> [1, 2, 3]
[83] pry(main)> a = [1, 2, 3] ;
[84] pry(main)>
Does not print output of the st...
Spaceship operator
<=>
a <=> b :=
if a < b then return -1
if a = b then return 0
if a > b then return 1
if a and b are not comparable then return...
[1,3,2] <=> [2,2,2]
- Ruby will start comparing each element of
both array from left hand side.
- 1 of left array is small...
case subsumption operator or case
equality operator
===
- "If I have a drawer labelled a would it
make sense to put b in that drawer?"
- The main usage for the === operator is in...
case a
when b
end
# Here b === a check is made in when
# not b == a
Diff between a == b and a === b
- (a == b) and (b == a) is always the same
- (a === b) and (b === a) is not always the
sam...
splat
Accept variable length arguments
Unwrap from array and pass as args
Coerce values into array
coerced = *"Hello World"
p coerced
# => ["Hello World"]
coerced = *nil
p coerced
# => []
coerced ...
Deconstruct array
data = [1, 2, 3, 4]
first, *rest = data
puts "#{first}, #{rest}"
# => 1, [2, 3, 4]
*list, last = data
pu...
Double Splat
Similar to splat but for hashes in arg list
def double_splat(**hash)
p hash
end
double_splat()
# => {}
double_splat(a: 1)
# => {:a => 1}
double_splat(a: 1, b: 2)
# =>...
def foo (args)
return args
end
h1 = { b: 2 }
h2 = { c: 3 }
foo(a: 1, **h1) # => {:a=>1, :b=>2}
foo(a: 1, **h1, **h2) # => ...
We just used double splat to capture all
keyword arguments
def join_array(arr, elements: , by_char: ‘,’)
arr.take(elements).join(by_char)
end
a = [20, 30, 10, 40]
# optional if ther...
Damn! lambda is not rhyming! :/
blocks, procs and lambdas
Just passing around a chunk of code
def parrot(&what_human_said)
puts “Hey, I’m gonna say what you said”
what_human_said.call
puts “Thank you. Have a nice day...
&what_human_said
makes passed block changed to proc
Sorta like a magic :)
Ruby also lets us do it implicitly
def parrot
puts “Hey, I’m gonna say what you said”
yield
puts “Thank you. Have a nice day”
end
parrot do
puts “I’m not Sir...
yield
- is not a method but a type.
- yield executes the block.
- faster than previous eg.
block_given? method of ruby
But, what is proc?
- an object
- with blocks of code
- bound to a set of local variables
lambda is just like proc but strict and nice
- lambda checks parameters passed to it
- lambda is not like that adamant chi...
Symbol#to_proc
odd = proc { |x| x.odd? }
=> #<Proc:0xb8c1c6d8>
odd.call(2)
=> false
odd.call(3)
=> true
odd = :odd?.to_proc
=> #<Proc:0xb8c1c6d8>
odd.call(2)
=> false
odd.call(3)
=> true
Both these are equivalent
:odd?.to_proc #==> &:odd?
proc { |x| x.odd? }
Also note, these are same
1 + 2
#=> 3
1.send(:+, 2)
#=> 3
And so, this works too(equivalence)
:odd?.to_proc
proc { |x| x.send(:odd?) }
And hence, these are same :)
[“ruby”, “rails”, “thor”].map do |x|
x.reverse
end
[“ruby”, “rails”, “thor”].map(&:reverse)
Proc=== is an alias to Proc.
call
mul_of_3 = proc { |num| num % 3 == 0 }
mul_of_3.call(30) #=> true
mul_of_3 === 30 #=> true
# And so,
case 30
when mul_of_3
puts “Yayyy”
end
#=> Yayyy
Proc curry
- A curried proc receives some arguments.
- If a sufficient number of arguments are
supplied, it passes the supplied argum...
multiple = proc { |x, y| x * y }
multiple.call(2, 3) #=> 6
# here x = 2, y = 3
curry_multiple = multiple.curry
#=> curried...
multiple_of_2 = curry_multiple.call(2)
# here x is 2, y is not yet passed
# when y is passed, the proc will
# get executed...
multiply = proc { |*args| args.reduce(:*) }
multiply_2_nums = multiply.curry(2)
twice= multiply_2_nums.call(2)
twice.call(...
methods
Assert if method exists
class Twitter
def tweet; end
end
t = Twitter.new
t.respond_to?(:tweet)
Twitter.method_defined?(:tweet)
making method object
def sum(a, b)
a + b
end
s = method(:sum)
s.methods # s is an object now :D
s.parameters
s.super_method
s.call(10, 20)
unbound method object
class Calc
def sum(a, b)
a + b
end
end
s = Calc.instance_method(:sum)
s.call(10, 20) # NoMethodError
s.bind(Calc.new).call...
def palindrome?
self.reverse == self
end
pal = Object.instance_method :palindrome?
=> #<UnboundMethod: Object#palindrome?>...
You can also invoke a method by
s.send(:sum, 10, 20)
eval “s.sum(1, 2)”
# eval is not recommended, never use
defining methods
(different way)
class Order
define_method :total_for |quantity|
10 * quantity
end
end
Order.new.total_for(20)
#=> 200
undefining methods
class Order
define_method :total_for |quantity|
10 * quantity
end
undef_method :total_for
#just unlinks but is in memory
e...
class Order
define_method :total_for |quantity|
10 * quantity
end
remove_method :total_for
#removes it totally
end
alias method
class Politics
def free_scheme
puts “Yo. Get lots of free stuff.”
end
alias_method :money_time, :free_scheme
end
Politics....
method_missing
(Do not try this at your home/code)
not found is not an option for you
Use it only when method
method curry
def multiple(x, y)
x * y
end
curry_multiple = method(:multiple).curry
#=> curried the multiple method, got proc
twice = cu...
Monkey patch
Open up classes and insert your own methods
class A
end
class A
def hello
“yolo”
end
end
class String
def palindrome?
self.reverse == self
end
end
# adds a method to the already existing String Class
Refinements
module Watson
refine String do
def palindrome?
self.reverse == self
end
end
end
“Ruby”.palindrome?
#=> NoMethodError: unde...
module Watson
p “RoR”.palindrome?
end
module Sherlock
using Watson
p “RoR”.palindrome?
end
Objects
inherits from the class “Object”
Every object in Ruby by default
class Foo
end
class Foo < Object
end
Both these classes are identical
Even class is an object
Foo.is_a?(Object)
Foo.new.is_a?(Object)
Both these are Objects
Ancestry
class Elizabeth1; end
class Victoria < Elizabeth1
end
class Elizabeth2 < Victoria
end
Who was Elizabeth1’s
ancestor?
May be just another
human?
Then who was human’s
ancestor?
Some ape, duh!
The APE is the BasicObject
In Ruby, human is Object
Who is this kernel?
And there are qualities that got mixed into you
See, you are human, not ape
that is mixed into the “Object” class
Kernel is a module
Ya, modules are part of
ancestors
Singleton methods
And how did you define on an object?
But only classes has methods
a singleton class(invisible to you) for the object
You are right. Ruby makes
just to hold object specific methods
have singleton classes not only objects
You know what, even classes
class God
def self.true_me
“:troll_face:”
end
end
God.singleton_class
God.singleton_methods
God.singleton_method(:true_me)...
singleton class for the class just to hold
So, ruby makes a
class specific methods ?
Foo and Foo.new are objects
Wait, I remember you saying
the class to hold the class specific methods
So, actually ruby is making a singleton class for
just like it does for objec...
invisible to the programmer.
AH! Yes! And The singleton class is typically
But you sorta see in one syntax, which is
class God
class << self
def self.true_me
“:troll_face:”
end
end
end
class << self is like class Singleton(self)
- You want to add a method just to a specific
object. (note: even class is an ...
class Human;end
matz = Human.new
class << matz
def write
puts “Writing the epic: Ruby”
end
end
matz.write
You can also define
Singleton methods by
class RubyLang; end
RubyLang.define_singleton_method(:minaswan) do
puts “Matz is nice and so we are nice”
end
RubyLang.min...
Ruby OO goodies
Yo = Class.new do
def ping
“hodor”
end
end
Yo.new.ping
A = Class.new
# proper class but..
a = Class.new
# an anonymous gen...
Struct is like class
with bundled accessor methods
Product = Struct.new(:name, :price)
pr = Product.new(“Book”, 20)
pr.name # attr_accessor out of box
pr.price = 10
pr.to_h ...
OpenStruct is like Struct
with more manipulation as if it is a hash
require ‘ostruct’
param = { name: “book”, price: 20 }
param_obj = OpenStruct.new(param)
param_obj.delivered = false
param_...
Delegator
Inherit it, and don’t write constructor as it
is already defined.
class CEO
attr_accessor :next_appointment
def fix_appointment(date)
next_appoinment = date
end
end
Ceo decides to hire a PA
and delegate some of her work to PA
require ‘delegate’
class CEO
attr_accessor :next_appointment
end
class PA < SimpleDelegator
def fix_appointment(date)
next...
elon_musk = CEO.new
elon_musk_pa = PA.new(elon_musk)
elon_musk_pa.fix_appointment(“7/6/2015”)
# you won’t know anything el...
Forwardable
require ‘forwardable’
class CEO
attr_accessor :availability, :office_mails
def phone_call
puts “Hi. How are you? How can I...
class PA
extend Forwardable
def_delegators :@ceo, :availability, :phone_call, :office_mails
def initialize(ceo)
@ceo = ceo...
jack_ma = CEO.new(“Jack Ma”)
jack_ma_pa = PA.new(jack_ma)
jack_ma_pa.phone_call do
puts “Hello, mr.jack ma.”
end
jack_ma_p...
Also look for other awesome classes
- Queue
- Stack
- Thread
- StringScanner
Manipulating variables
dynamically
class A
def initialize(foo)
@foo = foo
end
end
a = A.new (“cool”)
a.instance_variable_get “foo”
a.instance_variable_set :@...
class A
@@b = 10
end
A.class_variable_get “b”
A.class_variables
const_get
class A
PI = 3.14
end
A.const_get “PI” # also there is const_set
#only works with the classes not with objects
Eval
The evil }:-D
(Ruby will run this string )
eval “puts ‘hello world’ “
instance_eval
evaluates string/block of code in the
context of the object
class Subject
def initialize(name)
@name
end
end
maths = Subject.new(“Mathematics”)
maths.name #=> ERROR
maths.instance_ev...
# earlier we saw this code
class Human;end
matz = Human.new
class << matz
def write
puts “Writing the epic: Ruby”
end
end
...
# Can also be written as
class Human;end
matz = Human.new
matz.instance_eval do
def write
puts “Writing the epic: Ruby”
en...
Since class is also an object
we can use instance_eval on it.
# we earlier saw this
class RubyLang; end
RubyLang.define_singleton_method(:minaswan) do
puts “Matz is nice and so we are ...
# Also can be written as
class RubyLang; end
RubyLang.instance_eval do
puts “Matz is nice and so we are nice”
end
RubyLang...
class_eval
evaluates string/block of code in the
context of the class
class Person; end
Person.new.name #=> ERROR
Person.class_eval do
attr_accessor :name
def trumpet
puts “Me..me...me… #{name...
Modules
collection of methods and constants
module Mod
CONST = 1
def math
# ...
end
end
Mod.class #=> Module
Mod.constants #=> [:CONST]
Mod.instance_methods #=> [:mat...
that you can use across multiple classes
Modules are about providing methods
- extend
- include
- prepend
- using (refinements)
We already saw about ‘using’
module Hipster
def flame_wars
puts “Yo, this lang is better, that lang is worse”
end
end
class Programmer
end
me = Program...
Can you guess where the
module methods were inserted for object?
extend just did that for us :)
To the singleton class of the object.
module Hipster
def flame_wars
puts “Yo, this lang is better, that lang is worse”
end
end
class HipsterProgrammer
extend Hi...
Yes. We inserted module methods to
the singleton class of class by using extend
What if we want to just insert
module methods to the class?
module Hipster
def flame_wars
puts “Yo, this lang is better, that lang is worse”
end
end
class HipsterProgrammer
include H...
class HipsterProgrammer
include Hipster
end
HipsterProgrammer.ancestors
# => [HipsterProgrammer, Hipster, …]
# NOTE: You a...
module Validations
def save
puts "validating model"
end
end
class Model
include Validations
def save
super
puts "saving mo...
m = Model.new
m.save
#=> validating model
#=> saving model
prepend is just like include
But prepends itself first in the ancestors chain
module Friend
def opinion
puts "This would be best for you :) .."
end
end
class NormalPerson
include Friend
def opinion
pu...
NormalPerson.ancestors
#=> [NormalPerson, Friend,...]
# This is the order of method look up
NormalPerson.new.opinion
#=> “...
- Though “opinion” method exists in both
classes
- it would start from the first of the ancestors
- i.e NormalPerson in ou...
module Friend
def opinion
puts "This would be best for you :) .."
end
end
class BFF
prepend Friend
def opinion
puts "I thi...
BFF.ancestors
#=> [Friend, BFF, ...]
# This is the order of method look up
BFF.new.opinion
#=> “This would be best for you...
double underscore basically indicates
"special/avoid overwrite”
__VALUE__
- In foo.rb, __FILE__ would be "foo.rb".
- If foo.rb were in the dir /home/vysakh
then File.dirname(__FILE__) would return...
if foo.rb were in the dir /home/vysakh then
__dir__ would return /home/vysakh.
__dir__
def foo
[__method__, __callee__]
end
alias bar foo
p foo #=> [:foo, :foo]
p bar #=> [:foo, :bar]
__callee__ and __method__
class Errand
def send
puts “Buy stuff”
end
def check
puts “checking…”
end
end
Errand.new.__send__(“check”)
use __send__ if...
Also there are
__ENCODING__ (keyword)
__LINE__ (keyword)
__getobj__ (SimpleDelegator)
__setobj__ (SimpleDelegator)
Things we missed
- Operators like &&=, ||=, =~
- File operations
- System calls
- Enumerator methods
- threads
- exception...
Keep calm and write
Prose and Poetry using Ruby :)
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
A limited guide to intermediate and advanced Ruby
Upcoming SlideShare
Loading in …5
×

A limited guide to intermediate and advanced Ruby

1,167 views

Published on

If you are

Published in: Engineering, Software

A limited guide to intermediate and advanced Ruby

  1. 1. A limited guide to intermediate and advanced Ruby - Vysakh Sreenivasan (vysakh0)
  2. 2. Variables store only references to objects.
  3. 3. So, use dup or clone
  4. 4. scan & match
  5. 5. match returns the first match. scan returns all matches
  6. 6. (g - global) gsub and sub
  7. 7. >> "hello".sub('l', '*') => "he*lo" >> "hello".gsub('l', '*') => "he**o"
  8. 8. (when working in irb or pry) semicolon ;
  9. 9. [82] pry(main)> a = [1, 2, 3] => [1, 2, 3] [83] pry(main)> a = [1, 2, 3] ; [84] pry(main)> Does not print output of the statement
  10. 10. Spaceship operator <=>
  11. 11. a <=> b := if a < b then return -1 if a = b then return 0 if a > b then return 1 if a and b are not comparable then return nil
  12. 12. [1,3,2] <=> [2,2,2] - Ruby will start comparing each element of both array from left hand side. - 1 of left array is smaller than 2 of right array. - Hence left array is smaller than right array. Output will be -1.
  13. 13. case subsumption operator or case equality operator ===
  14. 14. - "If I have a drawer labelled a would it make sense to put b in that drawer?" - The main usage for the === operator is in case expressions a === b
  15. 15. case a when b end # Here b === a check is made in when # not b == a
  16. 16. Diff between a == b and a === b - (a == b) and (b == a) is always the same - (a === b) and (b === a) is not always the same Integer === 2 #true 2 === Integer #false
  17. 17. splat
  18. 18. Accept variable length arguments
  19. 19. Unwrap from array and pass as args
  20. 20. Coerce values into array coerced = *"Hello World" p coerced # => ["Hello World"] coerced = *nil p coerced # => [] coerced = *(1..3) p coerced # => [1, 2, 3]
  21. 21. Deconstruct array data = [1, 2, 3, 4] first, *rest = data puts "#{first}, #{rest}" # => 1, [2, 3, 4] *list, last = data puts "#{list}, #{last}" # => [1, 2, 3], 4 first, *center, last = data puts "#{first}, #{center}, #{last}" # => 1, [2, 3], 4
  22. 22. Double Splat Similar to splat but for hashes in arg list
  23. 23. def double_splat(**hash) p hash end double_splat() # => {} double_splat(a: 1) # => {:a => 1} double_splat(a: 1, b: 2) # => {:a => 1, :b => 2}
  24. 24. def foo (args) return args end h1 = { b: 2 } h2 = { c: 3 } foo(a: 1, **h1) # => {:a=>1, :b=>2} foo(a: 1, **h1, **h2) # => {:a=>1, :b=>2, :c=>3} foo(a: 1, h1) # Syntax Error: syntax error, unexpected ')', expecting => foo(h1, h2) # ArgumentError: wrong number of arguments (2 for 1)
  25. 25. We just used double splat to capture all keyword arguments
  26. 26. def join_array(arr, elements: , by_char: ‘,’) arr.take(elements).join(by_char) end a = [20, 30, 10, 40] # optional if there is default set in parameters, in this case it is by_char p join_array(a, elements: 3) p join_array(a, elements: 2, by_char: ‘-’) # order not important p join_array(a, by_char: ‘-’, elements: 3)
  27. 27. Damn! lambda is not rhyming! :/ blocks, procs and lambdas
  28. 28. Just passing around a chunk of code
  29. 29. def parrot(&what_human_said) puts “Hey, I’m gonna say what you said” what_human_said.call puts “Thank you. Have a nice day” end parrot do puts “I’m not Siri” puts “I’m green, eeee” end
  30. 30. &what_human_said makes passed block changed to proc
  31. 31. Sorta like a magic :) Ruby also lets us do it implicitly
  32. 32. def parrot puts “Hey, I’m gonna say what you said” yield puts “Thank you. Have a nice day” end parrot do puts “I’m not Siri” puts “I’m green, eeee” end
  33. 33. yield - is not a method but a type. - yield executes the block. - faster than previous eg.
  34. 34. block_given? method of ruby
  35. 35. But, what is proc? - an object - with blocks of code - bound to a set of local variables
  36. 36. lambda is just like proc but strict and nice - lambda checks parameters passed to it - lambda is not like that adamant child that forces you out of the movie just because he didn’t like it.
  37. 37. Symbol#to_proc
  38. 38. odd = proc { |x| x.odd? } => #<Proc:0xb8c1c6d8> odd.call(2) => false odd.call(3) => true
  39. 39. odd = :odd?.to_proc => #<Proc:0xb8c1c6d8> odd.call(2) => false odd.call(3) => true
  40. 40. Both these are equivalent :odd?.to_proc #==> &:odd? proc { |x| x.odd? }
  41. 41. Also note, these are same 1 + 2 #=> 3 1.send(:+, 2) #=> 3
  42. 42. And so, this works too(equivalence) :odd?.to_proc proc { |x| x.send(:odd?) }
  43. 43. And hence, these are same :) [“ruby”, “rails”, “thor”].map do |x| x.reverse end [“ruby”, “rails”, “thor”].map(&:reverse)
  44. 44. Proc=== is an alias to Proc. call
  45. 45. mul_of_3 = proc { |num| num % 3 == 0 } mul_of_3.call(30) #=> true mul_of_3 === 30 #=> true
  46. 46. # And so, case 30 when mul_of_3 puts “Yayyy” end #=> Yayyy
  47. 47. Proc curry
  48. 48. - A curried proc receives some arguments. - If a sufficient number of arguments are supplied, it passes the supplied arguments to the original proc and returns the result.
  49. 49. multiple = proc { |x, y| x * y } multiple.call(2, 3) #=> 6 # here x = 2, y = 3 curry_multiple = multiple.curry #=> curried the multiple proc
  50. 50. multiple_of_2 = curry_multiple.call(2) # here x is 2, y is not yet passed # when y is passed, the proc will # get executed multiple_of_2.call(3) #=> 6 # here x is 2, y is 3
  51. 51. multiply = proc { |*args| args.reduce(:*) } multiply_2_nums = multiply.curry(2) twice= multiply_2_nums.call(2) twice.call(5) # => 10
  52. 52. methods
  53. 53. Assert if method exists
  54. 54. class Twitter def tweet; end end t = Twitter.new t.respond_to?(:tweet) Twitter.method_defined?(:tweet)
  55. 55. making method object
  56. 56. def sum(a, b) a + b end s = method(:sum) s.methods # s is an object now :D s.parameters s.super_method s.call(10, 20)
  57. 57. unbound method object
  58. 58. class Calc def sum(a, b) a + b end end s = Calc.instance_method(:sum) s.call(10, 20) # NoMethodError s.bind(Calc.new).call(10, 20)
  59. 59. def palindrome? self.reverse == self end pal = Object.instance_method :palindrome? => #<UnboundMethod: Object#palindrome?> pal.bind("Madam").call => false pal.bind("madam").call => true
  60. 60. You can also invoke a method by s.send(:sum, 10, 20) eval “s.sum(1, 2)” # eval is not recommended, never use
  61. 61. defining methods (different way)
  62. 62. class Order define_method :total_for |quantity| 10 * quantity end end Order.new.total_for(20) #=> 200
  63. 63. undefining methods
  64. 64. class Order define_method :total_for |quantity| 10 * quantity end undef_method :total_for #just unlinks but is in memory end
  65. 65. class Order define_method :total_for |quantity| 10 * quantity end remove_method :total_for #removes it totally end
  66. 66. alias method
  67. 67. class Politics def free_scheme puts “Yo. Get lots of free stuff.” end alias_method :money_time, :free_scheme end Politics.new.free_scheme # what you see :P Politics.new.money_time # what they see :P
  68. 68. method_missing (Do not try this at your home/code)
  69. 69. not found is not an option for you Use it only when method
  70. 70. method curry
  71. 71. def multiple(x, y) x * y end curry_multiple = method(:multiple).curry #=> curried the multiple method, got proc twice = curry_multiple.call(2) twice.call(3) #=> 6
  72. 72. Monkey patch Open up classes and insert your own methods
  73. 73. class A end class A def hello “yolo” end end
  74. 74. class String def palindrome? self.reverse == self end end # adds a method to the already existing String Class
  75. 75. Refinements
  76. 76. module Watson refine String do def palindrome? self.reverse == self end end end “Ruby”.palindrome? #=> NoMethodError: undefined method `palindrome?' for "Ruby":String #Not available outside the namespace
  77. 77. module Watson p “RoR”.palindrome? end module Sherlock using Watson p “RoR”.palindrome? end
  78. 78. Objects
  79. 79. inherits from the class “Object” Every object in Ruby by default
  80. 80. class Foo end class Foo < Object end Both these classes are identical
  81. 81. Even class is an object
  82. 82. Foo.is_a?(Object) Foo.new.is_a?(Object) Both these are Objects
  83. 83. Ancestry
  84. 84. class Elizabeth1; end class Victoria < Elizabeth1 end class Elizabeth2 < Victoria end
  85. 85. Who was Elizabeth1’s ancestor?
  86. 86. May be just another human?
  87. 87. Then who was human’s ancestor?
  88. 88. Some ape, duh!
  89. 89. The APE is the BasicObject In Ruby, human is Object
  90. 90. Who is this kernel?
  91. 91. And there are qualities that got mixed into you See, you are human, not ape
  92. 92. that is mixed into the “Object” class Kernel is a module
  93. 93. Ya, modules are part of ancestors
  94. 94. Singleton methods
  95. 95. And how did you define on an object? But only classes has methods
  96. 96. a singleton class(invisible to you) for the object You are right. Ruby makes just to hold object specific methods
  97. 97. have singleton classes not only objects You know what, even classes
  98. 98. class God def self.true_me “:troll_face:” end end God.singleton_class God.singleton_methods God.singleton_method(:true_me).call God.true_me
  99. 99. singleton class for the class just to hold So, ruby makes a class specific methods ?
  100. 100. Foo and Foo.new are objects Wait, I remember you saying
  101. 101. the class to hold the class specific methods So, actually ruby is making a singleton class for just like it does for object because class is also object?
  102. 102. invisible to the programmer. AH! Yes! And The singleton class is typically But you sorta see in one syntax, which is
  103. 103. class God class << self def self.true_me “:troll_face:” end end end
  104. 104. class << self is like class Singleton(self) - You want to add a method just to a specific object. (note: even class is an object) - But you can’t write method to a object. - So, you write method to object’s singleton class like this.
  105. 105. class Human;end matz = Human.new class << matz def write puts “Writing the epic: Ruby” end end matz.write
  106. 106. You can also define Singleton methods by
  107. 107. class RubyLang; end RubyLang.define_singleton_method(:minaswan) do puts “Matz is nice and so we are nice” end RubyLang.minaswan
  108. 108. Ruby OO goodies
  109. 109. Yo = Class.new do def ping “hodor” end end Yo.new.ping A = Class.new # proper class but.. a = Class.new # an anonymous generic class
  110. 110. Struct is like class with bundled accessor methods
  111. 111. Product = Struct.new(:name, :price) pr = Product.new(“Book”, 20) pr.name # attr_accessor out of box pr.price = 10 pr.to_h #=> {:name=>”Book”, :price => 10} a = *pr #=> [”Book”, 10] Product = Struct.new(:name, :price) do def title “#{name} #{price}” end end
  112. 112. OpenStruct is like Struct with more manipulation as if it is a hash
  113. 113. require ‘ostruct’ param = { name: “book”, price: 20 } param_obj = OpenStruct.new(param) param_obj.delivered = false param_obj[:discount] = 5 param_obj.delete_field :delivered param_obj.to_h
  114. 114. Delegator Inherit it, and don’t write constructor as it is already defined.
  115. 115. class CEO attr_accessor :next_appointment def fix_appointment(date) next_appoinment = date end end
  116. 116. Ceo decides to hire a PA and delegate some of her work to PA
  117. 117. require ‘delegate’ class CEO attr_accessor :next_appointment end class PA < SimpleDelegator def fix_appointment(date) next_appoinment = date end end
  118. 118. elon_musk = CEO.new elon_musk_pa = PA.new(elon_musk) elon_musk_pa.fix_appointment(“7/6/2015”) # you won’t know anything else about the ceo
  119. 119. Forwardable
  120. 120. require ‘forwardable’ class CEO attr_accessor :availability, :office_mails def phone_call puts “Hi. How are you? How can I help you?” yield end end
  121. 121. class PA extend Forwardable def_delegators :@ceo, :availability, :phone_call, :office_mails def initialize(ceo) @ceo = ceo end def check_my_mail(mail) office_mails.include? (mail) end end
  122. 122. jack_ma = CEO.new(“Jack Ma”) jack_ma_pa = PA.new(jack_ma) jack_ma_pa.phone_call do puts “Hello, mr.jack ma.” end jack_ma_pa.check_my_mail(1234)
  123. 123. Also look for other awesome classes - Queue - Stack - Thread - StringScanner
  124. 124. Manipulating variables dynamically
  125. 125. class A def initialize(foo) @foo = foo end end a = A.new (“cool”) a.instance_variable_get “foo” a.instance_variable_set :@foo, “hotl” a.instance_variables
  126. 126. class A @@b = 10 end A.class_variable_get “b” A.class_variables
  127. 127. const_get class A PI = 3.14 end A.const_get “PI” # also there is const_set #only works with the classes not with objects
  128. 128. Eval The evil }:-D
  129. 129. (Ruby will run this string ) eval “puts ‘hello world’ “
  130. 130. instance_eval evaluates string/block of code in the context of the object
  131. 131. class Subject def initialize(name) @name end end maths = Subject.new(“Mathematics”) maths.name #=> ERROR maths.instance_eval { @name } #=> “Mathematics”
  132. 132. # earlier we saw this code class Human;end matz = Human.new class << matz def write puts “Writing the epic: Ruby” end end matz.write
  133. 133. # Can also be written as class Human;end matz = Human.new matz.instance_eval do def write puts “Writing the epic: Ruby” end end matz.write
  134. 134. Since class is also an object we can use instance_eval on it.
  135. 135. # we earlier saw this class RubyLang; end RubyLang.define_singleton_method(:minaswan) do puts “Matz is nice and so we are nice” end RubyLang.minaswan
  136. 136. # Also can be written as class RubyLang; end RubyLang.instance_eval do puts “Matz is nice and so we are nice” end RubyLang.minaswan
  137. 137. class_eval evaluates string/block of code in the context of the class
  138. 138. class Person; end Person.new.name #=> ERROR Person.class_eval do attr_accessor :name def trumpet puts “Me..me...me… #{name}” end end person = Person.new person.name = “Narcissis” person.trumpet
  139. 139. Modules collection of methods and constants
  140. 140. module Mod CONST = 1 def math # ... end end Mod.class #=> Module Mod.constants #=> [:CONST] Mod.instance_methods #=> [:math]
  141. 141. that you can use across multiple classes Modules are about providing methods
  142. 142. - extend - include - prepend - using (refinements) We already saw about ‘using’
  143. 143. module Hipster def flame_wars puts “Yo, this lang is better, that lang is worse” end end class Programmer end me = Programmer.new me.extend Hipster me.flame_wars
  144. 144. Can you guess where the module methods were inserted for object?
  145. 145. extend just did that for us :) To the singleton class of the object.
  146. 146. module Hipster def flame_wars puts “Yo, this lang is better, that lang is worse” end end class HipsterProgrammer extend Hipster end HipsterProgrammer.flame_wars
  147. 147. Yes. We inserted module methods to the singleton class of class by using extend
  148. 148. What if we want to just insert module methods to the class?
  149. 149. module Hipster def flame_wars puts “Yo, this lang is better, that lang is worse” end end class HipsterProgrammer include Hipster end me = HipsterProgrammer.new me.flame_wars
  150. 150. class HipsterProgrammer include Hipster end HipsterProgrammer.ancestors # => [HipsterProgrammer, Hipster, …] # NOTE: You are not inheriting here, but you are changing # method lookup chain here
  151. 151. module Validations def save puts "validating model" end end class Model include Validations def save super puts "saving model" end end
  152. 152. m = Model.new m.save #=> validating model #=> saving model
  153. 153. prepend is just like include But prepends itself first in the ancestors chain
  154. 154. module Friend def opinion puts "This would be best for you :) .." end end class NormalPerson include Friend def opinion puts "I think this would be best for me" end end
  155. 155. NormalPerson.ancestors #=> [NormalPerson, Friend,...] # This is the order of method look up NormalPerson.new.opinion #=> “I think this would be best for me”
  156. 156. - Though “opinion” method exists in both classes - it would start from the first of the ancestors - i.e NormalPerson in our case
  157. 157. module Friend def opinion puts "This would be best for you :) .." end end class BFF prepend Friend def opinion puts "I think this would be best for me" end end
  158. 158. BFF.ancestors #=> [Friend, BFF, ...] # This is the order of method look up BFF.new.opinion #=> “This would be best for you :) ..”
  159. 159. double underscore basically indicates "special/avoid overwrite” __VALUE__
  160. 160. - In foo.rb, __FILE__ would be "foo.rb". - If foo.rb were in the dir /home/vysakh then File.dirname(__FILE__) would return /home/vysakh. __FILE__
  161. 161. if foo.rb were in the dir /home/vysakh then __dir__ would return /home/vysakh. __dir__
  162. 162. def foo [__method__, __callee__] end alias bar foo p foo #=> [:foo, :foo] p bar #=> [:foo, :bar] __callee__ and __method__
  163. 163. class Errand def send puts “Buy stuff” end def check puts “checking…” end end Errand.new.__send__(“check”) use __send__ if the name send clashes with an existing method in obj
  164. 164. Also there are __ENCODING__ (keyword) __LINE__ (keyword) __getobj__ (SimpleDelegator) __setobj__ (SimpleDelegator)
  165. 165. Things we missed - Operators like &&=, ||=, =~ - File operations - System calls - Enumerator methods - threads - exceptions, backtraces, benchmarking - and many more, do check it out
  166. 166. Keep calm and write Prose and Poetry using Ruby :)

×