Ruby.Metaprogramming. class_eval

前端 未结 5 679
孤独总比滥情好
孤独总比滥情好 2020-12-18 16:50

There seem to be a mistake in my code. However I just can\'t find it out.

class Class
def attr_accessor_with_history(attr_name)
  attr_name = attr_name.to_s
         


        
5条回答
  •  情歌与酒
    2020-12-18 17:27

    Solution:

    class Class
      def attr_accessor_with_history(attr_name)
        ivar         = "@#{attr_name}"
        history_meth = "#{attr_name}_history"
        history_ivar = "@#{history_meth}"
    
        define_method(attr_name) { instance_variable_get ivar }
    
        define_method "#{attr_name}=" do |value|
          instance_variable_set ivar, value
          instance_variable_set history_ivar, send(history_meth) << value
        end
    
        define_method history_meth do
          value = instance_variable_get(history_ivar) || []
          value.dup
        end
      end
    end
    

    Tests:

    describe 'Class#attr_accessor_with_history' do
      let(:klass)     { Class.new { attr_accessor_with_history :bar } }
      let(:instance)  { instance = klass.new }
    
      it 'acs as attr_accessor' do
        instance.bar.should be_nil
        instance.bar = 1
        instance.bar.should == 1
        instance.bar = 2
        instance.bar.should == 2
      end
    
      it 'remembers history of setting' do
        instance.bar_history.should == []
        instance.bar = 1
        instance.bar_history.should == [1]
        instance.bar = 2
        instance.bar_history.should == [1, 2]
      end
    
      it 'is not affected by mutating the history array' do
        instance.bar_history << 1
        instance.bar_history.should == []
        instance.bar = 1
        instance.bar_history << 2
        instance.bar_history.should == [1]
      end
    end
    

提交回复
热议问题