brakeman 4.5.0 → 4.5.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of brakeman might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGES.md +15 -0
- data/README.md +6 -6
- data/bundle/load.rb +3 -3
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/AUTHORS +0 -0
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/COPYING +0 -0
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/Changelog.md +211 -15
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/Gemfile +22 -0
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/LICENSE +0 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/README.md +202 -0
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/TODO +0 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/appveyor.yml +37 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/highline.gemspec +35 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline.rb +650 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/builtin_styles.rb +129 -0
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/lib/highline/color_scheme.rb +49 -32
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/compatibility.rb +23 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/custom_errors.rb +57 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/import.rb +48 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/io_console_compatible.rb +37 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/list.rb +177 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/list_renderer.rb +261 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/menu.rb +576 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/menu/item.rb +32 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/paginator.rb +52 -0
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/lib/highline/question.rb +281 -131
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/question/answer_converter.rb +103 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/question_asker.rb +150 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/simulate.rb +59 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/statement.rb +88 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/string.rb +36 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/string_extensions.rb +130 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/style.rb +325 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/template_renderer.rb +62 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal.rb +190 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal/io_console.rb +36 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal/ncurses.rb +38 -0
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal/unix_stty.rb +51 -0
- data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/lib/highline/version.rb +3 -1
- data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/wrapper.rb +53 -0
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/History.rdoc +32 -0
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/Manifest.txt +0 -0
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/README.rdoc +0 -0
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/compare/normalize.rb +0 -0
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/debugging.md +0 -0
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/rp_extensions.rb +1 -1
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/rp_stringscanner.rb +0 -0
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby20_parser.rb +2427 -2432
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby20_parser.y +32 -29
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby21_parser.rb +2101 -2109
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby21_parser.y +32 -29
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby22_parser.rb +2080 -2095
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby22_parser.y +32 -29
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0/lib/ruby25_parser.rb → ruby_parser-3.13.1/lib/ruby23_parser.rb} +2339 -2333
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby23_parser.y +32 -29
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby24_parser.rb +2347 -2335
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby24_parser.y +32 -23
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0/lib/ruby23_parser.rb → ruby_parser-3.13.1/lib/ruby25_parser.rb} +2349 -2337
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby25_parser.y +32 -23
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby26_parser.rb +2351 -2338
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby26_parser.y +32 -23
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_lexer.rb +253 -161
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_lexer.rex +25 -25
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_lexer.rex.rb +68 -26
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_parser.rb +3 -1
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_parser.yy +34 -23
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_parser_extras.rb +64 -43
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/tools/munge.rb +2 -1
- data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/tools/ripper.rb +6 -1
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/CHANGELOG.md +4 -0
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/MIT-LICENSE.txt +0 -0
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/README.md +1 -1
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/data/display_width.marshal.gz +0 -0
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/lib/unicode/display_width.rb +0 -0
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/lib/unicode/display_width/constants.rb +2 -2
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/lib/unicode/display_width/index.rb +0 -0
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/lib/unicode/display_width/no_string_ext.rb +0 -0
- data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/lib/unicode/display_width/string_ext.rb +0 -0
- data/lib/brakeman.rb +7 -0
- data/lib/brakeman/app_tree.rb +34 -22
- data/lib/brakeman/checks.rb +7 -7
- data/lib/brakeman/checks/base_check.rb +9 -9
- data/lib/brakeman/checks/check_cross_site_scripting.rb +5 -0
- data/lib/brakeman/checks/check_default_routes.rb +5 -0
- data/lib/brakeman/checks/check_deserialize.rb +52 -0
- data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
- data/lib/brakeman/checks/check_force_ssl.rb +27 -0
- data/lib/brakeman/checks/check_json_parsing.rb +5 -0
- data/lib/brakeman/checks/check_link_to_href.rb +6 -1
- data/lib/brakeman/checks/check_mail_to.rb +1 -1
- data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
- data/lib/brakeman/checks/check_model_attributes.rb +12 -50
- data/lib/brakeman/checks/check_model_serialize.rb +1 -1
- data/lib/brakeman/checks/check_nested_attributes_bypass.rb +3 -3
- data/lib/brakeman/checks/check_secrets.rb +1 -1
- data/lib/brakeman/checks/check_session_settings.rb +10 -10
- data/lib/brakeman/checks/check_simple_format.rb +5 -0
- data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
- data/lib/brakeman/checks/check_sql.rb +15 -17
- data/lib/brakeman/checks/check_validation_regex.rb +1 -1
- data/lib/brakeman/file_parser.rb +6 -8
- data/lib/brakeman/file_path.rb +71 -0
- data/lib/brakeman/options.rb +7 -0
- data/lib/brakeman/parsers/template_parser.rb +3 -3
- data/lib/brakeman/processor.rb +3 -4
- data/lib/brakeman/processors/alias_processor.rb +12 -6
- data/lib/brakeman/processors/base_processor.rb +8 -7
- data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
- data/lib/brakeman/processors/controller_processor.rb +5 -9
- data/lib/brakeman/processors/haml_template_processor.rb +5 -0
- data/lib/brakeman/processors/lib/module_helper.rb +8 -8
- data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +3 -3
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
- data/lib/brakeman/processors/lib/render_helper.rb +2 -2
- data/lib/brakeman/processors/lib/render_path.rb +18 -1
- data/lib/brakeman/processors/library_processor.rb +5 -5
- data/lib/brakeman/processors/model_processor.rb +4 -5
- data/lib/brakeman/processors/output_processor.rb +5 -0
- data/lib/brakeman/processors/template_alias_processor.rb +4 -5
- data/lib/brakeman/processors/template_processor.rb +4 -4
- data/lib/brakeman/report.rb +3 -3
- data/lib/brakeman/report/ignore/config.rb +2 -3
- data/lib/brakeman/report/ignore/interactive.rb +2 -2
- data/lib/brakeman/report/pager.rb +1 -0
- data/lib/brakeman/report/report_base.rb +51 -6
- data/lib/brakeman/report/report_codeclimate.rb +3 -3
- data/lib/brakeman/report/report_hash.rb +1 -1
- data/lib/brakeman/report/report_html.rb +2 -2
- data/lib/brakeman/report/report_json.rb +1 -24
- data/lib/brakeman/report/report_table.rb +20 -4
- data/lib/brakeman/report/report_tabs.rb +1 -1
- data/lib/brakeman/report/report_text.rb +2 -2
- data/lib/brakeman/rescanner.rb +9 -12
- data/lib/brakeman/scanner.rb +19 -14
- data/lib/brakeman/tracker.rb +4 -4
- data/lib/brakeman/tracker/collection.rb +4 -3
- data/lib/brakeman/tracker/config.rb +6 -0
- data/lib/brakeman/util.rb +1 -147
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +23 -13
- data/lib/brakeman/warning_codes.rb +1 -0
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
- metadata +78 -61
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/Gemfile +0 -11
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/INSTALL +0 -59
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/README.rdoc +0 -74
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/highline.gemspec +0 -37
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline.rb +0 -1048
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/compatibility.rb +0 -16
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/import.rb +0 -41
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/menu.rb +0 -381
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/simulate.rb +0 -48
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/string_extensions.rb +0 -111
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/style.rb +0 -192
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/system_extensions.rb +0 -254
- data/bundle/ruby/2.5.0/gems/highline-1.7.10/setup.rb +0 -1360
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class HighLine
|
4
|
+
class Menu < Question
|
5
|
+
# Represents an Item of a HighLine::Menu.
|
6
|
+
#
|
7
|
+
class Item
|
8
|
+
attr_reader :name, :text, :help, :action
|
9
|
+
|
10
|
+
#
|
11
|
+
# @param name [String] The name that is matched against the user input
|
12
|
+
# @param attributes [Hash] options Hash to tailor menu item to your needs
|
13
|
+
# @option attributes text: [String] The text that displays for that
|
14
|
+
# choice (defaults to name)
|
15
|
+
# @option attributes help: [String] help/hint string to be displayed.
|
16
|
+
# @option attributes action: [Block] a block that gets called when choice
|
17
|
+
# is selected
|
18
|
+
#
|
19
|
+
def initialize(name, attributes)
|
20
|
+
@name = name
|
21
|
+
@text = attributes[:text] || @name
|
22
|
+
@help = attributes[:help]
|
23
|
+
@action = attributes[:action]
|
24
|
+
end
|
25
|
+
|
26
|
+
def item_help
|
27
|
+
return {} unless help
|
28
|
+
{ name.to_s.downcase => help }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
class HighLine
|
4
|
+
# Take the task of paginating some piece of text given a HighLine context
|
5
|
+
class Paginator
|
6
|
+
# @return [HighLine] HighLine context
|
7
|
+
attr_reader :highline
|
8
|
+
|
9
|
+
# Returns a HighLine::Paginator instance where you can
|
10
|
+
# call {#page_print} on it.
|
11
|
+
# @param highline [HighLine] context
|
12
|
+
# @example
|
13
|
+
# HighLine::Paginator.new(highline).page_print(statement)
|
14
|
+
def initialize(highline)
|
15
|
+
@highline = highline
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Page print a series of at most _page_at_ lines for _output_. After each
|
20
|
+
# page is printed, HighLine will pause until the user presses enter/return
|
21
|
+
# then display the next page of data.
|
22
|
+
#
|
23
|
+
# Note that the final page of _output_ is *not* printed, but returned
|
24
|
+
# instead. This is to support any special handling for the final sequence.
|
25
|
+
#
|
26
|
+
# @param text [String] text to be paginated
|
27
|
+
# @return [String] last line if paging is aborted
|
28
|
+
def page_print(text)
|
29
|
+
return text unless highline.page_at
|
30
|
+
|
31
|
+
lines = text.lines.to_a
|
32
|
+
while lines.size > highline.page_at
|
33
|
+
highline.puts lines.slice!(0...highline.page_at).join
|
34
|
+
highline.puts
|
35
|
+
# Return last line if user wants to abort paging
|
36
|
+
return "...\n#{lines.last}" unless continue_paging?
|
37
|
+
end
|
38
|
+
lines.join
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Ask user if they wish to continue paging output. Allows them to
|
43
|
+
# type "q" to cancel the paging process.
|
44
|
+
#
|
45
|
+
def continue_paging?
|
46
|
+
command = highline.new_scope.ask(
|
47
|
+
"-- press enter/return to continue or q to stop -- "
|
48
|
+
) { |q| q.character = true }
|
49
|
+
command !~ /\A[qQ]\Z/ # Only continue paging if Q was not hit.
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#--
|
1
4
|
# question.rb
|
2
5
|
#
|
3
6
|
# Created by James Edward Gray II on 2005-04-26.
|
@@ -5,9 +8,11 @@
|
|
5
8
|
#
|
6
9
|
# This is Free Software. See LICENSE and COPYING for details.
|
7
10
|
|
11
|
+
require "English"
|
8
12
|
require "optparse"
|
9
13
|
require "date"
|
10
14
|
require "pathname"
|
15
|
+
require "highline/question/answer_converter"
|
11
16
|
|
12
17
|
class HighLine
|
13
18
|
#
|
@@ -17,43 +22,49 @@ class HighLine
|
|
17
22
|
# process is handled according to the users wishes.
|
18
23
|
#
|
19
24
|
class Question
|
20
|
-
|
21
|
-
|
22
|
-
|
25
|
+
include CustomErrors
|
26
|
+
|
27
|
+
#
|
28
|
+
# If _template_or_question_ is already a Question object just return it.
|
29
|
+
# If not, build it.
|
30
|
+
#
|
31
|
+
# @param template_or_question [String, Question] what to ask
|
32
|
+
# @param answer_type [Class] to what class to convert the answer
|
33
|
+
# @param details to be passed to Question.new
|
34
|
+
# @return [Question]
|
35
|
+
def self.build(template_or_question, answer_type = nil, &details)
|
36
|
+
if template_or_question.is_a? Question
|
37
|
+
template_or_question
|
38
|
+
else
|
39
|
+
Question.new(template_or_question, answer_type, &details)
|
40
|
+
end
|
23
41
|
end
|
24
42
|
|
25
43
|
#
|
26
|
-
# Create an instance of HighLine::Question. Expects a
|
44
|
+
# Create an instance of HighLine::Question. Expects a _template_ to ask
|
27
45
|
# (can be <tt>""</tt>) and an _answer_type_ to convert the answer to.
|
28
46
|
# The _answer_type_ parameter must be a type recognized by
|
29
47
|
# Question.convert(). If given, a block is yielded the new Question
|
30
48
|
# object to allow custom initialization.
|
31
49
|
#
|
32
|
-
|
50
|
+
# @param template [String] any String
|
51
|
+
# @param answer_type [Class] the type the answer will be converted to it.
|
52
|
+
def initialize(template, answer_type)
|
33
53
|
# initialize instance data
|
34
|
-
@
|
54
|
+
@template = String(template).dup
|
35
55
|
@answer_type = answer_type
|
36
|
-
@completion
|
56
|
+
@completion = @answer_type
|
37
57
|
|
38
|
-
@character = nil
|
39
|
-
@limit = nil
|
40
58
|
@echo = true
|
41
|
-
@readline = false
|
42
59
|
@whitespace = :strip
|
43
60
|
@case = nil
|
44
|
-
@default = nil
|
45
|
-
@validate = nil
|
46
|
-
@above = nil
|
47
|
-
@below = nil
|
48
61
|
@in = nil
|
49
|
-
@confirm = nil
|
50
|
-
@gather = false
|
51
|
-
@verify_match = false
|
52
62
|
@first_answer = nil
|
53
|
-
@directory = Pathname.new(File.expand_path(File.dirname($0)))
|
54
63
|
@glob = "*"
|
55
|
-
@responses = Hash.new
|
56
64
|
@overwrite = false
|
65
|
+
@user_responses = {}
|
66
|
+
@internal_responses = default_responses_hash
|
67
|
+
@directory = Pathname.new(File.expand_path(File.dirname($PROGRAM_NAME)))
|
57
68
|
|
58
69
|
# allow block to override settings
|
59
70
|
yield self if block_given?
|
@@ -63,7 +74,11 @@ class HighLine
|
|
63
74
|
end
|
64
75
|
|
65
76
|
# The ERb template of the question to be asked.
|
66
|
-
attr_accessor :
|
77
|
+
attr_accessor :template
|
78
|
+
|
79
|
+
# The answer, set by HighLine#ask
|
80
|
+
attr_accessor :answer
|
81
|
+
|
67
82
|
# The type that will be used to convert this answer.
|
68
83
|
attr_accessor :answer_type
|
69
84
|
# For Auto-completion
|
@@ -133,11 +148,15 @@ class HighLine
|
|
133
148
|
attr_accessor :in
|
134
149
|
#
|
135
150
|
# Asks a yes or no confirmation question, to ensure a user knows what
|
136
|
-
# they have just agreed to.
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
151
|
+
# they have just agreed to. The confirm attribute can be set to :
|
152
|
+
# +true+ : In this case the question will be, "Are you sure?".
|
153
|
+
# Proc : The Proc is yielded the answer given. The Proc must
|
154
|
+
# output a string which is then used as the confirm
|
155
|
+
# question.
|
156
|
+
# String : The String must use ERB syntax. The String is
|
157
|
+
# evaluated with access to question and answer and
|
158
|
+
# is then used as the confirm question.
|
159
|
+
# When set to +false+ or +nil+ (the default), answers are not confirmed.
|
141
160
|
attr_accessor :confirm
|
142
161
|
#
|
143
162
|
# When set, the user will be prompted for multiple answers which will
|
@@ -201,7 +220,9 @@ class HighLine
|
|
201
220
|
# <tt>:not_valid</tt>:: The error message shown when
|
202
221
|
# validation checks fail.
|
203
222
|
#
|
204
|
-
|
223
|
+
def responses
|
224
|
+
@user_responses
|
225
|
+
end
|
205
226
|
#
|
206
227
|
# When set to +true+ the question is asked, but output does not progress to
|
207
228
|
# the next line. The Cursor is moved back to the beginning of the question
|
@@ -214,12 +235,11 @@ class HighLine
|
|
214
235
|
# Returns the provided _answer_string_ or the default answer for this
|
215
236
|
# Question if a default was set and the answer is empty.
|
216
237
|
#
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
end
|
238
|
+
# @param answer_string [String]
|
239
|
+
# @return [String] the answer itself or a default message.
|
240
|
+
def answer_or_default(answer_string)
|
241
|
+
return default if answer_string.empty? && default
|
242
|
+
answer_string
|
223
243
|
end
|
224
244
|
|
225
245
|
#
|
@@ -227,36 +247,55 @@ class HighLine
|
|
227
247
|
# responses based on the details of this Question object.
|
228
248
|
# Also used by Menu#update_responses.
|
229
249
|
#
|
230
|
-
|
250
|
+
# @return [Hash] responses Hash winner (new and old merge).
|
251
|
+
# @param message_source [Class] Array or String for example.
|
252
|
+
# Same as {#answer_type}.
|
253
|
+
|
254
|
+
def build_responses(message_source = answer_type)
|
231
255
|
append_default if [::String, Symbol].include? default.class
|
232
256
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
257
|
+
new_hash = build_responses_new_hash(message_source)
|
258
|
+
# Update our internal responses with the new hash
|
259
|
+
# generated from the message source
|
260
|
+
@internal_responses = @internal_responses.merge(new_hash)
|
261
|
+
end
|
262
|
+
|
263
|
+
def default_responses_hash
|
264
|
+
{
|
265
|
+
ask_on_error: "? ",
|
266
|
+
mismatch: "Your entries didn't match."
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
# When updating the responses hash, it generates the new one.
|
271
|
+
# @param message_source (see #build_responses)
|
272
|
+
# @return [Hash] responses hash
|
273
|
+
def build_responses_new_hash(message_source)
|
274
|
+
{ ambiguous_completion: "Ambiguous choice. Please choose one of " +
|
275
|
+
choice_error_str(message_source) + ".",
|
276
|
+
invalid_type: "You must enter a valid #{message_source}.",
|
277
|
+
no_completion: "You must choose one of " +
|
278
|
+
choice_error_str(message_source) + ".",
|
279
|
+
not_in_range: "Your answer isn't within the expected range " \
|
280
|
+
"(#{expected_range}).",
|
281
|
+
not_valid: "Your answer isn't valid (must match " \
|
282
|
+
"#{validate.inspect})." }
|
283
|
+
end
|
238
284
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
:mismatch =>
|
254
|
-
"Your entries didn't match.",
|
255
|
-
:not_valid =>
|
256
|
-
"Your answer isn't valid (must match " +
|
257
|
-
"#{@validate.inspect})." }
|
258
|
-
|
259
|
-
@responses = new_hash_wins ? old_hash.merge(new_hash) : new_hash.merge(old_hash)
|
285
|
+
# This is the actual responses hash that gets used in determining output
|
286
|
+
# Notice that we give @user_responses precedence over the responses
|
287
|
+
# generated internally via build_response
|
288
|
+
def final_responses
|
289
|
+
@internal_responses.merge(@user_responses)
|
290
|
+
end
|
291
|
+
|
292
|
+
def final_response(error)
|
293
|
+
response = final_responses[error]
|
294
|
+
if response.respond_to?(:call)
|
295
|
+
response.call(answer)
|
296
|
+
else
|
297
|
+
response
|
298
|
+
end
|
260
299
|
end
|
261
300
|
|
262
301
|
#
|
@@ -273,7 +312,10 @@ class HighLine
|
|
273
312
|
#
|
274
313
|
# An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
|
275
314
|
#
|
276
|
-
|
315
|
+
# @param answer_string [String]
|
316
|
+
# @return [String] upcased, downcased, capitalized
|
317
|
+
# or unchanged answer String.
|
318
|
+
def change_case(answer_string)
|
277
319
|
if [:up, :upcase].include?(@case)
|
278
320
|
answer_string.upcase
|
279
321
|
elsif [:down, :downcase].include?(@case)
|
@@ -314,46 +356,34 @@ class HighLine
|
|
314
356
|
# This method throws ArgumentError, if the conversion cannot be
|
315
357
|
# completed for any reason.
|
316
358
|
#
|
317
|
-
def convert
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
if @answer_type.is_a?(Array)
|
337
|
-
answer.last
|
338
|
-
elsif @answer_type == File
|
339
|
-
File.open(File.join(@directory.to_s, answer.last))
|
340
|
-
else
|
341
|
-
Pathname.new(File.join(@directory.to_s, answer.last))
|
342
|
-
end
|
343
|
-
elsif [Date, DateTime].include?(@answer_type) or @answer_type.is_a?(Class)
|
344
|
-
@answer_type.parse(answer_string)
|
345
|
-
elsif @answer_type.is_a?(Proc)
|
346
|
-
@answer_type[answer_string]
|
347
|
-
end
|
359
|
+
def convert
|
360
|
+
AnswerConverter.new(self).convert
|
361
|
+
end
|
362
|
+
|
363
|
+
# Run {#in_range?} and raise an error if not succesful
|
364
|
+
def check_range
|
365
|
+
raise NotInRangeQuestionError unless in_range?
|
366
|
+
end
|
367
|
+
|
368
|
+
# Try to auto complete answer_string
|
369
|
+
# @param answer_string [String]
|
370
|
+
# @return [String]
|
371
|
+
def choices_complete(answer_string)
|
372
|
+
# cheating, using OptionParser's Completion module
|
373
|
+
choices = selection
|
374
|
+
choices.extend(OptionParser::Completion)
|
375
|
+
answer = choices.complete(answer_string)
|
376
|
+
raise NoAutoCompleteMatch unless answer
|
377
|
+
answer
|
348
378
|
end
|
349
379
|
|
350
380
|
# Returns an English explanation of the current range settings.
|
351
|
-
def expected_range
|
352
|
-
expected = [
|
381
|
+
def expected_range
|
382
|
+
expected = []
|
353
383
|
|
354
|
-
expected << "above #{
|
355
|
-
expected << "below #{
|
356
|
-
expected << "included in #{@in.inspect}"
|
384
|
+
expected << "above #{above}" if above
|
385
|
+
expected << "below #{below}" if below
|
386
|
+
expected << "included in #{@in.inspect}" if @in
|
357
387
|
|
358
388
|
case expected.size
|
359
389
|
when 0 then ""
|
@@ -364,15 +394,15 @@ class HighLine
|
|
364
394
|
end
|
365
395
|
|
366
396
|
# Returns _first_answer_, which will be unset following this call.
|
367
|
-
def first_answer
|
397
|
+
def first_answer
|
368
398
|
@first_answer
|
369
399
|
ensure
|
370
400
|
@first_answer = nil
|
371
401
|
end
|
372
402
|
|
373
403
|
# Returns true if _first_answer_ is set.
|
374
|
-
def first_answer?
|
375
|
-
|
404
|
+
def first_answer?
|
405
|
+
true if @first_answer
|
376
406
|
end
|
377
407
|
|
378
408
|
#
|
@@ -381,10 +411,10 @@ class HighLine
|
|
381
411
|
# _in_ attribute. Otherwise, +false+ is returned. Any +nil+ attributes
|
382
412
|
# are not checked.
|
383
413
|
#
|
384
|
-
def in_range?
|
385
|
-
(
|
386
|
-
|
387
|
-
|
414
|
+
def in_range?
|
415
|
+
(!above || answer > above) &&
|
416
|
+
(!below || answer < below) &&
|
417
|
+
(!@in || @in.include?(answer))
|
388
418
|
end
|
389
419
|
|
390
420
|
#
|
@@ -406,43 +436,55 @@ class HighLine
|
|
406
436
|
#
|
407
437
|
# This process is skipped for single character input.
|
408
438
|
#
|
409
|
-
|
410
|
-
|
439
|
+
# @param answer_string [String]
|
440
|
+
# @return [String] answer string with whitespaces removed
|
441
|
+
def remove_whitespace(answer_string)
|
442
|
+
if !whitespace
|
411
443
|
answer_string
|
412
|
-
elsif [:strip, :chomp].include?(
|
413
|
-
answer_string.send(
|
414
|
-
elsif
|
444
|
+
elsif [:strip, :chomp].include?(whitespace)
|
445
|
+
answer_string.send(whitespace)
|
446
|
+
elsif whitespace == :collapse
|
415
447
|
answer_string.gsub(/\s+/, " ")
|
416
|
-
elsif [:strip_and_collapse, :chomp_and_collapse].include?(
|
417
|
-
result = answer_string.send(
|
448
|
+
elsif [:strip_and_collapse, :chomp_and_collapse].include?(whitespace)
|
449
|
+
result = answer_string.send(whitespace.to_s[/^[a-z]+/])
|
418
450
|
result.gsub(/\s+/, " ")
|
419
|
-
elsif
|
451
|
+
elsif whitespace == :remove
|
420
452
|
answer_string.gsub(/\s+/, "")
|
421
453
|
else
|
422
454
|
answer_string
|
423
455
|
end
|
424
456
|
end
|
425
457
|
|
458
|
+
# Convert to String, remove whitespace and change case
|
459
|
+
# when necessary
|
460
|
+
# @param answer_string [String]
|
461
|
+
# @return [String] converted String
|
462
|
+
def format_answer(answer_string)
|
463
|
+
answer_string = String(answer_string)
|
464
|
+
answer_string = remove_whitespace(answer_string)
|
465
|
+
change_case(answer_string)
|
466
|
+
end
|
467
|
+
|
426
468
|
#
|
427
469
|
# Returns an Array of valid answers to this question. These answers are
|
428
470
|
# only known when _answer_type_ is set to an Array of choices, File, or
|
429
471
|
# Pathname. Any other time, this method will return an empty Array.
|
430
472
|
#
|
431
|
-
def selection
|
432
|
-
if
|
433
|
-
|
434
|
-
elsif [File, Pathname].include?(
|
435
|
-
Dir[File.join(
|
473
|
+
def selection
|
474
|
+
if completion.is_a?(Array)
|
475
|
+
completion
|
476
|
+
elsif [File, Pathname].include?(completion)
|
477
|
+
Dir[File.join(directory.to_s, glob)].map do |file|
|
436
478
|
File.basename(file)
|
437
479
|
end
|
438
480
|
else
|
439
|
-
[
|
481
|
+
[]
|
440
482
|
end
|
441
483
|
end
|
442
484
|
|
443
|
-
# Stringifies the
|
485
|
+
# Stringifies the template to be asked.
|
444
486
|
def to_s
|
445
|
-
|
487
|
+
template
|
446
488
|
end
|
447
489
|
|
448
490
|
#
|
@@ -452,10 +494,110 @@ class HighLine
|
|
452
494
|
# It's important to realize that an answer is validated after whitespace
|
453
495
|
# and case handling.
|
454
496
|
#
|
455
|
-
def valid_answer?
|
456
|
-
|
457
|
-
|
458
|
-
|
497
|
+
def valid_answer?
|
498
|
+
!validate ||
|
499
|
+
(validate.is_a?(Regexp) && answer =~ validate) ||
|
500
|
+
(validate.is_a?(Proc) && validate[answer])
|
501
|
+
end
|
502
|
+
|
503
|
+
#
|
504
|
+
# Return a line or character of input, as requested for this question.
|
505
|
+
# Character input will be returned as a single character String,
|
506
|
+
# not an Integer.
|
507
|
+
#
|
508
|
+
# This question's _first_answer_ will be returned instead of input, if set.
|
509
|
+
#
|
510
|
+
# Raises EOFError if input is exhausted.
|
511
|
+
#
|
512
|
+
# @param highline [HighLine] context
|
513
|
+
# @return [String] a character or line
|
514
|
+
|
515
|
+
def get_response(highline)
|
516
|
+
return first_answer if first_answer?
|
517
|
+
|
518
|
+
case character
|
519
|
+
when :getc
|
520
|
+
highline.get_response_getc_mode(self)
|
521
|
+
when true
|
522
|
+
highline.get_response_character_mode(self)
|
523
|
+
else
|
524
|
+
highline.get_response_line_mode(self)
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
# Uses {#get_response} but returns a default answer
|
529
|
+
# using {#answer_or_default} in case no answers was
|
530
|
+
# returned.
|
531
|
+
#
|
532
|
+
# @param highline [HighLine] context
|
533
|
+
# @return [String]
|
534
|
+
|
535
|
+
def get_response_or_default(highline)
|
536
|
+
self.answer = answer_or_default(get_response(highline))
|
537
|
+
end
|
538
|
+
|
539
|
+
# Returns the String to be shown when asking for an answer confirmation.
|
540
|
+
# @param highline [HighLine] context
|
541
|
+
# @return [String] default "Are you sure?" if {#confirm} is +true+
|
542
|
+
# @return [String] {#confirm} rendered as a template if it is a String
|
543
|
+
def confirm_question(highline)
|
544
|
+
if confirm == true
|
545
|
+
"Are you sure? "
|
546
|
+
elsif confirm.is_a?(Proc)
|
547
|
+
confirm.call(answer)
|
548
|
+
else
|
549
|
+
# evaluate ERb under initial scope, so it will have
|
550
|
+
# access to question and answer
|
551
|
+
template = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
|
552
|
+
ERB.new(confirm, trim_mode: "%")
|
553
|
+
else
|
554
|
+
ERB.new(confirm, nil, "%")
|
555
|
+
end
|
556
|
+
template_renderer = TemplateRenderer.new(template, self, highline)
|
557
|
+
template_renderer.render
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
# Provides the String to be asked when at an error situation.
|
562
|
+
# It may be just the question itself (repeat on error).
|
563
|
+
# @return [self] if :ask_on_error on responses Hash is set to :question
|
564
|
+
# @return [String] if :ask_on_error on responses Hash is set to
|
565
|
+
# something else
|
566
|
+
def ask_on_error_msg
|
567
|
+
if final_responses[:ask_on_error] == :question
|
568
|
+
self
|
569
|
+
elsif final_responses[:ask_on_error]
|
570
|
+
final_responses[:ask_on_error]
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
# readline() needs to handle its own output, but readline only supports
|
575
|
+
# full line reading. Therefore if question.echo is anything but true,
|
576
|
+
# the prompt will not be issued. And we have to account for that now.
|
577
|
+
# Also, JRuby-1.7's ConsoleReader.readLine() needs to be passed the prompt
|
578
|
+
# to handle line editing properly.
|
579
|
+
# @param highline [HighLine] context
|
580
|
+
# @return [void]
|
581
|
+
def show_question(highline)
|
582
|
+
highline.say(self)
|
583
|
+
end
|
584
|
+
|
585
|
+
# Returns an echo string that is adequate for this Question settings.
|
586
|
+
# @param response [String]
|
587
|
+
# @return [String] the response itself if {#echo} is +true+.
|
588
|
+
# @return [String] echo character if {#echo} is truethy. Mainly a String.
|
589
|
+
# @return [String] empty string if {#echo} is falsy.
|
590
|
+
def get_echo_for_response(response)
|
591
|
+
# actually true, not only truethy value
|
592
|
+
if echo == true
|
593
|
+
response
|
594
|
+
# any truethy value, probably a String
|
595
|
+
elsif echo
|
596
|
+
echo
|
597
|
+
# any falsy value, false or nil
|
598
|
+
else
|
599
|
+
""
|
600
|
+
end
|
459
601
|
end
|
460
602
|
|
461
603
|
private
|
@@ -465,15 +607,23 @@ class HighLine
|
|
465
607
|
# Trailing whitespace is preserved so the function of HighLine.say() is
|
466
608
|
# not affected.
|
467
609
|
#
|
468
|
-
def append_default
|
469
|
-
if
|
470
|
-
|
471
|
-
elsif
|
472
|
-
|
473
|
-
elsif
|
474
|
-
|
610
|
+
def append_default
|
611
|
+
if template =~ /([\t ]+)\Z/
|
612
|
+
template << "|#{default}|#{Regexp.last_match(1)}"
|
613
|
+
elsif template == ""
|
614
|
+
template << "|#{default}| "
|
615
|
+
elsif template[-1, 1] == "\n"
|
616
|
+
template[-2, 0] = " |#{default}|"
|
617
|
+
else
|
618
|
+
template << " |#{default}|"
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
def choice_error_str(message_source)
|
623
|
+
if message_source.is_a? Array
|
624
|
+
"[" + message_source.join(", ") + "]"
|
475
625
|
else
|
476
|
-
|
626
|
+
message_source.inspect
|
477
627
|
end
|
478
628
|
end
|
479
629
|
end
|