summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Rakefile2
-rw-r--r--lib/highline.rb49
-rw-r--r--lib/highline/color_scheme.rb3
-rw-r--r--lib/highline/style.rb90
-rw-r--r--test/tc_style.rb528
-rw-r--r--test/ts_all.rb2
6 files changed, 608 insertions, 66 deletions
diff --git a/Rakefile b/Rakefile
index 39101e1..04d3c12 100644
--- a/Rakefile
+++ b/Rakefile
@@ -12,7 +12,7 @@ task :default => [:test]
Rake::TestTask.new do |test|
test.libs << "test"
- test.test_files = [ "test/ts_all.rb", "test/tc_string_extension.rb"]
+ test.test_files = [ "test/ts_all.rb"]
test.verbose = true
end
diff --git a/lib/highline.rb b/lib/highline.rb
index 19b6cd3..3c8a2c3 100644
--- a/lib/highline.rb
+++ b/lib/highline.rb
@@ -50,6 +50,13 @@ class HighLine
@@use_color
end
+ # For checking if the current version of HighLine supports RGB colors
+ # Usage: HighLine.supports_rgb_color? rescue false # rescue for compatibility with older versions
+ # Note: color usage also depends on HighLine.use_color being set
+ def self.supports_rgb_color?
+ true
+ end
+
# The setting used to disable EOF tracking.
@@track_eof = true
@@ -86,37 +93,37 @@ class HighLine
# done before the program exits!
#
- ERASE_LINE_STYLE = Style.new(:name=>'erase_line', :code=>"\e[K") # Erase the current line of terminal output
- ERASE_CHAR_STYLE = Style.new(:name=>'erase_char', :code=>"\e[P") # Erase the character under the cursor.
- CLEAR_STYLE = Style.new(:name=>'clear', :code=>"\e[0m") # Clear color settings
- RESET_STYLE = Style.new(:name=>'reset', :code=>"\e[0m") # Alias for CLEAR.
- BOLD_STYLE = Style.new(:name=>'bold', :code=>"\e[1m") # Bold; Note: bold + a color works as you'd expect,
+ ERASE_LINE_STYLE = Style.new(:name=>:erase_line, :builtin=>true, :code=>"\e[K") # Erase the current line of terminal output
+ ERASE_CHAR_STYLE = Style.new(:name=>:erase_char, :builtin=>true, :code=>"\e[P") # Erase the character under the cursor.
+ CLEAR_STYLE = Style.new(:name=>:clear, :builtin=>true, :code=>"\e[0m") # Clear color settings
+ RESET_STYLE = Style.new(:name=>:reset, :builtin=>true, :code=>"\e[0m") # Alias for CLEAR.
+ BOLD_STYLE = Style.new(:name=>:bold, :builtin=>true, :code=>"\e[1m") # Bold; Note: bold + a color works as you'd expect,
# for example bold black. Bold without a color displays
# the system-defined bold color (e.g. red on Mac iTerm)
- DARK_STYLE = Style.new(:name=>'dark', :code=>"\e[2m") # Dark; support uncommon
- UNDERLINE_STYLE = Style.new(:name=>'underline', :code=>"\e[4m") # Underline
- UNDERSCORE_STYLE = Style.new(:name=>'underscore', :code=>"\e[4m") # Alias for UNDERLINE
- BLINK_STYLE = Style.new(:name=>'blink', :code=>"\e[5m") # Blink; support uncommon
- REVERSE_STYLE = Style.new(:name=>'reverse', :code=>"\e[7m") # Reverse foreground and background
- CONCEALED_STYLE = Style.new(:name=>'concealed', :code=>"\e[8m") # Concealed; support uncommon
+ DARK_STYLE = Style.new(:name=>:dark, :builtin=>true, :code=>"\e[2m") # Dark; support uncommon
+ UNDERLINE_STYLE = Style.new(:name=>:underline, :builtin=>true, :code=>"\e[4m") # Underline
+ UNDERSCORE_STYLE = Style.new(:name=>:underscore, :builtin=>true, :code=>"\e[4m") # Alias for UNDERLINE
+ BLINK_STYLE = Style.new(:name=>:blink, :builtin=>true, :code=>"\e[5m") # Blink; support uncommon
+ REVERSE_STYLE = Style.new(:name=>:reverse, :builtin=>true, :code=>"\e[7m") # Reverse foreground and background
+ CONCEALED_STYLE = Style.new(:name=>:concealed, :builtin=>true, :code=>"\e[8m") # Concealed; support uncommon
STYLES = %w{CLEAR RESET BOLD DARK UNDERLINE UNDERSCORE BLINK REVERSE CONCEALED}
# These RGB colors are approximate; see http://en.wikipedia.org/wiki/ANSI_escape_code
- BLACK_STYLE = Style.new(:name=>'black', :code=>"\e[30m", :rgb=>[ 0, 0, 0])
- RED_STYLE = Style.new(:name=>'red', :code=>"\e[31m", :rgb=>[128, 0, 0])
- GREEN_STYLE = Style.new(:name=>'green', :code=>"\e[32m", :rgb=>[ 0,128, 0])
- BLUE_STYLE = Style.new(:name=>'blue', :code=>"\e[34m", :rgb=>[ 0, 0,128])
- YELLOW_STYLE = Style.new(:name=>'yellow', :code=>"\e[33m", :rgb=>[128,128, 0])
- MAGENTA_STYLE = Style.new(:name=>'magenta', :code=>"\e[35m", :rgb=>[128, 0,128])
- CYAN_STYLE = Style.new(:name=>'cyan', :code=>"\e[36m", :rgb=>[ 0,128,128])
+ BLACK_STYLE = Style.new(:name=>:black, :builtin=>true, :code=>"\e[30m", :rgb=>[ 0, 0, 0])
+ RED_STYLE = Style.new(:name=>:red, :builtin=>true, :code=>"\e[31m", :rgb=>[128, 0, 0])
+ GREEN_STYLE = Style.new(:name=>:green, :builtin=>true, :code=>"\e[32m", :rgb=>[ 0,128, 0])
+ BLUE_STYLE = Style.new(:name=>:blue, :builtin=>true, :code=>"\e[34m", :rgb=>[ 0, 0,128])
+ YELLOW_STYLE = Style.new(:name=>:yellow, :builtin=>true, :code=>"\e[33m", :rgb=>[128,128, 0])
+ MAGENTA_STYLE = Style.new(:name=>:magenta, :builtin=>true, :code=>"\e[35m", :rgb=>[128, 0,128])
+ CYAN_STYLE = Style.new(:name=>:cyan, :builtin=>true, :code=>"\e[36m", :rgb=>[ 0,128,128])
# On Mac OSX Terminal, white is actually gray
- WHITE_STYLE = Style.new(:name=>'white', :code=>"\e[37m", :rgb=>[192,192,192])
+ WHITE_STYLE = Style.new(:name=>:white, :builtin=>true, :code=>"\e[37m", :rgb=>[192,192,192])
# Alias for WHITE, since WHITE is actually a light gray on Macs
- GRAY_STYLE = Style.new(:name=>'gray', :code=>"\e[37m", :rgb=>[192,192,192])
+ GRAY_STYLE = Style.new(:name=>:gray, :builtin=>true, :code=>"\e[37m", :rgb=>[192,192,192])
# On Mac OSX Terminal, this is black foreground, or bright white background.
# Also used as base for RGB colors, if available
- NONE_STYLE = Style.new(:name=>'none', :code=>"\e[38m", :rgb=>[ 0, 0, 0])
+ NONE_STYLE = Style.new(:name=>:none, :builtin=>true, :code=>"\e[38m", :rgb=>[ 0, 0, 0])
BASIC_COLORS = %w{BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE GRAY NONE}
diff --git a/lib/highline/color_scheme.rb b/lib/highline/color_scheme.rb
index ead095b..3148bd0 100644
--- a/lib/highline/color_scheme.rb
+++ b/lib/highline/color_scheme.rb
@@ -73,7 +73,8 @@ class HighLine
# Allow the scheme to be set like a Hash.
def []=( color_tag, constants )
- @scheme[to_symbol(color_tag)] = constants.map { |c| to_constant(c) }
+ # @scheme[to_symbol(color_tag)] = constants.map { |c| to_constant(c) }
+ @scheme[to_symbol(color_tag)] = HighLine::Style.new(:name=>color_tag.to_sym, :list=>constants, :no_index=>true)
end
private
diff --git a/lib/highline/style.rb b/lib/highline/style.rb
index 7b4a354..22cebc5 100644
--- a/lib/highline/style.rb
+++ b/lib/highline/style.rb
@@ -7,6 +7,7 @@
#
# This is Free Software. See LICENSE and COPYING for details
+# TODO Re-engineer this to not use hashie/mash
require 'rubygems'
require 'hashie/mash'
require 'pp'
@@ -14,30 +15,29 @@ require 'pp'
class HighLine
def self.Style(*args)
- args = args.flatten
+ args = args.compact.flatten
if args.size==1
arg = args.first
if arg.is_a?(Style)
- name = arg.name
- Style.list[name] || Style.new(arg)
+ Style.list[arg.name] || Style.index(arg)
elsif arg.is_a?(::String) && arg =~ /^\e\[/ # arg is a code
- if style = Style.code_index[arg]
- style
+ if styles = Style.code_index[arg]
+ styles.first
else
- Style.new(:name=>'_code_'+arg[2..-1].gsub(/\W+/,'_'), :code=>arg)
+ Style.new(:code=>arg)
end
- elsif style = Style.list[arg.to_s.downcase]
+ elsif style = Style.list[arg]
style
elsif HighLine.color_scheme && HighLine.color_scheme[arg]
- Style(HighLine.color_scheme[arg])
+ HighLine.color_scheme[arg]
elsif arg.is_a?(Hash)
Style.new(arg)
- elsif arg.to_s.downcase =~ /^rgb_(\d{6})$/
+ elsif arg.to_s.downcase =~ /^rgb_([a-f0-9]{6})$/
Style.rgb($1)
- elsif arg.to_s.downcase =~ /^on_rgb_(\d{6})$/
+ elsif arg.to_s.downcase =~ /^on_rgb_([a-f0-9]{6})$/
Style.rgb($1).on
else
- raise NameError, "Don't know how to convert #{arg.inspect} to a Style"
+ raise NameError, "#{arg.inspect} is not a defined Style"
end
else
name = args
@@ -47,15 +47,16 @@ class HighLine
class Style < Hashie::Mash
- def self.define(style)
- name = style.name.to_s.downcase
- @@styles ||= {}
- @@styles[name] ||= Style.new(nil, nil, :no_define=>true)
- @@styles[name].merge! style
+ def self.index(style)
+ if style.name
+ @@styles ||= {}
+ @@styles[style.name] = style
+ end
if !style.list?
@@code_index ||= {}
- @@code_index[style.code] ||= Style.new(nil, nil, :no_define=>true)
- @@code_index[style.code].merge! style
+ @@code_index[style.code] ||= []
+ @@code_index[style.code].reject!{|indexed_style| indexed_style.name == style.name}
+ @@code_index[style.code] << style
end
style
end
@@ -72,16 +73,20 @@ class HighLine
def self.rgb(*colors)
hex = rgb_hex(*colors)
- name = 'rgb_' + hex
+ name = ('rgb_' + hex).to_sym
if style = list[name]
style
else
parts = rgb_parts(hex)
- rgb_number = 16 + parts.inject(0) {|kode, part| kode*6 + (part/256.0*6.0).floor}
- new(:name=>name, :code=>"\e[38;5;#{rgb_number}m", :rgb=>parts)
+ new(:name=>name, :code=>"\e[38;5;#{rgb_number(parts)}m", :rgb=>parts)
end
end
+ def self.rgb_number(*parts)
+ parts = parts.flatten
+ 16 + parts.inject(0) {|kode, part| kode*6 + (part/256.0*6.0).floor}
+ end
+
def self.list
@@styles ||= {}
end
@@ -99,16 +104,16 @@ class HighLine
# For a style (like :blink): name, code
# For a compound style (like :underline, :red): list
- def initialize(hsh = nil, default = nil, options={}, &blk)
- super(hsh, default, &blk)
+ def initialize(defn = {}, default=nil, &blk)
+ super
if rgb
hex = self.class.rgb_hex(rgb)
rgb = self.class.rgb_parts(hex)
- name ||= 'rgb_' + hex
- else
- name ||= list
+ self.name ||= 'rgb_' + hex
+ elsif list?
+ self.name ||= list
end
- self.class.define self unless options[:no_define]
+ self.class.index self unless defn[:no_index]
end
def color(string)
@@ -135,31 +140,30 @@ class HighLine
rgb && rgb[2]
end
- def bumped(name, increment)
- new_style = self.dup
- new_style.name = name
- raise "Unexpected code in #{self.inspect}" unless code =~ /^(.*?)(\d+)(.*)/
- new_style.code = $1 + ($2.to_i + increment).to_s + $3
- self.class.define new_style
+ def variant(new_name, options={})
+ raise "Cannot create a variant of a style list (#{inspect})" if list?
+ new_code = options[:code] || code
+ if options[:increment]
+ raise "Unexpected code in #{inspect}" unless new_code =~ /^(.*?)(\d+)(.*)/
+ new_code = $1 + ($2.to_i + options[:increment]).to_s + $3
+ end
+ new_rgb = options[:rgb] || rgb
+ new_style = self.class.new(self.to_hash.merge(:name=>new_name, :code=>new_code, :rgb=>new_rgb))
end
def on
- new_name = 'on_'+name
- self.class.list[new_name] ||= bumped(new_name, 10)
+ new_name = ('on_'+name.to_s).to_sym
+ self.class.list[new_name] ||= variant(new_name, :increment=>10)
end
def bright
- new_name = 'bright_'+name
+ raise "Cannot create a bright variant of a style list (#{inspect})" if list?
+ new_name = ('bright_'+name.to_s).to_sym
if style = self.class.list[new_name]
style
else
- new_style = bumped(new_name, 60)
- if self.rgb == [0,0,0]
- new_style.rgb = [128, 128, 128]
- else
- new_style.rgb = self.rgb.map {|color| color==0 ? 0 : 255 }
- end
- new_style
+ new_rgb = rgb == [0,0,0] ? [128, 128, 128] : rgb.map {|color| color==0 ? 0 : [color+128,255].min }
+ variant(new_name, :increment=>60, :rgb=>new_rgb)
end
end
end
diff --git a/test/tc_style.rb b/test/tc_style.rb
new file mode 100644
index 0000000..1e5fc2e
--- /dev/null
+++ b/test/tc_style.rb
@@ -0,0 +1,528 @@
+#!/usr/local/bin/ruby -w
+
+# tc_style.rb
+#
+# Created by Richard LeBer on 2011-06-11.
+#
+# This is Free Software. See LICENSE and COPYING for details.
+
+require "test/unit"
+
+require "highline"
+require "stringio"
+
+class TestStyle < Test::Unit::TestCase
+
+ def setup
+ @input = StringIO.new
+ @output = StringIO.new
+ @terminal = HighLine.new(@input, @output)
+ @style1 = HighLine::Style.new(:name=>:foo, :code=>"\e[99m", :rgb=>[1,2,3])
+ @style2 = HighLine::Style.new(:name=>:lando, :code=>"\e[98m")
+ @style3 = HighLine::Style.new(:name=>[:foo, :lando], :list=>[:foo, :lando])
+ @style4 = HighLine::Style(:rgb_654321)
+ end
+
+ def teardown
+ # HighLine::Style.clear_index
+ end
+
+ def test_style_method
+ # Retrieve a style from an existing Style (no new Style created)
+ new_style = @style1.dup # This will replace @style1 in the indexes
+ s = HighLine.Style(@style1)
+ assert_instance_of HighLine::Style, s
+ assert_same new_style, s # i.e. s===the latest style created, but not the one searched for
+
+ # Retrieve a style from a new Style (no new Style created)
+ s2 = HighLine::Style.new(:name=>:bar, :code=>"\e[97m")
+ s = HighLine.Style(s2)
+ assert_instance_of HighLine::Style, s
+ assert_same s2, s
+
+ # Create a builtin style from an existing ANSI escape string
+ s = HighLine.Style("\e[1m")
+ assert_instance_of HighLine::Style, s
+ assert_nil s.list
+ assert_equal "\e[1m", s.code
+ assert_equal :bold, s.name
+
+ # Create a builtin style from a new ANSI escape string
+ s = HighLine.Style("\e[96m")
+ assert_instance_of HighLine::Style, s
+ assert_nil s.list
+ assert_equal "\e[96m", s.code
+
+ # Create a builtin style from a symbol
+ s = HighLine.Style(:red)
+ assert_instance_of HighLine::Style, s
+ assert_nil s.list
+ assert_equal :red, s.name
+
+ # Retrieve an existing style by name (no new Style created)
+ s = HighLine.Style(@style2.name)
+ assert_instance_of HighLine::Style, s
+ assert_same @style2, s
+
+ # See below for color scheme tests
+
+ # Create style from a Hash
+ s = HighLine.Style(:name=>:han, :code=>"blah", :rgb=>'phooey')
+ assert_instance_of HighLine::Style, s
+ assert_equal :han, s.name
+ assert_equal "blah", s.code
+ assert_equal "phooey", s.rgb
+
+ # Create style from an RGB foreground color code
+ s = HighLine.Style(:rgb_1f2e3d)
+ assert_instance_of HighLine::Style, s
+ assert_equal :rgb_1f2e3d, s.name
+ assert_equal "\e[38;5;23m", s.code # Trust me; more testing below
+ assert_equal [31,46,61], s.rgb # 0x1f==31, 0x2e==46, 0x3d=61
+
+ # Create style from an RGB background color code
+ s = HighLine.Style(:on_rgb_1f2e3d)
+ assert_instance_of HighLine::Style, s
+ assert_equal :on_rgb_1f2e3d, s.name
+ assert_equal "\e[48;5;23m", s.code # Trust me; more testing below
+ assert_equal [31,46,61], s.rgb # 0x1f==31, 0x2e==46, 0x3d=61
+
+ # Create a style list
+ s1 = HighLine.Style(:bold, :red)
+ assert_instance_of HighLine::Style, s1
+ assert_equal [:bold, :red], s1.list
+
+ # Find an existing style list
+ s2 = HighLine.Style(:bold, :red)
+ assert_instance_of HighLine::Style, s2
+ assert_same s1, s2
+
+ # Create a style list with nils
+ s1 = HighLine.Style(:underline, nil, :blue)
+ assert_instance_of HighLine::Style, s1
+ assert_equal [:underline, :blue], s1.list
+
+ # Raise an error for an undefined style
+ assert_raise(::NameError) { HighLine.Style(:fubar) }
+ end
+
+ def test_no_color_scheme
+ HighLine.color_scheme = nil
+ assert_raise(::NameError) { HighLine.Style(:critical) }
+ end
+
+ def test_with_color_scheme
+ HighLine.color_scheme = HighLine::SampleColorScheme.new
+ s = HighLine.Style(:critical)
+ assert_instance_of HighLine::Style, s
+ assert_equal :critical, s.name
+ assert_equal [:yellow, :on_red], s.list
+ end
+
+ def test_builtin_foreground_colors_defined
+ HighLine::COLORS.each do |color|
+ style = HighLine.const_get(color+'_STYLE')
+ assert_instance_of HighLine::Style, style
+ assert_equal color.downcase.to_sym, style.name
+ assert style.builtin
+ code = HighLine.const_get(color)
+ assert_instance_of String, code, "Bad code for #{color}"
+ end
+ end
+
+ def test_builtin_background_colors_defined
+ HighLine::COLORS.each do |color|
+ style = HighLine.const_get('ON_' + color+'_STYLE')
+ assert_instance_of HighLine::Style, style
+ assert_equal ('ON_'+color).downcase.to_sym, style.name
+ assert style.builtin
+ code = HighLine.const_get('ON_' + color)
+ assert_instance_of String, code, "Bad code for ON_#{color}"
+ end
+ end
+
+ def test_builtin_styles_defined
+ HighLine::STYLES.each do |style_constant|
+ style = HighLine.const_get(style_constant+'_STYLE')
+ assert_instance_of HighLine::Style, style
+ assert_equal style_constant.downcase.to_sym, style.name
+ assert style.builtin
+ code = HighLine.const_get(style_constant)
+ assert_instance_of String, code, "Bad code for #{style_constant}"
+ end
+ end
+
+ def test_index
+ # Add a Style with a new name and code
+ assert_nil HighLine::Style.list[:s1]
+ assert_nil HighLine::Style.code_index['foo']
+ s1 = HighLine::Style.new(:name=>:s1, :code=>'foo')
+ assert_not_nil HighLine::Style.list[:s1]
+ assert_same s1, HighLine::Style.list[:s1]
+ assert_equal :s1, HighLine::Style.list[:s1].name
+ assert_equal 'foo', HighLine::Style.list[:s1].code
+ styles = HighLine::Style.list.size
+ codes = HighLine::Style.code_index.size
+ assert_instance_of Array, HighLine::Style.code_index['foo']
+ assert_equal 1, HighLine::Style.code_index['foo'].size
+ assert_same s1, HighLine::Style.code_index['foo'].last
+ assert_equal :s1, HighLine::Style.code_index['foo'].last.name
+ assert_equal 'foo', HighLine::Style.code_index['foo'].last.code
+
+ # Add another Style with a new name and code
+ assert_nil HighLine::Style.list[:s2]
+ assert_nil HighLine::Style.code_index['bar']
+ s2 = HighLine::Style.new(:name=>:s2, :code=>'bar')
+ assert_equal styles+1, HighLine::Style.list.size
+ assert_equal codes+1, HighLine::Style.code_index.size
+ assert_not_nil HighLine::Style.list[:s2]
+ assert_same s2, HighLine::Style.list[:s2]
+ assert_equal :s2, HighLine::Style.list[:s2].name
+ assert_equal 'bar', HighLine::Style.list[:s2].code
+ assert_instance_of Array, HighLine::Style.code_index['bar']
+ assert_equal 1, HighLine::Style.code_index['bar'].size
+ assert_same s2, HighLine::Style.code_index['bar'].last
+ assert_equal :s2, HighLine::Style.code_index['bar'].last.name
+ assert_equal 'bar', HighLine::Style.code_index['bar'].last.code
+
+ # Add a Style with an existing name
+ s3_before = HighLine::Style.list[:s2]
+ assert_not_nil HighLine::Style.list[:s2]
+ assert_nil HighLine::Style.code_index['baz']
+ s3 = HighLine::Style.new(:name=>:s2, :code=>'baz')
+ assert_not_same s2, s3
+ assert_not_same s3_before, s3
+ assert_equal styles+1, HighLine::Style.list.size
+ assert_equal codes+2, HighLine::Style.code_index.size
+ assert_not_nil HighLine::Style.list[:s2]
+ assert_same s3, HighLine::Style.list[:s2]
+ assert_not_same s2, HighLine::Style.list[:s2]
+ assert_equal :s2, HighLine::Style.list[:s2].name
+ assert_equal 'baz', HighLine::Style.list[:s2].code
+ assert_instance_of Array, HighLine::Style.code_index['baz']
+ assert_equal 1, HighLine::Style.code_index['baz'].size
+ assert_same s3, HighLine::Style.code_index['baz'].last
+ assert_equal :s2, HighLine::Style.code_index['baz'].last.name
+ assert_equal 'baz', HighLine::Style.code_index['baz'].last.code
+
+ # Add a Style with an existing code
+ assert_equal 1, HighLine::Style.code_index['baz'].size
+ s4 = HighLine::Style.new(:name=>:s4, :code=>'baz')
+ assert_equal styles+2, HighLine::Style.list.size
+ assert_equal codes+2, HighLine::Style.code_index.size
+ assert_not_nil HighLine::Style.list[:s4]
+ assert_same s4, HighLine::Style.list[:s4]
+ assert_equal :s4, HighLine::Style.list[:s4].name
+ assert_equal 'baz', HighLine::Style.list[:s4].code
+ assert_equal 2, HighLine::Style.code_index['baz'].size
+ assert_same s3, HighLine::Style.code_index['baz'].first # Unchanged from last time
+ assert_equal :s2, HighLine::Style.code_index['baz'].first.name # Unchanged from last time
+ assert_equal 'baz', HighLine::Style.code_index['baz'].first.code # Unchanged from last time
+ assert_same s4, HighLine::Style.code_index['baz'].last
+ assert_equal :s4, HighLine::Style.code_index['baz'].last.name
+ assert_equal 'baz', HighLine::Style.code_index['baz'].last.code
+ end
+
+ def test_rgb_hex
+ assert_equal "abcdef", HighLine::Style.rgb_hex("abcdef")
+ assert_equal "ABCDEF", HighLine::Style.rgb_hex("AB","CD","EF")
+ assert_equal "010203", HighLine::Style.rgb_hex(1,2,3)
+ assert_equal "123456", HighLine::Style.rgb_hex(18,52,86)
+ end
+
+ def test_rgb_parts
+ assert_equal [1,2,3], HighLine::Style.rgb_parts("010203")
+ assert_equal [18,52,86], HighLine::Style.rgb_parts("123456")
+ end
+
+ def test_rgb
+ s = HighLine::Style.rgb(1, 2, 3)
+ assert_instance_of HighLine::Style, s
+ assert_equal :rgb_010203, s.name
+ assert_equal [1,2,3], s.rgb
+ assert_equal "\e[38;5;16m", s.code
+
+ s = HighLine::Style.rgb("12", "34","56")
+ assert_instance_of HighLine::Style, s
+ assert_equal :rgb_123456, s.name
+ assert_equal [0x12, 0x34, 0x56], s.rgb
+ assert_equal "\e[38;5;24m", s.code
+
+ s = HighLine::Style.rgb("abcdef")
+ assert_instance_of HighLine::Style, s
+ assert_equal :rgb_abcdef, s.name
+ assert_equal [0xab, 0xcd, 0xef], s.rgb
+ assert_equal "\e[38;5;189m", s.code
+ end
+
+ def test_rgb_number
+ # ANSI RGB coding splits 0..255 into equal sixths, and then the
+ # red green and blue are encoded in base 6, plus 16, i.e.
+ # 16 + 36*(red_level) + 6*(green_level) + blue_level,
+ # where each of red_level, green_level, and blue_level are in
+ # the range 0..5
+
+ # This test logic works because 42 is just below 1/6 of 255,
+ # and 43 is just above
+
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 0, 0, 0)
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 0, 0, 42)
+ assert_equal 16 + 0*36 + 0*6 + 1, HighLine::Style.rgb_number( 0, 0, 43)
+
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 0, 42, 0)
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 0, 42, 42)
+ assert_equal 16 + 0*36 + 0*6 + 1, HighLine::Style.rgb_number( 0, 42, 43)
+
+ assert_equal 16 + 0*36 + 1*6 + 0, HighLine::Style.rgb_number( 0, 43, 0)
+ assert_equal 16 + 0*36 + 1*6 + 0, HighLine::Style.rgb_number( 0, 43, 42)
+ assert_equal 16 + 0*36 + 1*6 + 1, HighLine::Style.rgb_number( 0, 43, 43)
+
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 42, 0, 0)
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 42, 0, 42)
+ assert_equal 16 + 0*36 + 0*6 + 1, HighLine::Style.rgb_number( 42, 0, 43)
+
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 42, 42, 0)
+ assert_equal 16 + 0*36 + 0*6 + 0, HighLine::Style.rgb_number( 42, 42, 42)
+ assert_equal 16 + 0*36 + 0*6 + 1, HighLine::Style.rgb_number( 42, 42, 43)
+
+ assert_equal 16 + 0*36 + 1*6 + 0, HighLine::Style.rgb_number( 42, 43, 0)
+ assert_equal 16 + 0*36 + 1*6 + 0, HighLine::Style.rgb_number( 42, 43, 42)
+ assert_equal 16 + 0*36 + 1*6 + 1, HighLine::Style.rgb_number( 42, 43, 43)
+
+ assert_equal 16 + 1*36 + 0*6 + 0, HighLine::Style.rgb_number( 43, 0, 0)
+ assert_equal 16 + 1*36 + 0*6 + 0, HighLine::Style.rgb_number( 43, 0, 42)
+ assert_equal 16 + 1*36 + 0*6 + 1, HighLine::Style.rgb_number( 43, 0, 43)
+
+ assert_equal 16 + 1*36 + 0*6 + 0, HighLine::Style.rgb_number( 43, 42, 0)
+ assert_equal 16 + 1*36 + 0*6 + 0, HighLine::Style.rgb_number( 43, 42, 42)
+ assert_equal 16 + 1*36 + 0*6 + 1, HighLine::Style.rgb_number( 43, 42, 43)
+
+ assert_equal 16 + 1*36 + 1*6 + 0, HighLine::Style.rgb_number( 43, 43, 0)
+ assert_equal 16 + 1*36 + 1*6 + 0, HighLine::Style.rgb_number( 43, 43, 42)
+ assert_equal 16 + 1*36 + 1*6 + 1, HighLine::Style.rgb_number( 43, 43, 43)
+
+ assert_equal 16 + 5*36 + 5*6 + 5, HighLine::Style.rgb_number(255,255,255)
+ end
+
+ def test_list
+ list_size = HighLine::Style.list.size
+ # Add a Style with a new name and code
+ assert_nil HighLine::Style.list[:s5]
+ s5 = HighLine::Style.new(:name=>:s5, :code=>'foo')
+ assert_not_nil HighLine::Style.list[:s5]
+ assert_equal list_size+1, HighLine::Style.list.size
+ assert_not_nil HighLine::Style.list[:s5]
+ assert_same s5, HighLine::Style.list[:s5]
+ assert_equal :s5, HighLine::Style.list[:s5].name
+ assert_equal 'foo', HighLine::Style.list[:s5].code
+
+ # Add another Style with a new name and code
+ assert_nil HighLine::Style.list[:s6]
+ s6 = HighLine::Style.new(:name=>:s6, :code=>'bar')
+ assert_equal list_size+2, HighLine::Style.list.size
+ assert_not_nil HighLine::Style.list[:s6]
+ assert_same s6, HighLine::Style.list[:s6]
+ assert_equal :s6, HighLine::Style.list[:s6].name
+ assert_equal 'bar', HighLine::Style.list[:s6].code
+
+ # Add a Style with an existing name
+ s7 = HighLine::Style.new(:name=>:s6, :code=>'baz')
+ assert_equal list_size+2, HighLine::Style.list.size # No net addition to list
+ assert_not_nil HighLine::Style.list[:s6]
+ assert_same s7, HighLine::Style.list[:s6] # New one replaces old one
+ assert_not_same s6, HighLine::Style.list[:s6]
+ assert_equal :s6, HighLine::Style.list[:s6].name
+ assert_equal 'baz', HighLine::Style.list[:s6].code
+ end
+
+ def test_code_index
+ list_size = HighLine::Style.code_index.size
+
+ # Add a Style with a new name and code
+ assert_nil HighLine::Style.code_index['chewie']
+ s8 = HighLine::Style.new(:name=>:s8, :code=>'chewie')
+ assert_equal list_size+1, HighLine::Style.code_index.size
+ assert_instance_of Array, HighLine::Style.code_index['chewie']
+ assert_equal 1, HighLine::Style.code_index['chewie'].size
+ assert_equal :s8, HighLine::Style.code_index['chewie'].last.name
+ assert_equal 'chewie', HighLine::Style.code_index['chewie'].last.code
+
+ # Add another Style with a new name and code
+ assert_nil HighLine::Style.code_index['c3po']
+ s9 = HighLine::Style.new(:name=>:s9, :code=>'c3po')
+ assert_equal list_size+2, HighLine::Style.code_index.size
+ assert_instance_of Array, HighLine::Style.code_index['c3po']
+ assert_equal 1, HighLine::Style.code_index['c3po'].size
+ assert_equal :s9, HighLine::Style.code_index['c3po'].last.name
+ assert_equal 'c3po', HighLine::Style.code_index['c3po'].last.code
+
+ # Add a Style with an existing code
+ assert_equal 1, HighLine::Style.code_index['c3po'].size
+ s10 = HighLine::Style.new(:name=>:s10, :code=>'c3po')
+ assert_equal list_size+2, HighLine::Style.code_index.size
+ assert_equal 2, HighLine::Style.code_index['c3po'].size
+ assert_equal :s10, HighLine::Style.code_index['c3po'].last.name
+ assert_equal 'c3po', HighLine::Style.code_index['c3po'].last.code
+ end
+
+ def test_uncolor
+ # Normal color
+ assert_equal "This should be reverse underlined magenta!\n",
+ HighLine::Style.uncolor("This should be \e[7m\e[4m\e[35mreverse underlined magenta\e[0m!\n" )
+
+ # RGB color
+ assert_equal "This should be rgb_906030!\n",
+ HighLine::Style.uncolor("This should be \e[38;5;137mrgb_906030\e[0m!\n" )
+ end
+
+ def test_color
+ assert_equal "\e[99mstring\e[0m", @style1.color("string") # simple style
+ assert_equal "\e[99m\e[98mstring\e[0m", @style3.color("string") # Style list
+ end
+
+ def test_code
+ assert_equal "\e[99m", @style1.code # simple style
+ assert_equal "\e[99m\e[98m", @style3.code # Style list
+ end
+
+ def test_red
+ assert_equal 0x65, @style4.red
+ assert_equal 0, HighLine::Style(:none).red # Probably reliable
+ assert_equal 0, HighLine::Style(:black).red # Probably reliable
+ assert_equal 255, HighLine::Style(:bright_magenta).red # Seems to be reliable
+ assert_equal 255, HighLine::Style(:on_none).red # Probably reliable
+ end
+
+ def test_green
+ assert_equal 0x43, @style4.green
+ assert_equal 0, HighLine::Style(:none).green # Probably reliable
+ assert_equal 0, HighLine::Style(:black).green # Probably reliable
+ assert 240 <= HighLine::Style(:bright_cyan).green # Probably reliable
+ assert_equal 255, HighLine::Style(:on_none).green # Probably reliable
+ end
+
+ def test_blue
+ assert_equal 0x21, @style4.blue
+ assert_equal 0, HighLine::Style(:none).blue # Probably reliable
+ assert_equal 0, HighLine::Style(:black).blue # Probably reliable
+ assert_equal 255, HighLine::Style(:bright_blue).blue # Probably reliable
+ assert_equal 255, HighLine::Style(:on_none).blue # Probably reliable
+ end
+
+ def test_builtin
+ assert HighLine::Style(:red).builtin
+ assert !@style1.builtin
+ end
+
+ def test_variant
+ style1_name = @style1.name
+ style1_code = @style1.code
+ style1_rgb = @style1.rgb
+
+ s1 = @style1.variant(:new_foo1, :code=>'abracadabra')
+ assert_instance_of HighLine::Style, s1
+ assert_not_same @style1, s1 # This is a copy
+ assert_equal :new_foo1, s1.name # Changed
+ assert_equal 'abracadabra', s1.code # Changed
+ assert_equal [1,2,3], s1.rgb # Unchanged
+
+ s2 = @style1.variant(:new_foo2, :increment=>-15)
+ assert_instance_of HighLine::Style, s2
+ assert_not_same @style1, s2 # This is a copy
+ assert_equal :new_foo2, s2.name # Changed
+ assert_equal "\e[84m", s2.code # 99 (original code) - 15
+ assert_equal [1,2,3], s2.rgb # Unchanged
+
+ s3 = @style1.variant(:new_foo3, :code=>"\e[55m", :increment=>15)
+ assert_instance_of HighLine::Style, s3
+ assert_not_same @style1, s3 # This is a copy
+ assert_equal :new_foo3, s3.name # Changed
+ assert_equal "\e[70m", s3.code # 99 (new code) + 15
+ assert_equal [1,2,3], s3.rgb # Unchanged
+
+ s4 = @style1.variant(:new_foo4, :code=>"\e[55m", :increment=>15, :rgb=>"blah")
+ assert_instance_of HighLine::Style, s4
+ assert_not_same @style1, s4 # This is a copy
+ assert_equal :new_foo4, s4.name # Changed
+ assert_equal "\e[70m", s4.code # 99 (new code) + 15
+ assert_equal 'blah', s4.rgb # Changed
+
+ s5 = @style1.variant(:new_foo5)
+ assert_instance_of HighLine::Style, s5
+ assert_not_same @style1, s5 # This is a copy
+ assert_equal :new_foo5, s5.name # Changed
+ assert_equal "\e[99m", s5.code # Unchanged
+ assert_equal [1,2,3], s5.rgb # Unchanged
+
+ # No @style1's have been harmed in the running of this test
+ assert_equal style1_name, @style1.name
+ assert_equal style1_code, @style1.code
+ assert_equal style1_rgb, @style1.rgb
+
+ assert_raise(::RuntimeError) { @style3.variant(:new_foo6) } # Can't create a variant of a list style
+ end
+
+ def test_on
+ style1_name = @style1.name
+ style1_code = @style1.code
+ style1_rgb = @style1.rgb
+
+ s1 = @style1.on
+ assert_instance_of HighLine::Style, s1
+ assert_not_same @style1, s1 # This is a copy
+ assert_equal :on_foo, s1.name # Changed
+ assert_equal "\e[109m", s1.code # Changed
+ assert_equal [1,2,3], s1.rgb # Unchanged
+
+ # No @style1's have been harmed in the running of this test
+ assert_equal style1_name, @style1.name
+ assert_equal style1_code, @style1.code
+ assert_equal style1_rgb, @style1.rgb
+
+ assert_raise(::RuntimeError) { @style3.on } # Can't create a variant of a list style
+ end
+
+ def test_bright
+ style1_name = @style1.name
+ style1_code = @style1.code
+ style1_rgb = @style1.rgb
+
+ s1 = @style1.bright
+ assert_instance_of HighLine::Style, s1
+ assert_not_same @style1, s1 # This is a copy
+ assert_equal :bright_foo, s1.name # Changed
+ assert_equal "\e[159m", s1.code # Changed
+ assert_equal [129,130,131], s1.rgb # Changed
+
+ # No @style1's have been harmed in the running of this test
+ assert_equal style1_name, @style1.name
+ assert_equal style1_code, @style1.code
+ assert_equal style1_rgb, @style1.rgb
+
+ s2_base = HighLine::Style.new(:name=>:leia, :code=>"\e[92m", :rgb=>[0,0,14])
+ s2 = s2_base.bright
+ assert_instance_of HighLine::Style, s2
+ assert_not_same s2_base, s2 # This is a copy
+ assert_equal :bright_leia, s2.name # Changed
+ assert_equal "\e[152m", s2.code # Changed
+ assert_equal [0,0,142], s2.rgb # Changed
+
+ s3_base = HighLine::Style.new(:name=>:luke, :code=>"\e[93m", :rgb=>[20,21,0])
+ s3 = s3_base.bright
+ assert_instance_of HighLine::Style, s3
+ assert_not_same s3_base, s3 # This is a copy
+ assert_equal :bright_luke, s3.name # Changed
+ assert_equal "\e[153m", s3.code # Changed
+ assert_equal [148,149,0], s3.rgb # Changed
+
+ s4_base = HighLine::Style.new(:name=>:r2d2, :code=>"\e[94m", :rgb=>[0,0,0])
+ s4 = s4_base.bright
+ assert_instance_of HighLine::Style, s4
+ assert_not_same s4_base, s4 # This is a copy
+ assert_equal :bright_r2d2, s4.name # Changed
+ assert_equal "\e[154m", s4.code # Changed
+ assert_equal [128,128,128], s4.rgb # Changed; special case
+
+ assert_raise(::RuntimeError) { @style3.bright } # Can't create a variant of a list style
+ end
+end
diff --git a/test/ts_all.rb b/test/ts_all.rb
index 6b93b82..bd9665b 100644
--- a/test/ts_all.rb
+++ b/test/ts_all.rb
@@ -12,5 +12,7 @@ require "test/unit"
require "tc_highline"
require "tc_import"
require "tc_menu"
+require "tc_style"
require "tc_color_scheme"
require "tc_string_highline"
+require "tc_string_extension" \ No newline at end of file