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 +4 -4
- data/.gitlab-ci.yml +2 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile.lock +3 -2
- data/lib/puppet-repl.rb +2 -1
- data/lib/puppet-repl/cli.rb +24 -6
- data/lib/puppet-repl/code/code_file.rb +98 -0
- data/lib/puppet-repl/code/code_range.rb +69 -0
- data/lib/puppet-repl/code/loc.rb +80 -0
- data/lib/puppet-repl/repl_code.rb +312 -0
- data/lib/puppet-repl/support/input_responders.rb +13 -1
- data/lib/version.rb +1 -1
- data/puppet-repl.gemspec +1 -1
- data/spec/fixtures/sample_start_repl.pp +12 -0
- data/spec/puppet-repl_spec.rb +27 -4
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca90b4e2bd2667abaceead15b141c87b712aea32
|
4
|
+
data.tar.gz: 20aedb19e5dd5e93b62faf0438f47d7619a20e5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9dc96e79ff9bd8a348b0cf64d81cb857a38656e4d19a91e6d8a7d325eff7e5c6fa11f0ac3e01fcc178348986d5701f0677b0a1f84d3d502b66ddf2b07cc9da24
|
7
|
+
data.tar.gz: 3a5f8b6056dcf2d63101c25ea30765bf74a63a158211f72d8f3be45289683cdb5a8d653a768cad6b991ada7a5c353acaabdb8a19463295baef1155fc35455646
|
data/.gitlab-ci.yml
CHANGED
data/CHANGELOG.md
CHANGED
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.
|
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.
|
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 },
|
data/lib/puppet-repl/cli.rb
CHANGED
@@ -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 [
|
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
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'] =
|
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
|
data/spec/puppet-repl_spec.rb
CHANGED
@@ -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
|
-
|
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.
|
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:
|
127
|
+
allowed_push_host: https://rubygems.org
|
123
128
|
post_install_message:
|
124
129
|
rdoc_options: []
|
125
130
|
require_paths:
|