highline-sgonyea 1.6.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +2 -0
  2. data/AUTHORS +3 -0
  3. data/CHANGELOG +308 -0
  4. data/COPYING +340 -0
  5. data/INSTALL +55 -0
  6. data/LICENSE +7 -0
  7. data/README.rdoc +63 -0
  8. data/Rakefile +50 -0
  9. data/TODO +6 -0
  10. data/examples/ansi_colors.rb +36 -0
  11. data/examples/asking_for_arrays.rb +16 -0
  12. data/examples/basic_usage.rb +73 -0
  13. data/examples/color_scheme.rb +30 -0
  14. data/examples/limit.rb +10 -0
  15. data/examples/menus.rb +63 -0
  16. data/examples/overwrite.rb +17 -0
  17. data/examples/page_and_wrap.rb +320 -0
  18. data/examples/password.rb +5 -0
  19. data/examples/repeat_entry.rb +19 -0
  20. data/examples/trapping_eof.rb +20 -0
  21. data/examples/using_readline.rb +15 -0
  22. data/highline.gemspec +36 -0
  23. data/lib/highline.rb +1000 -0
  24. data/lib/highline/color_scheme.rb +134 -0
  25. data/lib/highline/compatibility.rb +16 -0
  26. data/lib/highline/import.rb +41 -0
  27. data/lib/highline/menu.rb +398 -0
  28. data/lib/highline/question.rb +472 -0
  29. data/lib/highline/simulate.rb +48 -0
  30. data/lib/highline/string_extensions.rb +131 -0
  31. data/lib/highline/style.rb +181 -0
  32. data/lib/highline/system_extensions.rb +186 -0
  33. data/setup.rb +1360 -0
  34. data/site/.cvsignore +1 -0
  35. data/site/highline.css +65 -0
  36. data/site/images/logo.png +0 -0
  37. data/site/index.html +58 -0
  38. data/test/string_methods.rb +32 -0
  39. data/test/tc_color_scheme.rb +96 -0
  40. data/test/tc_highline.rb +1027 -0
  41. data/test/tc_import.rb +52 -0
  42. data/test/tc_menu.rb +427 -0
  43. data/test/tc_string_extension.rb +20 -0
  44. data/test/tc_string_highline.rb +38 -0
  45. data/test/tc_style.rb +567 -0
  46. data/test/ts_all.rb +16 -0
  47. metadata +118 -0
@@ -0,0 +1,48 @@
1
+ # simulate.rb
2
+ #
3
+ # Created by Andy Rossmeissl on 2012-04-29.
4
+ # Copyright 2005 Gray Productions. All rights reserved.
5
+ #
6
+ # This is Free Software. See LICENSE and COPYING for details.
7
+ #
8
+ # adapted from https://gist.github.com/194554
9
+ class HighLine
10
+
11
+ # Simulates Highline input for use in tests.
12
+ class Simulate
13
+
14
+ # Creates a simulator with an array of Strings as a script
15
+ def initialize(strings)
16
+ @strings = strings
17
+ end
18
+
19
+ # Simulate StringIO#gets by shifting a string off of the script
20
+ def gets
21
+ @strings.shift
22
+ end
23
+
24
+ # Simulate StringIO#getbyte by shifting a single character off of the next line of the script
25
+ def getbyte
26
+ line = gets
27
+ if line.length > 0
28
+ char = line.slice! 0
29
+ @strings.unshift line
30
+ char
31
+ end
32
+ end
33
+
34
+ # The simulator handles its own EOF
35
+ def eof?
36
+ false
37
+ end
38
+
39
+ # A wrapper method that temporarily replaces the Highline instance in $terminal with an instance of this object for the duration of the block
40
+ def self.with(*strings)
41
+ @input = $terminal.instance_variable_get :@input
42
+ $terminal.instance_variable_set :@input, new(strings)
43
+ yield
44
+ ensure
45
+ $terminal.instance_variable_set :@input, @input
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,131 @@
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 builtin String class, as follows:
22
+ #
23
+ # require 'highline'
24
+ # Highline.colorize_strings
25
+
26
+ class HighLine
27
+ def self.String(s)
28
+ HighLine::String.new(s)
29
+ end
30
+
31
+ module StringExtensions
32
+ def self.included(base)
33
+ HighLine::COLORS.each do |color|
34
+ base.class_eval <<-END
35
+ if public_instance_methods.map { |m| m.to_s }.
36
+ include? "#{color.downcase}"
37
+ undef :#{color.downcase}
38
+ end
39
+ def #{color.downcase}
40
+ color(:#{color.downcase})
41
+ end
42
+ END
43
+ base.class_eval <<-END
44
+ if public_instance_methods.map { |m| m.to_s }.
45
+ include? "on_#{color.downcase}"
46
+ undef :on_#{color.downcase}
47
+ end
48
+ def on_#{color.downcase}
49
+ on(:#{color.downcase})
50
+ end
51
+ END
52
+ HighLine::STYLES.each do |style|
53
+ base.class_eval <<-END
54
+ if public_instance_methods.map { |m| m.to_s }.
55
+ include? "#{style.downcase}"
56
+ undef :#{style.downcase}
57
+ end
58
+ def #{style.downcase}
59
+ color(:#{style.downcase})
60
+ end
61
+ END
62
+ end
63
+ end
64
+
65
+ base.class_eval do
66
+ if public_instance_methods.map { |m| m.to_s }.include? "color"
67
+ undef :color
68
+ end
69
+ if public_instance_methods.map { |m| m.to_s }.include? "foreground"
70
+ undef :foreground
71
+ end
72
+ def color(*args)
73
+ self.class.new(HighLine.color(self, *args))
74
+ end
75
+ alias_method :foreground, :color
76
+
77
+ if public_instance_methods.map { |m| m.to_s }.include? "on"
78
+ undef :on
79
+ end
80
+ def on(arg)
81
+ color(('on_' + arg.to_s).to_sym)
82
+ end
83
+
84
+ if public_instance_methods.map { |m| m.to_s }.include? "uncolor"
85
+ undef :uncolor
86
+ end
87
+ def uncolor
88
+ self.class.new(HighLine.uncolor(self))
89
+ end
90
+
91
+ if public_instance_methods.map { |m| m.to_s }.include? "rgb"
92
+ undef :rgb
93
+ end
94
+ def rgb(*colors)
95
+ color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
96
+ raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
97
+ color("rgb_#{color_code}".to_sym)
98
+ end
99
+
100
+ if public_instance_methods.map { |m| m.to_s }.include? "on_rgb"
101
+ undef :on_rgb
102
+ end
103
+ def on_rgb(*colors)
104
+ color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
105
+ raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
106
+ color("on_rgb_#{color_code}".to_sym)
107
+ end
108
+
109
+ if public_instance_methods.map { |m| m.to_s }.include? "method_missing"
110
+ undef :method_missing
111
+ end
112
+ # TODO Chain existing method_missing
113
+ def method_missing(method, *args, &blk)
114
+ if method.to_s =~ /^(on_)?rgb_([0-9a-fA-F]{6})$/
115
+ color(method)
116
+ else
117
+ raise NoMethodError, "undefined method `#{method}' for #<#{self.class}:#{'%#x'%self.object_id}>"
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ class HighLine::String < ::String
125
+ include StringExtensions
126
+ end
127
+
128
+ def self.colorize_strings
129
+ ::String.send(:include, StringExtensions)
130
+ end
131
+ end
@@ -0,0 +1,181 @@
1
+ # color_scheme.rb
2
+ #
3
+ # Created by Richard LeBer on 2011-06-27.
4
+ # Copyright 2011. All rights reserved
5
+ #
6
+ # This is Free Software. See LICENSE and COPYING for details
7
+
8
+ class HighLine
9
+
10
+ def self.Style(*args)
11
+ args = args.compact.flatten
12
+ if args.size==1
13
+ arg = args.first
14
+ if arg.is_a?(Style)
15
+ Style.list[arg.name] || Style.index(arg)
16
+ elsif arg.is_a?(::String) && arg =~ /^\e\[/ # arg is a code
17
+ if styles = Style.code_index[arg]
18
+ styles.first
19
+ else
20
+ Style.new(:code=>arg)
21
+ end
22
+ elsif style = Style.list[arg]
23
+ style
24
+ elsif HighLine.color_scheme && HighLine.color_scheme[arg]
25
+ HighLine.color_scheme[arg]
26
+ elsif arg.is_a?(Hash)
27
+ Style.new(arg)
28
+ elsif arg.to_s.downcase =~ /^rgb_([a-f0-9]{6})$/
29
+ Style.rgb($1)
30
+ elsif arg.to_s.downcase =~ /^on_rgb_([a-f0-9]{6})$/
31
+ Style.rgb($1).on
32
+ else
33
+ raise NameError, "#{arg.inspect} is not a defined Style"
34
+ end
35
+ else
36
+ name = args
37
+ Style.list[name] || Style.new(:list=>args)
38
+ end
39
+ end
40
+
41
+ class Style
42
+
43
+ def self.index(style)
44
+ if style.name
45
+ @@styles ||= {}
46
+ @@styles[style.name] = style
47
+ end
48
+ 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
53
+ end
54
+ style
55
+ end
56
+
57
+ def self.rgb_hex(*colors)
58
+ colors.map do |color|
59
+ color.is_a?(Numeric) ? '%02x'%color : color.to_s
60
+ end.join
61
+ end
62
+
63
+ def self.rgb_parts(hex)
64
+ hex.scan(/../).map{|part| part.to_i(16)}
65
+ end
66
+
67
+ def self.rgb(*colors)
68
+ hex = rgb_hex(*colors)
69
+ name = ('rgb_' + hex).to_sym
70
+ if style = list[name]
71
+ style
72
+ else
73
+ parts = rgb_parts(hex)
74
+ new(:name=>name, :code=>"\e[38;5;#{rgb_number(parts)}m", :rgb=>parts)
75
+ end
76
+ end
77
+
78
+ def self.rgb_number(*parts)
79
+ parts = parts.flatten
80
+ 16 + parts.inject(0) {|kode, part| kode*6 + (part/256.0*6.0).floor}
81
+ end
82
+
83
+ def self.ansi_rgb_to_hex(ansi_number)
84
+ raise "Invalid ANSI rgb code #{ansi_number}" unless (16..231).include?(ansi_number)
85
+ parts = (ansi_number-16).to_s(6).rjust(3,'0').scan(/./).map{|d| (d.to_i*255.0/6.0).ceil}
86
+ rgb_hex(*parts)
87
+ end
88
+
89
+ def self.list
90
+ @@styles ||= {}
91
+ end
92
+
93
+ def self.code_index
94
+ @@code_index ||= {}
95
+ end
96
+
97
+ def self.uncolor(string)
98
+ string.gsub(/\e\[\d+(;\d+)*m/, '')
99
+ end
100
+
101
+ attr_reader :name, :list
102
+ attr_accessor :rgb, :builtin
103
+
104
+ # Single color/styles have :name, :code, :rgb (possibly), :builtin
105
+ # Compound styles have :name, :list, :builtin
106
+ def initialize(defn = {})
107
+ @definition = defn
108
+ @name = defn[:name]
109
+ @code = defn[:code]
110
+ @rgb = defn[:rgb]
111
+ @list = defn[:list]
112
+ @builtin = defn[:builtin]
113
+ if @rgb
114
+ hex = self.class.rgb_hex(@rgb)
115
+ @name ||= 'rgb_' + hex
116
+ elsif @list
117
+ @name ||= @list
118
+ end
119
+ self.class.index self unless defn[:no_index]
120
+ end
121
+
122
+ def dup
123
+ self.class.new(@definition)
124
+ end
125
+
126
+ def to_hash
127
+ @definition
128
+ end
129
+
130
+ def color(string)
131
+ code + string + HighLine::CLEAR
132
+ end
133
+
134
+ def code
135
+ if @list
136
+ @list.map{|element| HighLine.Style(element).code}.join
137
+ else
138
+ @code
139
+ end
140
+ end
141
+
142
+ def red
143
+ @rgb && @rgb[0]
144
+ end
145
+
146
+ def green
147
+ @rgb && @rgb[1]
148
+ end
149
+
150
+ def blue
151
+ @rgb && @rgb[2]
152
+ end
153
+
154
+ def variant(new_name, options={})
155
+ raise "Cannot create a variant of a style list (#{inspect})" if @list
156
+ new_code = options[:code] || code
157
+ if options[:increment]
158
+ raise "Unexpected code in #{inspect}" unless new_code =~ /^(.*?)(\d+)(.*)/
159
+ new_code = $1 + ($2.to_i + options[:increment]).to_s + $3
160
+ end
161
+ new_rgb = options[:rgb] || @rgb
162
+ self.class.new(self.to_hash.merge(:name=>new_name, :code=>new_code, :rgb=>new_rgb))
163
+ end
164
+
165
+ def on
166
+ new_name = ('on_'+@name.to_s).to_sym
167
+ self.class.list[new_name] ||= variant(new_name, :increment=>10)
168
+ end
169
+
170
+ def bright
171
+ raise "Cannot create a bright variant of a style list (#{inspect})" if @list
172
+ new_name = ('bright_'+@name.to_s).to_sym
173
+ if style = self.class.list[new_name]
174
+ style
175
+ else
176
+ new_rgb = @rgb == [0,0,0] ? [128, 128, 128] : @rgb.map {|color| color==0 ? 0 : [color+128,255].min }
177
+ variant(new_name, :increment=>60, :rgb=>new_rgb)
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,186 @@
1
+ # system_extensions.rb
2
+ #
3
+ # Created by James Edward Gray II on 2006-06-14.
4
+ # Copyright 2006 Gray Productions. All rights reserved.
5
+ #
6
+ # This is Free Software. See LICENSE and COPYING for details.
7
+
8
+ require "highline/compatibility"
9
+
10
+ class HighLine
11
+ module SystemExtensions
12
+ module_function
13
+
14
+ JRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
15
+
16
+ #
17
+ # This section builds character reading and terminal size functions
18
+ # to suit the proper platform we're running on. Be warned: Here be
19
+ # dragons!
20
+ #
21
+ begin
22
+ # Cygwin will look like Windows, but we want to treat it like a Posix OS:
23
+ raise LoadError, "Cygwin is a Posix OS." if RUBY_PLATFORM =~ /\bcygwin\b/i
24
+
25
+ require "Win32API" # See if we're on Windows.
26
+
27
+ CHARACTER_MODE = "Win32API" # For Debugging purposes only.
28
+
29
+ #
30
+ # Windows savvy getc().
31
+ #
32
+ # *WARNING*: This method ignores <tt>input</tt> and reads one
33
+ # character from +STDIN+!
34
+ #
35
+ def get_character( input = STDIN )
36
+ Win32API.new("msvcrt", "_getch", [ ], "L").Call
37
+ rescue Exception
38
+ Win32API.new("crtdll", "_getch", [ ], "L").Call
39
+ end
40
+
41
+ # A Windows savvy method to fetch the console columns, and rows.
42
+ def terminal_size
43
+ m_GetStdHandle = Win32API.new( 'kernel32',
44
+ 'GetStdHandle',
45
+ ['L'],
46
+ 'L' )
47
+ m_GetConsoleScreenBufferInfo = Win32API.new(
48
+ 'kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L'
49
+ )
50
+
51
+ format = 'SSSSSssssSS'
52
+ buf = ([0] * format.size).pack(format)
53
+ stdout_handle = m_GetStdHandle.call(0xFFFFFFF5)
54
+
55
+ m_GetConsoleScreenBufferInfo.call(stdout_handle, buf)
56
+ _, _, _, _, _,
57
+ left, top, right, bottom, _, _ = buf.unpack(format)
58
+ return right - left + 1, bottom - top + 1
59
+ end
60
+ rescue LoadError # If we're not on Windows try...
61
+ begin
62
+ require "termios" # Unix, first choice termios.
63
+
64
+ CHARACTER_MODE = "termios" # For Debugging purposes only.
65
+
66
+ #
67
+ # Unix savvy getc(). (First choice.)
68
+ #
69
+ # *WARNING*: This method requires the "termios" library!
70
+ #
71
+ def get_character( input = STDIN )
72
+ return input.getbyte if input.is_a? StringIO
73
+
74
+ old_settings = Termios.getattr(input)
75
+
76
+ new_settings = old_settings.dup
77
+ new_settings.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
78
+ new_settings.c_cc[Termios::VMIN] = 1
79
+
80
+ begin
81
+ Termios.setattr(input, Termios::TCSANOW, new_settings)
82
+ input.getbyte
83
+ ensure
84
+ Termios.setattr(input, Termios::TCSANOW, old_settings)
85
+ end
86
+ end
87
+ rescue LoadError # If our first choice fails, try using ffi-ncurses.
88
+ begin
89
+ require 'ffi-ncurses' # The ffi gem is builtin to JRUBY and because stty does not
90
+ # work correctly in JRuby manually installing the ffi-ncurses
91
+ # gem is the only way to get highline to operate correctly in
92
+ # JRuby. The ncurses library is only present on unix platforms
93
+ # so this is not a solution for using highline in JRuby on
94
+ # windows.
95
+
96
+ CHARACTER_MODE = "ncurses" # For Debugging purposes only.
97
+
98
+ #
99
+ # ncurses savvy getc().
100
+ #
101
+ def get_character( input = STDIN )
102
+ FFI::NCurses.initscr
103
+ FFI::NCurses.cbreak
104
+ begin
105
+ FFI::NCurses.curs_set 0
106
+ input.getbyte
107
+ ensure
108
+ FFI::NCurses.endwin
109
+ end
110
+ end
111
+
112
+ rescue LoadError # If the ffi-ncurses choice fails, try using stty
113
+ CHARACTER_MODE = "stty" # For Debugging purposes only.
114
+
115
+ #
116
+ # Unix savvy getc(). (Second choice.)
117
+ #
118
+ # *WARNING*: This method requires the external "stty" program!
119
+ #
120
+ def get_character( input = STDIN )
121
+ raw_no_echo_mode
122
+
123
+ begin
124
+ input.getbyte
125
+ ensure
126
+ restore_mode
127
+ end
128
+ end
129
+
130
+ #
131
+ # Switched the input mode to raw and disables echo.
132
+ #
133
+ # *WARNING*: This method requires the external "stty" program!
134
+ #
135
+ def raw_no_echo_mode
136
+ @state = `stty -g`
137
+ system "stty raw -echo -icanon isig"
138
+ end
139
+
140
+ #
141
+ # Restores a previously saved input mode.
142
+ #
143
+ # *WARNING*: This method requires the external "stty" program!
144
+ #
145
+ def restore_mode
146
+ system "stty #{@state}"
147
+ end
148
+ end
149
+ end
150
+ if CHARACTER_MODE == 'ncurses'
151
+ #
152
+ # A ncurses savvy method to fetch the console columns, and rows.
153
+ #
154
+ def terminal_size
155
+ size = [80, 40]
156
+ FFI::NCurses.initscr
157
+ begin
158
+ size = FFI::NCurses.getmaxyx(stdscr).reverse
159
+ ensure
160
+ FFI::NCurses.endwin
161
+ end
162
+ size
163
+ end
164
+ elsif JRUBY
165
+ # JRuby running on Unix can fetch the number of columns and rows from the builtin Jline library
166
+ require 'java'
167
+ java_import 'jline.Terminal'
168
+ def terminal_size
169
+ java_terminal = @java_terminal || Terminal.getTerminal
170
+ [ java_terminal.getTerminalWidth, java_terminal.getTerminalHeight ]
171
+ end
172
+ else
173
+ # A Unix savvy method using stty that to fetch the console columns, and rows.
174
+ # ... stty does not work in JRuby
175
+ def terminal_size
176
+ if /solaris/ =~ RUBY_PLATFORM and
177
+ `stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/
178
+ [$2, $1].map { |c| x.to_i }
179
+ else
180
+ `stty size`.split.map { |x| x.to_i }.reverse
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end