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 +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:
|