【问题标题】:How to I temporarily override print and puts from a class?如何临时覆盖课程中的打印和放置?
【发布时间】:2013-07-01 06:32:26
【问题描述】:

我正在为我的项目开发一个外壳。我希望 Shell 类在 shell 运行时覆盖所有打印功能,所以我这样做了:

# WARNING: Blocks until the user exits.
def start
  # Override Kernel print functions.
  master_print = Kernel.method :print
  master_puts = Kernel.method :puts

  Kernel.module_exec {
    define_method(:print) { |text = ""|
      self.send(:print_override, master_print, text)
    }
    define_method(:puts) { |text = ""|
      self.send(:puts_override, master_puts, text)
    }
    define_method(:puts_padded) { |text = ""|
      self.send(:puts_override, master_puts, "")
      self.send(:puts_override, master_puts, text)
      self.send(:puts_override, master_puts, "")
    }
  }

  # Readline loop and command parsing here...
end

只要只有Shell 类输出任何文本,这就会很好地工作,但只要命令类尝试puts,我就会明白:

NoMethodError: undefined method `puts_override' for #<AddressKit::CLI::Interactiv
e::Commands::LoadTable:0x000000027735b0>

我认为我上面写的 print 和 puts 块会留在这个范围内,而不是在它们碰巧被调用的范围内执行。有办法解决吗?


额外问题:我如何把原来的打印功能放回去?我已经计划好了:

Kernel.module_exec {
  define_method(:print, &master_print)
  define_method(:puts, &master_puts)
  undef_method(:puts_padded)
}

但我还没有尝试过,我不知道这是否会让Kernel 与我找到的完全一样。

【问题讨论】:

    标签: ruby ruby-2.0


    【解决方案1】:

    虽然块确实保留了作用域,但 self 是特殊的,它指的是运行该方法的实例(我假设是因为这更有用)。

    另一种策略是使用Kernel#puts 只执行$stdout.puts 的事实,因此不要覆盖puts,而是将$stdout 设置为您的一个类,这样可以在将值传递给@ 之前对其进行处理987654326@ 在前 $stdout 上。

    完成后,将$stdout 恢复为其原始值。

    【讨论】:

      【解决方案2】:

      好吧,我想我解决了这个问题,但我不确定它为什么会起作用。我猜测这些块既在调用它的范围内,也在定义它们的范围内,但前者的优先级更高。这意味着我不能使用 self 并期望它指向 shell。相反,我这样做了:

      shell = self
      
      Kernel.module_exec {
        define_method(:print) { |text = ""|
          shell.send(:print_override, master_print, text)
        }
        define_method(:puts) { |text = ""|
          shell.send(:puts_override, master_puts, text)
        }
        define_method(:puts_padded) { |text = ""|
          shell.send(:puts_override, master_puts, "")
          shell.send(:puts_override, master_puts, text)
          shell.send(:puts_override, master_puts, "")
        }
      }
      

      如果变量shell 存在于与printputs 相同的范围内,那么它工作得很好但是(如果我是对的)会中断。但它不会坏,我测试过!我真的不知道发生了什么,如果有人能解释一下,我将不胜感激:-)

      【讨论】:

        猜你喜欢
        • 2020-09-01
        • 1970-01-01
        • 2021-12-23
        • 1970-01-01
        • 1970-01-01
        • 2012-09-18
        • 1970-01-01
        • 2021-04-08
        • 1970-01-01
        相关资源
        最近更新 更多