您正在混合使用许多不同的条件变体,其中大部分是 Chef 的一部分,而不是 Ruby。让我尝试一一描述不同的选项。
通常,acase
大致相当于一系列if
andelsif
语句。你的case
上面
case node[:languages][:ruby][:host_cpu]
when "x86_64"
...
when "i686"
...
end
因此大致相当于
if node[:languages][:ruby][:host_cpu] == "x86_64"
...
elsif node[:languages][:ruby][:host_cpu] == "i686"
...
end
附带说明一下,case
实际上使用的===
运算符通常不是可交换的,但功能更强大。对于简单的比较,它的工作原理与此相同==
。这两种变体都是 Ruby 语言的一部分,您可以在其中编写食谱。
您提到的其他选项实际上是 Chef 在 Ruby 之上定义的 API 的一部分。这通常被称为 Chef DSL(代表域特定语言,即语言的扩展或改编,在这种情况下 Ruby 用于特定使用域,在这种情况下是配置管理。)
该platform?
方法是 Chef 定义的一种方法,用于检查当前平台是否是传递的值之一。您可以阅读更多相关信息(以及类似的方法,例如platform_family?
Chef docs 现在推荐的用于一般食谱的方法和一些常用的 ruby idioms。
附带说明一下:您可能会惊讶于 Ruby 允许?
和!
字符出现在方法名称的末尾,这使得 Ruby 在这方面的类似语言中相当独特。这些字符只是方法名称的一部分,对语言没有特殊意义。它们仅按惯例用于程序员以更好地识别方法的目的。如果一个方法?
的末尾有一个,它将用于检查某些条件,并期望返回一个真值或假值。以 a!
结尾的方法通常会执行一些潜在的危险操作,例如更改对象、删除内容……同样,这只是一个约定,不会被语言解释。
您提到的最后一个选项,only_if
and 通过扩展not_if
用于定义 Chef 资源的条件,以确保它们仅在某个条件为真时(或使用时not_if
,如果为假)执行。由于这些属性仅用于 Chef 资源,它们自然也由 Chef 定义。
要了解它们为何有用,有必要了解 Chef 运行的工作原理。详细信息可以在Chef Run 的解剖描述中找到。重要的是,您基本上有两个执行阶段:资源编译和收敛。第一步,执行定义资源的实际代码。在这里,您的case
语句中的代码也将运行。在加载了所有配方并定义了所有资源后,Chef 进入第二阶段,即收敛阶段。在那里,执行更改的资源的实际实现(创建文件和目录,安装包,...)运行。只有在这个阶段,才会检查only_if
和not_if
条件。
其实你可以观察到两者的区别
file "/tmp/helloworld"
action :create
content "hello world"
end
if File.exist?("/tmp/helloworld")
file "/tmp/foobar"
action :create
content "foobar"
end
end
和
file "/tmp/helloworld"
action :create
content "hello world"
end
file "/tmp/foobar"
action :create
content "foobar"
only_if{ File.exist?("/tmp/helloworld") }
end
在第一个变体中,/tmp/foobar
在资源编译期间检查条件是否存在。此时,实际创建/tmp/helloworld
文件的代码尚未运行,因为它仅在转换步骤中运行。因此,在您第一次运行期间,/tmp/foobar
不会创建该文件。
然而,在第二个变体中,检查是only_if
在转换期间进行评估的。在这里,您会注意到这两个文件都是在第一次运行时创建的。
如果您想了解更多关于 Ruby 中条件的定义是如何工作的(而且您绝对应该),您可以阅读Ruby Blocks,它们或多或少是可以传递以供以后执行的代码片段。