• #24 楼 @chenge 可以,我没想太多随便写的,你最好修改一下。ruby-china 没有站内信功能么。。。

  • attr_reader :title之后 title 返回的是@title,但是你你看Product.take.instance_variables里根本就没有@title,所以相当于你重写了 Product#title,使其返回一个不存在的@title

  • #12 楼 @reus 因为 Python 中的 foo 跟 foo() 不是一个东西,所以用 Python 写起来更自然。 对方法的引用 Python 是 foo,而 Ruby 是 self.method(:foo),其间并没有另外创建或者包装,因为这个 method object 实际就存在,只是通过一种很不 python 的方式取 (既 self.method(:foo))。 同样,调用一个作为参数的方法 Python 也更简单,加个括号foo()就行了,Ruby 就只能傻傻的 call 了,但是我认为本质都是一样的,只是 python 的马甲 (语法糖) 更好看一些就是了。

    不过话说回来,个人认为修饰器不是很 Ruby way,如#6 楼所说,当你用 Ruby 怀念修饰器的时候,肯定有别的更合适的方案,就算非要用修饰器,自己写一个满足自己需求的也不是很难,一楼已经证明。

  • #10 楼 @chenge 就是想说 ruby method 一样可以是对象,可以当参数传进别的方法。但是本质上没什么用,send 就已经很好用了。

  • #7 楼 @reus 这样算不算可以被引用的对象

    def hello method
        puts "hello, #{method.name}"
        method.call
        puts "goodby, #{method.name}"
    end
    
    def foo
        puts "i am foo"
    end
    
    hello method(:foo)
    
  • #3 楼 @reus Ruby method 可以是对象 http://www.ruby-doc.org/core-2.1.1/Method.html 顺便山寨一下 makeHtmlTag 那个例子

    module Decrorator
    
        def wrap method_name
            WarppedObj.new method_name, self
        end
    
        class WarppedObj
    
            def initialize method_name, context
                @method_name = method_name
                @context = context
                context.class_eval do 
                    @@_warped_counter ||= {}
                    @@_warped_counter[method_name] ||= 0
                end
            end
    
            def with method_name, *args
                warpped_method = @method_name
                @context.class_eval do
                    @@_warped_counter[warpped_method] += 1
                    alias_method :"#{@@_warped_counter[warpped_method]}_#{warpped_method}", warpped_method
                    i = @@_warped_counter[warpped_method]
                    define_method warpped_method do |*_args, &_blk|
                        ret = __send__ :"#{i}_#{warpped_method}", *_args, &_blk                 
                        __send__(method_name, *args) {ret}
                    end
                end
            end
        end
    
    end
    
    
    class HTMLHelper
        extend Decrorator
    
        def makeHtmlTag tag, opts
            "<#{tag} #{opts.map {|key, value| %Q{#{key}="#{value}"}}.join(' ')}>" + yield + "</#{tag}>"
        end
    
        def hello
            'hello world'
        end
    
        wrap(:hello).with :makeHtmlTag, 'i', class: 'italic_css'
        wrap(:hello).with :makeHtmlTag, 'b', class: 'bold_css'
    end
    
    puts HTMLHelper.new.hello # <b class="bold_css"><i class="italic_css">hello world</i></b>
    
  • 看看这道题怎么做, $SAFE=4 at 2014年03月20日

    log.group_by {|l| l[:time]}.values.map {|arr| arr.inject &:merge}

  • Module.class_variables + Module.class_variable_set

  • #3 楼 @diguage 按一楼说的方法把第一个 vm 导出来,然后第二个 vm 基于第一个 vm 导出的 box 文件建。

  • vagrant 的 box 跟你启动的 VM 好比类跟实例的关系。你新项目的 VM 跟你以前的 VM 是同一个 box 类的两个实例,所以你第一个 VM 装东西不会出现在第二个 VM 上。

  • vagrant package --output xxxx.box可以把你配置好的虚机导出来,然后用你导出来的 box 启一个 vm。

  • Callbacks 中的一些困惑 at 2014年01月28日

    attr_accessor :password相等于定义两个方法:

    def password
        @password
    end
    
    def password= p
       @password = p
    end
    

    如果用password = xxxx只是给一个局部变量赋值,self.password = xxxx才是调用第二个方法。password_salt 同理。如果单用password,那样不会有歧义,所以不需要加 self。

  • 元编程中验证的问题 at 2014年01月25日

    #3 楼 @engin123456789 顺手写了一下: 完整的 CheckAttr Module:

    module CheckAttr
        def self.included base
            base.extend ClassModule
            base.class_eval do
                def self.method_added method_name
                    if @_last_modified_method != method_name && method_name.to_s !~ /^_check_attr_/ && method_name.to_s !~ /=$/
                        @_last_modified_method = method_name
                        class_eval do
                            alias_method :"_check_attr_hacked_#{method_name}", method_name
                            define_method method_name do |*args, &blk|
                                ret = __send__(:"_check_attr_hacked_#{method_name}", *args, &blk)
                                instance_variables.each do |v| 
                                   method_name = :"#{v.to_s.gsub('@', '')}="
                                    __send__(method_name, instance_variable_get(v)) if respond_to? method_name
                                end
                                return ret
                            end
                        end
                    end
                end
            end
        end
    
        class InvalidAttributeError < Exception; end
    
        module ClassModule
            def attr_checked attr, &validate_block
                define_method "#{attr}=" do |value|
                    raise InvalidAttributeError.new("@#{attr}") unless validate_block.call value
                    instance_variable_set "@#{attr}",value
                end
    
                define_method attr do
                    instance_variable_get "@#{attr}"
                end
            end
        end
    
    
    end
    

    Usage:

    class Person
        include CheckAttr
        attr_checked :age do |v|
            v >= 18
        end
        attr_checked(:weight) {|v| v >= 40}
        def initialize name,age, weight
            @name = name
            @age = age
            @weight = weight
        end
    
        def lose_weight w
            @weight -= w
        end
    end
    
    #person1 = Person.new 'shiyj',16, 50 # raise: InvalidAttributeError: @age
    person2 = Person.new 'Fat Guy', 35, 200
    person2.lose_weight 180 # raise InvalidAttributeError: @weight
    

    大体就这思路,你可以再调整一下。 又或者你改一下你的思路,做成显示的验证,比如在执行 save 一类的时候验证,会方便高效许多。

  • 元编程中验证的问题 at 2014年01月25日

    #3 楼 @engin123456789 每个方法都加一遍验证一点都不过,我上面的代码稍微改动一下就行了,用 method_added 的钩子,自动 hack 每一个新加的方法,完成一遍验证。

  • 元编程中验证的问题 at 2014年01月23日

    不知道有没有@age=的时候能触发的 hook,不过根据你的需求可以实现在 initialize 的时候验证

    module CheckAttr
        def self.included base
            base.extend ClassModule
    
            base.class_eval do 
                def self.method_added method_name
                    if method_name == :initialize && !@_mark_
                        class_eval do
                            alias_method :original_initialize, :initialize
                            @_mark_ = true
    
                            def initialize *args, &blk
                                original_initialize *args, &blk
                                instance_variables.each do |v| 
                                   method_name = :"#{v.to_s.gsub('@', '')}="
                                    __send__(method_name, instance_variable_get(v)) if respond_to? method_name
                                end
                            end                        
                        end
                    end
                end
    
            end
    
        end
    
  • 准确的说应该是&会调用后面的东西的 to_proc 方法。

  • &:upcase 等于:upcase.to_proc,可以参考一下 Symbol#to_proc

  • proc 中的 return at 2014年01月06日

    #8 楼 @u1378130755 这段代码跟p = Proc.new { puts "hello test" ; return}等价,有什么问题么?

  • proc 中的 return at 2014年01月06日

    鼠标不好用……经常风怒

  • proc 中的 return at 2014年01月06日

    #3 楼 @u1378130755 p.call 是在这个 block 的作用域里执行 block 里面的代码,p 的作用域跟 test1 方法的作用域相同,所以里面的 return 跟在方法里 return 一样的。

  • proc 中的 return at 2014年01月06日

    #3 楼 @u1378130755 p.call 是在这个 block 的作用域里执行 block 里面的代码,p 的作用域跟 test1 方法的作用域相同,所以里面的 return 跟在方法里 return 一样的。

  • proc 中的 return at 2014年01月06日

    #3 楼 @u1378130755 这只是建了一个 Proc 对象,没执行 return,直到 call 了才会执行。

  • proc 中的 return at 2014年01月06日

    要用 block 里返回值要用 next,不是 return。

  • def generate_table operator
        1.upto(9) do |i|
            i.upto(9) {|j| print "#{i} #{operator} #{j} = #{i.send(operator, j)}\t"}
            print "\n"
        end
    end
    
    generate_table :+
    generate_table :-
    generate_table :*
    
  • :"xxx"相当于"xxx".to_sym,就像&:+相当于:+.to_proc

  • #4 楼 @fbsender 这里面的@@a是属于顶层Object类的类变量只是现象,不知道是什么原因。

    class A
        @@a = "It is @@a"
        def get_a
            puts @@a
        end
    end
    
    obj = A.new
    
    obj.get_a
    
    obj.singleton_class.class_eval do
        # 如果这里相当于Object.class_eval的话,为什么下面的get_a_singleton只属于obj?
        @@a = 1
    
        def get_a_singleton
            puts @@a
        end
    
    end
    
    obj.get_a_singleton
    

    不过 singleton_class 作为一个只有一个实例匿名的类想不出 class variable 能有什么作用,所以从使用的角度来说这种场景应该不会出现。

  • 因为前面的@@a 是 class A 的类变量,class << obj 里面的@@a 是 obj 的 singleton class 里的@@a,加上

    obj.singleton_class.class_eval do
        @@a = 1
    end
    

    这个@@a 才是 obj.get_a_singleton 能读到的@@a

  • 只学 ruby 的话很简单。要学 ror 的话,纯 ruby 的只是能占 40% 么……

  • ETL 工具都带这些功能吧