Some Obscures Features and Tricks of Ruby
Bài đăng này đã không được cập nhật trong 8 năm
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.
All rights reserved