highline 1.7.10 → 2.0.0.pre.develop.2

Sign up to get free protection for your applications and to get access to all the features.
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)