0
Posted on Tuesday, September 04, 2018 by 醉·醉·鱼 and labeled under

You have a class with a class method. Write a module that, when included, will override that class method.


在这篇文章里面已经介绍了一种方法 http://tech.tulentsev.com/2012/02/ruby-how-to-override-class-method-with-a-module/,但我还可以分享另外的方法。


方法一:用instance_eval。原文中的方法。

module BooModule
  def self.included base
    base.instance_eval do
      def bar
        puts "module"
      end
    end
  end
end

class KlassC

  def self.bar
    puts 'class'
  end
end

KlassC.send(:include, BooModule)

KlassC.bar #=> module
p KlassC.ancestors

方法二:用 class << base ; end


module TooModule
  def self.included base
    class << base
      def bar
        puts "module"
      end
    end
  end
end

class KlassD

  def self.bar
    puts 'class'
  end
end

KlassD.send(:include, TooModule)

KlassD.bar #=> module
p KlassD.ancestors

方法三:用prepend。如果你知道extend实际上就是class << base; include ClassMethods end的话,你就很好理解为啥prepend在这里可以起作用了。前两者都是直接修改类方法,而这直接通过修改继承链的方法去覆盖类方法。


module GooModule
  def self.included base
    class << base
      prepend ClassMethods
    end
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassE
  def self.bar
    puts 'class'
  end
end

KlassE.send(:include, GooModule)

KlassE.bar #=> module
p KlassE.ancestors


能够直接用prepend么?不行。你可以试试下面的例子。虽然说,被prepend的module会放到class的继承链的下方,但实际上,类方法却不受影响。


module FooModule
  def self.included base
    base.extend ClassMethods
  end

  def self.prepended base
    base.extend ClassMethods
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassA
  include FooModule

  def self.bar
    puts 'class'
  end
end


KlassA.bar #=> class
p KlassA.ancestors

class KlassB
  prepend FooModule

  def self.bar
    puts 'class'
  end
end


KlassB.bar #=> class
p KlassB.ancestors
0
Posted on Tuesday, September 04, 2018 by 醉·醉·鱼 and labeled under
最新的5.11.3 minitest不知道为什么,在verbose模式下,把对应的测试 用例的名字给抹掉了。这样的话,导致分析测试用例performance的时候,非常得不友好。

https://github.com/seattlerb/minitest/blob/master/lib/minitest.rb#L617


    def record result # :nodoc:
      io.print "%.2f s = " % [result.time] if options[:verbose]
      io.print result.result_code
      io.puts if options[:verbose]
    end
  end

将上述代码替换成下面代码,就可以看到某个test用掉多少时间。

    def record result # :nodoc:
      io.print "%s#%s = %.2f s = " % [result.klass, result.name, result.time] if options[:verbose]
      io.print result.result_code
      io.puts if options[:verbose]
    end

输出
Run options: -n test_viewing_transaction --verbose --seed 39465

# Running:

TransactionsControllerTest#test_viewing_transaction = 6.13 s = .

Finished in 7.851562s, 0.1274 runs/s, 0.1274 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips