Class: Retrospec::Puppet::RspecDumper

Inherits:
Puppet::Pops::Model::TreeDumper
  • Object
show all
Defined in:
lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb

Direct Known Subclasses

RspecDumperFull

Instance Attribute Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



310
311
312
313
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 310

def method_missing(name, *args, &block)
  logger.debug("Method #{name} called".warning)
  []
end

Instance Attribute Details

#var_storeObject (readonly)

Returns the value of attribute var_store.



10
11
12
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 10

def var_store
  @var_store
end

Instance Method Details

#add_var_to_store(key, value, force = false, type = :scope) ⇒ Object

adds a variable to the store, its value and type of scope



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 88

def add_var_to_store(key, value, force=false, type=:scope)
  key = normalize_key(key)
  if var_store.has_key?(key) and !force
    logger.debug ("Prevented from writing #{key} with value #{value}".info)
  else
    logger.debug("storing #{key} with value #{value}".yellow)
    var_store[key]= {:value => value, :type => type}
    other_key = key.split('::').last
    if key != other_key
      other_key = "$#{other_key}"
      unless key.split('::').first == '$'
        add_var_to_store(other_key, value, false, type)
      end

    end
  end
  value
end

#dump_AccessExpression(o) ⇒ String

x prints as (slice x y)

Parameters:

  • o (Puppet::Pops::Model::AccessExpression)

Returns:

  • (String)

    the value of the array expression



407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 407

def dump_AccessExpression o
  # o.keys.pop is the item to get in the array
  # o.left_expr is the array
  if o.left_expr.is_a?(::Puppet::Pops::Model::QualifiedReference)
    "#{dump_transform(o.left_expr).capitalize}" + dump_transform(o.keys).to_s.gsub("\"",'')
  else
    begin
      arr = dump_transform(o.left_expr)
      element_number = dump_transform(o.keys[0]).to_i
      arr.at(element_number)
    rescue NoMethodError => e
      puts "Invalid access of array element, check array variables in your puppet code?".fatal
    end
  end
end

#dump_Array(o) ⇒ Object



107
108
109
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 107

def dump_Array o
  o.collect {|e| dump_transform(e) }
end

#dump_AssignmentExpression(o) ⇒ Object

this doesn’t return anything as we use it to store variables

Parameters:

  • o (Puppet::Pops::Model::AssignmentExpression)


348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 348

def dump_AssignmentExpression o
  oper = o.operator.to_s
  result = []
  case oper
  when '='
    # we don't know the output type of a function call, so just assign nill
    # no need to add it to the var_store since its always the same
    # without this separation, values will get stored
    if o.right_expr.class == ::Puppet::Pops::Model::CallNamedFunctionExpression
      value = nil
    else
      value = dump(o.right_expr)
      key = dump(o.left_expr)
      # we dont want empty variables storing empty values
      unless key == value
        add_var_to_store(key, value, true)
      end
    end
    result
  else
    [o.operator.to_s, dump_transform(o.left_expr), dump_transform(o.right_expr)]
  end
end

#dump_AttributeOperation(o) ⇒ Object

Produces (name => expr) or (name +> expr)

Parameters:

  • o (Puppet::Pops::Model::AttributeOperation)


398
399
400
401
402
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 398

def dump_AttributeOperation o
  key = o.attribute_name
  value = dump_transform(o.value_expr) || nil
  [key.inspect, o.operator, value.inspect + ',']
end

#dump_BlockExpression(o) ⇒ Object

Parameters:

  • o (Puppet::Pops::Model::BlockExpression)


373
374
375
376
377
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 373

def dump_BlockExpression o
  result = [:break]
  o.statements.each {|x| result << dump_transform(x) }
  result
end

#dump_CallMethodExpression(o) ⇒ String

Returns the value of the expression or example value.

Parameters:

  • o (Puppet::Pops::Model::CallMethodExpression)

Returns:

  • (String)

    the value of the expression or example value



426
427
428
429
430
431
432
433
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 426

def dump_CallMethodExpression o
  # ie. ["call-method", [".", "$::facttest", "split"], "/"]
  result = [o.rval_required ? "# some_value" : do_dump(o.functor_expr),'(' ]
  o.arguments.collect {|a| result << do_dump(a) }
  results << ')'
  result << do_dump(o.lambda) if o.lambda
  result
end

#dump_CapabilityMapping(o) ⇒ Object



493
494
495
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 493

def dump_CapabilityMapping o
  [o.kind, dump_transform(o.component), o.capability, dump_transform(o.mappings)]
end

#dump_ConcatenatedString(o) ⇒ Object

Interpolated strings are shown as (cat seg0 seg1 … segN)



322
323
324
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 322

def dump_ConcatenatedString o
  o.segments.collect {|x| dump_transform(x)}.join
end

#dump_HostClassDefinition(o) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 199

def dump_HostClassDefinition o
  result = ["describe #{o.name.inspect}", :do]
  result << ['let(:params)', :do, '{', :break]
  result << o.parameters.collect {|k| dump_transform(k)}
  result << ['}', :end]
  # result << ["inherits", o.parent_class] if o.parent_class
  # we need to process the body so that we can relize which facts are used
  body_result = []
  if o.body
    body_result << [dump_transform(o.body)]
  else
    body_result << []
  end
  result << [:break,:break,'let(:facts)', :do, '{',:break]
  result << dump_top_scope_vars
  result << ['}',:end]
  result << body_result
  result << [:end]
  result
end

#dump_LiteralDefault(o) ⇒ Object



469
470
471
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 469

def dump_LiteralDefault o
  ":default"
end

#dump_LiteralFloat(o) ⇒ Object



435
436
437
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 435

def dump_LiteralFloat o
  o.value.to_s
end

#dump_LiteralHash(o) ⇒ Object



460
461
462
463
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 460

def dump_LiteralHash o
  data = o.entries.collect {|x| dump_transform(x)}
  Hash[*data.flatten]
end

#dump_LiteralInteger(o) ⇒ Object



439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 439

def dump_LiteralInteger o
  case o.radix
  when 10
    o.value.to_s
  when 8
    "0%o" % o.value
  when 16
    "0x%X" % o.value
  else
    "bad radix:" + o.value.to_s
  end
end

#dump_LiteralList(o) ⇒ Object



456
457
458
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 456

def dump_LiteralList o
  o.values.collect {|x| dump_transform(x)}
end

#dump_LiteralRegularExpression(o) ⇒ Object



477
478
479
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 477

def dump_LiteralRegularExpression o
  "/#{o.value.source}/"
end

#dump_LiteralString(o) ⇒ Object



465
466
467
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 465

def dump_LiteralString o
  "#{o.value}"
end

#dump_LiteralUndef(o) ⇒ Object



473
474
475
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 473

def dump_LiteralUndef o
  :undef
end

#dump_LiteralValue(o) ⇒ Object



452
453
454
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 452

def dump_LiteralValue o
  o.value
end

#dump_NamedAccessExpression(o) ⇒ Object

ie. $::var1.split(‘;’)

Parameters:

  • o (Puppet::Pops::Model::NamedAccessExpression)


317
318
319
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 317

def dump_NamedAccessExpression o
  [do_dump(o.left_expr), ".", do_dump(o.right_expr)]
end

#dump_NilClass(o) ⇒ Object



485
486
487
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 485

def dump_NilClass o
  :undef
end

#dump_Nop(o) ⇒ Object



481
482
483
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 481

def dump_Nop o
  ":nop"
end

#dump_NotExpression(o) ⇒ Object



489
490
491
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 489

def dump_NotExpression o
  ['!', dump(o.expr)]
end

#dump_Object(o) ⇒ Object



507
508
509
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 507

def dump_Object o
  []
end

#dump_Parameter(o) ⇒ Object

Produces parameters as name, or (= name value)



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 221

def dump_Parameter o
  name_prefix = o.captures_rest ? '*' : ''
  name_part = "#{name_prefix}#{o.name}"
  data_type = dump_transform(dump_transform(o.value)).first || dump_transform(o.type_expr)

  # records what is most likely a variable of some time and its value
  variable_value = dump_transform(o.value)
  # need a case for Puppet::Pops::Model::LambdaExpression
  if o.eContainer.class == ::Puppet::Pops::Model::LambdaExpression
    add_var_to_store("#{name_part}", variable_value, false, :lambda_scope)
  else
    parent_name = o.eContainer.name
    add_var_to_store("#{parent_name}::#{name_part}", variable_value, false, :parameter)
  end
  if o.value && o.type_expr
    value = {:type => data_type, :name => name_part, :required => false, :default_value => variable_value}
  elsif o.value
    value = {:type => data_type, :name => name_part, :default_value => variable_value, :required => false}
  elsif o.type_expr
    value = {:type => data_type, :name => name_part, :required => true,  :default_value => ''}
  else
    value = {:type => data_type, :name => name_part, :default_value => '', :required => true}
  end
  if value[:required]
    ['  ', "#{value[:name]}:", 'nil,', :break]
  else
    ['  ', "# #{value[:name]}:", value[:default_value].inspect + ',', :break]
  end
end

#dump_ParenthesizedExpression(o) ⇒ Object



497
498
499
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 497

def dump_ParenthesizedExpression o
  dump_transform(o.expr)
end

#dump_Program(o) ⇒ Object

Hides that Program exists in the output (only its body is shown), the definitions are just references to contained classes, resource types, and nodes



503
504
505
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 503

def dump_Program(o)
  dump(o.body)
end

#dump_RelationshipExpression(o) ⇒ Object

defines the resource expression and outputs -> when used this would be the place to insert relationsip matchers

Parameters:

  • o (Puppet::Pops::Model::RelationshipExpression)


392
393
394
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 392

def dump_RelationshipExpression o
  [dump_transform(o.left_expr), dump_transform(o.right_expr)]
end

#dump_Resource_Relationship(o) ⇒ Object

this will determine and dump the resource requirement by comparing itself against the resource relationship expression



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 253

def dump_Resource_Relationship o
  result = []
  id = o.eContainer.object_id # the id of this container
  relationship = o.eContainer.eContainer.eContainer.eContents.first
  if relationship.respond_to?(:left_expr)
    if relationship.left_expr.object_id == id
      type_name = dump(relationship.right_expr.type_name).capitalize
      result += relationship.right_expr.bodies.map do |b|
        title = dump(b.title)
        [:break,".that_comes_before('#{type_name}[#{title}]')"]
      end.flatten
    else
      if relationship.left_expr.respond_to?(:type_name)
        type_name = dump(relationship.left_expr.type_name).capitalize
        result += relationship.left_expr.bodies.map do |b|
          title = dump(b.title)
          [:break, ".that_requires('#{type_name}[#{title}]')"]
        end.flatten
      end
    end
  end
  result
end

#dump_ResourceBody(o) ⇒ Object

Note:

this is the starting point where a test is created. A resource can include a class or define

each resource contains parameters which can have variables or functions as values.

Parameters:

  • o (Puppet::Pops::Model::ResourceBody)


281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 281

def dump_ResourceBody o
  type_name = dump_transform(o.eContainer.type_name).gsub('::', '__')
  title = dump_transform(o.title).inspect
  #TODO remove the :: from the front of the title if exists
  result = ['  ', :indent, :it, :do, :indent, "is_expected.to contain_#{type_name}(#{title})".tr('"','\'')]
  # this determies if we should use the with() or not
  if o.operations.count > 0
    result[-1] += '.with('
    result << [:break]
    # each operation should be a resource parameter and value
    o.operations.each do |p|
      next unless p
      # this is a bit of a hack but the correct fix is to patch puppet
      result << dump_transform(p) << :break
    end
    result.pop  # remove last line break which is easier than using conditional in loop
    result << [:dedent, :break, ')']
    unless [::Puppet::Pops::Model::CallNamedFunctionExpression, ::Puppet::Pops::Model::BlockExpression].include?(o.eContainer.eContainer.class)
      result << dump_Resource_Relationship(o)
    end
    result << [:end]
    result << [:dedent]
    result << [:break]
  else
    result << [:dedent,:dedent, :break,'end',:dedent, '  ', :break]
  end
  result
end

#dump_ResourceExpression(o) ⇒ Object

this is the beginning of the resource not the body itself

Parameters:

  • o (Puppet::Pops::Model::ResourceExpression)


381
382
383
384
385
386
387
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 381

def dump_ResourceExpression o
  result = []
  o.bodies.each do |b|
    result << :break << dump_transform(b)
  end
  result
end

#dump_ResourceTypeDefinition(o) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 161

def dump_ResourceTypeDefinition o
  result = ["describe #{o.name.inspect}", :do]
  result << ['let(:title)', :do, 'XXreplace_meXX'.inspect, :break, :end]
  result << [:dedent, :break]
  result << [:indent, :break,'let(:params)', :do, '{', :break]
  result << o.parameters.collect {|k| dump_transform(k)}
  result << ['}', :end]
  # result << ["inherits", o.parent_class] if o.parent_class
  # we need to process the body so that we can relize which facts are used
  body_result = []
  if o.body
    body_result << [:break, dump_transform(o.body)]
  else
    body_result << []
  end
  result << [:break,:break,'let(:facts)', :do, '{',:break]
  result << dump_top_scope_vars
  result << ['}', :end]
  result << body_result
  result << [:end]
  result
end

#dump_TextExpression(o) ⇒ Object

Interpolation (to string) shown as (str expr)



327
328
329
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 327

def dump_TextExpression o
  [dump_transform(o.expr)]
end

#dump_top_scope_varsObject



191
192
193
194
195
196
197
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 191

def dump_top_scope_vars
  result = []
  top_scope_vars.sort.each do |k, v|
    result << ['  ',k.gsub('$::', ''), ':' ,v[:value].inspect + ',', :break ]
  end
  result
end

#dump_transform(d) ⇒ Object

wraps Puppet::Pops::Model::TreeDumper.do_dump to return ruby 1.9 hash syntax instead of the older < 1.9 syntax

Parameters:

d

A puppet object to dump

Return:

An array of representing the puppet object in ruby syntax


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 39

def dump_transform(d)
  # This is a bit messy, ideally need to send a patch upstream to puppet
  # https://github.com/puppetlabs/puppet/blob/master/lib/puppet/pops/visitor.rb#L34
  # The value we get back from puppet do_dump command dumps ruby hashs using the old
  # ruby syntax e.g. { "key" => "value" }.  this function munges the output to use
  # the new format e.g. { key: 'value' }
  dump = do_dump(d)
  if dump.kind_of?(Array) and dump[1] == :"=>"
    key = dump[0].tr('"','')
    value = dump[-1].tr('"','\'')
    [ "#{key}:", value ]
  else
    dump
  end
end

#dump_VariableExpression(o) ⇒ Object

outputs the value of the variable

Parameters:

  • VariableExpression

Returns:

  • String the value of the variable or the name if value is not found



334
335
336
337
338
339
340
341
342
343
344
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 334

def dump_VariableExpression o
  key = dump(o.expr)
  if value = lookup_var(key)
    value  # return the looked up value
  elsif [::Puppet::Pops::Model::AttributeOperation,
     ::Puppet::Pops::Model::AssignmentExpression].include?(o.eContainer.class)
    "$#{key}"
  else
    add_var_to_store(key, "$#{key}", false, :class_scope)
  end
end

#format(x) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 115

def format(x)
  result = ""
  parts = format_r(x)
  parts.each_index do |i|
    if i > 0
      # separate with space unless previous ends with whitepsace or (
      result << ' ' if parts[i] != ")" && parts[i-1] !~ /.*(?:\s+|\()$/ && parts[i] !~ /^\s+/
    end
    result << parts[i].to_s
  end
  result
end

#format_r(x) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 128

def format_r(x)
  result = []
  case x
  when :break
    result << "\n" + indent
  when :indent_break
    result << indent + "\n"
  when :indent
    @indent_count += 1
  when :dedent
    if @indent_count == 0
      logger.warn('tried dedent when indent_count is already 0')
    else
      @indent_count -= 1
    end
  when :do
    result << format_r([' ', x.to_s, :indent, :break])
  when :indent_end
    result << format_r([:indent, :break, 'end', :dedent])
  when :end
    result << format_r([:dedent, :break, x.to_s])
  when Array
    #result << '('
    result += x.collect {|a| format_r(a) }.flatten
    #result << ')'
  when Symbol
    result << x.to_s # Allows Symbols in arrays e.g. ["text", =>, "text"]
  else
    result << x
  end
  result
end

#indentObject



111
112
113
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 111

def indent
  "  " * indent_count
end

#is_nop?(o) ⇒ Boolean

Returns:

  • (Boolean)


511
512
513
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 511

def is_nop? o
  o.nil? || o.is_a?(::Puppet::Pops::Model::Nop)
end

#loggerObject



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 16

def logger
  unless @logger
    require 'logger'
    @logger = Logger.new(STDOUT)
    if ENV['RETROSPEC_LOGGER_LEVEL'] == 'debug'
      @logger.level = Logger::DEBUG
    else
      @logger.level = Logger::INFO
    end
  end
  @logger
end

#lookup_var(key) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 55

def lookup_var(key)
  # if exists, return value
  # if it doesn't exist, store and return key
  key = normalize_key(key)
  other_key = key.split('::').last
  if key != other_key
    other_key = "$#{other_key}"
  end
  logger.debug("looking up #{key}".yellow)
  if item = var_store[key]
    value = item[:value]
    logger.debug("Store hit: #{key} with value: #{value}")
  elsif item = var_store[other_key] # key does not exist
    logger.debug("looking up #{other_key}".yellow)
    logger.debug("Store hit: #{other_key} with value: #{value}")
    value = item[:value]
  else
    logger.debug("Store miss: #{key}".fatal)
    value = false
  end
  value
end

#normalize_key(key) ⇒ Object

prepends a dollar sign if doesn’t already exist



79
80
81
82
83
84
85
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 79

def normalize_key(key)
  unless key.start_with?('$')
    # prepend the dollar sign
    key = "$#{key}"
  end
  key
end

#top_scope_varsObject



184
185
186
187
188
# File 'lib/retrospec/plugins/v1/plugin/generators/serializers/rspec_dumper.rb', line 184

def top_scope_vars
  var_store.find_all do |k,v|
    v[:type] == :top_scope
  end
end