Rewbie Newbie

Documenting my path on becoming a Rails Developer.

Sorting Algorithms

Being able to code in an awesome language such as Ruby does not excuse one from not knowing how to reconstruct something that is already built into the language, case in point is the sort method in class Array. I will use this blog post to analyze the numerous sort algorithms and discuss why quicksort is the sort algorithm used in the Array#sort method.

Before I dig into each specific sorting algorithm, I want to lay down some ground-rules and prevent any ambiguities or confusion. Each algorithm will sort an unordered array from the smallest value to the largest value ordered from left to right.

Bubblesort

Bubblesort is a simple search algorithm where an array is sorted by comparing adjacent pairs of elements and swapping the element positions if the left element is greater than the right element. Each step-through of the array will always yield the correct position for the next largest value in the array, thus the next largest value is ‘bubbled’ to the right. This can be illustrated with a simple example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Bubblesort from least to greatest

starting array
=> [3,2,4,1]

1. compare the 3 and 2, since 3 is greater than 2, swap positions.
=> [2,3,4,1]

2. compare the 3 and 4, they are in the correct position, move to next pair.

3. compare the 1 and 4, 1 is less than 4, swap positions. 4 is in the correct position since it is the largest, so it will not be compared with another number again.
=> [2,3,1,4]

4. compare 2 and 3, they are in the correct postion, move to next pair.

5. compare 3 and 1, swap positions. 3 is in its correct position, it will not be compared again.
=> [2,1,3,4]

6. compare 2 and 1, swap positions. 2 is in its correct position, it will not be compared again. Sorting is complete.
=> [1,2,3,4]

Below is the bubblesort algorithm implemented in Ruby.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def bubble_sort(array)
  size = array.size
  if size == 1
    return array
  end
  size.downto(2).each do |step|
    (0...step-1).each do |p|
      if array[p] > array[p+1]
        array[p], array[p+1] = array[p+1], array[p]
      end
    end
  end
end

test = [60,37,3,21,3,2,5,6,33,44,55,7,3,4,2]

bubble_sort(test)

puts test
#=> [2, 2, 3, 3, 3, 4, 5, 6, 7, 21, 33, 37, 44, 55, 60]

Since there are n-1 + n-2 + … 2 + 1 comparisons made to execute bubblesort, the total comparisons made is (n-1)(n)/2 => (n2)/2 - n/2 and since n2 dominates as the dataset becomes large, bubblesort has an efficiency of Ο(n2).

Selection Sort

Selection sort sorts an array by repeatedly stepping through an array, keeping track of the successive smallest value’s position and swapping it with the starting position of each sweep.

1
2
3
4
5
6
7
8
9
10
11
12
Selection Sort from smallest to largest.

starting array
=> [3,2,4,1]

1. starting at 3, go through the array and keep track of the position of the smallest value. Since 1 is the smallest value, 3 and 1 swap places.
=> [1,2,4,3]

2. Starting at 2, go through the remaining array to its right and keep track of the successive smallest value. Since 2 is the next smallest value, no swap is needed.

3. Starting at 4 and going right, 3 and 4 are swapped and the array is sorted.
=> [1,2,3,4]

Below is the selection sort algorithm implemented in ruby.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
selection sort from smallest to largest

def selection_sort(array)
  size = array.size
  (0...size-1).each do |once|
    smallest = array[once]
    spot = once
    (once...size).each do |repeat|
      if array[repeat] < smallest
        smallest = array[repeat]
        spot = repeat
      end
    end
    array[spot], array[once] = array[once], array[spot]
  end
end

test = [44,2,5,2,7,11,87,99,66]

selection_sort(test)

puts test
#=> [2, 2, 5, 7, 11, 44, 66, 87, 99]

Selection sort also has an efficiency of Ο(n2).

Insertion Sort

Insertion sort is a search algorithm where a new number is introduced to an already sorted array and the new number is inserted into the correct position in the sequence. An example follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsorted array
=> [4,2,3,1]

1. Start with 4 as the only element in the sorted array.
=> [4]

2. Compare 2 with the 4, since 2 is less than 4 and there is no other number infront of 4, insert 2 in the position of 4.
=> [2,4]

3. Compare 3 with 4, since it is less than 4, compare 3 to the next number after 4, since 3 is greater than 2, insert 3 after 2.
=> [2,3,4]

4. Compare 1 with 4, 3, and 2, since it is smaller than all of them, it is inserted into the position of 1.
=> [1,2,3,4]

Below is the insertion sort algorithm implemented in ruby.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def insertion_sort(array)
  size = array.size
  (1...size).each do |once|
    (0..once).each do |repeat|
      if array[once] < array[repeat]
        array.insert(repeat, array[once])
        array.delete_at(once+1)
        break
      end
    end
  end
end

test = [5,2,3,7,9,2,4,5,2,0,1]

insertion_sort(test)

puts test
#=> [0, 1, 2, 2, 2, 3, 4, 5, 5, 7, 9]

Since the worst case scenario is that the array to be sorted is arranged from largest to smallest, it would take (n-1)(n)/2 steps, so insertion sort also has an efficiency of Ο(n2).

Merge Sort

Merge sort is a divide-and-conquer search algorithm where the array is broken down into smaller and smaller arrays until each number is the only element in its own array. Then each array is merged with adjacent array and this process is repeated until one long sorted array is formed.

1
2
3
4
5
6
7
8
9
10
11
unsorted array
=> [4,2,3,1]

1. Divide until each number is contained in its own array.
=> [4], [2], [3], [1]

2. Compare with adjacent array and merge.
=> [2,4], [1,3]

3. Compare each term of the merged arrays and merge again. Since 1 is less than 2, 1 is merged into the new array first. Then, comparing 2 and 3, 2 is merged and so on.
=> [1,2,3,4]

Below is the insertion sort algorithm implemented in ruby.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def merge(left, right)
  result = []
  while left.size > 0 || right.size > 0
    if left.size > 0 && right.size > 0
      if left.first <= right.first
        result << left.shift
      else
        result << right.shift
      end
    elsif left.size > 0
      result << left.shift
    elsif right.size > 0
      result << right.shift
    end
  end
  result
end

def merge_sort(array)
  if array.size <= 1
    return array
  end
  middle = array.size/2
  left = array[0..middle-1]
  right = array[middle..-1]
  left = merge_sort(left)
  right = merge_sort(right)
  return merge(left,right)
end

test = [33,77,23,34,49,1,2,5,2,3,7]

result = merge_sort(test)

puts result
#=> [1, 2, 2, 3, 5, 7, 23, 33, 34, 49, 77]

Merge Sort has an efficiency of Ο(n log n).

(More algorithms to come.)

The Big O Notation

The big O notation is used to denote the approximate effiency of an algorithm when the algorithm is applied on an arbitrarily large dataset. In other words, it give you a sense of how effiencient an algorithm is when it is applied on a small dataset compared to a very large dataset.

The effiency of an algorithm is measured either by the amount of time (speed) or the amount of memory the algorithm uses when executed. The aim of the big O is to capture the upper-bound or worst-case performance effciency of an algorithm.

The formal definition of the big O notation is much more complex than the application of the concept, so this is a topic best dealt with examples rather than getting tangled up in the intricacies of defining it.

Before we jump into the examples, let’s lay down some ground rules. Items will refer to the number of items in a dataset. Seconds is used as an arbitrary time unit to give a relative sense of how long it takes an algorithm to execute depending on the size of the dataset. The use of seconds does not at all reflect computation time, nanoseconds can be used to substituted for seconds, but I’ve chosen seconds because it’s much easier to relate to than a nanosecond, plus it’s shorter to type. Lastly, the hypothetical algorithm in each example is to be viewed independent of each other, the focus is not on the algorithm, but rather on how big O captures the efficiency of the each algorithm given varying dataset sizes.

Ο(1)

First off, the best case scenario is that an algorithm operates in Ο(1), which means it finishes executing in the same amount of time regardless of the size of the input dataset.

1
2
3
4
5
6
O(1) efficiency

1 item:         1 second
100 items:      1 second
10000 items:    1 second
1000000 items:  1 second

Ο(log2 n)

Ο(log2 n) is not as efficient as Ο(1), but it can handle large datasets almost as well.

1
2
3
4
5
6
O(log n) efficiency

1 item:         very small fraction of a second
100 items:      6.64 seconds
10000 items:    13.29 seconds
1000000 items:  19.93 seconds

Ο(n)

Ο(n) grows linearly, which means for each item added to the dataset, the execution time increases by one second.

1
2
3
4
5
6
O(n) efficiency

1 item:         1 second
100 items:      100 seconds
10000 items:    10000 seconds
1000000 items:  1000000 seconds

Ο(n log2 n)

Ο(n log2 n) is not as efficient as Ο(n), but it is not amongst the worst either.

1
2
3
4
5
6
O(n log n) efficiency

1 item:         very small fraction of a second
100 items:      664.39 seconds
10000 items:    132877.12 seconds
1000000 items:  19931568.57 seconds

Ο(n2) or Ο(na) where a is any integer >= 2

Ο(na) applies to any algorithm whose efficiency grows by a factor of a polynomial. The most common efficiency is the quadratic-time efficiency, and as you can see below, any algorithm with a polynomial effiency quickly deteriorates as the dataset size increases.

1
2
3
4
5
6
O(n**2) efficiency

1 item:         1 second
100 items:      10000 seconds
10000 items:    100000000 seconds
1000000 items:  1000000000000 seconds

Ο(2^n)

An algorithm with Ο(2^n) effiency becomes unusable even quicker as the dataset increases. The addition of each item doubles the execution time.

1
2
3
4
5
6
O(2**n) efficiency

1 item:         1 second
100 items:      1267650600228229401496703205376 seconds
10000 items:    Too big to print.
1000000 items:  Too big to print.

Ο(n!)

Ο(n!) effiency breaksdown very quickly. The execution time explodes even when the dataset size is still relatively small.

1
2
3
4
5
6
7
8
O(n!) efficiency

1 item:         1 second
10 items:       3628800 seconds
40 items:       815915283247897734345611269596115894272000000000 seconds
100 items:      Too big to print.
10000 items:    Too big to print.
1000000 items:  Too big to print.

Conclusion

In terms of effienciency, the list of the most common big Ο can be summed up as:

Ο(1)  >  Ο(log2 n)  >  Ο(n)  >  Ο(n log2 n)  >  Ο(n2)  >  Ο(2n)  >  Ο(n!)

Internal vs. External Iterators

I was wrapping my head around the Enumerator class while reading Pickaxe and it mentioned that the Enumerator class is how Ruby implements external iterators. Of course this caught my attention, if there is an external iterator, then there must also be an internal iterator. I did a little digging and my suspicion was confirmed.

Definition

Internal iterators are iterators that are built into the collection itself. For example, the most vanilla internal iterator in Ruby is the #each method of an Array instance. The #each method traverses over each array element and passes each element to the code block that is associated with the #each method call.

External iterators on the other hand, are objects that traverse a collection, specifically, the logic of how a collection is traversed is dictated by an external object.

Implementation

Creating an internal iterator is to simply call the #each method on a collection and attach a block to the #each method call.

1
2
3
4
5
array = (1..10).to_a

array.each { |n| print n.to_s + " " }

#=> 1 2 3 4 5 6 7 8 9 10

To create an external iterator, the most straight-forward way is to call #to_enum on a collection and a new enumerator object will be returned to you. What is also worth noting is when you call an internal iterator on a collection without attaching a block, it is equivalent to calling #to_enum on the collection.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
array = (1..10).to_a

enum = array.to_enum

enum.class
#=> Enumerator

enum = array.each
enum.class
#=> Enumerator

enum = array.map
enum.class
#=> Enumerator

Once you have an external iterator created, you have much greater control over how you can iterate over your collection.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
array = (1..10).to_a
enum = array.to_enum

enum.next
#=> 1
enum.next
#=> 2
enum.next
#=> 3

enum.rewind

enum.next
#=> 1

sections = array.each_slice(4)

sections.class
#=> Enumerator

section.next
#=> [1, 2, 3, 4]
sections.next
#=> [5, 6, 7, 8]
sections.next
#=> [9, 10]
sections.next
#=> StopIteration: iteration reached an end

sections.rewind

sections.next
#=> [1, 2, 3, 4]

Benefits and Drawbacks

Internal iterators are easy to implement but lack flexibility. The behavior of an internal iterator is preset by the collection. For example, both #map and #each will always traverse each element of an array from the beginning until the end. Due to these characteristics, internal iterators are suitable for when you need to linearly traverse a collection.

But when linear traversion is not what you are after, expect to write a few more lines of code and exercise control with an external iterator.

A Few Tools for Navigating the Sea of Methods

When I encounter an unfamiliar object in Ruby, my instinct is to look and see what classes, modules and methods I am dealing with.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Automobile
  attr_accessor :make, :model, :type
end

car = Automobile.new

Automobile.ancestors
car.class.ancestors   #ancestors can only be called on a class object
car.methods.sort
Automobile.instance_methods(false)
car.public_methods(false)
meth = car.method(:make)
meth.parameters
meth.owner
meth.source_location
#etc...

But typing numerous lines of code is not a practical solution to this reoccurring problem. Luckily more than a couple of people have been frustrated by this problem and they decided to provide a better solution.

Use the ‘looksee’ gem to get a better overview of the class and methods structure.

Simply call the ‘ls’ method on any object and looksee will list the inheritance structure along with what methods each class inheritance provides to the object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#This codeblock assumes both the class defintion for Automobile and #the car instance are in memory.

require 'looksee'

car.ls

###console output follows###

=> BasicObject
  !       __send__       instance_exec             singleton_method_undefined
  !=      equal?         method_missing
  ==      initialize     singleton_method_added
  __id__  instance_eval  singleton_method_removed
Kernel
  !~                       gem                         puts
  <=>                      gem_original_require        raise
  ===                      gets                        rand
  =~                       global_variables            readline
  Array                    hash                        readlines
  Complex                  initialize_clone            remove_instance_variable
  Float                    initialize_copy             require
  Integer                  initialize_dup              require_relative
  Rational                 inspect                     respond_to?
  String                   instance_of?                respond_to_missing?
  __callee__               instance_variable_defined?  select
  __method__               instance_variable_get       send
  `                        instance_variable_set       set_trace_func          
  abort                    instance_variables          singleton_class         
  at_exit                  is_a?                       singleton_methods       
  autoload                 iterator?                   sleep                   
  autoload?                kind_of?                    spawn                   
  binding                  lambda                      sprintf                 
  block_given?             load                        srand                   
  caller                   local_variables             syscall                 
  catch                    loop                        system                  
  class                    method                      taint                   
  clone                    methods                     tainted?                
  define_singleton_method  nil?                        tap                     
  display                  object_id                   test                    
  dup                      open                        throw                   
  enum_for                 p                           to_enum                 
  eql?                     pp                          to_s                    
  eval                     pretty_inspect              trace_var               
  exec                     print                       trap                    
  exit                     printf                      trust                   
  exit!                    private_methods             untaint                 
  extend                   proc                        untrace_var             
  fail                     protected_methods           untrust                 
  fork                     public_method               untrusted?              
  format                   public_methods              warn                    
  freeze                   public_send               
  frozen?                  putc                      
PP::ObjectMixin
  pretty_print        pretty_print_inspect           
  pretty_print_cycle  pretty_print_instance_variables
Looksee::ObjectMixin
  edit  ls
Object
  DelegateClass  Digest  P  __binding__  __p  log  pry
Automobile
  make  make=  model  model=  type  type=

Use ‘awesome_print’ to show method inheritance and argument requirements for each method

When you ‘ap’ object.methods, awesome_print prints out a 3 column table that is alphabetically sorted by method name. The first column acts as an index, the second column shows the method names and the argument requirements for each method and the third column indicates which class or module the method came from.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
require 'awesome_print'

ap car.methods

### console output follows ###

[
    [ 0]                               !()                 Automobile (BasicObject)
    [ 1]                              !=(arg1)             Automobile (BasicObject)
    [ 2]                              !~(arg1)             Automobile (Kernel)
    [ 3]                             <=>(arg1)             Automobile (Kernel)
    [ 4]                              ==(arg1)             Automobile (BasicObject)
    [ 5]                             ===(arg1)             Automobile (Kernel)
    [ 6]                              =~(arg1)             Automobile (Kernel)
    [ 7]                     __binding__()                 Automobile (Object)
    [ 8]                          __id__()                 Automobile (BasicObject)
    [ 9]                        __send__(*arg1)            Automobile (BasicObject)
    [10]                              ai(*options)         Automobile (Kernel)
    [11]                 awesome_inspect(*options)         Automobile (Kernel)
    [12]                   awesome_print(object, *options) Automobile (Kernel)
    [13]                           class()                 Automobile (Kernel)
    [14]                           clone()                 Automobile (Kernel)
    [15]         define_singleton_method(*arg1)            Automobile (Kernel)
    [16]                         display(*arg1)            Automobile (Kernel)
    [17]                             dup()                 Automobile (Kernel)
    [18]                            edit(name)             Automobile (Looksee::ObjectMixin)
    [19]                        enum_for(*arg1)            Automobile (Kernel)
    [20]                            eql?(arg1)             Automobile (Kernel)
    [21]                          equal?(arg1)             Automobile (BasicObject)
    [22]                          extend(*arg1)            Automobile (Kernel)
    [23]                          freeze()                 Automobile (Kernel)
    [24]                         frozen?()                 Automobile (Kernel)
    [25]                            hash()                 Automobile (Kernel)
    [26]                initialize_clone(arg1)             Automobile (Kernel)
    [27]                  initialize_dup(arg1)             Automobile (Kernel)
    [28]                         inspect()                 Automobile (Kernel)
    [29]                   instance_eval(*arg1)            Automobile (BasicObject)
    [30]                   instance_exec(*arg1)            Automobile (BasicObject)
    [31]                    instance_of?(arg1)             Automobile (Kernel)
    [32]      instance_variable_defined?(arg1)             Automobile (Kernel)
    [33]           instance_variable_get(arg1)             Automobile (Kernel)
    [34]           instance_variable_set(arg1, arg2)       Automobile (Kernel)
    [35]              instance_variables()                 Automobile (Kernel)
    [36]                           is_a?(arg1)             Automobile (Kernel)
    [37]                        kind_of?(arg1)             Automobile (Kernel)
    [38]                              ls(*args)            Automobile (Looksee::ObjectMixin)
    [39]                            make()                 Automobile
    [40]                           make=(arg1)             Automobile
    [41]                          method(arg1)             Automobile (Kernel)
    [42]                         methods(*args)            Automobile (Object)
    [43]                           model()                 Automobile
    [44]                          model=(arg1)             Automobile
    [45]                            nil?()                 Automobile (Kernel)
    [46]                       object_id()                 Automobile (Kernel)
    [47]                  pretty_inspect()                 Automobile (Kernel)
    [48]                    pretty_print(q)                Automobile (PP::ObjectMixin)
    [49]              pretty_print_cycle(q)                Automobile (PP::ObjectMixin)
    [50]            pretty_print_inspect()                 Automobile (PP::ObjectMixin)
    [51] pretty_print_instance_variables()                 Automobile (PP::ObjectMixin)
    [52]                 private_methods(*args)            Automobile (Object)
    [53]               protected_methods(*args)            Automobile (Object)
    [54]                             pry(*object, *hash)   Automobile (Object)
    [55]                   public_method(arg1)             Automobile (Kernel)
    [56]                  public_methods(*args)            Automobile (Object)
    [57]                     public_send(*arg1)            Automobile (Kernel)
    [58]                     respond_to?(*arg1)            Automobile (Kernel)
    [59]             respond_to_missing?(arg1, arg2)       Automobile (Kernel)
    [60]                            send(*arg1)            Automobile (Kernel)
    [61]                 singleton_class()                 Automobile (Kernel)
    [62]               singleton_methods(*args)            Automobile (Object)
    [63]                           taint()                 Automobile (Kernel)
    [64]                        tainted?()                 Automobile (Kernel)
    [65]                             tap()                 Automobile (Kernel)
    [66]                         to_enum(*arg1)            Automobile (Kernel)
    [67]                            to_s()                 Automobile (Kernel)
    [68]                           trust()                 Automobile (Kernel)
    [69]                            type()                 Automobile
    [70]                           type=(arg1)             Automobile
    [71]                         untaint()                 Automobile (Kernel)
    [72]                         untrust()                 Automobile (Kernel)
    [73]                      untrusted?()                 Automobile (Kernel)
]

Use ‘pry’ to dig deeper into the method

Use the ‘stat’ function in pry to find further info about a specific method. Also use ‘show-source’ to pull up the source code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
binding.pry

#'stat' and 'show-source' only work in the pry environment

[1] pry(main)> stat car.make
Method Information:
--
Name: make
Alias: None.
Owner: Automobile
Visibility: public
Type: Bound
Arity: 0
Method Signature: make()
Source Location: example.rb:2
[2] pry(main)> show-source car.make

From: example.rb @ line 2:
Owner: Automobile
Visibility: public
Number of lines: 1

attr_accessor :make, :model, :type
[3] pry(main)>

Hashes as Method Arguments

After trudging through rails for a couple of weeks now, one of the most confusing patterns for me is how hashes are passed as arguments without being bookended with curly braces. For example:

1
2
3
4
5
# What is going on here.
# Are there 2 arguments consisting of a string and a hash? 
# Or are there 3 arguments consisting of a string and 2 hashes?

link_to "home", :controller => "page", :action => "index"

I thought the answer would lie in some weird rails convention, but to my surprise, the practice is rooted in Ruby.

It turns out that in Ruby if you call a method and pass in a hash as the last argument, it is acceptable to write the hash without the curly braces. So, if you follow this rule, and you sprinkle in a few key-value pairs, Ruby will interpret all of the key-value pairs as one hash.

1
2
3
4
5
6
7
8
9
10
#Method with 1 argument

def some_method(a)
  puts a.class
  puts a
end

some_method a:1, b:2, c:3
#=> Hash
#=> {:a=>1, :b=>2, :c=>3}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#Method with 2 argument

def some_method(a,b)
  puts a.class
  puts a
  puts b.class
  puts b
end

some_method "words", a:1, b:2, c:3
#=> String
#=> words
#=> Hash
#=> {:a=>1, :b=>2, :c=>3}
1
2
3
4
5
6
7
8
9
10
11
#Method with 2 argument

def some_method(a,b)
  puts a.class
  puts a
  puts b.class
  puts b
end

some_method a:1, b:2, c:3, "words"
#=> syntax error, unexpected '\n', expecting tASSOC

As you can see in the last example, Ruby will throw a syntax error if you pass in a hash without curly braces when the hash is not the last argument.

But as I was eager to address the error of the missing curly braces, I encounted another error that I was not expecting:

1
2
3
4
5
6
7
8
9
10
11
#Method with 2 argument

def some_method(a,b)
  puts a.class
  puts a
  puts b.class
  puts b
end

some_method {a:1, b:2, c:3}, "words"
#=> syntax error, unexpected tINTEGER, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END

By adding curly braces, Ruby interpreted the hash as a block and complained when the syntax inside the braces did not match that of a block. This error can be easily solved by enclosing all of the arguments inside parentheses and leads to the conclusion that when you are passing a hash as the first of many arguments inside of a method, you must enclose the whole argument list within parentheses.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#Method with 2 argument

def some_method(a,b)
  puts a.class
  puts a
  puts b.class
  puts b
end

some_method({a:1, b:2, c:3}, "words")
#=> Hash
#=> {:a=>1, :b=>2, :c=>3}
#=> String
#=> words

Customize Your Bash Prompt

Like most rails developer, I spend a good chunk of time navigating around my files using bash everyday. I thought it’d be worth it to spend a couple of hours and learn how to customize an application that I will be using for years to come.

To make changes, locate your “.bash_profile” file and search in it for “PS1”. You will assign a string to the PS1 variable and what goes inside the string dictates what will be displayed in bash.

First off, whatever you put inside the string will be displayed unless you include special escape characters. For example, if you assign:

1
export PS1 = "Prompt >> "

you will get the following prompt display:

However, if you want your prompt to look like this:

you will have to learn a few escape characters. (Note: this list is non-comprehensive, I’ve included the ones I’ve found useful.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
\d : the date in "Weekday Month Date" format (e.g., "Tue May 26")

\D{format} :  the format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-specific time representation. The braces are required

\e : an ASCII escape character (033)

\h : the hostname up to the first '.'

\H : the hostname

\j : the number of jobs currently managed by the shell

\l : the basename of the shell’s terminal device name

\n : newline

\t : the current time in 24-hour HH:MM:SS format

\T : the current time in 12-hour HH:MM:SS format

\@ : the current time in 12-hour am/pm format

\A : the current time in 24-hour HH:MM format

\u : the username of the current user

\w : the current working directory, with $HOME abbreviated with a tilde

\W : the basename of the current working directory, with $HOME abbreviated with a tilde

\\ : a backslash

\[ : begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt

\] : end a sequence of non-printing characters

Try sticking a few of the escape characters into the string you assign to PS1 and see what each does to your prompt.

If you want to take your prompt to the next level, you can add some color. In the code below, replace the parentheses and the content inside the parentheses with the characters you want to display. (I’ve added a leading and trailing space for clarity, they should be removed when you sub in your characters.) You change the color by replacing the ‘#’ with a number between 0 and 256.

1
\e[38;5;#;48;5;#m (your characters go here!) \e[00m

To change your text color, change the ‘#’ following ‘38;5;’.

To change you background color, change the ‘#’ following ‘48;5;’.

Here are a couple of color tables, both have the exact same color for each number.

text color table background color table

The color escape sequence may look daunting, but if you can spot the pattern, you can easily get the output you desire.

The PS1 string for my customized prompt is:

1
export PS1 = "\n[\e[38;5;81;48;5;17m\$PWD/\e[00m](\e[38;5;81;48;5;17m\t\e[00m)\n\e[38;5;46m\e[00m "

(You can type the apple logo () by pressing shift + alt + k)

What the Heck Is a Spaceship Operator?

While reading The Well-Grounded Rubyist I came across the perhaps the coolest sounding term in the Ruby language – the spaceship operator, aka “<=>”. How it functions is quite simple, as shown in the code below:

1
2
3
4
5
6
7
2 <=> 3 #=> -1
2 <=> 2 #=> 0
2 <=> 1 #=> 1

"b" <=> "c" #=> -1
"b" <=> "b" #=> 0
"b" <=> "a" #=> 1

Basically the operator returns “1” if the object on left of the operator is greater than the object to the right, “-1” is returned if the left object is less than the right object, and “0” is returned if the left object is equal to the right object.

But, the duties of the spaceship operator does not just end with operating on strings and numbers, it has much deeper implications on the Ruby language. When you want to compare objects of the same class, you include the Comparable module in the class and then redefine the spaceship method. I will demonstrate the process in the following code sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Baller
  include Comparable

  attr_accessor :rank
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def <=>(player)                   # 'player' is an arbitrary name for a variable.  
    if self.rank < player.rank      # It is necessary to name the object you are  
      1                             # comparing self with.
    elsif self.rank > player.rank
      -1
    else
      0
    end
  end

end

kb = Baller.new("Kobe Bryant")
kb.rank = 2

mj = Baller.new("Michael Jordan")
mj.rank = 1

lj = Baller.new("LeBron James")
lj.rank = 3

puts mj > kb #=> true
puts kb < lj #=> false

As you can see, even though mj has a rank of 1 and kb has a rank of 2 and numerically speaking 2 is greater than 1, the outcome does not reflect that. By redefining the spaceship method, I changed the meaning of “>” and “<” to evaluate to the exact opposite of what they traditionally do, they now evaluate to “greater than” and “less than” based on ordinal value rather than numerical value.

(And yes, I did put Kobe ahead of LeBron.)

5 Reasons Why I’m Learning to Code

  1. It’s useful - you can barely pass a day without encountering some object that runs on software. If you are reading this on a computer, tablet or phone, then there is not much more I need to explain.

  2. It’s empowering - In life, there is very little that you can have control over, but if you learn to code, you can have full control over a computer. The computer is arguably the epitome of human civilization, and it feels pretty good to be able to manipulate it however you please.

  3. Better early than later - Coding is neither easy nor impossible, but it take years to master. So, if you’ve already agreed that coding is useful and empowering, why delay learning it.

  4. It expands your perspective - once you’ve gotten some coding under your belt, you can begin to infer how the different pieces of technology around you function. Twitter and Facebook won’t seem like they function by magic anymore.

  5. It’s fun. It’s always an adventure when you learn something new.