美文网首页
Ruby tips: patch on singleton_cl

Ruby tips: patch on singleton_cl

作者: davidhuangdw | 来源:发表于2014-11-29 20:52 被阅读31次

问题

如何实现以下stub方法:

user = User.new
user.login?          #=> false

user.stub(:login?){ 'totally tubbed' }
user.login?          #=> 'totally stubbed'

User.new.login?      #=> false

分析

不能直接patch在当前对象的类上,需要patch在当前对象的singleton_class上:

module Stubber
  extend self
  def mystub(method, to:nil, &blk)
    singleton = class << to||self; self end
    singleton.send(:define_method, method, &blk)        # define_method is private for singleton_class: use 'send' to bypass
  end
end

注意:

  1. 可以用class<<obj; self end取到singleton_class
  2. singleton_class的define_method是私有的,得用.send(:define_method,*args)

测试代码:

require_relative '../stubber'
require 'ostruct'

shared_examples_for 'stubbed' do
  it "should stub obj" do
    expect(after_stub.name).to eq 'stub'
    expect(other_obj.name).not_to eq 'stub'
  end
end

describe Stubber do
  let(:obj) {OpenStruct.new(name:'obj')}
  let(:other_obj) {OpenStruct.new(name:'obj')}
  let(:after_stub) do
    Stubber.mystub(:name, to:obj){ 'stub'}
    obj
  end
  it_behaves_like 'stubbed'

  context "when include Stubber in a class" do
    let(:foo_class) do
      Class.new do
        include Stubber
        def name; 'foo' end
      end
    end
    let(:obj) {foo_class.new}
    let(:other_obj) {foo_class.new}
    let(:after_stub) do
      obj.mystub(:name){'stub'}
      obj
    end
    it_behaves_like 'stubbed'
  end
end

相关文章

网友评论

      本文标题:Ruby tips: patch on singleton_cl

      本文链接:https://www.haomeiwen.com/subject/fskgtttx.html