simplecolor 0.2.0 → 0.3.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,111 @@
1
+ module SimpleColor
2
+ class RGB
3
+ GREY256=232
4
+ TRUE_COLOR=0xFFFFFF
5
+
6
+ ANSI_COLORS_16 = {
7
+ :black => 0,
8
+ :red => 1,
9
+ :green => 2,
10
+ :yellow => 3,
11
+ :blue => 4,
12
+ :magenta => 5,
13
+ :cyan => 6,
14
+ :white => 7,
15
+ :intense_black => 8,
16
+ :intense_red => 9,
17
+ :intense_green => 10,
18
+ :intense_yellow => 11,
19
+ :intense_blue => 12,
20
+ :intense_magenta => 13,
21
+ :intense_cyan => 14,
22
+ :intense_white => 15,
23
+ }
24
+ (0..15).each { |i| ANSI_COLORS_16[:"color#{i}"]=i}
25
+
26
+ # A list of color names for standard ansi colors, needed for 16/8 color fallback mode
27
+ # See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
28
+ # These are the xterm color palette
29
+ RGB_COLORS_ANSI = {
30
+ :black => [ 0, 0, 0],
31
+ :red => [205, 0, 0],
32
+ :green => [ 0, 205, 0],
33
+ :yellow => [205, 205, 0],
34
+ :blue => [ 0, 0, 238],
35
+ :magenta => [205, 0, 205],
36
+ :cyan => [ 0, 205, 205],
37
+ :white => [229, 229, 229],
38
+ :gray => [229, 229, 229],
39
+ }.each { |_k, v| v.freeze }.freeze
40
+
41
+ RGB_COLORS_ANSI_BRIGHT = {
42
+ :intense_black => [127, 127, 127],
43
+ :intense_red => [255, 0, 0],
44
+ :intense_green => [ 0, 255, 0],
45
+ :intense_yellow => [255, 255, 0],
46
+ :intense_blue => [ 92, 92, 255],
47
+ :intense_magenta => [255, 0, 255],
48
+ :intense_cyan => [ 0, 255, 255],
49
+ :intense_white => [255, 255, 255],
50
+ :intense_gray => [255, 255, 255],
51
+ }.each { |_k, v| v.freeze }.freeze
52
+
53
+ RGB_COLORS_ANSI_16 = RGB_COLORS_ANSI.merge(RGB_COLORS_ANSI_BRIGHT)
54
+
55
+ COLOR_NAMES={
56
+ :random => proc { rgb_random },
57
+ }
58
+
59
+ module ColorNames
60
+ def color_names
61
+ @color_names ||= COLOR_NAMES.dup
62
+ end
63
+
64
+ def all_color_names
65
+ return @rgb_color_names if defined? @rgb_color_names
66
+ # A list of color names, based on X11's rgb.txt
67
+ rgb_colors = File.dirname(__FILE__) + "/../../data/rgb_colors.json.gz"
68
+ # Rewrite file:
69
+ # h={}; rgb.each do |k,v| h[SimpleColor::RGB.rgb_clean(k)]=v end
70
+ # Pathname.new("data/rgb_colors.json").write(h.to_json)
71
+ File.open(rgb_colors, "rb") do |file|
72
+ serialized_data = Zlib::GzipReader.new(file).read
73
+ # serialized_data.force_encoding Encoding::BINARY
74
+ @rgb_color_names = JSON.parse(serialized_data)
75
+ end
76
+ end
77
+
78
+ def color_names_priority
79
+ @rgb_color_names.keys
80
+ end
81
+
82
+ def rgb_clean(name) #clean up name
83
+ name.gsub(/\s+/,'').downcase.gsub('gray','grey')
84
+ end
85
+
86
+ def find_color(name)
87
+ custom=color_names
88
+ case name
89
+ when String
90
+ return custom[name] if custom.key?(name)
91
+ name=rgb_clean(name)
92
+ return custom[name] if custom.key?(name)
93
+ colors=all_color_names
94
+ base, rest=name.split(':', 2)
95
+ if rest.nil?
96
+ color_names_priority.each do |base|
97
+ c=colors[base]
98
+ return c[name] if c.key?(name)
99
+ end
100
+ else
101
+ c=colors[base]
102
+ return c[rest]
103
+ end
104
+ else
105
+ custom[name]
106
+ end
107
+ end
108
+ end
109
+ extend ColorNames
110
+ end
111
+ end
@@ -1,4 +1,4 @@
1
1
  module SimpleColor
2
2
  # simplecolor version
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
data/simplecolor.gemspec CHANGED
@@ -35,6 +35,7 @@ Gem::Specification.new do |gem|
35
35
  end
36
36
  end
37
37
  gem.files = glob[gemspec['files']] if gemspec['files']
38
+ gem.files = gem.files + gemspec['extra_files'] if gemspec['extra_files']
38
39
 
39
40
  gem.executables = gemspec.fetch('executables') do
40
41
  glob['bin/*'].map { |path| File.basename(path) }
@@ -68,4 +69,5 @@ Gem::Specification.new do |gem|
68
69
  end
69
70
 
70
71
  gem.metadata['yard.run']='yri'
72
+ gem.metadata['project_name']='SimpleColor'
71
73
  end
data/test/test_rgb.rb ADDED
@@ -0,0 +1,103 @@
1
+ require 'helper'
2
+ require 'simplecolor'
3
+
4
+ describe SimpleColor::RGB do
5
+ it "Should output truecolor code" do
6
+ SimpleColor::RGB.new(10,20,30).ansi.must_equal "38;2;10;20;30"
7
+ end
8
+ it "Can degrade to 256 colors" do
9
+ SimpleColor::RGB.new(10,20,30).convert(256).ansi.must_equal "38;5;234"
10
+ end
11
+ it "Can degrade to 16 colors" do
12
+ SimpleColor::RGB.new(10,20,160).convert(16).ansi.must_equal "34"
13
+ end
14
+ it "Can degrade to 8 colors" do
15
+ SimpleColor::RGB.new(10,20,30).convert(8).ansi.must_equal "30"
16
+ end
17
+
18
+ describe "List name" do
19
+ it "Can specify color names" do
20
+ SimpleColor::RGB.parse("lavender").to_hex.must_equal "#9F90D0"
21
+ end
22
+ it "Can specify the dict to use for color names" do
23
+ SimpleColor::RGB.parse("x11:lavender").to_hex.must_equal "#E6E6FA"
24
+ end
25
+ it "Can use custom names" do
26
+ SimpleColor::RGB.parse("solarized_base03").to_hex.must_equal "#002B36"
27
+ end
28
+ it "Custom names have precedence" do
29
+ SimpleColor::RGB.parse("verydarkbluishgreen").to_hex.must_equal "#002A29"
30
+ SimpleColor::RGB.color_names["verydarkbluishgreen"]="#002B30"
31
+ SimpleColor::RGB.parse("verydarkbluishgreen").to_hex.must_equal "#002B30"
32
+ SimpleColor::RGB.parse("nbs:verydarkbluishgreen").to_hex.must_equal "#002A29"
33
+ end
34
+ end
35
+ end
36
+
37
+ describe SimpleColor do
38
+ after do #restore default options
39
+ SimpleColor.opts=nil
40
+ end
41
+
42
+ it "Can parse a true color name" do
43
+ SimpleColor.color("foo", "rgb:10-20-30").must_equal "\e[38;2;10;20;30mfoo\e[0m"
44
+ SimpleColor.color("foo", "10-20-30").must_equal "\e[38;2;10;20;30mfoo\e[0m"
45
+ SimpleColor.color("foo", "10:20:30").must_equal "\e[38;2;10;20;30mfoo\e[0m"
46
+ SimpleColor.color("foo", [10, 20, 30]).must_equal "\e[38;2;10;20;30mfoo\e[0m"
47
+ end
48
+
49
+ it "Can specify 256 colors" do
50
+ SimpleColor.color("foo", "rgb256:1-2-3").must_equal "\e[38;5;67mfoo\e[0m"
51
+ SimpleColor.color("foo", "256:1-2-3").must_equal "\e[38;5;67mfoo\e[0m"
52
+ SimpleColor.color("foo", "256:grey1").must_equal "\e[38;5;233mfoo\e[0m"
53
+ SimpleColor.color("foo", "256:10").must_equal "\e[38;5;10mfoo\e[0m"
54
+ end
55
+
56
+ it "Can specify hexa color name" do
57
+ SimpleColor.color("foo", "#10AABB").must_equal "\e[38;2;16;170;187mfoo\e[0m"
58
+ SimpleColor.color("foo", "#1AB").must_equal "\e[38;2;17;170;187mfoo\e[0m"
59
+ end
60
+
61
+ it "Can specify x11 color name" do
62
+ SimpleColor.color("foo", "Lemon Chiffon").must_equal "\e[38;2;255;250;205mfoo\e[0m"
63
+ SimpleColor.color("foo", "lemonchiffon").must_equal "\e[38;2;255;250;205mfoo\e[0m"
64
+ end
65
+
66
+ it "Can specify background color name" do
67
+ SimpleColor.color("foo", "on_lemonchiffon").must_equal "\e[48;2;255;250;205mfoo\e[0m"
68
+ SimpleColor.color("foo", "on_rgb:255+250+205").must_equal "\e[48;2;255;250;205mfoo\e[0m"
69
+ SimpleColor.color("foo", "on_#CCBBAA").must_equal "\e[48;2;204;187;170mfoo\e[0m"
70
+ SimpleColor.color("foo", "on_rgb256:1+2+3").must_equal "\e[48;5;67mfoo\e[0m"
71
+ SimpleColor.color("foo", "on_rgb256:1").must_equal "\e[48;5;1mfoo\e[0m"
72
+ SimpleColor.color("foo", "on_rgb256:gray1").must_equal "\e[48;5;233mfoo\e[0m"
73
+ SimpleColor.color("foo", [:on, 10, 20, 30]).must_equal "\e[48;2;10;20;30mfoo\e[0m"
74
+ end
75
+
76
+ describe "It can fallback to 256 colors" do
77
+ before do
78
+ SimpleColor.color_mode=256
79
+ end
80
+
81
+ it "Can specify x11 color name" do
82
+ SimpleColor.color("foo", "Lemon Chiffon").must_equal "\e[38;5;230mfoo\e[0m"
83
+ SimpleColor.color("foo", "on_Lemon Chiffon").must_equal "\e[48;5;230mfoo\e[0m"
84
+ end
85
+
86
+ it "Can be forced to be truecolor" do
87
+ SimpleColor.color("foo", "t:Lemon Chiffon").must_equal "\e[38;2;255;250;205mfoo\e[0m"
88
+ SimpleColor.color("foo", "truecolor:Lemon Chiffon").must_equal "\e[38;2;255;250;205mfoo\e[0m"
89
+ SimpleColor.color("foo", "true:on_Lemon Chiffon").must_equal "\e[48;2;255;250;205mfoo\e[0m"
90
+ end
91
+ end
92
+
93
+ describe "It can fallback to 8 colors" do
94
+ before do
95
+ SimpleColor.color_mode=8
96
+ end
97
+
98
+ it "Can specify x11 color name" do
99
+ SimpleColor.color("foo", "Lemon Chiffon").must_equal "\e[37mfoo\e[0m"
100
+ SimpleColor.color("foo", "on_Lemon Chiffon").must_equal "\e[47mfoo\e[0m"
101
+ end
102
+ end
103
+ end
@@ -2,18 +2,15 @@ require 'helper'
2
2
  require 'simplecolor'
3
3
 
4
4
  class TestSimpleColor < MiniTest::Test
5
-
6
5
  def test_version
7
6
  version = SimpleColor.const_get('VERSION')
8
-
9
7
  assert(!version.empty?, 'should have a VERSION constant')
10
8
  end
11
-
12
9
  end
13
10
 
14
11
  describe SimpleColor do
15
- before do
16
- SimpleColor.enabled=true
12
+ after do #restore default options
13
+ SimpleColor.opts=nil
17
14
  end
18
15
 
19
16
  it "Can be used directly" do
@@ -57,6 +54,50 @@ describe SimpleColor do
57
54
  SimpleColor.color?(SimpleColor.color("red",:red)).must_equal true
58
55
  end
59
56
 
57
+ it "Can only show color escape when passed nil" do
58
+ SimpleColor.color(nil, "x11:lavender").must_equal "\e[38;2;230;230;250m"
59
+ end
60
+
61
+ it "Accepts a block as color parameter" do
62
+ SimpleColor.color("foo", proc { "x11:lavender" }).must_equal "\e[38;2;230;230;250mfoo\e[0m"
63
+ end
64
+
65
+ it "Proc as color parameter can return multiple values" do
66
+ SimpleColor.color("foo", proc { ["x11:lavender", :bold] }).must_equal "\e[38;2;230;230;250;1mfoo\e[0m"
67
+ end
68
+
69
+ it "Has default options" do
70
+ SimpleColor.opts.must_equal(SimpleColor::Opts.default_opts)
71
+ end
72
+
73
+ describe "Abbreviations" do
74
+ before do
75
+ SimpleColor.abbreviations={red: SimpleColor.color(:green), color1: SimpleColor.color(nil, "x11:lavender")}
76
+ end
77
+
78
+ it "Can use the color1 abbreviations" do
79
+ SimpleColor.color("foo", :color1).must_equal "\e[38;2;230;230;250mfoo\e[0m"
80
+ end
81
+ it "Abbrevations have precedence" do
82
+ SimpleColor.color("foo", :red).must_equal SimpleColor.color("foo", :green)
83
+ end
84
+ end
85
+
86
+ describe "Random" do
87
+ it "Has a :random color" do
88
+ SimpleColor.color("foo", :random).must_match(/\e\[38;2;\d+;\d+;\d+mfoo\e\[0m/)
89
+ end
90
+ it "Has a :on_random color" do
91
+ SimpleColor.color("foo", :on_random).must_match(/\e\[48;2;\d+;\d+;\d+mfoo\e\[0m/)
92
+ end
93
+ end
94
+
95
+ describe "Abbreviations" do
96
+ it "Can specify abbreviations" do
97
+ SimpleColor.abbreviations[:important]=[:red, :bold]
98
+ SimpleColor.color("foo", :important).must_equal("\e[31;1mfoo\e[0m")
99
+ end
100
+ end
60
101
 
61
102
  describe "Shell mode" do
62
103
  before do
@@ -66,6 +107,23 @@ describe SimpleColor do
66
107
  it "Wraps color into shell escapes" do
67
108
  SimpleColor.color("red",:red).must_equal "%{\e[31m%}red%{\e[0m%}"
68
109
  end
110
+
111
+ it "Can uncolor correctly" do
112
+ SimpleColor.uncolor(SimpleColor.color("red",:red)).must_equal "red"
113
+ end
114
+
115
+ it "Only uncolor shell wrapped colors" do
116
+ red="\e[31mred\e[0m"
117
+ SimpleColor.uncolor(red).must_equal red
118
+ end
119
+
120
+ it "Can detect colors correctly" do
121
+ SimpleColor.color?(SimpleColor.color("red",:red)).must_equal true
122
+ end
123
+
124
+ it "Only detect shell wrapped colors" do
125
+ SimpleColor.color?("\e[31mred\e[0m").must_equal false
126
+ end
69
127
  end
70
128
 
71
129
  describe "It can be mixed in strings" do
@@ -104,10 +162,8 @@ describe SimpleColor do
104
162
  s.uncolor!
105
163
  s.must_equal "red"
106
164
  end
107
-
108
165
  end
109
166
 
110
-
111
167
  describe "It can be disabled" do
112
168
  before do
113
169
  SimpleColor.enabled=false
@@ -122,6 +178,13 @@ describe SimpleColor do
122
178
  word="\e[31mred\e[0m"
123
179
  SimpleColor.uncolor(word).must_equal "red"
124
180
  end
181
+
182
+ it "Can be disabled punctually" do
183
+ SimpleColor.enabled=true
184
+ word="red"
185
+ SimpleColor.color(word,:red, mode: false).must_equal word
186
+ SimpleColor.color(word,:red).must_equal "\e[31mred\e[0m"
187
+ end
125
188
  end
126
189
 
127
190
  describe "It has colors helpers utilities" do
@@ -145,10 +208,132 @@ describe SimpleColor do
145
208
  SimpleColor.attributes_from_colors("\e[m"+b+e).must_equal([:reset,:red,:bright,:reset])
146
209
  end
147
210
 
211
+ it "Can detect 256 and truecolor attributes" do
212
+ test=SimpleColor[nil, "rgb256:3", "on_rgb:1:2:3", :green, :bold, :conceal, :color15]
213
+ expected=[SimpleColor::RGB.new(3, mode: 256),
214
+ SimpleColor::RGB.new([1,2,3], background: true),
215
+ :green, :bright, :conceal, :intense_white]
216
+ SimpleColor.attributes_from_colors(test).must_equal(expected)
217
+ end
218
+
148
219
  it "Can split a string into color entities" do
149
220
  SimpleColor.color_entities(SimpleColor.color("red",:red,:bold)+SimpleColor.color("blue",:blue)).must_equal(["\e[31;1m", "r", "e", "d", "\e[0m\e[34m", "b", "l", "u", "e", "\e[0m"])
150
221
  SimpleColor.color_entities("blue "+SimpleColor.color("red",:red,:bold)+" green").must_equal(["b", "l", "u", "e", " ", "\e[31;1m", "r", "e", "d", "\e[0m", " ", "g", "r", "e", "e", "n"])
151
222
  end
223
+
224
+ it "Can split a string into color strings" do
225
+ SimpleColor.color_strings(SimpleColor.color("red",:red,:bold)+SimpleColor.color("blue",:blue)).must_equal(["\e[31;1m", "red", "\e[0m\e[34m", "blue", "\e[0m"])
226
+ SimpleColor.color_strings("blue "+SimpleColor.color("red",:red,:bold)+" green").must_equal(["blue ", "\e[31;1m", "red", "\e[0m", " green"])
227
+ end
228
+ end
229
+
230
+ describe "It can use a different color module" do
231
+ module SimpleColor2
232
+ extend SimpleColor
233
+ end
234
+
235
+ it "Can color too" do
236
+ SimpleColor2.color("red", :red).must_equal "\e[31mred\e[0m"
237
+ end
238
+
239
+ it "Still works if SimpleColor is disabled" do
240
+ SimpleColor.enabled=false
241
+ SimpleColor2.color("red", :red).must_equal "\e[31mred\e[0m"
242
+ SimpleColor.color("red", :red).must_equal "red"
243
+ end
244
+
245
+ it "Can be disabled without disabling SimpleColor" do
246
+ SimpleColor2.enabled=false
247
+ SimpleColor.color("red", :red).must_equal "\e[31mred\e[0m"
248
+ SimpleColor2.color("red", :red).must_equal "red"
249
+ SimpleColor2.enabled=true
250
+ end
251
+
252
+ it "Can be mixed in a class" do
253
+ string_class=Class.new(String)
254
+ SimpleColor2.mix_in(string_class)
255
+ string_class.new("red").color(:red).must_equal "\e[31mred\e[0m"
256
+ SimpleColor.enabled=false
257
+ string_class.new("red").color(:red).must_equal "\e[31mred\e[0m"
258
+ SimpleColor2.enabled=false
259
+ string_class.new("red").color(:red).must_equal "red"
260
+ SimpleColor2.enabled=true
261
+ end
262
+
263
+ it "Setting a different color module copy the defaults opts and not the current opts" do
264
+
265
+ default_opts=SimpleColor.opts
266
+ SimpleColor.opts={mode: false, colormode: 16}
267
+ module SimpleColor3
268
+ extend SimpleColor
269
+ end
270
+ SimpleColor.opts=default_opts
271
+ SimpleColor3.opts.must_equal default_opts
272
+ end
152
273
  end
153
274
 
275
+ describe "It raises invalid parameters" do
276
+ it "Raises when we pass invalid parameter" do
277
+ proc { SimpleColor.color("foo", mode: :garbage)}.must_raise SimpleColor::WrongParameter
278
+ end
279
+
280
+ it "Raises when we pass invalid rgb parameter" do
281
+ proc { SimpleColor.color("foo", "x11:lavender", color_mode:10)}.must_raise SimpleColor::WrongRGBParameter
282
+ end
283
+
284
+ it "Raises when we pass an invalid color" do
285
+ proc { SimpleColor.color("foo", SimpleColor)}.must_raise SimpleColor::WrongColor
286
+ proc { SimpleColor.color("foo", "nonexistingcolorname")}.must_raise SimpleColor::WrongRGBColor
287
+ end
288
+ end
289
+
290
+ describe "Chain colors" do
291
+ it "Can chain global colors" do
292
+ r=SimpleColor["red", :red]
293
+ SimpleColor.color(r, :blue).must_equal "\e[31m\e[34mred\e[0m"
294
+ end
295
+
296
+ it "Can keep global colors" do
297
+ r=SimpleColor["red", :red]
298
+ SimpleColor.color(r, :blue, global_color: :keep).must_equal SimpleColor["red", :red]
299
+ end
300
+
301
+ it "Can give precedence to existing global colors" do
302
+ r=SimpleColor["red", :red]
303
+ SimpleColor.color(r, :blue, global_color: :before).must_equal "\e[34m\e[31mred\e[0m"
304
+ end
305
+
306
+ it "Will give precedence to local colors" do
307
+ r="foo "+SimpleColor["red", :red]+" bar"
308
+ SimpleColor.color(r, :blue).must_equal "\e[34mfoo \e[31mred\e[0m\e[34m bar\e[0m"
309
+ r="foo "+SimpleColor["red", :red]
310
+ SimpleColor.color(r, :blue).must_equal "\e[34mfoo \e[31mred\e[0m"
311
+ r=+SimpleColor["red", :red]+" bar"
312
+ SimpleColor.color(r, :blue).must_equal "\e[34m\e[31mred\e[0m\e[34m bar\e[0m"
313
+ end
314
+
315
+ it "Can get precedence over local colors" do
316
+ r="foo "+SimpleColor["red", :red]+" bar"
317
+ SimpleColor.color(r, :blue, local_color: :after).must_equal "\e[34mfoo \e[31m\e[34mred\e[0m\e[34m bar\e[0m"
318
+ r="foo "+SimpleColor["red", :red]
319
+ SimpleColor.color(r, :blue, local_color: :after).must_equal "\e[34mfoo \e[31m\e[34mred\e[0m"
320
+ r=+SimpleColor["red", :red]+" bar"
321
+ SimpleColor.color(r, :blue, local_color: :after).must_equal "\e[31m\e[34mred\e[0m\e[34m bar\e[0m"
322
+ end
323
+
324
+ it "Can keep local colors" do
325
+ r="foo "+SimpleColor["red", :red]+" bar"
326
+ SimpleColor.color(r, :blue, local_color: :keep).must_equal "\e[34mfoo \e[0m\e[31mred\e[0m\e[34m bar\e[0m"
327
+ r="foo "+SimpleColor["red", :red]
328
+ SimpleColor.color(r, :blue, local_color: :keep).must_equal "\e[34mfoo \e[0m\e[31mred\e[0m"
329
+ r=+SimpleColor["red", :red]+" bar"
330
+ SimpleColor.color(r, :blue, local_color: :keep).must_equal "\e[31mred\e[0m\e[34m bar\e[0m"
331
+ end
332
+
333
+ it "Can store precedence settings" do
334
+ SimpleColor.opts[:global_color]=:keep
335
+ r=SimpleColor["red", :red]
336
+ SimpleColor.color(r, :blue).must_equal(SimpleColor["red", :red])
337
+ end
338
+ end
154
339
  end