【问题标题】:How does Ruby's block syntax work?Ruby 的块语法是如何工作的?
【发布时间】:2016-05-11 21:43:10
【问题描述】:

我是 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是一个参数,但是我不明白其余的代码。

【问题讨论】:

  • 你读过guides.rubyonrails.org/…吗?如果是这样,也许您可​​以询问那里尚未涵盖的内容。
  • 用英文写作时请使用英文标点。
  • @sawa 对不起我的英语不好
  • @DaveSchweisguth 我没有问那个代码是做什么的,我只是问了那个代码是如何工作的或者那个代码的结构。我知道在数据库中创建表的代码,并且我了解迁移、播种等

标签: ruby-on-rails ruby


【解决方案1】:

为它做好准备:)

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

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

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

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

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

    • 在将哈希作为最后一个参数或唯一参数传递给方法时,不仅括号是可选的,而且花括号也是可选的。
    • null: false,是{ :null => false } 的快捷语法。

所以以上所有内容都等价于:

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

【讨论】:

  • "null: false, is a shortcut" 尽管它是一个快捷方式,但它并不是设计为一体的,它只是新的 ruby​​ 2.x 哈希语法
  • @Koen。从技术上讲,1.9 和更新的版本支持它,所以它已经存在了一段时间。如果您仍在使用 1.8 风格,则需要一些时间来适应,但这样就不会那么大惊小怪了。
  • @Koen。不是完全。当键是符号时,它是哈希的快捷语法。您不能在键不是符号的情况下创建哈希(例如,字符串、数字、具有“较新”语法的对象。所以它仍然是一种语法糖。
  • 感谢@quardome 的解释,现在已经很清楚了:)
【解决方案2】:

让我们先忘掉 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 类型),并将该构建器“推”到块中(通过yielding 它)以便让用户定义表列。当用户完成对列的定义时,create_table 稍后会使用该构建器。

【讨论】:

  • 你可以在最后一个块中使用另一个变量名(例如b)来强调它独立于产生的变量名。
  • 谢谢@Aetherus 这就是我要找的:)
【解决方案3】:

学习 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。

我猜这是你找到的带有 yield 的代码:

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查看产量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-15
    • 2011-02-12
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    相关资源
    最近更新 更多