Use class_eval and instance_eval

current object and current class

Everything is an object in Ruby, there is an current object and current class referred to in every line of code. We use self to refer to current object (there is no keyword for current class).

When call a method on an object, self(current object) is the receiver of the method. In a class definition, self(current object) is the class itself.

Though there is no keyword for current class, it’s easy to refer to as long as we know what is our current object.

class_eval

Module#class_eval is used for modifying current class. It’s commonly used when we don’t know the exact name of class we want to refer to. For example,

def add_method_to(my_class)
  my_class.class_eval do
    def foo
      puts 'foo'
    end
  end
end
			
add_method_to(String)
"bar".foo
#=> "foo"

One example in Rails is putting common code for several models (just like what model conern does). For example, I want to add common validations for my models, I can create a module and use class_eval to add methods in classes that include it. In order to get that class, we need a hook method self.included, and put class_eval part inside this method.

module SomeCommonModule
  def self.included(base)
    base.class_eval do
      validates_presence_of :balabalabala
    end
  end
end

instance_eval

instance_eval is used for modifying current object (self), it breaks encapsulation, be careful with it.

An example is to change instance variable of an object:

class Foo
  def bar
    @bar = "bar"
  end
end

foo = Foo.new
foo.bar
puts foo.instance_eval { @bar }
 #=> "bar"
foo.instance_eval { @bar = "bbbbar" }
puts foo.instance_eval { @bar }
 #=> "bbbbar"

Simple Functional Programming in Ruby and Javascript

In Ruby, methods like map, reject, reduce are very handy to use. Recently, I came across Javascript functional programming, I found there are similar usages in Javascript.

map

map is used to transform an array into another

Here’s a simple example in Ruby, it accepts a block as parameter:

arr = ['m', 'o', 'n', 'k', 'e', 'y']
arr.map {|x| x + '1'}
 #=> ["m1", "o1", "n1", "k1", "e1", "y1"]

In Javascript, map accepts another function as a parameter, here is an example:

var arr = ['m', 'o', 'n', 'k', 'e', 'y'];
var arr2 = arr.map(function(x) {
  return x + '1';
});
console.log(arr2); 
// [ 'm1', 'o1', 'n1', 'k1', 'e1', 'y1' ]

In ES6, you can also do this with arrow function, which is much similar to Ruby way:

var arr = ['m', 'o', 'n', 'k', 'e', 'y'];
var arr2 = arr.map((x) => x + '1');
console.log(arr2);
// [ 'm1', 'o1', 'n1', 'k1', 'e1', 'y1' ]

reduce

reduce comes very handy to apply an operator on enumerable elements

Here is an example of reduce in Ruby, it takes an initial value and a block applying operation on element

arr = [1, 2, 3, 4, 5]
arr.reduce(0) {|sum, x| sum += x}
 #=> 15

reduce can also accept a symbol as a parameter, initial value is default set to 0 for :+, 1 for :*

arr = [1, 2, 3, 4, 5]
arr.reduce(:+)
 #=> 15

In Javascript, you can do this, the first parameter is a function that applies the operator, return value will be the next parameter that this function accepts, the second parameter is initial value:

var arr = [1, 2, 3, 4, 5];
var arr2 = arr.reduce(function(sum, x) {
  return sum + x;
}, 0);
console.log(arr2);
// 15

In ES6, you can do this, also I prefer this way as a Ruby programmer:

var arr = [1, 2, 3, 4, 5];
var arr2 = arr.reduce((sum, x) => sum + x, 0);
console.log(arr2);
// 15

\(^∀^)メ(^∀^)ノ

Let’s have more fun in functional programming


Using Concern To Refactor Rails Model

Background

Recently I’m working on upgrading a Rails 2.3 application to Rails 4.2 (Yes, it’s true, our company is still using 2.3 now, ( ‘Θ’)ノ( ‘Θ’)ノ( ‘Θ’)ノ). There are 5 models containing codes which are 90% the same. I tried to refactor them with Rails 4’s concern module.


What is concern

Rails 2.3 way

In Rails 2.3, if you extract code from model to a module, you need to create a module and put it into your /lib directory. To realize validations and class methods, you need to add a hook method in it, which was not an elegant way.

module Taggable
  def  self.included(base)
    base.extend ClassMethods
    base.class_eval do
      scope :disabled, -> { where(disabled: true) }
      # scope, validations, after_save .....
    end
  end

  module ClassMethods
    def find_with_tag(tag)
	 # .....
    end
  end
end

Realization with concern

In Rails 4, you can eaily realize it by creating a module extending ActiveSupport::Concern and include this module in your model.

module Taggable
  extend ActiveSupport::Concern
  included do
    scope :disabled, -> { where(disabled: true) }
  end
  
  class_methods do
    def find_with_tag(tag)
	 # ...
    end
  end
  
  #put instance methods here
end

Notice

  • If you want to know which class is using this module in a class method, you can simply call self. For example, I want to cache class method find, then in my taggble module, I use
class_methods do
  def some_class_method(id)
    Rails.cache.fetch("#{self.name}.find(#{id})", :expires_in => 15.minutes.to_i)
  end
end
  • If it’s in an instance method, use self.class instead
def some_instance_method(id)
  Rails.cache.fetch("#{self.class.name}.find(#{id})", :expires_in => 15.minutes.to_i)
end

And the code is more elegant (^m^ )クスッ.


Adjective Transformation in German

These days I was learning German grammar of transforming adjective. I learnt so many rules like, when the non which you describe is a accusative, if it’s male word append en, if it’s female or plural append e, if it’s neutral append es. But when the article is meine or keine and the word is plural, append en For nominative and dative phrase …..

Okay… My mood turns into (´Д`;)/ヽァ・・・

So I made a small program in Python to help me ‘remember’ which transformation of adjective to use (ノД`)ハァ.

def adj_transformation(adj, article, sex, case, plural):
    if case == 'accusative':
        if sex == 'male':
            adj += 'en'			
        elif sex == 'female' or plural:
            adj += 'e'
    	elif sex == 'neutral':
    	    adj += 'es'
    	elif (article == 'meine' or 'keine') and plural:
    	    adj += 'en'
    elif case == 'nominative':
     	if sex == 'male':
            adj += 'er'
    	else:
    	    adj
    elif case == 'dative':
      	adj += 'en'
    return adj

adj = input('input adjective, regular transaformation only: ')
article = input('input article between ein, eine, keine, meine: ')
sex = input('choose sex of the non bwtween male, female, neutral: ')
case = input('choose case between nominative, dative, accusative: ')
plural = input('input 1 for plural, 0 for non-plural:')

target_adj = adj_transformation(adj, article, sex, case, plural)
print('correct transformation for ', adj, ' is ', target_adj)

If I want to know the correct form of alt (old) in the sentence Er is ein (alt) Mann, run this program:

input adjective, regular transaformation only: alt
input article between ein, eine, kine, meine: ein
choose sex of the non bwtween male, female, neutral: male
choose case between nominative, dative, accusative: nominative
input 1 for plural, 0 for non-plural:0
correct transformation for  alt  is  alter

The result will shown in your terminal, correct transformation for alt is alter

Now I have a ‘German mind’ へ(´∀`へ)ヨイヨイ♪(ノ´∀`)ノヨイヨイ♪.


国内网页应用开发CDN链接被墙的应对方法

自从lantern被墙,换了新的vpn以来,从google cdn, bootstrap cdn, cloudflare cdn加载资源速度变得超慢,请求CDN资源能花上半分钟,超级令人不爽(`‐●_‐´怒)。

解决方法有:

  1. 把资源下载下来放在专门存放静态文件的文件夹中
  2. 如果网站主要面向的是国内的用户,换成国内的CDN也无妨。
  3. vpn开成全局模式。

如果国内的CDN的话可以用:

  • http://www.bootcdn.cn/ 流行的js库和css框架基本上都有

  • 新浪和微软的CDN资源也很全,网上搜一搜就会有具体的资源地址

如果还是速度很慢的话, 一定是你家的宽带有问题啊ああああああああ (´¬O¬)


   Tags
programming ( 13 )
中文 ( 2 )
language-learning ( 1 )
life ( 1 )
python ( 1 )
aws ( 2 )
study-note ( 2 )

About Me

I'm Yiwen, a web developer based in Tokyo, and I'm looking forward to opportunities in a international environment.