chromate 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ed103af7c44122bf148349eb167f49fb28f0e0ef
4
+ data.tar.gz: 6f4eced71e79c497aca419d5a3586456e16c8fb1
5
+ SHA512:
6
+ metadata.gz: 27925f1b9e358d43d8d7868a28cb0514c5e4b0c658f85359b1460ce702eafe7ac2e6a7c776d92667d4d723bf9d8b70d043e270600035c8e6e14d5d3fa0c28073
7
+ data.tar.gz: 4871e670910a5b0ec06fa2b2459428eea5f98e9737806eb79927887f7f3670b7593ae9f6532fa1a1f1639333773dddaf671461157717cff90bcfd65c460b3e11
@@ -0,0 +1,12 @@
1
+ require 'chromate/version'
2
+ require 'chromate/cache'
3
+ require 'chromate/rgb'
4
+ require 'chromate/hex'
5
+ require 'chromate/lab'
6
+ require 'chromate/effect'
7
+ require 'chromate/color'
8
+ require 'chromate/effect_set'
9
+ require 'chromate/effects'
10
+ require 'chromate/formattable'
11
+
12
+ require 'chromate/core_ext/string'
@@ -0,0 +1,6 @@
1
+ module Chromate
2
+
3
+ # A cache mapping RGB arrays to their Color representations
4
+ CACHE = {}
5
+
6
+ end
@@ -0,0 +1,368 @@
1
+ module Chromate
2
+
3
+ #
4
+ # The `Color` class is used to represent a terminal color in the range 0..255.
5
+ # Colors are powerful tools, and have a multitude of convenience methods to
6
+ # make working with them easier.
7
+ #
8
+ # Color Models
9
+ # ============
10
+ # All colors have a so-called 'color model' (accessible via the `color_model`
11
+ # attribute). The color model of a color determines how it will be escaped.
12
+ # The following color models are possible:
13
+ #
14
+ # - Colors in the range 0..7 have a color model of 8. These colors are
15
+ # always escaped as single-integer values in the ranges 30..37 and
16
+ # 40..47 for foregrounds and backgrounds, respectively.
17
+ # - Colors in the range 8..15 have a color model of 16. These colors
18
+ # can be escaped in two ways, with single-integer values in the
19
+ # ranges 90..97 and 100..107, for foreground and background,
20
+ # respectively, or with additional bold sequences. Which route is
21
+ # taken depends on the compliancy setting; single-integer values are
22
+ # non-compliant, while bold sequences are. The compliancy setting
23
+ # may be specified in three ways, each overriding the last: via the
24
+ # class attribute on `Color`, via the instance attribute by the same
25
+ # name, and in the method call as a second (optional parameter).
26
+ # The default at all levels is non-compliancy.
27
+ # - Colors in the range 16..255 have a color model of 256. These
28
+ # colors are always escaped as xterm-256 escape sequences of the
29
+ # form 38;5;x for foreground and 48;5;x for background, where x is
30
+ # the actual color value.
31
+ #
32
+ # Converting from Other Formats
33
+ # =============================
34
+ # The `Color` class features a powerful approximation mechanism, allowing the
35
+ # creation of colors from arbitrary RGB values, which may be specified either
36
+ # in RGB using {::from_rgb} or in hex using {::from_hex}. When either of these
37
+ # methods are used, the closest matching terminal color code will be found
38
+ # automatically, using the CIE 1976 delta-E algorithm. This operation is quite
39
+ # a bit slower compared to using exact color values, but it must be done only
40
+ # once, as all values are cached after first use and kept until the end of
41
+ # program execution.
42
+ #
43
+ # Making New Colors
44
+ # =================
45
+ # If you __really__ want to make a new color, you may do so by calling the
46
+ # provided constructor. However, this is wasteful -- there is, after all, a
47
+ # finite set of possible colors. Moreover, all of these colors already exist
48
+ # as members of the `COLORS` constant. That's all well and good if you have
49
+ # the raw color code, which can be used as an index for the `COLORS` array,
50
+ # but what if you don't? Well, then {::[]} is your new best friend! This
51
+ # method accepts the full range of color representations, including raw color
52
+ # codes, names, hex strings, and RGB values. The following example showcases
53
+ # all of the various types that {::[]} accepts:
54
+ #
55
+ # ```ruby
56
+ # # The following all return the 'black' color
57
+ # Color[0]
58
+ # Color['black']
59
+ # Color['#000000']
60
+ # Color[:black]
61
+ # Color[[0, 0, 0]]
62
+ # Color[0, 0, 0]
63
+ #
64
+ # # Malformed inputs
65
+ # Color[-1] # => ArgumentError: bad color code: -1
66
+ # Color[256] # => ArgumentError: bad color code: 256
67
+ # Color['foo'] # => nil
68
+ # Color['#'] # => ArgumentError: invalid hex string: #
69
+ # Color[:foo] # => nil
70
+ # ```
71
+ #
72
+ # Note that when getting a color from a name, `nil` will be returned if no
73
+ # color with that name exists, rather than throwing an error.
74
+ #
75
+ class Color < Effect
76
+
77
+ # @return [Integer] the color model of the color (either 8, 16, or 256)
78
+ attr_reader :color_model
79
+
80
+ # @return [Boolean] the default compliancy setting for {#to_fg} and {#to_bg}
81
+ attr_accessor :compliant
82
+
83
+ class << self
84
+ # @return [Boolean] the global default compliancy setting
85
+ attr_accessor :compliant
86
+
87
+ def compliant=(what)
88
+ @compliant = what
89
+ COLORS.each { |c| c.compliant = what }
90
+ end
91
+ end
92
+ @compliant = false
93
+
94
+ #
95
+ # Create a new Color object representing the specified color code. The color
96
+ # model will be inferred automatically based on the range of `value` (8 if
97
+ # it's less than 8, 16 if it's less than 16, and 256 otherwise).
98
+ # @param value [Numeric] the xterm color code of the new color
99
+ #
100
+ # @return [Color]
101
+ def initialize(value, compliant = Color.compliant)
102
+ if COLOR_NAMES.key?(value)
103
+ super(COLOR_NAMES[value])
104
+ else
105
+ super(value)
106
+ end
107
+
108
+ @compliant = compliant
109
+ @escape = :fg
110
+ @color_model = if @value < 8
111
+ 8
112
+ elsif @value < 16
113
+ 16
114
+ else
115
+ 256
116
+ end
117
+ end
118
+
119
+ #
120
+ # Get an existing Color object representing the specified color code, hex
121
+ # value, color name, or RGB array.
122
+ # @param value [String,Symbol,Array]
123
+ #
124
+ # @return [Color]
125
+ def self.[](value, g = nil, b = nil)
126
+ case value
127
+ when Fixnum
128
+ if value > 255 or value < 0
129
+ raise ArgumentError, "bad color code: #{value}"
130
+ else
131
+ COLORS[value]
132
+ end
133
+ when String
134
+ if value[0] == '#'
135
+ Color.from_hex(value)
136
+ elsif COLOR_NAMES.key?(value.intern)
137
+ COLORS[COLOR_NAMES[value.intern]]
138
+ else
139
+ nil
140
+ end
141
+ when Symbol
142
+ if COLOR_NAMES.key?(value)
143
+ COLORS[COLOR_NAMES[value]]
144
+ else
145
+ nil
146
+ end
147
+ when Array
148
+ Color.from_rgb(*value)
149
+ else
150
+ if g.nil? and b.nil?
151
+ raise TypeError, "don't know what to do with a #{value.class}"
152
+ else
153
+ Color.from_rgb(value, g, b)
154
+ end
155
+ end
156
+ end
157
+
158
+ #
159
+ # Get a Color object representing the specified hex string.
160
+ # @param hex [String] a string of the form #XXXXXX
161
+ #
162
+ # @return [Color]
163
+ def self.from_hex(hex)
164
+ if Hex::PATTERN =~ hex
165
+ Color.from_rgb(*hex.scan(Hex::BYTE).map { |b| b.to_i(16) })
166
+ else
167
+ raise ArgumentError, "invalid hex string: #{hex}"
168
+ end
169
+ end
170
+
171
+ #
172
+ # Get a Color object representing the specified color in RGB space.
173
+ # @note The `g` and `b` arguments default to the value passed in for `r`, so
174
+ # that if you have a monochromatic color (e.g., r, g, and b are the same),
175
+ # you may pass a single value.
176
+ # @param r [Integer] the red component
177
+ # @param g [Integer] the green component
178
+ # @param b [Integer] the blue component
179
+ #
180
+ # @example Getting a monochromatic color
181
+ # Color.from_rgb(0) # <=> Color.from_rgb(0, 0, 0)
182
+ #
183
+ # @return [Color]
184
+ def self.from_rgb(r, g = r, b = r)
185
+ ary = [r, g, b]
186
+ if RGB::COLORS.include?(ary)
187
+ COLORS[RGB::COLORS.index(ary)]
188
+ elsif CACHE.include?(ary)
189
+ CACHE[ary]
190
+ else
191
+ lab = RGB.to_lab(ary)
192
+ code = Lab::COLORS.index(Lab::COLORS.sort do |lab1, lab2|
193
+ Lab.difference(lab, lab1) <=> Lab.difference(lab, lab2)
194
+ end.first)
195
+ CACHE[ary] = COLORS[code]
196
+ COLORS[code]
197
+ end
198
+ end
199
+
200
+ #
201
+ # Is this color supported by the host environment?
202
+ #
203
+ # @return [Boolean]
204
+ def supported?
205
+ SUPPORTED_COLORS.include?(self)
206
+ end
207
+
208
+ #
209
+ # Is this color greyscale?
210
+ #
211
+ # @return [Boolean]
212
+ def greyscale?
213
+ GREYSCALE_COLORS.include?(self)
214
+ end
215
+
216
+ #
217
+ # Escape as a foreground SGR escape sequence.
218
+ # @param compliant [Boolean] whether to use standards-compliant bold
219
+ # sequences or the non-standard 90-97 range
220
+ #
221
+ # @return [String] an escape sequence setting the foreground to the color
222
+ def to_fg(compliant = @compliant)
223
+ case @color_model
224
+ when 8
225
+ "\e[#{30 + @value}m"
226
+ when 16
227
+ if compliant
228
+ "\e[#{30 + @value - 8};1m"
229
+ else
230
+ "\e[#{90 + @value - 8}m"
231
+ end
232
+ when 256
233
+ "\e[38;5;#{@value}m"
234
+ end
235
+ end
236
+
237
+ #
238
+ # Convert to a Color that escapes to a foreground by default.
239
+ #
240
+ # @return [Color]
241
+ def as_fg
242
+ @escape = :fg
243
+ self
244
+ end
245
+
246
+ #
247
+ # Does this color represent a foreground?
248
+ #
249
+ # @return [Boolean]
250
+ def fg?
251
+ @escape == :fg
252
+ end
253
+
254
+ #
255
+ # Escape as a background SGR escape sequence.
256
+ # @param compliant [Boolean] whether to use standards-compliant bold
257
+ # sequences or the non-standard 100-107 range
258
+ #
259
+ # @return [String] an escape sequence setting the foreground to the color
260
+ def to_bg(compliant = @compliant)
261
+ case @color_model
262
+ when 8
263
+ "\e[#{40 + @value}m"
264
+ when 16
265
+ if compliant
266
+ "\e[#{40 + @value - 8};1m"
267
+ else
268
+ "\e[#{100 + @value - 8}m"
269
+ end
270
+ when 256
271
+ "\e[48;5;#{@value}m"
272
+ end
273
+ end
274
+
275
+ #
276
+ # Convert to a Color that escapes to a background by default.
277
+ #
278
+ # @return [Color]
279
+ def as_bg
280
+ @escape = :bg
281
+ self
282
+ end
283
+
284
+ #
285
+ # Does this color represent a background?
286
+ #
287
+ # @return [Boolean]
288
+ def bg?
289
+ @escape == :bg
290
+ end
291
+
292
+ #
293
+ # Escape as an SGR escape sequence.
294
+ #
295
+ # @return [String] an escape sequence of the form "\e[1;2;3;...m"
296
+ def escape
297
+ case @escape
298
+ when :fg
299
+ to_fg
300
+ when :bg
301
+ to_bg
302
+ end
303
+ end
304
+
305
+ #
306
+ # Get the name of the color, if it exists.
307
+ #
308
+ # @return [Symbol]
309
+ def name
310
+ if COLOR_NAMES.value?(@value)
311
+ COLOR_NAMES.find { |k, v| v == @value }.first
312
+ end
313
+ end
314
+
315
+ def inspect
316
+ if name.nil?
317
+ "#<Color: (#{to_rgb.join(',')})>"
318
+ else
319
+ "#<Color: #{name}>"
320
+ end
321
+ end
322
+
323
+ #
324
+ # Get the RGB value represented by the color.
325
+ #
326
+ # @return [<Integer>] an array containing r, g, and b values, in that order
327
+ def to_rgb
328
+ RGB::COLORS[@value]
329
+ end
330
+
331
+ #
332
+ # Get the hex value represented by the color.
333
+ #
334
+ # @return [String] a string of the form #XXXXXX
335
+ def to_hex
336
+ '#' + Hex::COLORS[@value]
337
+ end
338
+
339
+ #
340
+ # Get the red component of the color.
341
+ #
342
+ # @return [Integer]
343
+ def red
344
+ RGB::COLORS[@value][0]
345
+ end
346
+ alias_method :r, :red
347
+
348
+ #
349
+ # Get the green component of the color.
350
+ #
351
+ # @return [Integer]
352
+ def green
353
+ RGB::COLORS[@value][1]
354
+ end
355
+ alias_method :g, :green
356
+
357
+ #
358
+ # Get the blue component of the color.
359
+ #
360
+ # @return [Integer]
361
+ def blue
362
+ RGB::COLORS[@value][2]
363
+ end
364
+ alias_method :b, :blue
365
+
366
+ end
367
+
368
+ end
@@ -0,0 +1,14 @@
1
+ class String
2
+
3
+ alias_method :old_plus, :+
4
+ private :old_plus
5
+
6
+ def +(other)
7
+ if other.is_a?(Chromate::Effect) or other.is_a?(Chromate::EffectSet)
8
+ self + other.escape
9
+ else
10
+ old_plus(other)
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,98 @@
1
+ module Chromate
2
+
3
+ #
4
+ # The `Effect` class is used to represent a generic escape sequences,
5
+ # providing a standardized escape mechanism. You may convert an effect to
6
+ # either a string, in which case it will be escaped as an SGR escape sequence,
7
+ # or an integer, in which case it will yield its internal value. You may also
8
+ # explicitly escape an effect by calling {#escape} on it.
9
+ #
10
+ class Effect
11
+
12
+ #
13
+ # Create a new effect with the specified value.
14
+ # @param value [Fixnum]
15
+ #
16
+ # @return [Effect]
17
+ def initialize(value)
18
+ unless value.is_a?(Numeric)
19
+ raise TypeError, "cannot create #{self.class} from #{value.class}"
20
+ end
21
+
22
+ @value = value.to_i
23
+ end
24
+
25
+ #
26
+ # Get the effect with the specified name.
27
+ # @param value [String,Symbol] the name of an effect
28
+ #
29
+ # @return [Effect]
30
+ def self.[](value)
31
+ if value.is_a?(Symbol) or value.is_a?(String)
32
+ EFFECTS[value.intern]
33
+ else
34
+ raise TypeError, "don't know what to do with a #{value.class}"
35
+ end
36
+ end
37
+
38
+ #
39
+ # Escape as an SGR escape sequence.
40
+ #
41
+ # @return [String] an escape sequence of the form "\e[1;2;3;...m"
42
+ def escape
43
+ "\e[#{@value}m"
44
+ end
45
+
46
+ #
47
+ # Get the name of this effect, if it exists.
48
+ #
49
+ # @return [Symbol]
50
+ def name
51
+ if EFFECTS.value?(self)
52
+ EFFECTS.find { |k, v| v == self }.first
53
+ end
54
+ end
55
+
56
+ # @return [String]
57
+ def inspect
58
+ if name.nil?
59
+ "#<Effect: #{@value}>"
60
+ else
61
+ "#<Effect: #{name}>"
62
+ end
63
+ end
64
+
65
+ #
66
+ # Yield the internal value.
67
+ #
68
+ # @return [Integer]
69
+ def to_i
70
+ @value
71
+ end
72
+
73
+ # @return [String]
74
+ def to_s
75
+ escape
76
+ end
77
+
78
+ # @return [Boolean]
79
+ def ==(other)
80
+ to_i == other.to_i
81
+ end
82
+
83
+ def +(other)
84
+ case other
85
+ when EffectSet
86
+ other.add(self)
87
+ when Effect
88
+ EffectSet.new([self, other])
89
+ when String
90
+ escape + other
91
+ else
92
+ raise TypeError, "cannot add #{other.class} to #{self.class}"
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ end
@@ -0,0 +1,139 @@
1
+ require 'set'
2
+
3
+ module Chromate
4
+
5
+ #
6
+ # A wrapper over the `Set` class, useful for maintaining and emitting
7
+ # collections of unrelated effects. Only effects may be added to an `EffectSet`,
8
+ # but some other types may be coerced into an effect. The coercion rules are
9
+ # as follows:
10
+ #
11
+ # 1. If the value is an `Effect`, it will remain as-is.
12
+ # 2. If the value is an `Array`, it is unambiguously in reference to a color,
13
+ # specifically an RGB array, and will be parsed as such.
14
+ # 3. If the value is a `Symbol`, it is in reference to a name of some sort.
15
+ # Names of effects will be checked before names of colors. If no effect
16
+ # or color exists with this name, an `ArgumentError` will be thrown.
17
+ # 4. If the value is a `String`, it may either be a name of some sort or a
18
+ # hex color string. If the value begins with a '#', it will be parsed as
19
+ # a hex string. Otherwise, it will be parsed according to rule 3.
20
+ # 5. If the value is a `Numeric`, it may either be a raw effect or a color
21
+ # code. If the value is negative or greater than 255, an error will be
22
+ # thrown. Otherwise, if the value is not a valid effect code, the value
23
+ # is unambiguously a color code and will be parsed as such. Otherwise,
24
+ # there is insufficient information available to determine course of
25
+ # action. The target class must be explicitly specified, or it will
26
+ # default to `Effect`. (Target class must be a subclass of `Effect`, or
27
+ # `Effect` itself.) As a special case, 0 is considered an invalid effect
28
+ # code, as it would make little sense to include an 'off' sequence in an
29
+ # unordered collection of effects. As such, adding 0 to an EffectSet will
30
+ # add the color black, not the off sequence.
31
+ #
32
+ class EffectSet < Set
33
+
34
+ #
35
+ # Construct a new `EffectSet` from an existing enumerable object containing
36
+ # effects. If non-effects are encountered, they will be parsed as per the
37
+ # rules of `EffectSet`.
38
+ # @param enum [Enumerable] an enumerable object containing colors
39
+ #
40
+ # @return [EffectSet]
41
+ def initialize(enum = [])
42
+ super(enum) { |what| parse_member(what) }
43
+ end
44
+
45
+ #
46
+ # Construct a new `EffectSet` from an array of effects. If non-effects are
47
+ # encountered, they will be parsed as per the rules of `EffectSet`.
48
+ # @param codes [<Chromate::Effect,Integer,<Integer>,Symbol,String>]
49
+ #
50
+ # @return [EffectSet]
51
+ def self.[](*codes)
52
+ new(codes)
53
+ end
54
+
55
+ #
56
+ # Generate a single escape sequence that is an agglomeration of the
57
+ # escape sequences of the individual effects within the set.
58
+ #
59
+ # @return [String]
60
+ def escape
61
+ "\e[" + map do |effect|
62
+ /\e\[(.*)m/.match(effect.escape)[1]
63
+ end.join(';') + 'm'
64
+ end
65
+ alias_method :to_s, :escape
66
+
67
+ #
68
+ # Add an element to the set. If it is a non-effect, it will be parsed as
69
+ # per the rules of `EffectSet`. An optional second parameter indicates the
70
+ # class of `Effect` to use if passing in an ambiguous effect code.
71
+ # @param what [Chromate::Effect,Integer,<Integer>,Symbol,String]
72
+ # @param klass [Class]
73
+ #
74
+ # @return [EffectSet] the same effect set with `what` added in to it
75
+ def add(what, klass = Effect)
76
+ super(parse_member(what, klass))
77
+ end
78
+
79
+ def +(other)
80
+ case other
81
+ when EffectSet
82
+ other.add(self)
83
+ when Effect
84
+ add(other)
85
+ when String
86
+ escape + other
87
+ else
88
+ raise TypeError, "cannot add #{other.class} to #{self.class}"
89
+ end
90
+ end
91
+
92
+ # @return [String]
93
+ def inspect
94
+ sprintf('#<EffectSet: {%s}>', to_a.inspect[1..-2])
95
+ end
96
+
97
+ private
98
+
99
+ def parse_member(what, klass = Effect)
100
+ unless klass <= Effect
101
+ raise TypeError, "#{klass.name} is not a sublcass of Effect"
102
+ end
103
+
104
+ case what
105
+ when Effect
106
+ what
107
+ when Numeric
108
+ return COLORS[0] if what == 0
109
+ if what < 0 or what > 255
110
+ raise ArgumentError, "invalid effect or color code: #{what}"
111
+ elsif VALID_EFFECTS.include?(what)
112
+ klass.new(what.to_i)
113
+ else
114
+ Color.new(what.to_i)
115
+ end
116
+ when Array
117
+ Color.from_rgb(*what)
118
+ when Symbol
119
+ if EFFECTS.include?(what)
120
+ EFFECTS[what]
121
+ elsif COLOR_NAMES.include?(what)
122
+ COLORS[COLOR_NAMES[what]]
123
+ else
124
+ raise ArgumentError, "no such effect or color: #{what}"
125
+ end
126
+ when String
127
+ if what[0] == '#'
128
+ Color.from_hex(what)
129
+ else
130
+ parse_member(what.intern)
131
+ end
132
+ else
133
+ raise TypeError, "cannot create Chromate::Effect from #{what.class}"
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+ end
@@ -0,0 +1,65 @@
1
+ module Chromate
2
+
3
+ # Commonly supported effect sequences
4
+ EFFECTS = {
5
+ :off => Effect.new(0),
6
+ :bold => Effect.new(1),
7
+ :underline => Effect.new(4),
8
+ :blink => Effect.new(5),
9
+ :negative => Effect.new(7)
10
+ }
11
+
12
+ # Valid effect sequences
13
+ VALID_EFFECTS = EFFECTS.map { |n, e| e.to_i }
14
+
15
+ OFF = EFFECTS[:off]
16
+ const_set(:Effects, Module.new do
17
+ Chromate::EFFECTS.each do |name, effect|
18
+ const_set(name.to_s.upcase, effect)
19
+ end
20
+ end)
21
+
22
+ # Names for common colors
23
+ COLOR_NAMES = {
24
+ :black => 0,
25
+ :dark_red => 1,
26
+ :dark_green => 2,
27
+ :dark_yellow => 3,
28
+ :dark_blue => 4,
29
+ :dark_magenta => 5,
30
+ :dark_cyan => 6,
31
+ :silver => 7,
32
+ :gray => 8,
33
+ :grey => 8,
34
+ :red => 9,
35
+ :green => 10,
36
+ :yellow => 11,
37
+ :blue => 12,
38
+ :magenta => 13,
39
+ :cyan => 14,
40
+ :white => 15
41
+ }
42
+
43
+ # All xterm-256 colors
44
+ COLORS = (0..255).map { |i| Color.new(i) }
45
+
46
+ # Greyscale colors
47
+ GREYSCALE_COLORS = COLORS[231..255] +
48
+ [COLORS[0], COLORS[7], COLORS[8], COLORS[15]]
49
+
50
+ # Colors supported by the host environment
51
+ SUPPORTED_COLORS = case RbConfig::CONFIG['host_os']
52
+ when /darwin|linux|arch|solaris|sunos|(free|net|open)bsd/i
53
+ COLORS[0..`tput colors`.to_i - 1]
54
+ when /mswin|windows/i
55
+ begin
56
+ require 'win32console'
57
+ COLORS[0..15]
58
+ rescue LoadError
59
+ []
60
+ end
61
+ else
62
+ []
63
+ end
64
+
65
+ end
@@ -0,0 +1,71 @@
1
+ module Chromate
2
+
3
+ #
4
+ # The `Formattable` module allows any class easy access to Chromate formatting,
5
+ # so long as it provides an `effects` method, which is expected to return an
6
+ # `EffectSet`.
7
+ #
8
+ module Formattable
9
+
10
+ #
11
+ # Introduce a format attribute. Each format attribute comes with two
12
+ # methods, which generally differ only by addition of a '?' character (
13
+ # although this behavior can be overriden). The first method sets the format
14
+ # attribute with the given name, and the second queries whether it is set.
15
+ # @param name [Symbol] the name of an attribute
16
+ # @param question_name [Symbol] the name of the method to query whether the
17
+ # attribute is set
18
+ #
19
+ # @api private
20
+ def self.format_attr(name, question_name = name.to_s + '?')
21
+ if EFFECTS.include?(name)
22
+ module_eval(<<-EOF
23
+ define_method :#{name} do
24
+ effects << Effect[:#{name}]
25
+ self
26
+ end
27
+
28
+ define_method :#{question_name} do
29
+ effects.include?(Effect[:#{name}])
30
+ end
31
+ EOF
32
+ )
33
+ else
34
+ raise ArgumentError, "no such effect: #{name}"
35
+ end
36
+ end
37
+ class << self; private :format_attr; end
38
+
39
+ format_attr :bold
40
+ format_attr :underline, :underlined?
41
+
42
+ #
43
+ # Set the foreground and return self.
44
+ # @param what [Object] an object describing the foreground color (see
45
+ # {Chromate::Color::[]})
46
+ #
47
+ # @return [Formattable] self
48
+ def fg(what)
49
+ effects << Color[what]
50
+ self
51
+ end
52
+
53
+ #
54
+ # Set the background and return self.
55
+ # @param what [Object] an object describing the background color (see
56
+ # {Chromate::Color::[]})
57
+ #
58
+ # @return [Formattable] self
59
+ def bg(what)
60
+ effects << Color[what].as_bg
61
+ self
62
+ end
63
+
64
+ # @return [String]
65
+ def to_s
66
+ effects + self + OFF
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,44 @@
1
+ module Chromate
2
+
3
+ module Hex
4
+
5
+ # A single hex byte, i.e., two valid hexadecimal numbers
6
+ BYTE = /[0-9A-F]{2}/i
7
+
8
+ # A CSS-style hex string, of the form #XXXXXX (case-insensitive), where X is
9
+ # a hexadecimal number
10
+ PATTERN = /#(#{BYTE})(#{BYTE})(#{BYTE})/io
11
+
12
+ # Hex string representations of the 256 xterm colors
13
+ COLORS = %w(
14
+ 000000 800000 008000 808000 000080 800080 008080 c0c0c0 808080 ff0000
15
+ 00ff00 ffff00 0000ff ff00ff 00ffff ffffff 000000 00005f 000087 0000af
16
+ 0000d7 0000ff 005f00 005f5f 005f87 005faf 005fd7 005fff 008700 00875f
17
+ 008787 0087af 0087d7 0087ff 00af00 00af5f 00af87 00afaf 00afd7 00afff
18
+ 00d700 00d75f 00d787 00d7af 00d7d7 00d7ff 00ff00 00ff5f 00ff87 00ffaf
19
+ 00ffd7 00ffff 5f0000 5f005f 5f0087 5f00af 5f00d7 5f00ff 5f5f00 5f5f5f
20
+ 5f5f87 5f5faf 5f5fd7 5f5fff 5f8700 5f875f 5f8787 5f87af 5f87d7 5f87ff
21
+ 5faf00 5faf5f 5faf87 5fafaf 5fafd7 5fafff 5fd700 5fd75f 5fd787 5fd7af
22
+ 5fd7d7 5fd7ff 5fff00 5fff5f 5fff87 5fffaf 5fffd7 5fffff 870000 87005f
23
+ 870087 8700af 8700d7 8700ff 875f00 875f5f 875f87 875faf 875fd7 875fff
24
+ 878700 87875f 878787 8787af 8787d7 8787ff 87af00 87af5f 87af87 87afaf
25
+ 87afd7 87afff 87d700 87d75f 87d787 87d7af 87d7d7 87d7ff 87ff00 87ff5f
26
+ 87ff87 87ffaf 87ffd7 87ffff af0000 af005f af0087 af00af af00d7 af00ff
27
+ af5f00 af5f5f af5f87 af5faf af5fd7 af5fff af8700 af875f af8787 af87af
28
+ af87d7 af87ff afaf00 afaf5f afaf87 afafaf afafd7 afafff afd700 afd75f
29
+ afd787 afd7af afd7d7 afd7ff afff00 afff5f afff87 afffaf afffd7 afffff
30
+ d70000 d7005f d70087 d700af d700d7 d700ff d75f00 d75f5f d75f87 d75faf
31
+ d75fd7 d75fff d78700 d7875f d78787 d787af d787d7 d787ff dfaf00 dfaf5f
32
+ dfaf87 dfafaf dfafdf dfafff dfdf00 dfdf5f dfdf87 dfdfaf dfdfdf dfdfff
33
+ dfff00 dfff5f dfff87 dfffaf dfffdf dfffff ff0000 ff005f ff0087 ff00af
34
+ ff00df ff00ff ff5f00 ff5f5f ff5f87 ff5faf ff5fdf ff5fff ff8700 ff875f
35
+ ff8787 ff87af ff87df ff87ff ffaf00 ffaf5f ffaf87 ffafaf ffafdf ffafff
36
+ ffdf00 ffdf5f ffdf87 ffdfaf ffdfdf ffdfff ffff00 ffff5f ffff87 ffffaf
37
+ ffffdf ffffff 080808 121212 1c1c1c 262626 303030 3a3a3a 444444 4e4e4e
38
+ 585858 626262 6c6c6c 767676 808080 8a8a8a 949494 9e9e9e a8a8a8 b2b2b2
39
+ bcbcbc c6c6c6 d0d0d0 dadada e4e4e4 eeeeee
40
+ )
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,281 @@
1
+ module Chromate
2
+
3
+ module Lab
4
+
5
+ # L*a*b* array representations of the 256 xterm colors
6
+ COLORS = [
7
+ [ 0.0, 0.0, 0.0],
8
+ [ 0.46573992598472813, 2.088717407442653, 0.7359554408427227],
9
+ [ 1.5661371650822282, -3.1994053792742116, 2.286912750078296],
10
+ [ 2.03187709106696, -1.1106879718315725, 3.022868190921024],
11
+ [ 0.1580585921287927, 1.1106870278938807, -3.022867813345936],
12
+ [ 0.6237985181135244, 3.199404435336492, -2.286912372503208],
13
+ [ 1.7241957572110245, -2.088718351380331, -0.7359550632676404],
14
+ [ 5.368312865335966,-2.3139277438577466e-06, 9.255710975430986e-07],
15
+ [ 2.1899356831957526, -9.439377057773868e-07, 3.775750823109547e-07],
16
+ [ 2.1702682120302335, 9.733065044192912, 3.429426187489948],
17
+ [ 7.2979307021415885, -14.908680584676814, 10.656621363709961],
18
+ [ 9.386516414015183, -4.836292441189285, 13.945215654378117],
19
+ [ 0.7365259429070754, 5.1756111418960336, -14.030418942944955],
20
+ [ 2.906794154937309, 14.90867618608896, -10.577468187682026],
21
+ [ 8.034374445289192, -9.732715133472695, -3.170796457047925],
22
+ [ 10.0284167860891,-3.7397147878426296e-06, 1.495885920688167e-06],
23
+ [ 0.0, 0.0, 0.0],
24
+ [ 0.08347787161759257, 0.5866039161370046, -1.5965128364159253],
25
+ [ 0.17750795822573195, 1.2473588679607768, -3.3948366001899046],
26
+ [ 0.31486836800315743, 2.212598550480893, -6.021852037641395],
27
+ [ 0.49992911286044617, 3.5130312945475946, -9.561135550220607],
28
+ [ 0.7365259429070754, 5.1756111418960336, -14.030418942944955],
29
+ [ 0.8271476763233778, -1.689750287577299, 1.207821772802542],
30
+ [ 0.9106255479409704, -1.1031463714402805, -0.3886910636133778],
31
+ [ 1.0046556345491098, -0.4423914196165224, -2.187014827387351],
32
+ [ 1.1420160443265353, 0.522848262903608, -4.814030264838859],
33
+ [ 1.327076789183824, 1.8232810069702954, -8.353313777418059],
34
+ [ 1.5636736192304532, 3.485860854318748, -12.806567152228022],
35
+ [ 1.758852883167851, -3.5930973999098725, 2.568321072833574],
36
+ [ 1.8423307547854435, -3.006493483772868, 0.9718082364176539],
37
+ [ 1.9363608413935829, -2.3457385319490958, -0.8265155273563196],
38
+ [ 2.0737212511710084, -1.3804988494289656, -3.453530964807822],
39
+ [ 2.258781996028297, -0.0800661053622781, -6.992814477387027],
40
+ [ 2.4953788260749263, 1.5825137419861746, -11.425760671238855],
41
+ [ 3.1199003268149355, -6.373532351418895, 4.5557566702606795],
42
+ [ 3.2033781984325316, -5.786928435281904, 2.959243833844755],
43
+ [ 3.2974082850406674, -5.126173483458133, 1.1609200700707756],
44
+ [ 3.4347686948180964, -4.160933800938002, -1.4660953673807153],
45
+ [ 3.619829439675385, -2.8605010568713145, -5.005378879959915],
46
+ [ 3.856426269722011, -1.197921209522848, -9.404496602590317],
47
+ [ 4.953590646431547, -10.119512463062835, 7.233357243902772],
48
+ [ 5.037068518049139, -9.532908546925817, 5.636844407486841],
49
+ [ 5.131098604657275, -8.872153595102045, 3.8385206437128616],
50
+ [ 5.268459014434704, -7.9069139125819285, 1.2115052062613652],
51
+ [ 5.453519759291993, -6.606481168515227, -2.3277783063178403],
52
+ [ 5.690116589338622, -4.943901321166788, -6.6737925931023625],
53
+ [ 7.2979307021415885, -14.908680584676814, 10.656621363709961],
54
+ [ 7.381408573759181, -14.322076668539797, 9.06010852729403],
55
+ [ 7.47543866036732, -13.661321716716039, 7.261784763520057],
56
+ [ 7.612799070144746, -12.696082034195907, 4.634769326068556],
57
+ [ 7.797859815002038, -11.395649290129233, 1.0954858134893664],
58
+ [ 8.034374445289192, -9.732715133472695, -3.170796457047925],
59
+ [ 0.24597826176295712, 1.1031458729042072, 0.38869126302781276],
60
+ [ 0.3294561333805497, 1.6897497890412116, -1.2078215733881126],
61
+ [ 0.4234862199886855, 2.3505047408649977, -3.0061453371620916],
62
+ [ 0.5608466297661145, 3.315744423385114, -5.633160774613588],
63
+ [ 0.7459073746234033, 4.616177167451829, -9.172444287192793],
64
+ [ 0.9825042046700325, 6.278757014800254, -13.639257157211764],
65
+ [ 1.0731259380863314, -0.5866044146730642, 1.5965130358303437],
66
+ [ 1.1566038097039275, -4.985360735343392e-07, 1.9941442941373566e-07],
67
+ [ 1.2506338963120633, 0.6607544532877124, -1.798323564359544],
68
+ [ 1.3879943060894924, 1.6259941358078152, -4.42533900181104],
69
+ [ 1.573055050946781, 2.9264268798745166, -7.964622514390252],
70
+ [ 1.8096518809934068, 4.589006727222969, -12.415097205484948],
71
+ [ 2.004831144930808, -2.4899515270056654, 2.9570123358613865],
72
+ [ 2.0883090165484006, -1.9033476108686609, 1.3604994994454611],
73
+ [ 2.1823391031565365, -1.2425926590448748, -0.4378242643285124],
74
+ [ 2.3196995129339655, -0.2773529765247723, -3.064839701780009],
75
+ [ 2.504760257791254, 1.023079767541929, -6.60412321435922],
76
+ [ 2.7413570878378835, 2.6856596148903678, -11.033952108865302],
77
+ [ 3.3658785885778926, -5.270386478514688, 4.944447933288481],
78
+ [ 3.449356460195485, -4.683782562377684, 3.3479350968725674],
79
+ [ 3.5433865468036245, -4.0230276105539255, 1.549611333098594],
80
+ [ 3.68074695658105, -3.057787928033795, -1.0774041043529137],
81
+ [ 3.8658077014383387, -1.7573551839670936, -4.616687616932113],
82
+ [ 4.102404531484968, -0.09477533661865489, -9.012208836891894],
83
+ [ 5.1995689081945, -9.0163665901586, 7.622048506930568],
84
+ [ 5.283046779812096, -8.429762674021624, 6.025535670514653],
85
+ [ 5.377076866420232, -7.769007722197838, 4.227211906740674],
86
+ [ 5.514437276197661, -6.803768039677721, 1.600196469289178],
87
+ [ 5.69949802105495, -5.50333529561102, -1.9390870432900331],
88
+ [ 5.936094851101579, -3.840755448262581, -6.280886529664969],
89
+ [ 7.543908963904542, -13.80553471177258, 11.045312626737768],
90
+ [ 7.627386835522138, -13.21893079563559, 9.44879979032185],
91
+ [ 7.721416922130274, -12.558175843811803, 7.65047602654787],
92
+ [ 7.858777331907703, -11.5929361612917, 5.0234605890963735],
93
+ [ 8.04372538421865, -10.29201767349075, 1.4839827790234683],
94
+ [ 8.27718726491764, -8.615925113436965, -2.7825997928274617],
95
+ [ 0.5230499792025647, 2.345737471858331, 0.8265159513926312],
96
+ [ 0.6065278508201573, 2.9323413879953493, -0.7699968850232997],
97
+ [ 0.7005579374282966, 3.5930963398190934, -2.568320648797273],
98
+ [ 0.8379183472057221, 4.558336022339238, -5.195336086248769],
99
+ [ 1.0229790920630109, 5.858768766405939, -8.734619598827981],
100
+ [ 1.25957592210964, 7.521348613754378, -13.198589208451061],
101
+ [ 1.3501976555259425, 0.6559871842810455, 2.0343377241951677],
102
+ [ 1.433675527143535, 1.24259110041805, 0.4378248877792479],
103
+ [ 1.527705613751671, 1.9033460522418222, -1.3604988759947312],
104
+ [ 1.6650660235291, 2.868585734761939, -3.9875143134462276],
105
+ [ 1.8501267683863887, 4.16901847882864, -7.526797826025433],
106
+ [ 2.086723598433018, 5.831598326177079, -11.974083544043578],
107
+ [ 2.2819028623704156, -1.247359928051528, 3.3948370242261996],
108
+ [ 2.365380733988008, -0.6607560119145373, 1.7983241878102851],
109
+ [ 2.4594108205961476,-1.0600907790481173e-06, 4.2403631161924693e-07],
110
+ [ 2.596771230373573, 0.9652386224293652, -2.627015013415196],
111
+ [ 2.781831975230862, 2.2656713664960666, -6.166298525994401],
112
+ [ 3.018428805277491, 3.928251213844505, -10.592558546339276],
113
+ [ 3.6429503060175, -4.027794879560551, 5.382272621653305],
114
+ [ 3.7264281776350963, -3.4411909634235878, 3.785759785237386],
115
+ [ 3.820458264243232, -2.780436011599802, 1.9874360214634068],
116
+ [ 3.9578186740206576, -1.815196329079685, -0.6395794159880952],
117
+ [ 4.142879418877946, -0.5147635850129562, -4.178862928567301],
118
+ [ 4.3794762489245755, 1.1478162623354826, -8.570277604210109],
119
+ [ 5.476640625634111, -7.7737749912044904, 8.059873195295392],
120
+ [ 5.560118497251704, -7.187171075067486, 6.463360358879472],
121
+ [ 5.654148583859843, -6.526416123243714, 4.665036595105493],
122
+ [ 5.791508993637269, -5.561176440723598, 2.038021157653996],
123
+ [ 5.9765697384945575, -4.260743696656896, -1.501262354925209],
124
+ [ 6.213166568541187, -2.5981638493084573, -5.838261492407609],
125
+ [ 7.820980681344153, -12.56294311281847, 11.483137315102587],
126
+ [ 7.904458552961749, -11.97633919668148, 9.886624478686667],
127
+ [ 7.998488639569885, -11.315584244857707, 8.088300714912688],
128
+ [ 8.135054279488433, -10.34691883018725, 5.45991498460105],
129
+ [ 8.316678738930346, -9.031674511054272, 1.9147068419953395],
130
+ [ 8.545001735678095, -7.333431589141681, -2.3550957847641163],
131
+ [ 0.9278000546103051, 4.160931920520639, 1.4660961195476718],
132
+ [ 1.0112779262279012, 4.7475358366576295, -0.13041671686824796],
133
+ [ 1.105308012836037, 5.408290788481401, -1.928740480642227],
134
+ [ 1.2426684226134626, 6.373530471001532, -4.555755918093729],
135
+ [ 1.4277291674707513, 7.673963215068246, -8.09503943067294],
136
+ [ 1.6643259975173805, 9.336543062416686, -12.554741017010935],
137
+ [ 1.754947730933683, 2.4711816329433534, 2.6739178923502136],
138
+ [ 1.8384256025512755, 3.057785549080344, 1.0774050559342885],
139
+ [ 1.932455689159415, 3.7185405009041164, -0.720918707839685],
140
+ [ 2.0698160989368404, 4.683780183424233, -3.347934145291187],
141
+ [ 2.254876843794129, 5.9842129274909475, -6.8872176578703925],
142
+ [ 2.4914736738407584, 7.646792774839387, -11.32973298057271],
143
+ [ 2.686652937778156, 0.567834520610766, 4.0344171923812455],
144
+ [ 2.770130809395752, 1.1544384367477427, 2.4379043559653257],
145
+ [ 2.864160896003888, 1.8151933885715288, 0.6395805921913467],
146
+ [ 3.0015213057813135, 2.7804330710916454, -1.9874348452601553],
147
+ [ 3.1865820506386022, 4.0808658151583606, -5.526718357839361],
148
+ [ 3.4231788806852315, 5.743445662506799, -9.94765588731043],
149
+ [ 4.047700381425244, -2.2126004308982843, 6.021852789808346],
150
+ [ 4.131178253042837, -1.6259965147612798, 4.4253399533924265],
151
+ [ 4.2252083396509725, -0.9652415629374939, 2.6270161896184527],
152
+ [ 4.362568749428402,-1.8804173912423394e-06, 7.521669509458206e-07],
153
+ [ 4.54762949428569, 1.300430863649324, -3.5392827604122545],
154
+ [ 4.784226324332316, 2.963010710997777, -7.9245934939712654],
155
+ [ 5.881390701041852, -5.958580542542183, 8.699453363450433],
156
+ [ 5.964868572659448, -5.37197662640522, 7.102940527034518],
157
+ [ 6.058898659267584, -4.71122167458142, 5.304616763260533],
158
+ [ 6.196259069045009, -3.745981992061304, 2.6776013258090368],
159
+ [ 6.381319813902298, -2.445549247994588, -0.861682186770174],
160
+ [ 6.617916643948927, -0.7829694006461496, -5.191568874186014],
161
+ [ 8.223607218362389, -10.738595481442792, 12.119056210172275],
162
+ [ 8.305275059300829, -10.14418970893012, 10.519422631206087],
163
+ [ 8.396613881889909, -9.47183448116215, 8.71645875705443],
164
+ [ 8.528826143428034, -8.484404504507104, 6.080567201948961],
165
+ [ 8.70472814153132, -7.1444944037420965, 2.525492746690433],
166
+ [ 8.926029928054998, -5.415987644656798, -1.7480821301431027],
167
+ [ 1.473105288901401, 6.606478182901276, 2.3277795005634205],
168
+ [ 1.5565831605189935, 7.193082099038267, 0.7312666641475007],
169
+ [ 1.6506132471271293, 7.853837050862053, -1.0670570996264783],
170
+ [ 1.7879736569045583, 8.81907673338217, -3.6940725370779806],
171
+ [ 1.973034401761847, 10.119509477448885, -7.233356049657186],
172
+ [ 2.2096312318084728, 11.782089324797337, -11.687093796927556],
173
+ [ 2.3002529652247787, 4.916727895323991, 3.5356012733659625],
174
+ [ 2.3837308368423713, 5.5033318114609955, 1.9390884369500427],
175
+ [ 2.477760923450507, 6.164086763284768, 0.14076467317606367],
176
+ [ 2.615121333227936, 7.12932644580487, -2.4862507642754386],
177
+ [ 2.800182078085225, 8.429759189871586, -6.025534276854638],
178
+ [ 3.0367789081318506, 10.092339037220038, -10.461413857059416],
179
+ [ 3.231958172069252, 3.013380782991404, 4.896100573397],
180
+ [ 3.3154360436868444, 3.5999846991284086, 3.299587736981074],
181
+ [ 3.4094661302949802, 4.260739650952194, 1.5012639732070898],
182
+ [ 3.5468265400724093, 5.2259793334722975, -1.1257514642443955],
183
+ [ 3.731887284929698, 6.526412077538998, -4.665034976823606],
184
+ [ 3.9684841149763272, 8.188991924887437, -9.07859827809046],
185
+ [ 4.719950073683535, 0.8022573384867254, 7.084131952532646],
186
+ [ 4.803427945301131, 1.3888612546237162, 5.487619116116738],
187
+ [ 4.897458031909267, 2.0496162064474883, 3.6892953523427527],
188
+ [ 5.034818441686692, 3.0148558889676185, 1.062279914891251],
189
+ [ 5.262960445386941, 4.6180231740532705, -3.3009319204752865],
190
+ [ 5.45647601659061, 5.977868480382758, -6.851902517813086],
191
+ [ 6.980514754786963, -3.815769078464981, 10.385065170167307],
192
+ [ 7.063992626404556, -3.2291651623279765, 8.788552333751381],
193
+ [ 7.158022713012695, -2.5684102105042044, 6.990228569977414],
194
+ [ 7.2953831227901205, -1.603170527984088, 4.363213132525912],
195
+ [ 7.5235251264903695, -3.242898435895647e-06, 1.2971593743582588e-06],
196
+ [ 7.717040697694038, 1.3595109328811417, -3.479420947230122],
197
+ [ 8.866298051616052, -7.5963288370378415, 13.130371822888593],
198
+ [ 8.943818556779096, -6.984046617217424, 11.523587664999313],
199
+ [ 9.0305651046354, -6.291897101808164, 9.712706075791145],
200
+ [ 9.156215163257453, -5.276181767756266, 7.0655003777269245],
201
+ [ 9.362175938461576, -3.6266215940371493, 2.664045044953273],
202
+ [ 9.534291317305062, -2.307210411480548, -0.7820413523084102],
203
+ [ 2.1702682120302335, 9.733065044192912, 3.429426187489948],
204
+ [ 2.253746083647826, 10.319668960329917, 1.832913351074017],
205
+ [ 2.3477761702559654, 10.980423912153675, 0.03458958730004902],
206
+ [ 2.485136580033391, 11.945663594673805, -2.5924258501514528],
207
+ [ 2.71327858373364, 13.54883087975943, -6.955637685517985],
208
+ [ 2.906794154937309, 14.90867618608896, -10.577468187682026],
209
+ [ 2.9974158883536113, 8.043314756615613, 4.637247960292489],
210
+ [ 3.080893759971204, 8.629918672752618, 3.0407351238765647],
211
+ [ 3.1749238465793397, 9.290673624576403, 1.2424113601025855],
212
+ [ 3.3122842563567687, 10.255913307096506, -1.384604077348911],
213
+ [ 3.540426260057014, 11.859080592182172, -5.747815912715448],
214
+ [ 3.7339418312606867, 13.21892589851166, -9.350937354703776],
215
+ [ 3.9291210951980844, 6.13996764428304, 5.997747260323516],
216
+ [ 4.0125989668156805, 6.726571560420017, 4.401234423907602],
217
+ [ 4.106629053423816, 7.387326512243803, 2.6029106601336283],
218
+ [ 4.243989463201242, 8.352566194763932, -0.0241047773178793],
219
+ [ 4.472131466901491, 9.955733479849584, -4.387316612684411],
220
+ [ 4.66564703810516, 11.315578786179072, -7.96718643389096],
221
+ [ 5.2901685388451725, 3.3595326927740032, 7.985182857750628],
222
+ [ 5.373646410462765, 3.9461366089109937, 6.388670021334702],
223
+ [ 5.467676497070901, 4.60689156073478, 4.590346257560723],
224
+ [ 5.605036906848326, 5.572131243254896, 1.963330820109227],
225
+ [ 5.833178910548575, 7.175298528340562, -2.3998810152573102],
226
+ [ 6.026694481752244, 8.534993990321052, -5.9417543099544385],
227
+ [ 7.550733219948597, -1.2584937241776895, 11.286116075385277],
228
+ [ 7.634211091566193, -0.6718898080407265, 9.689603238969363],
229
+ [ 7.728241178174329, -0.011134856216940547, 7.891279475195384],
230
+ [ 7.865601587951758, 0.9526131356607653, 5.264264037743882],
231
+ [ 8.093346866803692, 2.477891311819247, 0.9003681940181918],
232
+ [ 8.283854718648737, 3.6941518861046547, -2.5734295208431957],
233
+ [ 9.386516414015183, -4.836292441189285, 13.945215654378117],
234
+ [ 9.460906294700411, -4.2391184881929584, 12.333033868078802],
235
+ [ 9.544182347323037, -3.5829926712698383, 10.516168666398768],
236
+ [ 9.664865892482492, -2.6542303503559044, 7.860400014088703],
237
+ [ 9.862837195391332, -1.183527136262602, 3.4451697290818095],
238
+ [ 10.0284167860891,-3.7397147878426296e-06, 1.495885920688167e-06],
239
+ [ 0.021934076132581026, -9.454326210800446e-09, 3.781730484320178e-09],
240
+ [ 0.058780982569004436,-2.5336621689575622e-08, 1.0134648675830249e-08],
241
+ [ 0.11435633851765203,-4.9291529191641814e-08, 1.9716611676656726e-08],
242
+ [ 0.19243856430753326, -8.294763487182166e-08, 3.3179053948728665e-08],
243
+ [ 0.295077431223973, -1.271885236020509e-07, 5.087540944082036e-08],
244
+ [ 0.4240923330288915,-1.8279841529356133e-07, 7.311936611742453e-08],
245
+ [ 0.5811308595128502, -2.50487422470691e-07, 1.001949689882764e-07],
246
+ [ 0.7677063750858686,-3.3090787054934623e-07, 1.323631482197385e-07],
247
+ [ 0.9852237981900878,-4.2466538618946004e-07, 1.6986615447578401e-07],
248
+ [ 1.234998173671169, -5.323267521228914e-07, 2.1293070084915655e-07],
249
+ [ 1.518268563807407, -6.544260272578484e-07, 2.6177041090313935e-07],
250
+ [ 1.8362087507290958, -7.914691957378039e-07, 3.165876782951216e-07],
251
+ [ 2.1899356831957526, -9.439377057773868e-07, 3.775750823109547e-07],
252
+ [ 2.5805162775921744, -1.112291383997821e-06, 4.449165535991284e-07],
253
+ [ 3.0089729867597903,-1.2969709889398828e-06, 5.187883955759531e-07],
254
+ [ 3.476288425972694,-1.4984000151763155e-06, 5.993600171727564e-07],
255
+ [ 3.9834092637972525,-1.7169865668131834e-06, 6.867946267252734e-07],
256
+ [ 4.531249530409994, -1.953124606490775e-06, 7.812498425963099e-07],
257
+ [ 5.120693457658401, -2.20719523214008e-06, 8.828780984071471e-07],
258
+ [ 5.752597937960555,-2.4795678427169676e-06, 9.91827137086787e-07],
259
+ [ 6.427794669443173,-2.7706008737249377e-06, 1.1082403550410902e-06],
260
+ [ 7.147092040193037, -3.08064282417142e-06, 1.232257129668568e-06],
261
+ [ 7.911276793614039, -3.410032770045923e-06, 1.3640131080183693e-06],
262
+ [ 8.70043862073167,-3.5489133576316334e-06, 1.4195653430526534e-06],
263
+ ]
264
+
265
+ #
266
+ # Determine the difference (delta-E 1976) between two L*a*b* color values.
267
+ # @param lab1 [<Integer>] a L*a*b* array
268
+ # @param lab2 [<Integer>] another L*a*b* array
269
+ #
270
+ # @return [Integer]
271
+ def self.difference(lab1, lab2)
272
+ Math.sqrt(
273
+ (lab1[0] - lab2[0]) ** 2 +
274
+ (lab1[1] - lab2[1]) ** 2 +
275
+ (lab1[2] - lab2[2]) ** 2
276
+ )
277
+ end
278
+
279
+ end
280
+
281
+ end
@@ -0,0 +1,118 @@
1
+ require 'matrix'
2
+
3
+ module Chromate
4
+
5
+ module RGB
6
+
7
+ # RGB array representations of the 256 xterm colors
8
+ COLORS = [
9
+ [ 0, 0, 0], [128, 0, 0], [ 0, 128, 0], [128, 128, 0],
10
+ [ 0, 0, 128], [128, 0, 128], [ 0, 128, 128], [192, 192, 192],
11
+ [128, 128, 128], [255, 0, 0], [ 0, 255, 0], [255, 255, 0],
12
+ [ 0, 0, 255], [255, 0, 255], [ 0, 255, 255], [255, 255, 255],
13
+ [ 0, 0, 0], [ 0, 0, 95], [ 0, 0, 135], [ 0, 0, 175],
14
+ [ 0, 0, 215], [ 0, 0, 255], [ 0, 95, 0], [ 0, 95, 95],
15
+ [ 0, 95, 135], [ 0, 95, 175], [ 0, 95, 215], [ 0, 95, 255],
16
+ [ 0, 135, 0], [ 0, 135, 95], [ 0, 135, 135], [ 0, 135, 175],
17
+ [ 0, 135, 215], [ 0, 135, 255], [ 0, 175, 0], [ 0, 175, 95],
18
+ [ 0, 175, 135], [ 0, 175, 175], [ 0, 175, 215], [ 0, 175, 255],
19
+ [ 0, 215, 0], [ 0, 215, 95], [ 0, 215, 135], [ 0, 215, 175],
20
+ [ 0, 215, 215], [ 0, 215, 255], [ 0, 255, 0], [ 0, 255, 95],
21
+ [ 0, 255, 135], [ 0, 255, 175], [ 0, 255, 215], [ 0, 255, 255],
22
+ [ 95, 0, 0], [ 95, 0, 95], [ 95, 0, 135], [ 95, 0, 175],
23
+ [ 95, 0, 215], [ 95, 0, 255], [ 95, 95, 0], [ 95, 95, 95],
24
+ [ 95, 95, 135], [ 95, 95, 175], [ 95, 95, 215], [ 95, 95, 255],
25
+ [ 95, 135, 0], [ 95, 135, 95], [ 95, 135, 135], [ 95, 135, 175],
26
+ [ 95, 135, 215], [ 95, 135, 255], [ 95, 175, 0], [ 95, 175, 95],
27
+ [ 95, 175, 135], [ 95, 175, 175], [ 95, 175, 215], [ 95, 175, 255],
28
+ [ 95, 215, 0], [ 95, 215, 95], [ 95, 215, 135], [ 95, 215, 175],
29
+ [ 95, 215, 215], [ 95, 215, 255], [ 95, 255, 0], [ 95, 255, 95],
30
+ [ 95, 255, 135], [ 95, 255, 175], [ 95, 255, 215], [ 95, 255, 255],
31
+ [135, 0, 0], [135, 0, 95], [135, 0, 135], [135, 0, 175],
32
+ [135, 0, 215], [135, 0, 255], [135, 95, 0], [135, 95, 95],
33
+ [135, 95, 135], [135, 95, 175], [135, 95, 215], [135, 95, 255],
34
+ [135, 135, 0], [135, 135, 95], [135, 135, 135], [135, 135, 175],
35
+ [135, 135, 215], [135, 135, 255], [135, 175, 0], [135, 175, 95],
36
+ [135, 175, 135], [135, 175, 175], [135, 175, 215], [135, 175, 255],
37
+ [135, 215, 0], [135, 215, 95], [135, 215, 135], [135, 215, 175],
38
+ [135, 215, 215], [135, 215, 255], [135, 255, 0], [135, 255, 95],
39
+ [135, 255, 135], [135, 255, 175], [135, 255, 215], [135, 255, 255],
40
+ [175, 0, 0], [175, 0, 95], [175, 0, 135], [175, 0, 175],
41
+ [175, 0, 215], [175, 0, 255], [175, 95, 0], [175, 95, 95],
42
+ [175, 95, 135], [175, 95, 175], [175, 95, 215], [175, 95, 255],
43
+ [175, 135, 0], [175, 135, 95], [175, 135, 135], [175, 135, 175],
44
+ [175, 135, 215], [175, 135, 255], [175, 175, 0], [175, 175, 95],
45
+ [175, 175, 135], [175, 175, 175], [175, 175, 215], [175, 175, 255],
46
+ [175, 215, 0], [175, 215, 95], [175, 215, 135], [175, 215, 175],
47
+ [175, 215, 215], [175, 215, 255], [175, 255, 0], [175, 255, 95],
48
+ [175, 255, 135], [175, 255, 175], [175, 255, 215], [175, 255, 255],
49
+ [215, 0, 0], [215, 0, 95], [215, 0, 135], [215, 0, 175],
50
+ [215, 0, 215], [215, 0, 255], [215, 95, 0], [215, 95, 95],
51
+ [215, 95, 135], [215, 95, 175], [215, 95, 215], [215, 95, 255],
52
+ [215, 135, 0], [215, 135, 95], [215, 135, 135], [215, 135, 175],
53
+ [215, 135, 215], [215, 135, 255], [223, 175, 0], [223, 175, 95],
54
+ [223, 175, 135], [223, 175, 175], [223, 175, 223], [223, 175, 255],
55
+ [223, 223, 0], [223, 223, 95], [223, 223, 135], [223, 223, 175],
56
+ [223, 223, 223], [223, 223, 255], [223, 255, 0], [223, 255, 95],
57
+ [223, 255, 135], [223, 255, 175], [223, 255, 223], [223, 255, 255],
58
+ [255, 0, 0], [255, 0, 95], [255, 0, 135], [255, 0, 175],
59
+ [255, 0, 223], [255, 0, 255], [255, 95, 0], [255, 95, 95],
60
+ [255, 95, 135], [255, 95, 175], [255, 95, 223], [255, 95, 255],
61
+ [255, 135, 0], [255, 135, 95], [255, 135, 135], [255, 135, 175],
62
+ [255, 135, 223], [255, 135, 255], [255, 175, 0], [255, 175, 95],
63
+ [255, 175, 135], [255, 175, 175], [255, 175, 223], [255, 175, 255],
64
+ [255, 223, 0], [255, 223, 95], [255, 223, 135], [255, 223, 175],
65
+ [255, 223, 223], [255, 223, 255], [255, 255, 0], [255, 255, 95],
66
+ [255, 255, 135], [255, 255, 175], [255, 255, 223], [255, 255, 255],
67
+ [ 8, 8, 8], [ 18, 18, 18], [ 28, 28, 28], [ 38, 38, 38],
68
+ [ 48, 48, 48], [ 58, 58, 58], [ 68, 68, 68], [ 78, 78, 78],
69
+ [ 88, 88, 88], [ 98, 98, 98], [108, 108, 108], [118, 118, 118],
70
+ [128, 128, 128], [138, 138, 138], [148, 148, 148], [158, 158, 158],
71
+ [168, 168, 168], [178, 178, 178], [188, 188, 188], [198, 198, 198],
72
+ [208, 208, 208], [218, 218, 218], [228, 228, 228], [238, 238, 238]
73
+ ]
74
+
75
+ # D65 conversion matrix
76
+ CONVERSION_MATRIX = Matrix[
77
+ [0.4124564, 0.3575761, 0.1804375],
78
+ [0.2126729, 0.7151522, 0.0721750],
79
+ [0.0193339, 0.1191920, 0.9503041]
80
+ ]
81
+
82
+ # CIE D65 standard illuminant
83
+ RX = 95.047
84
+ RY = 100.0
85
+ RZ = 108.883
86
+
87
+ #
88
+ # Convert an RGB array into an array representing coordinates in L*a*b*
89
+ # color space.
90
+ # @param rgb [<Integer>] an RGB array
91
+ #
92
+ # @return [<Integer>] a L*a*b* array
93
+ def self.to_lab(rgb)
94
+ xyz_matrix = CONVERSION_MATRIX * Matrix[*rgb.map do |c|
95
+ c = c / 255.0
96
+ if c > 0.04045
97
+ [(c + 0.055 / 1.055) ** 2.4]
98
+ else
99
+ [c / 12.92]
100
+ end
101
+ end]
102
+ f_x, f_y, f_z = *[
103
+ xyz_matrix[0, 0] / RX,
104
+ xyz_matrix[1, 0] / RY,
105
+ xyz_matrix[2, 0] / RZ
106
+ ].map do |c|
107
+ if c > 0.008856
108
+ Math.cbrt(c)
109
+ else
110
+ (903.3 * c + 16) / 116
111
+ end
112
+ end
113
+ [116 * f_y - 16, 500 * (f_x - f_y), 200 * (f_y - f_z)]
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,3 @@
1
+ module Chromate
2
+ VERSION = '1.0.0'
3
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chromate
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Octaplex
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: ''
14
+ email:
15
+ - damanm72@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/chromate.rb
21
+ - lib/chromate/cache.rb
22
+ - lib/chromate/color.rb
23
+ - lib/chromate/core_ext/string.rb
24
+ - lib/chromate/effect.rb
25
+ - lib/chromate/effect_set.rb
26
+ - lib/chromate/effects.rb
27
+ - lib/chromate/formattable.rb
28
+ - lib/chromate/hex.rb
29
+ - lib/chromate/lab.rb
30
+ - lib/chromate/rgb.rb
31
+ - lib/chromate/version.rb
32
+ homepage: ''
33
+ licenses:
34
+ - GPLv3
35
+ metadata: {}
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 2.2.1
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: A dead-simple terminal coloring utility.
56
+ test_files: []
57
+ has_rdoc: