color_lib 1.4.4
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 +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +7 -0
- data/CHANGELOG +96 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +21 -0
- data/README.md +25 -0
- data/Rakefile +11 -0
- data/color_lib.gemspec +24 -0
- data/lib/color_lib.rb +139 -0
- data/lib/color_lib/cmyk.rb +280 -0
- data/lib/color_lib/css.rb +15 -0
- data/lib/color_lib/grayscale.rb +205 -0
- data/lib/color_lib/hsl.rb +221 -0
- data/lib/color_lib/palette.rb +4 -0
- data/lib/color_lib/palette/adobecolor.rb +265 -0
- data/lib/color_lib/palette/gimp.rb +103 -0
- data/lib/color_lib/palette/monocontrast.rb +169 -0
- data/lib/color_lib/pantone.rb +1499 -0
- data/lib/color_lib/rgb-colors.rb +343 -0
- data/lib/color_lib/rgb.rb +461 -0
- data/lib/color_lib/rgb/metallic.rb +31 -0
- data/lib/color_lib/version.rb +3 -0
- data/lib/color_lib/yiq.rb +79 -0
- data/lib/test/unit/assertions.rb +332 -0
- data/setup.rb +1588 -0
- data/test/test_adobecolor.rb +404 -0
- data/test/test_cmyk.rb +117 -0
- data/test/test_color.rb +129 -0
- data/test/test_css.rb +18 -0
- data/test/test_gimp.rb +87 -0
- data/test/test_grayscale.rb +110 -0
- data/test/test_hsl.rb +140 -0
- data/test/test_monocontrast.rb +131 -0
- data/test/test_rgb.rb +333 -0
- data/test/test_yiq.rb +62 -0
- metadata +132 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# This namespace contains some RGB metallic colours suggested by Jim Freeze.
|
2
|
+
module ColorLib::RGB::Metallic
|
3
|
+
Aluminum = ColorLib::RGB.new(0x99, 0x99, 0x99)
|
4
|
+
CoolCopper = ColorLib::RGB.new(0xd9, 0x87, 0x19)
|
5
|
+
Copper = ColorLib::RGB.new(0xb8, 0x73, 0x33)
|
6
|
+
Iron = ColorLib::RGB.new(0x4c, 0x4c, 0x4c)
|
7
|
+
Lead = ColorLib::RGB.new(0x19, 0x19, 0x19)
|
8
|
+
Magnesium = ColorLib::RGB.new(0xb3, 0xb3, 0xb3)
|
9
|
+
Mercury = ColorLib::RGB.new(0xe6, 0xe6, 0xe6)
|
10
|
+
Nickel = ColorLib::RGB.new(0x80, 0x80, 0x80)
|
11
|
+
PolySilicon = ColorLib::RGB.new(0x60, 0x00, 0x00)
|
12
|
+
Poly = PolySilicon
|
13
|
+
Silver = ColorLib::RGB.new(0xcc, 0xcc, 0xcc)
|
14
|
+
Steel = ColorLib::RGB.new(0x66, 0x66, 0x66)
|
15
|
+
Tin = ColorLib::RGB.new(0x7f, 0x7f, 0x7f)
|
16
|
+
Tungsten = ColorLib::RGB.new(0x33, 0x33, 0x33)
|
17
|
+
|
18
|
+
Aluminum.freeze
|
19
|
+
CoolCopper.freeze
|
20
|
+
Copper.freeze
|
21
|
+
Iron.freeze
|
22
|
+
Lead.freeze
|
23
|
+
Magnesium.freeze
|
24
|
+
Mercury.freeze
|
25
|
+
Nickel.freeze
|
26
|
+
PolySilicon.freeze
|
27
|
+
Silver.freeze
|
28
|
+
Steel.freeze
|
29
|
+
Tin.freeze
|
30
|
+
Tungsten.freeze
|
31
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# A colour object representing YIQ (NTSC) colour encoding.
|
2
|
+
class ColorLib::YIQ
|
3
|
+
# Creates a YIQ colour object from fractional values 0 .. 1.
|
4
|
+
#
|
5
|
+
# ColorLib::YIQ.new(0.3, 0.2, 0.1)
|
6
|
+
def self.from_fraction(y = 0, i = 0, q = 0)
|
7
|
+
color = ColorLib::YIQ.new
|
8
|
+
color.y = y
|
9
|
+
color.i = i
|
10
|
+
color.q = q
|
11
|
+
color
|
12
|
+
end
|
13
|
+
|
14
|
+
# Creates a YIQ colour object from percentages 0 .. 100.
|
15
|
+
#
|
16
|
+
# ColorLib::YIQ.new(10, 20, 30)
|
17
|
+
def initialize(y = 0, i = 0, q = 0)
|
18
|
+
@y = y / 100.0
|
19
|
+
@i = i / 100.0
|
20
|
+
@q = q / 100.0
|
21
|
+
end
|
22
|
+
|
23
|
+
# Compares the other colour to this one. The other colour will be
|
24
|
+
# converted to YIQ before comparison, so the comparison between a YIQ
|
25
|
+
# colour and a non-YIQ colour will be approximate and based on the other
|
26
|
+
# colour's #to_yiq conversion. If there is no #to_yiq conversion, this
|
27
|
+
# will raise an exception. This will report that two YIQ values are
|
28
|
+
# equivalent if all component colours are within COLOR_TOLERANCE of each
|
29
|
+
# other.
|
30
|
+
def ==(other)
|
31
|
+
other = other.to_yiq
|
32
|
+
other.kind_of?(ColorLib::YIQ) and
|
33
|
+
((@y - other.y).abs <= ColorLib::COLOR_TOLERANCE) and
|
34
|
+
((@i - other.i).abs <= ColorLib::COLOR_TOLERANCE) and
|
35
|
+
((@q - other.q).abs <= ColorLib::COLOR_TOLERANCE)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_yiq
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def brightness
|
43
|
+
@y
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_grayscale
|
47
|
+
ColorLib::GrayScale.new(@y)
|
48
|
+
end
|
49
|
+
|
50
|
+
alias to_greyscale to_grayscale
|
51
|
+
|
52
|
+
def y
|
53
|
+
@y
|
54
|
+
end
|
55
|
+
|
56
|
+
def y=(yy)
|
57
|
+
@y = ColorLib.normalize(yy)
|
58
|
+
end
|
59
|
+
|
60
|
+
def i
|
61
|
+
@i
|
62
|
+
end
|
63
|
+
|
64
|
+
def i=(ii)
|
65
|
+
@i = ColorLib.normalize(ii)
|
66
|
+
end
|
67
|
+
|
68
|
+
def q
|
69
|
+
@q
|
70
|
+
end
|
71
|
+
|
72
|
+
def q=(qq)
|
73
|
+
@q = ColorLib.normalize(qq)
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect
|
77
|
+
"YIQ [%.2f%%, %.2f%%, %.2f%%]" % [@y * 100, @i * 100, @q * 100]
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,332 @@
|
|
1
|
+
# Backport for ruby 2.2.0
|
2
|
+
|
3
|
+
require 'minitest/unit'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
module Test
|
7
|
+
module Unit
|
8
|
+
module Assertions
|
9
|
+
include MiniTest::Assertions
|
10
|
+
|
11
|
+
def mu_pp(obj) #:nodoc:
|
12
|
+
obj.pretty_inspect.chomp
|
13
|
+
end
|
14
|
+
|
15
|
+
MINI_DIR = File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), "minitest") #:nodoc:
|
16
|
+
|
17
|
+
UNASSIGNED = Object.new # :nodoc:
|
18
|
+
|
19
|
+
# :call-seq:
|
20
|
+
# assert( test, failure_message = UNASSIGNED )
|
21
|
+
#
|
22
|
+
#Tests if +test+ is true.
|
23
|
+
#
|
24
|
+
#+msg+ may be a String or a Proc. If +msg+ is a String, it will be used
|
25
|
+
#as the failure message. Otherwise, the result of calling +msg+ will be
|
26
|
+
#used as the message if the assertion fails.
|
27
|
+
#
|
28
|
+
#If no +msg+ is given, a default message will be used.
|
29
|
+
#
|
30
|
+
# assert(false, "This was expected to be true")
|
31
|
+
def assert(test, msg = UNASSIGNED)
|
32
|
+
case msg
|
33
|
+
when UNASSIGNED
|
34
|
+
msg = nil
|
35
|
+
when String, Proc
|
36
|
+
else
|
37
|
+
bt = caller.reject { |s| s.rindex(MINI_DIR, 0) }
|
38
|
+
raise ArgumentError, "assertion message must be String or Proc, but #{msg.class} was given.", bt
|
39
|
+
end
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
# :call-seq:
|
44
|
+
# assert_block( failure_message = nil )
|
45
|
+
#
|
46
|
+
#Tests the result of the given block. If the block does not return true,
|
47
|
+
#the assertion will fail. The optional +failure_message+ argument is the same as in
|
48
|
+
#Assertions#assert.
|
49
|
+
#
|
50
|
+
# assert_block do
|
51
|
+
# [1, 2, 3].any? { |num| num < 1 }
|
52
|
+
# end
|
53
|
+
def assert_block(*msgs)
|
54
|
+
assert yield, *msgs
|
55
|
+
end
|
56
|
+
|
57
|
+
# :call-seq:
|
58
|
+
# assert_raise( *args, &block )
|
59
|
+
#
|
60
|
+
#Tests if the given block raises an exception. Acceptable exception
|
61
|
+
#types maye be given as optional arguments. If the last argument is a
|
62
|
+
#String, it will be used as the error message.
|
63
|
+
#
|
64
|
+
# assert_raise do #Fails, no Exceptions are raised
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# assert_raise NameError do
|
68
|
+
# puts x #Raises NameError, so assertion succeeds
|
69
|
+
# end
|
70
|
+
def assert_raise(*args, &b)
|
71
|
+
assert_raises(*args, &b)
|
72
|
+
end
|
73
|
+
|
74
|
+
# :call-seq:
|
75
|
+
# assert_nothing_raised( *args, &block )
|
76
|
+
#
|
77
|
+
#If any exceptions are given as arguments, the assertion will
|
78
|
+
#fail if one of those exceptions are raised. Otherwise, the test fails
|
79
|
+
#if any exceptions are raised.
|
80
|
+
#
|
81
|
+
#The final argument may be a failure message.
|
82
|
+
#
|
83
|
+
# assert_nothing_raised RuntimeError do
|
84
|
+
# raise Exception #Assertion passes, Exception is not a RuntimeError
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# assert_nothing_raised do
|
88
|
+
# raise Exception #Assertion fails
|
89
|
+
# end
|
90
|
+
def assert_nothing_raised(*args)
|
91
|
+
self._assertions += 1
|
92
|
+
if Module === args.last
|
93
|
+
msg = nil
|
94
|
+
else
|
95
|
+
msg = args.pop
|
96
|
+
end
|
97
|
+
begin
|
98
|
+
line = __LINE__; yield
|
99
|
+
rescue MiniTest::Skip
|
100
|
+
raise
|
101
|
+
rescue Exception => e
|
102
|
+
bt = e.backtrace
|
103
|
+
as = e.instance_of?(MiniTest::Assertion)
|
104
|
+
if as
|
105
|
+
ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o
|
106
|
+
bt.reject! {|ln| ans =~ ln}
|
107
|
+
end
|
108
|
+
if ((args.empty? && !as) ||
|
109
|
+
args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a })
|
110
|
+
msg = message(msg) { "Exception raised:\n<#{mu_pp(e)}>" }
|
111
|
+
raise MiniTest::Assertion, msg.call, bt
|
112
|
+
else
|
113
|
+
raise
|
114
|
+
end
|
115
|
+
end
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
|
119
|
+
# :call-seq:
|
120
|
+
# assert_nothing_thrown( failure_message = nil, &block )
|
121
|
+
#
|
122
|
+
#Fails if the given block uses a call to Kernel#throw.
|
123
|
+
#
|
124
|
+
#An optional failure message may be provided as the final argument.
|
125
|
+
#
|
126
|
+
# assert_nothing_thrown "Something was thrown!" do
|
127
|
+
# throw :problem?
|
128
|
+
# end
|
129
|
+
def assert_nothing_thrown(msg=nil)
|
130
|
+
begin
|
131
|
+
yield
|
132
|
+
rescue ArgumentError => error
|
133
|
+
raise error if /\Auncaught throw (.+)\z/m !~ error.message
|
134
|
+
msg = message(msg) { "<#{$1}> was thrown when nothing was expected" }
|
135
|
+
flunk(msg)
|
136
|
+
end
|
137
|
+
assert(true, "Expected nothing to be thrown")
|
138
|
+
end
|
139
|
+
|
140
|
+
# :call-seq:
|
141
|
+
# assert_equal( expected, actual, failure_message = nil )
|
142
|
+
#
|
143
|
+
#Tests if +expected+ is equal to +actual+.
|
144
|
+
#
|
145
|
+
#An optional failure message may be provided as the final argument.
|
146
|
+
def assert_equal(exp, act, msg = nil)
|
147
|
+
msg = message(msg) {
|
148
|
+
exp_str = mu_pp(exp)
|
149
|
+
act_str = mu_pp(act)
|
150
|
+
exp_comment = ''
|
151
|
+
act_comment = ''
|
152
|
+
if exp_str == act_str
|
153
|
+
if (exp.is_a?(String) && act.is_a?(String)) ||
|
154
|
+
(exp.is_a?(Regexp) && act.is_a?(Regexp))
|
155
|
+
exp_comment = " (#{exp.encoding})"
|
156
|
+
act_comment = " (#{act.encoding})"
|
157
|
+
elsif exp.is_a?(Float) && act.is_a?(Float)
|
158
|
+
exp_str = "%\#.#{Float::DIG+2}g" % exp
|
159
|
+
act_str = "%\#.#{Float::DIG+2}g" % act
|
160
|
+
elsif exp.is_a?(Time) && act.is_a?(Time)
|
161
|
+
if exp.subsec * 1000_000_000 == exp.nsec
|
162
|
+
exp_comment = " (#{exp.nsec}[ns])"
|
163
|
+
else
|
164
|
+
exp_comment = " (subsec=#{exp.subsec})"
|
165
|
+
end
|
166
|
+
if act.subsec * 1000_000_000 == act.nsec
|
167
|
+
act_comment = " (#{act.nsec}[ns])"
|
168
|
+
else
|
169
|
+
act_comment = " (subsec=#{act.subsec})"
|
170
|
+
end
|
171
|
+
elsif exp.class != act.class
|
172
|
+
# a subclass of Range, for example.
|
173
|
+
exp_comment = " (#{exp.class})"
|
174
|
+
act_comment = " (#{act.class})"
|
175
|
+
end
|
176
|
+
elsif !Encoding.compatible?(exp_str, act_str)
|
177
|
+
if exp.is_a?(String) && act.is_a?(String)
|
178
|
+
exp_str = exp.dump
|
179
|
+
act_str = act.dump
|
180
|
+
exp_comment = " (#{exp.encoding})"
|
181
|
+
act_comment = " (#{act.encoding})"
|
182
|
+
else
|
183
|
+
exp_str = exp_str.dump
|
184
|
+
act_str = act_str.dump
|
185
|
+
end
|
186
|
+
end
|
187
|
+
"<#{exp_str}>#{exp_comment} expected but was\n<#{act_str}>#{act_comment}"
|
188
|
+
}
|
189
|
+
assert(exp == act, msg)
|
190
|
+
end
|
191
|
+
|
192
|
+
# :call-seq:
|
193
|
+
# assert_not_nil( expression, failure_message = nil )
|
194
|
+
#
|
195
|
+
#Tests if +expression+ is not nil.
|
196
|
+
#
|
197
|
+
#An optional failure message may be provided as the final argument.
|
198
|
+
def assert_not_nil(exp, msg=nil)
|
199
|
+
msg = message(msg) { "<#{mu_pp(exp)}> expected to not be nil" }
|
200
|
+
assert(!exp.nil?, msg)
|
201
|
+
end
|
202
|
+
|
203
|
+
# :call-seq:
|
204
|
+
# assert_not_equal( expected, actual, failure_message = nil )
|
205
|
+
#
|
206
|
+
#Tests if +expected+ is not equal to +actual+.
|
207
|
+
#
|
208
|
+
#An optional failure message may be provided as the final argument.
|
209
|
+
def assert_not_equal(exp, act, msg=nil)
|
210
|
+
msg = message(msg) { "<#{mu_pp(exp)}> expected to be != to\n<#{mu_pp(act)}>" }
|
211
|
+
assert(exp != act, msg)
|
212
|
+
end
|
213
|
+
|
214
|
+
# :call-seq:
|
215
|
+
# assert_no_match( regexp, string, failure_message = nil )
|
216
|
+
#
|
217
|
+
#Tests if the given Regexp does not match a given String.
|
218
|
+
#
|
219
|
+
#An optional failure message may be provided as the final argument.
|
220
|
+
def assert_no_match(regexp, string, msg=nil)
|
221
|
+
assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
|
222
|
+
self._assertions -= 1
|
223
|
+
msg = message(msg) { "<#{mu_pp(regexp)}> expected to not match\n<#{mu_pp(string)}>" }
|
224
|
+
assert(regexp !~ string, msg)
|
225
|
+
end
|
226
|
+
|
227
|
+
# :call-seq:
|
228
|
+
# assert_not_same( expected, actual, failure_message = nil )
|
229
|
+
#
|
230
|
+
#Tests if +expected+ is not the same object as +actual+.
|
231
|
+
#This test uses Object#equal? to test equality.
|
232
|
+
#
|
233
|
+
#An optional failure message may be provided as the final argument.
|
234
|
+
#
|
235
|
+
# assert_not_same("x", "x") #Succeeds
|
236
|
+
def assert_not_same(expected, actual, message="")
|
237
|
+
msg = message(msg) { build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__) }
|
238
|
+
<?>
|
239
|
+
with id <?> expected to not be equal\\? to
|
240
|
+
<?>
|
241
|
+
with id <?>.
|
242
|
+
EOT
|
243
|
+
assert(!actual.equal?(expected), msg)
|
244
|
+
end
|
245
|
+
|
246
|
+
# :call-seq:
|
247
|
+
# assert_respond_to( object, method, failure_message = nil )
|
248
|
+
#
|
249
|
+
#Tests if the given Object responds to +method+.
|
250
|
+
#
|
251
|
+
#An optional failure message may be provided as the final argument.
|
252
|
+
#
|
253
|
+
# assert_respond_to("hello", :reverse) #Succeeds
|
254
|
+
# assert_respond_to("hello", :does_not_exist) #Fails
|
255
|
+
def assert_respond_to obj, (meth, priv), msg = nil
|
256
|
+
if priv
|
257
|
+
msg = message(msg) {
|
258
|
+
"Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}#{" privately" if priv}"
|
259
|
+
}
|
260
|
+
return assert obj.respond_to?(meth, priv), msg
|
261
|
+
end
|
262
|
+
#get rid of overcounting
|
263
|
+
super if !caller[0].rindex(MINI_DIR, 0) || !obj.respond_to?(meth)
|
264
|
+
end
|
265
|
+
|
266
|
+
# :call-seq:
|
267
|
+
# assert_send( +send_array+, failure_message = nil )
|
268
|
+
#
|
269
|
+
# Passes if the method send returns a true value.
|
270
|
+
#
|
271
|
+
# +send_array+ is composed of:
|
272
|
+
# * A receiver
|
273
|
+
# * A method
|
274
|
+
# * Arguments to the method
|
275
|
+
#
|
276
|
+
# Example:
|
277
|
+
# assert_send([[1, 2], :member?, 1]) # -> pass
|
278
|
+
# assert_send([[1, 2], :member?, 4]) # -> fail
|
279
|
+
def assert_send send_ary, m = nil
|
280
|
+
recv, msg, *args = send_ary
|
281
|
+
m = message(m) {
|
282
|
+
if args.empty?
|
283
|
+
argsstr = ""
|
284
|
+
else
|
285
|
+
(argsstr = mu_pp(args)).sub!(/\A\[(.*)\]\z/m, '(\1)')
|
286
|
+
end
|
287
|
+
"Expected #{mu_pp(recv)}.#{msg}#{argsstr} to return true"
|
288
|
+
}
|
289
|
+
assert recv.__send__(msg, *args), m
|
290
|
+
end
|
291
|
+
|
292
|
+
# :call-seq:
|
293
|
+
# assert_not_send( +send_array+, failure_message = nil )
|
294
|
+
#
|
295
|
+
# Passes if the method send doesn't return a true value.
|
296
|
+
#
|
297
|
+
# +send_array+ is composed of:
|
298
|
+
# * A receiver
|
299
|
+
# * A method
|
300
|
+
# * Arguments to the method
|
301
|
+
#
|
302
|
+
# Example:
|
303
|
+
# assert_not_send([[1, 2], :member?, 1]) # -> fail
|
304
|
+
# assert_not_send([[1, 2], :member?, 4]) # -> pass
|
305
|
+
def assert_not_send send_ary, m = nil
|
306
|
+
recv, msg, *args = send_ary
|
307
|
+
m = message(m) {
|
308
|
+
if args.empty?
|
309
|
+
argsstr = ""
|
310
|
+
else
|
311
|
+
(argsstr = mu_pp(args)).sub!(/\A\[(.*)\]\z/m, '(\1)')
|
312
|
+
end
|
313
|
+
"Expected #{mu_pp(recv)}.#{msg}#{argsstr} to return false"
|
314
|
+
}
|
315
|
+
assert !recv.__send__(msg, *args), m
|
316
|
+
end
|
317
|
+
|
318
|
+
ms = instance_methods(true).map {|sym| sym.to_s }
|
319
|
+
ms.grep(/\Arefute_/) do |m|
|
320
|
+
mname = ('assert_not_' << m.to_s[/.*?_(.*)/, 1])
|
321
|
+
alias_method(mname, m) unless ms.include? mname
|
322
|
+
end
|
323
|
+
alias assert_include assert_includes
|
324
|
+
alias assert_not_include assert_not_includes
|
325
|
+
|
326
|
+
def build_message(head, template=nil, *arguments) #:nodoc:
|
327
|
+
template &&= template.chomp
|
328
|
+
template.gsub(/\G((?:[^\\]|\\.)*?)(\\)?\?/) { $1 + ($2 ? "?" : mu_pp(arguments.shift)) }
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|