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.

Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +15 -0
  3. data/README.md +6 -6
  4. data/bundle/load.rb +3 -3
  5. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/AUTHORS +0 -0
  6. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/COPYING +0 -0
  7. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/Changelog.md +211 -15
  8. data/bundle/ruby/2.5.0/gems/highline-2.0.2/Gemfile +22 -0
  9. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/LICENSE +0 -0
  10. data/bundle/ruby/2.5.0/gems/highline-2.0.2/README.md +202 -0
  11. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/TODO +0 -0
  12. data/bundle/ruby/2.5.0/gems/highline-2.0.2/appveyor.yml +37 -0
  13. data/bundle/ruby/2.5.0/gems/highline-2.0.2/highline.gemspec +35 -0
  14. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline.rb +650 -0
  15. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/builtin_styles.rb +129 -0
  16. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/lib/highline/color_scheme.rb +49 -32
  17. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/compatibility.rb +23 -0
  18. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/custom_errors.rb +57 -0
  19. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/import.rb +48 -0
  20. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/io_console_compatible.rb +37 -0
  21. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/list.rb +177 -0
  22. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/list_renderer.rb +261 -0
  23. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/menu.rb +576 -0
  24. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/menu/item.rb +32 -0
  25. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/paginator.rb +52 -0
  26. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/lib/highline/question.rb +281 -131
  27. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/question/answer_converter.rb +103 -0
  28. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/question_asker.rb +150 -0
  29. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/simulate.rb +59 -0
  30. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/statement.rb +88 -0
  31. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/string.rb +36 -0
  32. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/string_extensions.rb +130 -0
  33. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/style.rb +325 -0
  34. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/template_renderer.rb +62 -0
  35. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal.rb +190 -0
  36. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal/io_console.rb +36 -0
  37. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal/ncurses.rb +38 -0
  38. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/terminal/unix_stty.rb +51 -0
  39. data/bundle/ruby/2.5.0/gems/{highline-1.7.10 → highline-2.0.2}/lib/highline/version.rb +3 -1
  40. data/bundle/ruby/2.5.0/gems/highline-2.0.2/lib/highline/wrapper.rb +53 -0
  41. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/History.rdoc +32 -0
  42. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/Manifest.txt +0 -0
  43. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/README.rdoc +0 -0
  44. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/compare/normalize.rb +0 -0
  45. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/debugging.md +0 -0
  46. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/rp_extensions.rb +1 -1
  47. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/rp_stringscanner.rb +0 -0
  48. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby20_parser.rb +2427 -2432
  49. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby20_parser.y +32 -29
  50. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby21_parser.rb +2101 -2109
  51. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby21_parser.y +32 -29
  52. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby22_parser.rb +2080 -2095
  53. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby22_parser.y +32 -29
  54. 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
  55. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby23_parser.y +32 -29
  56. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby24_parser.rb +2347 -2335
  57. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby24_parser.y +32 -23
  58. 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
  59. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby25_parser.y +32 -23
  60. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby26_parser.rb +2351 -2338
  61. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby26_parser.y +32 -23
  62. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_lexer.rb +253 -161
  63. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_lexer.rex +25 -25
  64. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_lexer.rex.rb +68 -26
  65. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_parser.rb +3 -1
  66. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_parser.yy +34 -23
  67. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/lib/ruby_parser_extras.rb +64 -43
  68. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/tools/munge.rb +2 -1
  69. data/bundle/ruby/2.5.0/gems/{ruby_parser-3.13.0 → ruby_parser-3.13.1}/tools/ripper.rb +6 -1
  70. data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/CHANGELOG.md +4 -0
  71. data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/MIT-LICENSE.txt +0 -0
  72. data/bundle/ruby/2.5.0/gems/{unicode-display_width-1.5.0 → unicode-display_width-1.6.0}/README.md +1 -1
  73. 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
  74. 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
  75. 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
  76. 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
  77. 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
  78. 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
  79. data/lib/brakeman.rb +7 -0
  80. data/lib/brakeman/app_tree.rb +34 -22
  81. data/lib/brakeman/checks.rb +7 -7
  82. data/lib/brakeman/checks/base_check.rb +9 -9
  83. data/lib/brakeman/checks/check_cross_site_scripting.rb +5 -0
  84. data/lib/brakeman/checks/check_default_routes.rb +5 -0
  85. data/lib/brakeman/checks/check_deserialize.rb +52 -0
  86. data/lib/brakeman/checks/check_dynamic_finders.rb +1 -1
  87. data/lib/brakeman/checks/check_force_ssl.rb +27 -0
  88. data/lib/brakeman/checks/check_json_parsing.rb +5 -0
  89. data/lib/brakeman/checks/check_link_to_href.rb +6 -1
  90. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  91. data/lib/brakeman/checks/check_model_attr_accessible.rb +1 -1
  92. data/lib/brakeman/checks/check_model_attributes.rb +12 -50
  93. data/lib/brakeman/checks/check_model_serialize.rb +1 -1
  94. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +3 -3
  95. data/lib/brakeman/checks/check_secrets.rb +1 -1
  96. data/lib/brakeman/checks/check_session_settings.rb +10 -10
  97. data/lib/brakeman/checks/check_simple_format.rb +5 -0
  98. data/lib/brakeman/checks/check_skip_before_filter.rb +1 -1
  99. data/lib/brakeman/checks/check_sql.rb +15 -17
  100. data/lib/brakeman/checks/check_validation_regex.rb +1 -1
  101. data/lib/brakeman/file_parser.rb +6 -8
  102. data/lib/brakeman/file_path.rb +71 -0
  103. data/lib/brakeman/options.rb +7 -0
  104. data/lib/brakeman/parsers/template_parser.rb +3 -3
  105. data/lib/brakeman/processor.rb +3 -4
  106. data/lib/brakeman/processors/alias_processor.rb +12 -6
  107. data/lib/brakeman/processors/base_processor.rb +8 -7
  108. data/lib/brakeman/processors/controller_alias_processor.rb +10 -7
  109. data/lib/brakeman/processors/controller_processor.rb +5 -9
  110. data/lib/brakeman/processors/haml_template_processor.rb +5 -0
  111. data/lib/brakeman/processors/lib/module_helper.rb +8 -8
  112. data/lib/brakeman/processors/lib/processor_helper.rb +3 -3
  113. data/lib/brakeman/processors/lib/rails2_config_processor.rb +3 -3
  114. data/lib/brakeman/processors/lib/rails2_route_processor.rb +2 -2
  115. data/lib/brakeman/processors/lib/rails3_config_processor.rb +3 -3
  116. data/lib/brakeman/processors/lib/rails3_route_processor.rb +2 -2
  117. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  118. data/lib/brakeman/processors/lib/render_path.rb +18 -1
  119. data/lib/brakeman/processors/library_processor.rb +5 -5
  120. data/lib/brakeman/processors/model_processor.rb +4 -5
  121. data/lib/brakeman/processors/output_processor.rb +5 -0
  122. data/lib/brakeman/processors/template_alias_processor.rb +4 -5
  123. data/lib/brakeman/processors/template_processor.rb +4 -4
  124. data/lib/brakeman/report.rb +3 -3
  125. data/lib/brakeman/report/ignore/config.rb +2 -3
  126. data/lib/brakeman/report/ignore/interactive.rb +2 -2
  127. data/lib/brakeman/report/pager.rb +1 -0
  128. data/lib/brakeman/report/report_base.rb +51 -6
  129. data/lib/brakeman/report/report_codeclimate.rb +3 -3
  130. data/lib/brakeman/report/report_hash.rb +1 -1
  131. data/lib/brakeman/report/report_html.rb +2 -2
  132. data/lib/brakeman/report/report_json.rb +1 -24
  133. data/lib/brakeman/report/report_table.rb +20 -4
  134. data/lib/brakeman/report/report_tabs.rb +1 -1
  135. data/lib/brakeman/report/report_text.rb +2 -2
  136. data/lib/brakeman/rescanner.rb +9 -12
  137. data/lib/brakeman/scanner.rb +19 -14
  138. data/lib/brakeman/tracker.rb +4 -4
  139. data/lib/brakeman/tracker/collection.rb +4 -3
  140. data/lib/brakeman/tracker/config.rb +6 -0
  141. data/lib/brakeman/util.rb +1 -147
  142. data/lib/brakeman/version.rb +1 -1
  143. data/lib/brakeman/warning.rb +23 -13
  144. data/lib/brakeman/warning_codes.rb +1 -0
  145. data/lib/ruby_parser/bm_sexp_processor.rb +1 -0
  146. metadata +78 -61
  147. data/bundle/ruby/2.5.0/gems/highline-1.7.10/Gemfile +0 -11
  148. data/bundle/ruby/2.5.0/gems/highline-1.7.10/INSTALL +0 -59
  149. data/bundle/ruby/2.5.0/gems/highline-1.7.10/README.rdoc +0 -74
  150. data/bundle/ruby/2.5.0/gems/highline-1.7.10/highline.gemspec +0 -37
  151. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline.rb +0 -1048
  152. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/compatibility.rb +0 -16
  153. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/import.rb +0 -41
  154. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/menu.rb +0 -381
  155. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/simulate.rb +0 -48
  156. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/string_extensions.rb +0 -111
  157. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/style.rb +0 -192
  158. data/bundle/ruby/2.5.0/gems/highline-1.7.10/lib/highline/system_extensions.rb +0 -254
  159. data/bundle/ruby/2.5.0/gems/highline-1.7.10/setup.rb +0 -1360
@@ -1,37 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'highline/version'
5
-
6
- GEM_VERSION = HighLine::VERSION
7
-
8
- SPEC = Gem::Specification.new do |spec|
9
- spec.name = "highline"
10
- spec.version = GEM_VERSION
11
- spec.platform = Gem::Platform::RUBY
12
- spec.summary = "HighLine is a high-level command-line IO library."
13
- spec.files = `git ls-files`.split("\n")
14
-
15
- spec.test_files = `git ls-files -- test/*.rb`.split("\n")
16
- spec.has_rdoc = true
17
- spec.extra_rdoc_files = %w[README.rdoc INSTALL TODO Changelog.md LICENSE]
18
- spec.rdoc_options << '--title' << 'HighLine Documentation' <<
19
- '--main' << 'README'
20
-
21
- spec.require_path = 'lib'
22
-
23
- spec.author = "James Edward Gray II"
24
- spec.email = "james@graysoftinc.com"
25
- spec.rubyforge_project = "highline"
26
- spec.homepage = "https://github.com/JEG2/highline"
27
- spec.license = "Ruby"
28
- spec.description = <<END_DESC
29
- A high-level IO library that provides validation, type conversion, and more for
30
- command-line interfaces. HighLine also includes a complete menu system that can
31
- crank out anything from simple list selection to complete shells with just
32
- minutes of work.
33
- END_DESC
34
-
35
- spec.add_development_dependency "code_statistics"
36
- spec.required_ruby_version = '>= 1.9.3'
37
- end
@@ -1,1048 +0,0 @@
1
- # coding: utf-8
2
- # highline.rb
3
- #
4
- # Created by James Edward Gray II on 2005-04-26.
5
- # Copyright 2005 Gray Productions. All rights reserved.
6
- #
7
- # See HighLine for documentation.
8
- #
9
- # This is Free Software. See LICENSE and COPYING for details.
10
-
11
- require "erb"
12
- require "optparse"
13
- require "stringio"
14
- require "abbrev"
15
- require "highline/system_extensions"
16
- require "highline/question"
17
- require "highline/menu"
18
- require "highline/color_scheme"
19
- require "highline/style"
20
- require "highline/version"
21
-
22
- #
23
- # A HighLine object is a "high-level line oriented" shell over an input and an
24
- # output stream. HighLine simplifies common console interaction, effectively
25
- # replacing puts() and gets(). User code can simply specify the question to ask
26
- # and any details about user interaction, then leave the rest of the work to
27
- # HighLine. When HighLine.ask() returns, you'll have the answer you requested,
28
- # even if HighLine had to ask many times, validate results, perform range
29
- # checking, convert types, etc.
30
- #
31
- class HighLine
32
- # An internal HighLine error. User code does not need to trap this.
33
- class QuestionError < StandardError
34
- # do nothing, just creating a unique error type
35
- end
36
-
37
- # The setting used to disable color output.
38
- @@use_color = true
39
-
40
- # Pass +false+ to _setting_ to turn off HighLine's color escapes.
41
- def self.use_color=( setting )
42
- @@use_color = setting
43
- end
44
-
45
- # Returns true if HighLine is currently using color escapes.
46
- def self.use_color?
47
- @@use_color
48
- end
49
-
50
- # For checking if the current version of HighLine supports RGB colors
51
- # Usage: HighLine.supports_rgb_color? rescue false # rescue for compatibility with older versions
52
- # Note: color usage also depends on HighLine.use_color being set
53
- def self.supports_rgb_color?
54
- true
55
- end
56
-
57
- # The setting used to disable EOF tracking.
58
- @@track_eof = true
59
-
60
- # Pass +false+ to _setting_ to turn off HighLine's EOF tracking.
61
- def self.track_eof=( setting )
62
- @@track_eof = setting
63
- end
64
-
65
- # Returns true if HighLine is currently tracking EOF for input.
66
- def self.track_eof?
67
- @@track_eof
68
- end
69
-
70
- # The setting used to control color schemes.
71
- @@color_scheme = nil
72
-
73
- # Pass ColorScheme to _setting_ to set a HighLine color scheme.
74
- def self.color_scheme=( setting )
75
- @@color_scheme = setting
76
- end
77
-
78
- # Returns the current color scheme.
79
- def self.color_scheme
80
- @@color_scheme
81
- end
82
-
83
- # Returns +true+ if HighLine is currently using a color scheme.
84
- def self.using_color_scheme?
85
- not @@color_scheme.nil?
86
- end
87
-
88
- #
89
- # Embed in a String to clear all previous ANSI sequences. This *MUST* be
90
- # done before the program exits!
91
- #
92
-
93
- ERASE_LINE_STYLE = Style.new(:name=>:erase_line, :builtin=>true, :code=>"\e[K") # Erase the current line of terminal output
94
- ERASE_CHAR_STYLE = Style.new(:name=>:erase_char, :builtin=>true, :code=>"\e[P") # Erase the character under the cursor.
95
- CLEAR_STYLE = Style.new(:name=>:clear, :builtin=>true, :code=>"\e[0m") # Clear color settings
96
- RESET_STYLE = Style.new(:name=>:reset, :builtin=>true, :code=>"\e[0m") # Alias for CLEAR.
97
- BOLD_STYLE = Style.new(:name=>:bold, :builtin=>true, :code=>"\e[1m") # Bold; Note: bold + a color works as you'd expect,
98
- # for example bold black. Bold without a color displays
99
- # the system-defined bold color (e.g. red on Mac iTerm)
100
- DARK_STYLE = Style.new(:name=>:dark, :builtin=>true, :code=>"\e[2m") # Dark; support uncommon
101
- UNDERLINE_STYLE = Style.new(:name=>:underline, :builtin=>true, :code=>"\e[4m") # Underline
102
- UNDERSCORE_STYLE = Style.new(:name=>:underscore, :builtin=>true, :code=>"\e[4m") # Alias for UNDERLINE
103
- BLINK_STYLE = Style.new(:name=>:blink, :builtin=>true, :code=>"\e[5m") # Blink; support uncommon
104
- REVERSE_STYLE = Style.new(:name=>:reverse, :builtin=>true, :code=>"\e[7m") # Reverse foreground and background
105
- CONCEALED_STYLE = Style.new(:name=>:concealed, :builtin=>true, :code=>"\e[8m") # Concealed; support uncommon
106
-
107
- STYLES = %w{CLEAR RESET BOLD DARK UNDERLINE UNDERSCORE BLINK REVERSE CONCEALED}
108
-
109
- # These RGB colors are approximate; see http://en.wikipedia.org/wiki/ANSI_escape_code
110
- BLACK_STYLE = Style.new(:name=>:black, :builtin=>true, :code=>"\e[30m", :rgb=>[ 0, 0, 0])
111
- RED_STYLE = Style.new(:name=>:red, :builtin=>true, :code=>"\e[31m", :rgb=>[128, 0, 0])
112
- GREEN_STYLE = Style.new(:name=>:green, :builtin=>true, :code=>"\e[32m", :rgb=>[ 0,128, 0])
113
- BLUE_STYLE = Style.new(:name=>:blue, :builtin=>true, :code=>"\e[34m", :rgb=>[ 0, 0,128])
114
- YELLOW_STYLE = Style.new(:name=>:yellow, :builtin=>true, :code=>"\e[33m", :rgb=>[128,128, 0])
115
- MAGENTA_STYLE = Style.new(:name=>:magenta, :builtin=>true, :code=>"\e[35m", :rgb=>[128, 0,128])
116
- CYAN_STYLE = Style.new(:name=>:cyan, :builtin=>true, :code=>"\e[36m", :rgb=>[ 0,128,128])
117
- # On Mac OSX Terminal, white is actually gray
118
- WHITE_STYLE = Style.new(:name=>:white, :builtin=>true, :code=>"\e[37m", :rgb=>[192,192,192])
119
- # Alias for WHITE, since WHITE is actually a light gray on Macs
120
- GRAY_STYLE = Style.new(:name=>:gray, :builtin=>true, :code=>"\e[37m", :rgb=>[192,192,192])
121
- GREY_STYLE = Style.new(:name=>:grey, :builtin=>true, :code=>"\e[37m", :rgb=>[192,192,192])
122
- # On Mac OSX Terminal, this is black foreground, or bright white background.
123
- # Also used as base for RGB colors, if available
124
- NONE_STYLE = Style.new(:name=>:none, :builtin=>true, :code=>"\e[38m", :rgb=>[ 0, 0, 0])
125
-
126
- BASIC_COLORS = %w{BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE GRAY GREY NONE}
127
-
128
- colors = BASIC_COLORS.dup
129
- BASIC_COLORS.each do |color|
130
- bright_color = "BRIGHT_#{color}"
131
- colors << bright_color
132
- const_set bright_color+'_STYLE', const_get(color + '_STYLE').bright
133
-
134
- light_color = "LIGHT_#{color}"
135
- colors << light_color
136
- const_set light_color+'_STYLE', const_get(color + '_STYLE').light
137
- end
138
- COLORS = colors
139
-
140
- colors.each do |color|
141
- const_set color, const_get("#{color}_STYLE").code
142
- const_set "ON_#{color}_STYLE", const_get("#{color}_STYLE").on
143
- const_set "ON_#{color}", const_get("ON_#{color}_STYLE").code
144
- end
145
- ON_NONE_STYLE.rgb = [255,255,255] # Override; white background
146
-
147
- STYLES.each do |style|
148
- const_set style, const_get("#{style}_STYLE").code
149
- end
150
-
151
- # For RGB colors:
152
- def self.const_missing(name)
153
- if name.to_s =~ /^(ON_)?(RGB_)([A-F0-9]{6})(_STYLE)?$/ # RGB color
154
- on = $1
155
- suffix = $4
156
- if suffix
157
- code_name = $1.to_s + $2 + $3
158
- else
159
- code_name = name.to_s
160
- end
161
- style_name = code_name + '_STYLE'
162
- style = Style.rgb($3)
163
- style = style.on if on
164
- const_set(style_name, style)
165
- const_set(code_name, style.code)
166
- if suffix
167
- style
168
- else
169
- style.code
170
- end
171
- else
172
- raise NameError, "Bad color or uninitialized constant #{name}"
173
- end
174
- end
175
-
176
- #
177
- # Create an instance of HighLine, connected to the streams _input_
178
- # and _output_.
179
- #
180
- def initialize( input = $stdin, output = $stdout,
181
- wrap_at = nil, page_at = nil, indent_size=3, indent_level=0 )
182
- @input = input
183
- @output = output
184
-
185
- @multi_indent = true
186
- @indent_size = indent_size
187
- @indent_level = indent_level
188
-
189
- self.wrap_at = wrap_at
190
- self.page_at = page_at
191
-
192
- @question = nil
193
- @answer = nil
194
- @menu = nil
195
- @header = nil
196
- @prompt = nil
197
- @gather = nil
198
- @answers = nil
199
- @key = nil
200
-
201
- initialize_system_extensions if respond_to?(:initialize_system_extensions)
202
- end
203
-
204
- include HighLine::SystemExtensions
205
-
206
- # The current column setting for wrapping output.
207
- attr_reader :wrap_at
208
- # The current row setting for paging output.
209
- attr_reader :page_at
210
- # Indentation over multiple lines
211
- attr_accessor :multi_indent
212
- # The indentation size
213
- attr_accessor :indent_size
214
- # The indentation level
215
- attr_accessor :indent_level
216
-
217
- #
218
- # A shortcut to HighLine.ask() a question that only accepts "yes" or "no"
219
- # answers ("y" and "n" are allowed) and returns +true+ or +false+
220
- # (+true+ for "yes"). If provided a +true+ value, _character_ will cause
221
- # HighLine to fetch a single character response. A block can be provided
222
- # to further configure the question as in HighLine.ask()
223
- #
224
- # Raises EOFError if input is exhausted.
225
- #
226
- def agree( yes_or_no_question, character = nil )
227
- ask(yes_or_no_question, lambda { |yn| yn.downcase[0] == ?y}) do |q|
228
- q.validate = /\Ay(?:es)?|no?\Z/i
229
- q.responses[:not_valid] = 'Please enter "yes" or "no".'
230
- q.responses[:ask_on_error] = :question
231
- q.character = character
232
-
233
- yield q if block_given?
234
- end
235
- end
236
-
237
- #
238
- # This method is the primary interface for user input. Just provide a
239
- # _question_ to ask the user, the _answer_type_ you want returned, and
240
- # optionally a code block setting up details of how you want the question
241
- # handled. See HighLine.say() for details on the format of _question_, and
242
- # HighLine::Question for more information about _answer_type_ and what's
243
- # valid in the code block.
244
- #
245
- # If <tt>@question</tt> is set before ask() is called, parameters are
246
- # ignored and that object (must be a HighLine::Question) is used to drive
247
- # the process instead.
248
- #
249
- # Raises EOFError if input is exhausted.
250
- #
251
- def ask( question, answer_type = nil, &details ) # :yields: question
252
- @question ||= Question.new(question, answer_type, &details)
253
-
254
- return gather if @question.gather
255
-
256
- # readline() needs to handle its own output, but readline only supports
257
- # full line reading. Therefore if @question.echo is anything but true,
258
- # the prompt will not be issued. And we have to account for that now.
259
- # Also, JRuby-1.7's ConsoleReader.readLine() needs to be passed the prompt
260
- # to handle line editing properly.
261
- say(@question) unless ((JRUBY or @question.readline) and (@question.echo == true and @question.limit.nil?))
262
-
263
- begin
264
- @answer = @question.answer_or_default(get_response)
265
- unless @question.valid_answer?(@answer)
266
- explain_error(:not_valid)
267
- raise QuestionError
268
- end
269
-
270
- @answer = @question.convert(@answer)
271
-
272
- if @question.in_range?(@answer)
273
- if @question.confirm
274
- # need to add a layer of scope to ask a question inside a
275
- # question, without destroying instance data
276
- context_change = self.class.new(@input, @output, @wrap_at, @page_at, @indent_size, @indent_level)
277
- if @question.confirm == true
278
- confirm_question = "Are you sure? "
279
- else
280
- # evaluate ERb under initial scope, so it will have
281
- # access to @question and @answer
282
- template = ERB.new(@question.confirm, nil, "%")
283
- confirm_question = template.result(binding)
284
- end
285
- unless context_change.agree(confirm_question)
286
- explain_error(nil)
287
- raise QuestionError
288
- end
289
- end
290
-
291
- @answer
292
- else
293
- explain_error(:not_in_range)
294
- raise QuestionError
295
- end
296
- rescue QuestionError
297
- retry
298
- rescue ArgumentError, NameError => error
299
- raise if error.is_a?(NoMethodError)
300
- if error.message =~ /ambiguous/
301
- # the assumption here is that OptionParser::Completion#complete
302
- # (used for ambiguity resolution) throws exceptions containing
303
- # the word 'ambiguous' whenever resolution fails
304
- explain_error(:ambiguous_completion)
305
- else
306
- explain_error(:invalid_type)
307
- end
308
- retry
309
- rescue Question::NoAutoCompleteMatch
310
- explain_error(:no_completion)
311
- retry
312
- ensure
313
- @question = nil # Reset Question object.
314
- end
315
- end
316
-
317
- #
318
- # This method is HighLine's menu handler. For simple usage, you can just
319
- # pass all the menu items you wish to display. At that point, choose() will
320
- # build and display a menu, walk the user through selection, and return
321
- # their choice among the provided items. You might use this in a case
322
- # statement for quick and dirty menus.
323
- #
324
- # However, choose() is capable of much more. If provided, a block will be
325
- # passed a HighLine::Menu object to configure. Using this method, you can
326
- # customize all the details of menu handling from index display, to building
327
- # a complete shell-like menuing system. See HighLine::Menu for all the
328
- # methods it responds to.
329
- #
330
- # Raises EOFError if input is exhausted.
331
- #
332
- def choose( *items, &details )
333
- @menu = @question = Menu.new(&details)
334
- @menu.choices(*items) unless items.empty?
335
-
336
- # Set auto-completion
337
- @menu.completion = @menu.options
338
- # Set _answer_type_ so we can double as the Question for ask().
339
- @menu.answer_type = if @menu.shell
340
- lambda do |command| # shell-style selection
341
- first_word = command.to_s.split.first || ""
342
-
343
- options = @menu.options
344
- options.extend(OptionParser::Completion)
345
- answer = options.complete(first_word)
346
-
347
- if answer.nil?
348
- raise Question::NoAutoCompleteMatch
349
- end
350
-
351
- [answer.last, command.sub(/^\s*#{first_word}\s*/, "")]
352
- end
353
- else
354
- @menu.options # normal menu selection, by index or name
355
- end
356
-
357
- # Provide hooks for ERb layouts.
358
- @header = @menu.header
359
- @prompt = @menu.prompt
360
-
361
- if @menu.shell
362
- selected = ask("Ignored", @menu.answer_type)
363
- @menu.select(self, *selected)
364
- else
365
- selected = ask("Ignored", @menu.answer_type)
366
- @menu.select(self, selected)
367
- end
368
- end
369
-
370
- #
371
- # This method provides easy access to ANSI color sequences, without the user
372
- # needing to remember to CLEAR at the end of each sequence. Just pass the
373
- # _string_ to color, followed by a list of _colors_ you would like it to be
374
- # affected by. The _colors_ can be HighLine class constants, or symbols
375
- # (:blue for BLUE, for example). A CLEAR will automatically be embedded to
376
- # the end of the returned String.
377
- #
378
- # This method returns the original _string_ unchanged if HighLine::use_color?
379
- # is +false+.
380
- #
381
- def self.color( string, *colors )
382
- return string unless self.use_color?
383
- Style(*colors).color(string)
384
- end
385
-
386
- # In case you just want the color code, without the embedding and the CLEAR
387
- def self.color_code(*colors)
388
- Style(*colors).code
389
- end
390
-
391
- # Works as an instance method, same as the class method
392
- def color_code(*colors)
393
- self.class.color_code(*colors)
394
- end
395
-
396
- # Works as an instance method, same as the class method
397
- def color(*args)
398
- self.class.color(*args)
399
- end
400
-
401
- # Remove color codes from a string
402
- def self.uncolor(string)
403
- Style.uncolor(string)
404
- end
405
-
406
- # Works as an instance method, same as the class method
407
- def uncolor(string)
408
- self.class.uncolor(string)
409
- end
410
-
411
- #
412
- # This method is a utility for quickly and easily laying out lists. It can
413
- # be accessed within ERb replacements of any text that will be sent to the
414
- # user.
415
- #
416
- # The only required parameter is _items_, which should be the Array of items
417
- # to list. A specified _mode_ controls how that list is formed and _option_
418
- # has different effects, depending on the _mode_. Recognized modes are:
419
- #
420
- # <tt>:columns_across</tt>:: _items_ will be placed in columns,
421
- # flowing from left to right. If given,
422
- # _option_ is the number of columns to be
423
- # used. When absent, columns will be
424
- # determined based on _wrap_at_ or a
425
- # default of 80 characters.
426
- # <tt>:columns_down</tt>:: Identical to <tt>:columns_across</tt>,
427
- # save flow goes down.
428
- # <tt>:uneven_columns_across</tt>:: Like <tt>:columns_across</tt> but each
429
- # column is sized independently.
430
- # <tt>:uneven_columns_down</tt>:: Like <tt>:columns_down</tt> but each
431
- # column is sized independently.
432
- # <tt>:inline</tt>:: All _items_ are placed on a single line.
433
- # The last two _items_ are separated by
434
- # _option_ or a default of " or ". All
435
- # other _items_ are separated by ", ".
436
- # <tt>:rows</tt>:: The default mode. Each of the _items_ is
437
- # placed on its own line. The _option_
438
- # parameter is ignored in this mode.
439
- #
440
- # Each member of the _items_ Array is passed through ERb and thus can contain
441
- # their own expansions. Color escape expansions do not contribute to the
442
- # final field width.
443
- #
444
- def list( items, mode = :rows, option = nil )
445
- items = items.to_ary.map do |item|
446
- if item.nil?
447
- ""
448
- else
449
- ERB.new(item, nil, "%").result(binding)
450
- end
451
- end
452
-
453
- if items.empty?
454
- ""
455
- else
456
- case mode
457
- when :inline
458
- option = " or " if option.nil?
459
-
460
- if items.size == 1
461
- items.first
462
- else
463
- items[0..-2].join(", ") + "#{option}#{items.last}"
464
- end
465
- when :columns_across, :columns_down
466
- max_length = actual_length(
467
- items.max { |a, b| actual_length(a) <=> actual_length(b) }
468
- )
469
-
470
- if option.nil?
471
- limit = @wrap_at || 80
472
- option = (limit + 2) / (max_length + 2)
473
- end
474
-
475
- items = items.map do |item|
476
- pad = max_length + (item.to_s.length - actual_length(item))
477
- "%-#{pad}s" % item
478
- end
479
- row_count = (items.size / option.to_f).ceil
480
-
481
- if mode == :columns_across
482
- rows = Array.new(row_count) { Array.new }
483
- items.each_with_index do |item, index|
484
- rows[index / option] << item
485
- end
486
-
487
- rows.map { |row| row.join(" ") + "\n" }.join
488
- else
489
- columns = Array.new(option) { Array.new }
490
- items.each_with_index do |item, index|
491
- columns[index / row_count] << item
492
- end
493
-
494
- list = ""
495
- columns.first.size.times do |index|
496
- list << columns.map { |column| column[index] }.
497
- compact.join(" ") + "\n"
498
- end
499
- list
500
- end
501
- when :uneven_columns_across
502
- if option.nil?
503
- limit = @wrap_at || 80
504
- items.size.downto(1) do |column_count|
505
- row_count = (items.size / column_count.to_f).ceil
506
- rows = Array.new(row_count) { Array.new }
507
- items.each_with_index do |item, index|
508
- rows[index / column_count] << item
509
- end
510
-
511
- widths = Array.new(column_count, 0)
512
- rows.each do |row|
513
- row.each_with_index do |field, column|
514
- size = actual_length(field)
515
- widths[column] = size if size > widths[column]
516
- end
517
- end
518
-
519
- if column_count == 1 or
520
- widths.inject(0) { |sum, n| sum + n + 2 } <= limit + 2
521
- return rows.map { |row|
522
- row.zip(widths).map { |field, i|
523
- "%-#{i + (field.to_s.length - actual_length(field))}s" % field
524
- }.join(" ") + "\n"
525
- }.join
526
- end
527
- end
528
- else
529
- row_count = (items.size / option.to_f).ceil
530
- rows = Array.new(row_count) { Array.new }
531
- items.each_with_index do |item, index|
532
- rows[index / option] << item
533
- end
534
-
535
- widths = Array.new(option, 0)
536
- rows.each do |row|
537
- row.each_with_index do |field, column|
538
- size = actual_length(field)
539
- widths[column] = size if size > widths[column]
540
- end
541
- end
542
-
543
- return rows.map { |row|
544
- row.zip(widths).map { |field, i|
545
- "%-#{i + (field.to_s.length - actual_length(field))}s" % field
546
- }.join(" ") + "\n"
547
- }.join
548
- end
549
- when :uneven_columns_down
550
- if option.nil?
551
- limit = @wrap_at || 80
552
- items.size.downto(1) do |column_count|
553
- row_count = (items.size / column_count.to_f).ceil
554
- columns = Array.new(column_count) { Array.new }
555
- items.each_with_index do |item, index|
556
- columns[index / row_count] << item
557
- end
558
-
559
- widths = Array.new(column_count, 0)
560
- columns.each_with_index do |column, i|
561
- column.each do |field|
562
- size = actual_length(field)
563
- widths[i] = size if size > widths[i]
564
- end
565
- end
566
-
567
- if column_count == 1 or
568
- widths.inject(0) { |sum, n| sum + n + 2 } <= limit + 2
569
- list = ""
570
- columns.first.size.times do |index|
571
- list << columns.zip(widths).map { |column, width|
572
- field = column[index]
573
- "%-#{width + (field.to_s.length - actual_length(field))}s" %
574
- field
575
- }.compact.join(" ").strip + "\n"
576
- end
577
- return list
578
- end
579
- end
580
- else
581
- row_count = (items.size / option.to_f).ceil
582
- columns = Array.new(option) { Array.new }
583
- items.each_with_index do |item, index|
584
- columns[index / row_count] << item
585
- end
586
-
587
- widths = Array.new(option, 0)
588
- columns.each_with_index do |column, i|
589
- column.each do |field|
590
- size = actual_length(field)
591
- widths[i] = size if size > widths[i]
592
- end
593
- end
594
-
595
- list = ""
596
- columns.first.size.times do |index|
597
- list << columns.zip(widths).map { |column, width|
598
- field = column[index]
599
- "%-#{width + (field.to_s.length - actual_length(field))}s" % field
600
- }.compact.join(" ").strip + "\n"
601
- end
602
- return list
603
- end
604
- else
605
- items.map { |i| "#{i}\n" }.join
606
- end
607
- end
608
- end
609
-
610
- #
611
- # The basic output method for HighLine objects. If the provided _statement_
612
- # ends with a space or tab character, a newline will not be appended (output
613
- # will be flush()ed). All other cases are passed straight to Kernel.puts().
614
- #
615
- # The _statement_ parameter is processed as an ERb template, supporting
616
- # embedded Ruby code. The template is evaluated with a binding inside
617
- # the HighLine instance, providing easy access to the ANSI color constants
618
- # and the HighLine.color() method.
619
- #
620
- def say( statement )
621
- statement = format_statement(statement)
622
- return unless statement.length > 0
623
-
624
- out = (indentation+statement).encode(Encoding.default_external, { :undef => :replace } )
625
-
626
- # Don't add a newline if statement ends with whitespace, OR
627
- # if statement ends with whitespace before a color escape code.
628
- if /[ \t](\e\[\d+(;\d+)*m)?\Z/ =~ statement
629
- @output.print(out)
630
- @output.flush
631
- else
632
- @output.puts(out)
633
- end
634
- end
635
-
636
- #
637
- # Set to an integer value to cause HighLine to wrap output lines at the
638
- # indicated character limit. When +nil+, the default, no wrapping occurs. If
639
- # set to <tt>:auto</tt>, HighLine will attempt to determine the columns
640
- # available for the <tt>@output</tt> or use a sensible default.
641
- #
642
- def wrap_at=( setting )
643
- @wrap_at = setting == :auto ? output_cols : setting
644
- end
645
-
646
- #
647
- # Set to an integer value to cause HighLine to page output lines over the
648
- # indicated line limit. When +nil+, the default, no paging occurs. If
649
- # set to <tt>:auto</tt>, HighLine will attempt to determine the rows available
650
- # for the <tt>@output</tt> or use a sensible default.
651
- #
652
- def page_at=( setting )
653
- @page_at = setting == :auto ? output_rows - 2 : setting
654
- end
655
-
656
- #
657
- # Outputs indentation with current settings
658
- #
659
- def indentation
660
- return ' '*@indent_size*@indent_level
661
- end
662
-
663
- #
664
- # Executes block or outputs statement with indentation
665
- #
666
- def indent(increase=1, statement=nil, multiline=nil)
667
- @indent_level += increase
668
- multi = @multi_indent
669
- @multi_indent = multiline unless multiline.nil?
670
- begin
671
- if block_given?
672
- yield self
673
- else
674
- say(statement)
675
- end
676
- rescue
677
- @multi_indent = multi
678
- @indent_level -= increase
679
- raise
680
- end
681
- @multi_indent = multi
682
- @indent_level -= increase
683
- end
684
-
685
- #
686
- # Outputs newline
687
- #
688
- def newline
689
- @output.puts
690
- end
691
-
692
- #
693
- # Returns the number of columns for the console, or a default it they cannot
694
- # be determined.
695
- #
696
- def output_cols
697
- return 80 unless @output.tty?
698
- terminal_size.first
699
- rescue
700
- return 80
701
- end
702
-
703
- #
704
- # Returns the number of rows for the console, or a default if they cannot be
705
- # determined.
706
- #
707
- def output_rows
708
- return 24 unless @output.tty?
709
- terminal_size.last
710
- rescue
711
- return 24
712
- end
713
-
714
- private
715
-
716
- def format_statement statement
717
- statement = String(statement || "").dup
718
- return statement unless statement.length > 0
719
-
720
- template = ERB.new(statement, nil, "%")
721
- statement = template.result(binding)
722
-
723
- statement = wrap(statement) unless @wrap_at.nil?
724
- statement = page_print(statement) unless @page_at.nil?
725
-
726
- # 'statement' is encoded in US-ASCII when using ruby 1.9.3(-p551)
727
- # 'indentation' is correctly encoded (same as default_external encoding)
728
- statement = statement.force_encoding(Encoding.default_external)
729
-
730
- statement = statement.gsub(/\n(?!$)/,"\n#{indentation}") if @multi_indent
731
-
732
- statement
733
- end
734
-
735
- #
736
- # A helper method for sending the output stream and error and repeat
737
- # of the question.
738
- #
739
- def explain_error( error )
740
- say(@question.responses[error]) unless error.nil?
741
- if @question.responses[:ask_on_error] == :question
742
- say(@question)
743
- elsif @question.responses[:ask_on_error]
744
- say(@question.responses[:ask_on_error])
745
- end
746
- end
747
-
748
- #
749
- # Collects an Array/Hash full of answers as described in
750
- # HighLine::Question.gather().
751
- #
752
- # Raises EOFError if input is exhausted.
753
- #
754
- def gather( )
755
- original_question = @question
756
- original_question_string = @question.question
757
- original_gather = @question.gather
758
-
759
- verify_match = @question.verify_match
760
- @question.gather = false
761
-
762
- begin # when verify_match is set this loop will repeat until unique_answers == 1
763
- @answers = [ ]
764
- @gather = original_gather
765
- original_question.question = original_question_string
766
-
767
- case @gather
768
- when Integer
769
- @answers << ask(@question)
770
- @gather -= 1
771
-
772
- original_question.question = ""
773
- until @gather.zero?
774
- @question = original_question
775
- @answers << ask(@question)
776
- @gather -= 1
777
- end
778
- when ::String, Regexp
779
- @answers << ask(@question)
780
-
781
- original_question.question = ""
782
- until (@gather.is_a?(::String) and @answers.last.to_s == @gather) or
783
- (@gather.is_a?(Regexp) and @answers.last.to_s =~ @gather)
784
- @question = original_question
785
- @answers << ask(@question)
786
- end
787
-
788
- @answers.pop
789
- when Hash
790
- @answers = { }
791
- @gather.keys.sort.each do |key|
792
- @question = original_question
793
- @key = key
794
- @answers[key] = ask(@question)
795
- end
796
- end
797
-
798
- if verify_match && (unique_answers(@answers).size > 1)
799
- @question = original_question
800
- explain_error(:mismatch)
801
- else
802
- verify_match = false
803
- end
804
-
805
- end while verify_match
806
-
807
- original_question.verify_match ? @answer : @answers
808
- end
809
-
810
- #
811
- # A helper method used by HighLine::Question.verify_match
812
- # for finding whether a list of answers match or differ
813
- # from each other.
814
- #
815
- def unique_answers(list = @answers)
816
- (list.respond_to?(:values) ? list.values : list).uniq
817
- end
818
-
819
- #
820
- # Read a line of input from the input stream and process whitespace as
821
- # requested by the Question object.
822
- #
823
- # If Question's _readline_ property is set, that library will be used to
824
- # fetch input. *WARNING*: This ignores the currently set input stream.
825
- #
826
- # Raises EOFError if input is exhausted.
827
- #
828
- def get_line( )
829
- if @question.readline
830
- require "readline" # load only if needed
831
-
832
- # capture say()'s work in a String to feed to readline()
833
- old_output = @output
834
- @output = StringIO.new
835
- say(@question)
836
- question = @output.string
837
- @output = old_output
838
-
839
- # prep auto-completion
840
- Readline.completion_proc = lambda do |string|
841
- @question.selection.grep(/\A#{Regexp.escape(string)}/)
842
- end
843
-
844
- # work-around ugly readline() warnings
845
- old_verbose = $VERBOSE
846
- $VERBOSE = nil
847
- raw_answer = Readline.readline(question, true)
848
- if raw_answer.nil?
849
- if @@track_eof
850
- raise EOFError, "The input stream is exhausted."
851
- else
852
- raw_answer = String.new # Never return nil
853
- end
854
- end
855
- answer = @question.change_case(
856
- @question.remove_whitespace(raw_answer))
857
- $VERBOSE = old_verbose
858
-
859
- answer
860
- else
861
- if JRUBY
862
- statement = format_statement(@question)
863
- raw_answer = @java_console.readLine(statement, nil)
864
-
865
- raise EOFError, "The input stream is exhausted." if raw_answer.nil? and
866
- @@track_eof
867
- else
868
- raise EOFError, "The input stream is exhausted." if @@track_eof and
869
- @input.eof?
870
- raw_answer = @input.gets
871
- end
872
-
873
- @question.change_case(@question.remove_whitespace(raw_answer))
874
- end
875
- end
876
-
877
- #
878
- # Return a line or character of input, as requested for this question.
879
- # Character input will be returned as a single character String,
880
- # not an Integer.
881
- #
882
- # This question's _first_answer_ will be returned instead of input, if set.
883
- #
884
- # Raises EOFError if input is exhausted.
885
- #
886
- def get_response( )
887
- return @question.first_answer if @question.first_answer?
888
-
889
- if @question.character.nil?
890
- if @question.echo == true and @question.limit.nil?
891
- get_line
892
- else
893
- raw_no_echo_mode
894
-
895
- line = "".encode(Encoding::BINARY)
896
- backspace_limit = 0
897
- begin
898
-
899
- while character = get_character(@input)
900
- # honor backspace and delete
901
- if character == 127 or character == 8
902
- line = line.force_encoding(Encoding.default_external)
903
- line.slice!(-1, 1)
904
- backspace_limit -= 1
905
- line = line.force_encoding(Encoding::BINARY)
906
- else
907
- line << character.chr
908
- backspace_limit = line.dup.force_encoding(Encoding.default_external).size
909
- end
910
- # looking for carriage return (decimal 13) or
911
- # newline (decimal 10) in raw input
912
- break if character == 13 or character == 10
913
- if @question.echo != false
914
- if character == 127 or character == 8
915
- # only backspace if we have characters on the line to
916
- # eliminate, otherwise we'll tromp over the prompt
917
- if backspace_limit >= 0 then
918
- @output.print("\b#{HighLine.Style(:erase_char).code}")
919
- else
920
- # do nothing
921
- end
922
- else
923
- line_with_next_char_encoded = line.dup.force_encoding(Encoding.default_external)
924
- # For multi-byte character, does this
925
- # last character completes the character?
926
- # Then print it.
927
- if line_with_next_char_encoded.valid_encoding?
928
- if @question.echo == true
929
- @output.print(line_with_next_char_encoded[-1])
930
- else
931
- @output.print(@question.echo)
932
- end
933
- end
934
- end
935
- @output.flush
936
- end
937
- break if @question.limit and line.size == @question.limit
938
- end
939
- ensure
940
- restore_mode
941
- end
942
- if @question.overwrite
943
- @output.print("\r#{HighLine.Style(:erase_line).code}")
944
- @output.flush
945
- else
946
- say("\n")
947
- end
948
-
949
- @question.change_case(@question.remove_whitespace(line.force_encoding(Encoding.default_external)))
950
- end
951
- else
952
- if JRUBY #prompt has not been shown
953
- say @question
954
- end
955
-
956
- raw_no_echo_mode
957
- begin
958
- if @question.character == :getc
959
- response = @input.getbyte.chr
960
- else
961
- response = get_character(@input).chr
962
- if @question.overwrite
963
- @output.print("\r#{HighLine.Style(:erase_line).code}")
964
- @output.flush
965
- else
966
- echo = if @question.echo == true
967
- response
968
- elsif @question.echo != false
969
- @question.echo
970
- else
971
- ""
972
- end
973
- say("#{echo}\n")
974
- end
975
- end
976
- ensure
977
- restore_mode
978
- end
979
- @question.change_case(response)
980
- end
981
- end
982
-
983
- #
984
- # Page print a series of at most _page_at_ lines for _output_. After each
985
- # page is printed, HighLine will pause until the user presses enter/return
986
- # then display the next page of data.
987
- #
988
- # Note that the final page of _output_ is *not* printed, but returned
989
- # instead. This is to support any special handling for the final sequence.
990
- #
991
- def page_print( output )
992
- lines = output.lines.to_a
993
- while lines.size > @page_at
994
- @output.puts lines.slice!(0...@page_at).join
995
- @output.puts
996
- # Return last line if user wants to abort paging
997
- return "...\n#{lines.last}" unless continue_paging?
998
- end
999
- return lines.join
1000
- end
1001
-
1002
- #
1003
- # Ask user if they wish to continue paging output. Allows them to type "q" to
1004
- # cancel the paging process.
1005
- #
1006
- def continue_paging?
1007
- command = HighLine.new(@input, @output).ask(
1008
- "-- press enter/return to continue or q to stop -- "
1009
- ) { |q| q.character = true }
1010
- command !~ /\A[qQ]\Z/ # Only continue paging if Q was not hit.
1011
- end
1012
-
1013
- #
1014
- # Wrap a sequence of _lines_ at _wrap_at_ characters per line. Existing
1015
- # newlines will not be affected by this process, but additional newlines
1016
- # may be added.
1017
- #
1018
- def wrap( text )
1019
- wrapped = [ ]
1020
- text.each_line do |line|
1021
- # take into account color escape sequences when wrapping
1022
- wrap_at = @wrap_at + (line.length - actual_length(line))
1023
- while line =~ /([^\n]{#{wrap_at + 1},})/
1024
- search = $1.dup
1025
- replace = $1.dup
1026
- if index = replace.rindex(" ", wrap_at)
1027
- replace[index, 1] = "\n"
1028
- replace.sub!(/\n[ \t]+/, "\n")
1029
- line.sub!(search, replace)
1030
- else
1031
- line[$~.begin(1) + wrap_at, 0] = "\n"
1032
- end
1033
- end
1034
- wrapped << line
1035
- end
1036
- return wrapped.join
1037
- end
1038
-
1039
- #
1040
- # Returns the length of the passed +string_with_escapes+, minus and color
1041
- # sequence escapes.
1042
- #
1043
- def actual_length( string_with_escapes )
1044
- string_with_escapes.to_s.gsub(/\e\[\d{1,2}m/, "").length
1045
- end
1046
- end
1047
-
1048
- require "highline/string_extensions"