Ruby Ruby 的命名空间提案,引用包时避免污染全局环境

jjym · 2018年08月19日 · 最后由 lilijreey 回复于 2018年10月17日 · 3009 次阅读

https://bugs.ruby-lang.org/issues/14982

大致思路就是加入一些对上下文的造作,让用户来控制当前的上下文(Binding),而不是 gem 作者

示例:

1 引用 ruby 文件到单独的 module 下

# requiring into isolated Binding
require foo, into: :IsolatedBindingModule1
IsolatedBindingModule1.class # Module
IsolatedBindingModule1::Foo # access names

# the old way should still work
# requiring and polluting TOPLEVEL_BINDING
require foo
Foo

2 允许用户使用“干净”的上下文 (Binding)

Foo
isolate # isolate 关键字创建了新的 Binding(独立于 TOPLEVEL_BINDING)
    Foo # NameError
end

isolate module Bar # 隔离 Bar 的 Binding
  Foo # NameError
end

3 import,从另外 Binding 中导入名称

Foo
isolate
  # import name from a ruby file
  # import primitive is a convenient way to use isolated requiring
  import :Foo, from: foo
end

更多详细信息可以去看原帖

注意:这是个提案,目前还未被 Ruby 团队接受

早该作出改变了,多向 Python import 学学

考虑一下 Haskell 的 qualified,应该比 into 合适一些

我对这个特性不太感兴趣,一来自己的项目通过命名规范隔离已经足够,二来避免使用污染全局空间的库。ActiveSupport 是个特例,它是 Rails 的依赖不得不用,用起来也感觉良好。Rails 不用每个文件写一堆 import 也是它的优点。

最近用 ActiveStorage 的时候处理 js 端时发现问题,七牛的 js 上传逻辑跟 activestorage.js 里的不一样需要改写,但是这个包经过 ES6 的规范化打包之后,外部完全动不了里面的逻辑。本来只是改写一个方法可以搞定了,结果不得不把整个 js dump 到项目里改写。我还没想好怎么提 pr 让 activestorage.js 提供接口定制不同 service 的上传逻辑。

所以有了包的概念以后又不得不考虑怎么方便的问题了。

一是太麻烦了要是所有包都学这个,写点什么脚本全都得 import 一大堆 二是如果都搞 import 了为什么还不用 Python...

luikore 回复

你说的好像是只有 python 有 import 一样,应该反过来说 import 是个很好的控制复杂度的功能,除 ruby 外的主流语言中几乎都支持

luikore 回复

还有这个提案是不破坏旧的 require 功能的,对使用 require 导入的用户完全透明

控制命名空间是包的使用者来决定,只想写脚本可以完全和之前一样 require

并没有觉得有很大的必要

  1. 不算痛点
  2. 对代码习惯影响略大,甚至可能会引入兼容性问题
  3. Ruby 不是提倡开放的么?这个 feature 写成个 gem 也能实现,为啥要作为通则

我写 python 的时候,代码打开后首屏就是各式各样的 import,就在我还在庆幸 Ruby 避开了这套 import 设计的时候,然而……

我是觉得想要真的摸索 ruby off rails,这个功能对 ruby 还是很重要的 (当然实现方式不一定这样

rails 优秀的框架设计和约定优于配置哲学,其实在帮程序员很好的管理了代码的复杂性,一切代码井井有条,自有 DHH 帮你安排

当你 off rails 时可能发现 ruby 对于管理复杂性没有很好的通用方案,rust python 甚至 nodejs 都可以仅仅 "import" 需要的东西而忽略其它实现相关的代码,当你引入一个大项目时非常有帮助

另外 ruby 目前的设计是用 TOPLEVEL BINDING,但这不代表 rubyist 都要做原教旨主义者,这个提议的很大一部分就是在考虑如何同时兼容两种用法 (想一想连 nodejs 都能引入模块),平衡各种设计让用户选择才是 ruby 的魅力所在

IChou 回复

那你肯定没有考虑不破坏之前 require 用法的情况

jjym 回复

Ruby 的 module 已经和 Python / NodeJS 的 module 功能是否相似了,只是 foo.bar.baz 变成了 Foo::Bar::Baz, import 变成了 include 和 using 而已。这提案只能说明还没会用 Ruby 😂

我觉得挺好的,现在搞 sketchup 插件开发,当多个插件使用了同一个 gem 的不同版本时可能出现各种问题,目前的解决方案就是实现了一个类似的把 gem 引入指定模块的方法,但是实现方式很粗放,只能引入那些依赖不是那么复杂的 gem

jjym 回复

一堆语言都有,Python 和 Ruby 最相似而已。

增加一个作用和 import 差不多的语法,但写起来丑很多,功能和已有语法重叠... 这样的多余设计实在太丑陋了。如果真通过了我真不如该写 Python 算了

jjym 回复

向下兼容并不总是能解决所有问题,出了这个特性你用不用,一个项目里有的人用有的人不用,大丈夫?

@jjym 对了,我很好奇你和 @jjyr 是什么关系😄 😄

Rei 回复

我也遇到了这个问题,七牛不支持 active_storage.js 默认的 patch method 直传是吧。

一开始我也是想改下 active_storage.js, 后来写了个回调自己处理的

https://github.com/qinmingyuan/qiniu_rails/blob/master/lib/assets/javascripts/qiniu_direct_upload.js

mingyuan0715 回复

是的,我也试试这个方法。

Rei 回复

方便的话,用我这个 gem qiniu_rails 吧。支持的功能还是比较完善的,如果有发现 bug,我第一时间响应。

不明觉厉

需要 登录 后方可回复, 如果你还没有账号请 注册新账号