新手问题 能否通过元编程在加载 Module 之前更改 Module 中变量的值?

BadTudou · 2017年11月13日 · 最后由 BadTudou 回复于 2017年11月14日 · 1173 次阅读

之所以有这个问题,是因为我在开发的个人项目 (KindleNote,解析管理你的 Kindle 标记与笔记) 中用到了一个 QQ 互联 - 账户登录的gem

该 gem 会require 'const.rb',而const.rb会默认读取qq_secrets.yml文件。

由于指定的文件是qq_secrets.yml,因此它默认读取的是项目根目录下的qq_secrets.yml文件。

我想完成的是:使这个 gem 读取config/qq_secrets.yml,而非qq_secrets.yml

我的想法是:监测require事件,当发现它要加载的是const.rb时,设置 Module*QQ里的变量fconfig/qq_secrets.yml*,并使其不可更改。

所以,能否能通过元编程来完成这个需求?或者,这是不切实际的幻想.....

以下是 gem 的部分代码:

const.rb 的代码

module QQ
  f = 'qq_secrets.yml'
  return raise 'qq_secrets.yml not found!' unless File.exist?(f)
  s = YAML.load_file(f)
 .......
end

qq.rb 的代码

class Qq
  require 'const.rb'
end

一个建议:不要使用粗体。

愿意认真给你答案的人,肯定也愿意认真阅读你的问题。加粗所传达出的信息是“我知道你们都不会认真阅读,所以只读我加粗的重点就好了”。相关吐槽:https://programnt.github.io/design/2017/10/24/bold-bold-bold.html

回到主题,遇到这种问题我的解决方法是:

  • 如果在构建过程能生成配置文件(比如 configs 目录下的文件),或者配置文件都是提交进仓库的,无视它。反正也就是项目根目录里多一个文件而已。
  • 自己 fork 过来重写。反正 libs 文件夹里一共俩文件,加一块儿也就 50 来行。自己维护也没什么大不了的。
  • 因为这个库检测/加载 qq_secrets.yml 秘密文件用的是 File.exist?YAML.load_file,而 f 变量的值是个相对路径。也就是说这个库寻找秘密文件的逻辑是依赖于当前工作目录的(这个行为本身就不靠谱),而不是项目根目录。那么你可以在加载这个库时临时切换当前工作目录。虽然算不上是利用了高级语言特性的元编程,不过至少做到了不改动第三方代码就能让它的行为满足你的期望。

这种垃圾 gem 还不如自己写一个。。。。

3 楼 已删除
5long 回复

多谢,感谢您的建议。

我在require 'Qq'之前使用了Dir.chdir(Rails.root+'config'),终于治好了我的强迫症。

BadTudou 关闭了讨论。 11月14日 09:55
需要 登录 后方可回复, 如果你还没有账号请 注册新账号