highline 2.0.0.pre.develop.2 → 2.0.0.pre.develop.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,7 @@ require 'forwardable'
4
4
 
5
5
  class HighLine
6
6
  class Question
7
+ # It provides all answer conversion flow.
7
8
  class AnswerConverter
8
9
  extend Forwardable
9
10
 
@@ -11,10 +12,19 @@ class HighLine
11
12
  :answer, :answer=, :check_range,
12
13
  :directory, :answer_type, :choices_complete
13
14
 
15
+ # It should be initialized with a Question object.
16
+ # The class will get the answer from {Question#answer}
17
+ # and then convert it to the proper {Question#answer_type}.
18
+ # It is mainly used by {Question#convert}
19
+ #
20
+ # @param question [Question]
14
21
  def initialize(question)
15
22
  @question = question
16
23
  end
17
24
 
25
+ # Based on the given Question object's settings,
26
+ # it makes the conversion and returns the answer.
27
+ # @return [Object] the converted answer.
18
28
  def convert
19
29
  return unless answer_type
20
30
 
@@ -23,6 +33,7 @@ class HighLine
23
33
  answer
24
34
  end
25
35
 
36
+ # @return [HighLine::String] answer converted to a HighLine::String
26
37
  def to_string
27
38
  HighLine::String(answer)
28
39
  end
@@ -33,37 +44,45 @@ class HighLine
33
44
  HighLine::String(answer)
34
45
  end
35
46
 
47
+ # @return [Integer] answer converted to an Integer
36
48
  def to_integer
37
49
  Kernel.send(:Integer, answer)
38
50
  end
39
51
 
52
+ # @return [Float] answer converted to a Float
40
53
  def to_float
41
54
  Kernel.send(:Float, answer)
42
55
  end
43
56
 
57
+ # @return [Symbol] answer converted to an Symbol
44
58
  def to_symbol
45
59
  answer.to_sym
46
60
  end
47
61
 
62
+ # @return [Regexp] answer converted to a Regexp
48
63
  def to_regexp
49
64
  Regexp.new(answer)
50
65
  end
51
66
 
67
+ # @return [File] answer converted to a File
52
68
  def to_file
53
69
  self.answer = choices_complete(answer)
54
70
  File.open(File.join(directory.to_s, answer.last))
55
71
  end
56
72
 
73
+ # @return [Pathname] answer converted to an Pathname
57
74
  def to_pathname
58
75
  self.answer = choices_complete(answer)
59
76
  Pathname.new(File.join(directory.to_s, answer.last))
60
77
  end
61
78
 
79
+ # @return [Array] answer converted to an Array
62
80
  def to_array
63
81
  self.answer = choices_complete(answer)
64
82
  answer.last
65
83
  end
66
84
 
85
+ # @return [Proc] answer converted to an Proc
67
86
  def to_proc
68
87
  answer_type.call(answer)
69
88
  end
@@ -1,9 +1,17 @@
1
1
  class HighLine
2
+ # Deals with the task of "asking" a question
2
3
  class QuestionAsker
4
+ # @return [Question] question to be asked
3
5
  attr_reader :question
4
6
 
5
7
  include CustomErrors
6
8
 
9
+ # To do its work QuestionAsker needs a Question
10
+ # to be asked and a HighLine context where to
11
+ # direct output.
12
+ #
13
+ # @param question [Question] question to be asked
14
+ # @param highline [HighLine] context
7
15
  def initialize(question, highline)
8
16
  @question = question
9
17
  @highline = highline
@@ -12,6 +20,7 @@ class HighLine
12
20
  #
13
21
  # Gets just one answer, as opposed to #gather_answers
14
22
  #
23
+ # @return [String] answer
15
24
  def ask_once
16
25
  question.show_question(@highline)
17
26
 
@@ -25,19 +34,8 @@ class HighLine
25
34
  raise NoConfirmationQuestionError unless @highline.send(:confirm, question)
26
35
  end
27
36
 
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
37
+ rescue ExplainableError => e
38
+ explain_error(e.explanation_key)
41
39
  retry
42
40
 
43
41
  rescue ArgumentError => error
@@ -54,11 +52,8 @@ class HighLine
54
52
  else
55
53
  raise
56
54
  end
57
-
58
- rescue NoAutoCompleteMatch
59
- explain_error(:no_completion)
60
- retry
61
55
  end
56
+
62
57
  question.answer
63
58
  end
64
59
 
@@ -68,6 +63,7 @@ class HighLine
68
63
  # Collects an Array/Hash full of answers as described in
69
64
  # HighLine::Question.gather().
70
65
  #
66
+ # @return [Array, Hash] answers
71
67
  def gather_answers
72
68
  original_question_template = question.template
73
69
  verify_match = question.verify_match
@@ -87,12 +83,17 @@ class HighLine
87
83
  question.verify_match ? @highline.send(:last_answer, answers) : answers
88
84
  end
89
85
 
86
+ # Gather multiple integer values based on {Question#gather} count
87
+ # @return [Array] answers
90
88
  def gather_integer
91
89
  gather_with_array do |answers|
92
90
  (question.gather-1).times { answers << ask_once }
93
91
  end
94
92
  end
95
93
 
94
+ # Gather multiple values until any of them matches the
95
+ # {Question#gather} Regexp.
96
+ # @return [Array] answers
96
97
  def gather_regexp
97
98
  gather_with_array do |answers|
98
99
  answers << ask_once until answer_matches_regex(answers.last)
@@ -100,6 +101,9 @@ class HighLine
100
101
  end
101
102
  end
102
103
 
104
+ # Gather multiple values and store them on a Hash
105
+ # with keys provided by the Hash on {Question#gather}
106
+ # @return [Hash]
103
107
  def gather_hash
104
108
  answers = {}
105
109
 
@@ -10,12 +10,15 @@
10
10
  #
11
11
  # adapted from https://gist.github.com/194554
12
12
 
13
+
13
14
  class HighLine
14
15
 
15
16
  # Simulates Highline input for use in tests.
16
17
  class Simulate
17
18
 
18
19
  # Creates a simulator with an array of Strings as a script
20
+ # @param strings [Array<String>] preloaded string to be used
21
+ # as input buffer when simulating.
19
22
  def initialize(strings)
20
23
  @strings = strings
21
24
  end
@@ -40,7 +43,13 @@ class HighLine
40
43
  false
41
44
  end
42
45
 
43
- # A wrapper method that temporarily replaces the Highline instance in $terminal with an instance of this object for the duration of the block
46
+ # A wrapper method that temporarily replaces the Highline
47
+ # instance in $terminal with an instance of this object
48
+ # for the duration of the block
49
+ #
50
+ # @param strings [String] preloaded string buffer that
51
+ # will feed the input operations when simulating.
52
+
44
53
  def self.with(*strings)
45
54
  @input = $terminal.instance_variable_get :@input
46
55
  $terminal.instance_variable_set :@input, new(strings)
@@ -4,55 +4,79 @@ require 'highline/wrapper'
4
4
  require 'highline/paginator'
5
5
  require 'highline/template_renderer'
6
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
7
+ class HighLine
8
+ # This class handles proper formatting based
9
+ # on a HighLine context, applying wrapping,
10
+ # pagination, indentation and color rendering
11
+ # when necessary. It's used by {HighLine#render_statement}
12
+ # @see HighLine#render_statement
13
+ class Statement
14
+ # The source object to be stringfied and formatted.
15
+ attr_reader :source
16
16
 
17
- def statement
18
- @statement ||= format_statement
19
- end
17
+ # The HighLine context
18
+ # @return [HighLine]
19
+ attr_reader :highline
20
20
 
21
- def to_s
22
- statement
23
- end
21
+ # The stringfied source object
22
+ # @return [String]
23
+ attr_reader :template_string
24
24
 
25
- private
25
+ # It needs the input String and the HighLine context
26
+ # @param source [#to_s]
27
+ # @param highline [HighLine] context
28
+ def initialize(source, highline)
29
+ @highline = highline
30
+ @source = source
31
+ @template_string = stringfy(source)
32
+ end
26
33
 
27
- def stringfy(template_string)
28
- String(template_string || "").dup
29
- end
34
+ # Returns the formated statement.
35
+ # Applies wrapping, pagination, indentation and color rendering
36
+ # based on HighLine instance settings.
37
+ # @return [String] formated statement
38
+ def statement
39
+ @statement ||= format_statement
40
+ end
30
41
 
31
- def format_statement
32
- return template_string unless template_string.length > 0
42
+ # (see #statement)
43
+ # Delegates to {#statement}
44
+ def to_s
45
+ statement
46
+ end
33
47
 
34
- statement = render_template
48
+ private
35
49
 
36
- statement = HighLine::Wrapper.wrap(statement, highline.wrap_at)
37
- statement = HighLine::Paginator.new(highline).page_print(statement)
50
+ def stringfy(template_string)
51
+ String(template_string || "").dup
52
+ end
38
53
 
39
- statement = statement.gsub(/\n(?!$)/,"\n#{highline.indentation}") if highline.multi_indent
40
- statement
41
- end
54
+ def format_statement
55
+ return template_string unless template_string.length > 0
42
56
 
43
- def render_template
44
- # Assigning to a local var so it may be
45
- # used inside instance eval block
57
+ statement = render_template
46
58
 
47
- template_renderer = TemplateRenderer.new(template, source, highline)
48
- template_renderer.render
49
- end
59
+ statement = HighLine::Wrapper.wrap(statement, highline.wrap_at)
60
+ statement = HighLine::Paginator.new(highline).page_print(statement)
50
61
 
51
- def template
52
- @template ||= ERB.new(template_string, nil, "%")
53
- end
62
+ statement = statement.gsub(/\n(?!$)/,"\n#{highline.indentation}") if highline.multi_indent
63
+ statement
64
+ end
65
+
66
+ def render_template
67
+ # Assigning to a local var so it may be
68
+ # used inside instance eval block
69
+
70
+ template_renderer = TemplateRenderer.new(template, source, highline)
71
+ template_renderer.render
72
+ end
73
+
74
+ def template
75
+ @template ||= ERB.new(template_string, nil, "%")
76
+ end
54
77
 
55
- def self.const_missing(constant)
56
- HighLine.const_get(constant)
78
+ def self.const_missing(constant)
79
+ HighLine.const_get(constant)
80
+ end
57
81
  end
58
82
  end
@@ -2,32 +2,33 @@
2
2
 
3
3
  require "highline/string_extensions"
4
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
5
  class HighLine
6
+
7
+ #
8
+ # HighLine::String is a subclass of String with convenience methods added for colorization.
9
+ #
10
+ # Available convenience methods include:
11
+ # * 'color' method e.g. highline_string.color(:bright_blue, :underline)
12
+ # * colors e.g. highline_string.magenta
13
+ # * RGB colors e.g. highline_string.rgb_ff6000
14
+ # or highline_string.rgb(255,96,0)
15
+ # * background colors e.g. highline_string.on_magenta
16
+ # * RGB background colors e.g. highline_string.on_rgb_ff6000
17
+ # or highline_string.on_rgb(255,96,0)
18
+ # * styles e.g. highline_string.underline
19
+ #
20
+ # Additionally, convenience methods can be chained, for instance the following are equivalent:
21
+ # highline_string.bright_blue.blink.underline
22
+ # highline_string.color(:bright_blue, :blink, :underline)
23
+ # HighLine.color(highline_string, :bright_blue, :blink, :underline)
24
+ #
25
+ # For those less squeamish about possible conflicts, the same convenience methods can be
26
+ # added to the built-in String class, as follows:
27
+ #
28
+ # require 'highline'
29
+ # Highline.colorize_strings
30
+ #
31
+
31
32
  class String < ::String
32
33
  include StringExtensions
33
34
  end
@@ -1,40 +1,30 @@
1
1
  # coding: utf-8
2
2
 
3
3
  class HighLine
4
+ # Returns a HighLine::String from any given String.
5
+ # @param s [String]
6
+ # @return [HighLine::String] from the given string.
4
7
  def self.String(s)
5
8
  HighLine::String.new(s)
6
9
  end
7
10
 
8
- # HighLine extensions for String class
9
- # Included by HighLine::String
11
+ # HighLine extensions for String class.
12
+ # Included by HighLine::String.
10
13
  module StringExtensions
14
+ # Included hook. Actions to take when being included.
15
+ # @param base [Class, Module] base class
11
16
  def self.included(base)
12
- HighLine::COLORS.each do |color|
13
- color = color.downcase
14
- base.class_eval <<-END
15
- undef :#{color} if method_defined? :#{color}
16
- def #{color}
17
- color(:#{color})
18
- end
19
- END
20
-
21
- base.class_eval <<-END
22
- undef :on_#{color} if method_defined? :on_#{color}
23
- def on_#{color}
24
- on(:#{color})
25
- end
26
- END
27
- HighLine::STYLES.each do |style|
28
- style = style.downcase
29
- base.class_eval <<-END
30
- undef :#{style} if method_defined? :#{style}
31
- def #{style}
32
- color(:#{style})
33
- end
34
- END
35
- end
36
- end
17
+ define_builtin_style_methods(base)
18
+ define_style_support_methods(base)
19
+ end
37
20
 
21
+ # At include time, it defines all basic style
22
+ # support method like #color, #on, #uncolor,
23
+ # #rgb, #on_rgb and the #method_missing callback
24
+ # @return [void]
25
+ # @param base [Class, Module] the base class/module
26
+ #
27
+ def self.define_style_support_methods(base)
38
28
  base.class_eval do
39
29
  undef :color if method_defined? :color
40
30
  undef :foreground if method_defined? :foreground
@@ -55,19 +45,17 @@ class HighLine
55
45
 
56
46
  undef :rgb if method_defined? :rgb
57
47
  def rgb(*colors)
58
- color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
59
- raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
48
+ color_code = setup_color_code(*colors)
60
49
  color("rgb_#{color_code}".to_sym)
61
50
  end
62
51
 
63
52
  undef :on_rgb if method_defined? :on_rgb
64
53
  def on_rgb(*colors)
65
- color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
66
- raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
54
+ color_code = setup_color_code(*colors)
67
55
  color("on_rgb_#{color_code}".to_sym)
68
56
  end
69
57
 
70
- # TODO Chain existing method_missing
58
+ # @todo Chain existing method_missing?
71
59
  undef :method_missing if method_defined? :method_missing
72
60
  def method_missing(method, *args, &blk)
73
61
  if method.to_s =~ /^(on_)?rgb_([0-9a-fA-F]{6})$/
@@ -76,10 +64,50 @@ class HighLine
76
64
  raise NoMethodError, "undefined method `#{method}' for #<#{self.class}:#{'%#x'%self.object_id}>"
77
65
  end
78
66
  end
67
+
68
+ private
69
+
70
+ def setup_color_code(*colors)
71
+ color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
72
+ raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
73
+ color_code
74
+ end
75
+ end
76
+ end
77
+
78
+ # At include time, it defines all basic builtin styles.
79
+ # @param base [Class, Module] base Class/Module
80
+ def self.define_builtin_style_methods(base)
81
+ HighLine::COLORS.each do |color|
82
+ color = color.downcase
83
+ base.class_eval <<-END
84
+ undef :#{color} if method_defined? :#{color}
85
+ def #{color}
86
+ color(:#{color})
87
+ end
88
+ END
89
+
90
+ base.class_eval <<-END
91
+ undef :on_#{color} if method_defined? :on_#{color}
92
+ def on_#{color}
93
+ on(:#{color})
94
+ end
95
+ END
96
+
97
+ HighLine::STYLES.each do |style|
98
+ style = style.downcase
99
+ base.class_eval <<-END
100
+ undef :#{style} if method_defined? :#{style}
101
+ def #{style}
102
+ color(:#{style})
103
+ end
104
+ END
105
+ end
79
106
  end
80
107
  end
81
108
  end
82
109
 
110
+ # Adds color support to the base String class
83
111
  def self.colorize_strings
84
112
  ::String.send(:include, StringExtensions)
85
113
  end