puppet-repl 0.3.1 → 0.3.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d8ce23921a5f416b32187a87b404f5175f4bd37
4
- data.tar.gz: a510663097037ec81141e66552f253817cb6d9c3
3
+ metadata.gz: ca90b4e2bd2667abaceead15b141c87b712aea32
4
+ data.tar.gz: 20aedb19e5dd5e93b62faf0438f47d7619a20e5a
5
5
  SHA512:
6
- metadata.gz: 125c9d2e1024849306165a4371d5468f39179c6adb660cbefe0801343111ae85bb25a1070b8f669893a8efc4d26cd34432192ac1d971bf7ae68c6c803d577b90
7
- data.tar.gz: 48d7203e5f8db5a73cc76e4ce3b3be1af12b935955d24a349ef19379e961f36791366fb1fd7a650b818f705ed5092be2264d6095c554fa9206ba99cd9e2af4ac
6
+ metadata.gz: 9dc96e79ff9bd8a348b0cf64d81cb857a38656e4d19a91e6d8a7d325eff7e5c6fa11f0ac3e01fcc178348986d5701f0677b0a1f84d3d502b66ddf2b07cc9da24
7
+ data.tar.gz: 3a5f8b6056dcf2d63101c25ea30765bf74a63a158211f72d8f3be45289683cdb5a8d653a768cad6b991ada7a5c353acaabdb8a19463295baef1155fc35455646
data/.gitlab-ci.yml CHANGED
@@ -16,6 +16,8 @@ web_trigger_staging:
16
16
  type: web_deploy
17
17
  variables:
18
18
  REF: staging
19
+ only:
20
+ - master
19
21
  script:
20
22
  - "curl -X POST -F token=$PREPL_BUILD_TRIGGER_TOKEN -F ref=$REF https://gitlab.com/api/v3/projects/1146764/trigger/builds"
21
23
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,5 @@
1
+ ## 0.3.2
2
+ * Fixes #31 - adds ability to show surrounding code
1
3
  ## 0.3.1
2
4
  * Fixes #28 - puppet 4.6 support
3
5
  * Fixes #27 - repl should throw puppet error message instead of stacktrace
data/Gemfile.lock CHANGED
@@ -21,7 +21,8 @@ GEM
21
21
  coderay (~> 1.1.0)
22
22
  method_source (~> 0.8.1)
23
23
  slop (~> 3.4)
24
- puppet (4.6.0)
24
+ puppet (4.7.0)
25
+ CFPropertyList (~> 2.2.6)
25
26
  facter (> 2.0, < 4)
26
27
  hiera (>= 2.0, < 4)
27
28
  json_pure (~> 1.8)
@@ -64,4 +65,4 @@ DEPENDENCIES
64
65
  simplecov
65
66
 
66
67
  BUNDLED WITH
67
- 1.12.5
68
+ 1.13.1
data/lib/puppet-repl.rb CHANGED
@@ -4,6 +4,8 @@ require 'awesome_print'
4
4
  require_relative 'awesome_print/ext/awesome_puppet'
5
5
  require_relative 'trollop'
6
6
  require 'puppet/util/log'
7
+ require_relative 'puppet-repl/repl_code'
8
+
7
9
  require_relative 'puppet-repl/support/errors'
8
10
  # monkey patch in some color effects string methods
9
11
  class String
@@ -39,7 +41,6 @@ Puppet::Util::Log.newdesttype :buffer do
39
41
  :crit => { :name => 'Critical', :color => :hred, :stream => err_buffer },
40
42
  :err => { :name => 'Error', :color => :hred, :stream => err_buffer },
41
43
  :warning => { :name => 'Warning', :color => :hred, :stream => err_buffer },
42
-
43
44
  :notice => { :name => 'Notice', :color => :reset, :stream => out_buffer },
44
45
  :info => { :name => 'Info', :color => :green, :stream => out_buffer },
45
46
  :debug => { :name => 'Debug', :color => :cyan, :stream => out_buffer },
@@ -13,13 +13,14 @@ module PuppetRepl
13
13
  @log_level = 'notice'
14
14
  @out_buffer = options[:out_buffer] || $stdout
15
15
  @html_mode = options[:html_mode] || false
16
+ @source_file = options[:source_file] || nil
17
+ @source_line_num = options[:source_line] || nil
16
18
  @in_buffer = options[:in_buffer] || $stdin
17
19
  comp = Proc.new do |s|
18
20
  key_words.grep(/^#{Regexp.escape(s)}/)
19
21
  end
20
22
  Readline.completion_append_character = ""
21
23
  Readline.basic_word_break_characters = " "
22
-
23
24
  Readline.completion_proc = comp
24
25
  AwesomePrint.defaults = {
25
26
  :html => @html_mode,
@@ -91,11 +92,10 @@ module PuppetRepl
91
92
  #
92
93
  def handle_input(input)
93
94
  raise ArgumentError unless input.instance_of?(String)
94
-
95
95
  begin
96
96
  output = ''
97
97
  case input
98
- when /^play|^classification|^facterdb_filter|^facts|^vars|^functions|^classes|^resources|^krt|^environment|^reset|^help/
98
+ when /^play|^classification|^whereami|^facterdb_filter|^facts|^vars|^functions|^classes|^resources|^krt|^environment|^reset|^help/
99
99
  args = input.split(' ')
100
100
  command = args.shift.to_sym
101
101
  if self.respond_to?(command)
@@ -149,7 +149,7 @@ Ruby Version: #{RUBY_VERSION}
149
149
  Puppet Version: #{Puppet.version}
150
150
  Puppet Repl Version: #{PuppetRepl::VERSION}
151
151
  Created by: NWOps <corey@nwops.io>
152
- Type "exit", "functions", "vars", "krt", "facts", "resources", "classes",
152
+ Type "exit", "functions", "vars", "krt", "whereami", "facts", "resources", "classes",
153
153
  "play", "classification", "reset", or "help" for more information.
154
154
 
155
155
  EOT
@@ -194,10 +194,28 @@ Type "exit", "functions", "vars", "krt", "facts", "resources", "classes",
194
194
  end
195
195
  end
196
196
 
197
+ # used to start a repl without attempting to read from stdin
198
+ # or
199
+ # @param [Hash] must contain at least the puppet scope object
200
+ def self.start_without_stdin(options={:scope => nil})
201
+ puts print_repl_desc unless options[:quiet]
202
+ repl_obj = PuppetRepl::Cli.new(options)
203
+ repl_obj.remote_node_name = options[:node_name] if options[:node_name]
204
+ repl_obj.initialize_from_scope(options[:scope])
205
+ puts repl_obj.whereami if options[:source_file] and options[:source_line]
206
+ # helper code to make tests exit the loop
207
+ repl_obj.read_loop unless options[:run_once]
208
+ if options[:play]
209
+ repl_obj.play_back(options)
210
+ else
211
+ repl_obj.read_loop
212
+ end
213
+ end
214
+
197
215
  # start reads from stdin or from a file
198
216
  # if from stdin, the repl will process the input and exit
199
217
  # if from a file, the repl will process the file and continue to prompt
200
- # @param [Scope] puppet scope object
218
+ # @param [Hash] puppet scope object
201
219
  def self.start(options={:scope => nil})
202
220
  opts = Trollop::options do
203
221
  opt :play, "Url or file to load from", :required => false, :type => String
@@ -207,7 +225,7 @@ Type "exit", "functions", "vars", "krt", "facts", "resources", "classes",
207
225
  end
208
226
  options = opts.merge(options)
209
227
  puts print_repl_desc unless options[:quiet]
210
- repl_obj = PuppetRepl::Cli.new
228
+ repl_obj = PuppetRepl::Cli.new(options)
211
229
  repl_obj.remote_node_name = opts[:node_name] if opts[:node_name]
212
230
  repl_obj.initialize_from_scope(options[:scope])
213
231
  if options[:play]
@@ -0,0 +1,98 @@
1
+
2
+ class CodeFile
3
+ class SourceNotFound < Exception
4
+ end
5
+
6
+ DEFAULT_EXT = '.pp'
7
+
8
+ # List of all supported languages.
9
+ # @return [Hash]
10
+ EXTENSIONS = {
11
+ %w(.py) => :python,
12
+ %w(.js) => :javascript,
13
+ %w(.pp) => :puppet,
14
+ %w(.css) => :css,
15
+ %w(.xml) => :xml,
16
+ %w(.php) => :php,
17
+ %w(.html) => :html,
18
+ %w(.diff) => :diff,
19
+ %w(.java) => :java,
20
+ %w(.json) => :json,
21
+ %w(.c .h) => :c,
22
+ %w(.rhtml) => :rhtml,
23
+ %w(.yaml .yml) => :yaml,
24
+ %w(.cpp .hpp .cc .h cxx) => :cpp,
25
+ %w(.rb .ru .irbrc .gemspec .pryrc) => :ruby,
26
+ }
27
+
28
+ # @return [Symbol] The type of code stored in this wrapper.
29
+ attr_reader :code_type
30
+
31
+ # @param [String] filename The name of a file with code to be detected
32
+ # @param [Symbol] code_type The type of code the `filename` contains
33
+ def initialize(filename, code_type = type_from_filename(filename))
34
+ @filename = filename
35
+ @code_type = code_type
36
+ end
37
+
38
+ # @return [String] The code contained in the current `@filename`.
39
+ def code
40
+ path = abs_path
41
+ @code_type = type_from_filename(path)
42
+ File.read(path)
43
+ end
44
+
45
+ private
46
+
47
+ # @raise [MethodSource::SourceNotFoundError] if the `filename` is not
48
+ # readable for some reason.
49
+ # @return [String] absolute path for the given `filename`.
50
+ def abs_path
51
+ code_path.detect { |path| readable?(path) } or
52
+ raise SourceNotFound,
53
+ "Cannot open #{ @filename.inspect } for reading."
54
+ end
55
+
56
+ # @param [String] path
57
+ # @return [Boolean] if the path, with or without the default ext,
58
+ # is a readable file then `true`, otherwise `false`.
59
+ def readable?(path)
60
+ File.readable?(path) && !File.directory?(path) or
61
+ File.readable?(path << DEFAULT_EXT)
62
+ end
63
+
64
+ # @return [Array] All the paths that contain code that Pry can use for its
65
+ # API's. Skips directories.
66
+ def code_path
67
+ [from_pwd, from_pry_init_pwd, *from_load_path]
68
+ end
69
+
70
+ # @param [String] filename
71
+ # @param [Symbol] default (:unknown) the file type to assume if none could be
72
+ # detected.
73
+ # @return [Symbol, nil] The CodeRay type of a file from its extension, or
74
+ # `nil` if `:unknown`.
75
+ def type_from_filename(filename, default = :unknown)
76
+ _, @code_type = EXTENSIONS.find do |k, _|
77
+ k.any? { |ext| ext == File.extname(filename) }
78
+ end
79
+
80
+ code_type || default
81
+ end
82
+
83
+ # @return [String]
84
+ def from_pwd
85
+ File.expand_path(@filename, Dir.pwd)
86
+ end
87
+
88
+ # @return [String]
89
+ def from_pry_init_pwd
90
+ File.expand_path(@filename, Dir.pwd)
91
+ end
92
+
93
+ # @return [String]
94
+ def from_load_path
95
+ $LOAD_PATH.map { |path| File.expand_path(@filename, path) }
96
+ end
97
+
98
+ end
@@ -0,0 +1,69 @@
1
+ class ReplCode
2
+
3
+ # Represents a range of lines in a code listing.
4
+ #
5
+ # @api private
6
+ class CodeRange
7
+
8
+ # @param [Integer] start_line
9
+ # @param [Integer?] end_line
10
+ def initialize(start_line, end_line = nil)
11
+ @start_line = start_line
12
+ @end_line = end_line
13
+ force_set_end_line
14
+ end
15
+
16
+ # @param [Array<LOC>] lines
17
+ # @return [Range]
18
+ def indices_range(lines)
19
+ Range.new(*indices(lines))
20
+ end
21
+
22
+ private
23
+
24
+ def start_line; @start_line; end
25
+ def end_line; @end_line; end
26
+
27
+ # If `end_line` is equal to `nil`, then calculate it from the first
28
+ # parameter, `start_line`. Otherwise, leave it as it is.
29
+ # @return [void]
30
+ def force_set_end_line
31
+ if start_line.is_a?(Range)
32
+ set_end_line_from_range
33
+ else
34
+ @end_line ||= start_line
35
+ end
36
+ end
37
+
38
+ # Finds indices of `start_line` and `end_line` in the given Array of
39
+ # +lines+.
40
+ #
41
+ # @param [Array<LOC>] lines
42
+ # @return [Array<Integer>]
43
+ def indices(lines)
44
+ [find_start_index(lines), find_end_index(lines)]
45
+ end
46
+
47
+ # @return [Integer]
48
+ def find_start_index(lines)
49
+ return start_line if start_line < 0
50
+ lines.index { |loc| loc.lineno >= start_line } || lines.length
51
+ end
52
+
53
+ # @return [Integer]
54
+ def find_end_index(lines)
55
+ return end_line if end_line < 0
56
+ (lines.index { |loc| loc.lineno > end_line } || 0) - 1
57
+ end
58
+
59
+ # For example, if the range is 4..10, then `start_line` would be equal to
60
+ # 4 and `end_line` to 10.
61
+ # @return [void]
62
+ def set_end_line_from_range
63
+ @end_line = start_line.last
64
+ @end_line -= 1 if start_line.exclude_end?
65
+ @start_line = start_line.first
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,80 @@
1
+ class ReplCode
2
+
3
+ # Represents a line of code. A line of code is a tuple, which consists of a
4
+ # line and a line number. A `LOC` object's state (namely, the line
5
+ # parameter) can be changed via instance methods. `Pry::Code` heavily uses
6
+ # this class.
7
+ #
8
+ # @api private
9
+ # @example
10
+ # loc = LOC.new("def example\n :example\nend", 1)
11
+ # puts loc.line
12
+ # def example
13
+ # :example
14
+ # end
15
+ # #=> nil
16
+ #
17
+ # loc.indent(3)
18
+ # loc.line #=> " def example\n :example\nend"
19
+ class LOC
20
+
21
+ # @return [Array<String, Integer>]
22
+ attr_reader :tuple
23
+
24
+ # @param [String] line The line of code.
25
+ # @param [Integer] lineno The position of the +line+.
26
+ def initialize(line, lineno)
27
+ @tuple = [line.chomp, lineno.to_i]
28
+ end
29
+
30
+ # @return [Boolean]
31
+ def ==(other)
32
+ other.tuple == tuple
33
+ end
34
+
35
+ def dup
36
+ self.class.new(line, lineno)
37
+ end
38
+
39
+ # @return [String]
40
+ def line
41
+ tuple.first
42
+ end
43
+
44
+ # @return [Integer]
45
+ def lineno
46
+ tuple.last
47
+ end
48
+
49
+ #Prepends the line number `lineno` to the `line`.
50
+ # @param [Integer] max_width
51
+ # @return [void]
52
+ def add_line_number(max_width = 0)
53
+ padded = lineno.to_s.rjust(max_width)
54
+ tuple[0] = "#{ padded }: #{ line }"
55
+ end
56
+
57
+ # Prepends a marker "=>" or an empty marker to the +line+.
58
+ #
59
+ # @param [Integer] marker_lineno If it is equal to the `lineno`, then
60
+ # prepend a hashrocket. Otherwise, an empty marker.
61
+ # @return [void]
62
+ def add_marker(marker_lineno)
63
+ tuple[0] =
64
+ if lineno == marker_lineno
65
+ " => #{ line }".cyan
66
+ else
67
+ " #{ line }"
68
+ end
69
+ end
70
+
71
+ # Indents the `line` with +distance+ spaces.
72
+ #
73
+ # @param [Integer] distance
74
+ # @return [void]
75
+ def indent(distance)
76
+ tuple[0] = "#{ ' ' * distance }#{ line }"
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,312 @@
1
+ require_relative 'code/loc'
2
+ require_relative 'code/code_range'
3
+ require_relative 'code/code_file'
4
+
5
+ # `Pry::Code` is a class that encapsulates lines of source code and their
6
+ # line numbers and formats them for terminal output. It can read from a file
7
+ # or method definition or be instantiated with a `String` or an `Array`.
8
+ #
9
+ # In general, the formatting methods in `Code` return a new `Code` object
10
+ # which will format the text as specified when `#to_s` is called. This allows
11
+ # arbitrary chaining of formatting methods without mutating the original
12
+ # object.
13
+ class ReplCode
14
+ class << self
15
+ # include MethodSource::CodeHelpers
16
+
17
+ # Instantiate a `Code` object containing code loaded from a file or
18
+ # Pry's line buffer.
19
+ #
20
+ # @param [String] filename The name of a file, or "(pry)".
21
+ # @param [Symbol] code_type The type of code the file contains.
22
+ # @return [Code]
23
+ def from_file(filename, code_type = nil)
24
+ if filename == :code
25
+ new(Puppet[:code], 1, code_type)
26
+ else
27
+ code_file = CodeFile.new(filename, code_type)
28
+ new(code_file.code, 1, code_file.code_type)
29
+ end
30
+ end
31
+ end
32
+
33
+ # @return [Symbol] The type of code stored in this wrapper.
34
+ attr_accessor :code_type
35
+
36
+ # Instantiate a `Code` object containing code from the given `Array`,
37
+ # `String`, or `IO`. The first line will be line 1 unless specified
38
+ # otherwise. If you need non-contiguous line numbers, you can create an
39
+ # empty `Code` object and then use `#push` to insert the lines.
40
+ #
41
+ # @param [Array<String>, String, IO] lines
42
+ # @param [Integer?] start_line
43
+ # @param [Symbol?] code_type
44
+ def initialize(lines = [], start_line = 1, code_type = :ruby)
45
+ if lines.is_a? String
46
+ lines = lines.lines
47
+ end
48
+ @lines = lines.each_with_index.map { |line, lineno|
49
+ LOC.new(line, lineno + start_line.to_i) }
50
+ @code_type = code_type
51
+
52
+ @with_marker = @with_indentation = nil
53
+ end
54
+
55
+ # Append the given line. +lineno+ is one more than the last existing
56
+ # line, unless specified otherwise.
57
+ #
58
+ # @param [String] line
59
+ # @param [Integer?] lineno
60
+ # @return [String] The inserted line.
61
+ def push(line, lineno = nil)
62
+ if lineno.nil?
63
+ lineno = @lines.last.lineno + 1
64
+ end
65
+ @lines.push(LOC.new(line, lineno))
66
+ line
67
+ end
68
+ alias << push
69
+
70
+ # Filter the lines using the given block.
71
+ #
72
+ # @yield [LOC]
73
+ # @return [Code]
74
+ def select(&block)
75
+ alter do
76
+ @lines = @lines.select(&block)
77
+ end
78
+ end
79
+
80
+ # Remove all lines that aren't in the given range, expressed either as a
81
+ # `Range` object or a first and last line number (inclusive). Negative
82
+ # indices count from the end of the array of lines.
83
+ #
84
+ # @param [Range, Integer] start_line
85
+ # @param [Integer?] end_line
86
+ # @return [Code]
87
+ def between(start_line, end_line = nil)
88
+ return self unless start_line
89
+
90
+ code_range = CodeRange.new(start_line, end_line)
91
+
92
+ alter do
93
+ @lines = @lines[code_range.indices_range(@lines)] || []
94
+ end
95
+ end
96
+
97
+ # Take `num_lines` from `start_line`, forward or backwards.
98
+ #
99
+ # @param [Integer] start_line
100
+ # @param [Integer] num_lines
101
+ # @return [Code]
102
+ def take_lines(start_line, num_lines)
103
+ start_idx =
104
+ if start_line >= 0
105
+ @lines.index { |loc| loc.lineno >= start_line } || @lines.length
106
+ else
107
+ [@lines.length + start_line, 0].max
108
+ end
109
+
110
+ alter do
111
+ @lines = @lines.slice(start_idx, num_lines)
112
+ end
113
+ end
114
+
115
+ # Remove all lines except for the +lines+ up to and excluding +lineno+.
116
+ #
117
+ # @param [Integer] lineno
118
+ # @param [Integer] lines
119
+ # @return [Code]
120
+ def before(lineno, lines = 1)
121
+ return self unless lineno
122
+
123
+ select do |loc|
124
+ loc.lineno >= lineno - lines && loc.lineno < lineno
125
+ end
126
+ end
127
+
128
+ # Remove all lines except for the +lines+ on either side of and including
129
+ # +lineno+.
130
+ #
131
+ # @param [Integer] lineno
132
+ # @param [Integer] lines
133
+ # @return [Code]
134
+ def around(lineno, lines = 1)
135
+ return self unless lineno
136
+
137
+ select do |loc|
138
+ loc.lineno >= lineno - lines && loc.lineno <= lineno + lines
139
+ end
140
+ end
141
+
142
+ # Remove all lines except for the +lines+ after and excluding +lineno+.
143
+ #
144
+ # @param [Integer] lineno
145
+ # @param [Integer] lines
146
+ # @return [Code]
147
+ def after(lineno, lines = 1)
148
+ return self unless lineno
149
+
150
+ select do |loc|
151
+ loc.lineno > lineno && loc.lineno <= lineno + lines
152
+ end
153
+ end
154
+
155
+ # Remove all lines that don't match the given `pattern`.
156
+ #
157
+ # @param [Regexp] pattern
158
+ # @return [Code]
159
+ def grep(pattern)
160
+ return self unless pattern
161
+ pattern = Regexp.new(pattern)
162
+
163
+ select do |loc|
164
+ loc.line =~ pattern
165
+ end
166
+ end
167
+
168
+ # Format output with line numbers next to it, unless `y_n` is falsy.
169
+ #
170
+ # @param [Boolean?] y_n
171
+ # @return [Code]
172
+ def with_line_numbers(y_n = true)
173
+ alter do
174
+ @with_line_numbers = y_n
175
+ end
176
+ end
177
+
178
+ # Format output with a marker next to the given +lineno+, unless +lineno+ is
179
+ # falsy.
180
+ #
181
+ # @param [Integer?] lineno
182
+ # @return [Code]
183
+ def with_marker(lineno = 1)
184
+ alter do
185
+ @with_marker = !!lineno
186
+ @marker_lineno = lineno
187
+ end
188
+ end
189
+
190
+ # Format output with the specified number of spaces in front of every line,
191
+ # unless `spaces` is falsy.
192
+ #
193
+ # @param [Integer?] spaces
194
+ # @return [Code]
195
+ def with_indentation(spaces = 0)
196
+ alter do
197
+ @with_indentation = !!spaces
198
+ @indentation_num = spaces
199
+ end
200
+ end
201
+
202
+ # @return [String]
203
+ def inspect
204
+ Object.instance_method(:to_s).bind(self).call
205
+ end
206
+
207
+ # @return [Integer] the number of digits in the last line.
208
+ def max_lineno_width
209
+ @lines.length > 0 ? @lines.last.lineno.to_s.length : 0
210
+ end
211
+
212
+ # @return [String] a formatted representation (based on the configuration of
213
+ # the object).
214
+ def to_s
215
+ print_to_output("", false)
216
+ end
217
+
218
+ # @return [String] a (possibly highlighted) copy of the source code.
219
+ def highlighted
220
+ print_to_output("", true)
221
+ end
222
+
223
+ # Writes a formatted representation (based on the configuration of the
224
+ # object) to the given output, which must respond to `#<<`.
225
+ def print_to_output(output, color=false)
226
+ @lines.each do |loc|
227
+ loc = loc.dup
228
+ loc.add_line_number(max_lineno_width) if @with_line_numbers
229
+ loc.add_marker(@marker_lineno) if @with_marker
230
+ loc.indent(@indentation_num) if @with_indentation
231
+ output << loc.line
232
+ output << "\n"
233
+ end
234
+ output
235
+ end
236
+
237
+ # Get the comment that describes the expression on the given line number.
238
+ #
239
+ # @param [Integer] line_number (1-based)
240
+ # @return [String] the code.
241
+ def comment_describing(line_number)
242
+ self.class.comment_describing(raw, line_number)
243
+ end
244
+
245
+ # Get the multiline expression that starts on the given line number.
246
+ #
247
+ # @param [Integer] line_number (1-based)
248
+ # @return [String] the code.
249
+ def expression_at(line_number, consume = 0)
250
+ self.class.expression_at(raw, line_number, :consume => consume)
251
+ end
252
+
253
+ # Get the multiline expression that starts on the given line number.
254
+ #
255
+ # @param [Integer] line_number (1-based)
256
+ # @return [String] the code.
257
+ def self.expression_at(raw, line_number, consume = 0)
258
+ #self.class.expression_at(raw, line_number, :consume => consume)
259
+ raw
260
+ end
261
+
262
+ # Get the (approximate) Module.nesting at the give line number.
263
+ #
264
+ # @param [Integer] line_number line number starting from 1
265
+ # @param [Module] top_module the module in which this code exists
266
+ # @return [Array<Module>] a list of open modules.
267
+ def nesting_at(line_number, top_module = Object)
268
+ Indent.nesting_at(raw, line_number)
269
+ end
270
+
271
+ # Return an unformatted String of the code.
272
+ #
273
+ # @return [String]
274
+ def raw
275
+ @lines.map(&:line).join("\n") << "\n"
276
+ end
277
+
278
+ # Return the number of lines stored.
279
+ #
280
+ # @return [Integer]
281
+ def length
282
+ @lines ? @lines.length : 0
283
+ end
284
+
285
+ # Two `Code` objects are equal if they contain the same lines with the same
286
+ # numbers. Otherwise, call `to_s` and `chomp` and compare as Strings.
287
+ #
288
+ # @param [Code, Object] other
289
+ # @return [Boolean]
290
+ def ==(other)
291
+ if other.is_a?(Code)
292
+ other_lines = other.instance_variable_get(:@lines)
293
+ @lines.each_with_index.all? { |loc, i| loc == other_lines[i] }
294
+ else
295
+ to_s.chomp == other.to_s.chomp
296
+ end
297
+ end
298
+
299
+ # Forward any missing methods to the output of `#to_s`.
300
+ def method_missing(name, *args, &block)
301
+ to_s.send(name, *args, &block)
302
+ end
303
+ undef =~
304
+
305
+ protected
306
+
307
+ # An abstraction of the `dup.instance_eval` pattern used throughout this
308
+ # class.
309
+ def alter(&block)
310
+ dup.tap { |o| o.instance_eval(&block) }
311
+ end
312
+ end
@@ -4,10 +4,22 @@ module PuppetRepl
4
4
 
5
5
  def static_responder_list
6
6
  ["exit", "functions", "classification","vars", 'facterdb_filter', "krt", "facts",
7
- "resources", "classes", "play","reset", "help"
7
+ "resources", "classes", "whereami", "play","reset", "help"
8
8
  ]
9
9
  end
10
10
 
11
+ # @source_file and @source_line_num instance variables must be set for this
12
+ # method to show the surrounding code
13
+ # @return [String] - string output of the code surrounded by the breakpoint or nil if file or line_num do not exist
14
+ def whereami(command=nil, args=nil)
15
+ file=@source_file
16
+ line_num=@source_line_num
17
+ if file and line_num
18
+ code = ReplCode.from_file(file, :puppet)
19
+ return code.with_marker(line_num).around(line_num, 5).with_line_numbers.with_indentation(5).to_s
20
+ end
21
+ end
22
+
11
23
  def facterdb_filter(args=[])
12
24
  dynamic_facterdb_filter.ai
13
25
  end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module PuppetRepl
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.2'
3
3
  end
data/puppet-repl.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
11
11
  # to allow pushing to a single host or delete this section to allow pushing to any host.
12
12
  if s.respond_to?(:metadata)
13
- s.metadata['allowed_push_host'] = "'http://mygemserver.com'"
13
+ s.metadata['allowed_push_host'] = 'https://rubygems.org'
14
14
  else
15
15
  raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
16
16
  end
@@ -0,0 +1,12 @@
1
+ class sample_test_breakpoint(
2
+
3
+ ) {
4
+
5
+ include stdlib
6
+ file{'/tmp/test':
7
+ ensure => present,
8
+ }
9
+ range(1,5).map | $num | {
10
+ start_repl()
11
+ }
12
+ }
@@ -15,7 +15,11 @@ describe "PuppetRepl" do
15
15
  end
16
16
 
17
17
  let(:repl) do
18
- PuppetRepl::Cli.new(:out_buffer => output)
18
+ PuppetRepl::Cli.new({:out_buffer => output}.merge(options))
19
+ end
20
+
21
+ let(:options) do
22
+ {}
19
23
  end
20
24
 
21
25
  let(:input) do
@@ -178,7 +182,7 @@ describe "PuppetRepl" do
178
182
  'help'
179
183
  end
180
184
  it 'can show the help screen' do
181
- expected_repl_output = /Type \"exit\", \"functions\", \"vars\", \"krt\", \"facts\", \"resources\", \"classes\",\n \"play\", \"classification\", \"reset\", or \"help\" for more information.\n\n/
185
+ expected_repl_output = /Type \"exit\", \"functions\", \"vars\", \"krt\", \"whereami\", \"facts\", \"resources\", \"classes\",\n \"play\", \"classification\", \"reset\", or \"help\" for more information.\n\n/
182
186
  repl.handle_input(input)
183
187
  expect(output.string).to match(/Ruby Version: #{RUBY_VERSION}\n/)
184
188
  expect(output.string).to match(/Puppet Version: \d.\d.\d\n/)
@@ -445,12 +449,31 @@ describe "PuppetRepl" do
445
449
  end
446
450
  end
447
451
 
452
+ describe 'whereami' do
453
+ let(:input) do
454
+ File.expand_path File.join(fixtures_dir, 'sample_start_repl.pp')
455
+ end
456
+ let(:options) do
457
+ {
458
+ source_file: input,
459
+ source_line: 10,
460
+ }
461
+ end
462
+
463
+ it 'runs' do
464
+ expect(repl.whereami).to match(/\s+5/)
465
+ end
466
+ it 'contains marker' do
467
+ expect(repl.whereami).to match(/\s+=>\s10/)
468
+ end
469
+
470
+ end
471
+
448
472
  describe 'error message' do
449
473
  let(:input) do
450
474
  "file{'/tmp/test': ensure => present, contact => 'blah'}"
451
475
  end
452
- p_version = ENV['PUPPET_GEM_VERSION'].split(' ').last
453
- if Gem::Version.new(p_version) >= Gem::Version.new('4.0')
476
+ if Gem::Version.new(Puppet.version) >= Gem::Version.new('4.0')
454
477
  it 'show error message' do
455
478
  repl_output = /no\ parameter\ named\ 'contact'/
456
479
  repl.handle_input(input)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-repl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Corey Osman
@@ -90,6 +90,10 @@ files:
90
90
  - lib/awesome_print/ext/awesome_puppet.rb
91
91
  - lib/puppet-repl.rb
92
92
  - lib/puppet-repl/cli.rb
93
+ - lib/puppet-repl/code/code_file.rb
94
+ - lib/puppet-repl/code/code_range.rb
95
+ - lib/puppet-repl/code/loc.rb
96
+ - lib/puppet-repl/repl_code.rb
93
97
  - lib/puppet-repl/support.rb
94
98
  - lib/puppet-repl/support/compiler.rb
95
99
  - lib/puppet-repl/support/environment.rb
@@ -109,6 +113,7 @@ files:
109
113
  - spec/fixtures/invalid_node_obj.yaml
110
114
  - spec/fixtures/node_obj.yaml
111
115
  - spec/fixtures/sample_manifest.pp
116
+ - spec/fixtures/sample_start_repl.pp
112
117
  - spec/prepl_spec.rb
113
118
  - spec/puppet-repl_spec.rb
114
119
  - spec/remote_node_spec.rb
@@ -119,7 +124,7 @@ homepage: http://github.com/nwops/puppet-repl
119
124
  licenses:
120
125
  - MIT
121
126
  metadata:
122
- allowed_push_host: "'http://mygemserver.com'"
127
+ allowed_push_host: https://rubygems.org
123
128
  post_install_message:
124
129
  rdoc_options: []
125
130
  require_paths: