style_train 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.
- data/LISENCE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/lib/style_train/color.rb +103 -0
- data/lib/style_train/color_types/color_type.rb +218 -0
- data/lib/style_train/color_types/hex_color.rb +44 -0
- data/lib/style_train/color_types/hsl_color.rb +5 -0
- data/lib/style_train/color_types/keyword_color.rb +192 -0
- data/lib/style_train/color_types/rgb_color.rb +57 -0
- data/lib/style_train/sheet.rb +234 -0
- data/lib/style_train/support/gnash.rb +143 -0
- data/lib/style_train/support/numbers.rb +23 -0
- data/lib/style_train/support/string.rb +24 -0
- data/lib/style_train.rb +22 -0
- data/spec/color/color_spec.rb +224 -0
- data/spec/color/color_type_spec.rb +370 -0
- data/spec/color/hex_color_spec.rb +160 -0
- data/spec/color/keyword_color_spec.rb +56 -0
- data/spec/color/rgb_color_spec.rb +75 -0
- data/spec/numbers_spec.rb +25 -0
- data/spec/sheet_spec.rb +549 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +11 -0
- data/style_train.gemspec +74 -0
- data/utils/alexch_color_gist/color.rb +160 -0
- data/utils/alexch_color_gist/color_test.rb +176 -0
- data/utils/overview.txt +151 -0
- data/utils/stylesheet.txt +161 -0
- metadata +102 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
# Taken from RAILS, see RAIL'S LICENSE for usage
|
2
|
+
|
3
|
+
# This class has dubious semantics and we only have it so that
|
4
|
+
# people can write params[:key] instead of params['key']
|
5
|
+
# and they get the same value for both keys.
|
6
|
+
unless defined?(HashWithIndifferentAccess)
|
7
|
+
class Hash
|
8
|
+
def with_indifferent_access
|
9
|
+
hash = HashWithIndifferentAccess.new(self)
|
10
|
+
hash.default = self.default
|
11
|
+
hash
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class HashWithIndifferentAccess < Hash
|
16
|
+
def initialize(constructor = {})
|
17
|
+
if constructor.is_a?(Hash)
|
18
|
+
super()
|
19
|
+
update(constructor)
|
20
|
+
else
|
21
|
+
super(constructor)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def default(key = nil)
|
26
|
+
if key.is_a?(Symbol) && include?(key = key.to_s)
|
27
|
+
self[key]
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
34
|
+
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
35
|
+
|
36
|
+
# Assigns a new value to the hash:
|
37
|
+
#
|
38
|
+
# hash = HashWithIndifferentAccess.new
|
39
|
+
# hash[:key] = "value"
|
40
|
+
#
|
41
|
+
def []=(key, value)
|
42
|
+
regular_writer(convert_key(key), convert_value(value))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Updates the instantized hash with values from the second:
|
46
|
+
#
|
47
|
+
# hash_1 = HashWithIndifferentAccess.new
|
48
|
+
# hash_1[:key] = "value"
|
49
|
+
#
|
50
|
+
# hash_2 = HashWithIndifferentAccess.new
|
51
|
+
# hash_2[:key] = "New Value!"
|
52
|
+
#
|
53
|
+
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
54
|
+
#
|
55
|
+
def update(other_hash)
|
56
|
+
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
alias_method :merge!, :update
|
61
|
+
|
62
|
+
# Checks the hash for a key matching the argument passed in:
|
63
|
+
#
|
64
|
+
# hash = HashWithIndifferentAccess.new
|
65
|
+
# hash["key"] = "value"
|
66
|
+
# hash.key? :key # => true
|
67
|
+
# hash.key? "key" # => true
|
68
|
+
#
|
69
|
+
def key?(key)
|
70
|
+
super(convert_key(key))
|
71
|
+
end
|
72
|
+
|
73
|
+
alias_method :include?, :key?
|
74
|
+
alias_method :has_key?, :key?
|
75
|
+
alias_method :member?, :key?
|
76
|
+
|
77
|
+
# Fetches the value for the specified key, same as doing hash[key]
|
78
|
+
def fetch(key, *extras)
|
79
|
+
super(convert_key(key), *extras)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns an array of the values at the specified indices:
|
83
|
+
#
|
84
|
+
# hash = HashWithIndifferentAccess.new
|
85
|
+
# hash[:a] = "x"
|
86
|
+
# hash[:b] = "y"
|
87
|
+
# hash.values_at("a", "b") # => ["x", "y"]
|
88
|
+
#
|
89
|
+
def values_at(*indices)
|
90
|
+
indices.collect {|key| self[convert_key(key)]}
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns an exact copy of the hash.
|
94
|
+
def dup
|
95
|
+
HashWithIndifferentAccess.new(self)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
|
99
|
+
# Does not overwrite the existing hash.
|
100
|
+
def merge(hash)
|
101
|
+
self.dup.update(hash)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
|
105
|
+
# This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
|
106
|
+
def reverse_merge(other_hash)
|
107
|
+
super other_hash.with_indifferent_access
|
108
|
+
end
|
109
|
+
|
110
|
+
# Removes a specified key from the hash.
|
111
|
+
def delete(key)
|
112
|
+
super(convert_key(key))
|
113
|
+
end
|
114
|
+
|
115
|
+
def stringify_keys!; self end
|
116
|
+
def symbolize_keys!; self end
|
117
|
+
def to_options!; self end
|
118
|
+
|
119
|
+
# Convert to a Hash with String keys.
|
120
|
+
def to_hash
|
121
|
+
Hash.new(default).merge(self)
|
122
|
+
end
|
123
|
+
|
124
|
+
protected
|
125
|
+
def convert_key(key)
|
126
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
127
|
+
end
|
128
|
+
|
129
|
+
def convert_value(value)
|
130
|
+
case value
|
131
|
+
when Hash
|
132
|
+
value.with_indifferent_access
|
133
|
+
when Array
|
134
|
+
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
|
135
|
+
else
|
136
|
+
value
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
Gnash = HashWithIndifferentAccess unless defined?( Gnash ) # because Gnash is easier to write, thanks Merb!
|
143
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# From ActiveSupport
|
2
|
+
|
3
|
+
unless String.instance_methods.include?( 'constantize' )
|
4
|
+
class String
|
5
|
+
# Constantize tries to find a declared constant with the name specified
|
6
|
+
# in the string. It raises a NameError when the name is not in CamelCase
|
7
|
+
# or is not initialized.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# "Module".constantize #=> Module
|
11
|
+
# "Class".constantize #=> Class
|
12
|
+
def constantize
|
13
|
+
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
|
14
|
+
raise NameError, "#{self.inspect} is not a valid constant name!"
|
15
|
+
end
|
16
|
+
|
17
|
+
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def dasherize
|
21
|
+
self.gsub('_', '-') || self
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/style_train.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$LOAD_PATH.unshift( File.dirname(__FILE__) )
|
2
|
+
|
3
|
+
# ruby libs
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
# Support stuff
|
7
|
+
require 'style_train/support/gnash'
|
8
|
+
require 'style_train/support/string'
|
9
|
+
require 'style_train/support/numbers'
|
10
|
+
|
11
|
+
# The color load!
|
12
|
+
require 'style_train/color_types/color_type'
|
13
|
+
require 'style_train/color_types/rgb_color'
|
14
|
+
require 'style_train/color_types/hsl_color'
|
15
|
+
require 'style_train/color_types/keyword_color'
|
16
|
+
require 'style_train/color_types/hex_color'
|
17
|
+
require "style_train/color"
|
18
|
+
# require 'lib/palette'
|
19
|
+
|
20
|
+
require "style_train/sheet"
|
21
|
+
# require 'set'
|
22
|
+
# require 'style'
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
Color = StyleTrain::Color unless defined?(Color)
|
4
|
+
HexColor = StyleTrain::HexColor unless defined?( HexColor )
|
5
|
+
KeywordColor = StyleTrain::KeywordColor unless defined?( KeywordColor )
|
6
|
+
RGBcolor = StyleTrain::RGBcolor unless defined?( RGBcolor )
|
7
|
+
|
8
|
+
describe Color do
|
9
|
+
def build_color_type( color_class, args )
|
10
|
+
color_class.new(:color => args)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'alpha' do
|
14
|
+
it 'should be delegated' do
|
15
|
+
color = Color.new(:black, :alpha => 0.5)
|
16
|
+
color.alpha.should == 0.5
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'setter should be delegated' do
|
20
|
+
color = Color.new(:black)
|
21
|
+
color.alpha = 0.5
|
22
|
+
color.delegate.alpha.should == 0.5
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'initialization' do
|
27
|
+
describe 'with an existing color' do
|
28
|
+
it 'should build a delegate of the existing type' do
|
29
|
+
Color.new(Color.new(:white)).delegate.should == build_color_type(KeywordColor, :white)
|
30
|
+
Color.new(Color.new('#FFF')).delegate.should == build_color_type(HexColor, '#FFF')
|
31
|
+
Color.new(Color.new([255,255,255])).delegate.should == build_color_type(RGBcolor, [255,255,255])
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should set the background if the argument color has a background' do
|
35
|
+
Color.new(Color.new(:white), :background => :gray).background.should == Color.new(:gray)
|
36
|
+
Color.new(Color.new(:white)).background_set.should_not be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'after the new color is created changes to the delegate should not change the original' do
|
40
|
+
original = Color.new(:white)
|
41
|
+
new_color = Color.new(original, :background => :black, :alpha => 0.5)
|
42
|
+
original.alpha.should == 1.0
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should set the alpha' do
|
46
|
+
color = Color.new(Color.new(:white), :alpha => 0.5)
|
47
|
+
color.alpha.should == 0.5
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'assigns a delegate' do
|
52
|
+
describe 'with a keyword argument' do
|
53
|
+
it 'should build an html keyword color' do
|
54
|
+
Color.new("gray").delegate.should == build_color_type(KeywordColor, 'gray')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should build a svg keyword color' do
|
58
|
+
Color.new(:linen).delegate.should == build_color_type(KeywordColor, :linen)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'with a hex string argument' do
|
63
|
+
it '(3-digit no #) should build a hex color' do
|
64
|
+
Color.new('333').delegate.should == build_color_type(HexColor, '333')
|
65
|
+
end
|
66
|
+
|
67
|
+
it '(3-digit with #) should build a hex color' do
|
68
|
+
Color.new('#333').delegate.should == build_color_type(HexColor, '#333')
|
69
|
+
end
|
70
|
+
|
71
|
+
it '(6-digit no #) should build a hex color' do
|
72
|
+
Color.new('333333').delegate.should == build_color_type(HexColor, '333333')
|
73
|
+
end
|
74
|
+
|
75
|
+
it '(6-digit with #) should build a hex color' do
|
76
|
+
Color.new('#333333').delegate.should == build_color_type(HexColor, '#333333')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'with an rgb array argument' do
|
81
|
+
it '(with a byte array) should build a rgb color' do
|
82
|
+
Color.new([127,127,127]).delegate.should == build_color_type(RGBcolor, [127,127,127])
|
83
|
+
end
|
84
|
+
|
85
|
+
it '(with a percentage array) should build a rgb color' do
|
86
|
+
Color.new(['50%','50%','50%']).delegate.should == build_color_type(RGBcolor, [127,127,127])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'hsl colors'
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'options' do
|
94
|
+
it 'should pass on the alpha argument' do
|
95
|
+
color = Color.new(:black, :alpha => 0.5)
|
96
|
+
color.alpha.should == 0.5
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'comparison' do
|
102
|
+
before do
|
103
|
+
@color = Color.new(:black)
|
104
|
+
@color_type = KeywordColor.new(:color => :black)
|
105
|
+
@color_type_too = RGBcolor.new(:color => [0,0,0])
|
106
|
+
@color_too = Color.new(:black)
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '=~' do
|
110
|
+
describe 'with another Color object' do
|
111
|
+
it 'should not be true if the delegates don\'t match' do
|
112
|
+
(@color =~ Color.new(:white)).should_not be_true
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should be indifferent to background' do
|
116
|
+
(@color =~ Color.new(:black, :background => :yellow)).should be_true
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should be true if background and delegate match' do
|
120
|
+
(@color =~ @color_too).should be_true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'with a ColorType object' do
|
125
|
+
it 'should be true if the delegate matches the ColorType' do
|
126
|
+
(@color =~ @color_type).should be_true
|
127
|
+
(@color =~ @color_type_too).should be_true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '==' do
|
133
|
+
describe 'with another Color object' do
|
134
|
+
it 'should not be true if the delegates don\'t match' do
|
135
|
+
(@color == Color.new(:white)).should_not be_true
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should be indifferent to background' do
|
139
|
+
(@color == Color.new(:black, :background => :yellow)).should_not be_true
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should be true if background and delegate match' do
|
143
|
+
(@color == @color_too).should be_true
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'with a ColorType object' do
|
148
|
+
it 'should be false' do
|
149
|
+
(@color == @color_type).should be_false
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe 'background' do
|
156
|
+
before do
|
157
|
+
@color = Color.new(:black, :alpha => 0.5)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'should have a white opaque background by default' do
|
161
|
+
@color.background.should =~ Color.new(:white)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should be settable' do
|
165
|
+
@color.background = :black
|
166
|
+
@color.background.should =~ Color.new(:black)
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should ignore alpha' do
|
170
|
+
@color.background = {:color => :black, :alpha => 0.5 }
|
171
|
+
@color.background.delegate.should == Color.new(:black, :alpha => 1.0).delegate
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should be initalized into the instance' do
|
175
|
+
color = Color.new(:black, :background => :yellow)
|
176
|
+
color.background.should =~ Color.new(:yellow)
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should set a flag when it is set not by default' do
|
180
|
+
color = Color.new(:black)
|
181
|
+
color.background
|
182
|
+
color.background_set.should_not == true
|
183
|
+
|
184
|
+
color = Color.new(:black, :background => :yellow)
|
185
|
+
color.background_set.should == true
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe 'rendering' do
|
190
|
+
it 'should render via the delegates default method by default' do
|
191
|
+
Color.new(:white).render.should == build_color_type(KeywordColor, :white).render_as_given
|
192
|
+
Color.new(['100%', '100%', '100%']).render.should == build_color_type(RGBcolor, ['100%', '100%', '100%']).render_as_given
|
193
|
+
Color.new([255,255,255]).render.should == build_color_type(RGBcolor, [255,255,255]).render_as_given
|
194
|
+
Color.new('#FFF').render.should == build_color_type(HexColor, '#FFF').render_as_given
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should render rgba if it has transparency' do
|
198
|
+
Color.new(:white, :alpha => 0.5).render.should =~ /rgba/
|
199
|
+
Color.new(['100%', '100%', '100%'], :alpha => 0.5).render.should =~ /rgba/
|
200
|
+
Color.new([255,255,255], :alpha => 0.5).render.should =~ /rgba/
|
201
|
+
Color.new('#FFF', :alpha => 0.5).render.should =~ /rgba/
|
202
|
+
end
|
203
|
+
|
204
|
+
describe 'ie' do
|
205
|
+
it 'should render as a hex color' do
|
206
|
+
Color.new(:white).render(:ie).should == build_color_type(HexColor, '#ffffff').render_as_given
|
207
|
+
Color.new(['100%', '100%', '100%']).render(:ie).should == build_color_type(HexColor, '#ffffff').render_as_given
|
208
|
+
Color.new([255,255,255]).render(:ie).should == build_color_type(HexColor, '#ffffff').render_as_given
|
209
|
+
Color.new('#FFF').render(:ie).should == build_color_type(HexColor, '#ffffff').render_as_given
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should render delegate layered on the background if there is transparency and as a hex color' do
|
213
|
+
Color.new(:black, :alpha => 0.5).render(:ie).should == build_color_type( HexColor, '#808080' ).render
|
214
|
+
Color.new(['0%', '0%', '0%'], :alpha => 0.5).render(:ie).should == build_color_type( HexColor, '#808080' ).render
|
215
|
+
Color.new([255,255,255], :alpha => 0.5, :background => :black).render(:ie).should == build_color_type( HexColor, '#808080' ).render
|
216
|
+
Color.new('#FFF', :alpha => 0.5, :background => :black).render(:ie).should == build_color_type( HexColor, '#808080' ).render
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should alias #to_s to render' do
|
221
|
+
Color.new(:black, :alpha => 0.5).to_s.should == Color.new(:black, :alpha => 0.5).render
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,370 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
ColorType = StyleTrain::ColorType unless defined?( ColorType )
|
4
|
+
HexColor = StyleTrain::HexColor unless defined?( HexColor )
|
5
|
+
KeywordColor = StyleTrain::KeywordColor unless defined?( KeywordColor )
|
6
|
+
RGBcolor = StyleTrain::RGBcolor unless defined?( RGBcolor )
|
7
|
+
|
8
|
+
describe ColorType do
|
9
|
+
describe 'class methods' do
|
10
|
+
describe 'percentages' do
|
11
|
+
it 'should return false if string does not contain a percentage' do
|
12
|
+
ColorType.percentage( '255' ).should == false
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return the number' do
|
16
|
+
ColorType.percentage( '33%' ).should == 33
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should return decimal values of percentages' do
|
20
|
+
ColorType.percentage( '33.5%' ).should == 33.5
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should raise an argument error if the percentage is out of range' do
|
24
|
+
lambda { ColorType.percentage( '133%' ) }.should raise_error( ArgumentError )
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'byte numbers' do
|
29
|
+
it 'should return the number' do
|
30
|
+
ColorType.byte( '33' ).should == 33
|
31
|
+
ColorType.byte( '0' ).should == 0
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should raise an argument error if the number is out of range' do
|
35
|
+
lambda { ColorType.byte( '256' ) }.should raise_error( ArgumentError )
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'conversion' do
|
40
|
+
it 'should convert from byte numbers to percentages' do
|
41
|
+
ColorType.byte_to_percentage( 255 ).should == 100
|
42
|
+
ColorType.byte_to_percentage( 127 ).should == 50
|
43
|
+
ColorType.byte_to_percentage( 64 ).should == 25
|
44
|
+
ColorType.byte_to_percentage( 0 ).should == 0
|
45
|
+
lambda{ ColorType.byte_to_percentage(256) }.should raise_error( ColorType::ByteNumberError )
|
46
|
+
lambda{ ColorType.byte_to_percentage(-5) }.should raise_error( ColorType::ByteNumberError )
|
47
|
+
lambda{ ColorType.byte_to_percentage(122.6) }.should_not raise_error
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should convert from percentage to byte' do
|
51
|
+
ColorType.percent_to_byte( 100 ).should == 255
|
52
|
+
ColorType.percent_to_byte( 50 ).should == 127
|
53
|
+
ColorType.percent_to_byte( 25 ).should == 64
|
54
|
+
ColorType.percent_to_byte( 0 ).should == 0
|
55
|
+
lambda{ ColorType.percent_to_byte(101) }.should raise_error( ColorType::PercentageError )
|
56
|
+
lambda{ ColorType.percent_to_byte(-5) }.should raise_error( ColorType::PercentageError )
|
57
|
+
lambda{ ColorType.percent_to_byte(22.6) }.should_not raise_error
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'custom argument errors should raise custom messages' do
|
61
|
+
begin
|
62
|
+
ColorType.percent_to_byte(101)
|
63
|
+
rescue Exception => e
|
64
|
+
e.message.match(/must be between 0 and/)
|
65
|
+
end
|
66
|
+
|
67
|
+
begin
|
68
|
+
ColorType.byte_to_percentage(256)
|
69
|
+
rescue Exception => e
|
70
|
+
e.message.match(/must be between 0 and/)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#is_color?' do
|
76
|
+
it 'should recognize any of the color types' do
|
77
|
+
ColorType.is_color?(KeywordColor.new(:color => :linen)).should be_true
|
78
|
+
ColorType.is_color?(RGBcolor.new(:color => [0,0,0])).should be_true
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should be false if not a color type' do
|
82
|
+
ColorType.is_color?( nil ).should be_false
|
83
|
+
ColorType.is_color?( {} ).should be_false
|
84
|
+
ColorType.is_color?( [] ).should be_false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#make' do
|
89
|
+
it 'returns nil if not the right type' do
|
90
|
+
HexColor.make(:color => :lightyellow).should be_nil
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns an instance on the color type if arguments are correct' do
|
94
|
+
KeywordColor.make(:color => :lightyellow).is_a?(KeywordColor).should be_true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'instance methods' do
|
100
|
+
describe 'conversion' do
|
101
|
+
describe 'from rgb' do
|
102
|
+
before do
|
103
|
+
@color = RGBcolor.new(:color => [0,0,0])
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'to keyword works' do
|
107
|
+
new_color = @color.to(:keyword)
|
108
|
+
new_color.class.should == KeywordColor
|
109
|
+
new_color.keyword.should == :black
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'to hex works' do
|
113
|
+
new_color = @color.to(:hex)
|
114
|
+
new_color.class.should == HexColor
|
115
|
+
new_color.hex_6.should == 0x000000
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe 'from hex' do
|
120
|
+
before do
|
121
|
+
@color = HexColor.new(:color => '#000')
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'to keyword works' do
|
125
|
+
new_color = @color.to(:keyword)
|
126
|
+
new_color.class.should == KeywordColor
|
127
|
+
new_color.keyword.should == :black
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'to rgb works' do
|
131
|
+
new_color = @color.to(:rgb)
|
132
|
+
new_color.class.should == RGBcolor
|
133
|
+
new_color.red.should == 0
|
134
|
+
new_color.green.should == 0
|
135
|
+
new_color.blue.should == 0
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe 'from keyword' do
|
140
|
+
before do
|
141
|
+
@color = KeywordColor.new(:color => :black)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'to rgb works' do
|
145
|
+
new_color = @color.to(:rgb)
|
146
|
+
new_color.class.should == RGBcolor
|
147
|
+
new_color.red.should == 0
|
148
|
+
new_color.green.should == 0
|
149
|
+
new_color.blue.should == 0
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'to hex works' do
|
153
|
+
new_color = @color.to(:hex)
|
154
|
+
new_color.class.should == HexColor
|
155
|
+
new_color.hex_6.should == 0x000000
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe 'alpha' do
|
161
|
+
before do
|
162
|
+
@color = KeywordColor.new(:color => :black)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should be 1.0 by default' do
|
166
|
+
@color.alpha.should == 1.0
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should be 1.0 if alpha is entered as 1' do
|
170
|
+
@color.alpha = 1
|
171
|
+
@color.alpha.should == 1.0
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should be be 0.0 if set to 0' do
|
175
|
+
@color.alpha = 0
|
176
|
+
@color.alpha.should == 0.0
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should be a decimal value between zero and one if set that way' do
|
180
|
+
@color.alpha = 0.5
|
181
|
+
@color.alpha.should == 0.5
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should be set via the initializer' do
|
185
|
+
color = KeywordColor.new(:color => :black, :alpha => 0.5)
|
186
|
+
color.alpha.should == 0.5
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should raise an error if out of range' do
|
190
|
+
lambda{ @color.alpha = 1.5 }.should raise_error
|
191
|
+
end
|
192
|
+
|
193
|
+
describe '#alpha?' do
|
194
|
+
it '#should be false if alpha value is 1.0' do
|
195
|
+
@color.alpha?.should == false
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should be true if alpha is greater than 0 and less than 1' do
|
199
|
+
@color.alpha = 0.5
|
200
|
+
@color.alpha?.should be_true
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe 'comparisons' do
|
206
|
+
before do
|
207
|
+
@hex = HexColor.new(:color => '#000')
|
208
|
+
@keyword = KeywordColor.new(:color => :black)
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '=~' do
|
212
|
+
it 'should be true if the r, g, b values are the same' do
|
213
|
+
(@hex =~ @keyword).should == true
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should be true even if the alpha values are different' do
|
217
|
+
@hex.alpha = 0.5
|
218
|
+
(@hex =~ @keyword).should == true
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should compare with the delagate of a color' do
|
222
|
+
(@hex =~ StyleTrain::Color.new('#000')).should == true
|
223
|
+
(@hex =~ StyleTrain::Color.new('#fff')).should == false
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
describe '==' do
|
228
|
+
it 'should be true if the colors are =~ and also have the same alpha' do
|
229
|
+
(@hex == @keyword).should == true
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'should be false if the alphas are different' do
|
233
|
+
@hex.alpha = 0.5
|
234
|
+
(@hex == @keyword).should == false
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'should be false if the r, g, b values are different' do
|
238
|
+
color = KeywordColor.new(:color => :maroon)
|
239
|
+
(color == @keyword).should == false
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '===' do
|
244
|
+
before do
|
245
|
+
@key2 = KeywordColor.new(:color => :black)
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'should be true if the colors are == and also have the same class' do
|
249
|
+
(@key2 === @keyword).should == true
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'should be false if the classes are different' do
|
253
|
+
(@keyword === @hex).should == false
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'should be false if the alphas are different' do
|
257
|
+
@key2.alpha = 0.5
|
258
|
+
(@key2 == @keyword).should == false
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should be false if the r, g, b values are different' do
|
262
|
+
color = KeywordColor.new(:color => :maroon)
|
263
|
+
(color == @keyword).should == false
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe 'mixing' do
|
269
|
+
before do
|
270
|
+
@rgb = RGBcolor.new(:color => [20,40,60], :alpha => 0.5)
|
271
|
+
@hex = HexColor.new(:color => '#666')
|
272
|
+
end
|
273
|
+
|
274
|
+
describe 'averaging' do
|
275
|
+
it 'should average the r, g, and b values' do
|
276
|
+
color = @rgb.mix(@hex)
|
277
|
+
color.r.should == ((102+20)/2.0).round
|
278
|
+
color.g.should == ((102+40)/2.0).round
|
279
|
+
color.b.should == ((102+60)/2.0).round
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should average the alpha' do
|
283
|
+
color = @rgb.mix(@hex)
|
284
|
+
color.alpha.should == 0.75
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'should return the original color type' do
|
288
|
+
color = @rgb.mix(@hex)
|
289
|
+
color.class.should == RGBcolor
|
290
|
+
|
291
|
+
color = @hex.mix(@rgb)
|
292
|
+
color.class.should == HexColor
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe 'layering' do
|
297
|
+
before do
|
298
|
+
@white = HexColor.new(:color => '#FFF')
|
299
|
+
@shadow = HexColor.new(:color => '#000', :alpha => 0.5)
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should blend on the class method' do
|
303
|
+
ColorType.blend(255, 0, 0.5).should == 128
|
304
|
+
ColorType.blend(128, 0, 0.5).should == 64
|
305
|
+
ColorType.blend(255, 0, 0.25).should == 64
|
306
|
+
end
|
307
|
+
|
308
|
+
describe 'r, g, b' do
|
309
|
+
describe 'opaque top layer' do
|
310
|
+
it 'should have the r, g, b values of the top layer' do
|
311
|
+
color = @rgb.layer(@hex)
|
312
|
+
color.r.should == 102
|
313
|
+
color.g.should == 102
|
314
|
+
color.b.should == 102
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
describe 'opaque bottom layer' do
|
319
|
+
before do
|
320
|
+
@color = @white.layer(@shadow)
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'should mix the r, g, and b in proportion to the top layer\'s alpha' do
|
324
|
+
@color.r.should == 128
|
325
|
+
@color.g.should == 128
|
326
|
+
@color.b.should == 128
|
327
|
+
|
328
|
+
red = RGBcolor.new(:color => [153,0,0], :alpha => 0.25)
|
329
|
+
color = @white.layer(red)
|
330
|
+
color.r.should == (153*0.25 + 255*0.75).round
|
331
|
+
color.g.should == (0*0.25 + 255*0.75).round
|
332
|
+
color.b.should == (0*0.25 + 255*0.75).round
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe 'alpha blending' do
|
338
|
+
it 'should be 1.0 if bottom layer is opaque' do
|
339
|
+
color = @white.layer(@shadow)
|
340
|
+
color.alpha.should == 1.0
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'should be 1.0 if the top layer is opaque' do
|
344
|
+
color = @shadow.layer(@white)
|
345
|
+
color.alpha.should == 1.0
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'should have an alpha greater than or equal to the composites' do
|
349
|
+
color = @rgb.layer(@shadow)
|
350
|
+
(color.alpha >= @rgb.alpha).should be_true
|
351
|
+
(color.alpha >= @shadow.alpha).should be_true
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'should calculate the blending of two alphas properly' do
|
355
|
+
color = @rgb.layer(@shadow)
|
356
|
+
color.alpha.should == 0.75 # 0.5 for the base color, plus 0.5 of the remaining transparency
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
describe 'stepping'
|
362
|
+
|
363
|
+
end
|
364
|
+
|
365
|
+
describe 'rendering' do
|
366
|
+
# todo: do color specs first, to work out where the blending of background should happen
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
end
|