为什么 rspec puppet 在切换 ruby 版本时失败并出现未定义的方法错误?
Why does rspec puppet fail with undefined method error when switching ruby versions?
我在以下 gem 文件上使用 ruby 版本 1.8.7
运行 bundle install
开发了我的人偶模块并且 rspec 测试成功(木偶也是运行):
source 'https://rubygems.org'
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', '3.7.5'
end
gem 'metadata-json-lint'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
gem 'puppet-lint', '>= 1.0.0'
gem 'facter', '>= 1.7.0'
gem 'rspec-puppet-facts'
# rspec must be v2 for ruby 1.8.7
if RUBY_VERSION >= '1.8.7' and RUBY_VERSION < '1.9'
gem 'rspec', '~> 2.0'
end
然而,当我在我的 CI 服务器上的同一个 Gemfile
上执行 bundle install
时 ruby 1.9.3
我遇到了以下 rspec失败:
常见的错误是:
Puppet::Error:
Failed to parse template silex/var/config/settings.json.erb:
Filepath: /var/tmp/silex/spec/fixtures/modules/silex/templates/var/config/settings.json.erb
Line: 4
Detail: undefined method `each_with_index' for "default":String
使用each_with_index
方法的模板:
{
"elasticsearch.settings": {
"connections": [
<% @elastic_hosts.each_with_index do |host,i| -%>
{"host":"<%= host['ip'] %>", "port": <%= host['port'] %> }<%= ',' if i < (@elastic_hosts.size - 1) -%>
<% end -%>
],
"index": "<%= @elastic_index %>"
}
},
"cache.lifetime": <%= @elastic_cache_lifetime %>,
"environment": "dev",
"trusted": [
<% @trusted_hosts.each_with_index do |host,i| -%>
{"host":"<%= host['host'] %>"}<%= ',' if i < (@trusted_hosts.size - 1) -%>
<% end -%>
],
"homepage.settings": {
"hero.count": 20,
"list.count": 20
}
}
我不明白为什么使用不同版本的 ruby 会失败?我也试过 ruby 2.1.1
结果相同。结果仅在具有 ruby 1.8.7
的 CI 服务器上成功(与我用于开发模块的版本相同)。
更新 1
似乎因为 elastic_hosts
是一个散列映射,而我有一个字符串,所以它失败了。我确实与 trusted_hosts
(另一个哈希映射)一起解决了这个问题,这导致大部分测试都通过了,但错误仍然存在。
注意:错误与上面突出显示的常见错误没有变化。
我还用完整内容更新了上面的模板文件。
如果您查看我的配置规范文件,我没有在任何地方将 default
指定为字符串,但它告诉我这是错误..
修复
正如我怀疑的那样,我的初始化规范 class 设置了默认值并添加了 elastic_hosts
和 trusted_hosts
的 hiera 查找解决了这个问题。
更新 2
此行为可在版本 1.8.7
和版本 > 1.9.3
之间重现。它似乎与哈希的处理方式有关。
答案很简单:因为 each
方法已从较新版本的 Ruby 中删除。一个原因是该方法在 UTF-8
字符串的上下文中令人困惑:each
是否迭代 每个字符 或 每个字节 ?
但是有 each_char
,您可以将其与 with_index
结合使用:
string.each_char.with_index do |char, i|
# ...
end
此外,您在 @elastic_hosts
上调用该方法,在代码片段中显然应该是 hosts
的数组。但是错误消息告诉我们 @elastic_hosts
是字符串 default
。因此,使用 each_with_index
的方法调用失败是有道理的,但迭代本身似乎没有意义。我建议检查 @elastic_hosts
是否设置正确。
我在以下 gem 文件上使用 ruby 版本 1.8.7
运行 bundle install
开发了我的人偶模块并且 rspec 测试成功(木偶也是运行):
source 'https://rubygems.org'
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', '3.7.5'
end
gem 'metadata-json-lint'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
gem 'puppet-lint', '>= 1.0.0'
gem 'facter', '>= 1.7.0'
gem 'rspec-puppet-facts'
# rspec must be v2 for ruby 1.8.7
if RUBY_VERSION >= '1.8.7' and RUBY_VERSION < '1.9'
gem 'rspec', '~> 2.0'
end
然而,当我在我的 CI 服务器上的同一个 Gemfile
上执行 bundle install
时 ruby 1.9.3
我遇到了以下 rspec失败:
常见的错误是:
Puppet::Error:
Failed to parse template silex/var/config/settings.json.erb:
Filepath: /var/tmp/silex/spec/fixtures/modules/silex/templates/var/config/settings.json.erb
Line: 4
Detail: undefined method `each_with_index' for "default":String
使用each_with_index
方法的模板:
{
"elasticsearch.settings": {
"connections": [
<% @elastic_hosts.each_with_index do |host,i| -%>
{"host":"<%= host['ip'] %>", "port": <%= host['port'] %> }<%= ',' if i < (@elastic_hosts.size - 1) -%>
<% end -%>
],
"index": "<%= @elastic_index %>"
}
},
"cache.lifetime": <%= @elastic_cache_lifetime %>,
"environment": "dev",
"trusted": [
<% @trusted_hosts.each_with_index do |host,i| -%>
{"host":"<%= host['host'] %>"}<%= ',' if i < (@trusted_hosts.size - 1) -%>
<% end -%>
],
"homepage.settings": {
"hero.count": 20,
"list.count": 20
}
}
我不明白为什么使用不同版本的 ruby 会失败?我也试过 ruby 2.1.1
结果相同。结果仅在具有 ruby 1.8.7
的 CI 服务器上成功(与我用于开发模块的版本相同)。
更新 1
似乎因为 elastic_hosts
是一个散列映射,而我有一个字符串,所以它失败了。我确实与 trusted_hosts
(另一个哈希映射)一起解决了这个问题,这导致大部分测试都通过了,但错误仍然存在。
注意:错误与上面突出显示的常见错误没有变化。
我还用完整内容更新了上面的模板文件。
如果您查看我的配置规范文件,我没有在任何地方将 default
指定为字符串,但它告诉我这是错误..
修复
正如我怀疑的那样,我的初始化规范 class 设置了默认值并添加了 elastic_hosts
和 trusted_hosts
的 hiera 查找解决了这个问题。
更新 2
此行为可在版本 1.8.7
和版本 > 1.9.3
之间重现。它似乎与哈希的处理方式有关。
答案很简单:因为 each
方法已从较新版本的 Ruby 中删除。一个原因是该方法在 UTF-8
字符串的上下文中令人困惑:each
是否迭代 每个字符 或 每个字节 ?
但是有 each_char
,您可以将其与 with_index
结合使用:
string.each_char.with_index do |char, i|
# ...
end
此外,您在 @elastic_hosts
上调用该方法,在代码片段中显然应该是 hosts
的数组。但是错误消息告诉我们 @elastic_hosts
是字符串 default
。因此,使用 each_with_index
的方法调用失败是有道理的,但迭代本身似乎没有意义。我建议检查 @elastic_hosts
是否设置正确。