puppet-repl 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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: