gpt4 book ai didi

ruby - 如何在 Ruby 中使用 "fake"C# 样式属性?

转载 作者:数据小太阳 更新时间:2023-10-29 07:09:31 25 4
gpt4 key购买 nike

编辑:我稍微更改了规范,以更好地符合我的想象。

好吧,我真的不想伪造 C# 属性,我想将它们合而为一并支持 AOP。

给定程序:

class Object
def Object.profile
# magic code here
end
end

class Foo
# This is the fake attribute, it profiles a single method.
profile
def bar(b)
puts b
end

def barbar(b)
puts(b)
end

comment("this really should be fixed")
def snafu(b)
end

end

Foo.new.bar("test")
Foo.new.barbar("test")
puts Foo.get_comment(:snafu)

期望的输出:

Foo.bar was called with param: b = "test"testFoo.bar call finished, duration was 1mstestThis really should be fixed

有什么办法可以实现吗?

最佳答案

我有一些不同的方法:

class Object
def self.profile(method_name)
return_value = nil
time = Benchmark.measure do
return_value = yield
end

puts "#{method_name} finished in #{time.real}"
return_value
end
end

require "benchmark"

module Profiler
def method_added(name)
profile_method(name) if @method_profiled
super
end

def profile_method(method_name)
@method_profiled = nil
alias_method "unprofiled_#{method_name}", method_name
class_eval <<-ruby_eval
def #{method_name}(*args, &blk)
name = "\#{self.class}##{method_name}"
msg = "\#{name} was called with \#{args.inspect}"
msg << " and a block" if block_given?
puts msg

Object.profile(name) { unprofiled_#{method_name}(*args, &blk) }
end
ruby_eval
end

def profile
@method_profiled = true
end
end

module Comment
def method_added(name)
comment_method(name) if @method_commented
super
end

def comment_method(method_name)
comment = @method_commented
@method_commented = nil
alias_method "uncommented_#{method_name}", method_name
class_eval <<-ruby_eval
def #{method_name}(*args, &blk)
puts #{comment.inspect}
uncommented_#{method_name}(*args, &blk)
end
ruby_eval
end

def comment(text)
@method_commented = text
end
end

class Foo
extend Profiler
extend Comment

# This is the fake attribute, it profiles a single method.
profile
def bar(b)
puts b
end

def barbar(b)
puts(b)
end

comment("this really should be fixed")
def snafu(b)
end
end

关于这个解决方案的几点:

  • 我通过模块提供了额外的方法,这些模块可以根据需要扩展到新的类中。这避免了污染所有模块的全局命名空间。
  • 我避免使用 alias_method,因为模块包含允许 AOP 样式的扩展(在本例中,用于 method_added)而无需别名。
  • 我选择使用 class_eval 而不是 define_method 来定义新方法,以便能够支持采用 block 的方法。这也需要使用 alias_method
  • 因为我选择支持 block ,所以我还在输出中添加了一些文本,以防该方法需要一个 block 。
  • 有一些方法可以获得实际的参数名称,这将更接近于您的原始输出,但它们并不真正适合此处的响应。你可以看看merb-action-args ,我们在其中编写了一些需要获取实际参数名称的代码。它适用于 JRuby、Ruby 1.8.x、Ruby 1.9.1(带有 gem)和 Ruby 1.9 trunk(原生)。
  • 这里的基本技术是在调用profilecomment 时存储类实例变量,然后在添加方法时应用。与前面的解决方案一样,method_added Hook 用于跟踪何时添加了新方法,但 Hook 不是每次都移除 Hook ,而是检查实例变量。实例变量在应用 AOP 后被删除,因此它只应用一次。如果多次使用相同的技术,它可以进一步抽象。
  • 总的来说,我尽量坚持您的“规范”,这就是为什么我包含了 Object.profile 片段而不是内联实现它的原因。

关于ruby - 如何在 Ruby 中使用 "fake"C# 样式属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1085070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com