ionfish-stylish 0.1.4 → 0.1.5
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/History.txt +8 -0
- data/README.md +2 -7
- data/VERSION.yml +1 -1
- data/lib/stylish/color.rb +7 -6
- data/lib/stylish/core.rb +43 -26
- data/lib/stylish/{background.rb → extended.rb} +128 -75
- data/lib/stylish/formattable.rb +35 -44
- data/lib/stylish/generate.rb +44 -12
- data/lib/stylish/numeric.rb +94 -0
- data/lib/stylish/tree.rb +3 -4
- data/lib/stylish.rb +2 -4
- data/test/background_test.rb +16 -25
- data/test/formattable_test.rb +6 -25
- data/test/generate_test.rb +17 -0
- data/test/length_test.rb +20 -0
- data/test/position_test.rb +22 -0
- metadata +8 -5
- data/lib/stylish/image.rb +0 -32
- data/lib/stylish/stylesheet.rb +0 -25
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== Version 0.1.5 (2009-05-03)
|
2
|
+
|
3
|
+
Improved background support
|
4
|
+
* Length, Position and Percentage classes
|
5
|
+
* accept_format now a class method
|
6
|
+
* Improved API and internals for multiple background properties
|
7
|
+
|
8
|
+
|
1
9
|
=== Version 0.1.4 (2009-04-25)
|
2
10
|
|
3
11
|
Bug fixes
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ 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
|
26
|
+
A number of additional examples are available in the `example/` directory.
|
27
27
|
|
28
28
|
|
29
29
|
Compatibility
|
@@ -37,9 +37,6 @@ Future considerations
|
|
37
37
|
---------------------
|
38
38
|
|
39
39
|
* Add a Border class to complement Background.
|
40
|
-
* Add better support for CSS3 properties to Background.
|
41
|
-
* Fundamental objects like percentages need their own classes rather than
|
42
|
-
being dealt with in an ad-hoc manner by higher-level objects.
|
43
40
|
* Add a parser so CSS can be read as well as written.
|
44
41
|
|
45
42
|
|
@@ -59,9 +56,7 @@ Stylish treats CSS as object code--but it treats it nicely.
|
|
59
56
|
Licence
|
60
57
|
-------
|
61
58
|
|
62
|
-
Copyright (c) 2008-2009, Benedict Eastaugh
|
63
|
-
|
64
|
-
All rights reserved.
|
59
|
+
Copyright (c) 2008-2009, Benedict Eastaugh. All rights reserved.
|
65
60
|
|
66
61
|
Redistribution and use in source and binary forms, with or without
|
67
62
|
modification, are permitted provided that the following conditions are met:
|
data/VERSION.yml
CHANGED
data/lib/stylish/color.rb
CHANGED
@@ -22,14 +22,15 @@ module Stylish #:nodoc:
|
|
22
22
|
# RGB integer; a hexadecimal representation of an RGB color; a rgb()
|
23
23
|
# representation of an RGB color; and an rgba() representation of an RGBA
|
24
24
|
# color.
|
25
|
+
pct = Percentage::PCTSTR
|
25
26
|
OPACITY = /([0-1]|0\.\d+)/
|
26
27
|
RGB_INT = /(\d{1,2}|[1-2][0-5]{2})/
|
27
28
|
HSL_INT = /(\d{1,2}|[1-2]\d{2}|3([0-5]\d|60))/
|
28
29
|
HEX_COLOR = /^#?([\da-fA-F]{3}){1,2}$/
|
29
|
-
RGB_COLOR = /rgb\(\s*((#{RGB_INT}|#{
|
30
|
-
RGBA_COLOR = /rgba\(\s*((#{RGB_INT}|#{
|
31
|
-
HSL_COLOR = /hsl\(\s*((#{HSL_INT}|#{
|
32
|
-
HSLA_COLOR = /hsla\(\s*((#{HSL_INT}|#{
|
30
|
+
RGB_COLOR = /rgb\(\s*((#{RGB_INT}|#{pct}),\s*){2}(#{RGB_INT}|#{pct})\s*\)/
|
31
|
+
RGBA_COLOR = /rgba\(\s*((#{RGB_INT}|#{pct}),\s*){3}#{OPACITY}\s*\)/
|
32
|
+
HSL_COLOR = /hsl\(\s*((#{HSL_INT}|#{pct}),\s*){2}(#{HSL_INT}|#{pct})\s*\)/
|
33
|
+
HSLA_COLOR = /hsla\(\s*((#{HSL_INT}|#{pct}),\s*){3}(#{OPACITY})\s*\)/
|
33
34
|
|
34
35
|
# Colors can be of several types: keywords, hexadecimal strings, RGB and
|
35
36
|
# RGBA formats. The type of the color is set on initialisation, so that
|
@@ -253,7 +254,7 @@ module Stylish #:nodoc:
|
|
253
254
|
rgb << v
|
254
255
|
elsif v =~ /^#{RGB_INT}$/
|
255
256
|
rgb << v.to_i
|
256
|
-
elsif v
|
257
|
+
elsif Percentage.match? v
|
257
258
|
rgb << (v.chop.to_f * 256 / 100).round
|
258
259
|
end
|
259
260
|
|
@@ -503,7 +504,7 @@ module Stylish #:nodoc:
|
|
503
504
|
map do |value|
|
504
505
|
if value =~ /^#{RGB_INT}$/
|
505
506
|
value.to_i
|
506
|
-
elsif value
|
507
|
+
elsif Percentage.match? value
|
507
508
|
(value.chop.to_f * 255 / 100).round
|
508
509
|
else
|
509
510
|
value.to_f
|
data/lib/stylish/core.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
module Stylish
|
2
2
|
|
3
|
-
# Regular expressions matching a percentage, and matching only a percentage.
|
4
|
-
PCT = /-?(0\.)?\d+%/
|
5
|
-
PERCENTAGE = /^#{PCT}$/
|
6
|
-
|
7
3
|
# A list of all valid HTML5 elements. Used primarily in the stylesheet
|
8
4
|
# generation DSL as method names.
|
9
5
|
HTML_ELEMENTS = [:html, :head, :title, :base, :link, :meta, :style, :script,
|
@@ -21,6 +17,28 @@ module Stylish
|
|
21
17
|
:command, :bb, :menu, :legend, :div, :h1, :h2, :h3, :h4,
|
22
18
|
:h5, :h6]
|
23
19
|
|
20
|
+
class Stylesheet < Tree::SelectorScope
|
21
|
+
accept_format(/\s*/m, "\n")
|
22
|
+
|
23
|
+
# Stylesheets are pure aggregate objects; they can contain child nodes,
|
24
|
+
# but have no data of their own. Their initializer therefore accepts no
|
25
|
+
# arguments.
|
26
|
+
def initialize
|
27
|
+
@nodes = []
|
28
|
+
end
|
29
|
+
|
30
|
+
# Stylesheets are the roots of selector trees.
|
31
|
+
def root?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Recursively serialise the tree to a stylesheet.
|
36
|
+
def to_s(symbols = {})
|
37
|
+
return "" if @nodes.empty?
|
38
|
+
@nodes.map {|node| node.to_s(symbols) }.join(self.class.format)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
24
42
|
# Rule objects represent CSS rules, and serialise to them. They possess one
|
25
43
|
# or more selectors, and zero or more declarations. In addition to their
|
26
44
|
# importance as the major building-blocks of stylesheets, they act as the
|
@@ -45,6 +63,7 @@ module Stylish
|
|
45
63
|
include Formattable, Tree::Leaf
|
46
64
|
|
47
65
|
attr_reader :selectors, :declarations
|
66
|
+
accept_format(/^\s*%s\s*\{\s*%s\s*\}\s*$/m, "%s {%s}")
|
48
67
|
|
49
68
|
# Every Rule must have at least one selector, but may have any number of
|
50
69
|
# declarations. Empty rules are often used in stylesheets to indicate
|
@@ -61,8 +80,6 @@ module Stylish
|
|
61
80
|
# This makes Rule objects a very flexible foundation for the higher-level
|
62
81
|
# data structures and APIs in Stylish.
|
63
82
|
def initialize(selectors, declarations)
|
64
|
-
accept_format(/^\s*%s\s*\{\s*%s\s*\}\s*$/m, "%s {%s}")
|
65
|
-
|
66
83
|
@selectors = selectors.inject(Selectors.new) do |ss, s|
|
67
84
|
ss << s
|
68
85
|
end
|
@@ -74,7 +91,7 @@ module Stylish
|
|
74
91
|
|
75
92
|
# Serialise the rule to valid CSS code.
|
76
93
|
def to_s(symbols = {}, scope = "")
|
77
|
-
sprintf(
|
94
|
+
sprintf(self.class.format, selectors.join(symbols, scope),
|
78
95
|
@declarations.to_s(symbols))
|
79
96
|
end
|
80
97
|
end
|
@@ -201,20 +218,14 @@ module Stylish
|
|
201
218
|
class Selectors < Array
|
202
219
|
include Formattable
|
203
220
|
|
204
|
-
|
205
|
-
# is done in its initialiser, regardless of arguments, is to set the
|
206
|
-
# default serialisation format.
|
207
|
-
def initialize(*args)
|
208
|
-
accept_format(/^\s*,\s*$/m, ", ")
|
209
|
-
super
|
210
|
-
end
|
221
|
+
accept_format(/^\s*,\s*$/m, ", ")
|
211
222
|
|
212
223
|
# The join method overrides the superclass' method in order to always use a
|
213
224
|
# specific separator, and so that the scope that the selectors are being
|
214
225
|
# used in can be passed through when Rules etc. are serialised.
|
215
226
|
def join(symbols = {}, scope = "")
|
216
227
|
self.inject("") do |ss, s|
|
217
|
-
(ss.empty? ? "" : ss + self.format) + s.to_s(symbols, scope)
|
228
|
+
(ss.empty? ? "" : ss + self.class.format) + s.to_s(symbols, scope)
|
218
229
|
end
|
219
230
|
end
|
220
231
|
|
@@ -232,10 +243,10 @@ module Stylish
|
|
232
243
|
include Formattable
|
233
244
|
|
234
245
|
attr_accessor :value
|
246
|
+
accept_format(/^\s*%s\s*:\s*%s;\s*$/m, "%s:%s;")
|
235
247
|
|
236
248
|
# Each Declaration has a property name and a value.
|
237
249
|
def initialize(name, value)
|
238
|
-
accept_format(/^\s*%s\s*:\s*%s;\s*$/m, "%s:%s;")
|
239
250
|
self.value = value
|
240
251
|
self.name = name
|
241
252
|
end
|
@@ -270,7 +281,7 @@ module Stylish
|
|
270
281
|
value = @value.to_s
|
271
282
|
end
|
272
283
|
|
273
|
-
sprintf(
|
284
|
+
sprintf(self.class.format, @property_name.to_s, value)
|
274
285
|
end
|
275
286
|
end
|
276
287
|
|
@@ -280,18 +291,12 @@ module Stylish
|
|
280
291
|
class Declarations < Array
|
281
292
|
include Formattable
|
282
293
|
|
283
|
-
|
284
|
-
# characters, including newline. The default format string is a single
|
285
|
-
# space, which is probably the most common choice in hand-written CSS.
|
286
|
-
def initialize(*args)
|
287
|
-
accept_format(/^\s*$/m, " ")
|
288
|
-
super
|
289
|
-
end
|
294
|
+
accept_format(/^\s*$/m, " ")
|
290
295
|
|
291
296
|
# The format attribute is always used as the separator when joining the
|
292
297
|
# elements of a Declarations object.
|
293
298
|
def join
|
294
|
-
super(
|
299
|
+
super(self.class.format)
|
295
300
|
end
|
296
301
|
|
297
302
|
# Returns a string by converting each element to a string, separated by the
|
@@ -300,9 +305,21 @@ module Stylish
|
|
300
305
|
# CSS code.
|
301
306
|
def to_s(symbols = {})
|
302
307
|
self.inject("") do |a, o|
|
303
|
-
a << (a.empty? ? "" :
|
308
|
+
a << (a.empty? ? "" : self.class.format) << o.to_s(symbols)
|
304
309
|
end
|
305
310
|
end
|
306
311
|
end
|
307
312
|
|
313
|
+
# PropertyBundle objects are simple wrappers around property values with
|
314
|
+
# multiple values.
|
315
|
+
class PropertyBundle < Array
|
316
|
+
include Formattable
|
317
|
+
|
318
|
+
accept_format(/^\s*,\s*$/m, ", ")
|
319
|
+
|
320
|
+
def to_s
|
321
|
+
self.join(self.class.format)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
308
325
|
end
|
@@ -1,5 +1,34 @@
|
|
1
1
|
module Stylish
|
2
2
|
|
3
|
+
# Instances of the Image class are used to represent paths to images,
|
4
|
+
# generally background images.
|
5
|
+
class Image
|
6
|
+
include Formattable
|
7
|
+
|
8
|
+
attr_accessor :path
|
9
|
+
accept_format(/^url\(\s*('|")?%s\1\s*\)$/, "url('%s')")
|
10
|
+
|
11
|
+
# Image instances are serialised to URI values. The path to the image file
|
12
|
+
# can be surrounded by either single quotes, double quotes or neither;
|
13
|
+
# single quotes are the default in Stylish.
|
14
|
+
def initialize(path)
|
15
|
+
@path = path
|
16
|
+
end
|
17
|
+
|
18
|
+
# Serialising Image objects to a string produces the URI values seen in
|
19
|
+
# background-image declarations, e.g.
|
20
|
+
#
|
21
|
+
# image = Image.new("test.png")
|
22
|
+
# image.to_s # => "url('test.png')"
|
23
|
+
#
|
24
|
+
# background = Stylish::Background.new(:image => "test.png")
|
25
|
+
# background.to_s # => "background-image:url('test.png');"
|
26
|
+
#
|
27
|
+
def to_s
|
28
|
+
sprintf(self.class.format, path.to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
3
32
|
# The Background class is a specialised kind of Declaration, geared towards
|
4
33
|
# dealing with the oddities of the background family of declarations, which
|
5
34
|
# can exist in both long- and shorthand forms.
|
@@ -19,15 +48,6 @@ module Stylish
|
|
19
48
|
# weighting to only override specific parts of other rules' background
|
20
49
|
# declarations.
|
21
50
|
class Background < Declaration
|
22
|
-
attr_reader :color,
|
23
|
-
:image,
|
24
|
-
:repeat,
|
25
|
-
:position,
|
26
|
-
:attachment,
|
27
|
-
:origin,
|
28
|
-
:break,
|
29
|
-
:compressed
|
30
|
-
|
31
51
|
PROPERTIES = [
|
32
52
|
[:color, "background-color"],
|
33
53
|
[:image, "background-image"],
|
@@ -41,105 +61,134 @@ module Stylish
|
|
41
61
|
REPEAT_VALUES = ["repeat-x", "repeat-y", "repeat",
|
42
62
|
"space", "round", "no-repeat"]
|
43
63
|
ATTACHMENT_VALUES = ["scroll", "fixed", "local"]
|
44
|
-
HORIZONTAL_POSITIONS = ["left", "center", "right"]
|
45
|
-
VERTICAL_POSITIONS = ["top", "center", "bottom"]
|
46
64
|
ORIGIN_VALUES = ["border-box", "padding-box", "content-box"]
|
47
65
|
BREAK_VALUES = ["bounding-box", "each-box", "continuous"]
|
48
66
|
|
67
|
+
PROPERTIES.each do |name, value|
|
68
|
+
attr_reader name
|
69
|
+
end
|
70
|
+
|
49
71
|
# Create a new Background object with the specified properties.
|
50
72
|
def initialize(options)
|
51
|
-
accept_format(/^\s*%s\s*:\s*%s;\s*$/m, "%s:%s;")
|
52
73
|
self.value = options
|
53
74
|
end
|
54
75
|
|
55
76
|
# Input validation for colours is handled by the Color class, which will
|
56
77
|
# raise an ArgumentError if the argument is an invalid colour value.
|
78
|
+
#
|
79
|
+
# coloured = Background.new :color => "545454"
|
80
|
+
# coloured.to_s # => "background-color:#545454;"
|
81
|
+
#
|
57
82
|
def color=(val)
|
58
83
|
@color = Color.new(val)
|
59
84
|
end
|
60
85
|
|
61
|
-
# Set the background image
|
62
|
-
# background images, so this method attempts to provide a backwards-
|
63
|
-
# compatible solution.
|
86
|
+
# Set the background image.
|
64
87
|
#
|
65
88
|
# background = Background.new :image => "sky.png", :compressed => true
|
66
89
|
# background.to_s # => "background:url('sky.png');"
|
67
90
|
#
|
68
|
-
|
91
|
+
def image=(path)
|
92
|
+
@image = Image.new(path)
|
93
|
+
end
|
94
|
+
|
95
|
+
# As of CSS3, elements may have multiple background images.
|
96
|
+
#
|
97
|
+
# background.images = ["ball.png", "grass.png"]
|
69
98
|
# background.to_s # => "background:url('ball.png'), url('grass.png');"
|
70
99
|
#
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
if @image.length < 2
|
76
|
-
@image = @image.first
|
77
|
-
else
|
78
|
-
def @image.to_s
|
79
|
-
join(", ")
|
80
|
-
end
|
100
|
+
def images=(paths)
|
101
|
+
@image = paths.inject(PropertyBundle.new) do |is, i|
|
102
|
+
is << Image.new(i)
|
81
103
|
end
|
82
104
|
end
|
83
105
|
|
84
|
-
# Set the background repeat
|
85
|
-
#
|
86
|
-
#
|
106
|
+
# Set the background repeat.
|
107
|
+
#
|
108
|
+
# nonrepeating = Background.new :repeat => "no-repeat"
|
109
|
+
# nonrepeating.to_s # => "background-repeat:no-repeat;"
|
110
|
+
#
|
111
|
+
def repeat=(repeat)
|
112
|
+
@repeat = repeat if REPEAT_VALUES.include? repeat
|
113
|
+
end
|
114
|
+
|
115
|
+
# As of CSS3, the background-repeat property may have multiple values.
|
87
116
|
#
|
88
|
-
# repeating = Background.new :
|
117
|
+
# repeating = Background.new :repeats => ["repeat-x", "repeat-y"]
|
89
118
|
# repeating.to_s # => "background-repeat:repeat-x, repeat-y;"
|
90
119
|
#
|
91
|
-
def
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
if @repeat.length < 2
|
96
|
-
@repeat = @repeat.first
|
97
|
-
else
|
98
|
-
def @repeat.to_s
|
99
|
-
join(", ")
|
100
|
-
end
|
120
|
+
def repeats=(repeats)
|
121
|
+
@repeat = repeats.inject(PropertyBundle.new) do |rs, r|
|
122
|
+
rs << r if REPEAT_VALUES.include? r
|
123
|
+
rs
|
101
124
|
end
|
102
125
|
end
|
103
126
|
|
104
|
-
#
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
127
|
+
# Positions have an x and a y value, and are handled by a specialised
|
128
|
+
# Position class. They should be passed an array of two values, e.g.
|
129
|
+
#
|
130
|
+
# positioned = Background.new :position => ["100%", 0]
|
131
|
+
# positioned.to_s # => "background-position:100% 0;"
|
132
|
+
#
|
133
|
+
# See the documentation for the Position class for further details on
|
134
|
+
# permitted position types.
|
135
|
+
def position=(position)
|
136
|
+
@position = Position.new(position[0], position[1])
|
137
|
+
end
|
138
|
+
|
139
|
+
# As of CSS3, elements may have multiple background images, and
|
140
|
+
# consequently they will need to be separately positioned as well.
|
141
|
+
#
|
142
|
+
# p = Background.new :positions => [["left", "top"], ["right", "top"]]
|
143
|
+
# p.to_s # => "background-position:left top, right top;"
|
144
|
+
#
|
145
|
+
def positions=(positions)
|
146
|
+
@position = positions.inject(PropertyBundle.new) do |ps, p|
|
147
|
+
ps << Position.new(p[0], p[1])
|
109
148
|
end
|
110
149
|
end
|
111
150
|
|
112
151
|
# The background-attachment property takes a limited range of values, so
|
113
152
|
# only a value within that range will be accepted.
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
153
|
+
#
|
154
|
+
# attached = Background.new :attachment => "fixed"
|
155
|
+
# attached.to_s # => "background-attachment:fixed;"
|
156
|
+
#
|
157
|
+
def attachment=(attachment)
|
158
|
+
@attachment = attachment if ATTACHMENT_VALUES.include? attachment
|
159
|
+
end
|
160
|
+
|
161
|
+
# As of CSS3 elements may have multiple background-attachment values.
|
162
|
+
#
|
163
|
+
# atts = Background.new :attachments => ["fixed", "scroll"]
|
164
|
+
# atts.to_s # => "background-attachment:fixed, scroll;"
|
165
|
+
#
|
166
|
+
def attachments=(attachments)
|
167
|
+
@attachment = attachments.inject(PropertyBundle.new) do |as, a|
|
168
|
+
as << a if ATTACHMENT_VALUES.include? a
|
169
|
+
as
|
124
170
|
end
|
125
171
|
end
|
126
172
|
|
127
173
|
# The background-origin property specifies the background positioning area.
|
128
|
-
# It is a CSS3 property which takes multiple values.
|
129
174
|
#
|
130
|
-
# original = Background.new :origin =>
|
131
|
-
# original.to_s # => background-origin:
|
175
|
+
# original = Background.new :origin => "content-box"
|
176
|
+
# original.to_s # => background-origin:content-box;
|
132
177
|
#
|
133
|
-
def origin=(
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
178
|
+
def origin=(origin)
|
179
|
+
@origin = origin if ORIGIN_VALUES.include? origin
|
180
|
+
end
|
181
|
+
|
182
|
+
# The background-origin property is a CSS3 property and can take multiple
|
183
|
+
# values.
|
184
|
+
#
|
185
|
+
# origs = Background.new :origin => ["padding-box", "content-box"]
|
186
|
+
# origs.to_s # => background-origin:padding-box, content-box;
|
187
|
+
#
|
188
|
+
def origins=(origins)
|
189
|
+
@origin = origins.inject(PropertyBundle.new) do |os, o|
|
190
|
+
os << o if ORIGIN_VALUES.include? o
|
191
|
+
os
|
143
192
|
end
|
144
193
|
end
|
145
194
|
|
@@ -164,11 +213,11 @@ module Stylish
|
|
164
213
|
# background-repeat:no-repeat; background-position:0 0;
|
165
214
|
#
|
166
215
|
def compressed=(val)
|
167
|
-
@compressed = val == true
|
216
|
+
@compressed = val == true
|
168
217
|
end
|
169
218
|
|
170
|
-
# Override Declaration#name, since it's not compatible with the
|
171
|
-
#
|
219
|
+
# Override Declaration#name, since it's not compatible with the internals
|
220
|
+
# of this class.
|
172
221
|
def name
|
173
222
|
PROPERTIES.reject {|n, p| p.nil? }.map {|n, p|
|
174
223
|
value = self.send(n)
|
@@ -176,8 +225,8 @@ module Stylish
|
|
176
225
|
}.compact
|
177
226
|
end
|
178
227
|
|
179
|
-
# Override Declaration#name=, since it's not compatible with the
|
180
|
-
#
|
228
|
+
# Override Declaration#name=, since it's not compatible with the internals
|
229
|
+
# of this class.
|
181
230
|
def name=(val)
|
182
231
|
raise NoMethodError, "name= is not defined for Background."
|
183
232
|
end
|
@@ -199,8 +248,10 @@ module Stylish
|
|
199
248
|
raise ArgumentError, "Argument must be a hash of background properties"
|
200
249
|
end
|
201
250
|
|
202
|
-
PROPERTIES.each do |name,
|
251
|
+
PROPERTIES.each do |name, value|
|
252
|
+
plural = (name.to_s + "s").to_sym
|
203
253
|
self.send(:"#{name.to_s}=", options[name]) if options[name]
|
254
|
+
self.send(:"#{name.to_s}s=", options[plural]) if options[plural]
|
204
255
|
end
|
205
256
|
end
|
206
257
|
|
@@ -218,7 +269,9 @@ module Stylish
|
|
218
269
|
if @compressed
|
219
270
|
"background:#{self.value(true).map {|p, v| v }.compact.join(" ")};"
|
220
271
|
else
|
221
|
-
self.value(true).map {|p, v|
|
272
|
+
self.value(true).map {|p, v|
|
273
|
+
sprintf(self.class.format, p, v.to_s)
|
274
|
+
}.join(" ")
|
222
275
|
end
|
223
276
|
end
|
224
277
|
end
|
data/lib/stylish/formattable.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Stylish
|
2
2
|
|
3
3
|
# The Formattable mixin gives an API for changing the output format of any of
|
4
|
-
# Stylish's core
|
5
|
-
# provided
|
6
|
-
#
|
4
|
+
# Stylish's core classes, as long as the new output format matches the regex
|
5
|
+
# provided when the class was declared. This is because in order to generate
|
6
|
+
# valid CSS, strings must be joined in the correct way.
|
7
7
|
#
|
8
8
|
# For example, a rule's selectors must be comma-separated and its
|
9
9
|
# declarations must be wrapped in curly braces, while each declaration
|
@@ -11,56 +11,47 @@ module Stylish
|
|
11
11
|
# terminating with a semicolon.
|
12
12
|
#
|
13
13
|
# In order to employ the Formattable mixin, it must be included into a class
|
14
|
-
# and the
|
15
|
-
#
|
14
|
+
# and the accept_format method must be called with the allowed format (as a
|
15
|
+
# regular expression) and the default format (a string).
|
16
16
|
#
|
17
17
|
# class Stylesheet
|
18
18
|
# include Formattable
|
19
|
-
#
|
20
|
-
# def initialize
|
21
|
-
# accept_format(/\s*/m, "\n")
|
22
|
-
# end
|
19
|
+
# accept_format(/\s*/m, "\n")
|
23
20
|
# end
|
24
21
|
#
|
25
|
-
# If one then creates a new Stylesheet object, one can modify the way it's
|
26
|
-
# formatted when serialised to CSS code.
|
27
|
-
#
|
28
|
-
# stylesheet = Stylesheet.new
|
29
|
-
# stylesheet.format # => "\n"
|
30
|
-
# stylesheet.format = "\n\n"
|
31
|
-
# stylesheet.format # => "\n\n"
|
32
|
-
#
|
33
22
|
module Formattable
|
34
|
-
attr_reader :format
|
35
23
|
|
36
|
-
|
37
|
-
|
38
|
-
# object's initialize method.
|
39
|
-
def format=(format)
|
40
|
-
if format_validates?(format)
|
41
|
-
@format = format
|
42
|
-
else
|
43
|
-
raise ArgumentError, "Not an allowed format."
|
44
|
-
end
|
24
|
+
def self.included(base)
|
25
|
+
base.extend(FormattableMethods)
|
45
26
|
end
|
46
27
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
28
|
+
module FormattableMethods
|
29
|
+
attr_reader :format
|
30
|
+
|
31
|
+
def format=(format)
|
32
|
+
if format_validates?(format)
|
33
|
+
@format = format
|
34
|
+
else
|
35
|
+
raise ArgumentError, "Not an allowed format."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def accept_format(pattern, default)
|
40
|
+
@format_pattern = pattern if pattern.is_a? Regexp
|
41
|
+
self.format = default
|
42
|
+
end
|
43
|
+
|
44
|
+
def format_validates?(format_string)
|
45
|
+
format_string =~ @format_pattern
|
46
|
+
end
|
47
|
+
|
48
|
+
def inherited(subclass)
|
49
|
+
["format", "format_pattern"].each do |attribute|
|
50
|
+
instance_var = "@#{attribute}"
|
51
|
+
subclass.instance_variable_set(instance_var,
|
52
|
+
instance_variable_get(instance_var))
|
53
|
+
end
|
54
|
+
end
|
64
55
|
end
|
65
56
|
end
|
66
57
|
|
data/lib/stylish/generate.rb
CHANGED
@@ -55,13 +55,13 @@ module Stylish
|
|
55
55
|
key = key.to_s.sub("_", "-").to_sym
|
56
56
|
|
57
57
|
if key == :background
|
58
|
-
if
|
58
|
+
if includes_symbols? value
|
59
59
|
declaration = Variable.new(value, Background)
|
60
60
|
else
|
61
61
|
declaration = Background.new(value)
|
62
62
|
end
|
63
63
|
elsif key == :color
|
64
|
-
if
|
64
|
+
if includes_symbols? value
|
65
65
|
value = Variable.new(value, Color)
|
66
66
|
else
|
67
67
|
value = Color.new(value)
|
@@ -69,7 +69,7 @@ module Stylish
|
|
69
69
|
|
70
70
|
declaration = Declaration.new("color", value)
|
71
71
|
else
|
72
|
-
value = Variable.new(value) if
|
72
|
+
value = Variable.new(value) if includes_symbols? value
|
73
73
|
declaration = Declaration.new(key, value)
|
74
74
|
end
|
75
75
|
|
@@ -77,6 +77,18 @@ module Stylish
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
+
def self.includes_symbols?(value)
|
81
|
+
return true if value.is_a? Symbol
|
82
|
+
|
83
|
+
if value.is_a? Array
|
84
|
+
return value.any? {|v| includes_symbols?(v) }
|
85
|
+
elsif value.is_a? Hash
|
86
|
+
return value.values.any? {|v| includes_symbols?(v) }
|
87
|
+
end
|
88
|
+
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
80
92
|
# Variables are elements of a selector tree that haven't been assigned
|
81
93
|
# values yet. When a tree that includes Variable objects is serialised, it
|
82
94
|
# must be passed a symbol table so that the variables may be given values.
|
@@ -109,16 +121,36 @@ module Stylish
|
|
109
121
|
# the tree is traversed. Nodes must then serialise themselves, and if
|
110
122
|
# they contain Variables they must pass them the symbol table so that
|
111
123
|
# they can be resolved to a given value.
|
112
|
-
def to_s(
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
@constructor.new(
|
124
|
+
def to_s(symbol_table, scope = "")
|
125
|
+
evald = eval(nil, symbol_table)
|
126
|
+
|
127
|
+
unless @constructor.nil?
|
128
|
+
@constructor.new(evald).to_s(symbol_table, scope)
|
129
|
+
else
|
130
|
+
evald
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Recursively replace symbols with values. This allows for symbol lookup
|
135
|
+
# within more complex nested structures of arrays and hashes, created by
|
136
|
+
# e.g. background declarations.
|
137
|
+
def eval(name_or_hash, symbol_table)
|
138
|
+
replaceable = name_or_hash || @name
|
139
|
+
|
140
|
+
if replaceable.is_a? Symbol
|
141
|
+
symbol_table[replaceable]
|
142
|
+
elsif replaceable.is_a?(Hash) || replaceable.is_a?(Array)
|
143
|
+
replaceable.to_a.inject(replaceable.class.new) do |acc, el|
|
144
|
+
if acc.is_a? Hash
|
145
|
+
acc[el[0]] = eval(el[1], symbol_table)
|
146
|
+
else
|
147
|
+
acc << eval(el, symbol_table)
|
148
|
+
end
|
149
|
+
|
150
|
+
acc
|
151
|
+
end
|
117
152
|
else
|
118
|
-
|
119
|
-
a[e.first] = symbols[e.last]
|
120
|
-
a
|
121
|
-
}).to_s(symbols, scope)
|
153
|
+
replaceable
|
122
154
|
end
|
123
155
|
end
|
124
156
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Stylish
|
2
|
+
|
3
|
+
class Percentage
|
4
|
+
PCTSTR = /-?(0\.)?\d+%/
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
value = value[0..-2]
|
8
|
+
|
9
|
+
if value =~ /^\d+$/
|
10
|
+
@number = value.to_i
|
11
|
+
else
|
12
|
+
@number = value.to_f
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s(symbols = {}, scope = "")
|
17
|
+
@number.to_s + "%"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.match?(value)
|
21
|
+
value =~ /^#{PCTSTR}$/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Length
|
26
|
+
UNITS = [
|
27
|
+
# Relative length units
|
28
|
+
"em", "ex", "px",
|
29
|
+
# Absolute length units
|
30
|
+
"in", "cm", "mm", "pt", "pc"]
|
31
|
+
|
32
|
+
attr_reader :unit, :value
|
33
|
+
|
34
|
+
def initialize(value)
|
35
|
+
self.unit = value.match(/(#{UNITS * "|"})$/)[0]
|
36
|
+
self.value = value[0..-3]
|
37
|
+
end
|
38
|
+
|
39
|
+
def value=(value)
|
40
|
+
if value.is_a? Numeric
|
41
|
+
@value = value
|
42
|
+
elsif value =~ /^\d+$/
|
43
|
+
@value = value.to_i
|
44
|
+
elsif value =~ /^\d+\.\d+$/
|
45
|
+
@value = value.to_f
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def unit=(unit)
|
50
|
+
@unit = unit if UNITS.include? unit
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s(symbols = {}, scope = "")
|
54
|
+
self.value.to_s + self.unit
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Position
|
59
|
+
HORIZONTAL = ["left", "center", "right"]
|
60
|
+
VERTICAL = ["top", "center", "bottom"]
|
61
|
+
|
62
|
+
attr_reader :x, :y
|
63
|
+
|
64
|
+
def initialize(xpos, ypos)
|
65
|
+
self.x = xpos || "center"
|
66
|
+
self.y = ypos || "center"
|
67
|
+
end
|
68
|
+
|
69
|
+
def x=(xpos)
|
70
|
+
if HORIZONTAL.include?(xpos) || xpos.to_i == 0
|
71
|
+
@x = xpos
|
72
|
+
elsif Percentage.match? xpos
|
73
|
+
@x = Percentage.new(xpos)
|
74
|
+
else
|
75
|
+
@x = Length.new(xpos)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def y=(ypos)
|
80
|
+
if VERTICAL.include?(ypos) || ypos.to_i == 0
|
81
|
+
@y = ypos
|
82
|
+
elsif Percentage.match? ypos
|
83
|
+
@y = Percentage.new(ypos)
|
84
|
+
else
|
85
|
+
@y = Length.new(ypos)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_s(symbols = {}, scope = "")
|
90
|
+
@x.to_s + " " + @y.to_s
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
data/lib/stylish/tree.rb
CHANGED
@@ -41,14 +41,13 @@ module Stylish
|
|
41
41
|
include Formattable, Node
|
42
42
|
|
43
43
|
attr_reader :nodes
|
44
|
+
accept_format(/\s*/m, "\n")
|
44
45
|
|
45
46
|
def initialize(selector)
|
46
|
-
accept_format(/\s*/m, "\n")
|
47
|
-
|
48
47
|
@nodes = []
|
49
48
|
@scope = selector
|
50
49
|
end
|
51
|
-
|
50
|
+
|
52
51
|
# Return the child node at the given index.
|
53
52
|
def [](index)
|
54
53
|
@nodes[index]
|
@@ -89,7 +88,7 @@ module Stylish
|
|
89
88
|
|
90
89
|
@nodes.map {|node|
|
91
90
|
node.to_s(symbols, @scope.to_s(symbols, scope))
|
92
|
-
}.join(
|
91
|
+
}.join(self.class.format)
|
93
92
|
end
|
94
93
|
|
95
94
|
# Return the node's child nodes.
|
data/lib/stylish.rb
CHANGED
@@ -8,10 +8,8 @@ module Stylish
|
|
8
8
|
require STYLISH_PATH + 'formattable'
|
9
9
|
require STYLISH_PATH + 'tree'
|
10
10
|
require STYLISH_PATH + 'core'
|
11
|
-
require STYLISH_PATH + '
|
12
|
-
require STYLISH_PATH + '
|
13
|
-
require STYLISH_PATH + 'image'
|
14
|
-
require STYLISH_PATH + 'background'
|
11
|
+
require STYLISH_PATH + 'numeric'
|
12
|
+
require STYLISH_PATH + 'extended'
|
15
13
|
require STYLISH_PATH + 'color'
|
16
14
|
require STYLISH_PATH + 'generate'
|
17
15
|
end
|
data/test/background_test.rb
CHANGED
@@ -3,7 +3,7 @@ class BackgroundTest < Test::Unit::TestCase
|
|
3
3
|
def setup
|
4
4
|
@composite = Stylish::Background.new(:color => "#CCC",
|
5
5
|
:image => "images/test.png", :repeat => "no-repeat",
|
6
|
-
:position => "left", :attachment => "scroll")
|
6
|
+
:position => ["left", "top"], :attachment => "scroll")
|
7
7
|
end
|
8
8
|
|
9
9
|
def test_valid_background_colors
|
@@ -22,7 +22,7 @@ class BackgroundTest < Test::Unit::TestCase
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_multiple_background_images
|
25
|
-
bg = Stylish::Background.new :
|
25
|
+
bg = Stylish::Background.new :images =>
|
26
26
|
["flower.png", "ball.png", "grass.png"]
|
27
27
|
|
28
28
|
assert_equal(3, bg.image.length)
|
@@ -35,20 +35,27 @@ class BackgroundTest < Test::Unit::TestCase
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_multiple_background_repeats
|
38
|
-
bg = Stylish::Background.new :
|
38
|
+
bg = Stylish::Background.new :repeats => ["repeat-x", "repeat-y"]
|
39
39
|
|
40
40
|
assert_equal(2, bg.repeat.length)
|
41
41
|
assert_equal("background-repeat:repeat-x, repeat-y;", bg.to_s)
|
42
42
|
end
|
43
43
|
|
44
44
|
def test_valid_background_positions
|
45
|
-
assert_equal(
|
46
|
-
assert_equal("
|
47
|
-
assert_equal("center", @composite.position[1])
|
45
|
+
assert_equal("left", @composite.position.x)
|
46
|
+
assert_equal("top", @composite.position.y)
|
48
47
|
end
|
49
48
|
|
50
|
-
def
|
49
|
+
def test_position_serialisation
|
50
|
+
positioned = Stylish::Background.new({:position => ["100%", 0]})
|
51
|
+
assert_equal("background-position:100% 0;", positioned.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_compression
|
51
55
|
assert(Stylish::Background.new(:compressed => true))
|
56
|
+
assert_equal(false, Stylish::Background.new(:compressed => "true").compressed)
|
57
|
+
assert_equal(false, Stylish::Background.new(:compressed => "false").compressed)
|
58
|
+
assert_nil(Stylish::Background.new(:compressed => nil).compressed)
|
52
59
|
end
|
53
60
|
|
54
61
|
def test_valid_background_attachments
|
@@ -58,7 +65,7 @@ class BackgroundTest < Test::Unit::TestCase
|
|
58
65
|
end
|
59
66
|
|
60
67
|
def test_multiple_attachments
|
61
|
-
glued = Stylish::Background.new :
|
68
|
+
glued = Stylish::Background.new :attachments => ["local", "fixed"]
|
62
69
|
|
63
70
|
assert_equal(2, glued.attachment.length)
|
64
71
|
assert_equal("background-attachment:local, fixed;", glued.to_s)
|
@@ -71,7 +78,7 @@ class BackgroundTest < Test::Unit::TestCase
|
|
71
78
|
end
|
72
79
|
|
73
80
|
def test_origins
|
74
|
-
original = Stylish::Background.new :
|
81
|
+
original = Stylish::Background.new :origins => ["border-box", "padding-box"]
|
75
82
|
|
76
83
|
assert_equal(2, original.origin.length)
|
77
84
|
assert_equal("background-origin:border-box, padding-box;", original.to_s)
|
@@ -83,31 +90,15 @@ class BackgroundTest < Test::Unit::TestCase
|
|
83
90
|
assert_equal("background-break:bounding-box;", broken.to_s)
|
84
91
|
end
|
85
92
|
|
86
|
-
def test_invalid_image_values
|
87
|
-
assert_nil(Stylish::Background.new(:image => []).image)
|
88
|
-
assert_nil(Stylish::Background.new(:image => {}).image)
|
89
|
-
end
|
90
|
-
|
91
93
|
def test_invalid_background_repeats
|
92
94
|
assert_nil(Stylish::Background.new(:repeat => 'maxim-gun').repeat)
|
93
95
|
end
|
94
96
|
|
95
|
-
def test_invalid_background_positions
|
96
|
-
assert_nil(Stylish::Background.new(:position => "green ideas").position)
|
97
|
-
assert_nil(Stylish::Background.new(:position => "top").position)
|
98
|
-
end
|
99
|
-
|
100
97
|
def test_invalid_background_attachments
|
101
98
|
assert_nil(Stylish::Background.new(:attachment => "static").attachment)
|
102
99
|
assert_nil(Stylish::Background.new(:attachment => "unhooked").attachment)
|
103
100
|
end
|
104
101
|
|
105
|
-
def test_invalid_compression
|
106
|
-
assert_nil(Stylish::Background.new(:compressed => "true").compressed)
|
107
|
-
assert_nil(Stylish::Background.new(:compressed => "false").compressed)
|
108
|
-
assert_nil(Stylish::Background.new(:compressed => nil).compressed)
|
109
|
-
end
|
110
|
-
|
111
102
|
def test_declaration_property
|
112
103
|
assert_equal(["background-color", "background-repeat"],
|
113
104
|
Stylish::Background.new(:color => "red", :repeat => "no-repeat").name)
|
data/test/formattable_test.rb
CHANGED
@@ -1,40 +1,21 @@
|
|
1
1
|
class FormattableTest < Test::Unit::TestCase
|
2
2
|
|
3
|
-
def setup
|
4
|
-
@selectors = Stylish::Selectors.new
|
5
|
-
@declaration = Stylish::Declaration.new("background-color", "#000")
|
6
|
-
@background = Stylish::Background.new("color" => "red")
|
7
|
-
end
|
8
|
-
|
9
3
|
def test_reading_default_formats
|
10
|
-
assert_equal(", ",
|
11
|
-
assert_equal("%s:%s;",
|
12
|
-
assert_equal("%s:%s;",
|
4
|
+
assert_equal(", ", Stylish::Selectors.format)
|
5
|
+
assert_equal("%s:%s;", Stylish::Declaration.format)
|
6
|
+
assert_equal("%s:%s;", Stylish::Background.format)
|
13
7
|
end
|
14
8
|
|
15
9
|
def test_setting_allowed_formats
|
16
10
|
assert_nothing_raised do
|
17
|
-
|
11
|
+
Stylish::Selectors.format = ",\n"
|
12
|
+
Stylish::Selectors.format = ", "
|
18
13
|
end
|
19
14
|
end
|
20
15
|
|
21
16
|
def test_setting_disallowed_formats
|
22
17
|
assert_raise ArgumentError do
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class ConfusedAboutFormatting
|
28
|
-
include Stylish::Formattable
|
29
|
-
|
30
|
-
def initialize
|
31
|
-
accept_format(/^\s*$/, "///")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_class_definition_with_disallowed_format
|
36
|
-
assert_raise ArgumentError do
|
37
|
-
ConfusedAboutFormatting.new
|
18
|
+
Stylish::Selectors.format = "//"
|
38
19
|
end
|
39
20
|
end
|
40
21
|
end
|
data/test/generate_test.rb
CHANGED
@@ -77,4 +77,21 @@ class GenerateTest < Test::Unit::TestCase
|
|
77
77
|
assert_equal("A glorious comment!", style.comments[0].header)
|
78
78
|
assert_equal("An additional note.", style.comments[1].lines[0])
|
79
79
|
end
|
80
|
+
|
81
|
+
def test_complex_background
|
82
|
+
style = Stylish.generate do
|
83
|
+
div :background => {
|
84
|
+
:images => ["tl.png", "tr.png", "br.png", "bl.png"],
|
85
|
+
:positions => [
|
86
|
+
["left", "top"],
|
87
|
+
["right", "top"],
|
88
|
+
["right", "bottom"],
|
89
|
+
["left", :pos]]}
|
90
|
+
end
|
91
|
+
|
92
|
+
assert_equal("div {background-image:url('tl.png'), url('tr.png'), " +
|
93
|
+
"url('br.png'), url('bl.png'); " +
|
94
|
+
"background-position:left top, right top, right bottom, left bottom;}",
|
95
|
+
style.to_s({:pos => "bottom"}))
|
96
|
+
end
|
80
97
|
end
|
data/test/length_test.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
class LengthTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def test_different_units
|
4
|
+
assert_equal("px", Stylish::Length.new("10px").unit)
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_serialisation
|
8
|
+
length = Stylish::Length.new("5em")
|
9
|
+
assert_equal("5em", length.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_accessors
|
13
|
+
length = Stylish::Length.new("30mm")
|
14
|
+
length.unit = "px"
|
15
|
+
length.value = 50
|
16
|
+
|
17
|
+
assert_equal("px", length.unit)
|
18
|
+
assert_equal(50, length.value)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class PositionTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
def setup
|
4
|
+
@pos = Stylish::Position.new(0, 0)
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_percentage_positions
|
8
|
+
percentage = Stylish::Position.new("5%", "10%")
|
9
|
+
assert_equal("5%", percentage.x.to_s)
|
10
|
+
assert_equal("10%", percentage.y.to_s)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_keyword_positions
|
14
|
+
keyed = Stylish::Position.new("left", "top")
|
15
|
+
assert_equal("left", keyed.x)
|
16
|
+
assert_equal("top", keyed.y)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_serialisation
|
20
|
+
assert_equal("0 0", @pos.to_s)
|
21
|
+
end
|
22
|
+
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.5
|
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-
|
12
|
+
date: 2009-05-03 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -27,13 +27,12 @@ files:
|
|
27
27
|
- Rakefile
|
28
28
|
- VERSION.yml
|
29
29
|
- lib/stylish.rb
|
30
|
-
- lib/stylish/background.rb
|
31
30
|
- lib/stylish/color.rb
|
32
31
|
- lib/stylish/core.rb
|
32
|
+
- lib/stylish/extended.rb
|
33
33
|
- lib/stylish/formattable.rb
|
34
34
|
- lib/stylish/generate.rb
|
35
|
-
- lib/stylish/
|
36
|
-
- lib/stylish/stylesheet.rb
|
35
|
+
- lib/stylish/numeric.rb
|
37
36
|
- lib/stylish/tree.rb
|
38
37
|
- test/background_test.rb
|
39
38
|
- test/color_test.rb
|
@@ -43,6 +42,8 @@ files:
|
|
43
42
|
- test/formattable_test.rb
|
44
43
|
- test/generate_test.rb
|
45
44
|
- test/image_test.rb
|
45
|
+
- test/length_test.rb
|
46
|
+
- test/position_test.rb
|
46
47
|
- test/rule_test.rb
|
47
48
|
- test/selector_test.rb
|
48
49
|
- test/selectors_test.rb
|
@@ -84,6 +85,8 @@ test_files:
|
|
84
85
|
- test/formattable_test.rb
|
85
86
|
- test/generate_test.rb
|
86
87
|
- test/image_test.rb
|
88
|
+
- test/length_test.rb
|
89
|
+
- test/position_test.rb
|
87
90
|
- test/rule_test.rb
|
88
91
|
- test/selector_test.rb
|
89
92
|
- test/selectors_test.rb
|
data/lib/stylish/image.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
module Stylish
|
2
|
-
|
3
|
-
# Instances of the Image class are used to represent paths to images,
|
4
|
-
# generally background images.
|
5
|
-
class Image
|
6
|
-
include Formattable
|
7
|
-
|
8
|
-
attr_accessor :path
|
9
|
-
|
10
|
-
# Image instances are serialised to URI values. The path to the image file
|
11
|
-
# can be surrounded by either single quotes, double quotes or neither;
|
12
|
-
# single quotes are the default in Stylish.
|
13
|
-
def initialize(path)
|
14
|
-
accept_format(/^url\(\s*('|")?%s\1\s*\)$/, "url('%s')")
|
15
|
-
@path = path
|
16
|
-
end
|
17
|
-
|
18
|
-
# Serialising Image objects to a string produces the URI values seen in
|
19
|
-
# background-image declarations, e.g.
|
20
|
-
#
|
21
|
-
# image = Image.new("test.png")
|
22
|
-
# image.to_s # => "url('test.png')"
|
23
|
-
#
|
24
|
-
# background = Stylish::Background.new(:image => "test.png")
|
25
|
-
# background.to_s # => "background-image:url('test.png');"
|
26
|
-
#
|
27
|
-
def to_s
|
28
|
-
sprintf(@format, path.to_s)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
data/lib/stylish/stylesheet.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Stylish
|
2
|
-
|
3
|
-
class Stylesheet < Tree::SelectorScope
|
4
|
-
|
5
|
-
# Stylesheets are pure aggregate objects; they can contain child nodes,
|
6
|
-
# but have no data of their own. Their initializer therefore accepts no
|
7
|
-
# arguments.
|
8
|
-
def initialize
|
9
|
-
accept_format(/\s*/m, "\n")
|
10
|
-
@nodes = []
|
11
|
-
end
|
12
|
-
|
13
|
-
# Stylesheets are the roots of selector trees.
|
14
|
-
def root?
|
15
|
-
true
|
16
|
-
end
|
17
|
-
|
18
|
-
# Recursively serialise the tree to a stylesheet.
|
19
|
-
def to_s(symbols = {})
|
20
|
-
return "" if @nodes.empty?
|
21
|
-
@nodes.map {|node| node.to_s(symbols) }.join(@format)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|