扩展模块中的类方法

2023-11-24

我正在研究 ruby​​ 的元编程功能,我发现它有点棘手。我正在尝试使用模块包装方法调用。目前,我正在这样做:

module Bar
  module ClassMethods
    def wrap(method)
      class_eval do
        old_method = "wrapped_#{method}".to_sym
        unless respond_to? old_method
          alias_method old_method, method

          define_method method do |*args|
            send old_method, *args
          end
        end
      end
    end
  end

  def self.included(base)
    base.extend ClassMethods
  end
end

class Foo
  include Bar

  def bar(arg = 'foo')
    puts arg
  end

  wrap :bar
end

三个问题:

  1. 有没有办法在不重命名方法的情况下做到这一点,以便允许使用super?或者更干净/更短的东西?

  2. 有没有一种干净的方法来设置默认值?

  3. 有没有办法移动wrap :bar再往上打电话?


1)更干净/更短

module ClassMethods
  def wrap(method)
    old = "_#{method}".to_sym
    alias_method old, method
    define_method method do |*args|
      send(old, *args)
    end
  end
end

class Foo
  extend ClassMethods

  def bar(arg = 'foo')
    puts arg
  end

  wrap :bar
end

据我所知,如果不重命名,就无法实现这一目标。你可以尝试打电话super在 - 的里面define_method堵塞。但首先,请致电super从一个内define_method仅当您显式指定参数时才会成功,否则您会收到错误。但即使你打电话,例如super(*args), self在这种情况下将是 Foo 的一个实例。所以打电话给bar会去超级班Foo,找不到并最终导致错误。

2)是的,像这样

define_method method do |def_val='foo', *rest|
  send(old, def_val, *rest)
end

然而,在 Ruby 1.8 中它是不可能使用一个块define_method,但这已在 1.9 中修复。如果你使用的是1.9,你也可以使用这个

define_method method do |def_val='foo', *rest, &block|
  send(old, def_val, *rest, &block)
end

3)不幸的是,不。alias_method需要存在作为输入的方法。当 Ruby 方法在解析时出现时,wrap调用必须在定义之后进行bar否则alias_method会引发异常。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

扩展模块中的类方法 的相关文章

随机推荐

  • 使用 axios 获取本地 JSON 数据时遇到问题

    我正在尝试使用 axios 从本地 json 文件获取数据 在控制台下我什至无法得到回应 所以我想我应该在这里询问一下 js 文件 var loadData function loadData axios url filepath json
  • ASP.Net MVC 模型绑定 - 如何更改日期格式?

    我有这个应用程序 默认日期格式必须是dd MM yyyy 语言为巴西葡萄牙语 我已经将文化和 UI 文化设置为pt BR现在myDate ToShortDateString 返回我想要的日期 我可以毫无困难地展示它们 问题是 当用户在输入字
  • Yii2:如何在非 Restful API 上允许 CORS

    我正在 Yii2 Framework 上使用预构建的 API 不是 Restfull 它使用 JSON 数据进行响应 并根据用户类型和凭证令牌接受请求 现在我必须制作一个位于不同位置 域 的应用程序 这会导致 CORS 冲突 我的应用程序是
  • 如何在 matlab 中格式化复数以进行文本输出

    我有一个复数 我想使用 fprintf 命令将其输出为文本 我没有看到复数的格式规范 是否有捷径可寻 使用定点格式规范仅输出实部 根据文档fprintf and sprintf 数字转换仅打印复数的实部 所以对于一个复杂的值z你可以用这个
  • Django 错误消息“在定义中添加 related_name 参数”

    D zjm code basic project gt python manage py syncdb Error One or more models did not validate topics topic Accessor for
  • 如何处理 MS Word 添加的“特殊”字符?

    我想知道你如何清理 MS Word 中的特殊字符 例如 m 和 n 破折号以及弯引号 我经常发现自己从 Word 中复制客户端内容并粘贴到静态 HTML 页面中 但内容最终会出现奇怪的字符 因为特殊字符未转换为正确的 ACSII 代码 因此
  • 将字符串转换为 &strs 时,切片和显式重新借用之间有区别吗?

    下面两个例子等价吗 示例1 let x String new let y x 示例2 let x String new let y x 一种比另一种更有效率还是它们基本相同 如果是String and Vec 他们做同样的事情 在gener
  • Node.js/Async - 如何避免异步回调地狱?

    我是后端 Node Js 和 JavaScript Web 开发的新手 我发现回调中的回调可能会很痛苦 并且有一些模块可以避免这种情况 这些模块之一是异步的 https github com caolan async 我已阅读文档 但很难开
  • 如何在解决方案资源管理器上保留源文件夹层次结构?

    我在Linux上做了一个C 项目 我将源文件分组在许多目录中以自己组织 我使用 CMake 进行编译 每个子目录上都有一个 CMakeFiles txt srcs folderA Toto cpp Tata cpp folderB Foo
  • htaccess重写库

    我的根目录中有两个目录 dev and live 这些目录中的所有内容都有相对路径 例如 css style css or js home js 我希望能够使用 htaccess 更改根目录 以便相对路径变为 live css style
  • 将字符串数组转换为打字稿中的对象键

    我有下一个数组 const arrayData a b as const 该数组有下一个类型 ArrayType a b 我想获得与下一个类型一致的对象 type Type a boolean b boolean 预期对象 const re
  • 在Python中异步播放声音

    我有一个while loop让我的相机 带有 opencv 在物体移动时拍照 我也想调用一个函数来播放声音 但是当我调用并播放它时 它将在该执行时间内停止循环 我试过ThreadPoolExecutor但不知道如何将它与我的代码混合 因为我
  • 使用 gettext() 将 settings.LANGUAGES 与正确翻译的名称一起使用

    来自 Django 文档 如果您定义了自定义LANGUAGES设置 标记语言就可以了 作为翻译字符串 如 上面显示的默认值 但是 使用 假人 gettext 函数 不 中的一个django utils translation 你永远不应该导
  • 结构体总是分配堆栈还是有时分配堆?

    我的印象是 在 C 中 结构元素是在堆栈上分配的 因此从创建它们的方法返回时会消失 但是如果我将结构值放入列表中并返回它会发生什么 元素得以幸存 结构体实例有时会分配在堆上吗 internal struct Stru public int
  • file_get_contents 是否使用缓存?

    我有一个函数可以生成一个包含数据库内容的表 有些单元格具有自定义 HTML 我通过模板系统使用 file get contents 读取这些 HTML 小内容是相同的 但此操作可能执行 15 次 我限制每页 15 个表行 那么file ge
  • Lollipop 设置默认本地不起作用

    我在大多数 Android API 版本上运行此方法来使用语言 字符串等 设置应用程序 protected void setDefaultLocale Context context Locale locale Locale setDefa
  • 仅锁定 ID

    我有一个方法需要专门运行一段代码 但我只想在确实需要时添加此限制 根据 Id 值 Int32 我将加载 修改不同的对象 因此锁定所有线程的访问没有意义 这是这样做的第一次尝试 private static readonly Concurre
  • 直接输入地址栏时,您必须使用 API 密钥来验证对 Google Maps Platform API 的每个请求

    我收到这样的错误 error message This API project is not authorized to use this API results status REQUEST DENIED 每当我运行这个 https ma
  • Web api 从处理程序内部获取路由模板

    在将问题放在这里之前 我进行了很多搜索 但搜索得越多 我就越感到困惑 所以我创建了一个处理程序 我试图获取这样的路线 public class ExecutionDelegatingHandler DelegatingHandler pro
  • 扩展模块中的类方法

    我正在研究 ruby 的元编程功能 我发现它有点棘手 我正在尝试使用模块包装方法调用 目前 我正在这样做 module Bar module ClassMethods def wrap method class eval do old me