我有一个简单的函数,它使用JSON和'做某事'。主要部分工作正常但该功能不仅返回我想要的,而且还返回 .each 循环的结果!
代码:
module Puppet::Parser::Functions
newfunction(:mlh, :type => :rvalue) do |args|
lvm_default_hash = args[0]
lvm_additional_hash = args[1]
if lvm_additional_hash.keys.length == 1
if lvm_additional_hash.keys.include? 'logical_volumes'
# do stuff - we have only 'logical_volumes'
lvm_default_hash.keys.each do |key|
pv_array = Hash['physical_volumes' => lvm_default_hash[key]['physical_volumes']]
lv_hash = lvm_default_hash[key]['logical_volumes']
new_lv_hash = lvm_additional_hash['logical_volumes']
merged_lv_hash = Hash['logical_volumes' => lv_hash.merge(new_lv_hash)]
# this is what I want to return to init.pp
puts Hash[key => pv_array.merge(merged_lv_hash)]
end
end
end
end
end
init.pp 中的变量是:
$default_volume_groups = {
'sys' => {
'physical_volumes' => [
'/dev/sda2',
],
'logical_volumes' => {
'root' => {'size' => '4G'},
'swap' => {'size' => '256M'},
'var' => {'size' => '8G'},
'docker' => {'size' => '16G'},
},
},
}
和hieradata的第二个参数:
modified_volume_groups:
logical_volumes:
cloud_log:
size: '16G'
在 init.pp 中我有类似的东西来测试它:
notice(mlh($default_volume_groups, $modified_volume_groups))
给了我一个结果:
syslogical_volumesvarsize8Gdockersize16Gcloud_logsize16Gswapsize256Mrootsize4Gphysical_volumes/dev/sda2
Notice: Scope(Class[Ops_lvm]): sys
通知之前的“长”部分是来自 puts 的正确结果,但注意:Scope():sys 就是这样我不知道想要! 我知道这是每个循环对 default_volumes_groups 的结果:
lvm_default_hash.keys.each do |key|
# some stuff
end
如何阻止这种不必要的结果?它打破了我的木偶逻辑,因为我的 init.pp 看到了这个 sys ,而不是我想要的。
有人知道如何处理这样的问题吗?
谢谢!
答案 0 :(得分:1)
我找到了如何处理这个问题,但也许有人可以用这种方式解释我为什么这样做:)
这不起作用(短版):
module Puppet::Parser::Functions
newfunction(:mlh, :type => :rvalue) do |args|
lvm_default_hash = args[0]
lvm_additional_hash = args[1]
if lvm_additional_hash.keys.length == 1
if lvm_additional_hash.keys.include? 'logical_volumes'
lvm_default_hash.keys.each do |key|
pv_array = Hash['physical_volumes' => lvm_default_hash[key]['physical_volumes']]
lv_hash = lvm_default_hash[key]['logical_volumes']
new_lv_hash = lvm_additional_hash['logical_volumes']
merged_lv_hash = Hash['logical_volumes' => lv_hash.merge(new_lv_hash)]
puts Hash[key => pv_array.merge(merged_lv_hash)]
end
end
end
end
end
但这有效:
module Puppet::Parser::Functions
newfunction(:mlh, :type => :rvalue) do |args|
lvm_default_hash = args[0]
lvm_additional_hash = args[1]
# empty Hash
hash_to_return = {}
if lvm_additional_hash.keys.length == 1
if lvm_additional_hash.keys.include? 'logical_volumes'
lvm_default_hash.keys.each do |key|
pv_array = Hash['physical_volumes' => lvm_default_hash[key]['physical_volumes']]
lv_hash = lvm_default_hash[key]['logical_volumes']
new_lv_hash = lvm_additional_hash['logical_volumes']
merged_lv_hash = Hash['logical_volumes' => lv_hash.merge(new_lv_hash)]
# assigned value in the 'each' loop we want to return to puppet
hash_to_return = Hash[key => pv_array.merge(merged_lv_hash)]
end
# returned Hash - instead of previous 'puts'
return hash_to_return
end
end
end
end
现在我有我需要的东西!
Notice: Scope(Class[Ops_lvm]): sysphysical_volumes/de
答案 1 :(得分:1)
你已经得到了 - 第一个不起作用,因为在Ruby中,块或函数的返回值是最后一个被评估的语句。对于不起作用的情况,最后评估的语句是.each
。事实证明,each
评估它可以循环的可枚举。
一个简单的例子:
def foo
[1, 2, 3].each do |n|
puts n
end
end
如果我要运行它,函数的返回值将是数组:
> foo
1
2
3
=> [1, 2, 3]
所以你的工作是什么,因为评估的最后一件事是return hash_to_return
。你甚至可以去hash_to_return
它就可以了。
如果您想摆脱return
并稍微清理一下(如果您使用的是Ruby 1.9或更高版本),您可以将each
行替换为:
lvm_default_hash.keys.each_with_object({}) do |key, hash_to_return|
这是因为each_with_object
计算到“对象”(在这种情况下是传递给方法的空哈希,在块参数中称为hash_to_return
)。如果您这样做,可以删除return
以及初始化hash_to_return = {}
。
希望这有帮助!
答案 2 :(得分:0)
您的自定义函数具有右值类型,这意味着它需要返回值。如果您默认情况下未指定return <something>
,则您的最后一个陈述将隐含地返回
在上面的示例中,第一个无法正常工作,在每个块中都有最后一条语句:
puts Hash[key => pv_array.merge(merged_lv_hash)]
你的第二个例子是正确的,因为你在每个块中为hash_to_return设置了值,然后&#34;返回&#34;它在每个街区之外。不确定这是否是您想要的行为,因为上次分配的哈希值(在每个块内的最后一个循环中)将是从此函数返回的行为。