12/08/2018, 13:45

Some Obscures Features and Tricks of Ruby

In this post I will try to go into some obscure structures and syntax that I find interesting. I think most ruby on rails developers already know a big portion of what I am going to write, but It will be a chance to bring it out and present it here again so that you can refresh it all over again. ...

In this post I will try to go into some obscure structures and syntax that I find interesting.

I think most ruby on rails developers already know a big portion of what I am going to write, but It will be a chance to bring it out and present it here again so that you can refresh it all over again.

It was not long ago that I have begun to look more into Ruby and Rails source code, which are quite fascinating.

Prevent JSON of self-reference

This may be not so useful in term of application but I found it quite intriguing in term of logic and elegance.

Suppose you start by:

x = {}        => {}
y = {x: x}    => {:x=>{}}
Here how thing get interesting. Suppose now you add:
x[:y] = y     => {:x=>{:y=>{...}}}

Now you have a hash with infinite depth which references to itself Let's create a method to find the depth of the hash just created

class Hash
    def depth
        a = self.to_a
        d = 1
        while (a.flatten!(1).map! {|e| (e.is_a? Hash) ? e.to_a.flatten(1) : nil}.compact!.size > 0)
            d += 1
            p a
            puts d
        end
        d
    end
end

I warn you that your computer might crash... haha. You never reach the bottom of the hash! Pretty amazing, isn't it? Press Ctrl + C to exit the loop.

Ruby knows about this danger so it prevents creating json with circular reference. If you try to run

require 'json'
x.to_json you will get this error "JSON::NestingError: nesting of 100 is too deep"

All are Singleton classes except Fixnums and Symbols

We know that everything in ruby is object, but not every object have singleton class of its own, and those are Fixnums and Symbols. The reason why it does not have singleton class because They are immediate value which means they are stored as themselves in memory rather than a pointer to a data structure for efficiency reason.

If you tried to create a singleton class for Fixnums for example, it will throw

a = 2
class << a
    def abc
        "1"
    end
end
=> TypeError: can't define singleton

I think this is also that we can't create singleton class of Fixnum or else something really weird might happen.

a = 2
class << a
    def + (b)
        b - self
    end
end

a + 2 would equal 0. It is so confusing to see something like this.

What about singleton class of true, false and nil? Interesting enough they are the only instance of TrueClass, FalseClass and NilClass respectively. It is logical that their singleton class are their very own class.

So if you were to write:

class << true
    self
end

or simply

true.singleton_class

It will return TrueClass Also:

false.singleton_class
=> FalseClass
nil.singleton_class
=> NilClass

Metaid

I think it all useful to mention about an awesome snippet written by someone with the nickname 'why the lucky stiff'. The file is name metaid.rb

class Object
    # The hidden singleton lurks behind everyone
    def metaclass
        class << self
            self
        end
    end

    def meta_eval &blk
        metaclass.instance_eval &blk
    end

    # Adds methods to a metaclass
    def meta_def name, &blk
        meta_eval { define_method name, &blk }
    end

    # Defines an instance method within a class
    def class_def name, &blk
        class_eval { define_method name, &blk }
    end
end

OK, Let's see what the methods above do metaclass surely defines singleton class of an object. meta_eval is equivalent to class_eval for singleton classes. meta_def define method for the receiver's singleton class. class_def define instance method for the receiver.

With this new methods we can create something like this

Look up Method from console

I am sure you will meet a situation in which you are in the middle of testing your code in the console and you need to look up a method definition of a particular class or editing an existing file or writing a new file.

suppose we have models:

class Stock < ApplicationRecord
    def new
    end

    def self.add
        puts "add stock"
    end
end

we are in the console. we are testing if the model works well and now we now we want to take a look at a particular method, for example, add

method = Stock.instance_method(:add)

Here we objectify the method. Now we can get the source_location of the method by:

location = method.source_location

OK, Let's use a text editor to open the source code, here I use sublime text. You can use other text editor.

`subl #{location[0]}:#{location[1]}`

It will open straight to the method you looking for.

We can create a method below to easier use later:

def source_code(object, method_symbol)
    if object.respond_to?(method_symbol, true)
      method = object.method(method_symbol)
    elsif object.is_a?(Module)
      method = object.instance_method(method_symbol)
    end
    location = method.source_location
    `subl #{location[0]}:#{location[1]}` if location
rescue
    nil
end

You see that we add object.is_a?(Module) to account for class method.

Now we can look into the method by typing:

source_code(Stock, :add)
source_code(Stock.new, :new)

I personally really like this method. You can imagine the convenience of looking into the rails source code itself. Wicked, isn't it?

I hope you enjoyed and learn something from this.

0