Darcy Tang’s Blog

记录一点编程心得

Puppet3.2的迭代器

Puppet在最新的3.2版本中实现了lambda风格的迭代器语法,而且支持链式语法。当然要使用的话,需要在puppet.conf中启用parser=future

目前已经实现的有:

  • each/foreach
  • slice
  • select
  • collect
  • reject
  • reduce

含义和作用域与Ruby中的基本一致,基本用法也一致。

1
2
3
4
$a = [1,2,3]
each($a) |$value| { notice $value } # 迭代数组

[1,20,3].select |$value| {$value < 10 }.each |$value| { notice $value } # 链式语法

根据说明,也可以使用多种风格的语法

1
2
3
4
5
6
each($x)  |$value| {  }
$x.each   |$value| {  }
$x.each() |$value| {  }

slice($x, 2) |$value| {  }
$x.slice(2)  |$value| {  }

或者

1
2
3
4
5
6
7
8
# Alternative 0 (as shown): Parameters are outside the lambda block.
[1,2,3].each |$value| { notice $value }

# Alternative 1: Parameters are inside the lambda block.
[1,2,3].each { |$value| notice $value }

# Alternative 2: A fat arrow is placed after the parameters.
[1,2,3].each |$value| => { notice $value }

但是我自己实验,只有

1
[1,2,3].each { |$value| notice $value }

的方式成功了。

其实这些函数都是通过添加Puppet自定义函数的形式实现的,lambda表达式作为一个参数进行处理,调一个call就执行了。

比如迭代哈希的关键代码就是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  receiver = args[0]
  pblock = args[1]
  foreach_Hash(receiver, self, pblock)
  def foreach_Hash(o, scope, pblock)
      return nil unless pblock
      serving_size = pblock.parameter_count

      enumerator = o.each_pair

      if serving_size == 1
        (o.size).times do
          pblock.call(scope, enumerator.next)
        end
      else
        (o.size).times do
          pblock.call(scope, *enumerator.next)
        end
      end
      o
  end

其实还是使用了Ruby中的each_pair这个迭代器。在Puppet中写的lambda表达式还是循环调用,并把each_pair作为每一次的参数传进去用。

感觉Puppet在解释lambda表达式时应该还做了些工作,今天就不研究了。

Comments