1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
# frozen_string_literal: true
module Rainbow
class Color
attr_reader :ground
def self.build(ground, values)
unless [1, 3].include?(values.size)
raise ArgumentError,
"Wrong number of arguments for color definition, should be 1 or 3"
end
color = values.size == 1 ? values.first : values
case color
# NOTE: Properly handle versions before/after Ruby 2.4.0.
# Ruby 2.4+ unifies Fixnum & Bignum into Integer.
# However previous versions would still use Fixnum.
# To avoid missing `Fixnum` input, call `0.class` which would
# return either `Integer` or `Fixnum`.
when 0.class
Indexed.new(ground, color)
when Symbol
if Named.color_names.include?(color)
Named.new(ground, color)
elsif X11Named.color_names.include?(color)
X11Named.new(ground, color)
else
raise ArgumentError,
"Unknown color name, valid names: " +
(Named.color_names + X11Named.color_names).join(', ')
end
when Array
RGB.new(ground, *color)
when String
RGB.new(ground, *parse_hex_color(color))
end
end
def self.parse_hex_color(hex)
unless hex =~ /^#?[a-f0-9]{6}/i
raise ArgumentError,
"Invalid hexadecimal RGB triplet. Valid format: /^#?[a-f0-9]{6}/i"
end
hex = hex.sub(/^#/, '')
r = hex[0..1].to_i(16)
g = hex[2..3].to_i(16)
b = hex[4..5].to_i(16)
[r, g, b]
end
class Indexed < Color
attr_reader :num
def initialize(ground, num)
@ground = ground
@num = num
end
def codes
code = num + (ground == :foreground ? 30 : 40)
[code]
end
end
class Named < Indexed
NAMES = {
black: 0,
red: 1,
green: 2,
yellow: 3,
blue: 4,
magenta: 5,
cyan: 6,
white: 7,
default: 9
}.freeze
def self.color_names
NAMES.keys
end
def self.valid_names
color_names.join(', ')
end
def initialize(ground, name)
unless Named.color_names.include?(name)
raise ArgumentError,
"Unknown color name, valid names: #{self.class.valid_names}"
end
super(ground, NAMES[name])
end
end
class RGB < Indexed
attr_reader :r, :g, :b
def self.to_ansi_domain(value)
(6 * (value / 256.0)).to_i
end
def initialize(ground, *values)
if values.min.negative? || values.max > 255
raise ArgumentError, "RGB value outside 0-255 range"
end
super(ground, 8)
@r, @g, @b = values
end
def codes
super + [5, code_from_rgb]
end
private
def code_from_rgb
16 + self.class.to_ansi_domain(r) * 36 +
self.class.to_ansi_domain(g) * 6 +
self.class.to_ansi_domain(b)
end
end
class X11Named < RGB
include X11ColorNames
def self.color_names
NAMES.keys
end
def self.valid_names
color_names.join(', ')
end
def initialize(ground, name)
unless X11Named.color_names.include?(name)
raise ArgumentError,
"Unknown color name, valid names: #{self.class.valid_names}"
end
super(ground, *NAMES[name])
end
end
end
end
|