Instead of making a class, defining a primitive field is much simpler. However, if you keep adding fields more and more, eventually, it becomes huge. One way to solve this problem is to replace data value with object.

# dollars/cents

[5, 30]
# OR
{
  dollars: 5.
  cents: 30
}
# Dave with age 30

['Dave', 30]
# OR
{
  name: 'Dave'.
  age: 30
}

Replace with an object

class Money
  attr_reader :dollars, :cents

  def from_cents(cents)
    new(cents/100, cents%100)
  end

  def initialize(dollars, cents)
    @dollars, @cents = dollars, cents
  end
end

p Money.new.from_cents(530) #<Money:... @dollars=5, @cents=30>

As a Rails developer, I did not have a chance to create a Rails API application from the scratch. So I thought it would be great experience to build a simple API app.

Rails version 5 supports API only applications so let’s start by creating todo-backend with a magical argument --api.

$ rails _5.1.3_ new todo-backend -T --api
  create  README.md
  create  Rakefile
  create  config.ru
  create  .gitignore
  create  Gemfile
  ...
  • _5.1.3 specifies the Rails version.
  • -T skips the default testing framework.
  • --api tells Rails that we want an API application.

Then the Rails API app is created and is little bit different than a regular Rails app.

Gemfile

  • Jquery and turbolinks gems are removed

application.rb

  • config.api_only = true

application_controller.rb

  • won’t check for CSRF protection
  • inherits from ::API
# before
class ApplicationController < ActionController::Base end

# after
class ApplicationController < ActionController::API end

References

In this post, I would like to introduce some ways to set up your own preferences using .rc files. Whenever I create a project, it was really annoying to specify a database type with -d option (beacuse rails gives SQLite as a default) and etc. So I thought it would be nice if you customize the rails generator.

I did not know the types of .rc files until I have searched about it and it was interesting. You can try with the following comman:

$ ls ~/.*rc

.irbrc

In rails console, you can use awesome_print as a default option.

# ~/.irbrc
require "awesome_print"
AwesomePrint.irb!

.gemrc

You can skip rdoc and ri generation for the faster installation of gems.

# ~/.gemrc
gem: --no-document

.railsrc

You can skip Test Unit and add PostgreSQL as the default option.

# ~/.railsrc
-d postgresql --skip-test-unit

Recently, I have realized that there are many powerful enumerable methods in Ruby so I would like to introduce them in this post. I will keep adding contents as I learn more methods.

inject vs each_with_object

Building a new hash and mapping, you should consider using inject and each_with_object methods.

Let’s say we would like to return a hash of its correct length with given an array. So for example:

hash = ['ben', 'chris', 'mark']
puts get_string_lengths(hash)
# expected {"ben"=>3, "chris"=>5, "mark"=>4}

All versions below give the same result.

# solution 1
def get_string_lengths_v1(strings)
    strings.inject({}) do |hash, string|
        hash[string] = string.length
        hash
    end
end

# solution 2
def get_string_lengths_v2(strings)
    strings.inject({}) do |hash, string|
        hash.merge(string => string.length)
    end
end

# solution 3
def get_string_lengths_v3(strings)
    strings.each_with_object({}) do |string, hash|
        hash[string] = string.length
    end
end

puts get_string_lengths_v1(%w(ben chris mark))
puts get_string_lengths_v2(%w(ben chris mark))
puts get_string_lengths_v3(%w(ben chris mark))

For the first solution, inject requires memoized value for subsequent block calls, so I returned the hash object in the block. I felt it is less convenient so I tried using merge method in the second solution because it returns a hash. Lastly, I used each_with_object method and I felt more convenient.

You cannot use immutable objects for each_with_object method.

(1..5).each_with_object(0) do |item, sum|
  sum += item
end
# => 0 since numbers are immutable

In this case, inject method is used for immutable objects which return a new value.

(1..5).inject(:+)

In the quick sort algorithm, partition method is the main concept.

Time Complexity

Note: N is the size of input

Quicksort is a popular sorting algorithm with O(N * logN) best and average-case , and O(N^2) worst case performance.

Implementation

class Array
    attr_accessor :array

    def initialize(array)
        @array = array
    end

    def quick_sort(p=0, r=array.size-1)
        if p < r
            q = partition(p, r)
            quick_sort(p, q-1)
            quick_sort(q+1, r)
        end
    end

    private
        def partition(p, r)
            x = array[r]
            i = p - 1
            (p..r-1).each do |j|
                if array[j] <= x
                    i += 1
                    array[i], array[j] = array[j], array[i]
                end
            end
            array[i+1], array[r] = array[r], array[i+1]
            return i + 1
        end
end

array = Array.new([5, 1, 10, 2])
array.quick_sort
p array.array # => [1, 2, 5, 10]

Merge Sort vs Quick Sort

  • Quick sort is significantly faster in practice.
  • Quick sort has very low memory requirement.
  • Quick sort divides sub-problems in vary
  • Merge sort divides sub-problems in half