Skip to content

Instantly share code, notes, and snippets.

@venkatch789
Last active June 21, 2016 19:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save venkatch789/209de279cc58557aba46 to your computer and use it in GitHub Desktop.
Save venkatch789/209de279cc58557aba46 to your computer and use it in GitHub Desktop.
Ruby

Design patterns (in Ruby)

Design patterns are just tools that help us constructing a software.

Template Method pattern

In the Template Method pattern, we create a skeletal class and it is basis for various subclasses or concrete classes. Within in the skeletal class, there are abstract methods, which in turn, will be overridden by the methods of subclasses.

Let's take an example of simple payment system,

Usually, the payment process has the same flow regardless of the provider we use.

The flow of our example payment system is,

  1. Authenticate the merchant (our application) with the provider
  2. Send the User's card data with the amount of order
  3. Receive confirmation or error from the provider

If we want to implement this payment algorithm, it would look like,

class StripePayment
  def initialize card, amount
    @api_key = ENV['STRIPE_API_KEY']
    @card = card
    @amount = amount
  end
  
  def process_payment!
    authenticate_merchant && make_payment
  end
  
  def authenticate_merchant
    begin
      return true if Stripe::Merchant.authenticate @api_key
    rescue Stripe::MerchantError => e
      Rails.logger.error "Cannot establish connection between Merchant and Provider."
      return false
    rescue Stripe::ProviderUnreachable => e
      Rails.logger.error "Provider unreachable."
      return false
    end
  end
  
  def make_payment
    begin
      return true if Stripe::Payment.process! @api_key, @card, @amount
    rescue Stripe::PaymentUnprocessable => e
      Rails.logger.error "Payment unprocessable, try again."
      return false
    end
  end
end

So this looks all fine. We can instantiate a new StripePayment object, pass the card object and the amount of the order as parameters in the initializer and call the process_payment! method on the object to execute the payment. For a successful payment, we need the Merchant (our web application) to successfully authenticate with the payment provider (Stripe) and then the credit card to be charged the total of the order. If any of these two fail, the payment wont be processed.

What about PayPal payment?

Well, we will think to add a new class and which defines the same flow. And what if we would like to add another payment options like credit card payment, or some other.

So, here comes the idea of Template Method pattern.

class BasePayment
  def initialize card, amount
    @card = card
    @amount = amount
  end
  
  def process_payment!
    authenticate_merchant && make_payment
  end
  
  def authenticate_merchant
    raise NotImplementedError.new "authenticate_merchant"
  end
  
  def make_payment
    raise NotImplementedError.new "make_payment"
  end
end
class StripePayment < BasePayment
  def authenticate_merchant
    begin
      return true if Stripe::Merchant.authenticate ENV['STRIPE_API_KEY']
    rescue Stripe::MerchantError => e
      Rails.logger.error "Cannot establish connection between Merchant and Provider."
      return false
    rescue Stripe::ProviderUnreachable => e
      Rails.logger.error "Provider unreachable."
      return false
    end
  end
  
  def make_payment
    begin
      return true if Stripe::Payment.process! ENV['STRIPE_API_KEY'], @card, @amount
    rescue Stripe::PaymentUnprocessable => e
      Rails.logger.error "Payment unprocessable, try again."
      return false
    end
  end
end
class PaypalPayment < BasePayment
  def authenticate_merchant
    begin
      return true if Paypal::Account.authenticate ENV['PAYPAL_API_KEY']
    rescue Paypal::NotAuthenticated => e
      Rails.logger.error "Cannot establish connection between Merchant and Provider."
      return false
    rescue Paypal::NotFound => e
      Rails.logger.error "Provider unreachable."
      return false
    end
  end
  
  def make_payment
    begin
      return true if Paypal::Payment.create! ENV['PAYPAL_API_KEY'], @card, @amount
    rescue Paypal::UnprocessablePayment => e
      Rails.logger.error "Payment unprocessable, try again."
      return false
    end
  end
end

Singleton pattern

Observer pattern

Decorator pattern

Factory pattern

Blocks in Ruby

What are the differences between procs and lambdas?

Before getting into the differences, they are very similar and both are Proc objects.

proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }

proc.class # returns 'Proc'
lam.class  # returns 'Proc'

And the differences are,

  • Lambda is very strict about the no.of arguments passed. It throws exception when incorrect arguments. But Proc does not complain abut the no.of arguments passed, it just returns nil.
lam = lambda { |x| puts x }    # Creates a lambda that takes one argument and prints it
lam.call(2)                    # It executes and prints 2
lam.call                       # ArgumentError: Wrong number of arguments (0 for 1)
lam.call(2,3)                  # ArgumentError: Wrong number of arguments (2 for 1)
proc = Proc.new { |x| puts x } # Creates a lambda that takes one argument and prints it
proc.call(2)                   # It executes and prints 2
proc.call                      # Returns nil
proc.call(1,2,3)               # It executes and prints 1. And it forgets about the extra arguments
  • Lambdas and Procs treat the return statement differently. If there is a return statement mentioned in the lambda, it continues to execute the rest of the code. But in Proc, the return statement will return the result for entire method.
def lamda_test
  lam = lambda { return }
  lam.call
  puts "Hello world!"
end
lamda_test             # Calling this method will print "Hello world!" (i.e the flow control continues to execute after the lambda block also)
def proc_test
  proc = Proc.new { return }
  proc.call
  puts "Hello world!"
end
proc_test              # Calling this method will print nothing (i.e the flow control terminates within the Proc block only.)

PS: Both proc and lambda are the methods defined in the Kernal module

What is SQL injection?

SQL injection is a code injection technique, used to attack data-driven applications, in which malicious SQL statements inserted into the entry field for execution.

What is splat operator in Ruby?

class_eval, instance_eval and module_eval

Ruby's most fame is its dynamic capabilities.

class_eval and module_eval These two methods grant you access to the existing class and module definition.

Dog.class_eval do
  def bark
    puts "huf huf..."
  end
end

..is same as,

class Dog
  def bark
    puts "huf huf..."
  end
end

What's the difference?

Well, using these methods we add methods to the exsting classes or modules at runtime.

If our class called Dog is not defined before we use class_eval, we would see an error NameError: uninitialized constant Dog

Perfect example for class_eval is implementation of attr_accessor in Rails.

Object.class_eval do
  class << self
    def attribute_accessor( *attribute_names )
      attribute_names.each do |attr_name|
        class_eval %Q?
          def #{attr_name}
            @#{attr_name}
          end
          def #{attr_name}=( new_value )
            @#{attr_name} = new_value
          end
        ?
      end
    end
  end
end 

class Dog
  attribute_accessor :name
end

dog = Dog.new
dog.name = "MyDog"

puts dog.name
  • The module_eval method is just an alias to class_eval so you can use them both for classes and modules.

instance_eval

The instance_eval just works like class_eval but adds the behaviour to the particular object where it was called. That means the code added via class_eval works as it was added to the the class body. That is every object of class is permitted to access this behaviour. But the code added via instance_eval would be accessed to only that particular object.

Let's see an example how it works,

class Dog
  attribute_accessor :name
end

dog = Dog.new
dog.name = 'Fido'

dog.instance_eval do
    #here I am defining a bark method only for this “dog” instance and not for the Dog class
  def bark
   puts 'Huf! Huf! Huf!'
  end

end

other_dog = Dog.new
other_dog.name = 'Dido'

puts dog.name
puts other_dog.name

dog.bark
other_dog.bark #this line will raise a NoMethodError as there’s no “bark” method
                      #at this other_dog object

Lets' wrap it... No..no. wait! There is one more interesting point to be discuss,

We know every class is an object in Ruby, so can I use instance_eval on the classes?

Yes, we can use. And the methods defined in this way will be available as class methods to that class. That's interesting, right?

Let's see an example,

Object.instance_eval do
  def attribute_accessor( *attribute_names )
    attribute_names.each do |attribute_name|
      class_eval %Q?
          def #{attribute_name}
              @#{attribute_name}
          end
          def #{attribute_name}=( new_value )
              @#{attribute_name} = new_value
          end
      ?
    end
  end
end

What are the limitations of Ruby on Rails?

It is somewhat difficult to write about the weaknesses and constraints of Ruby on Rails when you actually are a Ruby on Rails developer

  • Ruby is slow, because of it is interpreted language.
  • Ruby on Rails development is community driven: there is no formal institution that would take the responsibility for the changes introduced to the framework.
  • Constant, rapid changes of the framework is also one type of limitation

How would you create a rake task?

Rake is Ruby make, a software task management tool, like Make utility in Unix systems.

There are several ways to create a rake task.

  1. Create it from scratch
  2. Copy-paste code from another ready rake task and change code to required.
  3. Use task generator

Using generator,

$ rails g task my_namespace my_task1 my_task2

It will generate scaffold for our new rake task: >lib/tasks/my_namespace.rake

namespace :my_namespace do
  desc "TODO"
  task :my_task1 => :environment do
  end

  desc "TODO"
  task :my_task2 => :environment do
  end
end

To list all your rake tasks,

$ rake -T

Or if specific tasks,

$ rake -T | grep my_namespace

Explain Single Table Inheritance (STI) in Ruby?

Explain Polymorphic Associations in Rails? And discuss what is the difference between STI and Polymorphic associations?

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