mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
semi-working implementation of eval-based input validation
This commit is contained in:
parent
7109cebadd
commit
8d9890f876
2 changed files with 51 additions and 34 deletions
|
@ -534,45 +534,54 @@ class Pry
|
|||
prompt_stack.size > 1 ? prompt_stack.pop : prompt
|
||||
end
|
||||
|
||||
if RUBY_VERSION =~ /1.9/ && RUBY_ENGINE == "ruby"
|
||||
require 'ripper'
|
||||
|
||||
# Determine if a string of code is a valid Ruby expression.
|
||||
# Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser.
|
||||
# @param [String] code The code to validate.
|
||||
# @return [Boolean] Whether or not the code is a valid Ruby expression.
|
||||
# @example
|
||||
# valid_expression?("class Hello") #=> false
|
||||
# valid_expression?("class Hello; end") #=> true
|
||||
def valid_expression?(code)
|
||||
!!Ripper::SexpBuilder.new(code).parse
|
||||
end
|
||||
|
||||
elsif RUBY_VERSION =~ /1.9/ && RUBY_ENGINE == 'jruby'
|
||||
|
||||
# JRuby doesn't have Ripper, so use its native parser for 1.9 mode.
|
||||
def valid_expression?(code)
|
||||
JRuby.parse(code)
|
||||
true
|
||||
rescue SyntaxError
|
||||
false
|
||||
end
|
||||
|
||||
def valid_expression?(str)
|
||||
if defined?(Rubinius::Melbourne19) && RUBY_VERSION =~ /^1\.9/
|
||||
Rubinius::Melbourne19.parse_string(str, Pry.eval_path)
|
||||
elsif defined?(Rubinius::Melbourne)
|
||||
Rubinius::Melbourne.parse_string(str, Pry.eval_path)
|
||||
else
|
||||
require 'ruby_parser'
|
||||
catch(:valid) {
|
||||
eval("BEGIN{throw :valid, true}\n#{str}", binding, Pry.eval_path)
|
||||
}
|
||||
end
|
||||
rescue SyntaxError => e
|
||||
if incomplete_user_input_exception?(e, caller)
|
||||
false
|
||||
else
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
# Determine if a string of code is a valid Ruby expression.
|
||||
# Ruby 1.9 uses Ripper, Ruby 1.8 uses RubyParser.
|
||||
# @param [String] code The code to validate.
|
||||
# @return [Boolean] Whether or not the code is a valid Ruby expression.
|
||||
# @example
|
||||
# valid_expression?("class Hello") #=> false
|
||||
# valid_expression?("class Hello; end") #=> true
|
||||
def valid_expression?(code)
|
||||
# NOTE: we're using .dup because RubyParser mutates the input
|
||||
RubyParser.new.parse(code.dup)
|
||||
true
|
||||
rescue Racc::ParseError, SyntaxError
|
||||
# Check whether the exception indicates that the user should input more.
|
||||
#
|
||||
# The first part of the check verifies that the exception was raised from
|
||||
# the input to the eval, taking care not to be confused if the input contains
|
||||
# an eval() with incomplete syntax.
|
||||
#
|
||||
# @param [SyntaxError] the exception object that was raised.
|
||||
# @param [Array<String>] The stack frame of the function that executed eval.
|
||||
# @return [Boolean]
|
||||
#
|
||||
def incomplete_user_input_exception?(ex, stack)
|
||||
# deliberate use of ^ instead of \A, error messages can be two lines long.
|
||||
from_pry_input = /^#{Regexp.escape(Pry.eval_path)}/
|
||||
|
||||
return false unless SyntaxError === ex && ex.message =~ from_pry_input
|
||||
|
||||
case ex.message
|
||||
when /unexpected (\$end|end-of-file|END_OF_FILE)/, # mri, jruby, ironruby
|
||||
/unterminated (quoted string|string|regexp) meets end of file/, # "quoted string" is ironruby
|
||||
/missing 'end' for/, /: expecting '[})\]]'$/, /can't find string ".*" anywhere before EOF/, /expecting keyword_end/ # rbx
|
||||
backtrace = ex.backtrace
|
||||
backtrace = backtrace.drop(1) if RUBY_VERSION =~ /^1\.8/ && RUBY_PLATFORM !~ /java/
|
||||
backtrace.grep(from_pry_input).count <= stack.grep(from_pry_input).count
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -180,3 +180,11 @@ CommandTester = Pry::CommandSet.new do
|
|||
output.puts arg
|
||||
end
|
||||
end
|
||||
|
||||
# to help with tracking down bugs that cause an infinite loop in the test suite
|
||||
if ENV["SET_TRACE_FUNC"]
|
||||
require 'set_trace' if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/ # gem install 'rbx-tracer'
|
||||
set_trace_func proc { |event, file, line, id, binding, classname|
|
||||
STDERR.printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
|
||||
}
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue