highline 1.7.10 → 2.0.0.pre.develop.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.simplecov +5 -0
  4. data/.travis.yml +11 -6
  5. data/Changelog.md +112 -20
  6. data/Gemfile +8 -7
  7. data/README.rdoc +3 -0
  8. data/Rakefile +7 -2
  9. data/appveyor.yml +19 -0
  10. data/examples/asking_for_arrays.rb +3 -0
  11. data/examples/basic_usage.rb +3 -0
  12. data/examples/get_character.rb +3 -0
  13. data/examples/limit.rb +3 -0
  14. data/examples/menus.rb +3 -0
  15. data/examples/overwrite.rb +3 -0
  16. data/examples/password.rb +3 -0
  17. data/examples/repeat_entry.rb +4 -1
  18. data/lib/highline.rb +182 -704
  19. data/lib/highline/builtin_styles.rb +109 -0
  20. data/lib/highline/color_scheme.rb +4 -1
  21. data/lib/highline/compatibility.rb +2 -0
  22. data/lib/highline/custom_errors.rb +19 -0
  23. data/lib/highline/import.rb +4 -2
  24. data/lib/highline/list.rb +93 -0
  25. data/lib/highline/list_renderer.rb +232 -0
  26. data/lib/highline/menu.rb +20 -20
  27. data/lib/highline/paginator.rb +43 -0
  28. data/lib/highline/question.rb +157 -97
  29. data/lib/highline/question/answer_converter.rb +84 -0
  30. data/lib/highline/question_asker.rb +147 -0
  31. data/lib/highline/simulate.rb +5 -1
  32. data/lib/highline/statement.rb +58 -0
  33. data/lib/highline/string.rb +34 -0
  34. data/lib/highline/string_extensions.rb +3 -28
  35. data/lib/highline/style.rb +18 -8
  36. data/lib/highline/template_renderer.rb +38 -0
  37. data/lib/highline/terminal.rb +78 -0
  38. data/lib/highline/terminal/io_console.rb +98 -0
  39. data/lib/highline/terminal/ncurses.rb +38 -0
  40. data/lib/highline/terminal/unix_stty.rb +94 -0
  41. data/lib/highline/version.rb +3 -1
  42. data/lib/highline/wrapper.rb +43 -0
  43. data/test/acceptance/acceptance.rb +62 -0
  44. data/test/acceptance/acceptance_test.rb +69 -0
  45. data/test/acceptance/at_color_output_using_erb_templates.rb +17 -0
  46. data/test/acceptance/at_echo_false.rb +23 -0
  47. data/test/acceptance/at_readline.rb +37 -0
  48. data/test/io_console_compatible.rb +37 -0
  49. data/test/string_methods.rb +3 -0
  50. data/test/test_answer_converter.rb +26 -0
  51. data/test/{tc_color_scheme.rb → test_color_scheme.rb} +7 -9
  52. data/test/test_helper.rb +26 -0
  53. data/test/{tc_highline.rb → test_highline.rb} +193 -136
  54. data/test/{tc_import.rb → test_import.rb} +5 -2
  55. data/test/test_list.rb +60 -0
  56. data/test/{tc_menu.rb → test_menu.rb} +6 -3
  57. data/test/test_paginator.rb +73 -0
  58. data/test/test_question_asker.rb +20 -0
  59. data/test/test_simulator.rb +24 -0
  60. data/test/test_string_extension.rb +72 -0
  61. data/test/{tc_string_highline.rb → test_string_highline.rb} +7 -3
  62. data/test/{tc_style.rb → test_style.rb} +70 -35
  63. data/test/test_wrapper.rb +188 -0
  64. metadata +57 -22
  65. data/lib/highline/system_extensions.rb +0 -254
  66. data/test/tc_simulator.rb +0 -33
  67. data/test/tc_string_extension.rb +0 -33
@@ -0,0 +1,84 @@
1
+ # coding: utf-8
2
+
3
+ require 'forwardable'
4
+
5
+ class HighLine
6
+ class Question
7
+ class AnswerConverter
8
+ extend Forwardable
9
+
10
+ def_delegators :@question,
11
+ :answer, :answer=, :check_range,
12
+ :directory, :answer_type, :choices_complete
13
+
14
+ def initialize(question)
15
+ @question = question
16
+ end
17
+
18
+ def convert
19
+ return unless answer_type
20
+
21
+ self.answer = convert_by_answer_type
22
+ check_range
23
+ answer
24
+ end
25
+
26
+ def to_string
27
+ HighLine::String(answer)
28
+ end
29
+
30
+ # That's a weird name for a method!
31
+ # But it's working ;-)
32
+ define_method "to_highline::string" do
33
+ HighLine::String(answer)
34
+ end
35
+
36
+ def to_integer
37
+ Kernel.send(:Integer, answer)
38
+ end
39
+
40
+ def to_float
41
+ Kernel.send(:Float, answer)
42
+ end
43
+
44
+ def to_symbol
45
+ answer.to_sym
46
+ end
47
+
48
+ def to_regexp
49
+ Regexp.new(answer)
50
+ end
51
+
52
+ def to_file
53
+ self.answer = choices_complete(answer)
54
+ File.open(File.join(directory.to_s, answer.last))
55
+ end
56
+
57
+ def to_pathname
58
+ self.answer = choices_complete(answer)
59
+ Pathname.new(File.join(directory.to_s, answer.last))
60
+ end
61
+
62
+ def to_array
63
+ self.answer = choices_complete(answer)
64
+ answer.last
65
+ end
66
+
67
+ def to_proc
68
+ answer_type.call(answer)
69
+ end
70
+
71
+ private
72
+
73
+ def convert_by_answer_type
74
+ if answer_type.respond_to? :parse
75
+ answer_type.parse(answer)
76
+ elsif answer_type.is_a? Class
77
+ send("to_#{answer_type.name.downcase}")
78
+ else
79
+ send("to_#{answer_type.class.name.downcase}")
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,147 @@
1
+ class HighLine
2
+ class QuestionAsker
3
+ attr_reader :question
4
+
5
+ include CustomErrors
6
+
7
+ def initialize(question, highline)
8
+ @question = question
9
+ @highline = highline
10
+ end
11
+
12
+ #
13
+ # Gets just one answer, as opposed to #gather_answers
14
+ #
15
+ def ask_once
16
+ question.show_question(@highline)
17
+
18
+ begin
19
+ question.get_response_or_default(@highline)
20
+ raise NotValidQuestionError unless question.valid_answer?
21
+
22
+ question.convert
23
+
24
+ if question.confirm
25
+ raise NoConfirmationQuestionError unless @highline.send(:confirm, question)
26
+ end
27
+
28
+ rescue NoConfirmationQuestionError
29
+ explain_error(nil)
30
+ retry
31
+
32
+ rescue NotInRangeQuestionError
33
+ explain_error(:not_in_range)
34
+ retry
35
+
36
+ rescue NotValidQuestionError
37
+ explain_error(:not_valid)
38
+ retry
39
+
40
+ rescue QuestionError
41
+ retry
42
+
43
+ rescue ArgumentError => error
44
+ case error.message
45
+ when /ambiguous/
46
+ # the assumption here is that OptionParser::Completion#complete
47
+ # (used for ambiguity resolution) throws exceptions containing
48
+ # the word 'ambiguous' whenever resolution fails
49
+ explain_error(:ambiguous_completion)
50
+ retry
51
+ when /invalid value for/
52
+ explain_error(:invalid_type)
53
+ retry
54
+ else
55
+ raise
56
+ end
57
+
58
+ rescue NoAutoCompleteMatch
59
+ explain_error(:no_completion)
60
+ retry
61
+ end
62
+ question.answer
63
+ end
64
+
65
+ ## Multiple questions
66
+
67
+ #
68
+ # Collects an Array/Hash full of answers as described in
69
+ # HighLine::Question.gather().
70
+ #
71
+ def gather_answers
72
+ original_question_template = question.template
73
+ verify_match = question.verify_match
74
+
75
+ begin # when verify_match is set this loop will repeat until unique_answers == 1
76
+ question.template = original_question_template
77
+
78
+ answers = gather_answers_based_on_type
79
+
80
+ if verify_match && (@highline.send(:unique_answers, answers).size > 1)
81
+ explain_error(:mismatch)
82
+ else
83
+ verify_match = false
84
+ end
85
+ end while verify_match
86
+
87
+ question.verify_match ? @highline.send(:last_answer, answers) : answers
88
+ end
89
+
90
+ def gather_integer
91
+ gather_with_array do |answers|
92
+ (question.gather-1).times { answers << ask_once }
93
+ end
94
+ end
95
+
96
+ def gather_regexp
97
+ gather_with_array do |answers|
98
+ answers << ask_once until answer_matches_regex(answers.last)
99
+ answers.pop
100
+ end
101
+ end
102
+
103
+ def gather_hash
104
+ answers = {}
105
+
106
+ question.gather.keys.sort.each do |key|
107
+ @highline.key = key
108
+ answers[key] = ask_once
109
+ end
110
+ answers
111
+ end
112
+
113
+
114
+ private
115
+
116
+ ## Delegate to Highline
117
+ def explain_error(error)
118
+ @highline.say(question.responses[error]) if error
119
+ @highline.say(question.ask_on_error_msg)
120
+ end
121
+
122
+ def gather_with_array
123
+ [].tap do |answers|
124
+ answers << ask_once
125
+ question.template = ""
126
+
127
+ yield answers
128
+ end
129
+ end
130
+
131
+ def answer_matches_regex(answer)
132
+ (question.gather.is_a?(::String) && answer.to_s == question.gather) ||
133
+ (question.gather.is_a?(Regexp) && answer.to_s =~ question.gather)
134
+ end
135
+
136
+ def gather_answers_based_on_type
137
+ case question.gather
138
+ when Integer
139
+ gather_integer
140
+ when ::String, Regexp
141
+ gather_regexp
142
+ when Hash
143
+ gather_hash
144
+ end
145
+ end
146
+ end
147
+ end
@@ -1,3 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ #--
1
4
  # simulate.rb
2
5
  #
3
6
  # Created by Andy Rossmeissl on 2012-04-29.
@@ -6,6 +9,7 @@
6
9
  # This is Free Software. See LICENSE and COPYING for details.
7
10
  #
8
11
  # adapted from https://gist.github.com/194554
12
+
9
13
  class HighLine
10
14
 
11
15
  # Simulates Highline input for use in tests.
@@ -23,7 +27,7 @@ class HighLine
23
27
 
24
28
  # Simulate StringIO#getbyte by shifting a single character off of the next line of the script
25
29
  def getbyte
26
- line = gets.dup
30
+ line = gets
27
31
  if line.length > 0
28
32
  char = line.slice! 0
29
33
  @strings.unshift line
@@ -0,0 +1,58 @@
1
+ # coding: utf-8
2
+
3
+ require 'highline/wrapper'
4
+ require 'highline/paginator'
5
+ require 'highline/template_renderer'
6
+
7
+ class HighLine::Statement
8
+ attr_reader :source, :highline
9
+ attr_reader :template_string
10
+
11
+ def initialize(source, highline)
12
+ @highline = highline
13
+ @source = source
14
+ @template_string = stringfy(source)
15
+ end
16
+
17
+ def statement
18
+ @statement ||= format_statement
19
+ end
20
+
21
+ def to_s
22
+ statement
23
+ end
24
+
25
+ private
26
+
27
+ def stringfy(template_string)
28
+ String(template_string || "").dup
29
+ end
30
+
31
+ def format_statement
32
+ return template_string unless template_string.length > 0
33
+
34
+ statement = render_template
35
+
36
+ statement = HighLine::Wrapper.wrap(statement, highline.wrap_at)
37
+ statement = HighLine::Paginator.new(highline).page_print(statement)
38
+
39
+ statement = statement.gsub(/\n(?!$)/,"\n#{highline.indentation}") if highline.multi_indent
40
+ statement
41
+ end
42
+
43
+ def render_template
44
+ # Assigning to a local var so it may be
45
+ # used inside instance eval block
46
+
47
+ template_renderer = TemplateRenderer.new(template, source, highline)
48
+ template_renderer.render
49
+ end
50
+
51
+ def template
52
+ @template ||= ERB.new(template_string, nil, "%")
53
+ end
54
+
55
+ def self.const_missing(constant)
56
+ HighLine.const_get(constant)
57
+ end
58
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ require "highline/string_extensions"
4
+
5
+ #
6
+ # HighLine::String is a subclass of String with convenience methods added for colorization.
7
+ #
8
+ # Available convenience methods include:
9
+ # * 'color' method e.g. highline_string.color(:bright_blue, :underline)
10
+ # * colors e.g. highline_string.magenta
11
+ # * RGB colors e.g. highline_string.rgb_ff6000
12
+ # or highline_string.rgb(255,96,0)
13
+ # * background colors e.g. highline_string.on_magenta
14
+ # * RGB background colors e.g. highline_string.on_rgb_ff6000
15
+ # or highline_string.on_rgb(255,96,0)
16
+ # * styles e.g. highline_string.underline
17
+ #
18
+ # Additionally, convenience methods can be chained, for instance the following are equivalent:
19
+ # highline_string.bright_blue.blink.underline
20
+ # highline_string.color(:bright_blue, :blink, :underline)
21
+ # HighLine.color(highline_string, :bright_blue, :blink, :underline)
22
+ #
23
+ # For those less squeamish about possible conflicts, the same convenience methods can be
24
+ # added to the built-in String class, as follows:
25
+ #
26
+ # require 'highline'
27
+ # Highline.colorize_strings
28
+ #
29
+
30
+ class HighLine
31
+ class String < ::String
32
+ include StringExtensions
33
+ end
34
+ end
@@ -1,33 +1,12 @@
1
- # Extensions for class String
2
- #
3
- # HighLine::String is a subclass of String with convenience methods added for colorization.
4
- #
5
- # Available convenience methods include:
6
- # * 'color' method e.g. highline_string.color(:bright_blue, :underline)
7
- # * colors e.g. highline_string.magenta
8
- # * RGB colors e.g. highline_string.rgb_ff6000
9
- # or highline_string.rgb(255,96,0)
10
- # * background colors e.g. highline_string.on_magenta
11
- # * RGB background colors e.g. highline_string.on_rgb_ff6000
12
- # or highline_string.on_rgb(255,96,0)
13
- # * styles e.g. highline_string.underline
14
- #
15
- # Additionally, convenience methods can be chained, for instance the following are equivalent:
16
- # highline_string.bright_blue.blink.underline
17
- # highline_string.color(:bright_blue, :blink, :underline)
18
- # HighLine.color(highline_string, :bright_blue, :blink, :underline)
19
- #
20
- # For those less squeamish about possible conflicts, the same convenience methods can be
21
- # added to the built-in String class, as follows:
22
- #
23
- # require 'highline'
24
- # Highline.colorize_strings
1
+ # coding: utf-8
25
2
 
26
3
  class HighLine
27
4
  def self.String(s)
28
5
  HighLine::String.new(s)
29
6
  end
30
7
 
8
+ # HighLine extensions for String class
9
+ # Included by HighLine::String
31
10
  module StringExtensions
32
11
  def self.included(base)
33
12
  HighLine::COLORS.each do |color|
@@ -101,10 +80,6 @@ class HighLine
101
80
  end
102
81
  end
103
82
 
104
- class HighLine::String < ::String
105
- include StringExtensions
106
- end
107
-
108
83
  def self.colorize_strings
109
84
  ::String.send(:include, StringExtensions)
110
85
  end
@@ -1,3 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ #--
1
4
  # color_scheme.rb
2
5
  #
3
6
  # Created by Richard LeBer on 2011-06-27.
@@ -42,18 +45,25 @@ class HighLine
42
45
 
43
46
  def self.index(style)
44
47
  if style.name
45
- @@styles ||= {}
46
- @@styles[style.name] = style
48
+ @styles ||= {}
49
+ @styles[style.name] = style
47
50
  end
48
51
  if !style.list
49
- @@code_index ||= {}
50
- @@code_index[style.code] ||= []
51
- @@code_index[style.code].reject!{|indexed_style| indexed_style.name == style.name}
52
- @@code_index[style.code] << style
52
+ @code_index ||= {}
53
+ @code_index[style.code] ||= []
54
+ @code_index[style.code].reject!{|indexed_style| indexed_style.name == style.name}
55
+ @code_index[style.code] << style
53
56
  end
54
57
  style
55
58
  end
56
59
 
60
+ def self.clear_index
61
+ # reset to builtin only styles
62
+ @styles = list.select { |name, style| style.builtin }
63
+ @code_index = {}
64
+ @styles.each { |name, style| index(style) }
65
+ end
66
+
57
67
  def self.rgb_hex(*colors)
58
68
  colors.map do |color|
59
69
  color.is_a?(Numeric) ? '%02x'%color : color.to_s
@@ -87,11 +97,11 @@ class HighLine
87
97
  end
88
98
 
89
99
  def self.list
90
- @@styles ||= {}
100
+ @styles ||= {}
91
101
  end
92
102
 
93
103
  def self.code_index
94
- @@code_index ||= {}
104
+ @code_index ||= {}
95
105
  end
96
106
 
97
107
  def self.uncolor(string)