Ruby的块语法如何工作?

时间:2016-05-11 21:43:11

标签: ruby-on-rails ruby

我是Ruby的新手并试图理解这种语法:

create_table :posts do |t|
  t.string :title
  t.string :content
  t.string :likes
  t.string :comments

  t.timestamps null: false
end

我完全理解这个代码正在做什么,但我不明白 它是如何工作的。更具体地说,我理解create_table是一种方法,而:posts是一个参数,但我不了解其余的代码。

3 个答案:

答案 0 :(得分:8)

支持它:)

  1. create_table是一种方法。 :posts是作为参数传递的符号。括号是可选的,因此它看起来很奇怪,但它是一个简单的方法调用。

  2. doend之间的所有内容都是代码块。这是将代码作为参数传递给方法的众多方法之一。代码块非常适用于常见情况。其他类似(但不同)的方法是使用Proclambda->

  3. |t|是由create_table传递到代码块的参数。 create_table将执行您的代码块,并将表对象作为单个参数传递给它。您选择命名该对象t

  4. 现在在您的代码块中,您在对象string上调用方法t并将其作为参数传递。你这样做了四次。括号再次是可选的。

  5. 您正在同一个对象timestamps上调用t方法。在这里你传递一个参数,它是一个值为{ :null => false }的哈希。

    • 不仅括号是可选的,而且当将散列作为最后一个或仅作为参数传递给方法时,花括号也是可选的。
    • null: false{ :null => false }的快捷语法。
  6. 所以上述所有内容都相当于:

    create_table(:posts) do |t|
      t.string(:title)
      t.string(:content)
      t.string(:likes)
      t.string(:comments)
      t.timestamps({:null => false})
    end
    

答案 1 :(得分:4)

让我们首先忘记Active Record并专注于代码结构本身。这是该结构的超简单版本。

class MyBuilder
  def initialize
    # keys are property names, values are options
    @properties = {}
  end

  def property(name, options={})
    @properties[name] = options
  end

  def build
    # For simplicity, just return all properties
    @properties
  end
end

def create_thing(name)
  puts "Begin creating #{name}"

  builder = MyBuilder.new

  puts "Let user use the builder to define properties"
  yield builder

  puts "Consume the builder"
  properties = builder.build

  puts "Persist changes to #{name}..."
  # For simplicity just print them out
  p properties

  puts 'done'
end

create_thing :bar do |builder|
  builder.property :counter, color: 'brown'
  builder.property :wine_storage, texture: 'wood'
end

请手动输入上面的代码以获得一些感觉。

虽然上面的代码与Active Record无关,但它具有与迁移相同的结构。

当调用create_table时,它实例化一个构建器(类型为TableDefinition),并且"推送"该构建器到块(通过yield)以便让用户定义表列。当用户完成定义列时,构建器稍后将被create_table使用。

答案 2 :(得分:2)

学习Ruby的一个难点是,像smalltalk等人一样,你可以传递代码和数据。 将代码传递给方法的一种方法是使用代码块。 然后,您可以使用yield调用方法定义中的代码块,其中“插入此代码块代替yield”:

def do_it
  yield
end

do_it { 2 + 4 }
=> 6 

您还可以从方法定义向代码块发送参数。 这就是| t |的地方进来:

def do_it_with_ten
  yield 10
end

do_it_with_ten { |t| (2 + 4) * t }
=> 60 

请注意,花括号等同于do..end。

我猜这是你在其中找到的代码:

def create_table(name, options = {})
  table_definition = TableDefinition.new(self)
  table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false

  yield table_definition

  if options[:force]
    drop_table(name) rescue nil
  end

  create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
  create_sql << "#{name} ("
  create_sql << table_definition.to_sql
  create_sql << ") #{options[:options]}"
  execute create_sql
end

这正是您正在寻找的。这是我们调用的create_table方法的定义。您可以使用参数table_definition来查看收益率。