48 Specific ways to write better ruby
杰瑞发布于2025-03-04
48 Specific ways to write better ruby
- 28. 模块和类的钩子方法:
Ruby的hook在类和模块的级别实现元编程。在类和模块中定义方法-单例方法。混合引入模块时,ruby都会调用钩子方法included or extended;这个钩子可以看作是一个,通知通知当前模块即将要被扩展到另一个类中。代理的方法只是重定向了。interited; method_added method_removed method_undefined 实例方法;singleton_method_added singleton_method_remove singleton_mothod_undefined 可以被用于模块方法或类方法。这些方法只接受一个symbol ,方法名; Triggers singleton_method_removed(:hello) class << self; remove_mothod(hello);end- 30.define_method or method_missing:
如果没有找到任何方法,method_missing就会被执行;但是因为又super的原因,这里会有迷惑。def method_missing(name, *args, &block) if @hash.respond_to?(name) @hash.send(name, *args, &block) else super end end; Hash.public_instance_methods(false).each do |name| define_method(name) do |*args, &block| @hash.send(name, *args, &block) end; h.public_methods(false).sort.take(5); 实现了Hash的方法。
AuditDecorator @logger = Logger.new($stdout); private def method_messing(name, *arg, &block) @logger.info("calling '#{name}' on #{@object.inspect}"); @object.send(name, *args, &block); define_method更加适合做这个了。 mod=Module.new do object.public_methods.each do |name| define_method(name) do |*args, &block| @logger.info("") @object.send(name, *args, &block) end end end extend(mod) ; 创建了一个匿名的模块。 —— define_method恢复了内省方法。。 respond_to? and respond_to_missing?- 31. eval; instance_eval定义的是单例方法;:
def glass_case_of_emotion x="I'm in a " + __method__.to_s.tr('_',' ') binding; binding 可以获得当前的临时域并把这个临时域封装到Binding对象中作为返回结果。这个指定的上下文是eval方法的第二个参数; eval("x", glass_case_of_emotion); class_eval很像是重新打开类,实际上是被定义在Module里面,only被模块和类使用。= moudle_eval; instance_eval访问实例变量;class_eval定义实例方法。 class Widget attr_accessor(:name, :quantity) def initialize(&block) instance_eval(&block) if block end ;;; w= Widget.new do |widget| widget.name= "Elbow Grease" ; @quantity = 0; end ; instance_exec, class_exec, moudle_exec; only accept 代码块, no string; object.instance_eval("@#{name} = DEFAULT")
module Reset def self.reset_var (object, name) object.instance_exec("@#{name}.to_sym") do |var| const = self.class.const_get(:DEFAULT); instance_variable_set(var, const) end ...- 38. Mock模拟对象 define一个method,并模仿mock需要调用的特定对象;:
def alive? echo = Time.now.to_f.to_s response = get(echo) response.success? && response.body ==echo end; private get(echo) url=RUI::HTTP.build(host:@server, path: "/echo/#{echo}") HTTP.get(url.to_s) end
monitor = Monitor.new("example.com"); response = MiniTest::Mock.new ; monitor.define_singleton_method(:get) do |echo| response.expect(:success? , true); response.expect(body, echo); response end assert(monitor.alive?, "should be alive") response.verify end; 用Mock格里外部系统不稳定因素;Mock#verify- 39.测试的重要性; fuzzbert and mrproper属性测试;SimpleCov 测试覆盖率 ZenTest监测代码:
尽可能的自动化测试;运行代码才知道代码在干啥;测试又happy path and exception path; fuzz testing and property testing; require('fuzzbert') require('uri') fuzz('URI::HTTP:build') do data("random server names") do FuzzBert::Generators.random end deploy do |data| URI::HTTP.build(host: data, path: '/') end 会持续运行,手动停止。 MrProper; properties("Version") do data([Integer, Integer, Integer]); property("new(str).to_s == str") do |data| str= data.join('.'); assert_equal(str, Version.new(str).to_s); 测试驱动开发里面的测试并不好写,- 48.memoization优化模式: