Class: PuppetDB::ASTNode

Inherits:
Object
  • Object
show all
Defined in:
lib/puppetdb/astnode.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, value, children = []) ⇒ ASTNode

Returns a new instance of ASTNode.



4
5
6
7
8
# File 'lib/puppetdb/astnode.rb', line 4

def initialize(type, value, children = [])
  @type = type
  @value = value
  @children = children
end

Instance Attribute Details

#childrenObject

Returns the value of attribute children.



2
3
4
# File 'lib/puppetdb/astnode.rb', line 2

def children
  @children
end

#typeObject

Returns the value of attribute type.



2
3
4
# File 'lib/puppetdb/astnode.rb', line 2

def type
  @type
end

#valueObject

Returns the value of attribute value.



2
3
4
# File 'lib/puppetdb/astnode.rb', line 2

def value
  @value
end

Instance Method Details

#capitalize_class(name) ⇒ Object



10
11
12
# File 'lib/puppetdb/astnode.rb', line 10

def capitalize_class(name)
  name.to_s.split('::').collect(&:capitalize).join('::')
end

#comparison(left, right) ⇒ Object

Helper method to produce a comparison expression



138
139
140
141
142
143
144
# File 'lib/puppetdb/astnode.rb', line 138

def comparison(left, right)
  if @value[0] == '!'
    ['not', [@value[1], left, right]]
  else
    [@value, left, right]
  end
end

#evaluate(mode = [:nodes]) ⇒ Array

Evalutate the node and all children

Parameters:

  • mode (Symbol) (defaults to: [:nodes])

    The query mode we are evaluating for

Returns:

  • (Array)

    the resulting PuppetDB query



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/puppetdb/astnode.rb', line 55

def evaluate(mode = [:nodes])
  case @type
  when :comparison
    left = @children[0].evaluate(mode)
    right = @children[1].evaluate(mode)
    if mode.last == :subquery
      left = left[0] if left.length == 1
      comparison(left, right)
    elsif mode.last == :resources
      if left[0] == 'tag'
        comparison(left[0], right)
      else
        comparison(['parameter', left[0]], right)
      end
    else
      subquery(mode.last,
               :fact_contents,
               ['and', left, comparison('value', right)])
    end
  when :boolean
    value
  when :string
    value
  when :number
    value
  when :date
    require 'chronic'
    ret = Chronic.parse(value, :guess => false).first.utc.iso8601
    fail "Failed to parse datetime: #{value}" if ret.nil?
    ret
  when :booleanop
    [value.to_s, *evaluate_children(mode)]
  when :subquery
    mode.push :subquery
    ret = subquery(mode[-2], value + 's', children[0].evaluate(mode))
    mode.pop
    ret
  when :regexp_node_match
    mode.push :regexp
    ret = ['~', 'certname', Regexp.escape(value.evaluate(mode))]
    mode.pop
    ret
  when :identifier_path
    if mode.last == :subquery || mode.last == :resources
      evaluate_children(mode)
    elsif mode.last == :regexp
      evaluate_children(mode).join '.'
    else
      # Check if any of the children are of regexp type
      # in that case we need to escape the others and use the ~> operator
      if children.any? { |c| c.type == :regexp_identifier }
        mode.push :regexp
        ret = ['~>', 'path', evaluate_children(mode)]
        mode.pop
        ret
      else
        ['=', 'path', evaluate_children(mode)]
      end
    end
  when :regexp_identifier
    value
  when :identifier
    mode.last == :regexp ? Regexp.escape(value) : value
  when :resource
    mode.push :resources
    regexp = value[:title].type == :regexp_identifier
    if !regexp && value[:type].capitalize == 'Class'
      title = capitalize_class(value[:title].evaluate)
    else
      title = value[:title].evaluate
    end
    ret = subquery(mode[-2], :resources,
                   ['and',
                    ['=', 'type', capitalize_class(value[:type])],
                    [regexp ? '~' : '=', 'title', title],
                    ['=', 'exported', value[:exported]],
                    *evaluate_children(mode)])
    mode.pop
    ret
  end
end

#evaluate_children(mode) ⇒ Array

Evaluate all children nodes

Returns:

  • (Array)

    The evaluate results of the children nodes



149
150
151
# File 'lib/puppetdb/astnode.rb', line 149

def evaluate_children(mode)
  children.collect { |c| c.evaluate mode }
end

#optimizeObject

Go through the AST and optimize boolean expressions into triplets etc Changes the AST in place

Returns:

  • The optimized AST



37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/puppetdb/astnode.rb', line 37

def optimize
  case @type
  when :booleanop
    @children.each do |c|
      if c.type == :booleanop && c.value == @value
        c.children.each { |cc| @children << cc }
        @children.delete c
      end
    end
  end
  @children.each(&:optimize)
  self
end

#subquery(from_mode, to_mode, query) ⇒ Array

Generate the the query code for a subquery

As a special case, the from_mode of :none will not wrap the subquery at all, returning it as is.

Parameters:

  • from_mode (Symbol)

    the mode you want to subquery from

  • to_mode (Symbol)

    the mode you want to subquery to

  • query

    the query inside the subquery

Returns:

  • (Array)

    the resulting subquery



23
24
25
26
27
28
29
30
31
# File 'lib/puppetdb/astnode.rb', line 23

def subquery(from_mode, to_mode, query)
  if from_mode == :none
    return query
  else
    return ['in', 'certname',
            ['extract', 'certname',
             ["select_#{to_mode}", query]]]
  end
end