style_train 0.3.2 → 0.4.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.
@@ -294,14 +294,18 @@ CSS
294
294
  end
295
295
  end
296
296
 
297
- def opacity(value)
297
+ def opacity(value, opts={})
298
298
  value = value.to_f
299
299
  str = ""
300
300
  str << property( 'opacity', value )
301
- str << property( 'filter', "alpha(opacity=#{(value*100).to_i})")
301
+ str << alpha( value.to_f*100 ) if opts[:alpha]
302
302
  str
303
303
  end
304
304
 
305
+ def alpha(value)
306
+ property('filter', "alpha(opacity=#{(value.to_i)})")
307
+ end
308
+
305
309
  [
306
310
  'color', 'display', 'float', 'clear', 'visibility', 'cursor',
307
311
  'height', 'width', 'max_height', 'max_width', 'min_height', 'min_width',
@@ -1,5 +1,5 @@
1
1
  class Fixnum
2
- ['px', 'em', 'pt'].each do |meth|
2
+ ['px', 'em', 'pt', 'degrees'].each do |meth|
3
3
  class_eval <<-RUBY
4
4
  def #{meth}
5
5
  self.to_s + "#{meth}"
@@ -13,11 +13,15 @@ class Fixnum
13
13
  end
14
14
 
15
15
  class Float
16
- ['em', 'pt'].each do |meth|
16
+ ['em', 'pt', 'degrees'].each do |meth|
17
17
  class_eval <<-RUBY
18
18
  def #{meth}
19
19
  self.to_s + "#{meth}"
20
20
  end
21
21
  RUBY
22
22
  end
23
+
24
+ def percent
25
+ "#{self}%"
26
+ end
23
27
  end
@@ -0,0 +1,1447 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ Color = StyleTrain::Color unless defined?(Color)
4
+ describe Color do
5
+ TOLERANCE = 0.009
6
+
7
+ describe 'initialization' do
8
+ describe 'auto-detection' do
9
+ it 'raises an error if autodetection fails' do
10
+ lambda{ Color.new('ggg') }.should raise_error(Color::AutodetectionError)
11
+ end
12
+
13
+ describe 'transparent' do
14
+ before :all do
15
+ @trans = Color.new(:transparent)
16
+ @trans_too = Color.new('transparent')
17
+ end
18
+
19
+ it 'has the type transparent' do
20
+ @trans.type.should == @trans_too.type
21
+ @trans.type.should == :transparent
22
+ end
23
+
24
+ it 'has r, g, b values of 0' do
25
+ @trans.r.should == 0
26
+ @trans.g.should == 0
27
+ @trans.b.should == 0
28
+ end
29
+
30
+ it 'has an alpha of 0' do
31
+ @trans.alpha.should == 0
32
+ end
33
+
34
+ it 'should ignore options, alpha, background, etc' do
35
+ color = Color.new(:transparent, :alpha => 1.0, :background => '#666')
36
+ color.type.should == :transparent
37
+ color.alpha.should == 0
38
+ color.background.should be_nil
39
+ end
40
+ end
41
+
42
+ describe 'keyword colors' do
43
+ it 'sets the type appropriately when passed a symbol' do
44
+ Color.new(:lightyellow).type.should == :keyword
45
+ end
46
+
47
+ it 'raises an error if the symbol is not found' do
48
+ lambda{ Color.new(:light_puke) }.should raise_error(
49
+ Color::KeywordError, "Color :light_puke not found as a keyword"
50
+ )
51
+ end
52
+
53
+ it 'should not raise an error if :transparent is given' do
54
+ lambda{ Color.new(:transparent) }.should_not raise_error
55
+ end
56
+
57
+ it 'should set the r, g, and b values based on the key' do
58
+ color = Color.new(:azure)
59
+ color.r.should == 240/255.0
60
+ color.b.should == 1.0
61
+ color.g.should == 1.0
62
+ end
63
+ end
64
+
65
+ describe 'hexidecimal colors' do
66
+ it 'sets the type to :hex' do
67
+ Color.new('#666').type.should == :hex
68
+ Color.new('#666666').type.should == :hex
69
+ end
70
+
71
+ it 'sets the hex_6' do
72
+ Color.new('#444').hex_6.should == 0x444444
73
+ Color.new('#404040').hex_6.should == 0x404040
74
+ end
75
+
76
+ it 'sets the rgb appropriately' do
77
+ @gray = Color.new('#666')
78
+ @red = Color.new('#993300')
79
+ @gold = Color.new('#FC0')
80
+
81
+ @gray.r.should == 102/255.0
82
+ @red.r.should == 153/255.0
83
+ @gold.r.should == 255/255.0
84
+
85
+ @gray.g.should == 102/255.0
86
+ @red.g.should == 51/255.0
87
+ @gold.g.should == 204/255.0
88
+
89
+ @gray.b.should == 102/255.0
90
+ @red.b.should == 0
91
+ @gold.b.should == 0
92
+ end
93
+
94
+ it 'should pass of colors with many arguments' do
95
+ lambda { Color.new('666', 100, 100) }.should raise_error(Color::AutodetectionError)
96
+ end
97
+ end
98
+
99
+ describe 'rgb colors' do
100
+ before do
101
+ @color = Color.new(20,40,60)
102
+ end
103
+
104
+ it 'should set the type to :rgb' do
105
+ @color.type.should == :rgb
106
+ end
107
+
108
+ it 'sets the rgb values appropriately' do
109
+ @color.r.should == 20/255.0
110
+ @color.g.should == 40/255.0
111
+ @color.b.should == 60/255.0
112
+ end
113
+
114
+ it 'takes percentages if a string' do
115
+ color = Color.new(0.percent, 50.percent, 100.percent)
116
+ color.type.should == :rgb
117
+ color.r.should == 0
118
+ color.g.should == 0.5
119
+ color.b.should == 1.0
120
+ end
121
+
122
+ it 'takes a ratio' do
123
+ color = Color.new(0.0, 0.5, 1.0)
124
+ color.type.should == :rgb
125
+ color.r.should == 0
126
+ color.g.should == 0.5
127
+ color.b.should == 1.0
128
+ end
129
+
130
+ it 'raises an error if numbers are too large' do
131
+ lambda{ Color.new(20, 300, 255) }.should raise_error(Color::ByteError)
132
+ end
133
+
134
+ it 'raises an error if the numbers are too small' do
135
+ lambda{ Color.new(20, 100, -155) }.should raise_error(Color::ByteError)
136
+ end
137
+ end
138
+
139
+ describe 'hsl colors' do
140
+ before do
141
+ @color = Color.new( 350, 50.percent, 100.percent )
142
+ end
143
+
144
+ it 'correctly detects the type when first argument is greater than 255' do
145
+ @color.type.should == :hsl
146
+ end
147
+
148
+ it 'takes ratios for s and l' do
149
+ color = Color.new( 120.degrees, 0.0, 0.75 )
150
+ color.type.should == :hsl
151
+ color.h.should == 120.0/360
152
+ color.s.should == 0
153
+ color.l.should == 0.75
154
+ end
155
+
156
+ it 'sets the hsl correctly' do
157
+ color = Color.new(0.degrees, 0.percent, 40.percent)
158
+ color.h.should == 0
159
+ color.s.should == 0
160
+ color.l.should == 0.4
161
+ end
162
+
163
+ it 'converts to rgb correctly' do
164
+ color = Color.new(0.degrees, 0.percent, 40.percent)
165
+ color.r.should == 102/255.0
166
+ color.g.should == 102/255.0
167
+ color.b.should == 102/255.0
168
+
169
+ color = Color.new(210.degrees, 65.percent, 20.percent)
170
+ color.r.should == 0.07
171
+ color.g.should be_within(TOLERANCE).of(0.2)
172
+ color.b.should == 0.33
173
+ end
174
+ end
175
+ end
176
+
177
+ describe 'explicit typing' do
178
+ describe 'keyword' do
179
+ it 'will raise an error if the keyword is not found' do
180
+ lambda { Color.new(:light_puke, :type => :keyword) }.should raise_error(Color::KeywordError)
181
+ end
182
+ end
183
+
184
+ describe 'hexidecimal colors' do
185
+ it 'will convert a string without the preceeding #' do
186
+ color = Color.new('666', :type => :hex )
187
+ color.type.should == :hex
188
+ color.r.should == 102/255.0
189
+ color.g.should == 102/255.0
190
+ color.b.should == 102/255.0
191
+ end
192
+
193
+ it 'raises an error if the string does not match hex color standards' do
194
+ lambda{ Color.new('ggg', :type => :hex) }.should raise_error(ArgumentError)
195
+ end
196
+ end
197
+
198
+ describe 'rgb colors' do
199
+ it 'should work with good numbers' do
200
+ color = Color.new(255,255,0, :type => :rgb)
201
+ color.type.should == :rgb
202
+ color.r.should == 1.0
203
+ color.g.should == 1.0
204
+ color.b.should == 0
205
+ end
206
+
207
+ it 'raises an error if any byte number is out of range' do
208
+ lambda{ Color.new(300, 100, 100, :type => :rgb) }.should raise_error(ArgumentError)
209
+ end
210
+
211
+ it 'raises an error if any percentage is out of range' do
212
+ lambda{ Color.new(300.percent, 100.percent, 100.percent, :type => :rgb) }.should raise_error(ArgumentError)
213
+ end
214
+
215
+ it 'raises an error if any ratio is out of range' do
216
+ lambda{ Color.new(2.0, 1.0, 1.0, :type => :rgb) }.should raise_error(ArgumentError)
217
+ end
218
+ end
219
+
220
+ describe 'hsl colors' do
221
+ it 'will recognize the type even if hue is within byte range' do
222
+ color = Color.new(220, 127, 127, :type => :hsl)
223
+ color.type.should == :hsl
224
+ color.r.should be_within(TOLERANCE).of(0.25)
225
+ color.g.should be_within(TOLERANCE).of(0.416)
226
+ color.b.should be_within(TOLERANCE).of(0.75)
227
+ end
228
+
229
+ it 'accepts ratios for hue' do
230
+ color = Color.new(0.611111, 0.5, 0.5, :type => :hsl)
231
+ color.type.should == :hsl
232
+ color.r.should == 0.25
233
+ color.g.should be_within(TOLERANCE).of(0.416)
234
+ color.b.should == 0.75
235
+ end
236
+
237
+ it 'accepts percentages for hue' do
238
+ color = Color.new(61.1111.percent, 50.percent, 50.percent, :type => :hsl)
239
+ color.type.should == :hsl
240
+ color.r.should == 0.25
241
+ color.g.should be_within(TOLERANCE).of(0.416)
242
+ color.b.should == 0.75
243
+ end
244
+ end
245
+ end
246
+
247
+ describe 'alpha' do
248
+ describe 'autodetection' do
249
+ it 'ignores the alpha with a transparent color' do
250
+ Color.new(:transparent, :alpha => 0.5).alpha.should == 0.0
251
+ end
252
+
253
+ it 'sets the alpha with a keyword type' do
254
+ Color.new(:lightyellow, :alpha => 0.5).alpha.should == 0.5
255
+ end
256
+
257
+ it 'sets the alpha with a hex color' do
258
+ Color.new('#666', :alpha => 0.75).alpha.should == 0.75
259
+ end
260
+
261
+ it 'sets the alpha with a rgb color' do
262
+ Color.new(100.percent, 50.percent, 25.percent, :alpha => 0.25).alpha.should == 0.25
263
+ end
264
+
265
+ it 'sets the alpha with a hsl color' do
266
+ Color.new(20.degrees, 50.percent, 50.percent, :alpha => 0.10).alpha.should == 0.1
267
+ end
268
+
269
+ it 'sets the alpha to 1.0 by default' do
270
+ Color.new(:lightyellow).alpha.should == 1.0
271
+ end
272
+ end
273
+
274
+ describe 'explicit typing' do
275
+ it 'ignores the alpha with a transparent color' do
276
+ Color.new(:transparent, :alpha => 0.5, :type => :transparent).alpha.should == 0.0
277
+ end
278
+
279
+ it 'sets the alpha with a keyword type' do
280
+ Color.new(:lightyellow, :type => :keyword, :alpha => 0.5).alpha.should == 0.5
281
+ end
282
+
283
+ it 'sets the alpha with a hex color' do
284
+ Color.new('#123456', :type => :hex, :alpha => 0.25).alpha.should == 0.25
285
+ end
286
+
287
+ it 'sets the alpha with a rgb color' do
288
+ Color.new(255,127,64, :type => :rgb, :alpha => 0.1).alpha.should == 0.1
289
+ end
290
+
291
+ it 'sets the alpha with a hsl color' do
292
+ Color.new(20, 50.percent, 50.percent, :type => :hsl, :alpha => 0.75).alpha.should == 0.75
293
+ end
294
+ end
295
+ end
296
+
297
+ describe 'background' do
298
+ describe 'autodetection' do
299
+ describe 'different detection types' do
300
+ it 'ignores the background with a transparent color' do
301
+ Color.new(:transparent, :background => :black).background.should == nil
302
+ end
303
+
304
+ it 'sets the background with a keyword type' do
305
+ Color.new(:lightyellow, :background => :black).background.should == Color.new(:black)
306
+ end
307
+
308
+ it 'sets the background with a hex color' do
309
+ Color.new('#666', :background => :black).background.should == Color.new(:black)
310
+ end
311
+
312
+ it 'sets the background with a rgb color' do
313
+ Color.new(100.percent, 50.percent, 25.percent, :background => :black).background.should == Color.new(:black)
314
+ end
315
+
316
+ it 'sets the background with a hsl color' do
317
+ Color.new(20.degrees, 50.percent, 50.percent, :background => :black).background.should == Color.new(:black)
318
+ end
319
+
320
+ it 'sets the background to :white by default' do
321
+ Color.new(:lightyellow).background.should == Color.new(:white)
322
+ end
323
+ end
324
+
325
+ describe "different background types/arguments" do
326
+ it 'takes background a keyword arguments' do
327
+ Color.new(:lightyellow, :background => :black).background.should == Color.new(:black)
328
+ end
329
+
330
+ it 'takes background with hex color arguments' do
331
+ Color.new(:lightyellow, :background => '#000').background.should == Color.new(:black)
332
+ end
333
+
334
+ it 'takes background with rgb color arguments' do
335
+ Color.new(:lightyellow, :background => [0,0,0]).background.should == Color.new(:black)
336
+ end
337
+
338
+ it 'takes background with hsl color arguments' do
339
+ Color.new(:lightyellow, :background => [0.degrees, 0, 0]).background.should == Color.new(:black)
340
+ end
341
+ end
342
+ end
343
+
344
+ describe 'explicit typing' do
345
+ it 'ignores the background with a transparent color' do
346
+ Color.new(:transparent, :background => :black, :type => :transparent).background.should == nil
347
+ end
348
+
349
+ it 'sets the background with a keyword type' do
350
+ Color.new(:lightyellow, :background => :black, :type => :keyword).background.should == Color.new(:black)
351
+ end
352
+
353
+ it 'sets the background with a hex color' do
354
+ Color.new('#666', :background => :black, :type => :hex).background.should == Color.new(:black)
355
+ end
356
+
357
+ it 'sets the background with a rgb color' do
358
+ Color.new(100.percent, 50.percent, 25.percent, :background => :black, :type => :rgb).background.should == Color.new(:black)
359
+ end
360
+
361
+ it 'sets the background with a hsl color' do
362
+ Color.new(20.degrees, 50.percent, 50.percent, :background => :black, :type => :hsl).background.should == Color.new(:black)
363
+ end
364
+ end
365
+ end
366
+ end
367
+
368
+ describe 'alpha' do
369
+ describe 'acceptable values' do
370
+ before do
371
+ @color = Color.new('666')
372
+ end
373
+
374
+ it 'takes ratios' do
375
+ @color.alpha = 0.5
376
+ @color.alpha.should == 0.5
377
+ end
378
+
379
+ it 'should raise an error if the ratio is out of range' do
380
+ lambda { @color.alpha = 1.1 }.should raise_error( Color::RatioError )
381
+ end
382
+
383
+ it 'takes percentages' do
384
+ @color.alpha = 72.5.percent
385
+ @color.alpha.should == 0.725
386
+ end
387
+
388
+ it 'accepts integers as percentages' do
389
+ @color.alpha = 78
390
+ @color.alpha.should == 0.78
391
+ end
392
+
393
+ it 'should raise an error if the percentage is out of range' do
394
+ lambda { @color.alpha = 300.percent }.should raise_error(Color::PercentageError)
395
+ end
396
+ end
397
+ end
398
+
399
+ describe 'background' do
400
+ before do
401
+ @background = Color.new(:lightyellow)
402
+ @color = Color.new(:black, :alpha => 0.5)
403
+ end
404
+
405
+ it 'takes a color object' do
406
+ @color.background = @background
407
+ @color.background.should == @background
408
+ end
409
+
410
+ it 'otherwise tries to construct a color object from the arguments' do
411
+ @color.background = :lightyellow
412
+ @color.background.should == @background
413
+ end
414
+ end
415
+
416
+ describe 'comparisons' do
417
+ it 'should be === if the colors have the same object id' do
418
+ (Color.new(:lightyellow) === Color.new(:lightyellow)).should == false
419
+ color = Color.new(:lightyellow)
420
+ (color === color).should == true
421
+ end
422
+
423
+ it 'should be =~ if the colors have the same rgb, but different alphas' do
424
+ (Color.new(:lightyellow, :alpha => 0.5) =~ Color.new(:lightyellow)).should == true
425
+ end
426
+
427
+ describe '==' do
428
+ it 'should be false if the alpha is different' do
429
+ Color.new(255, 255, 224, :alpha => 0.5).should_not == Color.new(:lightyellow)
430
+ end
431
+
432
+ it 'should be false if the rgb values are different' do
433
+ Color.new(255, 255, 225, :alpha => 1.0).should_not == Color.new(:lightyellow)
434
+ end
435
+
436
+ it 'should be == if the colors have the same rgb and alpha' do
437
+ Color.new(255, 255, 224, :alpha => 1.0).should == Color.new(:lightyellow)
438
+ end
439
+
440
+ it 'should be indifferent to backgrounds' do
441
+ Color.new(255, 255, 224, :alpha => 1.0, :background => :black).should == Color.new(:lightyellow)
442
+ end
443
+ end
444
+ end
445
+
446
+ describe 'normalizer' do
447
+ describe 'percentages' do
448
+ it 'should return valid integers' do
449
+ Color.normalize_percentage(25.percent).should == 25
450
+ end
451
+
452
+ it 'should return valid floats' do
453
+ Color.normalize_percentage(50.5.percent).should == 50.5
454
+ end
455
+
456
+ it 'works with an integer' do
457
+ Color.normalize_percentage(50).should == 50
458
+ end
459
+
460
+ it 'works with floats' do
461
+ Color.normalize_percentage(20.5).should == 20.5
462
+ end
463
+
464
+ it 'raises an error if greater than 100' do
465
+ lambda{ Color.normalize_percentage(105) }.should raise_error(Color::PercentageError)
466
+ end
467
+
468
+ it 'raises an error if lower than 0' do
469
+ lambda{ Color.normalize_percentage(-25) }.should raise_error(Color::PercentageError)
470
+ end
471
+
472
+ it 'converts to byte' do
473
+ Color.percentage_to_byte(100.0).should == 255
474
+ Color.percentage_to_byte(0).should == 0
475
+ Color.percentage_to_byte(50.percent).should == 127
476
+ end
477
+ end
478
+
479
+ describe 'degrees' do
480
+ it 'should return a number between 0 and 359 when given such a number' do
481
+ Color.normalize_degrees(30).should == 30/360.0
482
+ Color.normalize_degrees(42).should == 42/360.0
483
+ end
484
+
485
+ it 'should return a number when given a degree string' do
486
+ Color.normalize_degrees(42.degrees).should == 42/360.0
487
+ end
488
+
489
+ it 'should return nil when given a string without degrees' do
490
+ Color.normalize_degrees('42').should == nil
491
+ end
492
+
493
+ it 'should normalize a number greater than 359' do
494
+ Color.normalize_degrees(360).should == 0
495
+ Color.normalize_degrees(460).should == 100/360.0
496
+ end
497
+
498
+ it 'should normalize negative number' do
499
+ Color.normalize_degrees(-127).should == 233/360.0
500
+ end
501
+
502
+ it 'works with strings containing "degrees"' do
503
+ Color.normalize_degrees(127.degrees).should == 127/360.0
504
+ end
505
+
506
+ it 'rejects percentage strings' do
507
+ Color.normalize_degrees(12.percent).should == nil
508
+ end
509
+ end
510
+
511
+ describe 'ratios' do
512
+ it 'raises an error if below 0' do
513
+ lambda{ Color.ratio_to_byte(-0.1) }.should raise_error(Color::RatioError)
514
+ end
515
+
516
+ it 'raises an error if it is above 1.0' do
517
+ lambda{ Color.ratio_to_byte(1.1)}.should raise_error(Color::RatioError)
518
+ end
519
+
520
+ it 'converts correctly to byte otherwise' do
521
+ Color.ratio_to_byte(0.5).should == 127
522
+ end
523
+ end
524
+ end
525
+
526
+ describe 'type transformation' do
527
+ before do
528
+ @red_values = {
529
+ :rgb => [100, 25, 25],
530
+ :hex => ['641919', 0x641919],
531
+ :hsl => [0.degrees, 0.6, 0.25]
532
+ }
533
+ @green_values = {
534
+ :rgb => [25, 100, 25],
535
+ :hex => ['196419', 0x196419],
536
+ :hsl => [120.degrees, 0.60, 0.25]
537
+ }
538
+ @blue_values = {
539
+ :rgb => [25, 25, 100],
540
+ :hex => ['191964', 0x191964],
541
+ :hsl => [240.degrees, 0.60, 0.25]
542
+ }
543
+ end
544
+
545
+ describe '#set_hsl' do
546
+ before do
547
+ @red = Color.new(*@red_values[:rgb])
548
+ @red.set_hsl
549
+ @blue = Color.new(*@blue_values[:rgb])
550
+ @blue.set_hsl
551
+ @green = Color.new(*@green_values[:rgb])
552
+ @green.set_hsl
553
+ end
554
+
555
+ it 'changes the type to :hsl' do
556
+ @red.type.should == :hsl
557
+ @blue.type.should == :hsl
558
+ @green.type.should == :hsl
559
+ end
560
+
561
+ it 'converts adds hsl value' do
562
+ @red.h.should be_within(TOLERANCE).of(Color.normalize_degrees(@red_values[:hsl][0]))
563
+ @red.s.should be_within(TOLERANCE).of( @red_values[:hsl][1])
564
+ @red.l.should be_within(TOLERANCE).of(@red_values[:hsl][2])
565
+
566
+ @green.h.should be_within(TOLERANCE).of(Color.normalize_degrees(@green_values[:hsl][0]))
567
+ @green.s.should be_within(TOLERANCE).of( @green_values[:hsl][1])
568
+ @green.l.should be_within(TOLERANCE).of(@green_values[:hsl][2])
569
+
570
+ @blue.h.should be_within(TOLERANCE).of(Color.normalize_degrees(@blue_values[:hsl][0]))
571
+ @blue.s.should be_within(TOLERANCE).of( @blue_values[:hsl][1])
572
+ @blue.l.should be_within(TOLERANCE).of(@blue_values[:hsl][2])
573
+ end
574
+ end
575
+
576
+ describe '#set_rgb' do
577
+ before do
578
+ @color = Color.new('#555')
579
+ @color.set_rgb
580
+ end
581
+
582
+ it 'changes the type' do
583
+ @color.type.should == :rgb
584
+ end
585
+ end
586
+
587
+ describe '#set_hex' do
588
+ before do
589
+ @red = Color.new(*@red_values[:rgb])
590
+ end
591
+
592
+ it 'sets the hex and hex_6' do
593
+ @red.hex = 'foo'
594
+ @red.hex_6 = 'foo'
595
+ @red.set_hex
596
+ @red.hex.should == @red_values[:hex][0]
597
+ @red.hex_6.should == @red_values[:hex][1]
598
+ end
599
+
600
+ it 'sets the type to :hex' do
601
+ @red.set_hex
602
+ @red.type.should == :hex
603
+ end
604
+ end
605
+
606
+ describe '#hsl_to_rgb' do
607
+ before do
608
+ @red = Color.new(*@red_values[:hsl])
609
+ @red.set_hex
610
+ @red.l += 0.1
611
+ @red.hsl_to_rgb
612
+ end
613
+
614
+ it 'resets the r, g, b values from h, s, l' do
615
+ @red.r.should be_within(TOLERANCE).of(143/255.0)
616
+ @red.g.should be_within(TOLERANCE).of(36/255.0)
617
+ @red.b.should be_within(TOLERANCE).of(36/255.0)
618
+ end
619
+
620
+ it 'clears the hex' do
621
+ @red.hex.should == nil
622
+ @red.hex_6.should == nil
623
+ end
624
+ end
625
+ end
626
+
627
+ describe 'modification' do
628
+ before do
629
+ @red_values = {
630
+ :rgb => [100, 25, 25],
631
+ :hex => ['641919', 0x641919],
632
+ :hsl => [Color.normalize_degrees(0.degrees), 0.6, 0.25]
633
+ }
634
+ @red = Color.new(*@red_values[:rgb])
635
+ end
636
+
637
+ describe 'shift' do
638
+ describe 'lighten!' do
639
+ before do
640
+ @red.lighten!
641
+ end
642
+
643
+ it 'adds 10% to the l value by default' do
644
+ @red.l.should be_within(TOLERANCE).of(@red_values[:hsl][2] + 0.1)
645
+ end
646
+
647
+ it 'recalculates the rgb' do
648
+ @red.r.should be_within(TOLERANCE).of(143/255.0)
649
+ @red.g.should be_within(TOLERANCE).of(36/255.0)
650
+ @red.b.should be_within(TOLERANCE).of(36/255.0)
651
+ end
652
+
653
+ it 'takes a percentage argument and adds that from the l' do
654
+ l = @red.l
655
+ @red.lighten!(30.percent)
656
+ @red.l.should == l + 0.30
657
+ end
658
+
659
+ it 'takes a ratio argument' do
660
+ l = @red.l
661
+ @red.lighten!(0.21)
662
+ @red.l.should == l + 0.21
663
+ end
664
+
665
+ it 'assumes integers are percentages' do
666
+ l = @red.l
667
+ @red.lighten!(20)
668
+ @red.l.should == l + 0.2
669
+ @red.lighten!(80)
670
+ @red.l.should == 1.0
671
+ end
672
+
673
+ it 'should cap at 100 percent' do
674
+ @red.lighten!(0.80)
675
+ @red.l.should == 1.0
676
+ end
677
+ end
678
+
679
+ describe 'lighten' do
680
+ before do
681
+ @less_red = @red.lighten
682
+ end
683
+
684
+ it 'should not affect the originating color' do
685
+ @red.type.should == :rgb
686
+ @red.r.should be_within(TOLERANCE).of(0.4)
687
+ end
688
+
689
+ it 'should return a transformed object' do
690
+ @less_red.r.should be_within(TOLERANCE).of(143/255.0)
691
+ @less_red.g.should be_within(TOLERANCE).of(36/255.0)
692
+ @less_red.b.should be_within(TOLERANCE).of(36/255.0)
693
+ end
694
+ end
695
+
696
+ describe 'darken!' do
697
+ before do
698
+ @red.darken!
699
+ end
700
+
701
+ it 'makes subtracts 10% to the l value by default' do
702
+ @red.l.should be_within(TOLERANCE).of(@red_values[:hsl][2] - 0.1)
703
+ end
704
+
705
+ it 'recalculates the rgb' do
706
+ @red.r.should be_within(TOLERANCE).of(61/255.0)
707
+ @red.g.should be_within(TOLERANCE).of(15/255.0)
708
+ @red.b.should be_within(TOLERANCE).of(15/255.0)
709
+ end
710
+
711
+ it 'takes a percentage argument and subtracts that from the l' do
712
+ l = @red.l
713
+ @red.darken!(5.percent)
714
+ @red.l.should == l - 0.05
715
+ end
716
+
717
+ it 'takes a ratio argument' do
718
+ l = @red.l
719
+ @red.darken!(0.07)
720
+ @red.l.should == l - 0.07
721
+ end
722
+ end
723
+
724
+ describe 'darken' do
725
+ before do
726
+ @darker_red = @red.darken
727
+ end
728
+
729
+ it 'should not affect the originating color' do
730
+ @red.type.should == :rgb
731
+ @red.r.should be_within(TOLERANCE).of(0.4)
732
+ end
733
+
734
+ it 'should return a transformed object' do
735
+ @darker_red.r.should be_within(TOLERANCE).of(61/255.0)
736
+ @darker_red.g.should be_within(TOLERANCE).of(15/255.0)
737
+ @darker_red.b.should be_within(TOLERANCE).of(15/255.0)
738
+ end
739
+ end
740
+
741
+ describe 'saturate!' do
742
+ before do
743
+ @red.saturate!
744
+ end
745
+
746
+ it 'adds 10% to the s value by default' do
747
+ @red.s.should be_within(TOLERANCE).of(@red_values[:hsl][1] + 0.1)
748
+ end
749
+
750
+ it 'recalculates the rgb' do
751
+ @red.r.should be_within(TOLERANCE).of(108/255.0)
752
+ @red.g.should be_within(TOLERANCE).of(19/255.0)
753
+ @red.b.should be_within(TOLERANCE).of(19/255.0)
754
+ end
755
+
756
+ it 'takes a percentage argument and adds that from the s' do
757
+ s = @red.s
758
+ @red.saturate!(30.percent)
759
+ @red.s.should == s + 0.30
760
+ end
761
+
762
+ it 'takes a ratio argument' do
763
+ s = @red.s
764
+ @red.saturate!(0.21)
765
+ @red.s.should be_within(TOLERANCE).of(s + 0.21)
766
+ end
767
+
768
+ it 'assumes integers are percentages' do
769
+ s = @red.s
770
+ @red.saturate!(20)
771
+ @red.s.should == s + 0.2
772
+ @red.saturate!(80)
773
+ @red.s.should == 1.0
774
+ end
775
+
776
+ it 'should cap at 100 percent' do
777
+ @red.saturate!(0.80)
778
+ @red.s.should == 1.0
779
+ end
780
+
781
+ it 'aliases to #brighten' do
782
+ @red.brighten!(0.8)
783
+ @red.s.should == 1.0
784
+ end
785
+ end
786
+
787
+ describe 'saturate' do
788
+ before do
789
+ @brighter_red = @red.saturate
790
+ end
791
+
792
+ it 'should not affect the originating color' do
793
+ @red.type.should == :rgb
794
+ @red.r.should be_within(TOLERANCE).of(0.4)
795
+ end
796
+
797
+ it 'should return a transformed object' do
798
+ @brighter_red.r.should be_within(TOLERANCE).of(108/255.0)
799
+ @brighter_red.g.should be_within(TOLERANCE).of(19/255.0)
800
+ @brighter_red.b.should be_within(TOLERANCE).of(19/255.0)
801
+ end
802
+ end
803
+
804
+ describe 'dull!' do
805
+ before do
806
+ @red.dull!
807
+ end
808
+
809
+ it 'adds 10% to the s value by default' do
810
+ @red.s.should be_within(TOLERANCE).of(@red_values[:hsl][1] - 0.1)
811
+ end
812
+
813
+ it 'recalculates the rgb' do
814
+ @red.r.should be_within(TOLERANCE).of(96/255.0)
815
+ @red.g.should be_within(TOLERANCE).of(32/255.0)
816
+ @red.b.should be_within(TOLERANCE).of(32/255.0)
817
+ end
818
+
819
+ it 'takes a percentage argument and adds that from the s' do
820
+ s = @red.s
821
+ @red.dull!(30.percent)
822
+ @red.s.should be_within(TOLERANCE).of(s - 0.30)
823
+ end
824
+
825
+ it 'takes a ratio argument' do
826
+ s = @red.s
827
+ @red.dull!(0.21)
828
+ @red.s.should be_within(TOLERANCE).of(s - 0.21)
829
+ end
830
+
831
+ it 'assumes integers are percentages' do
832
+ s = @red.s
833
+ @red.dull!(20)
834
+ @red.s.should be_within(TOLERANCE).of(s - 0.2)
835
+ @red.dull!(80)
836
+ @red.s.should == 0.0
837
+ end
838
+
839
+ it 'should cap at 100 percent' do
840
+ @red.dull!(0.80)
841
+ @red.s.should == 0.0
842
+ end
843
+
844
+ it 'aliases to #desaturate' do
845
+ @red.desaturate!(0.8)
846
+ @red.s.should == 0.0
847
+ end
848
+ end
849
+
850
+ describe 'dull' do
851
+ before do
852
+ @dull_red = @red.dull
853
+ end
854
+
855
+ it 'should not affect the originating color' do
856
+ @red.type.should == :rgb
857
+ @red.r.should be_within(TOLERANCE).of(0.4)
858
+ end
859
+
860
+ it 'should return a transformed object' do
861
+ @dull_red.r.should be_within(TOLERANCE).of(96/255.0)
862
+ @dull_red.g.should be_within(TOLERANCE).of(32/255.0)
863
+ @dull_red.b.should be_within(TOLERANCE).of(32/255.0)
864
+ end
865
+ end
866
+ end
867
+
868
+ describe 'rotate' do
869
+ describe 'arbitrary' do
870
+ it 'defaults to 10 degrees' do
871
+ @new = @red.rotate
872
+ @new.h.should be_within(TOLERANCE).of(10/360.0)
873
+ end
874
+
875
+ it 'takes other positive degree values' do
876
+ @new = @red.rotate(30.degrees)
877
+ @new.h.should be_within(TOLERANCE).of(30/360.0 )
878
+ end
879
+
880
+ it 'takes negative degrees' do
881
+ @new = @red.rotate(-20.degrees)
882
+ @new.h.should be_within(TOLERANCE).of((360-20)/360.0 )
883
+ end
884
+
885
+ it 'will rotate beyond end points' do
886
+ @new = @red.rotate(300.degrees)
887
+ @new.h.should be_within(TOLERANCE).of(300/360.0)
888
+
889
+ @new.rotate!(100.degrees)
890
+ @new.h.should be_within(TOLERANCE).of(40/360.0)
891
+ end
892
+
893
+ it 'takes ratios' do
894
+ @red.rotate(0.5).h.should be_within(TOLERANCE).of(0.5)
895
+ end
896
+
897
+ it 'calculates the rgb values' do
898
+ @new = @red.rotate(0.5)
899
+ @new.r.should be_within(TOLERANCE).of(26/255.0)
900
+ @new.g.should be_within(TOLERANCE).of(102/255.0)
901
+ @new.b.should be_within(TOLERANCE).of(102/255.0)
902
+ end
903
+
904
+ it 'returns a new color object' do
905
+ @new = @red.rotate(0.5)
906
+ @new.should_not == @red
907
+ end
908
+
909
+ it 'does not modify the existing object' do
910
+ @red.rotate(0.5)
911
+ @red.type.should == :rgb
912
+ @red.r.should be_within(TOLERANCE).of(@red_values[:rgb][0]/255.0)
913
+ end
914
+
915
+ it 'has a ! method that modifies self' do
916
+ @red.rotate!(0.5)
917
+ @red.type.should == :hsl
918
+ @red.r.should be_within(TOLERANCE).of(26/255.0)
919
+ end
920
+ end
921
+
922
+ describe 'compliment' do
923
+ it 'rotates half way around' do
924
+ @red.compliment.should == @red.rotate(0.5)
925
+ end
926
+ end
927
+
928
+ describe '#dial' do
929
+ it 'gives triangular colors' do
930
+ @red.triangulate.should == [@red, @red.rotate(120.degrees), @red.rotate(240.degrees)]
931
+ end
932
+
933
+ it 'gives offset triangular colors' do
934
+ dial = @red.triangulate(1/6.0)
935
+ dial[0].should == @red.rotate(1/6.0)
936
+ dial[1].should == @red.rotate(0.5)
937
+ dial[2].should == @red.rotate(5/6.0)
938
+ end
939
+
940
+ it 'dialing allows dividing by any integer' do
941
+ @red.dial(5).should == [
942
+ @red,
943
+ @red.rotate((360/5.0).degrees),
944
+ @red.rotate((2*360/5.0).degrees),
945
+ @red.rotate((3*360/5.0).degrees),
946
+ @red.rotate((4*360/5.0).degrees)
947
+ ]
948
+ end
949
+
950
+ it 'dailing allows offset too' do
951
+ @red.dial(5, 120.degrees).should == [
952
+ @red.rotate(120.degrees),
953
+ @red.rotate((120 + 360/5.0).degrees),
954
+ @red.rotate((120 + 2*360/5.0).degrees),
955
+ @red.rotate((120 + 3*360/5.0).degrees),
956
+ @red.rotate((120 + 4*360/5.0).degrees)
957
+ ]
958
+ end
959
+ end
960
+
961
+ describe 'warmer' do
962
+ it 'does nothing if at the warmest hue' do
963
+ @red.rotate!(Color::WARMEST_HUE)
964
+ @red.warmer.should == @red
965
+ end
966
+
967
+ it 'does nothing if at the coldest hue' do
968
+ @red.rotate!(Color::COLDEST_HUE)
969
+ @red.warmer.should == @red
970
+ end
971
+
972
+ describe 'direction' do
973
+ before do
974
+ @red.rotate!(0.5)
975
+ end
976
+
977
+ describe 'hue is between 0 degrees and 240 degrees' do
978
+ it 'defaults to rotating 10 degrees lower' do
979
+ @red.warmer.h.should be_within(TOLERANCE).of( 0.5 - 10/360.0 )
980
+ end
981
+
982
+ it 'will not go below the warmest point' do
983
+ # currently at 180
984
+ @red.rotate!(-175.degrees) # to 5 degrees
985
+ @red.warmer.h.should be_within(TOLERANCE).of(0.0) # subtract 10 degrees, should stop at 0
986
+ end
987
+
988
+ it 'takes an custom rotation amount' do
989
+ @red.warmer(0.4).h.should be_within(TOLERANCE).of(0.5 - 0.4)
990
+ end
991
+ end
992
+
993
+ describe "hue is between 240 degrees and 360" do
994
+ before do
995
+ @red.rotate! 0.25 # 270 degrees
996
+ end
997
+
998
+ it 'defaults to rotating 10 degrees higher' do
999
+ @red.warmer.h.should be_within( TOLERANCE ).of( 0.75 + 10/360.0 )
1000
+ end
1001
+
1002
+ it 'takes a custom rotation amount' do
1003
+ @red.warmer(0.2).h.should be_within( TOLERANCE ).of( 0.95 )
1004
+ end
1005
+
1006
+ it 'will not go higher than 360' do
1007
+ @red.warmer(0.3).h.should be_within( TOLERANCE ).of( 0.0 )
1008
+ end
1009
+ end
1010
+ end
1011
+ end
1012
+
1013
+ describe 'cooler' do
1014
+ it 'does nothing if at the warmest hue' do
1015
+ @red.rotate!(Color::WARMEST_HUE)
1016
+ @red.cooler.should == @red
1017
+ end
1018
+
1019
+ it 'does nothing if at the coldest hue' do
1020
+ @red.rotate!(Color::COLDEST_HUE)
1021
+ @red.cooler.should == @red
1022
+ end
1023
+
1024
+ describe 'direction' do
1025
+ before do
1026
+ @red.rotate!(0.5)
1027
+ end
1028
+
1029
+ describe 'hue is between 0 degrees and 240 degrees' do
1030
+ it 'defaults to rotating 10 degrees higher' do
1031
+ @red.cooler.h.should be_within(TOLERANCE).of( 0.5 + 10/360.0 )
1032
+ end
1033
+
1034
+ it 'will not go below the coolest point' do
1035
+ # currently at 180
1036
+ @red.rotate!(60.degrees) # change to 235 degrees
1037
+ @red.cooler.h.should be_within(TOLERANCE).of(Color::COLDEST_HUE) # adding 10 degrees should stop at 240
1038
+ end
1039
+
1040
+ it 'takes an custom rotation amount' do
1041
+ @red.cooler(0.1).h.should be_within(TOLERANCE).of(0.5 + 0.1)
1042
+ end
1043
+ end
1044
+
1045
+ describe "hue is between 240 degrees and 360" do
1046
+ before do
1047
+ @red.rotate! 0.25 # 270 degrees = 0.75
1048
+ end
1049
+
1050
+ it 'defaults to rotating 10 degrees lower' do
1051
+ @red.cooler.h.should be_within( TOLERANCE ).of( 0.75 - 10/360.0 )
1052
+ end
1053
+
1054
+ it 'takes a custom rotation amount' do
1055
+ @red.cooler(0.05).h.should be_within( TOLERANCE ).of( 0.70 )
1056
+ end
1057
+
1058
+ it 'will not go lower than than 240 degress' do
1059
+ @red.cooler(0.1).h.should be_within( TOLERANCE ).of( Color::COLDEST_HUE )
1060
+ end
1061
+ end
1062
+ end
1063
+ end
1064
+ end
1065
+
1066
+ describe 'combining colors' do
1067
+ before :all do
1068
+ @black = Color.new('#000')
1069
+ @yellow = Color.new(:lightyellow)
1070
+ @trans = Color.new(:lightyellow, :alpha => 0.5)
1071
+ end
1072
+
1073
+ describe 'layering' do
1074
+ before do
1075
+ @white = Color.new('#FFF')
1076
+ @shadow = Color.new('#000', :alpha => 0.5)
1077
+ @dark_blue = Color.new(20,40,60, :alpha => 0.5)
1078
+ end
1079
+
1080
+ describe 'r, g, b values' do
1081
+ describe 'opaque top layer' do
1082
+ it 'should have the r, g, b values of the top layer' do
1083
+ color = @shadow.layer(@white)
1084
+ color.r.should == 1.0
1085
+ color.g.should == 1.0
1086
+ color.b.should == 1.0
1087
+ end
1088
+ end
1089
+
1090
+ describe 'opaque bottom layer' do
1091
+ before do
1092
+ @color = @white.layer(@shadow)
1093
+ end
1094
+
1095
+ it 'should mix the r, g, and b in proportion to the top layer\'s alpha' do
1096
+ @color.r.should == 0.5
1097
+ @color.g.should == 0.5
1098
+ @color.b.should == 0.5
1099
+ @color.alpha.should == 1.0
1100
+
1101
+ red = Color.new(153,0,0, :alpha => 0.25)
1102
+ color = @white.layer(red)
1103
+ color.r.should == 0.6*0.25 + 1.0*0.75
1104
+ color.g.should == 0*0.25 + 1.0*0.75
1105
+ color.b.should == 0*0.25 + 1.0*0.75
1106
+ end
1107
+ end
1108
+ end
1109
+
1110
+ describe 'alpha blending' do
1111
+ it 'should be 1.0 if bottom layer is opaque' do
1112
+ color = @white.layer(@shadow)
1113
+ color.alpha.should == 1.0
1114
+ end
1115
+
1116
+ it 'should be 1.0 if the top layer is opaque' do
1117
+ color = @shadow.layer(@white)
1118
+ color.alpha.should == 1.0
1119
+ end
1120
+
1121
+ it 'should have an alpha greater than or equal to the composites' do
1122
+ color = @dark_blue.layer(@shadow)
1123
+ (color.alpha >= @dark_blue.alpha).should be_true
1124
+ (color.alpha >= @shadow.alpha).should be_true
1125
+ end
1126
+
1127
+ it 'should calculate the blending of two alphas properly' do
1128
+ color = @dark_blue.layer(@shadow)
1129
+ color.alpha.should == 0.75 # 0.5 for the base color, plus 0.5 of the remaining transparency
1130
+ end
1131
+ end
1132
+ end
1133
+
1134
+ describe 'mix' do
1135
+ it 'should not affect either color' do
1136
+ black = @black.dup
1137
+ yellow = @yellow.dup
1138
+ @black.mix(@yellow)
1139
+ @black.should == black
1140
+ @yellow.should == yellow
1141
+ end
1142
+
1143
+ it 'mixes half of each by default' do
1144
+ color = @black.mix(@yellow)
1145
+ color.r.should == (@yellow.r/2.0)
1146
+ color.g.should == (@yellow.g/2.0)
1147
+ color.b.should == (@yellow.b/2.0)
1148
+ color.alpha.should == 1.0
1149
+ end
1150
+
1151
+ it 'mixes alphas' do
1152
+ color = @black.mix(@trans)
1153
+ color.r.should == (@yellow.r/2.0)
1154
+ color.g.should == (@yellow.g/2.0)
1155
+ color.b.should == (@yellow.b/2.0)
1156
+ color.alpha.should == 0.75
1157
+ end
1158
+
1159
+ it 'returns a copy, and does not alter the original' do
1160
+ color = @black.mix(@trans)
1161
+ color.should_not === @black
1162
+ color.should_not === @trans
1163
+ end
1164
+
1165
+ describe 'on another ratio' do
1166
+ it 'will mix on a ratio' do
1167
+ color = @black.mix(@trans, 0.25)
1168
+ color.r.should == @trans.r*0.25
1169
+ color.b.should == @trans.b*0.25
1170
+ color.g.should == @trans.g*0.25
1171
+ color.alpha.should == 1.0*0.75 + 0.5*0.25
1172
+ end
1173
+
1174
+ describe '#percent alternate syntax' do
1175
+ it 'sets the mix ratio on the color being mixed in' do
1176
+ @trans.percent(13)
1177
+ @trans.mix_ratio.should == 0.13
1178
+ end
1179
+
1180
+ it 'will be used by the mix when applied to the first color' do
1181
+ color = @black.percent(75).mix(@trans)
1182
+ color.r.should == @trans.r*0.25
1183
+ color.b.should == @trans.b*0.25
1184
+ color.g.should == @trans.g*0.25
1185
+ color.alpha.should == 1.0*0.75 + 0.5*0.25
1186
+ end
1187
+
1188
+ it 'will be used by the mix when applied to the second color' do
1189
+ color = @black.mix(@trans.percent(25))
1190
+ color.r.should == @trans.r*0.25
1191
+ color.b.should == @trans.b*0.25
1192
+ color.g.should == @trans.g*0.25
1193
+ color.alpha.should == 1.0*0.75 + 0.5*0.25
1194
+ end
1195
+
1196
+ it 'consumes the mix ratio' do
1197
+ color = @black.percent(75).mix(@trans.percent(75))
1198
+ @black.mix_ratio.should be_nil
1199
+ @trans.mix_ratio.should be_nil
1200
+ end
1201
+ end
1202
+ end
1203
+ end
1204
+
1205
+ describe 'flatten' do
1206
+ it 'does not affect colors with an alpha of 1' do
1207
+ @black.background = Color.new(:white)
1208
+ color = @black.flatten
1209
+ color.should == @black
1210
+ end
1211
+
1212
+ it 'layers the transparent color onto the background' do
1213
+ @yellow.background = @black
1214
+ color = @yellow.flatten
1215
+ layered = @black.layer(@yellow)
1216
+ color.should == layered
1217
+ end
1218
+
1219
+ it 'ignores the alpha of the background' do
1220
+ background = Color.new(:white, :alpha => 0.5)
1221
+ @yellow.background = background
1222
+ color = @yellow.flatten
1223
+
1224
+ background.alpha = 1.0
1225
+ color.should == background.layer(@yellow)
1226
+ end
1227
+ end
1228
+
1229
+ describe 'stepping' do
1230
+ before :all do
1231
+ @black = Color.new('#000')
1232
+ @yellow = Color.new(:lightyellow, :alpha => 0.5)
1233
+ @steps = @black.step(@yellow)
1234
+ end
1235
+
1236
+ it 'returs an array' do
1237
+ @steps.is_a?(Array).should be_true
1238
+ end
1239
+
1240
+ it 'has 10 steps by default' do
1241
+ @steps.size.should == 10
1242
+ end
1243
+
1244
+ it 'first color should be the starting point (dupped)' do
1245
+ @steps.first.should == @black
1246
+ @steps.first.should_not === @black
1247
+ end
1248
+
1249
+ it 'last color should be the last point (dupped)' do
1250
+ @steps.last.should == @yellow
1251
+ @steps.last.should_not === @yellow
1252
+ end
1253
+
1254
+ it 'interior steps should be equally spaced colors between the two' do
1255
+ mid = @steps[4]
1256
+ mid.r.should == @yellow.r/2.0
1257
+ mid.g.should == @yellow.g/2.0
1258
+ mid.b.should == @yellow.b/2.0
1259
+ end
1260
+
1261
+ it 'has takes optional number of steps' do
1262
+ @black.step(@yellow, 5).size.should == 5
1263
+ end
1264
+ end
1265
+ end
1266
+ end
1267
+
1268
+ describe 'rendering' do
1269
+ before do
1270
+ Color.render_as = nil
1271
+ end
1272
+
1273
+ it 'inspects' do
1274
+ color = Color.new('#000')
1275
+ color.inspect.should == "#<#{color.class}:#{color.object_id} @alpha=#{color.alpha} @r=#{color.r} @g=#{color.g} @b=#{color.b}>"
1276
+ end
1277
+
1278
+ describe 'class level render_as' do
1279
+ it 'defaults to :hex' do
1280
+ Color.render_as.should == :hex
1281
+ end
1282
+
1283
+ it 'can be set' do
1284
+ Color.render_as = :foo
1285
+ Color.render_as.should == :foo
1286
+ end
1287
+ end
1288
+
1289
+ describe '#render' do
1290
+ it 'renders to the default render_as method without transparency' do
1291
+ color = Color.new(0,0,0)
1292
+ color.render.should == '#000000'
1293
+ end
1294
+
1295
+ it 'renders as rgba if there is transparency' do
1296
+ color = Color.new(0.5, 0.5, 0.5, :alpha => 0.5)
1297
+ color.render.should == "rgba(50.0%, 50.0%, 50.0%, 0.5)"
1298
+ end
1299
+
1300
+ describe 'specific render methods' do
1301
+ describe ':hex' do
1302
+ it 'will render as :hex if alpha is 1' do
1303
+ Color.render_as = :rgb
1304
+ color = Color.new(0,0,0)
1305
+ color.render(:hex).should == '#000000'
1306
+ end
1307
+
1308
+ it 'will render as :rgba if alpha is less than 1' do
1309
+ Color.render_as = :hsl
1310
+ color = Color.new(0,0,0, :alpha => 0.9)
1311
+ color.render(:hex).should == "rgba(0.0%, 0.0%, 0.0%, 0.9)"
1312
+ end
1313
+
1314
+ it 'will render as :hex if render_as is set that way' do
1315
+ Color.render_as = :hex
1316
+ color = Color.new(0,0,0)
1317
+ color.render.should == '#000000'
1318
+ end
1319
+
1320
+ it 'will render as :rgba if render_as is set that way but alpha is less than 1' do
1321
+ Color.render_as = :hex
1322
+ color = Color.new(0,0,0, :alpha => 0.9)
1323
+ color.render.should == "rgba(0.0%, 0.0%, 0.0%, 0.9)"
1324
+ end
1325
+ end
1326
+
1327
+ describe ':hsl' do
1328
+ it 'will render as :hsl from #render if the alpha is 1' do
1329
+ color = Color.new(0.5, 0.5, 0.5)
1330
+ color.set_hsl
1331
+ color.render(:hsl).should == "hsl(#{(color.h*360).round}, #{color.s*100}%, #{color.l*100}%)"
1332
+ end
1333
+
1334
+ it 'will render as hsla from #render if the alpha is less than 1' do
1335
+ color = Color.new(0.5, 0.5, 0.5, :alpha => 0.75)
1336
+ color.set_hsl
1337
+ color.render(:hsl).should == "hsla(#{(color.h*360).round}, #{color.s*100}%, #{color.l*100}%, 0.75)"
1338
+ end
1339
+
1340
+ it "will render this way when the render_as is set to it and alpha is 1" do
1341
+ Color.render_as = :hsl
1342
+ color = Color.new(0.5, 0.5, 0.5)
1343
+ color.set_hsl
1344
+ color.render.should == "hsl(#{(color.h*360).round}, #{color.s*100}%, #{color.l*100}%)"
1345
+ end
1346
+
1347
+ it 'wil render as hsla with a render_as of :hsl if the alpha is less than 1' do
1348
+ Color.render_as = :hsl
1349
+ color = Color.new(0.5, 0.5, 0.5, :alpha => 0.75)
1350
+ color.set_hsl
1351
+ color.render.should == "hsla(#{(color.h*360).round}, #{color.s*100}%, #{color.l*100}%, 0.75)"
1352
+ end
1353
+ end
1354
+
1355
+ describe ':hsla' do
1356
+ it 'will render as :hsla if alpha is 1' do
1357
+ color = Color.new(0.5, 0.5, 0.5)
1358
+ color.set_hsl
1359
+ color.render(:hsla).should == "hsla(#{(color.h*360).round}, #{color.s*100}%, #{color.l*100}%, 1.0)"
1360
+ end
1361
+
1362
+ it 'will render as :hsla if alpha is less than 1' do
1363
+ color = Color.new(0.5, 0.5, 0.5, :alpha => 0.2)
1364
+ color.set_hsl
1365
+ color.render(:hsla).should == "hsla(#{(color.h*360).round}, #{color.s*100}%, #{color.l*100}%, 0.2)"
1366
+ end
1367
+
1368
+ it 'will render as :hsla when the Colol render_as is set that way' do
1369
+ Color.render_as = :hsla
1370
+ color = Color.new(0.5, 0.5, 0.5)
1371
+ color.set_hsl
1372
+ color.render.should == "hsla(#{(color.h*360).round}, #{color.s*100}%, #{color.l*100}%, 1.0)"
1373
+ end
1374
+ end
1375
+
1376
+ describe ':rgb' do
1377
+ it 'will render as :rgb from #render if the alpha is 1' do
1378
+ color = Color.new(0.5, 0.5, 0.5)
1379
+ color.render(:rgb).should == "rgb(#{color.r*100}%, #{color.g*100}%, #{color.b*100}%)"
1380
+ end
1381
+
1382
+ it 'will render as rgba from #render if the alpha is less than 1' do
1383
+ color = Color.new(0.5, 0.5, 0.5, :alpha => 0.75)
1384
+ color.render(:rgb).should == "rgba(#{color.r*100}%, #{color.g*100}%, #{color.b*100}%, 0.75)"
1385
+ end
1386
+
1387
+ it "will render this way when the render_as is set to it and alpha is 1" do
1388
+ Color.render_as = :rgb
1389
+ color = Color.new(0.5, 0.5, 0.5)
1390
+ color.render.should == "rgb(#{color.r*100}%, #{color.g*100}%, #{color.b*100}%)"
1391
+ end
1392
+
1393
+ it 'wil render as rgba with a render_as of :rgb if the alpha is less than 1' do
1394
+ Color.render_as = :rgb
1395
+ color = Color.new(0.5, 0.5, 0.5, :alpha => 0.75)
1396
+ color.render(:rgb).should == "rgba(#{color.r*100}%, #{color.g*100}%, #{color.b*100}%, 0.75)"
1397
+ end
1398
+ end
1399
+
1400
+ describe ':rgba' do
1401
+ it 'will render as :rgba if alpha is 1' do
1402
+ color = Color.new(0.5, 0.5, 0.5)
1403
+ color.set_rgb
1404
+ color.render(:rgba).should == "rgba(#{color.r*100}%, #{color.g*100}%, #{color.b*100}%, 1.0)"
1405
+ end
1406
+
1407
+ it 'will render as :rgba if alpha is less than 1' do
1408
+ color = Color.new(0.5, 0.5, 0.5, :alpha => 0.2)
1409
+ color.set_rgb
1410
+ color.render(:rgba).should == "rgba(#{color.r*100}%, #{color.g*100}%, #{color.b*100}%, 0.2)"
1411
+ end
1412
+
1413
+ it 'will render as :rgba when the Colol render_as is set that way' do
1414
+ Color.render_as = :rgba
1415
+ color = Color.new(0.5, 0.5, 0.5)
1416
+ color.set_rgb
1417
+ color.render.should == "rgba(#{color.r*100}%, #{color.g*100}%, #{color.b*100}%, 1.0)"
1418
+ end
1419
+ end
1420
+ end
1421
+
1422
+ describe 'flattened' do
1423
+ it 'will render as the render_as type when opaque' do
1424
+ Color.render_as = :hsl
1425
+ color = Color.new(:black)
1426
+ color.render(:flat).should == Color.new(:black).render_as_hsl
1427
+ end
1428
+
1429
+ it 'will flatten the color before rendering' do
1430
+ Color.render_as = :rgb
1431
+ color = Color.new(:black, :alpha => 0.5)
1432
+ color.render(:flat).should == Color.new(0.5,0.5,0.5).render_as_rgb
1433
+ end
1434
+
1435
+ it 'will render as the non-alpha type even with alhpa' do
1436
+ Color.render_as = :hex
1437
+ color = Color.new(:black, :alpha => 0.5)
1438
+ color.render(:flat).should == Color.new(0.5,0.5,0.5).render_as_hex
1439
+ end
1440
+ end
1441
+
1442
+ it 'aliases to #to_s' do
1443
+ Color.new(:black).render(:rgba).should == Color.new(:black).to_s(:rgba)
1444
+ end
1445
+ end
1446
+ end
1447
+ end