therubyway:ruby way的动态特性的一

  1 动态evaluate代码

  全局思路方法eval 编译并且执行段包含ruby代码片断这是个很power机制它允许你建造在运行时

  执行代码看下面例子:

  Ruby代码 parameters = {} 
 
ARGF.each do |line| 
 name, expr = line.split(/\s*=\s*/, 2) 
 parameters[name] = eval expr 
end


  假设输出是这样:

  引用

  a = 1

  b = 2 + 3

  c = `date`

  然后你parameters 应该是这样{"a"=>1, "b"=>5, "c"=>"Mon Apr 30 21:17:47 CDT 2001\n"}. 不过这样

  险性很高假设你传入个 "rm *"那么就很郁闷了

  ruby有 3个思路方法来做到在运行时evaluate代码_eval, module_eval, 和instance_eval前两个是同义而这 3

  个思路方法其实所做事都是他们都是evaluate 或者个block但是在做这件事时候他们会把

  self改变为他们自己接收者.如果你想看些例子推荐你去看ruby内置库delegate.rb.

  eval 思路方法还能够在局部变量创建域外面evaluate.

  你能够使用 Kernel#binding思路方法来将个当前绑定付给个对象而eval第 2个参数就是这个绑定:

  Ruby代码  

def some_ethod 
 a = "local variable" 
  binding 
end 
 
the_binding = some_method 
eval "a", the_binding  # "local variable"


  而如果带有block这个block则是被存储为这个绑定部分:

  Ruby代码

def some_method 
  binding 
end 
 
the_binding = some_method { puts "hello" } 
eval "yield", the_binding        # hello


  2 使用const_get

  const_get思路方法从类或者模块得到个常量值:

  Ruby代码

str = "PI" 
Math.const_get(str)   # Evaluates to Math::PI


  这是种避免使用eval思路方法还有些类似思路方法instance_variable_, instance_variable_get和

  _method.

  const_get 比eval快而且他更可读更明确

  3 通过个名字来动态例子化个类

  可以使用const_get思路方法在ruby中所有类通常情况下都被命名为个常量作为Object个全局成员.

  Ruby代码

name = "Array" 
 
klass = Object.const_get(name) 
x = klass.(4, 1)    # [1, 1, 1, 1]


  如果类名字嵌套就会报错:

  Ruby代码

 Alpha 
  Beta 
   Gamma 
   FOOBAR = 237 
  end 
 end 
end 
 
str = "Alpha::Beta::Gamma::FOOBAR" 
val = Object.const_get(str)     # error!


  这是const_get思路方法并没有那么智能可是我们可以这么做:

  Ruby代码

str = "Alpha::Beta::Gamma::FOOBAR" 
val = str.split("::").inject(Object) {|x,y| x.const_get(y) } # 237


  4 动态存取例子变量

  看下面例子:

  Ruby代码

 MyClass 
 attr_reader :alpha, :beta 
 
 def initialize(a,b,g) 
  @alpha, @beta, @gamma = a, b, g 
 end 
end 
 
 
x = MyClass.(10,11,12) 
 
x.instance_variable_("@alpha",234) 
p x.alpha                  # 234 
 
x.instance_variable_("@gamma",345)    # 345 
v = x.instance_variable_get("@gamma")    # 345 


  这里要注意必须用变量全名来作为参数也就是说要带上@符号.

  5 使用_method

  比起def,_method只是个很平常个思路方法到个对象或者个类个思路方法.

  如果我们想要在个思路方法体内或者其他类似地方重新打开这个类(也就是说增加些思路方法)那么除非这个类是singleton 这时在老版本ruby中我们必须使用eval可是现在我们能够使用_method由于_method是 private所以我们必须这样使用:

  Ruby代码

 today =~ /Saturday|Sunday/ 
 Object._eval { _method(:activity) { puts "Playing!" } } 
 
 Object._eval { _method(:activity) { puts "Working!" } } 
end 
 
activity


  我们也可以把_method直接插在个类里面:

  Ruby代码

 MyClass 
 _method(:mymeth) { puts "This is my method." } 
end


  然后你可以这样做:

  Ruby代码

 MyClass 
 def self._method(name, &block) 
  _method(name, &block) 
 end 
end 
 
MyClass._method(:mymeth) { puts "This is my method." } 
x = MyClass. 
x.mymeth      # Prs "This is my method." 


  如果你想要使用在例子级别你可以这么做:

  Ruby代码

 MyClass 
 def _method(name, &block) 
  self..send(:_method,name, &block) 
 end 
end 
 
x = MyClass. 
x._method(:mymeth) { puts "This is my method." } 
x.mymeth      # Prs "This is my method."


  这里要注意的所以使用sendsend也可以用于私有思路方法而在ruby1.9中send是不能用于私有思路方法.

  我们可以看到_method思路方法还带有个block为参数这就意味着我们能够保留定义这个block时上下文:

  Ruby代码

 MyClass 
 def self._method(name, &block) 
  _method(name, &block) 
 end 
end 
 
a,b = 3,79 
 
MyClass._method(:compute) { a*b } 
x = MyClass. 
puts x.compute      # 237 
 
a,b = 23,24 
puts x.compute      # 552


  看下面我们读取个类变量例子:

  Ruby代码

 SomeClass 
 @@var = 999 
 
 _method(:peek) { @@var } 
end 
 
x = SomeClass. 
p x.peek       # 999


  假设这时我们想要读取个例子变量:

  Ruby代码

 SomeClass 
 @var = 999 
 
 _method(:peek) { @var } 
end 
 
x = SomeClass. 
p x.peek       # prs nil 


  竟然打印出nil为什么呢?可是修改下又可以打出正确值了:

  Ruby代码  SomeClass 
 @var = 999 
 x = @var 
 
 _method(:peek) { x } 
end 
 
x = SomeClass. 
p x.peek   # 999


  原因是新建思路方法上下文是对象例子上下文而不是类因此在这里这个类例子变量会被对象例子变量

  所覆盖也就是说这里打印其实是例子变量@var

  6 使用const_missing

  const_missing 思路方法和method_missing很相似如果你想要得到个你不知道常量这个思路方法就会被:

  Ruby代码

 Module 
 def const_missing(x) 
  "from Module" 
 end 
end 
 
 X 
end 
 
p X::BAR    # "from Module" 
p BAR      # "from Module" 
p Array::BAR  # "from Module"


  如果想要让他作为个类思路方法你可以这样做:

  Ruby代码  

 Alpha 
 def self.const_missing(sym) 
  "Alpha has no #{sym}" 
 end 
end 
 
 Beta 
 def self.const_missing(sym) 
  "Beta has no #{sym}" 
 end 
end 
 
 A < Alpha 
end 
 
 B < Beta 
end 
 
p Alpha::FOO    # "Alpha has no FOO" 
p Beta::FOO    # "Beta has no FOO" 
p A::FOO      # "Alpha has no FOO" 
p B::FOO      # "Beta has no FOO"


  7 移除定义

  比如个思路方法我们想要彻底删除它这时我们就能用到undef(和def刚好相反).你能够undef 思路方法局部变量常量...可以要注意你不能undef个类:

  Ruby代码  

def asbestos 
 puts "Now fireproof" 
end 
 
tax = 0.08 
 
PI = 3 
 
asbestos 
puts "PI=#{PI}, tax=#{tax}" 
 
undef asbestos 
undef tax 
undef PI 
 
# 下面上面思路方法或者变量就会报错


  这里要注意你不能undef个例子变量.

  还有remove_method 和 undef_method思路方法他们区别是很细小:remove_method 将会remove掉当前思路方法定义 undef_method 思路方法 将会remove掉所有思路方法定义(比如超类思路方法):

  Ruby代码  

 Parent 
 
 def alpha 
  puts "parent alpha" 
 end 
 
 def beta 
  puts "parent beta" 
 end 
end 
 
 Child < Parent 
 
 def alpha 
  puts "child alpha" 
 end 
 
 def beta 
  puts "child beta" 
 end 
 
 remove_method :alpha  # Remove "this" alpha 
 undef_method :beta   # Remove every beta 
 
end 
 
 
x = Child. 
 
x.alpha     # parent alpha 
x.beta      # Error!




  remove_const 将会remove掉个常量.

  Ruby代码  

module Math 
 
 remove_const :PI 
 
end 
 
# No PI anymore!


  我们现在可以利用remove_const来移除掉个类定义(标识符其实也就是个常量):

  Ruby代码

 BriefCandle 
 def test 
  p "aaa" 
 end 
end 
 
out_out = BriefCandle. 
 
 Object 
 remove_const :BriefCandle 
end 
out=BriefCandle. 
out_out.test


  要注意remove_const和remove_method都是私有思路方法.



Tags:  ruby安装 ruby是什么意思 rubyonrails therubyway

延伸阅读

最新评论

发表评论