paleta 0.0.1 → 0.0.2

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.
data/.gitignore CHANGED
@@ -1,4 +1,7 @@
1
1
  .DS_Store
2
2
  .rspec
3
3
  Gemfile.lock
4
- Guardfile
4
+ Guardfile
5
+ *.gem
6
+ .bundle
7
+ tmp
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Jordan Stephens <http://jordanstephens.net>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/lib/paleta.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'paleta/version'
2
2
  require 'paleta/color'
3
+ require 'paleta/multiple_regression'
3
4
  require 'paleta/palette'
4
5
 
5
6
  module Paleta
data/lib/paleta/color.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  module Paleta
2
2
  class Color
3
+ include Math
3
4
 
4
- attr_reader :red, :green, :blue, :hue, :saturation, :lightness
5
+ attr_reader :red, :green, :blue, :hue, :saturation, :lightness, :hex
5
6
 
6
7
  def initialize(red = 0, green = 0, blue = 0)
7
8
  self.red = red
@@ -12,31 +13,77 @@ module Paleta
12
13
  def red=(val)
13
14
  @red = range_validator(val, 0..255)
14
15
  update_hsl
16
+ update_hex
15
17
  end
16
18
 
17
19
  def green=(val)
18
20
  @green = range_validator(val, 0..255)
19
21
  update_hsl
22
+ update_hex
20
23
  end
21
24
 
22
25
  def blue=(val)
23
26
  @blue = range_validator(val, 0..255)
24
27
  update_hsl
28
+ update_hex
25
29
  end
26
30
 
27
31
  def lightness=(val)
28
32
  @lightness = range_validator(val, 0..100)
29
33
  update_rgb
34
+ update_hex
30
35
  end
31
36
 
32
37
  def saturation=(val)
33
38
  @saturation = range_validator(val, 0..100)
34
39
  update_rgb
40
+ update_hex
35
41
  end
36
42
 
37
43
  def hue=(val)
38
44
  @hue = range_validator(val, 0..360)
39
45
  update_rgb
46
+ update_hex
47
+ end
48
+
49
+ def hex=(val)
50
+ if val.length != 6 ||
51
+ (val[0..1] == 0 && val[0..1] != "00") ||
52
+ (val[2..3] == 0 && val[2..3] != "00") ||
53
+ (val[4..5] == 0 && val[4..5] != "00")
54
+ raise(ArgumentError, "Invalid Hex String")
55
+ end
56
+ @hex = val.upcase
57
+ @red = val[0..1].hex
58
+ @green = val[2..3].hex
59
+ @blue = val[4..5].hex
60
+ update_hsl
61
+ end
62
+
63
+ def lighten!(percent = 5)
64
+ @lightness += percent
65
+ @lightness = 100 if @lightness > 100
66
+ update_rgb
67
+ update_hex
68
+ end
69
+
70
+ def darken!(percent = 5)
71
+ @lightness -= percent
72
+ @lightness = 0 if @lightness < 0
73
+ update_rgb
74
+ update_hex
75
+ end
76
+
77
+ def invert!
78
+ @red = 255 - @red
79
+ @green = 255 - @green
80
+ @blue = 255 - @blue
81
+ update_hsl
82
+ update_hex
83
+ end
84
+
85
+ def similarity(color)
86
+ sqrt(((@red - color.red) ** 2) + ((@green - color.green) ** 2) + ((@blue - color.blue) ** 2)) / sqrt(3 * (255 ** 2))
40
87
  end
41
88
 
42
89
  private
@@ -50,22 +97,21 @@ module Paleta
50
97
  max = [r, g, b].max
51
98
  delta = max - min
52
99
 
53
- @hue = 0
54
- @saturation = 0
55
- @lightness = (max + min) / 2.0
100
+ h = s = 0
101
+ l = (max + min) / 2.0
56
102
 
57
103
  if delta != 0
58
- @saturation = (@lightness < 0.5) ? delta / (max + min) : delta / (2.0 - max - min)
104
+ s = (l < 0.5) ? delta / (max + min) : delta / (2.0 - max - min)
59
105
  case max
60
- when r; @hue = (g - b) / delta
61
- when g; @hue = 2 + (b - r) / delta
62
- when b; @hue = 4 + (r - g) / delta
106
+ when r; h = (g - b) / delta
107
+ when g; h = 2 + (b - r) / delta
108
+ when b; h = 4 + (r - g) / delta
63
109
  end
64
110
  end
65
- @hue *= 60
111
+ @hue = h * 60
66
112
  @hue += 360 if @hue < 0
67
- @saturation *= 100
68
- @lightness *= 100
113
+ @saturation = s * 100
114
+ @lightness = l * 100
69
115
  end
70
116
 
71
117
  def update_rgb
@@ -75,32 +121,34 @@ module Paleta
75
121
  l = @lightness / 100.0
76
122
 
77
123
  if s == 0
78
- r = l * 255
79
- g = l * 255
80
- b = l * 255
124
+ r = g = b = l * 255
81
125
  else
82
- th = h / 6.0
83
- if l < 0.5
84
- t2 = l * (s + 1)
85
- else
86
- t2 = (l + s) - (l * s)
87
- end
126
+ h /= 6.0
127
+ t2 = l < 0.5 ? l * (s + 1) : (l + s) - (l * s)
88
128
  t1 = 2 * l - t2
89
129
 
90
- tr = th + (1.0 / 3.0)
91
- tg = th
92
- tb = th - (1.0 / 3.0)
130
+ r = h + (1.0 / 3.0)
131
+ g = h
132
+ b = h - (1.0 / 3.0)
93
133
 
94
- tr = hue_calc(tr, t1, t2)
95
- tg = hue_calc(tg, t1, t2)
96
- tb = hue_calc(tb, t1, t2)
134
+ r = hue_calc(r, t1, t2)
135
+ g = hue_calc(g, t1, t2)
136
+ b = hue_calc(b, t1, t2)
97
137
 
98
- @red = tr * 255.0
99
- @green = tg * 255.0
100
- @blue = tb * 255.0
138
+ @red = r * 255.0
139
+ @green = g * 255.0
140
+ @blue = b * 255.0
101
141
  end
102
142
  end
103
143
 
144
+ def update_hex
145
+ r = @red.to_s(16) rescue "00"
146
+ g = @green.to_s(16) rescue "00"
147
+ b = @blue.to_s(16) rescue "00"
148
+ [r, g, b].each { |c| c = "0#{c}" if c.length < 2 }
149
+ @hex = "#{r}#{g}#{b}".upcase
150
+ end
151
+
104
152
  def hue_calc(value, t1, t2)
105
153
  value += 1 if value < 0
106
154
  value -= 1 if value > 1
@@ -0,0 +1,39 @@
1
+ class MultipleRegression
2
+ attr_accessor :slope, :offset
3
+
4
+ def initialize dr, dg, db
5
+
6
+ @size = dr.size
7
+ raise "arguments not same length!" unless @size == dg.size && @size == db.size
8
+
9
+ if @size == 1
10
+ @slope = { :r => dr[0], :g => dg[0], :b => db[0] }
11
+ @offset = { :r => 0, :g => 0, :b => 0 }
12
+ return
13
+ end
14
+
15
+ srr = sgg = sbb = srg = sbr = sgb = sr = sb = sg = 0
16
+ dr.zip(dg,db).each do |r,g,b|
17
+ srr += r ** 2
18
+ sgg += g ** 2
19
+ srg += r * g
20
+ sbr += b * r
21
+ sgb += g * b
22
+ sr += r
23
+ sb += g
24
+ sg += b
25
+ end
26
+
27
+ slope_rg = ( @size * srg - sr * sb ) / ( @size * srr - sr ** 2 ).to_f
28
+ slope_gb = ( @size * sgb - sb * sg ) / ( @size * sgg - sb ** 2 ).to_f
29
+ slope_br = ( @size * sgb - sb * sg ) / ( @size * sbb - sg ** 2 ).to_f
30
+
31
+ offset_rg = (sb - slope_rg * sr) / @size
32
+ offset_gb = (sg - slope_gb * sb) / @size
33
+ offset_br = (sr - slope_br * sg) / @size
34
+
35
+ @slope = { :r => slope_rg, :g => slope_gb, :b => slope_br }
36
+ @offset = { :r => offset_rg, :g => offset_gb, :b => offset_br }
37
+ return
38
+ end
39
+ end
@@ -1,5 +1,6 @@
1
1
  module Paleta
2
2
  class Palette
3
+ include Math
3
4
 
4
5
  attr_accessor :colors
5
6
 
@@ -18,8 +19,62 @@ module Paleta
18
19
  @colors[i]
19
20
  end
20
21
 
22
+ def size
23
+ @colors.size
24
+ end
25
+
21
26
  def include?(color)
22
27
  @colors.include?(color)
23
28
  end
29
+
30
+ def lighten!(percent = 5)
31
+ @colors.each do |color|
32
+ color.lighten!(percent)
33
+ end
34
+ end
35
+
36
+ def darken!(percent = 5)
37
+ @colors.each do |color|
38
+ color.darken!(percent)
39
+ end
40
+ end
41
+
42
+ def invert!
43
+ @colors.each do |color|
44
+ color.invert!
45
+ end
46
+ end
47
+
48
+ def similarity(palette)
49
+ r1 = self.fit
50
+ r2 = palette.fit
51
+
52
+ a1, a2, b1, b2 = {}, {}, {}, {}
53
+ a1[:r] = 0 * r1.slope[:r] + r1.offset[:r]
54
+ a1[:g] = 0 * r1.slope[:g] + r1.offset[:g]
55
+ a1[:b] = 0 * r1.slope[:b] + r1.offset[:b]
56
+ b1[:r] = 255 * r1.slope[:r] + r1.offset[:r]
57
+ b1[:g] = 255 * r1.slope[:g] + r1.offset[:g]
58
+ b1[:b] = 255 * r1.slope[:b] + r1.offset[:b]
59
+ a2[:r] = 0 * r2.slope[:r] + r2.offset[:r]
60
+ a2[:g] = 0 * r2.slope[:g] + r2.offset[:g]
61
+ a2[:b] = 0 * r2.slope[:b] + r2.offset[:b]
62
+ b2[:r] = 255 * r2.slope[:r] + r2.offset[:r]
63
+ b2[:g] = 255 * r2.slope[:g] + r2.offset[:g]
64
+ b2[:b] = 255 * r2.slope[:b] + r2.offset[:b]
65
+
66
+ d1 = sqrt(((a1[:r] - a2[:r]) ** 2) + ((a1[:g] - a2[:g]) ** 2) + ((a1[:b] - a2[:b]) ** 2)) / sqrt(3 * (65025 ** 2))
67
+ d2 = sqrt(((b1[:r] - b2[:r]) ** 2) + ((b1[:g] - b2[:g]) ** 2) + ((b1[:b] - b2[:b]) ** 2)) / sqrt(3 * (65025 ** 2))
68
+
69
+ d1 + d2
70
+ end
71
+
72
+ def fit
73
+ # create a 3xn matrix where n = @colors.size to represent the set of colors
74
+ reds = @colors.map { |c| c.red }
75
+ greens = @colors.map { |c| c.green }
76
+ blues = @colors.map { |c| c.blue }
77
+ MultipleRegression.new(reds, greens, blues)
78
+ end
24
79
  end
25
80
  end
@@ -1,3 +1,3 @@
1
1
  module Paleta
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
data/paleta.gemspec CHANGED
@@ -4,8 +4,8 @@ require File.expand_path('../lib/paleta/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ['Jordan Stephens']
6
6
  gem.email = ['iam@jordanstephens.net']
7
- gem.description = 'color palette gem'
8
- gem.summary = 'color palette gem'
7
+ gem.description = 'A gem for working with color palettes'
8
+ gem.summary = 'A little library for creating, manipulating and comparing colors and color palettes'
9
9
  gem.homepage = 'http://jordanstephens.net'
10
10
 
11
11
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
data/readme.markdown ADDED
@@ -0,0 +1,86 @@
1
+ # Paleta
2
+
3
+ A gem for working with color palettes
4
+
5
+ ## Installation
6
+
7
+ To install, run
8
+
9
+ $ gem install paleta
10
+
11
+ Or, add this to your application's Gemfile
12
+
13
+ ``` ruby
14
+ gem 'paleta'
15
+ ```
16
+
17
+ and run
18
+
19
+ $ bundle
20
+
21
+ ## Usage
22
+
23
+ ### Color
24
+
25
+ # create a color with RGB components
26
+ color = Paleta::Color.new(94, 161, 235)
27
+
28
+ # access component values
29
+ color.red # => 94
30
+ color.green # => 161
31
+ color.blue # => 235
32
+
33
+ # HSL components are maintained too!
34
+ color.hue # => 211.48936170212767
35
+ color.saturation # => 77.90055248618782
36
+ color.lightness # => 64.50980392156862
37
+
38
+ # a HEX value is also maintained for each Color
39
+ color.hex # => "5EA1EB"
40
+
41
+ # lighten by a percentage
42
+ color.lighten!(10)
43
+
44
+ # darken by a percentage
45
+ color.darken!(10)
46
+
47
+ # invert a color
48
+ color.invert!
49
+
50
+ # calculate similarity between Colors
51
+ # Color#similarity calculates the similarity between two colors and returns a
52
+ # value in 0..1, with 0 being identical and 1 being as dissimilar as possible
53
+ color2 = Paleta::Color.new(237, 172, 33)
54
+ color.similarity(color2) # => 0.5609077061558945
55
+
56
+ ### Palette
57
+
58
+ # add Colors to a Palette
59
+ color1 = Paleta::Color.new(13, 57, 182)
60
+ color2 = Paleta::Color.new(94, 161, 235)
61
+ palette = Paleta::Palette.new(c1, c2)
62
+
63
+ # retreive a Color from a Palette
64
+ palette[1] # => color2
65
+
66
+ # lighten and darken an entire Palette by a percentage
67
+ palette.lighten!(15)
68
+ palette.darken!(20)
69
+
70
+ # invert each color in a Palette
71
+ palette.invert!
72
+
73
+ # calculate similarity of two Palettes
74
+ color1 = Paleta::Color.new(13, 57, 182)
75
+ color2 = Paleta::Color.new(237, 172, 33)
76
+ palette1 = Paleta::Palette.new(color1, color2)
77
+
78
+ color3 = Paleta::Color.new(13, 57, 182)
79
+ color4 = Paleta::Color.new(94, 161, 235)
80
+ palette2 = Paleta::Palette.new(color3, color4)
81
+
82
+ palette1.similarity(palette2) # => 0.0046992695975874915
83
+
84
+ See the [documentation](http://rubydoc.info/gems/paleta/ "Documentation").
85
+
86
+
@@ -56,4 +56,74 @@ describe Paleta::Color do
56
56
  color.green.to_i.should == 195
57
57
  color.blue.to_i.should == 178
58
58
  end
59
+
60
+ it "should lighten by a percentage, " do
61
+ color = Paleta::Color.new(94, 161, 235)
62
+ lightness = color.lightness
63
+ color.lighten!
64
+ color.lightness.should == lightness + 5
65
+ lightness = color.lightness
66
+ color.lighten!(20)
67
+ color.lightness.should == lightness + 20
68
+ end
69
+
70
+ it "should quietly maintain a maximum of 100 when lightening" do
71
+ color = Paleta::Color.new(94, 161, 235)
72
+ color.lighten!(300)
73
+ color.lightness.should == 100
74
+ end
75
+
76
+ it "should darken by a percentage" do
77
+ color = Paleta::Color.new(94, 161, 235)
78
+ lightness = color.lightness
79
+ color.darken!
80
+ color.lightness.should == lightness - 5
81
+ lightness = color.lightness
82
+ color.darken!(20)
83
+ color.lightness.should == lightness - 20
84
+ end
85
+
86
+ it "should quietly maintain a minimum of 0 when darkening" do
87
+ color = Paleta::Color.new(94, 161, 235)
88
+ color.darken!(300)
89
+ color.lightness.should == 0
90
+ end
91
+
92
+ it "should invert" do
93
+ color = Paleta::Color.new(94, 161, 235)
94
+ color.invert!
95
+ color.red.should == 161
96
+ color.green.should == 94
97
+ color.blue.should == 20
98
+ end
99
+
100
+ it "should calculate its similarity to another Color" do
101
+ color1 = Paleta::Color.new(94, 161, 235)
102
+ color2 = Paleta::Color.new(237, 172, 33)
103
+ color1.similarity(color2).round(5).should == 0.56091
104
+
105
+ color1 = Paleta::Color.new(237, 172, 33)
106
+ color2 = Paleta::Color.new(237, 172, 33)
107
+ color1.similarity(color2).should == 0
108
+
109
+ color1 = Paleta::Color.new(0, 0, 0)
110
+ color2 = Paleta::Color.new(255, 255, 255)
111
+ color1.similarity(color2).should == 1
112
+ end
113
+
114
+ it "should maintain its HEX value" do
115
+ color = Paleta::Color.new(94, 161, 235)
116
+ color.hex.should == "5EA1EB"
117
+ end
118
+
119
+ it "should update its HSB and RGB components when its HEX value is updated" do
120
+ color = Paleta::Color.new
121
+ color.hex = "ffffff"
122
+ color.red.should == 255
123
+ color.green.should == 255
124
+ color.blue.should == 255
125
+ color.hue.should == 0
126
+ color.saturation.should == 0
127
+ color.lightness.should == 100
128
+ end
59
129
  end
@@ -28,4 +28,84 @@ describe Paleta::Palette do
28
28
  palette[0].should == c1
29
29
  palette[1].should be_nil
30
30
  end
31
+
32
+ it "should lighten each color in a palette by a percentage" do
33
+ c1 = Paleta::Color.new(13, 57, 182)
34
+ c2 = Paleta::Color.new(94, 161, 235)
35
+ palette = Paleta::Palette.new(c1, c2)
36
+ lightness1 = c1.lightness
37
+ lightness2 = c2.lightness
38
+ percent = 20
39
+ palette.lighten!(percent)
40
+ palette[0].lightness.should == lightness1 + percent
41
+ palette[1].lightness.should == lightness2 + percent
42
+ end
43
+
44
+ it "should darken each color in a palette by a percentage" do
45
+ c1 = Paleta::Color.new(13, 57, 182)
46
+ c2 = Paleta::Color.new(94, 161, 235)
47
+ palette = Paleta::Palette.new(c1, c2)
48
+ lightness1 = c1.lightness
49
+ lightness2 = c2.lightness
50
+ percent = 20
51
+ palette.darken!(percent)
52
+ palette[0].lightness.should == lightness1 - percent
53
+ palette[1].lightness.should == lightness2 - percent
54
+ end
55
+
56
+ it "should invert each color in a palette" do
57
+ c1 = Paleta::Color.new(13, 57, 182)
58
+ c2 = Paleta::Color.new(94, 161, 235)
59
+ palette = Paleta::Palette.new(c1, c2)
60
+ palette.invert!
61
+ palette[0].red.should == 242
62
+ palette[0].green.should == 198
63
+ palette[0].blue.should == 73
64
+ palette[1].red.should == 161
65
+ palette[1].green.should == 94
66
+ palette[1].blue.should == 20
67
+ end
68
+
69
+ it "should calculate a multiple regression over each Color in the Palette in RGB space" do
70
+ c1 = Paleta::Color.new(13, 57, 182)
71
+ c2 = Paleta::Color.new(94, 161, 235)
72
+ c3 = Paleta::Color.new(237, 172, 33)
73
+ palette = Paleta::Palette.new(c1, c2, c3)
74
+ r = palette.fit
75
+ r.slope[:r].should == 0.4632575855725132
76
+ r.slope[:g].should == -0.5730072013906133
77
+ r.slope[:b].should == 0.06837037037037037
78
+ r.offset[:r].should == 76.87979685435182
79
+ r.offset[:g].should == 224.49093618077973
80
+ r.offset[:b].should == 104.41111111111111
81
+ end
82
+
83
+ it "should calculate its similarity to another Palette" do
84
+ c1 = Paleta::Color.new(0, 0, 0)
85
+ p1 = Paleta::Palette.new(c1)
86
+
87
+ c2 = Paleta::Color.new(255, 255, 255)
88
+ p2 = Paleta::Palette.new(c2)
89
+
90
+ p1.similarity(p2).should == 1
91
+
92
+ c3 = Paleta::Color.new(0, 0, 0)
93
+ c4 = Paleta::Color.new(255, 255, 255)
94
+ p3 = Paleta::Palette.new(c3, c4)
95
+
96
+ c5 = Paleta::Color.new(0, 0, 0)
97
+ c6 = Paleta::Color.new(255, 255, 255)
98
+ p4 = Paleta::Palette.new(c5, c6)
99
+ p3.similarity(p4).should == 0
100
+
101
+
102
+ c7 = Paleta::Color.new(13, 57, 182)
103
+ c8 = Paleta::Color.new(237, 172, 33)
104
+ p5 = Paleta::Palette.new(c7, c8)
105
+
106
+ c9 = Paleta::Color.new(13, 57, 182)
107
+ c10 = Paleta::Color.new(94, 161, 235)
108
+ p6 = Paleta::Palette.new(c9, c10)
109
+ p5.similarity(p6).round(5).should == 0.0047
110
+ end
31
111
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paleta
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,9 +9,9 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-02 00:00:00.000000000Z
12
+ date: 2012-01-06 00:00:00.000000000Z
13
13
  dependencies: []
14
- description: color palette gem
14
+ description: A gem for working with color palettes
15
15
  email:
16
16
  - iam@jordanstephens.net
17
17
  executables: []
@@ -20,11 +20,14 @@ extra_rdoc_files: []
20
20
  files:
21
21
  - .gitignore
22
22
  - Gemfile
23
+ - LICENSE
23
24
  - lib/paleta.rb
24
25
  - lib/paleta/color.rb
26
+ - lib/paleta/multiple_regression.rb
25
27
  - lib/paleta/palette.rb
26
28
  - lib/paleta/version.rb
27
29
  - paleta.gemspec
30
+ - readme.markdown
28
31
  - spec/models/color_spec.rb
29
32
  - spec/models/palette_spec.rb
30
33
  - spec/spec_helper.rb
@@ -51,7 +54,8 @@ rubyforge_project:
51
54
  rubygems_version: 1.8.10
52
55
  signing_key:
53
56
  specification_version: 3
54
- summary: color palette gem
57
+ summary: A little library for creating, manipulating and comparing colors and color
58
+ palettes
55
59
  test_files:
56
60
  - spec/models/color_spec.rb
57
61
  - spec/models/palette_spec.rb