“公共/受保护/私有”如何?方法已实现,我该如何模拟它?

发布于 2024-12-09 19:40:13 字数 501 浏览 0 评论 0原文

在 ruby​​ 中,您可以这样做:

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 是公共的,f2 和 f4 是私有的。内部发生了什么,允许您调用一个类方法,然后更改方法定义? 我如何实现相同的功能(表面上是创建我自己的 java 类注释)

例如,

class Thing
  fun
  def f1
    puts "hey"
  end

  notfun
  def f2
    puts "hey"
  end
end

...而 fun 和 notfun 会更改以下函数定义。

谢谢

In ruby, you can do this:

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

where now f1 and f3 and public, f2 and f4 is private. What is going on internally that allows you to invoke a class method that then changes the method definition? How can I implement the same functionality (ostensibly to create my own java like annotations)

for example...

class Thing
  fun
  def f1
    puts "hey"
  end

  notfun
  def f2
    puts "hey"
  end
end

and fun and notfun would change the following function definitions.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦一生花开无言 2024-12-16 19:40:13

有时您可以将 Ruby 放入浓缩咖啡杯中。让我们看看如何。

这是一个模块 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

You can sometimes shove Ruby into an espressso cup. Let's see how.

Here's a module 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

... that you can use to extend a class ...

class Thing

  extend FunNotFun

  fun
  def f1
    puts "hey"
  end

  notfun
  def f2
    puts "hey"
  end
end

... with this result:

Thing.new.f1
# => hey
# => That was fun

Thing.new.f2
# => hey
# => That was not fun

But see below the line for a better way.


Annotations (see normalocity's answer) are less trouble and, being a common Ruby idiom, will more easily communicate your code's intent. Here's how to do it with annotations:

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

In use, the annotation comes after the method is defined, rather than before:

class Thing

  extend FunNotFun

  def f1
    puts "hey"
  end
  fun :f1

  def f2
    puts "hey"
  end
  notfun :f2

end

The result is the same:

Thing.new.f1
# => hey
# => That was fun

Thing.new.f2
# => hey
# => That was not fun
舂唻埖巳落 2024-12-16 19:40:13

听起来您想为 Ruby 语言本身编写扩展,这是可能的。这不是可以简单解释的内容,但此链接应该可以帮助您入门:

http: //ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html

这个参考资料与 Ruby 中的注释有关,也可能有帮助/相关:

http://martinfowler.com/bliki/RubyAnnotations.html

Sounds like you want to write extensions to the Ruby language itself, which is possible. It's not something that can be explained briefly, but this link should get you started:

http://ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html

This reference, having to do with annotations in Ruby, might also be helpful/relevant:

http://martinfowler.com/bliki/RubyAnnotations.html

奶茶白久 2024-12-16 19:40:13

这是一个纯红宝石解决方案,可以帮助您找到正确的方向。它取决于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

Here's a pure-ruby solution to get you in the right direction. It hinges on method_added. Be careful to avoid recursion by using a guard clause.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文