`
fantaxy025025
  • 浏览: 1327983 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

ruby的加载机制和rails_自动加载机制_对比

 
阅读更多

 

prefer:http://urbanautomaton.com/blog/2013/08/27/rails-autoloading-hell/

参考这篇文章,总结的已经很好了,有改动和补充。

Ruby Constant Lookup(注意这里是Ruby的)

Constant lookup in Ruby is reasonably simple, once you know the rules, but it isn’t always totally intuitive. When you refer to a constant in a given lexical scope, that constant is searched for in:

  1. Each entry in Module.nesting
  2. Each entry in Module.nesting.first.ancestors
  3. Each entry in Object.ancestors if Module.nesting.first is nil or a module.

关于Module.nesting 可以参考文档:http://ruby-doc.org/core-2.1.2/Module.html#method-c-nesting

翻译一下:

虽然汉语并不是一个精确的语言,但意境和直觉的表达,不论松本先生还是哪个程序猿,都是一样的。

1. 从当前作用域开始,逐层向上,寻找直接可视的目标

2. 从当前作用域的祖先们里寻找目标(2比1优先级低为什么?因为这点不符合第一直接可视要求,想想看很多的include进来的东西,哪里能看见呢!谁要是这么写程序,就是程序员公敌)

3. 寻找顶层作用域内的目标(这也符合直觉,因为顶层作用域是公用的,放最后也符合习惯;)

 

大大的缺陷

缺陷在第二步,从当前作用域的祖先们里寻找目标。

对一个程序员来说,最好的是能准确的写出自己用哪个名字空间内的哪个目标。

这个第二步中的默认规则显然违背了这个原理,因为如果我要用祖先的作用域内的目标,我可以写明使用这个目标,即多写几个字母,把目标的命名空间写上。

举例来说:

找A::B::C

就只应该找1. A::B空间内的C,或者3. 唯一默认空间内的::C

而不应该去找A::C,因为如果程序员想用A::C,则需要写明,只需要多写几个字母。

 

这个缺陷将会导致什么问题呢?

不明确的东西,就要有一个统一的默认值。而如果默认的寻找路径是多个,就必须保证不能交叉。否则就麻烦了。

找A::B::C,结果可能找到A::C和::C,这可不是我们愿意的,一旦程序大了,谁去理清楚这个玩意儿。最后还不是得程序员埋单,要么还得写清楚,要么就报错搞死人。

期待ruby后面改掉这个糟粕呀!!

 

测试代码改了下:

 

C = "At the top level"

module A
  C = "In A"
end

module A
  module Y
    #none
  end
end

module A
  module B
    include A::Y

    module X

    end

    puts "----B----"
    puts "Module.nesting=#{Module.nesting.inspect}" # => [A::B, A]
    puts "Module.nesting.first=#{Module.nesting.first}"
    puts "Module.nesting.first.ancestors=#{Module.nesting.first.ancestors.inspect}"
    puts "Object.ancestors=#{Object.ancestors}"
    puts C              # => "In A"
    puts "----B----"
  end
end

module A::B
  puts Module.nesting # => [A::B]
  puts C              # => "At the top level"
end

 你要是能写对,可真不错。理解了这个,下面的问题才能更好理解。

----B----

Module.nesting=[A::B, A]

Module.nesting.first=A::B

Module.nesting.first.ancestors=[A::B, A::Y]

Object.ancestors=[Object, Kernel, BasicObject]

In A

----B----

A::B

At the top level

 

Process finished with exit code 0

 

Ruby's Autoload

http://fantaxy025025.iteye.com/blog/2098356 因为篇幅,拎出去写了分析,这里。

 

Rails Constant Autoloading

实现原理

    使用了钩子方法:Module#const_missing

查找和加载步骤:

1. 使用ruby加载。

2. 如果报错,则用rails机制寻找并加载文件:MyModule::SomeClass # => my_module/some_class.rb

 

rails是跑在ruby上的。并没有修改ruby的寻找机制,只是出错了才处理加载,去加载常量对应的文件。

上文分析了ruby寻找常量时,在命名空间上一层一层的找法的缺陷。

rails也遵循了ruby的寻找方法,区别在于,rails会去加载对应的文件。

When Foo::Bar::Baz is referred to, then, Rails will attempt to load the following constants in turn, until it finds one that is already loaded:

  • Foo::Bar::Baz | 对应autoload_paths/foo/bar/baz.rb
  • Foo::Baz | 对应autoload_paths/foo/baz.rb
  • Baz | 对应autoload_paths/baz.rb

这样也会有加载的文件产生交叉的问题。

As soon as an already-loaded constant Baz is encountered, Rails knows this cannot be the Baz it is looking for, and the algorithm raises a NameError.

这个是rails的机制,原因是什么?

因为ruby找不到的常量,rails只认为是因为没有加载对应的文件,其实这也是rails做的唯一工作

而如果已经存在一个这样的常量了,而ruby找不到,那么rails也不能做太多的工作。

 

rails为什么不去掉中间这种不好的加载方法呢?

    是可以去掉的。但很多人写的ruby代码,使用了2这种默认机制,如果去掉,就会导致自动加载不能用了。为了兼顾ruby,只能这样了。

 

 

Rails 自动加载的缺陷

# 同ruby一样,第二种加载容易导致交叉。

  详细见上面分析。

 

# 依赖加载顺序

  因为找不到相应的常量时,就会去找相应的文件。运行时,执行的不同顺序,会导致加载文件的顺序发生变化。这样可能引发很多问题,比如不同文件定义的常量同名了,但运行到不同的分支导致加载了不同的常量,这样的bug很难排查。

 

# 上下文信息丢失

  ruby中的常量有多重,class, module, 字面常量比如Cache="MEM"这种。rails只收到const_missing,并没有收到上下文信息。

  比如const_missing接收到Foo::Bar::Baz 这个常量有很多种表现形式,比如上面的简单的就3种了,还有不少变种,比如下面两种module的写法就是不同的,更别提module和class了。 

 

module Foo
  module Bar
    #sth
  end
end

 

module Foo::Bar
    #sth
  end
end

 

class Foo
  class Bar
    #sth
  end
end

 

rails接收不到上下文信息,所以导致rails只认为是第一种方式。

 

理解了文章的一些内容,再看 http://urbanautomaton.com/blog/2013/08/27/rails-autoloading-hell/

这个文章就好理解了。很多东西还是有其内在的原因的,死记只能解一时只用。 

 

+

+

+

——

+

+

+

分享到:
评论

相关推荐

    bhl_rails_solr-源码.rar

    2. **lib目录**:存放自定义的Ruby模块和类,如连接Solr的适配器、Solr配置文件解析工具等。 3. **app/models/solr_document.rb**:定义了Solr文档对象,用于映射Rails模型到Solr索引。 4. **config目录**:配置文件...

    angular_rails_csrf-源码.rar

    2. Rails的控制器和视图:Rails端可能有修改过的控制器,用于在响应中返回CSRF令牌,或者更新后的视图,用于在页面加载时将令牌传递给Angular。 3. 配置文件:可能包括Rails的`config/application.rb`或`config/...

    举例理解Ruby on Rails的页面缓存机制

    在标题和描述中提到的“举例理解Ruby on Rails的页面缓存机制”,主要是指通过具体的例子来阐述如何在实际项目中运用页面缓存。例如,IBM 官方技术文档中的内容可能包含以下示例: 1. **启用页面缓存**:在 Rails ...

    Ruby on Rails 指南 v5.0.1 中文版

    ### Ruby on Rails 指南 v5.0.1 中文版 #### Rails入门 - **前提条件**:为了能够顺利地开始Rails的学习之旅,读者需要具备一定的Ruby语言基础,并且对Web开发有一定的了解。 - **Rails是什么?**:Rails是一种...

    Ruby on Rails插件

    Rails的插件定位和加载机制是可以扩展的,开发者可以创建自定义的定位器和加载器以适应特定的需求。 安装Rails插件通常使用内置的`script/plugin`工具,它支持多种命令如`discover`、`source`、`unsource`、`...

    Ruby-極光Rails5專屬伺服器安裝包

    Ruby 2.3.1是该语言的一个稳定版本,它提供了许多性能优化和新特性,例如:语法糖的增强、新的垃圾回收机制以及对大型数据处理的支持,使得Rails应用的运行更为流畅。 2. **Passenger 5**: Passenger(又名Phusion ...

    Rails Best Practices

    Rails,全称Ruby on Rails,是一个基于Ruby语言的开源Web应用程序框架,遵循MVC(模型-视图-控制器)架构模式。它以其简洁、高效和开发速度闻名,深受开发者喜爱。Rails最佳实践是提升代码质量和可维护性的关键,...

    Rails确认替换为SweetAlert_Ruby_HTML_下载.zip

    本压缩包"Rails确认替换为SweetAlert_Ruby_HTML_下载.zip"可能包含了一个名为"sweet-alert-rails-confirm-master"的项目,该项目可能是对Rails中默认确认机制的替换,用SweetAlert来实现确认对话框。接下来,我们将...

    api_rails_grape_1

    标题“api_rails_grape_1”暗示了我们即将探讨的是关于使用Ruby构建API的专题,特别是关于Rails框架中的Grape库。Rails是Ruby社区广泛使用的Web开发框架,而Grape是一个轻量级且模块化的库,用于创建RESTful API。 ...

    ruby for rails

    在本书中,作者详细介绍了Ruby的基础知识,包括变量、常量、方法、类、模块等核心概念,以及Ruby的元编程特性,如对象的反射和自定义类加载机制。这些内容对于理解Rails框架的工作原理至关重要,因为Rails充分利用了...

    Ruby-这是一个在Rails应用程序中使用React并使用webpack的示例

    在Ruby开发领域,Web开发框架Rails(Ruby on Rails)因其高效和简洁的代码风格而备受开发者喜爱。近年来,随着前端技术的发展,JavaScript库如React在构建用户界面方面展现了强大潜力。本示例将探讨如何在Rails应用...

    Ruby On Rails For Dummies

    - **Routing**:Rails 使用了一种基于正则表达式的路由机制,可以根据 URL 自动映射到对应的控制器方法。 - **Middleware**:中间件是 Rails 应用的一个重要组成部分,它们位于 HTTP 请求和响应的处理流程中,可以...

    Pro.Active.Record.Databases.with.Ruby.and.Rails

    《Pro Active Record Databases with Ruby and Rails》一书由Kevin Marshall、Chad Pytel和Jon Yurek共同撰写,旨在帮助开发者掌握如何使用Ruby及Ruby on Rails(简称Rails)框架进行高级数据库应用开发的技术。...

    Ruby on Rails Tutorial 3 源码

    首先,Ruby 2.2.1 是一个稳定版本的 Ruby 语言,引入了多项性能优化和语法改进,如细化常量查找、元编程的改进以及更好的垃圾回收机制。这些改进使得代码运行更高效,同时也提高了开发者的生产力。 Rails 4.2.6 是...

    Rails的自动完成分页插件

    Rails是Ruby on Rails框架的一个重要组成部分,它是一个用于构建Web应用程序的强大工具。在这个场景中,我们关注的是Rails的自动完成、文件上传、分页以及上传进度管理相关的插件。让我们详细了解一下这些关键知识点...

    SOA系列:开源框架Ruby on Rails

    4. **强大的社区支持**:由于 Ruby 和 Rails 的流行度不断提升,围绕这两种技术的社区也日益壮大,这为开发者提供了丰富的资源和解决方案,有助于解决开发过程中遇到的问题。 #### 三、Ruby 语言简介 **Ruby** ...

    Pro Active Record. Databases with Ruby and Rails

    《Pro Active Record: Databases with Ruby and Rails》是一本由Kevin Marshall、Chad Pytel和Jon Yurek共同编写的关于Ruby on Rails(简称Rails)框架下的Active Record模式使用的专业指南。该书于2007年出版,提供...

    ruby on rails

    12. **Asset Pipeline**:Rails的静态资源管理机制,允许合并、压缩JavaScript和CSS文件,提高页面加载速度。 13. **Railties**:Rails的核心组件,提供了初始化、命令行工具和插件系统等功能,使得Rails能够与其他...

    Ruby-RailsFootnotes在每一个Rails页脚展示应用程序的相关信息方便调试

    Ruby on Rails是一款强大的Web开发框架,它以简洁和生产力为导向,深受开发者喜爱。在开发过程中,调试是必不可少的一部分,为了帮助开发者更有效地定位问题,Rails社区创建了多种辅助工具,其中之一便是Rails ...

    ruby eclipse插件

    Ruby Eclipse 插件是专为在Eclipse集成开发环境中(IDE)进行Ruby和Ruby on Rails开发设计的一款扩展工具。这款插件将Eclipse强大的功能与Ruby语言的灵活性结合在一起,为开发者提供了一站式的开发体验。 首先,让...

Global site tag (gtag.js) - Google Analytics