style_train 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|