说说Rails吧,config的幕后工作 - 差沙的密码 -- SSHWSFC‘s cod...

来源:百度文库 编辑:神马文学网 时间:2024/03/29 22:35:03
说说Rails吧,config的幕后工作
说ruby是怪异的语法有点不妥当,动态语言里面不乏这样的语法出现。但是看了一些源码后发现,使用ruby的用法真的各有不同,就像大家以前说的,ruby每个人写出来的可能都不同。
现来说Rails里面如何加载config的吧。
在java里面config绝对是一个resource文件,然后通过读取配置的工具加入进来,在分析处理。
在ROR里面完全不是这么回事。
1.首先大家要了解的是,在我们启动 ruby script/server 的时候,rails做了一系列的处理,最后他执行了environment.rb
ruby 代码
Rails::Initializer.run do  | config |
   #  这里能插入我们自己的配置。
   #  config. 之类
end
这里的config其实是Initializer内部的一个变量,掌控全局的配置信息,我们可以使用这个config来配置我们想要的。Rails::Initializer.run的源码是这样的,yield再一次显示了他的威力,让我们在配置文件中得以配置config。然后实例化了一个initializer 之后,把config作为参数传入了。
ruby 代码
def  self.run(command  =  :process, configuration  =  Configuration.new)
   yield  configuration  if  block_given?
  initializer  =  new configuration
  initializer.send(command)
  initializer
end
我们接着往下走,可以看到initializer 做了一系列的初始化工作,包括load_path的设定,路由的初始化,和activerecord的初始化。我们关心的还是配置如何起作用,那么来看看environments目录下面的配置文件是如何导入的吧。
ruby 代码
def  load_environment
  silence_warnings do
    config  =  configuration
    constants  =  self. class .constants
    eval(IO.read(configuration.environment_path), binding)
    (self. class .constants  -  constants).each do  | const |
      Object.const_set(const, self. class .const_get(const))
    end
  end
end

IO.read(configuration.environment_path) ,,这里就不使用什么回调不回调了,而是干脆IO拿出来eval一把,这里也是吃了一惊,这样也可以呀~~~~~~~然后,我们可以看看,他处理常量的方法,把自己配置文件中的常量全部放入Object里面,起到全局常量的目的。
最绝的还是initialize_framework_settings,使用了有一个ruby的技巧。
ruby 代码
def  initialize_framework_settings
  configuration.frameworks.each do  | framework |
    base_class  =  framework.to_s.camelize.constantize.const_get( " Base " )

    configuration.send(framework).each do  | setting, value |
      base_class.send( " #{setting}= " , value)
    end
  end
end
configuration.frameworks里面存放的是rails个个组件的名字,比方说active_record之类。然后把这个名字大写转换,然后用constantize取得ActiveRecord这个Module(注意,这些东在都在activerecord里面呢,activesupport/lib/active_support/core_ext/string/inflections.rb )。然后用const_get取得这个模块的Base类,也就是ActiveRecord::Base这个类了(下面都叫做Base类),所有的Rails的组件都是这个命名规则改天我们自己想要做一个Rails的组件加进来,也可以这样(但是要稍微修改一个源码)。
然后,我们吧config里面的内容给Base类。configuration.send(framework)是调用一个组件名称的方法,比方说active_record,就是去的config里面的active_record属性(这是最基本的),通过后面的do我们可以看到config返回的是一个hash,然后把hash中每一个key作为变量,value为传入值,传入Base类。。。这里大家应该没什么问题了,看看我们的config文件是怎么写的吧。
ruby 代码
#  Settings specified here will take precedence over those in config/environment.rb

#  In the development environment your application‘s code is reloaded on
#  every request.  This slows down response time but is perfect for development
#  since you don‘t have to restart the webserver when you make code changes.
config.cache_classes  =  false

#  Log error messages when you accidentally call methods on nil.
config.whiny_nils  =  true

#  Enable the breakpoint server that script/breakpointer connects to
config.breakpoint_server  =  true

#  Show full error reports and disable caching
config.action_controller.consider_all_requests_local  =  true
config.action_controller.perform_caching              =  false
config.action_view.cache_template_extensions          =  false
config.action_view.debug_rjs                          =  true

#  Don‘t care if the mailer can‘t send
config.action_mailer.raise_delivery_errors  =  false
哦,看着很晕吧,config就是我们的配置对象,按照我们上面的说法,config.action_view之类framework的变量应该是一个hash才对呀,如果是hash的话,不应该用这样的方式传入,可能会用 config.action_view = {:debug_rjs => true}来传入。
OK.我们来看这个变量到底是什么样的hash。
ruby 代码
def  initialize
  .
  .
   for  framework  in  default_frameworks
    self.send( " #{framework}= " , OrderedOptions.new)
  end
end
在初始化这些变量的时候,Rails给他赋值为OrderedOptions.new。这个特殊的类型可能就是关键。
ruby 代码
class  OrderedOptions  <  OrderedHash  # :nodoc:
   def  [] = (key, value)
    super(key.to_sym, value)
  end

   def  [](key)
    super(key.to_sym)
  end

   def  method_missing(name,  * args)
     if  name.to_s  =~   / (. * ) = $ /
      self[$ 1 .to_sym]  =  args.first
     else
      self[name]
    end
  end
end
看到其中的玄妙了么,method_missing~~~!! 如果调用一个**=的方法 ,就像当用传入一个HASH的值,key就是方法的名字。
也就是:config.action_view.debug_rjs  = true 相当于config.action_view[:debug_rjs] = true
OK ,大体上描述了一下,可以看到简单的一个Rails初始化已经给我们展示了几乎全部ruby的靓丽之处,这能说明,这个亮点肯定是贯穿rails的基本,在以后的深入研究中我们就能看到了。