Skip to content

Instantly share code, notes, and snippets.

@vgvinay2
Forked from canujohann/ruby-language.md
Last active August 29, 2015 14:20
Show Gist options
  • Save vgvinay2/a0d7e2d7489a22e8e0dc to your computer and use it in GitHub Desktop.
Save vgvinay2/a0d7e2d7489a22e8e0dc to your computer and use it in GitHub Desktop.

Ruby language

General

[extend ]

The extend method works similar to include, but unlike include, you can use it to extend any object by including methods and constants from a module. It can add class level methods - something that include can't do.

module Foo
  def say_hi
    puts "Hi!"
  end
end

class Bar
end

Bar.extend Foo
Bar.say_hi

add all the module instance methods as module functions

module Foo
 extend self
 def foo
 end
end

p Foo.foo.

Mimick "include" with "extend"

module Foo
  def method_in_module
     "The method defined in the module invoked"
  end
end

class Bar
  def initialize
    self.extend Foo
  end
end

Asterisk (*)

As method parameter

take all parameters and put it into an array

def my_method(*name)
When calling a method

transform an array in object : hoge(1.2.3)

arr = [1,2,3]
hoge(*arr)

Ampersand (&)

When calling a method
def hello
  yield if block_given?
end

hello do
  puts "hello"
end

is similar to :

def hello
  yield if block_given?
end

#with lambda
blah = ->{puts "hello"}
hello(&blah)

<=>

The Comparable mixin is used by classes whose objects may be ordered. The class must define the <=>

class SizeMatters
  include Comparable
  attr :str
  def <=>(anOther)
    str.size <=> anOther.str.size
  end
  def initialize(str)
    @str = str
  end
  def inspect
    @str
  end
end

s1 = SizeMatters.new("Z")
s2 = SizeMatters.new("YY")
s3 = SizeMatters.new("XXX")
s4 = SizeMatters.new("WWWW")
s5 = SizeMatters.new("VVVVV")

s1 < s2                       #=> true
s4.between?(s1, s3)           #=> false
s4.between?(s3, s5)           #=> true
[ s3, s2, s5, s4, s1 ].sort   #=> [Z, YY, XXX, WWWW, VVVVV]

as simple operator

Combined comparison operator. Returns 0 if first operand equals second, 1 if first operand is greater than the second and -1 if first operand is less than the second.

As method parameter
def hello(&block)
  block.call if block_given?
end

Class Methods

Simple way
class Item
  def self.show
    puts "Class method show invoked"
  end  
end
Rubyiest way
class Item
  class << self
    def show
      puts "Class method show invoked"
    end
  end
end

Class variables

class Planet
  @@planets_count = 0
end
p Planet.planets_count

instance_variable_set method

book = Book.new("Programming Ruby")
book.instance_variable_set(:@title, "Programming Ruby 1.9")

instance_variable_get method

Returns the value of the given instance variable, or nil if the instance variable is not set.

def inspect_instance_variable(class_name, variable)
  Module.const_get(class_name).new.instance_variable_get("@" + variable)
end
class Fred
  def initialize(p1, p2)
    @a, @b = p1, p2
  end
end
fred = Fred.new('cat', 99)
fred.instance_variable_get(:@a)    #=> "cat"
fred.instance_variable_get("@b")   #=> 99

const_get

Checks for a constant with the given name

Math.const_get(:PI)   #=> 3.14159265358979
def inspect_instance_variable(class_name, variable)
  Module.const_get(class_name).new.instance_variable_get("@" + variable)
end

Other methods

Method function
parameters Returns all the parameters that the method is defined withd
arity Returns a Fixnum representing the number of arguments that the method can accept is used
method Returns the Method object
def monk(arg1, *args2)
  "Monks" + arg1 + args2.first
end

mo = self.method(:monk)

puts "Arity"
p mo.arity

puts "Parameters"
p mo.parameters

Metaprogramming methods

re-open a class

In using class_eval
String.class_eval do
  def get_size
    length
  end
end
Redefine it
class String
  def get_size
    length
  end
end
With double "less than" (only for current instance)
class << someinstance
  def foo
    "Hello."
  end
end

We can use alias for keeping overriden method

alias old_my_greeting my_greeting 

define_method

One major benefit of this is that you can reduce the duplication inherent methods with similar definitions.

class Doctor
  ["rhinoplasty", "checkup", "interpretive_dance"].each do |action|
	  define_method("perform_#{action}") do |argument|
			"performing #{action.gsub('_', ' ')} on #{argument}"
  	end
  end
end

doctor = Doctor.new
puts doctor.perform_rhinoplasty("nose")
puts doctor.perform_checkup("throat")
puts doctor.perform_interpretive_dance("in da club")

class_eval

Define a class method

monk = Class.new
monk.class_eval do 
  def zen
    42
  end
end

p Module.const_get('monk').new.zen

Used with block

class ChefDSL
  def template(path, &block)
    TemplateDSL.new(path, &block)
  end
end

class TemplateDSL
  def initialize(path, &block)
    @path = path
    instance_eval &block
  end

  def source(source); @source = source; end
  def owner(owner);   @owner  = owner;  end
  def mode(mode);     @mode   = mode;   end
end

...

template "/path/to/file.conf" do
  source "file.conf.erb"
  owner  "trotter"
  mode   "0755"
end

instance_eval method

Define an instance method , Evaluates a string containing Ruby source code

class That
end

p Module.const_get('This').new

eval method

class Monk
  eval "def zen; end"
end

Evaluating code read out of a file or a string coming from a database greatly increases the risk of execution of malicious code and is one of the reasons why eval is considered evil.

class_exec

Evaluates the given block in the context of the class/module

class Thing
end
Thing.class_exec{
  def hello() "Hello there!" end
}
puts Thing.new.hello()

method_missing

Called when a non existing method is called

class ActiveRecord::Base
  def method_missing(meth, *args, &block)
    if meth.to_s =~ /^find_by_(.+)$/
      run_find_by_method($1, *args, &block)
    else
      super # You *must* call super if you don't handle the
            # method, otherwise you'll mess up Ruby's method
            # lookup.
    end
end

const_missing

Invoked when a reference is made to an undefined constant in mod

def Foo.const_missing(name)
  name # return the constant name as Symbol
end

Foo::UNDEFINED_CONST    #=> :UNDEFINED_CONST: symbol returned

send

class Klass
  def hello(*args)
    "Hello " + args.join(' ')
  end
end
k = Klass.new
k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"
Add class level methods

It can add class level methods - something that "include" can't do.

module Foo
  def say_hi
    puts "Hi!"
  end
end

class Bar
end

Bar.extend Foo
Bar.say_hi
Using "include" and "extends" for instance/ class variable
module Foo
  
  def self.included(klass)
    klass.extend ClassMethods  
  end
  
  module ClassMethods
    def guitar
      "gently weeps"
    end
  end
end

class Bar
  include Foo
end

puts Bar.guitar

Callbacks methods

Method function
method_addded when a new method is added with add_method
method_removed When remove_method is used
singleton_method_added
singleton_method_removed
method_undefined When an undefined method is called
included When a module is included

ex for included :

module Foo
  def self.included(klass)
    puts "Foo has been included in class #{klass}"
  end
end

class Bar
  include Foo
end

Patterns seen in many ruby gems

module Gym

  def self.included(class_or_module)
    class_or_module.send(:include, InstanceMethods)
    class_or_module.extend(ClassMethods)
  end

  module ClassMethods
    def build
    end
  end

  module InstanceMethods
    def open
    end

    def book_for_practice
    end

    def close
    end
  end
end
module HashInitialized

  def hash_initialized(*fields)
    define_method(:initialize) do |h|
   missing = fields - h.keys
   raise Exception, "Not all fields set: #{missing}" if missing.any?

      h.each do |k,v|
        instance_variable_set("@#{k}", v) if fields.include?(k)
      end
    end
  end
end

class Cheese
  extend HashInitialized
  attr_accessor :color, :odor, :taste
  hash_initialized :color, :odor, :taste
end

Other

Add a "not" function
class Object
  def not
    Not.new(self)
  end

  class Not
    def initialize(original)
      @original = original
    end

    def method_missing(sym, *args, &blk)
      !@original.send(sym, *args, &blk)
    end
  end
end

class Person
  def initialize(name)
    @name = name
  end

  def smith?
    @name == "Smith"
  end
end

puts Person.new("Ziggy").not.smith?
A simple benchmark
require 'benchmark'

class Monk
  eval "def zen; end"

  define_method(:zen_block) {}
end

monk = Monk.new

Benchmark.bmbm do |x|
  x.report("eval zen: ") { 10_000.times { monk.zen } }
  x.report("define_method zen: ") { 10_000.times { monk.zen_block } }
end
class Symbol
  def for(&sblk)
    if self == :meditate
      Calculate.new.instance_eval(&sblk)
    end
  end
end

class Calculate
end


class Monks
  class << self
    def should(&sblk)
      self.new.instance_eval(&sblk)
    end
  end
end

Monks.should do
  :meditate.for do
    puts "5 seconds"
  end
end
class Callbacker
  def make_callback(obj, meth)
    metaclass = class << self; self; end
    metaclass.send(:define_method, :callback) do
      obj.send(meth)
    end
  end
end

# usage
callbacker = Callbacker.new
callbacker.make_callback("   hello   ", :strip)
callbacker.callback   # => "hello"

http://rubymonk.com

Block, Proc and Lambda

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment