在红宝石中,你可以这样做:
class Thing
public
def f1
puts "f1"
end
private
def f2
puts "f2"
end
public
def f3
puts "f3"
end
private
def f4
puts "f4"
end
end
现在f1和f3以及public,f2和f4是私有的。内部发生了什么,允许您调用一个类方法然后更改方法定义?我如何实现相同的功能(表面上是为了创建我自己的java注释)
例如......
class Thing
fun
def f1
puts "hey"
end
notfun
def f2
puts "hey"
end
end
而fun和notfun会改变以下函数定义。
由于
答案 0 :(得分:8)
你有时可以将红宝石推入espressso杯中。我们来看看如何。
这是FunNotFun模块......
module FunNotFun
def fun
@method_type = 'fun'
end
def notfun
@method_type = 'not fun'
end
def method_added(id)
return unless @method_type
return if @bypass_method_added_hook
orig_method = instance_method(id)
@bypass_method_added_hook = true
method_type = @method_type
define_method(id) do |*args|
orig_method.bind(self).call(*args).tap do
puts "That was #{method_type}"
end
end
@bypass_method_added_hook = false
end
end
...你可以用来扩展一个类......
class Thing
extend FunNotFun
fun
def f1
puts "hey"
end
notfun
def f2
puts "hey"
end
end
......结果如下:
Thing.new.f1
# => hey
# => That was fun
Thing.new.f2
# => hey
# => That was not fun
但请参阅下面的行以获得更好的方法。
注释(参见normalocity的答案)不那么麻烦,作为一种常见的Ruby习语,将更容易传达代码的意图。以下是使用注释的方法:
module FunNotFun
def fun(method_id)
wrap_method(method_id, "fun")
end
def notfun(method_id)
wrap_method(method_id, "not fun")
end
def wrap_method(method_id, type_of_method)
orig_method = instance_method(method_id)
define_method(method_id) do |*args|
orig_method.bind(self).call(*args).tap do
puts "That was #{type_of_method}"
end
end
end
end
在使用中,注释来自定义方法之后,而不是之前:
class Thing
extend FunNotFun
def f1
puts "hey"
end
fun :f1
def f2
puts "hey"
end
notfun :f2
end
结果是一样的:
Thing.new.f1
# => hey
# => That was fun
Thing.new.f2
# => hey
# => That was not fun
答案 1 :(得分:1)
听起来你想要编写Ruby语言本身的扩展,这是可能的。这不是可以简单解释的东西,但是这个链接应该让你开始:
http://ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html
此引用与Ruby中的注释有关,也可能有用/相关:
答案 2 :(得分:1)
这是一个纯粹的红宝石解决方案,可以帮助您朝着正确的方向前进。它取决于method_added
。使用保护条款时要小心避免递归。
module Annotations
def fun
@state = :fun
end
def not_fun
@state = :not_fun
end
def inject_label(method_name)
state = @state
define_method(:"#{method_name}_with_label") do |*args, &block|
puts "Invoking #{method_name} in state #{state}"
send(:"#{method_name}_without_label", *args, &block)
end
alias_method :"#{method_name}_without_label", :"#{method_name}"
alias_method :"#{method_name}", :"#{method_name}_with_label"
end
def self.extended(base)
base.instance_eval do
def self.method_added(method_name)
return if method_name.to_s =~ /_with(out)?_label\Z/
@seen ||= {}
unless @seen[method_name]
@seen[method_name] = true
inject_label(method_name)
end
end
end
end
end
class Foo
extend Annotations
fun
def something
puts "I'm something"
end
not_fun
def other
puts "I'm the other"
end
end