ionfish-stylish 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +32 -0
- data/README.md +2 -5
- data/Rakefile +16 -5
- data/VERSION.yml +1 -1
- data/lib/stylish/background.rb +226 -0
- data/lib/stylish/color.rb +14 -20
- data/lib/stylish/core.rb +24 -159
- data/lib/stylish/generate.rb +62 -3
- data/lib/stylish/stylesheet.rb +2 -2
- data/lib/stylish/tree.rb +2 -2
- data/lib/stylish.rb +15 -9
- data/test/background_test.rb +36 -3
- data/test/color_test.rb +8 -13
- data/test/comment_test.rb +0 -3
- data/test/declaration_test.rb +0 -3
- data/test/declarations_test.rb +1 -4
- data/test/formattable_test.rb +0 -3
- data/test/generate_test.rb +0 -3
- data/test/image_test.rb +0 -3
- data/test/rule_test.rb +0 -3
- data/test/selector_test.rb +1 -4
- data/test/selectors_test.rb +0 -3
- data/test/stylesheet_test.rb +0 -3
- data/test/tree_test.rb +0 -3
- data/test/variable_test.rb +46 -0
- metadata +6 -2
data/History.txt
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
=== Version 0.1.3 (TODO)
|
2
|
+
|
3
|
+
Variables in the DSL
|
4
|
+
* Selector and property variables
|
5
|
+
* New descope example
|
6
|
+
* Limited CSS3 background support
|
7
|
+
* Cleaned up various things
|
8
|
+
|
9
|
+
|
10
|
+
=== Version 0.1.2 (2009-04-12)
|
11
|
+
|
12
|
+
Documentation release
|
13
|
+
* Documented the stylesheet generation DSL
|
14
|
+
* Updated example code in the README
|
15
|
+
* Added an Image class to handle background images
|
16
|
+
|
17
|
+
|
18
|
+
=== Version 0.1.1 (2009-04-12)
|
19
|
+
|
20
|
+
More DSL features
|
21
|
+
* Added the ability to append comments through the stylesheet generation DSL
|
22
|
+
* Fixed some parsing and selector serialisation problems
|
23
|
+
* Updated the main example file to work with the new DSL
|
24
|
+
* Completed the documentation of the core classes
|
25
|
+
|
26
|
+
|
27
|
+
=== Version 0.1.0 (2009-04-10)
|
28
|
+
|
29
|
+
First major release
|
30
|
+
* New selector scope tree, which serialises to a valid stylesheet
|
31
|
+
* Stylesheet generation DSL based on the tree datastructure
|
32
|
+
* HSL(A) colour space support, complementing the existing RGB support
|
data/README.md
CHANGED
@@ -23,6 +23,8 @@ Calling the stylesheet's `to_s` method would produce the following
|
|
23
23
|
.content h2 {font-size:2em;}
|
24
24
|
.content p {margin:0 0 1em 0;}
|
25
25
|
|
26
|
+
A number of additional examples are available in the example/ directory.
|
27
|
+
|
26
28
|
|
27
29
|
Compatibility
|
28
30
|
-------------
|
@@ -36,11 +38,6 @@ Future considerations
|
|
36
38
|
|
37
39
|
* Add a Border class to complement Background.
|
38
40
|
* Add better support for CSS3 properties to Background.
|
39
|
-
* Add a native mapping construct to allow symbol lookup for alternate
|
40
|
-
stylesheets.
|
41
|
-
* Change stylesheet generation to a two-step process where the tree structure
|
42
|
-
is generated in the first step and symbols (for example, those employed by
|
43
|
-
a mapping construct) are evaluated the second.
|
44
41
|
* Fundamental objects like percentages need their own classes rather than
|
45
42
|
being dealt with in an ad-hoc manner by higher-level objects.
|
46
43
|
* Add a parser so CSS can be read as well as written.
|
data/Rakefile
CHANGED
@@ -11,14 +11,16 @@ begin
|
|
11
11
|
s.authors = ["Benedict Eastaugh"]
|
12
12
|
end
|
13
13
|
rescue LoadError
|
14
|
-
puts "Jeweler not available. Install it with: sudo gem install "
|
15
|
-
|
14
|
+
puts "Jeweler not available. Install it with: sudo gem install " +
|
15
|
+
"technicalpickles-jeweler -s http://gems.github.com"
|
16
16
|
end
|
17
17
|
|
18
18
|
task :default => :test
|
19
19
|
|
20
20
|
desc "Run the Stylish test suite"
|
21
21
|
task :test do
|
22
|
+
require 'test/unit'
|
23
|
+
|
22
24
|
testdir = "test"
|
23
25
|
Dir.foreach(testdir) do |f|
|
24
26
|
path = "#{testdir}/#{f}"
|
@@ -28,7 +30,16 @@ task :test do
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
namespace :example do
|
34
|
+
|
35
|
+
desc "An extended generator DSL example."
|
36
|
+
task :tarski do
|
37
|
+
require 'example/tarski'
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Extract base rules from a selector tree."
|
41
|
+
task :descope do
|
42
|
+
require 'example/descope'
|
43
|
+
end
|
34
44
|
end
|
45
|
+
|
data/VERSION.yml
CHANGED
@@ -0,0 +1,226 @@
|
|
1
|
+
module Stylish
|
2
|
+
|
3
|
+
# The Background class is a specialised kind of Declaration, geared towards
|
4
|
+
# dealing with the oddities of the background family of declarations, which
|
5
|
+
# can exist in both long- and shorthand forms.
|
6
|
+
#
|
7
|
+
# For example, these longhand background declarations
|
8
|
+
#
|
9
|
+
# background-color: #999;
|
10
|
+
# background-image: url('bg.png');
|
11
|
+
# background-repeat: repeat-x;
|
12
|
+
#
|
13
|
+
# could be compressed into a single shorthand declaration
|
14
|
+
#
|
15
|
+
# background: #999 url('bg.png') repeat-x;
|
16
|
+
#
|
17
|
+
# The Background class allows for easy conversion between these forms. It
|
18
|
+
# defaults to the longhand versions, allowing rules with stronger selector
|
19
|
+
# weighting to only override specific parts of other rules' background
|
20
|
+
# declarations.
|
21
|
+
class Background < Declaration
|
22
|
+
attr_reader :color,
|
23
|
+
:image,
|
24
|
+
:repeat,
|
25
|
+
:position,
|
26
|
+
:attachment,
|
27
|
+
:origin,
|
28
|
+
:break,
|
29
|
+
:compressed
|
30
|
+
|
31
|
+
PROPERTIES = [
|
32
|
+
[:color, "background-color"],
|
33
|
+
[:image, "background-image"],
|
34
|
+
[:repeat, "background-repeat"],
|
35
|
+
[:position, "background-position"],
|
36
|
+
[:attachment, "background-attachment"],
|
37
|
+
[:origin, "background-origin"],
|
38
|
+
[:break, "background-break"],
|
39
|
+
[:compressed]]
|
40
|
+
|
41
|
+
REPEAT_VALUES = ["repeat-x", "repeat-y", "repeat",
|
42
|
+
"space", "round", "no-repeat"]
|
43
|
+
ATTACHMENT_VALUES = ["scroll", "fixed", "local"]
|
44
|
+
HORIZONTAL_POSITIONS = ["left", "center", "right"]
|
45
|
+
VERTICAL_POSITIONS = ["top", "center", "bottom"]
|
46
|
+
ORIGIN_VALUES = ["border-box", "padding-box", "content-box"]
|
47
|
+
BREAK_VALUES = ["bounding-box", "each-box", "continuous"]
|
48
|
+
|
49
|
+
# Create a new Background object with the specified properties.
|
50
|
+
def initialize(options)
|
51
|
+
accept_format(/^\s*%s\s*:\s*%s;\s*$/m, "%s:%s;")
|
52
|
+
self.value = options
|
53
|
+
end
|
54
|
+
|
55
|
+
# Input validation for colours is handled by the Color class, which will
|
56
|
+
# raise an ArgumentError if the argument is an invalid colour value.
|
57
|
+
def color=(val)
|
58
|
+
@color = Color.new(val)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set the background image(s). As of CSS3, elements may have multiple
|
62
|
+
# background images, so this method attempts to provide a backwards-
|
63
|
+
# compatible solution.
|
64
|
+
#
|
65
|
+
# background = Background.new :image => "sky.png", :compressed => true
|
66
|
+
# background.to_s # => "background:url('sky.png');"
|
67
|
+
#
|
68
|
+
# background.image = ["ball.png", "grass.png"]
|
69
|
+
# background.to_s # => "background:url('ball.png'), url('grass.png');"
|
70
|
+
#
|
71
|
+
def image=(paths)
|
72
|
+
paths = [paths] if paths.is_a?(String)
|
73
|
+
@image = paths.inject([]) {|images, path| images << Image.new(path) }
|
74
|
+
|
75
|
+
if @image.length < 2
|
76
|
+
@image = @image.first
|
77
|
+
else
|
78
|
+
def @image.to_s
|
79
|
+
join(", ")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Set the background repeat(s). As of CSS3, the background-repeat property
|
85
|
+
# may have multiple values, so this method provides a backwards-compatible
|
86
|
+
# solution.
|
87
|
+
#
|
88
|
+
# repeating = Background.new :repeat => ["repeat-x", "repeat-y"]
|
89
|
+
# repeating.to_s # => "background-repeat:repeat-x, repeat-y;"
|
90
|
+
#
|
91
|
+
def repeat=(repeats)
|
92
|
+
repeats = [repeats] if repeats.is_a? String
|
93
|
+
@repeat = repeats.find_all {|r| REPEAT_VALUES.include? r }
|
94
|
+
|
95
|
+
if @repeat.length < 2
|
96
|
+
@repeat = @repeat.first
|
97
|
+
else
|
98
|
+
def @repeat.to_s
|
99
|
+
join(", ")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Only position keywords are currently handled, not percentages or lengths.
|
105
|
+
def position=(val)
|
106
|
+
xpos, ypos = val.split(/\s+/) << "center"
|
107
|
+
if HORIZONTAL_POSITIONS.include?(xpos) && VERTICAL_POSITIONS.include?(ypos)
|
108
|
+
@position = [xpos, ypos]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# The background-attachment property takes a limited range of values, so
|
113
|
+
# only a value within that range will be accepted.
|
114
|
+
def attachment=(attachments)
|
115
|
+
attachments = [attachments] if attachments.is_a? String
|
116
|
+
@attachment = attachments.find_all {|a| ATTACHMENT_VALUES.include? a }
|
117
|
+
|
118
|
+
if @attachment.length < 2
|
119
|
+
@attachment = @attachment.first
|
120
|
+
else
|
121
|
+
def @attachment.to_s
|
122
|
+
join(", ")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# The background-origin property specifies the background positioning area.
|
128
|
+
# It is a CSS3 property which takes multiple values.
|
129
|
+
#
|
130
|
+
# original = Background.new :origin => ["padding-box", "content-box"]
|
131
|
+
# original.to_s # => background-origin:padding-box, content-box;
|
132
|
+
#
|
133
|
+
def origin=(origins)
|
134
|
+
origins = [origins] if origins.is_a? String
|
135
|
+
@origin = origins.find_all {|o| ORIGIN_VALUES.include? o }
|
136
|
+
|
137
|
+
if @origin.length < 2
|
138
|
+
@origin = @origin.first
|
139
|
+
else
|
140
|
+
def @origin.to_s
|
141
|
+
join(", ")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# The background-break property, defined in CSS3, specifies how the
|
147
|
+
# background positioning area is derived when an element is broken into
|
148
|
+
# multiple boxes.
|
149
|
+
#
|
150
|
+
# broken = Background.new :break => "bounding-box"
|
151
|
+
# broken.to_s # => "background-break:bounding-box;"
|
152
|
+
#
|
153
|
+
def break=(value)
|
154
|
+
@break = value if BREAK_VALUES.include? value
|
155
|
+
end
|
156
|
+
|
157
|
+
# Set this to true to generate a shorthand declaration, e.g.
|
158
|
+
#
|
159
|
+
# background:#ccc url('bg.png') no-repeat 0 0;
|
160
|
+
#
|
161
|
+
# As opposed to the longhand version:
|
162
|
+
#
|
163
|
+
# background-color:#ccc; background-image:url('bg.png');
|
164
|
+
# background-repeat:no-repeat; background-position:0 0;
|
165
|
+
#
|
166
|
+
def compressed=(val)
|
167
|
+
@compressed = val == true || nil
|
168
|
+
end
|
169
|
+
|
170
|
+
# Override Declaration#name, since it's not compatible with the
|
171
|
+
# internals of this class.
|
172
|
+
def name
|
173
|
+
PROPERTIES.reject {|n, p| p.nil? }.map {|n, p|
|
174
|
+
value = self.send(n)
|
175
|
+
p.to_s unless value.nil?
|
176
|
+
}.compact
|
177
|
+
end
|
178
|
+
|
179
|
+
# Override Declaration#name=, since it's not compatible with the
|
180
|
+
# internals of this class.
|
181
|
+
def name=(val)
|
182
|
+
raise NoMethodError, "name= is not defined for Background."
|
183
|
+
end
|
184
|
+
|
185
|
+
# Override Declaration#value, since it's not compatible with the internals
|
186
|
+
# of this class.
|
187
|
+
def value(name_and_value = false)
|
188
|
+
PROPERTIES.reject {|n, p| p.nil? }.map {|n, p|
|
189
|
+
value = self.send(n)
|
190
|
+
next if value.nil?
|
191
|
+
name_and_value ? [p.to_s, value] : value
|
192
|
+
}.compact
|
193
|
+
end
|
194
|
+
|
195
|
+
# Override Declaration#value=, since it's not compatible with the internals
|
196
|
+
# of this class.
|
197
|
+
def value=(options)
|
198
|
+
unless options.is_a? Hash
|
199
|
+
raise ArgumentError, "Argument must be a hash of background properties"
|
200
|
+
end
|
201
|
+
|
202
|
+
PROPERTIES.each do |name, property|
|
203
|
+
self.send(:"#{name.to_s}=", options[name]) if options[name]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Generate a string representation of a Background instance.
|
208
|
+
#
|
209
|
+
# There are two kinds of representation, each of which have slightly
|
210
|
+
# different CSS semantics. If compressed is set to true, this method will
|
211
|
+
# produce a shorthand CSS declaration such as the following:
|
212
|
+
#
|
213
|
+
# background: #fff url('bg.png') no-repeat 50% 0;
|
214
|
+
#
|
215
|
+
# Otherwise it will produce an unordered list of individual background
|
216
|
+
# declarations.
|
217
|
+
def to_s(symbols = {})
|
218
|
+
if @compressed
|
219
|
+
"background:#{self.value(true).map {|p, v| v }.compact.join(" ")};"
|
220
|
+
else
|
221
|
+
self.value(true).map {|p, v| sprintf(@format, p, v.to_s) }.join(" ")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
data/lib/stylish/color.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'mathn'
|
2
|
-
require 'rational'
|
3
|
-
|
4
1
|
module Stylish #:nodoc:
|
5
2
|
|
6
3
|
# The Color class is intended to eventually implement the entirety of the
|
@@ -214,7 +211,7 @@ module Stylish #:nodoc:
|
|
214
211
|
[:red, :green, :blue].each do |color|
|
215
212
|
reader = color
|
216
213
|
writer = :"#{color}="
|
217
|
-
color
|
214
|
+
color = :"@#{color.to_s}"
|
218
215
|
|
219
216
|
unless self.respond_to?(reader)
|
220
217
|
self.send(:define_method, reader) do
|
@@ -246,11 +243,11 @@ module Stylish #:nodoc:
|
|
246
243
|
# Attribute writer for the color's value. Uses the ColorStringParser inner
|
247
244
|
# class to parse string values, and contains other logic to handle arrays.
|
248
245
|
def value=(value)
|
249
|
-
if value.is_a?(String)
|
246
|
+
if value.is_a?(String)
|
250
247
|
parser = ColorStringParser.new
|
251
248
|
@type, @red, @green, @blue, @opacity = parser.parse(value)
|
252
249
|
return unless @type.nil?
|
253
|
-
|
250
|
+
else
|
254
251
|
rgb = value[0..2].inject([]) do |rgb, v|
|
255
252
|
if v.is_a?(Integer) || v.is_a?(Float)
|
256
253
|
rgb << v
|
@@ -263,14 +260,12 @@ module Stylish #:nodoc:
|
|
263
260
|
rgb
|
264
261
|
end
|
265
262
|
|
266
|
-
if
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
@type = :rgba and return
|
273
|
-
end
|
263
|
+
if value.length < 4
|
264
|
+
@red, @green, @blue, @opacity = rgb << nil
|
265
|
+
@type = :rgb and return
|
266
|
+
else
|
267
|
+
@red, @green, @blue, @opacity = rgb << value[3].to_f
|
268
|
+
@type = :rgba and return
|
274
269
|
end
|
275
270
|
end
|
276
271
|
|
@@ -289,10 +284,7 @@ module Stylish #:nodoc:
|
|
289
284
|
# color.opacity # => 0.5
|
290
285
|
#
|
291
286
|
def opacity=(value)
|
292
|
-
|
293
|
-
return if value < 0 || value > 1
|
294
|
-
|
295
|
-
@opacity = value
|
287
|
+
@opacity = value unless value < 0 || value > 1
|
296
288
|
end
|
297
289
|
|
298
290
|
# Returns a color keyword string if the RGB value of the color is equal to
|
@@ -381,7 +373,7 @@ module Stylish #:nodoc:
|
|
381
373
|
# color.type = :rgb
|
382
374
|
# color.to_s # => "rgb(0, 0, 0)"
|
383
375
|
#
|
384
|
-
def to_s
|
376
|
+
def to_s(symbols = {})
|
385
377
|
return "inherit" if @type == :inherit
|
386
378
|
|
387
379
|
self.send(:"to_#{self.type.to_s}")
|
@@ -415,7 +407,9 @@ module Stylish #:nodoc:
|
|
415
407
|
huer.call(red - green, 240)
|
416
408
|
end
|
417
409
|
|
418
|
-
[hue].concat([saturation, lightness].map {|r|
|
410
|
+
[hue].concat([saturation, lightness].map {|r|
|
411
|
+
(r * 100).to_f.round.to_s + "%"
|
412
|
+
})
|
419
413
|
end
|
420
414
|
|
421
415
|
def hsla
|
data/lib/stylish/core.rb
CHANGED
@@ -73,8 +73,9 @@ module Stylish
|
|
73
73
|
end
|
74
74
|
|
75
75
|
# Serialise the rule to valid CSS code.
|
76
|
-
def to_s(scope = "")
|
77
|
-
sprintf(@format, selectors.join(scope),
|
76
|
+
def to_s(symbols = {}, scope = "")
|
77
|
+
sprintf(@format, selectors.join(symbols, scope),
|
78
|
+
@declarations.to_s(symbols))
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
@@ -150,7 +151,7 @@ module Stylish
|
|
150
151
|
# the serialisation API of those trees, and thus the #to_s method has a
|
151
152
|
# scope argument, which is in practice discarded when the serialisation of
|
152
153
|
# the comment occurs.
|
153
|
-
def to_s(scope = "")
|
154
|
+
def to_s(symbols = {}, scope = "")
|
154
155
|
if @lines.empty? && @metadata.empty?
|
155
156
|
sprintf("/**\n * %s\n */", @header)
|
156
157
|
else
|
@@ -178,8 +179,8 @@ module Stylish
|
|
178
179
|
|
179
180
|
# Selectors are immutable once created; the value of a given Selector must
|
180
181
|
# be set when the object is created.
|
181
|
-
def initialize(
|
182
|
-
@selector =
|
182
|
+
def initialize(selector)
|
183
|
+
@selector = selector
|
183
184
|
end
|
184
185
|
|
185
186
|
# Each Rule possesses one or more Selectors. Rules are often placed in
|
@@ -190,8 +191,9 @@ module Stylish
|
|
190
191
|
#
|
191
192
|
# The Selector class is also used internally by the Tree::SelectorScope
|
192
193
|
# class, to store its scope value.
|
193
|
-
def to_s(scope = "")
|
194
|
-
(scope.empty? ? "" : scope + " ") +
|
194
|
+
def to_s(symbols = {}, scope = "")
|
195
|
+
(scope.empty? ? "" : scope + " ") +
|
196
|
+
(@selector.is_a?(String) ? @selector.to_s : @selector.to_s(symbols))
|
195
197
|
end
|
196
198
|
end
|
197
199
|
|
@@ -211,15 +213,15 @@ module Stylish
|
|
211
213
|
# The join method overrides the superclass' method in order to always use a
|
212
214
|
# specific separator, and so that the scope that the selectors are being
|
213
215
|
# used in can be passed through when Rules etc. are serialised.
|
214
|
-
def join(scope = "")
|
216
|
+
def join(symbols = {}, scope = "")
|
215
217
|
self.inject("") do |ss, s|
|
216
|
-
(ss.empty? ? "" : ss + self.format) + s.to_s(scope)
|
218
|
+
(ss.empty? ? "" : ss + self.format) + s.to_s(symbols, scope)
|
217
219
|
end
|
218
220
|
end
|
219
221
|
|
220
222
|
# The to_s method alternative way of calling the join method.
|
221
|
-
def to_s(scope = "")
|
222
|
-
self.join(scope)
|
223
|
+
def to_s(symbols = {}, scope = "")
|
224
|
+
self.join(symbols, scope)
|
223
225
|
end
|
224
226
|
end
|
225
227
|
|
@@ -262,12 +264,17 @@ module Stylish
|
|
262
264
|
#
|
263
265
|
# Since the formatting can be adjusted via the #format= accessor, the exact
|
264
266
|
# spacing of the declaration can be controlled if desired.
|
265
|
-
def to_s
|
266
|
-
|
267
|
+
def to_s(symbols = {})
|
268
|
+
if @value.is_a?(Generate::Variable) || @value.is_a?(Color)
|
269
|
+
value = @value.to_s(symbols)
|
270
|
+
else
|
271
|
+
value = @value.to_s
|
272
|
+
end
|
273
|
+
|
274
|
+
sprintf(@format, @property_name.to_s, value)
|
267
275
|
end
|
268
276
|
end
|
269
277
|
|
270
|
-
|
271
278
|
# Declarations subclasses Array so that whenever #join is called, the
|
272
279
|
# instance's format attribute will be used as the join string, rather than
|
273
280
|
# the empty string.
|
@@ -292,151 +299,9 @@ module Stylish
|
|
292
299
|
# format attribute. Assuming that its contents are indeed Declaration
|
293
300
|
# objects, this will invoke their own #to_s method and generating correct
|
294
301
|
# CSS code.
|
295
|
-
def to_s
|
296
|
-
self.
|
297
|
-
|
298
|
-
end
|
299
|
-
|
300
|
-
# The Background class is a specialised kind of Declaration, geared towards
|
301
|
-
# dealing with the oddities of the background family of declarations, which
|
302
|
-
# can exist in both long- and shorthand forms.
|
303
|
-
#
|
304
|
-
# For example, these longhand background declarations
|
305
|
-
#
|
306
|
-
# background-color: #999;
|
307
|
-
# background-image: url('bg.png');
|
308
|
-
# background-repeat: repeat-x;
|
309
|
-
#
|
310
|
-
# could be compressed into a single shorthand declaration
|
311
|
-
#
|
312
|
-
# background: #999 url('bg.png') repeat-x;
|
313
|
-
#
|
314
|
-
# The Background class allows for easy conversion between these forms. It
|
315
|
-
# defaults to the longhand versions, allowing rules with stronger selector
|
316
|
-
# weighting to only override specific parts of other rules' background
|
317
|
-
# declarations.
|
318
|
-
class Background < Declaration
|
319
|
-
attr_reader :color,
|
320
|
-
:image,
|
321
|
-
:repeat,
|
322
|
-
:position,
|
323
|
-
:attachment,
|
324
|
-
:compressed
|
325
|
-
|
326
|
-
PROPERTIES = [
|
327
|
-
[:color, "background-color"],
|
328
|
-
[:image, "background-image"],
|
329
|
-
[:repeat, "background-repeat"],
|
330
|
-
[:position, "background-position"],
|
331
|
-
[:attachment, "background-attachment"],
|
332
|
-
[:compressed]]
|
333
|
-
|
334
|
-
REPEAT_VALUES = ["repeat", "repeat-x", "repeat-y", "no-repeat"]
|
335
|
-
ATTACHMENT_VALUES = ["scroll", "fixed", "inherit"]
|
336
|
-
HORIZONTAL_POSITIONS = ["left", "center", "right"]
|
337
|
-
VERTICAL_POSITIONS = ["top", "center", "bottom"]
|
338
|
-
|
339
|
-
# Create a new Background object with the specified properties.
|
340
|
-
def initialize(options)
|
341
|
-
accept_format(/^\s*%s\s*:\s*%s;\s*$/m, "%s:%s;")
|
342
|
-
self.value = options
|
343
|
-
end
|
344
|
-
|
345
|
-
# Input validation for colours is handled by the Color class, which will
|
346
|
-
# raise an ArgumentError if the argument is an invalid colour value.
|
347
|
-
def color=(val)
|
348
|
-
@color = Color.new(val)
|
349
|
-
end
|
350
|
-
|
351
|
-
# Set the background image.
|
352
|
-
def image=(path)
|
353
|
-
@image = Image.new(path) if path.is_a?(String)
|
354
|
-
end
|
355
|
-
|
356
|
-
# Set the background repeat.
|
357
|
-
def repeat=(val)
|
358
|
-
@repeat = val if REPEAT_VALUES.include?(val)
|
359
|
-
end
|
360
|
-
|
361
|
-
# Only position keywords are currently handled, not percentages or lengths.
|
362
|
-
def position=(val)
|
363
|
-
xpos, ypos = val.split(/\s+/) << "center"
|
364
|
-
if HORIZONTAL_POSITIONS.include?(xpos) && VERTICAL_POSITIONS.include?(ypos)
|
365
|
-
@position = [xpos, ypos]
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
# The background-attachment property takes a limited range of values, so
|
370
|
-
# only a value within that range will be accepted.
|
371
|
-
def attachment=(val)
|
372
|
-
@attachment = val if ATTACHMENT_VALUES.include?(val)
|
373
|
-
end
|
374
|
-
|
375
|
-
# Set this to true to generate a shorthand declaration, e.g.
|
376
|
-
#
|
377
|
-
# background:#ccc url('bg.png') no-repeat 0 0;
|
378
|
-
#
|
379
|
-
# As opposed to the longhand version:
|
380
|
-
#
|
381
|
-
# background-color:#ccc; background-image:url('bg.png');
|
382
|
-
# background-repeat:no-repeat; background-position:0 0;
|
383
|
-
#
|
384
|
-
def compressed=(val)
|
385
|
-
@compressed = val == true || nil
|
386
|
-
end
|
387
|
-
|
388
|
-
# Override Declaration#name, since it's not compatible with the
|
389
|
-
# internals of this class.
|
390
|
-
def name
|
391
|
-
PROPERTIES.reject {|n, p| p.nil? }.map {|n, p|
|
392
|
-
value = self.send(n)
|
393
|
-
p.to_s unless value.nil?
|
394
|
-
}.compact
|
395
|
-
end
|
396
|
-
|
397
|
-
# Override Declaration#name=, since it's not compatible with the
|
398
|
-
# internals of this class.
|
399
|
-
def name=(val)
|
400
|
-
raise NoMethodError, "name= is not defined for Background."
|
401
|
-
end
|
402
|
-
|
403
|
-
# Override Declaration#value, since it's not compatible with the internals
|
404
|
-
# of this class.
|
405
|
-
def value(name_and_value = false)
|
406
|
-
PROPERTIES.reject {|n, p| p.nil? }.map {|n, p|
|
407
|
-
value = self.send(n)
|
408
|
-
next if value.nil?
|
409
|
-
name_and_value ? [p.to_s, value] : value
|
410
|
-
}.compact
|
411
|
-
end
|
412
|
-
|
413
|
-
# Override Declaration#value=, since it's not compatible with the internals
|
414
|
-
# of this class.
|
415
|
-
def value=(options)
|
416
|
-
unless options.is_a? Hash
|
417
|
-
raise ArgumentError, "Argument must be a hash of background properties"
|
418
|
-
end
|
419
|
-
|
420
|
-
PROPERTIES.each do |name, property|
|
421
|
-
self.send(:"#{name.to_s}=", options[name]) if options[name]
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
# Generate a string representation of a Background instance.
|
426
|
-
#
|
427
|
-
# There are two kinds of representation, each of which have slightly
|
428
|
-
# different CSS semantics. If compressed is set to true, this method will
|
429
|
-
# produce a shorthand CSS declaration such as the following:
|
430
|
-
#
|
431
|
-
# background: #fff url('bg.png') no-repeat 50% 0;
|
432
|
-
#
|
433
|
-
# Otherwise it will produce an unordered list of individual background
|
434
|
-
# declarations.
|
435
|
-
def to_s
|
436
|
-
if @compressed
|
437
|
-
"background:#{self.value(true).map {|p, v| v }.compact.join(" ")};"
|
438
|
-
else
|
439
|
-
self.value(true).map {|p, v| sprintf(@format, p, v.to_s) }.join(" ")
|
302
|
+
def to_s(symbols = {})
|
303
|
+
self.inject("") do |a, o|
|
304
|
+
a << (a.empty? ? "" : @format) << o.to_s(symbols)
|
440
305
|
end
|
441
306
|
end
|
442
307
|
end
|
data/lib/stylish/generate.rb
CHANGED
@@ -55,10 +55,21 @@ module Stylish
|
|
55
55
|
key = key.to_s.sub("_", "-").to_sym
|
56
56
|
|
57
57
|
if key == :background
|
58
|
-
|
58
|
+
if value.any? {|k,v| v.is_a? Symbol }
|
59
|
+
declaration = Variable.new(value, Background)
|
60
|
+
else
|
61
|
+
declaration = Background.new(value)
|
62
|
+
end
|
59
63
|
elsif key == :color
|
60
|
-
|
64
|
+
if value.is_a? Symbol
|
65
|
+
value = Variable.new(value, Color)
|
66
|
+
else
|
67
|
+
value = Color.new(value)
|
68
|
+
end
|
69
|
+
|
70
|
+
declaration = Declaration.new("color", value)
|
61
71
|
else
|
72
|
+
value = Variable.new(value) if value.is_a? Symbol
|
62
73
|
declaration = Declaration.new(key, value)
|
63
74
|
end
|
64
75
|
|
@@ -66,6 +77,52 @@ module Stylish
|
|
66
77
|
end
|
67
78
|
end
|
68
79
|
|
80
|
+
# Variables are elements of a selector tree that haven't been assigned
|
81
|
+
# values yet. When a tree that includes Variable objects is serialised, it
|
82
|
+
# must be passed a symbol table so that the variables may be given values.
|
83
|
+
class Variable
|
84
|
+
|
85
|
+
# When Variable objects are initialised they may be given either a simple
|
86
|
+
# symbol, or a compound object (such as a hash) which contains symbols.
|
87
|
+
# When a compound object is given, a constructor must also be given.
|
88
|
+
#
|
89
|
+
# varbg = Variable.new({:image => :button, :color => :bright})
|
90
|
+
# varbg.to_s({:button => "button.png", :bright => "0f0"})
|
91
|
+
#
|
92
|
+
# Which would give the following:
|
93
|
+
#
|
94
|
+
# background-image:url('button.png'); background-color:#0f0;
|
95
|
+
#
|
96
|
+
# Constructors can also be given for simple values, e.g. when creating a
|
97
|
+
# Color.
|
98
|
+
#
|
99
|
+
# varc = Variable.new(:bright, Color)
|
100
|
+
# varc.to_s({:bright => "f00"}) # => "#f00"
|
101
|
+
#
|
102
|
+
def initialize(name_or_hash, constructor = nil)
|
103
|
+
@name = name_or_hash
|
104
|
+
@constructor = constructor
|
105
|
+
end
|
106
|
+
|
107
|
+
# The symbol table is given as an argument to the root element of a
|
108
|
+
# selector tree when it is serialised, and passed down to each node as
|
109
|
+
# the tree is traversed. Nodes must then serialise themselves, and if
|
110
|
+
# they contain Variables they must pass them the symbol table so that
|
111
|
+
# they can be resolved to a given value.
|
112
|
+
def to_s(symbols)
|
113
|
+
if @constructor.nil?
|
114
|
+
symbols[@name]
|
115
|
+
elsif @name.is_a? Symbol
|
116
|
+
@constructor.new(symbols[@name]).to_s
|
117
|
+
else
|
118
|
+
@constructor.new(@name.to_a.inject({}) {|a, e|
|
119
|
+
a[e.first] = symbols[e.last]
|
120
|
+
a
|
121
|
+
}).to_s
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
69
126
|
# Often the selector associated with a call to the rule method would simply
|
70
127
|
# be a single HTML element name. This has been factored out by adding
|
71
128
|
# methods to the Description DSL class corresponding to all the HTML
|
@@ -161,7 +218,9 @@ module Stylish
|
|
161
218
|
return unless declarations || block
|
162
219
|
|
163
220
|
selectors = [selectors] unless selectors.is_a?(Array)
|
164
|
-
selectors.map!
|
221
|
+
selectors.map! do |s|
|
222
|
+
Selector.new(s.is_a?(Symbol) ? Variable.new(s) : s)
|
223
|
+
end
|
165
224
|
|
166
225
|
declarations = Generate.parse_declarations(declarations)
|
167
226
|
|
data/lib/stylish/stylesheet.rb
CHANGED
@@ -16,9 +16,9 @@ module Stylish
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# Recursively serialise the tree to a stylesheet.
|
19
|
-
def to_s
|
19
|
+
def to_s(symbols = {})
|
20
20
|
return "" if @nodes.empty?
|
21
|
-
@nodes.map {|node| node.to_s }.join(@format)
|
21
|
+
@nodes.map {|node| node.to_s(symbols) }.join(@format)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
data/lib/stylish/tree.rb
CHANGED
@@ -84,10 +84,10 @@ module Stylish
|
|
84
84
|
end
|
85
85
|
|
86
86
|
# Recursively serialise the selector tree.
|
87
|
-
def to_s(scope = "")
|
87
|
+
def to_s(symbols = {}, scope = "")
|
88
88
|
return "" if @nodes.empty?
|
89
89
|
scope = scope.empty? ? @scope.to_s : scope + " " + @scope.to_s
|
90
|
-
@nodes.map {|node| node.to_s(scope) }.join(@format)
|
90
|
+
@nodes.map {|node| node.to_s(symbols, scope) }.join(@format)
|
91
91
|
end
|
92
92
|
|
93
93
|
# Return the node's child nodes.
|
data/lib/stylish.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
|
-
$:.unshift File.dirname(__FILE__)
|
2
|
-
|
3
1
|
require 'pathname'
|
2
|
+
require 'mathn'
|
3
|
+
require 'rational'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require '
|
9
|
-
require '
|
10
|
-
require '
|
11
|
-
require '
|
5
|
+
module Stylish
|
6
|
+
STYLISH_PATH = File.expand_path(File.dirname(__FILE__)) + '/stylish/'
|
7
|
+
|
8
|
+
require STYLISH_PATH + 'formattable'
|
9
|
+
require STYLISH_PATH + 'tree'
|
10
|
+
require STYLISH_PATH + 'core'
|
11
|
+
require STYLISH_PATH + 'tree'
|
12
|
+
require STYLISH_PATH + 'stylesheet'
|
13
|
+
require STYLISH_PATH + 'image'
|
14
|
+
require STYLISH_PATH + 'background'
|
15
|
+
require STYLISH_PATH + 'color'
|
16
|
+
require STYLISH_PATH + 'generate'
|
17
|
+
end
|
data/test/background_test.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require './lib/stylish'
|
3
|
-
|
4
1
|
class BackgroundTest < Test::Unit::TestCase
|
5
2
|
|
6
3
|
def setup
|
@@ -24,10 +21,26 @@ class BackgroundTest < Test::Unit::TestCase
|
|
24
21
|
Stylish::Background.new(:image => "background.jpg").image.path)
|
25
22
|
end
|
26
23
|
|
24
|
+
def test_multiple_background_images
|
25
|
+
bg = Stylish::Background.new :image =>
|
26
|
+
["flower.png", "ball.png", "grass.png"]
|
27
|
+
|
28
|
+
assert_equal(3, bg.image.length)
|
29
|
+
assert_equal("background-image:" +
|
30
|
+
"url('flower.png'), url('ball.png'), url('grass.png');", bg.to_s)
|
31
|
+
end
|
32
|
+
|
27
33
|
def test_valid_background_repeats
|
28
34
|
assert_equal('no-repeat', @composite.repeat)
|
29
35
|
end
|
30
36
|
|
37
|
+
def test_multiple_background_repeats
|
38
|
+
bg = Stylish::Background.new :repeat => ["repeat-x", "repeat-y"]
|
39
|
+
|
40
|
+
assert_equal(2, bg.repeat.length)
|
41
|
+
assert_equal("background-repeat:repeat-x, repeat-y;", bg.to_s)
|
42
|
+
end
|
43
|
+
|
31
44
|
def test_valid_background_positions
|
32
45
|
assert_equal(2, @composite.position.length)
|
33
46
|
assert_equal("left", @composite.position[0])
|
@@ -44,12 +57,32 @@ class BackgroundTest < Test::Unit::TestCase
|
|
44
57
|
Stylish::Background.new(:attachment => "fixed").attachment)
|
45
58
|
end
|
46
59
|
|
60
|
+
def test_multiple_attachments
|
61
|
+
glued = Stylish::Background.new :attachment => ["local", "fixed"]
|
62
|
+
|
63
|
+
assert_equal(2, glued.attachment.length)
|
64
|
+
assert_equal("background-attachment:local, fixed;", glued.to_s)
|
65
|
+
end
|
66
|
+
|
47
67
|
def test_invalid_background_colors
|
48
68
|
assert_raise ArgumentError do
|
49
69
|
Stylish::Background.new(:color => "sky-blue")
|
50
70
|
end
|
51
71
|
end
|
52
72
|
|
73
|
+
def test_origins
|
74
|
+
original = Stylish::Background.new :origin => ["border-box", "padding-box"]
|
75
|
+
|
76
|
+
assert_equal(2, original.origin.length)
|
77
|
+
assert_equal("background-origin:border-box, padding-box;", original.to_s)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_breaks
|
81
|
+
broken = Stylish::Background.new :break => "bounding-box"
|
82
|
+
|
83
|
+
assert_equal("background-break:bounding-box;", broken.to_s)
|
84
|
+
end
|
85
|
+
|
53
86
|
def test_invalid_image_values
|
54
87
|
assert_nil(Stylish::Background.new(:image => []).image)
|
55
88
|
assert_nil(Stylish::Background.new(:image => {}).image)
|
data/test/color_test.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require './lib/stylish'
|
3
|
-
|
4
1
|
class ColorTest < Test::Unit::TestCase
|
5
2
|
|
6
3
|
def setup
|
7
|
-
@red = Stylish::Color.new(
|
8
|
-
@green = Stylish::Color.new(
|
4
|
+
@red = Stylish::Color.new("red")
|
5
|
+
@green = Stylish::Color.new("green")
|
9
6
|
@blue = Stylish::Color.new("#0000FF")
|
10
7
|
@white = Stylish::Color.new("#FFF")
|
11
8
|
@yellow = Stylish::Color.new([255, 255, 0])
|
@@ -68,8 +65,6 @@ class ColorTest < Test::Unit::TestCase
|
|
68
65
|
end
|
69
66
|
|
70
67
|
def test_case_insensitivity_of_keywords
|
71
|
-
assert_equal([0, 128, 0, nil], Stylish::Color.new(:Green).value)
|
72
|
-
assert_equal([0, 128, 0, nil], Stylish::Color.new(:GrEeN).value)
|
73
68
|
assert_equal([0, 128, 0, nil], Stylish::Color.new("Green").value)
|
74
69
|
assert_equal([0, 128, 0, nil], Stylish::Color.new("GrEeN").value)
|
75
70
|
end
|
@@ -117,7 +112,7 @@ class ColorTest < Test::Unit::TestCase
|
|
117
112
|
|
118
113
|
def test_keyword_to_string
|
119
114
|
assert_equal("green", @green.to_s)
|
120
|
-
assert_equal("yellow", Stylish::Color.new(
|
115
|
+
assert_equal("yellow", Stylish::Color.new("yellow").to_s)
|
121
116
|
end
|
122
117
|
|
123
118
|
def test_rgb_to_string
|
@@ -148,8 +143,8 @@ class ColorTest < Test::Unit::TestCase
|
|
148
143
|
end
|
149
144
|
|
150
145
|
def test_inherit_and_transparent_to_hex
|
151
|
-
assert_nil(Stylish::Color.new(
|
152
|
-
assert_nil(Stylish::Color.new(
|
146
|
+
assert_nil(Stylish::Color.new("inherit").to_hex)
|
147
|
+
assert_nil(Stylish::Color.new("transparent").to_hex)
|
153
148
|
end
|
154
149
|
|
155
150
|
def test_hex_to_hex
|
@@ -160,8 +155,8 @@ class ColorTest < Test::Unit::TestCase
|
|
160
155
|
end
|
161
156
|
|
162
157
|
def test_keywords_to_hex
|
163
|
-
assert_equal("#808080", Stylish::Color.new(
|
164
|
-
assert_equal("#800000", Stylish::Color.new(
|
158
|
+
assert_equal("#808080", Stylish::Color.new("gray").to_hex)
|
159
|
+
assert_equal("#800000", Stylish::Color.new("maroon").to_hex)
|
165
160
|
end
|
166
161
|
|
167
162
|
def test_rgb_to_hex
|
@@ -174,7 +169,7 @@ class ColorTest < Test::Unit::TestCase
|
|
174
169
|
assert_equal("#fff", Stylish::Color.new([255, 255, 255]).to_hex)
|
175
170
|
assert_equal("#fff", Stylish::Color.new("#ffffff").to_hex)
|
176
171
|
assert_equal("#fb0", Stylish::Color.new("#ffbb00").to_hex)
|
177
|
-
assert_equal("#0ff", Stylish::Color.new(
|
172
|
+
assert_equal("#0ff", Stylish::Color.new("aqua").to_hex)
|
178
173
|
end
|
179
174
|
|
180
175
|
def test_rgb_to_hsl
|
data/test/comment_test.rb
CHANGED
data/test/declaration_test.rb
CHANGED
data/test/declarations_test.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require './lib/stylish'
|
3
|
-
|
4
1
|
class DeclarationsTest < Test::Unit::TestCase
|
5
2
|
|
6
3
|
def setup
|
7
4
|
@ds = Stylish::Declarations.new
|
8
5
|
@ds << Stylish::Declaration.new("border-color", "red")
|
9
|
-
@ds << Stylish::Background.new(:color =>
|
6
|
+
@ds << Stylish::Background.new(:color => "blue", :image => "test.png")
|
10
7
|
end
|
11
8
|
|
12
9
|
def test_join
|
data/test/formattable_test.rb
CHANGED
data/test/generate_test.rb
CHANGED
data/test/image_test.rb
CHANGED
data/test/rule_test.rb
CHANGED
data/test/selector_test.rb
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require './lib/stylish'
|
3
|
-
|
4
1
|
class SelectorTest < Test::Unit::TestCase
|
5
2
|
|
6
3
|
def test_to_string
|
7
4
|
s = Stylish::Selector.new(".test")
|
8
5
|
assert_equal(".test", s.to_s)
|
9
6
|
|
10
|
-
s = Stylish::Selector.new(
|
7
|
+
s = Stylish::Selector.new("div")
|
11
8
|
assert_equal("div", s.to_s)
|
12
9
|
end
|
13
10
|
end
|
data/test/selectors_test.rb
CHANGED
data/test/stylesheet_test.rb
CHANGED
data/test/tree_test.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
class VariableTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def setup
|
4
|
+
@style = Stylish.generate do
|
5
|
+
div :font_weight => :weighty
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_variable_inclusion
|
10
|
+
assert_instance_of(Stylish::Generate::Variable,
|
11
|
+
@style.rules.first.declarations.first.value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_variable_serialisation
|
15
|
+
assert_equal("div {font-weight:bold;}",
|
16
|
+
@style.to_s({:weighty => "bold"}))
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_selector_variables
|
20
|
+
style = Stylish.generate do
|
21
|
+
rule :some_selector, :line_height => 1.5
|
22
|
+
end
|
23
|
+
|
24
|
+
assert_equal("body p {line-height:1.5;}",
|
25
|
+
style.to_s({:some_selector => "body p"}))
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_color_variables
|
29
|
+
style = Stylish.generate do
|
30
|
+
body :color => :bright_as_a_button
|
31
|
+
end
|
32
|
+
|
33
|
+
assert_equal("body {color:#57b5cc;}",
|
34
|
+
style.to_s({:bright_as_a_button => "57b5cc"}))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_background_variables
|
38
|
+
style = Stylish.generate do
|
39
|
+
body :background => {:color => :dark, :image => :buttonish}
|
40
|
+
end
|
41
|
+
|
42
|
+
assert_equal(
|
43
|
+
"body {background-color:#000; background-image:url('button.png');}",
|
44
|
+
style.to_s({:dark => "000", :buttonish => "button.png"}))
|
45
|
+
end
|
46
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ionfish-stylish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benedict Eastaugh
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-24 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -22,10 +22,12 @@ extensions: []
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- README.md
|
24
24
|
files:
|
25
|
+
- History.txt
|
25
26
|
- README.md
|
26
27
|
- Rakefile
|
27
28
|
- VERSION.yml
|
28
29
|
- lib/stylish.rb
|
30
|
+
- lib/stylish/background.rb
|
29
31
|
- lib/stylish/color.rb
|
30
32
|
- lib/stylish/core.rb
|
31
33
|
- lib/stylish/formattable.rb
|
@@ -46,6 +48,7 @@ files:
|
|
46
48
|
- test/selectors_test.rb
|
47
49
|
- test/stylesheet_test.rb
|
48
50
|
- test/tree_test.rb
|
51
|
+
- test/variable_test.rb
|
49
52
|
has_rdoc: true
|
50
53
|
homepage: http://github.com/ionfish/stylish
|
51
54
|
post_install_message:
|
@@ -86,3 +89,4 @@ test_files:
|
|
86
89
|
- test/selectors_test.rb
|
87
90
|
- test/stylesheet_test.rb
|
88
91
|
- test/tree_test.rb
|
92
|
+
- test/variable_test.rb
|