ruby

Table of Contents

iterator

each, map

map是将block施加与array的每一个成员之上,并将计算结果组织为新的array,each只有 前半部分,不会组织成新的array,collect 与map类似

ruby中迭代器很多,大部分是语法糖,有的甚至没什么差别。 大致分为两大类:

  1. 关注迭代过程
  2. 关注迭代返回值
a = [1,2,3,4,5]
a.each { |x|  x+1 }
a = [1,2,3,4,5]
a.map { |x| x+1}
a = [1,2,3,4,5]
a.collect { |x| x+1}
  • inject
    a = [1,2,3,4,5]
    sum = 10
    sum = a.inject{|sum,item| sum+item}
    
  • reject
    • chunk
    • count
    • cycle
    • detect
    • find
    • drop
    • each_cons
    • each_entry
    • each_slice
    • select
    • first
    • include?
    • memeber?
    • reduce

moduleEnumerable

  1. each
  2. <=>

block,lambda,proc

block

array = [1,2,3,4]
array.map! do |n|
  n * n
end

block 能工作是因为yield方法。yield 调用把原来函数中的代码执行推迟到代码块执行之后。

class Array
  def map!
    self.each_with_index do |value, index|
      self[index] = yield(value)
    end
  end
end

proc

代码块的问题是我们不能重用代码块,因为它没有名字。

a_proc = Proc.new { |n| n * n }
     class Array
 def map!(proc_object)
   self.each_with_index do |value, index|
     self[index] = proc_object.call(value)
   end
 end
end

array = [1,2,3,4]
a_proc.call(2)
array.map!(a_proc)

lambda

与 proc的区别:

  1. lambda检查传入的参数个数
    a = lambda { |x| puts "hi,#{x}"}
    a.call('Meler')
    a.call
    
    a = Proc.new{ |x| puts "hi,#{x}"}
    a.call('Meler')
    a.call
    
  2. return Proc里面的return会跳出正在执行的方法,并将值proc结果作为方法返回值。 lambda,就地返回值,return只跳出代码快,方法继续执行
                def proc_math
        Proc.new { return 1 + 1 }.call
       return 2 + 2
     end
     def lambda_math
       lambda { return 1 + 1 }.call
       return 2 + 2
     end
    
    proc_math
    lambda_math
    
  3. lambda新语法 ->
    a = lambda(x) {puts "hi,#{x}"}
    a  = ->(x) { puts "hi,#{x}" }
    a.call('sam')
    
  4. compare
def f1
  yield
end

def f2(&p)
  p.call
end

def f3(p)
  p.call
end

f1 { puts "f1" }
p = Proc.new{puts "f1"}
f1(&p)

f2 { puts "f2" }

f3(proc{ puts "f3"})

f3(Proc.new{puts "f3"})

f3(lambda{puts "f3"})

f3(-> {puts "f3})
["1", "2", "3"].map(&:to_i)
["1", "2", "3"].map {|i| i.to_i }

符号&会触发 :to_ito_proc 方法, to_proc 执行后会返回一个proc实例, 然后&会把 这个proc实例转换成一个block,我们需要要明白map方法后挂的是一个block,而不是 接收一个proc对象做为参数。 &:to_i 是一个block,block不能独立存在,同时你也没 有办法直接存储或传递它,必须把block挂在某个方法后面。

  1. block_given?

convert

&proc -> block 给最后一个具名参数加上&,就可以把block转化成proc副职给这个变量。

      def an_method(&proc)
   proc.call
end
x = 1
proc = an_method {"hello"}

why lambda and proc

  1. proc is more like a block and can convert with block convinencely.
  2. lambda is more like method
  3. ruby alway provide diversity
    1. scope (method lambda)

inheritance

      a = 'hello'
a.class.ancestors
String Enumerable Comparable Object Kernel

puts

    module M; end
module N; end
class C; end
class D < C include M end
object = D.new
class << object include N p ancestors end

在上面例子中,首先定义了module M和N,然后定义class C和D,其中D继承自C,并且包含 了M。我们通过class << object; end来让“隐身”的 class现身,然后在 object的singleton classinclude module N, 然后打印出object的ancestors 。从输出 的结果,我们可以清楚的看到Ruby中的继承顺序。

先查找单体类中是否定义改方法;是则执行该方法,否则转2 是否引入module,是则查找该module是否定义,否则转3 查找其原来的类(即D)是否定义改方法,依此类推,往继承树上查找

class,module

module include,extend 模块是方法和常量的集合,模块和类一样,其中的可以包括两种方法:实例方法 (Instance Method)、模块方法(Module Method)。当一个类混入(Mixin)一 个模块时,模块中的实例方法会成为该类的方法(具体是类的类方法还是实例方法,取决于 是include还是extend)。但是模块方法会被忽略,而且,模块方法可以虽然定义在模块中, 但是可以直接调用。

module Mod
    def func_instance
        puts 'Call: Instance Method'
    end

    def self.func_module
        puts 'Call: Module Method'
    end
end

class Clz
    include Mod
end

puts "Class Methods: #{ Clz.methods.grep /^func/ }"
puts "Instance Methods: #{ Clz.instance_methods.grep /^func/ }"

class ClzNew
    extend Mod
end

puts "Class Methods: #{ ClzNew.methods.grep /^func/ }"
puts "Instance Methods: #{ ClzNew.instance_methods.grep /^func/ }"

# func_isntance为ClzNew的类方法
ClzNew.func_instance

scope

使用 define_class, define_method 和block的重点都是作用域不同。 method本身也只是可调用对象,但是在调用它的对象作用域上。而block作用域在定义它的地方。

def a
  return 2
end
a
      a = 1
a

self

ruby中任何东西都是对象,所以任何代码都有一个相关的对象作为上下文环境。这个对象就用self指代。

    class A
      self
def a
   self
end
    end
   def location
     if  !postcode.nil? && postcode.length==3
       postcode = '0' + postcode
     end
     suburb_name + ' ' + state + ' ' + postcode
   end
  end

def hello
  'hello'
end
hello
if hello.nil?
  hello=0
end
hello

hooks,callback

alias, alias\method

alias是ruby语言关键字,对当前类的method定义别名, alias_method 是库增强(好像是active support),参数是symbol

      class Boss
def name
   p "Andrea"
end
alias :full_name :name
end

Boss.new.name
Boss.new.full_name
class Employee < Boss

 def name
    p "Bob"
 end

end

Employee.new.name
Employee.new.full_name

因为本对象找不到,所以调用了父类的 full_name,alias是ruby关键字

alias_method 是一个方法而已,定义在module之中,只在当前上下文执行。

class Boss
def name
   p "Andrea"
end
def self.apply_alias
    alias_method :full_name, :name
end
apply_alias
 end

 class Employee < Boss
     def name
        p "Bob"
     end
     apply_alias
 end

 Boss.new.name
 Boss.new.full_name
 Employee.new.name
 Employee.new.full_name

Module#included(parent) (include)

Module#append_features (extend)

ghost method

异常捕获 rails Model.find_by_name

def method_missing(method_id, *args, &block)
    case method.to_s
   when /^find_by_([_a-zA-Z]\w*)$/
    attr_names = $1.split('_and_')
    conditions = Hash[attr_names.map {|a| [a, arg[attr_names.index(a)]]}]
    relation = scoped
    relation.send(:where, conditions).first
  else
    super
  end
end
class Bug
  def method_missing(first,*args)
   args.each do |x|
     puts "your params is:" + x.to_s
     last_param = x
   end
   puts "you call #{first} with params #{last_params}"
  end
end

Bug.new.hello(1,2,3)

reflection

  1. respond_to?
  2. class
  3. methods
  4. instance_methods
  5. instance_variabl

tips

  1. !!var
    def confirmed?
        !!confirmed_at
    end
    
  2. a += 1
  3. code unless true
  4. error ||= env["omniauth.error.type"].to\s