colorable 0.0.8 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd1ee00539ef3544f0938729f93a1abc32c3b3ec
4
- data.tar.gz: 72879c844b5456ad6908cf0875cc5468f553b0ea
3
+ metadata.gz: b79f5456ff48188f4232decead4443e0c511ba3f
4
+ data.tar.gz: cf8e2236927be3b23baaec50d220d112190076b5
5
5
  SHA512:
6
- metadata.gz: a04a172d115e8c82c5f0d6746bebebd90670e74ac8a7a97bf8369c961a37de9e2825ef7ba6f57199862ef0253910af6d79d20ff20ef7bdc8ed925c7296d2694a
7
- data.tar.gz: fe15f0a313eea761fbd741398159dad8d8aaa26d4f56f74b9ff1ff45a48cfaa571537578b4ccb95db1f02a88919b10ab91ea52ef8f10a3f79e8d4f25eb83a6a2
6
+ metadata.gz: a7fc1f13cefb37d408c10491150020f788445693855b9a07d39c3653298d739f5f4b3f4de4f8d7e3fe5e2db58f0d3976d0982a167b330c54558c9abb768bc87d
7
+ data.tar.gz: 66a27bbed8977cd6b543b86eb947a7fa5b9ece0fa5a40d1d7e0e7d110ac26b2472f3b69348bb9a83e7b7c69651459512a91c856c7e7b84fc91dfdda5280f6368
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Colorable
2
2
 
3
- A simple color handler which provide a conversion between colorname, RGB, HSB and HEX. It also provides a colorset which can be sorted by above color units.
3
+ Colorable is a color handler written in Ruby which include Color and Colorset classes.
4
+ A color object provide a conversion between X11 colorname, RGB, HSB and HEX or other manipulations. a colorset object represent X11 colorset which can be manipulated like enumerable object.
4
5
 
5
6
  ## Installation
6
7
 
@@ -21,33 +22,103 @@ Or install it yourself as:
21
22
  Create a color object:
22
23
 
23
24
  require "colorable"
25
+ include Colorable
24
26
 
25
- # Accept X11 color names
26
- c = Colorable::Color.new(:green) #=> #<Colorable::Color:0x007fa449954ee0 @name="Green", @rgb=[0, 255, 0], @hex=nil, @hsb=nil, @esc=nil>
27
- c.name #=> "Green"
28
- c.hsb #=> [120, 100, 100]
29
- c.hex #=> "#00FF00"
30
- c.to_s #=> "rgb(0,255,0)"
31
-
32
- # or RGB
33
- c2 = Colorable::Color.new([240, 248, 255]) #=> #<Colorable::Color:0x007fa449a69c90 @name="Alice Blue", @rgb=[240, 248, 255], @hex=nil, @hsb=nil, @esc=nil>
34
- c2.name #=> "Alice Blue"
35
- c2.rgb #=> [240, 248, 255]
36
- c2.hsb #=> [208, 6, 100]
37
- c2.hex #=> "#F0F8FF"
38
- c2.to_s #=> "rgb(240,248,255)"
39
-
40
- Create a colorset object:
41
-
42
- # Default colorset sequence is by its color name order.
43
- cs = Colorable::Colorset.new #=> #<Colorset 0/144 pos='Alice Blue:rgb(240,248,255)'>
44
- cs.at #=> #<Colorable::Color:0x007fa448beb2b8 @name="Alice Blue", @rgb=[240, 248, 255], @hex=nil, @hsb=nil, @esc=nil>
45
- 10.times.map { cs.next.name } #=> ["Antique White", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "Blanched Almond", "Blue", "Blue Violet"]
46
-
47
- # Using Colorset#[], the order of the sequence is specified.
48
- cs2 = Colorable::Colorset[:hsb] #=> #<Colorset 0/144 pos='Black:rgb(0,0,0)'>
49
- cs2.at #=> #<Colorable::Color:0x007fa448a913e0 @name="Black", @rgb=[0, 0, 0], @hex=nil, @hsb=[0, 0, 0], @esc=nil>
50
- 10.times.map { cs2.next.hsb } #=> [[0, 0, 41], [0, 0, 50], [0, 0, 66], [0, 0, 75], [0, 0, 75], [0, 0, 83], [0, 0, 86], [0, 0, 96], [0, 0, 100], [0, 2, 100]]
27
+ # with a X11 colorname
28
+ c = Color.new :lime_green
29
+ c.to_s #=> "Lime Green"
30
+ c.rgb.to_a #=> [50, 205, 50]
31
+ c.hsb.to_a #=> [120, 76, 80]
32
+ c.hex.to_s #=> "#32CD32"
33
+ c.dark? #=> false
34
+
35
+ # with Array of RGB values
36
+ c = Color.new [50, 205, 50]
37
+ c.to_s #=> "rgb(50,205,50)"
38
+ c.name.to_s #=> "Lime Green"
39
+ c.hsb.to_a #=> [120, 76, 80]
40
+ c.hex.to_s #=> "#32CD32"
41
+
42
+ # with a HEX string
43
+ c = Color.new '#32CD32'
44
+ c.to_s #=> "#32CD32"
45
+
46
+ # with a RGB, HSB or HEX object
47
+ c = Color.new RGB.new(50, 205, 50)
48
+ c = Color.new HSB.new(120, 76, 80)
49
+ c = Color.new HEX.new('#32CD32')
50
+
51
+ Manipulate color object:
52
+
53
+ c = Color.new :lime_green
54
+
55
+ c.to_s #=> "Lime Green"
56
+ c.rgb.to_a #=> [50, 205, 50]
57
+ c.hsb.to_a #=> [120, 76, 80]
58
+ c.hex.to_s #=> "#32CD32"
59
+ c.dark? #=> false
60
+
61
+ # info returns information of the color
62
+ c.info #=> {:NAME=>"Lime Green", :RGB=>[50, 205, 50], :HSB=>[120, 76, 80], :HEX=>"#32CD32", :MODE=>:NAME, :DARK=>false}
63
+
64
+ # next, prev returns next, prev color object in X11 color sequence
65
+ c.next.to_s #=> "Linen"
66
+ c.next(2).to_s #=> "Magenta"
67
+ c.prev.to_s #=> "Lime"
68
+ c.prev(2).to_s #=> "Light Yellow"
69
+
70
+ # +, - returns incremented or decremented color object
71
+ (c + 1).to_s #=> "Linen"
72
+ (c + 2).to_s #=> "Magenta"
73
+ (c - 1).to_s #=> "Lime"
74
+ (c - 2).to_s #=> "Light Yellow"
75
+
76
+ Color object has a mode which represent output mode of the color. Behaviours of `#to_s`, `next`, `prev`, `+`, `-` will be changed based on the mode. You can change the mode with `#mode=` between :NAME, :RGB, :HSB, :HEX.
77
+
78
+ c = Color.new 'Lime Green'
79
+ c.mode = :NAME
80
+ c.to_s #=> "Lime Green"
81
+ c.next.to_s #=> "Linen"
82
+
83
+ c.mode = :RGB
84
+ c.to_s #=> "rgb(50,205,50)"
85
+ c.next.to_s #=> "rgb(60,179,113)"
86
+ c.next.name.to_s #=> "Medium Sea Green"
87
+ (c + 10).to_s #=> "rgb(60,215,60)"
88
+ (c + [0, 50, 100]).to_s #=> "rgb(50, 255, 150)"
89
+
90
+
91
+ Create a X11 colorset object:
92
+
93
+ include Colorable
94
+
95
+ cs = Colorset.new #=> #<Colorset 0/144 pos='Alice Blue/rgb(240,248,255)/hsb(208,6,100)'>
96
+
97
+ # with option
98
+ cs = Colorset.new(order: :RGB) #=> #<Colorset 0/144 pos='Black/rgb(0,0,0)/hsb(0,0,0)'>
99
+ cs = Colorset.new(order: :HSB, dir: :-) #=> #<Colorset 0/144 pos='Light Pink/rgb(255,182,193)/hsb(352,29,100)'>
100
+
101
+ Manupilate colorset:
102
+
103
+ cs = Colorset.new
104
+ cs.size #=> 144
105
+ cs.at.to_s #=> "Alice Blue"
106
+ cs.at(1).to_s #=> "Antique White"
107
+ cs.at(2).to_s #=> "Aqua"
108
+
109
+ # next(prev) methods moves cursor position
110
+ cs.next.to_s #=> "Antique White"
111
+ cs.at.to_s #=> "Antique White"
112
+ cs.next.to_s #=> "Aqua"
113
+ cs.at.to_s #=> "Aqua"
114
+ cs.rewind
115
+ cs.at.to_s #=> "Alice Blue"
116
+
117
+ cs.map(&:to_s).take(10) #=> ["Alice Blue", "Antique White", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "Blanched Almond", "Blue"]
118
+
119
+ cs.sort_by(&:rgb).map(&:to_s).take(10) #=> ["Black", "Navy", "Dark Blue", "Medium Blue", "Blue", "Dark Green", "Green2", "Teal", "Dark Cyan", "Deep Sky Blue"]
120
+
121
+ cs.sort_by(&:hsb).map(&:to_s).take(10) #=> ["Black", "Dim Gray", "Gray2", "Dark Gray", "Gray", "Silver", "Light Gray", "Gainsboro", "White Smoke", "White"]
51
122
 
52
123
 
53
124
  ## Contributing
data/lib/colorable.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "colorable/version"
2
- %w(system_extension converter color colorset).each { |lib| require_relative "colorable/" + lib }
2
+ %w(system_extension converter color colorset color_space).each { |lib| require_relative "colorable/" + lib }
3
3
 
4
4
  module Colorable
5
5
 
@@ -1,71 +1,161 @@
1
1
  module Colorable
2
2
  class Color
3
- class ColorNameError < StandardError; end
4
- include Colorable::Converter
3
+ class NameError < StandardError; end
5
4
  include Comparable
6
5
  attr_reader :name, :rgb
7
6
 
8
- def initialize(name_or_rgb)
9
- @name, @rgb, @hex, @hsb, @esc = nil
10
- case name_or_rgb
11
- when String, Symbol
12
- @name = varidate_name(name_or_rgb)
13
- @rgb = name2rgb(@name)
14
- when Array
15
- @rgb = validate_rgb(name_or_rgb)
16
- @name = rgb2name(@rgb)
17
- else
18
- raise ArgumentError, "'#{name_or_rgb}' is wrong argument. Only colorname and RGB value are acceptable"
19
- end
7
+ # Create a Color object which has several representations of a color.
8
+ #
9
+ # +arg+ can be:
10
+ # String or Symbol of color name
11
+ # String of HEX color
12
+ # Array of RGB values
13
+ # NAME, RGB, HSB, HEX objects
14
+ #
15
+ # Color object has output mode, which is determined by +arg+ type.
16
+ def initialize(arg)
17
+ @name, @rgb, @hsb, @hex, @mode = set_variables(arg)
18
+ end
19
+
20
+ # Returns a current output mode
21
+ def mode
22
+ "#{@mode.class}"[/\w+$/].intern
23
+ end
24
+
25
+ # Set output mode.
26
+ def mode=(mode)
27
+ modes = [rgb, hsb, name, hex]
28
+ @mode = modes.detect { |m| m.class.to_s.match /#{mode}/i } || begin
29
+ raise ArgumentError, "Invalid mode given"
30
+ end
20
31
  end
21
32
 
22
33
  def to_s
23
- "rgb(%i,%i,%i)" % rgb
34
+ @mode.to_s
35
+ end
36
+
37
+ # Returns information of the color object
38
+ def info
39
+ {
40
+ NAME: name.to_s,
41
+ RGB: rgb.to_a,
42
+ HSB: hsb.to_a,
43
+ HEX: hex.to_s,
44
+ MODE: mode,
45
+ DARK: dark?
46
+ }
24
47
  end
25
48
 
26
49
  def hex
27
- @hex ||= rgb2hex(rgb)
50
+ @hex ||= HEX.new rgb.to_hex
28
51
  end
29
52
 
30
53
  def hsb
31
- @hsb ||= rgb2hsb(rgb)
54
+ @hsb ||= HSB.new *rgb.to_hsb
32
55
  end
33
56
  alias :hsv :hsb
34
57
 
35
- %w(red green blue).each_with_index do |c, i|
36
- define_method(c) { rgb[i] }
58
+ %w(red green blue).each do |c|
59
+ define_method(c) { rgb.send c }
37
60
  end
38
61
 
39
- %w(hue sat bright).each_with_index do |n, i|
40
- define_method(n) { hsb[i] }
62
+ %w(hue sat bright).each do |c|
63
+ define_method(c) { hsb.send c }
41
64
  end
42
65
 
43
66
  def <=>(other)
44
- self.name <=> other.name
67
+ self.rgb <=> other.rgb
45
68
  end
46
69
 
47
70
  @@colorset = {}
48
- def next(set=:name, n=1)
49
- @@colorset[set] ||= Colorable::Colorset[set]
50
- idx = @@colorset[set].find_index(self)
51
- @@colorset[set].at(idx+n) if idx
71
+ # Returns a next color object in X11 colors.
72
+ # The color sequence is determined by its color mode.
73
+ def next(n=1)
74
+ @@colorset[mode] ||= Colorable::Colorset.new(order: mode)
75
+ idx = @@colorset[mode].find_index(self)
76
+ @@colorset[mode].at(idx+n).tap{|c| c.mode = mode } if idx
52
77
  end
53
78
 
54
- def prev(set=:name, n=1)
55
- self.next(set, -n)
79
+ # Returns a previous color object in X11 colors.
80
+ # The color sequence is determined by its color mode.
81
+ def prev(n=1)
82
+ self.next(-n)
56
83
  end
57
84
 
58
85
  def dark?
59
- DARK_COLORS.detect { |d| d == self.name }
86
+ !!DARK_COLORS.detect { |d| d == name.to_s }
87
+ end
88
+
89
+ # Returns a color object which has incremented color values.
90
+ # Array of values or a Fixnum is acceptable as an argument.
91
+ # Which values are affected is determined by its color mode.
92
+ def +(arg)
93
+ self.class.new @mode + arg
94
+ end
95
+
96
+ # Returns a color object which has decremented color values.
97
+ # Array of values or a Fixnum is acceptable as an argument.
98
+ # Which values are affected is determined by its color mode.
99
+ def -(arg)
100
+ self.class.new @mode - arg
60
101
  end
61
102
 
62
103
  private
63
- def varidate_name(name)
64
- COLORNAMES.detect do |label, _|
65
- [label, name].same? { |str| "#{str}".gsub(/[_\s]/,'').downcase }
66
- end.tap do |res, _|
67
- raise ColorNameError, "'#{name}' is not a valid colorname" unless res
68
- break res
104
+ def set_variables(arg)
105
+ case arg
106
+ when String, Symbol
107
+ begin
108
+ hex = HEX.new(arg)
109
+ name = NAME.new(hex.to_name) rescue nil
110
+ rgb = RGB.new *hex.to_rgb
111
+ hsb = nil
112
+ mode = hex
113
+ rescue ArgumentError
114
+ name = validate_name(arg)
115
+ rgb = RGB.new *name.to_rgb
116
+ hsb = nil
117
+ hex = nil
118
+ mode = name
119
+ end
120
+ when Array
121
+ rgb = RGB.new *arg
122
+ name = NAME.new(rgb.to_name) rescue nil
123
+ hsb = nil
124
+ hex = nil
125
+ mode = rgb
126
+ when RGB
127
+ rgb = arg
128
+ name = NAME.new(rgb.to_name) rescue nil
129
+ hsb = nil
130
+ hex = nil
131
+ mode = rgb
132
+ when HSB
133
+ hsb = arg
134
+ rgb = RGB.new *hsb.to_rgb
135
+ name = NAME.new(rgb.to_name) rescue nil
136
+ hex = nil
137
+ mode = hsb
138
+ when NAME
139
+ name = arg
140
+ rgb = RGB.new *name.to_rgb
141
+ hsb = nil
142
+ hex = nil
143
+ mode = name
144
+ when HEX
145
+ hex = arg
146
+ name = NAME.new(hex.to_name) rescue nil
147
+ rgb = RGB.new *hex.to_rgb
148
+ hsb = nil
149
+ mode = hex
150
+ else
151
+ raise ArgumentError
152
+ end
153
+ return name, rgb, hsb, hex, mode
154
+ end
155
+
156
+ def validate_name(name)
157
+ NAME.new(name).tap do |res|
158
+ raise NameError, "Invalid color name given" unless res.name
69
159
  end
70
160
  end
71
161
  end
@@ -0,0 +1,260 @@
1
+ module Colorable
2
+ class ColorSpace
3
+ include Colorable::Converter
4
+ include Comparable
5
+
6
+ def <=>(other)
7
+ self.to_a <=> other.to_a
8
+ end
9
+
10
+ def move_to_top(idx)
11
+ arr = self.to_a
12
+ arr.insert 0, arr.delete_at(idx)
13
+ end
14
+
15
+ def +(arg)
16
+ raise "Subclass must implement it"
17
+ end
18
+
19
+ def -(arg)
20
+ arg = arg.is_a?(Fixnum) ? -arg : arg.map(&:-@)
21
+ self + arg
22
+ end
23
+
24
+ def coerce(arg)
25
+ [self, arg]
26
+ end
27
+
28
+ def to_s
29
+ name = "#{self.class}"[/\w+$/].downcase
30
+ "#{name}(%i,%i,%i)" % to_a
31
+ end
32
+
33
+ private
34
+ def validate(pattern, data)
35
+ case Array(data)
36
+ when Pattern[*Array(pattern)] then data
37
+ else
38
+ raise ArgumentError, "'#{data}' is invalid for a #{self.class} value"
39
+ end
40
+ end
41
+ end
42
+
43
+ class RGB < ColorSpace
44
+ attr_accessor :rgb, :r, :g, :b
45
+ def initialize(r=0,g=0,b=0)
46
+ @r, @g, @b = @rgb = validate_rgb([r, g, b])
47
+ end
48
+ alias :red :r
49
+ alias :green :g
50
+ alias :blue :b
51
+ alias :to_a :rgb
52
+
53
+ # Pass Array of [r, g, b] or a Fixnum.
54
+ # Returns new RGB object with added RGB.
55
+ def +(arg)
56
+ arg =
57
+ case arg
58
+ when Fixnum
59
+ [arg] * 3
60
+ when Array
61
+ raise ArgumentError, "Must be three numbers contained" unless arg.size==3
62
+ arg
63
+ else
64
+ raise ArgumentError, "Accept only Array of three numbers or a Fixnum"
65
+ end
66
+ new_rgb = self.rgb.zip(arg).map { |x, y| x + y }
67
+ self.class.new *new_rgb
68
+ end
69
+
70
+ def to_name
71
+ rgb2name(self.to_a)
72
+ end
73
+
74
+ def to_hsb
75
+ rgb2hsb(self.to_a)
76
+ end
77
+
78
+ def to_hex
79
+ rgb2hex(self.to_a)
80
+ end
81
+
82
+ private
83
+ def validate_rgb(rgb)
84
+ validate([0..255, 0..255, 0..255], rgb)
85
+ end
86
+ end
87
+
88
+ class HSB < ColorSpace
89
+ attr_accessor :hsb, :h, :s, :b
90
+ def initialize(h=0,s=0,b=0)
91
+ @h, @s, @b = @hsb = validate_hsb([h, s, b])
92
+ end
93
+ alias :hue :h
94
+ alias :sat :s
95
+ alias :bright :b
96
+ alias :to_a :hsb
97
+ undef :coerce
98
+
99
+ # Pass Array of [h, s, b] or a Fixnum.
100
+ # Returns new HSB object with added HSB.
101
+ def +(arg)
102
+ arg =
103
+ case arg
104
+ when Array
105
+ raise ArgumentError, "Must be three numbers contained" unless arg.size==3
106
+ arg
107
+ else
108
+ raise ArgumentError, "Accept only Array of three numbers"
109
+ end
110
+ new_hsb = self.hsb.zip(arg).map { |x, y| x + y }
111
+ self.class.new *new_hsb
112
+ end
113
+
114
+ def to_name
115
+ rgb2name(self.to_rgb)
116
+ end
117
+
118
+ def to_rgb
119
+ hsb2rgb(self.to_a)
120
+ end
121
+
122
+ def to_hex
123
+ rgb2hex(self.to_rgb)
124
+ end
125
+
126
+ private
127
+ def validate_hsb(hsb)
128
+ validate([0..359, 0..100, 0..100], hsb)
129
+ end
130
+ end
131
+
132
+ class HEX < ColorSpace
133
+ attr_reader :hex
134
+ def initialize(hex='#FFFFFF')
135
+ @hex = validate_hex(hex)
136
+ end
137
+ alias :to_s :hex
138
+
139
+ def to_a
140
+ @hex.unpack('A1A2A2A2').drop(1)
141
+ end
142
+
143
+ def +(arg)
144
+ build_hex_with(:+, arg)
145
+ end
146
+
147
+ def -(arg)
148
+ build_hex_with(:-, arg)
149
+ end
150
+
151
+ def to_rgb
152
+ hex2rgb(self.to_s)
153
+ end
154
+
155
+ def to_hsb
156
+ rgb2hsb(self.to_rgb)
157
+ end
158
+
159
+ def to_name
160
+ rgb2name(self.to_rgb)
161
+ end
162
+
163
+ private
164
+ def validate_hex(hex)
165
+ hex = hex.join if hex.is_a?(Array)
166
+ validate(/^#[0-9A-F]{6}$/i, hex_norm(hex))
167
+ end
168
+
169
+ def hex_norm(hex)
170
+ hex = hex.to_s.sub(/^#/, '').upcase
171
+ .sub(/^([0-9A-F])([0-9A-F])([0-9A-F])$/, '\1\1\2\2\3\3')
172
+ "##{hex}"
173
+ end
174
+
175
+ def rgb2hex(rgb)
176
+ hex = rgb.map do |val|
177
+ val.to_s(16).tap { |h| break "0#{h}" if h.size==1 }
178
+ end
179
+ '#' + hex.join.upcase
180
+ end
181
+
182
+ def hex2rgb(hex)
183
+ _, *hex = hex.unpack('A1A2A2A2')
184
+ hex.map { |val| val.to_i(16) }
185
+ end
186
+
187
+ def build_hex_with(op, arg)
188
+ _rgb =
189
+ case arg
190
+ when Fixnum
191
+ [arg] * 3
192
+ when String
193
+ hex2rgb(validate_hex arg)
194
+ else
195
+ raise ArgumentError, "Accept only a Hex string or a Fixnum"
196
+ end
197
+ rgb = hex2rgb(self.hex).zip(_rgb).map { |x, y| x.send(op, y) }
198
+ self.class.new rgb2hex(rgb)
199
+ end
200
+ end
201
+
202
+ class NAME < ColorSpace
203
+ attr_accessor :name
204
+ attr_reader :sym
205
+ def initialize(name)
206
+ @name = find_name(name)
207
+ @sym = nil
208
+ end
209
+
210
+ alias :to_s :name
211
+
212
+ def sym
213
+ @name.gsub(/\s/, '_').downcase.intern if @name
214
+ end
215
+
216
+ def dark?
217
+ DARK_COLORS.detect { |d| d == self.name }
218
+ end
219
+
220
+ def <=>(other)
221
+ self.name <=> other.name
222
+ end
223
+
224
+ def +(n)
225
+ raise ArgumentError, 'Only accept a Fixnum' unless n.is_a?(Fixnum)
226
+ pos = COLORNAMES.find_index{|n,_| n==self.name} + n
227
+ self.class.new COLORNAMES.at(pos % COLORNAMES.size)[0]
228
+ end
229
+
230
+ def -(n)
231
+ raise ArgumentError, 'Only accept a Fixnum' unless n.is_a?(Fixnum)
232
+ self + -n
233
+ end
234
+
235
+ def coerce(arg)
236
+ [self, arg]
237
+ end
238
+
239
+ def to_rgb
240
+ name2rgb(self.to_s)
241
+ end
242
+
243
+ def to_hsb
244
+ rgb2hsb(self.to_rgb)
245
+ end
246
+
247
+ def to_hex
248
+ rgb2hex(self.to_rgb)
249
+ end
250
+
251
+ private
252
+ def find_name(name)
253
+ COLORNAMES.map(&:first).detect { |c|
254
+ [c, name].same? { |str| "#{str}".gsub(/[_\s]/,'').downcase }
255
+ } || begin
256
+ raise ArgumentError, "'#{name}' is not in X11 colorset."
257
+ end
258
+ end
259
+ end
260
+ end