puppet-debugger 0.15.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +21 -45
  3. data/.rubocop.yml +64 -233
  4. data/.rubocop_todo.yml +89 -147
  5. data/.ruby-version +1 -1
  6. data/.vscode/launch.json +15 -0
  7. data/CHANGELOG.md +34 -2
  8. data/Gemfile +7 -5
  9. data/README.md +29 -261
  10. data/Rakefile +11 -12
  11. data/bin/pdb +1 -1
  12. data/lib/awesome_print/ext/awesome_puppet.rb +22 -8
  13. data/lib/plugins/puppet-debugger/input_responders/benchmark.rb +5 -4
  14. data/lib/plugins/puppet-debugger/input_responders/classes.rb +14 -2
  15. data/lib/plugins/puppet-debugger/input_responders/classification.rb +4 -2
  16. data/lib/plugins/puppet-debugger/input_responders/commands.rb +18 -18
  17. data/lib/plugins/puppet-debugger/input_responders/datatypes.rb +22 -6
  18. data/lib/plugins/puppet-debugger/input_responders/environment.rb +4 -2
  19. data/lib/plugins/puppet-debugger/input_responders/exit.rb +4 -2
  20. data/lib/plugins/puppet-debugger/input_responders/facterdb_filter.rb +4 -2
  21. data/lib/plugins/puppet-debugger/input_responders/facts.rb +4 -2
  22. data/lib/plugins/puppet-debugger/input_responders/functions.rb +34 -32
  23. data/lib/plugins/puppet-debugger/input_responders/help.rb +4 -2
  24. data/lib/plugins/puppet-debugger/input_responders/krt.rb +4 -2
  25. data/lib/plugins/puppet-debugger/input_responders/play.rb +22 -24
  26. data/lib/plugins/puppet-debugger/input_responders/reset.rb +5 -3
  27. data/lib/plugins/puppet-debugger/input_responders/resources.rb +16 -7
  28. data/lib/plugins/puppet-debugger/input_responders/set.rb +34 -32
  29. data/lib/plugins/puppet-debugger/input_responders/stacktrace.rb +23 -0
  30. data/lib/plugins/puppet-debugger/input_responders/types.rb +6 -2
  31. data/lib/plugins/puppet-debugger/input_responders/vars.rb +8 -7
  32. data/lib/plugins/puppet-debugger/input_responders/whereami.rb +5 -3
  33. data/lib/puppet-debugger.rb +1 -45
  34. data/lib/puppet-debugger/cli.rb +120 -92
  35. data/lib/puppet-debugger/code/code_file.rb +13 -14
  36. data/lib/puppet-debugger/code/code_range.rb +5 -3
  37. data/lib/puppet-debugger/code/loc.rb +1 -1
  38. data/lib/puppet-debugger/debugger_code.rb +2 -0
  39. data/lib/puppet-debugger/hooks.rb +15 -16
  40. data/lib/puppet-debugger/input_responder_plugin.rb +54 -52
  41. data/lib/puppet-debugger/monkey_patches.rb +57 -0
  42. data/lib/puppet-debugger/plugin_test_helper.rb +9 -8
  43. data/lib/puppet-debugger/support.rb +27 -17
  44. data/lib/puppet-debugger/support/environment.rb +10 -3
  45. data/lib/puppet-debugger/support/errors.rb +25 -27
  46. data/lib/puppet-debugger/support/facts.rb +5 -5
  47. data/lib/puppet-debugger/support/node.rb +4 -7
  48. data/lib/puppet-debugger/support/scope.rb +29 -0
  49. data/lib/puppet-debugger/trollop.rb +38 -31
  50. data/lib/puppet-debugger/version.rb +1 -1
  51. data/lib/puppet/application/debugger.rb +151 -126
  52. data/output.json +1 -0
  53. data/puppet-debugger.gemspec +17 -15
  54. data/spec/awesome_print/ext/awesome_puppet_spec.rb +30 -30
  55. data/spec/fixtures/pe-xl-core-0.puppet.vm.json +1 -0
  56. data/spec/fixtures/sample_start_debugger.pp +3 -2
  57. data/spec/hooks_spec.rb +33 -35
  58. data/spec/input_responder_plugin_spec.rb +7 -6
  59. data/spec/input_responders/benchmark_spec.rb +3 -1
  60. data/spec/input_responders/classes_spec.rb +12 -13
  61. data/spec/input_responders/classification_spec.rb +4 -2
  62. data/spec/input_responders/commands_spec.rb +2 -0
  63. data/spec/input_responders/datatypes_spec.rb +8 -2
  64. data/spec/input_responders/environment_spec.rb +2 -0
  65. data/spec/input_responders/exit_spec.rb +9 -11
  66. data/spec/input_responders/facterdb_filter_spec.rb +2 -0
  67. data/spec/input_responders/facts_spec.rb +2 -0
  68. data/spec/input_responders/functions_spec.rb +30 -28
  69. data/spec/input_responders/help_spec.rb +5 -3
  70. data/spec/input_responders/krt_spec.rb +3 -1
  71. data/spec/input_responders/play_spec.rb +10 -20
  72. data/spec/input_responders/reset_spec.rb +2 -0
  73. data/spec/input_responders/resources_spec.rb +7 -1
  74. data/spec/input_responders/set_spec.rb +3 -1
  75. data/spec/input_responders/stacktrace_spec.rb +15 -0
  76. data/spec/input_responders/types_spec.rb +2 -0
  77. data/spec/input_responders/vars_spec.rb +4 -4
  78. data/spec/input_responders/whereami_spec.rb +2 -0
  79. data/spec/pdb_spec.rb +0 -9
  80. data/spec/puppet/application/debugger_spec.rb +35 -17
  81. data/spec/puppet_debugger_spec.rb +81 -83
  82. data/spec/remote_node_spec.rb +1 -5
  83. data/spec/spec_helper.rb +22 -18
  84. data/spec/support_spec.rb +3 -5
  85. data/test_matrix.rb +1 -1
  86. metadata +53 -19
@@ -1,31 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "puppet"
4
- require "readline"
5
- require "json"
6
- require "puppet-debugger/support"
7
- require "pluginator"
8
- require "puppet-debugger/hooks"
9
- require "forwardable"
10
- require "plugins/puppet-debugger/input_responders/functions"
11
- require "plugins/puppet-debugger/input_responders/datatypes"
12
-
3
+ require 'puppet'
4
+ require 'readline'
5
+ require 'json'
6
+ require 'puppet-debugger/support'
7
+ require 'pluginator'
8
+ require 'puppet-debugger/hooks'
9
+ require 'forwardable'
10
+ require 'plugins/puppet-debugger/input_responders/functions'
11
+ require 'plugins/puppet-debugger/input_responders/datatypes'
12
+ require 'tty-pager'
13
13
  module PuppetDebugger
14
14
  class Cli
15
15
  include PuppetDebugger::Support
16
16
  extend Forwardable
17
17
  attr_accessor :settings, :log_level, :in_buffer, :out_buffer, :html_mode, :extra_prompt, :bench
18
- attr_reader :source_file, :source_line_num, :hooks
18
+ attr_reader :source_file, :source_line_num, :hooks, :options
19
19
  def_delegators :hooks, :exec_hook, :add_hook, :delete_hook
20
-
20
+ OUT_SYMBOL = ' => '
21
21
  def initialize(options = {})
22
22
  do_initialize if Puppet[:codedir].nil?
23
23
  Puppet.settings[:name] = :debugger
24
- Puppet.settings[:trusted_server_facts] = true unless Puppet.settings[:trusted_server_facts].nil?
24
+ @options = options
25
25
  Puppet[:static_catalogs] = false unless Puppet.settings[:static_catalogs].nil?
26
26
  set_remote_node_name(options[:node_name])
27
27
  initialize_from_scope(options[:scope])
28
- @log_level = "notice"
28
+ set_catalog(options[:catalog])
29
+ @log_level = 'notice'
29
30
  @out_buffer = options[:out_buffer] || $stdout
30
31
  @html_mode = options[:html_mode] || false
31
32
  @source_file = options[:source_file] || nil
@@ -33,13 +34,13 @@ module PuppetDebugger
33
34
  @in_buffer = options[:in_buffer] || $stdin
34
35
  Readline.input = @in_buffer
35
36
  Readline.output = @out_buffer
36
- Readline.completion_append_character = ""
37
- Readline.basic_word_break_characters = " "
37
+ Readline.completion_append_character = ''
38
+ Readline.basic_word_break_characters = ' '
38
39
  Readline.completion_proc = command_completion
39
40
  AwesomePrint.defaults = {
40
41
  html: @html_mode,
41
42
  sort_keys: true,
42
- indent: 2,
43
+ indent: 2
43
44
  }
44
45
  end
45
46
 
@@ -50,11 +51,12 @@ module PuppetDebugger
50
51
  proc do |input|
51
52
  words = Readline.line_buffer.split(Readline.basic_word_break_characters)
52
53
  next key_words.grep(/^#{Regexp.escape(input)}/) if words.empty?
54
+
53
55
  first_word = words.shift
54
56
  plugins = PuppetDebugger::InputResponders::Commands.plugins.find_all do |p|
55
57
  p::COMMAND_WORDS.find { |word| word.start_with?(first_word) }
56
58
  end
57
- if plugins.count == 1 and /\A#{first_word}\s/.match(Readline.line_buffer)
59
+ if (plugins.count == 1) && /\A#{first_word}\s/.match(Readline.line_buffer)
58
60
  plugins.first.command_completion(words)
59
61
  else
60
62
  key_words.grep(/^#{Regexp.escape(input)}/)
@@ -76,7 +78,8 @@ module PuppetDebugger
76
78
  PuppetDebugger::InputResponders::Functions.instance.debugger = self
77
79
  funcs = PuppetDebugger::InputResponders::Functions.instance.func_list
78
80
  PuppetDebugger::InputResponders::Datatypes.instance.debugger = self
79
- (scoped_vars + funcs + static_responder_list + PuppetDebugger::InputResponders::Datatypes.instance.all_data_types).uniq.sort
81
+ (scoped_vars + funcs + static_responder_list +
82
+ PuppetDebugger::InputResponders::Datatypes.instance.all_data_types).uniq.sort
80
83
  end
81
84
 
82
85
  # looks up the type in the catalog by using the type and title
@@ -106,7 +109,7 @@ module PuppetDebugger
106
109
  end
107
110
 
108
111
  def contains_resources?(result)
109
- !Array(result).flatten.find { |r| r.class.to_s =~ /Puppet::Pops::Types/ }.nil?
112
+ !Array(result).flatten.find { |r| r.class.to_s =~ /Puppet::Pops::Types::PResourceType/ }.nil?
110
113
  end
111
114
 
112
115
  def normalize_output(result)
@@ -116,87 +119,107 @@ module PuppetDebugger
116
119
  # if the only output is a resource then return it
117
120
  # otherwise it is multiple items or an actually array
118
121
  return output.first if output.count == 1
122
+
119
123
  return output
120
124
  end
121
125
  result
122
126
  end
123
127
 
124
128
  def responder_list
125
- plugins = Pluginator.find(PuppetDebugger)
129
+ Pluginator.find(PuppetDebugger)
130
+ end
131
+
132
+ # @return [TTY::Pager] the pager object, disable if CI or testing is present
133
+ def pager
134
+ @pager ||= TTY::Pager.new(output: out_buffer, enabled: pager_enabled?)
135
+ end
136
+
137
+ def pager_enabled?
138
+ ENV['CI'].nil?
139
+ end
140
+
141
+ # @param output [String] - the content to output
142
+ # @summary outputs the output to the output buffer
143
+ # uses the pager if the screen height is less than the height of the
144
+ # output content
145
+ # Disabled if CI or testing is being done
146
+ def handle_output(output)
147
+ return if output.nil?
148
+ if pager_enabled? && output.lines.count >= TTY::Screen.height
149
+ output << "\n"
150
+ pager.page(output)
151
+ else
152
+ out_buffer.puts(output) unless output.empty?
153
+ end
126
154
  end
127
155
 
128
156
  # this method handles all input and expects a string of text.
129
- #
157
+ # @param input [String] - the input content to parse or run
130
158
  def handle_input(input)
131
159
  raise ArgumentError unless input.instance_of?(String)
132
- begin
133
- output = ""
134
- case input.strip
135
- when PuppetDebugger::InputResponders::Commands.command_list_regex
136
- args = input.split(" ")
137
- command = args.shift
138
- plugin = PuppetDebugger::InputResponders::Commands.plugin_from_command(command)
139
- output = plugin.execute(args, self)
140
- return out_buffer.puts output
141
- when "_"
142
- output = " => #{@last_item}"
143
- else
144
- result = puppet_eval(input)
145
- @last_item = result
146
- output = normalize_output(result)
147
- output = output.nil? ? "" : output.ai
160
+
161
+ output =
162
+ begin
163
+ case input.strip
164
+ when PuppetDebugger::InputResponders::Commands.command_list_regex
165
+ args = input.split(' ')
166
+ command = args.shift
167
+ plugin = PuppetDebugger::InputResponders::Commands.plugin_from_command(command)
168
+ plugin.execute(args, self) || ''
169
+ when '_'
170
+ " => #{@last_item}"
171
+ else
172
+ result = puppet_eval(input)
173
+ @last_item = result
174
+ o = normalize_output(result)
175
+ o.nil? ? '' : o.ai
176
+ end
177
+ rescue PuppetDebugger::Exception::InvalidCommand => e
178
+ e.message.fatal
179
+ rescue LoadError => e
180
+ e.message.fatal
181
+ rescue Errno::ETIMEDOUT => e
182
+ e.message.fatal
183
+ rescue ArgumentError => e
184
+ e.message.fatal
185
+ rescue Puppet::ResourceError => e
186
+ e.message.fatal
187
+ rescue Puppet::Error => e
188
+ e.message.fatal
189
+ rescue Puppet::ParseErrorWithIssue => e
190
+ e.message.fatal
191
+ rescue PuppetDebugger::Exception::FatalError => e
192
+ handle_output(e.message.fatal)
193
+ exit 1 # this can sometimes causes tests to fail
194
+ rescue PuppetDebugger::Exception::Error => e
195
+ e.message.fatal
196
+ rescue ::RuntimeError => e
197
+ handle_output(e.message.fatal)
198
+ exit 1
148
199
  end
149
- rescue PuppetDebugger::Exception::InvalidCommand => e
150
- output = e.message.fatal
151
- rescue LoadError => e
152
- output = e.message.fatal
153
- rescue Errno::ETIMEDOUT => e
154
- output = e.message.fatal
155
- rescue ArgumentError => e
156
- output = e.message.fatal
157
- rescue Puppet::ResourceError => e
158
- output = e.message.fatal
159
- rescue Puppet::Error => e
160
- output = e.message.fatal
161
- rescue Puppet::ParseErrorWithIssue => e
162
- output = e.message.fatal
163
- rescue PuppetDebugger::Exception::FatalError => e
164
- output = e.message.fatal
165
- out_buffer.puts output
166
- exit 1 # this can sometimes causes tests to fail
167
- rescue PuppetDebugger::Exception::Error => e
168
- output = e.message.fatal
169
- rescue ::RuntimeError => e
170
- output = e.message.fatal
171
- out_buffer.puts output
172
- exit 1
173
- end
174
- unless output.empty?
175
- out_buffer.print " => "
176
- out_buffer.puts output unless output.empty?
177
- exec_hook :after_output, out_buffer, self, self
178
- end
200
+ output = OUT_SYMBOL + output unless output.empty?
201
+ handle_output(output)
202
+ exec_hook :after_output, out_buffer, self, self
179
203
  end
180
204
 
181
205
  def self.print_repl_desc
182
- output = <<-EOT
183
- Ruby Version: #{RUBY_VERSION}
184
- Puppet Version: #{Puppet.version}
185
- Puppet Debugger Version: #{PuppetDebugger::VERSION}
186
- Created by: NWOps <corey@nwops.io>
187
- Type "commands" for a list of debugger commands
188
- or "help" to show the help screen.
206
+ <<~OUT
207
+ Ruby Version: #{RUBY_VERSION}
208
+ Puppet Version: #{Puppet.version}
209
+ Puppet Debugger Version: #{PuppetDebugger::VERSION}
210
+ Created by: NWOps <corey@nwops.io>
211
+ Type "commands" for a list of debugger commands
212
+ or "help" to show the help screen.
189
213
 
190
214
 
191
- EOT
192
- output
215
+ OUT
193
216
  end
194
217
 
195
218
  # tries to determine if the input is going to be a multiline input
196
219
  # by reading the parser error message
197
220
  # @return [Boolean] - return true if this is a multiline input, false otherwise
198
- def multiline_input?(e)
199
- case e.message
221
+ def multiline_input?(data)
222
+ case data.message
200
223
  when /Syntax error at end of/i
201
224
  true
202
225
  else
@@ -211,7 +234,7 @@ or "help" to show the help screen.
211
234
  # input
212
235
  def read_loop
213
236
  line_number = 1
214
- full_buffer = ""
237
+ full_buffer = ''
215
238
  while buf = Readline.readline("#{line_number}:#{extra_prompt}>> ", true)
216
239
  begin
217
240
  full_buffer += buf
@@ -222,14 +245,14 @@ or "help" to show the help screen.
222
245
  parser.parse_string(full_buffer)
223
246
  rescue Puppet::ParseErrorWithIssue => e
224
247
  if multiline_input?(e)
225
- out_buffer.print " "
248
+ out_buffer.print ' '
226
249
  full_buffer += "\n"
227
250
  next
228
251
  end
229
252
  end
230
253
  end
231
254
  handle_input(full_buffer)
232
- full_buffer = ""
255
+ full_buffer = ''
233
256
  end
234
257
  end
235
258
  end
@@ -251,7 +274,7 @@ or "help" to show the help screen.
251
274
  repl_obj.out_buffer.puts print_repl_desc unless options[:quiet]
252
275
  repl_obj.handle_input(options[:content]) if options[:content]
253
276
  # TODO: make the output optional so we can have different output destinations
254
- repl_obj.handle_input("whereami") if options[:source_file] && options[:source_line]
277
+ repl_obj.handle_input('whereami') if options[:source_file] && options[:source_line]
255
278
  repl_obj.handle_input("play #{options[:play]}") if options[:play]
256
279
  repl_obj.read_loop unless options[:run_once]
257
280
  end
@@ -262,10 +285,15 @@ or "help" to show the help screen.
262
285
  # @param [Hash] puppet scope object
263
286
  def self.start(options = { scope: nil })
264
287
  opts = Trollop.options do
265
- opt :play, "Url or file to load from", required: false, type: String
266
- opt :run_once, "Evaluate and quit", required: false, default: false
267
- opt :node_name, "Remote Node to grab facts from", required: false, type: String
268
- opt :quiet, "Do not display banner", required: false, default: false
288
+ opt :play, 'Url or file to load from', required: false, type: String
289
+ opt :run_once, 'Evaluate and quit', required: false, default: false
290
+ opt :node_name, 'Remote Node to grab facts from', required: false, type: String
291
+ opt :catalog, 'Import a catalog file to inspect', required: false, type: String
292
+ opt :quiet, 'Do not display banner', required: false, default: false
293
+ end
294
+ if !STDIN.tty? && !STDIN.closed?
295
+ options[:run_once] = true
296
+ options[:quiet] = true
269
297
  end
270
298
  options = opts.merge(options)
271
299
  options[:play] = options[:play].path if options[:play].respond_to?(:path)
@@ -273,14 +301,14 @@ or "help" to show the help screen.
273
301
  repl_obj.out_buffer.puts print_repl_desc unless options[:quiet]
274
302
  if options[:play]
275
303
  repl_obj.handle_input("play #{options[:play]}")
276
- elsif ARGF.filename != "-"
277
- # when the user supplied a file name without using the args (stdin)
278
- path = File.expand_path(ARGF.filename)
279
- repl_obj.handle_input("play #{path}")
280
- elsif (ARGF.filename == "-") && (!STDIN.tty? && !STDIN.closed?)
304
+ elsif (ARGF.filename == '-') && (!STDIN.tty? && !STDIN.closed?)
281
305
  # when the user supplied a file content using stdin, aka. cat,pipe,echo or redirection
282
306
  input = ARGF.read
283
307
  repl_obj.handle_input(input)
308
+ elsif ARGF.filename != '-'
309
+ # when the user supplied a file name without using the args (stdin)
310
+ path = File.expand_path(ARGF.filename)
311
+ repl_obj.handle_input("play #{path}")
284
312
  end
285
313
  # helper code to make tests exit the loop
286
314
  repl_obj.read_loop unless options[:run_once]
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  class CodeFile
@@ -10,18 +9,18 @@ class CodeFile
10
9
  # List of all supported languages.
11
10
  # @return [Hash]
12
11
  EXTENSIONS = {
13
- %w[.py] => :python,
14
- %w[.js] => :javascript,
15
- %w[.pp] => :puppet,
16
- %w[.css] => :css,
17
- %w[.xml] => :xml,
18
- %w[.php] => :php,
19
- %w[.html] => :html,
20
- %w[.diff] => :diff,
21
- %w[.java] => :java,
22
- %w[.json] => :json,
23
- %w[.c .h] => :c,
24
- %w[.rhtml] => :rhtml,
12
+ %w[.py] => :python,
13
+ %w[.js] => :javascript,
14
+ %w[.pp] => :puppet,
15
+ %w[.css] => :css,
16
+ %w[.xml] => :xml,
17
+ %w[.php] => :php,
18
+ %w[.html] => :html,
19
+ %w[.diff] => :diff,
20
+ %w[.java] => :java,
21
+ %w[.json] => :json,
22
+ %w[.c .h] => :c,
23
+ %w[.rhtml] => :rhtml,
25
24
  %w[.yaml .yml] => :yaml,
26
25
  %w[.cpp .hpp .cc .h cxx] => :cpp,
27
26
  %w[.rb .ru .irbrc .gemspec .pryrc] => :ruby
@@ -96,4 +95,4 @@ class CodeFile
96
95
  def from_load_path
97
96
  $LOAD_PATH.map { |path| File.expand_path(@filename, path) }
98
97
  end
99
- end
98
+ end
@@ -47,13 +47,15 @@ class DebuggerCode
47
47
 
48
48
  # @return [Integer]
49
49
  def find_start_index(lines)
50
- return start_line if start_line < 0
50
+ return start_line if start_line.negative?
51
+
51
52
  lines.index { |loc| loc.lineno >= start_line } || lines.length
52
53
  end
53
54
 
54
55
  # @return [Integer]
55
56
  def find_end_index(lines)
56
- return end_line if end_line < 0
57
+ return end_line if end_line.negative?
58
+
57
59
  (lines.index { |loc| loc.lineno > end_line } || 0) - 1
58
60
  end
59
61
 
@@ -66,4 +68,4 @@ class DebuggerCode
66
68
  @start_line = start_line.first
67
69
  end
68
70
  end
69
- end
71
+ end
@@ -76,4 +76,4 @@ class DebuggerCode
76
76
  tuple[0] = "#{' ' * distance}#{line}"
77
77
  end
78
78
  end
79
- end
79
+ end
@@ -164,6 +164,7 @@ class DebuggerCode
164
164
  # @return [Code]
165
165
  def grep(pattern)
166
166
  return self unless pattern
167
+
167
168
  pattern = Regexp.new(pattern)
168
169
 
169
170
  select do |loc|
@@ -238,6 +239,7 @@ class DebuggerCode
238
239
 
239
240
  def add_file_reference
240
241
  return "From inline code: \n" unless filename
242
+
241
243
  "From file: #{File.basename(filename)}\n"
242
244
  end
243
245
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'puppet-debugger/support/errors'
2
4
 
3
5
  module PuppetDebugger
@@ -18,7 +20,7 @@ module PuppetDebugger
18
20
  end
19
21
 
20
22
  # Ensure that duplicates have their @hooks object.
21
- def initialize_copy(orig)
23
+ def initialize_copy(_orig)
22
24
  hooks_dup = @hooks.dup
23
25
  @hooks.each do |k, v|
24
26
  hooks_dup[k] = v.dup
@@ -37,8 +39,9 @@ module PuppetDebugger
37
39
  # @return [PuppetDebugger::Hooks] The receiver.
38
40
  # @see {#merge}
39
41
  def merge!(other)
40
- @hooks.merge!(other.dup.hooks) do |key, array, other_array|
41
- temp_hash, output = {}, []
42
+ @hooks.merge!(other.dup.hooks) do |_key, array, other_array|
43
+ temp_hash = {}
44
+ output = []
42
45
 
43
46
  (array + other_array).reverse_each do |pair|
44
47
  temp_hash[pair.first] ||= output.unshift(pair)
@@ -57,7 +60,7 @@ module PuppetDebugger
57
60
  # @return [PuppetDebugger::Hooks] a new `PuppetDebugger::Hooks` instance containing a merge of the
58
61
  # contents of two `PuppetDebugger::Hooks` instances.
59
62
  def merge(other)
60
- self.dup.tap do |v|
63
+ dup.tap do |v|
61
64
  v.merge!(other)
62
65
  end
63
66
  end
@@ -68,7 +71,7 @@ module PuppetDebugger
68
71
  # @param [#call] callable The callable.
69
72
  # @yield The block to use as the callable (if no `callable` provided).
70
73
  # @return [PuppetDebugger::Hooks] The receiver.
71
- def add_hook(event_name, hook_name, callable=nil, &block)
74
+ def add_hook(event_name, hook_name, callable = nil, &block)
72
75
  event_name = event_name.to_s
73
76
 
74
77
  # do not allow duplicates, but allow multiple `nil` hooks
@@ -77,12 +80,10 @@ module PuppetDebugger
77
80
  raise ArgumentError, "Hook with name '#{hook_name}' already defined!"
78
81
  end
79
82
 
80
- if !block && !callable
81
- raise ArgumentError, "Must provide a block or callable."
82
- end
83
+ raise ArgumentError, 'Must provide a block or callable.' if !block && !callable
83
84
 
84
85
  # ensure we only have one anonymous hook
85
- @hooks[event_name].delete_if { |h, k| h.nil? } if hook_name.nil?
86
+ @hooks[event_name].delete_if { |h, _k| h.nil? } if hook_name.nil?
86
87
 
87
88
  if block
88
89
  @hooks[event_name] << [hook_name, block]
@@ -98,7 +99,7 @@ module PuppetDebugger
98
99
  # @param [Array] args The arguments to pass to each hook function.
99
100
  # @return [Object] The return value of the last executed hook.
100
101
  def exec_hook(event_name, *args, &block)
101
- @hooks[event_name.to_s].map do |hook_name, callable|
102
+ @hooks[event_name.to_s].map do |_hook_name, callable|
102
103
  begin
103
104
  callable.call(*args, &block)
104
105
  rescue PuppetDebugger::Exception::Error, ::RuntimeError => e
@@ -118,10 +119,10 @@ module PuppetDebugger
118
119
  # @param [Symbol] hook_name The name of the hook
119
120
  # @return [#call] a specific hook for a given event.
120
121
  def get_hook(event_name, hook_name)
121
- hook = @hooks[event_name.to_s].find do |current_hook_name, callable|
122
+ hook = @hooks[event_name.to_s].find do |current_hook_name, _callable|
122
123
  current_hook_name == hook_name
123
124
  end
124
- hook.last if hook
125
+ hook&.last
125
126
  end
126
127
 
127
128
  # @param [Symbol] event_name The name of the event.
@@ -167,8 +168,6 @@ module PuppetDebugger
167
168
 
168
169
  protected
169
170
 
170
- def hooks
171
- @hooks
172
- end
171
+ attr_reader :hooks
173
172
  end
174
- end
173
+ end