差沙的密码 -- SSHWSFC's code
阅读本Blog请自备塑料袋一只
posts - 14,  comments - 59,  trackbacks - 0

说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(注意,这些东西都在activesupport里面呢,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的基本,在以后的深入研究中我们就能看到了。

posted on 2006-11-21 12:10 差沙 阅读(3719) 评论(2)  编辑  收藏 所属分类: ROR

FeedBack:
# re: 说说Rails吧,config的幕后工作
2008-07-05 15:46 |
撒卡拉 ;大大怕怕;;发撒;  回复  更多评论
  
# re: 说说Rails吧,config的幕后工作
2008-07-05 15:47 |
看到其中的玄妙了么,method_missing~~~!! 如果调用一个**=的方法 ,就像当用传入一个HASH的值,key就是方法的名字。

也就是:config.action_view.debug_rjs = true 相当于config.action_view[:debug_rjs] = true

OK ,大体上描述了一下,可以看到简单的一个Rails初始化已经给我们展示了几乎全部ruby的靓丽之处,这能说明,这个亮点肯定是贯穿rails的基本,在以后的深入研究中我们就能看到了。

  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
 
这家伙很懒,但起码还是写了一句话。

<2006年11月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

常用链接

留言簿(8)

随笔分类

随笔档案

文章分类

搜索

  •  

最新评论

阅读排行榜

评论排行榜