cloudhead-less 1.0.10 → 1.0.13
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/VERSION +1 -1
- data/less.gemspec +40 -30
- data/lib/less/engine/less.tt +29 -27
- data/lib/less/engine/nodes/element.rb +47 -11
- data/lib/less/engine/nodes/property.rb +26 -6
- data/lib/less/engine/nodes/ruleset.rb +12 -0
- data/lib/less/engine/nodes.rb +1 -0
- data/lib/less/engine/parser.rb +166 -132
- data/lib/less/engine.rb +2 -2
- data/spec/css/{accessors-1.0.css → accessors.css} +0 -0
- data/spec/css/{big-1.0.css → big.css} +0 -0
- data/spec/css/{colors-1.0.css → colors.css} +0 -0
- data/spec/css/{comments-1.0.css → comments.css} +0 -0
- data/spec/css/css-3.css +2 -0
- data/spec/css/{css-1.0.css → css.css} +1 -0
- data/spec/css/{functions-1.0.css → functions.css} +0 -0
- data/spec/css/{import-1.0.css → import.css} +1 -0
- data/spec/css/lazy-eval.css +1 -0
- data/spec/css/mixins-args.css +0 -0
- data/spec/css/{mixins-1.0.css → mixins.css} +0 -0
- data/spec/css/{operations-1.0.css → operations.css} +0 -0
- data/spec/css/{rulesets-1.0.css → rulesets.css} +0 -0
- data/spec/css/{scope-1.0.css → scope.css} +1 -4
- data/spec/css/selectors.css +8 -0
- data/spec/css/{strings-1.0.css → strings.css} +0 -0
- data/spec/css/{variables-1.0.css → variables.css} +0 -0
- data/spec/css/{whitespace-1.0.css → whitespace.css} +1 -4
- data/spec/engine_spec.rb +15 -3
- data/spec/less/{accessors-1.0.less → accessors.less} +0 -0
- data/spec/less/{big-1.0.less → big.less} +0 -0
- data/spec/less/{colors-1.0.less → colors.less} +0 -0
- data/spec/less/{comments-1.0.less → comments.less} +0 -0
- data/spec/less/css-3.less +11 -0
- data/spec/less/{css-1.0.less → css.less} +1 -0
- data/spec/less/{functions-1.0.less → functions.less} +0 -0
- data/spec/less/import/import-test-c.less +1 -0
- data/spec/less/import/import-test-d.css +1 -0
- data/spec/less/{import-1.0.less → import.less} +0 -0
- data/spec/less/lazy-eval.less +6 -0
- data/spec/less/mixins-args.less +0 -0
- data/spec/less/{mixins-1.0.less → mixins.less} +0 -0
- data/spec/less/{operations-1.0.less → operations.less} +0 -0
- data/spec/less/{rulesets-1.0.less → rulesets.less} +0 -0
- data/spec/less/{scope-1.0.less → scope.less} +1 -2
- data/spec/less/selectors.less +15 -0
- data/spec/less/{strings-1.0.less → strings.less} +0 -0
- data/spec/less/{variables-1.0.less → variables.less} +0 -0
- data/spec/less/{whitespace-1.0.less → whitespace.less} +0 -0
- data/spec/spec.css +1 -3
- metadata +40 -30
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.13
|
data/less.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{less}
|
5
|
-
s.version = "1.0.
|
5
|
+
s.version = "1.0.13"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["cloudhead"]
|
9
|
-
s.date = %q{2009-07-
|
9
|
+
s.date = %q{2009-07-20}
|
10
10
|
s.default_executable = %q{lessc}
|
11
11
|
s.description = %q{LESS is leaner CSS}
|
12
12
|
s.email = %q{self@cloudhead.net}
|
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
|
|
34
34
|
"lib/less/engine/nodes/function.rb",
|
35
35
|
"lib/less/engine/nodes/literal.rb",
|
36
36
|
"lib/less/engine/nodes/property.rb",
|
37
|
+
"lib/less/engine/nodes/ruleset.rb",
|
37
38
|
"lib/less/engine/nodes/selector.rb",
|
38
39
|
"lib/less/engine/parser.rb",
|
39
40
|
"lib/vendor/treetop/.gitignore",
|
@@ -127,41 +128,50 @@ Gem::Specification.new do |s|
|
|
127
128
|
"lib/vendor/treetop/spec/spec_suite.rb",
|
128
129
|
"lib/vendor/treetop/treetop.gemspec",
|
129
130
|
"spec/command_spec.rb",
|
130
|
-
"spec/css/accessors
|
131
|
-
"spec/css/big
|
132
|
-
"spec/css/colors
|
133
|
-
"spec/css/comments
|
134
|
-
"spec/css/css-
|
135
|
-
"spec/css/
|
136
|
-
"spec/css/
|
137
|
-
"spec/css/
|
138
|
-
"spec/css/
|
139
|
-
"spec/css/
|
140
|
-
"spec/css/
|
141
|
-
"spec/css/
|
142
|
-
"spec/css/
|
143
|
-
"spec/css/
|
131
|
+
"spec/css/accessors.css",
|
132
|
+
"spec/css/big.css",
|
133
|
+
"spec/css/colors.css",
|
134
|
+
"spec/css/comments.css",
|
135
|
+
"spec/css/css-3.css",
|
136
|
+
"spec/css/css.css",
|
137
|
+
"spec/css/functions.css",
|
138
|
+
"spec/css/import.css",
|
139
|
+
"spec/css/lazy-eval.css",
|
140
|
+
"spec/css/mixins-args.css",
|
141
|
+
"spec/css/mixins.css",
|
142
|
+
"spec/css/operations.css",
|
143
|
+
"spec/css/rulesets.css",
|
144
|
+
"spec/css/scope.css",
|
145
|
+
"spec/css/selectors.css",
|
146
|
+
"spec/css/strings.css",
|
147
|
+
"spec/css/variables.css",
|
148
|
+
"spec/css/whitespace.css",
|
144
149
|
"spec/engine_spec.rb",
|
145
|
-
"spec/less/accessors
|
146
|
-
"spec/less/big
|
147
|
-
"spec/less/colors
|
148
|
-
"spec/less/comments
|
149
|
-
"spec/less/css-
|
150
|
+
"spec/less/accessors.less",
|
151
|
+
"spec/less/big.less",
|
152
|
+
"spec/less/colors.less",
|
153
|
+
"spec/less/comments.less",
|
154
|
+
"spec/less/css-3.less",
|
155
|
+
"spec/less/css.less",
|
150
156
|
"spec/less/exceptions/mixed-units-error.less",
|
151
157
|
"spec/less/exceptions/name-error-1.0.less",
|
152
158
|
"spec/less/exceptions/syntax-error-1.0.less",
|
153
|
-
"spec/less/functions
|
154
|
-
"spec/less/import
|
159
|
+
"spec/less/functions.less",
|
160
|
+
"spec/less/import.less",
|
155
161
|
"spec/less/import/import-test-a.less",
|
156
162
|
"spec/less/import/import-test-b.less",
|
157
163
|
"spec/less/import/import-test-c.less",
|
158
|
-
"spec/less/
|
159
|
-
"spec/less/
|
160
|
-
"spec/less/
|
161
|
-
"spec/less/
|
162
|
-
"spec/less/
|
163
|
-
"spec/less/
|
164
|
-
"spec/less/
|
164
|
+
"spec/less/import/import-test-d.css",
|
165
|
+
"spec/less/lazy-eval.less",
|
166
|
+
"spec/less/mixins-args.less",
|
167
|
+
"spec/less/mixins.less",
|
168
|
+
"spec/less/operations.less",
|
169
|
+
"spec/less/rulesets.less",
|
170
|
+
"spec/less/scope.less",
|
171
|
+
"spec/less/selectors.less",
|
172
|
+
"spec/less/strings.less",
|
173
|
+
"spec/less/variables.less",
|
174
|
+
"spec/less/whitespace.less",
|
165
175
|
"spec/spec.css",
|
166
176
|
"spec/spec.less",
|
167
177
|
"spec/spec_helper.rb"
|
data/lib/less/engine/less.tt
CHANGED
@@ -14,13 +14,13 @@ grammar Less
|
|
14
14
|
selectors "{" ws primary ws "}" ws {
|
15
15
|
def build env
|
16
16
|
# Build the ruleset for each selector
|
17
|
-
selectors.build(env, :
|
17
|
+
selectors.build(env, :ruleset).each do |sel|
|
18
18
|
primary.build sel
|
19
19
|
end
|
20
20
|
end
|
21
21
|
} / ws selectors ';' ws {
|
22
22
|
def build env
|
23
|
-
selectors.build(env, :
|
23
|
+
selectors.build(env, :mixin).each do |path|
|
24
24
|
rules = path.inject(env.root) do |current, node|
|
25
25
|
current.descend(node.selector, node) or raise MixinNameError, path.join
|
26
26
|
end.rules
|
@@ -34,7 +34,7 @@ grammar Less
|
|
34
34
|
"@import" S url:(string / url) medias? s ';' ws {
|
35
35
|
def build env
|
36
36
|
path = File.join(env.root.file, url.value)
|
37
|
-
path += '.less' unless path =~ /\.
|
37
|
+
path += '.less' unless path =~ /\.(le|c)ss$/
|
38
38
|
if File.exist? path
|
39
39
|
imported = Less::Engine.new(File.new path).to_tree
|
40
40
|
env.rules += imported.rules
|
@@ -79,16 +79,16 @@ grammar Less
|
|
79
79
|
# div > p a {...}
|
80
80
|
#
|
81
81
|
rule selector
|
82
|
-
(s select element s)+ {
|
83
|
-
def
|
84
|
-
elements.inject(env) do |node, e|
|
82
|
+
sel:(s select element s)+ arguments? {
|
83
|
+
def ruleset env
|
84
|
+
sel.elements.inject(env) do |node, e|
|
85
85
|
node << Node::Element.new(e.element.text_value, e.select.text_value)
|
86
86
|
node.last
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
def
|
91
|
-
elements.map do |e|
|
90
|
+
def mixin env
|
91
|
+
sel.elements.map do |e|
|
92
92
|
Node::Element.new(e.element.text_value, e.select.text_value)
|
93
93
|
end
|
94
94
|
end
|
@@ -102,7 +102,7 @@ grammar Less
|
|
102
102
|
rule declaration
|
103
103
|
ws name:(ident / variable) s ':' s expression s (';'/ ws &'}') ws {
|
104
104
|
def build env
|
105
|
-
env << (name.text_value =~ /^@/ ? Node::Variable : Node::Property).new(name.text_value)
|
105
|
+
env << (name.text_value =~ /^@/ ? Node::Variable : Node::Property).new(name.text_value, [])
|
106
106
|
expression.build env
|
107
107
|
end
|
108
108
|
# Empty rule
|
@@ -156,7 +156,7 @@ grammar Less
|
|
156
156
|
rule variable
|
157
157
|
'@' [-a-zA-Z0-9_]+ {
|
158
158
|
def build env
|
159
|
-
env.identifiers.last <<
|
159
|
+
env.identifiers.last << Node::Variable.new(text_value)
|
160
160
|
end
|
161
161
|
}
|
162
162
|
end
|
@@ -248,7 +248,7 @@ grammar Less
|
|
248
248
|
# `blue`, `small`, `normal` etc.
|
249
249
|
#
|
250
250
|
rule keyword
|
251
|
-
[
|
251
|
+
[-a-zA-Z]+ !ns {
|
252
252
|
def build env
|
253
253
|
env.identifiers.last << Node::Keyword.new(text_value)
|
254
254
|
end
|
@@ -294,10 +294,9 @@ grammar Less
|
|
294
294
|
def build env
|
295
295
|
env.identifiers.last << Node::Color.new(*rgb.build)
|
296
296
|
end
|
297
|
-
} / fn:(('hsl'/'rgb') 'a'?)
|
297
|
+
} / fn:(('hsl'/'rgb') 'a'?) arguments {
|
298
298
|
def build env
|
299
|
-
|
300
|
-
env.identifiers.last << Node::Function.new(fn.text_value, args.flatten)
|
299
|
+
env.identifiers.last << Node::Function.new(fn.text_value, arguments.build.flatten)
|
301
300
|
end
|
302
301
|
}
|
303
302
|
end
|
@@ -325,43 +324,46 @@ grammar Less
|
|
325
324
|
# Functions and arguments
|
326
325
|
#
|
327
326
|
rule function
|
328
|
-
name:([-a-zA-Z_]+)
|
327
|
+
name:([-a-zA-Z_]+) arguments {
|
329
328
|
def build env
|
330
|
-
|
331
|
-
env.identifiers.last << Node::Function.new(name.text_value, [args].flatten)
|
329
|
+
env.identifiers.last << Node::Function.new(name.text_value, [arguments.build].flatten)
|
332
330
|
end
|
333
331
|
}
|
334
332
|
end
|
335
333
|
|
336
334
|
rule arguments
|
337
|
-
argument s ',' s
|
338
|
-
def build
|
339
|
-
|
340
|
-
e.build
|
335
|
+
'(' s argument s tail:(',' s argument s)* ')' {
|
336
|
+
def build
|
337
|
+
all.map do |e|
|
338
|
+
e.build if e.respond_to? :build
|
341
339
|
end.compact
|
342
340
|
end
|
343
|
-
|
341
|
+
|
342
|
+
def all
|
343
|
+
[argument] + tail.elements.map {|e| e.argument }
|
344
|
+
end
|
345
|
+
}
|
344
346
|
end
|
345
347
|
|
346
348
|
rule argument
|
347
349
|
color {
|
348
|
-
def build
|
350
|
+
def build
|
349
351
|
Node::Color.new text_value
|
350
352
|
end
|
351
353
|
} / number unit {
|
352
|
-
def build
|
354
|
+
def build
|
353
355
|
Node::Number.new number.text_value, unit.text_value
|
354
356
|
end
|
355
357
|
} / string {
|
356
|
-
def build
|
358
|
+
def build
|
357
359
|
Node::String.new text_value
|
358
360
|
end
|
359
361
|
} / [a-zA-Z]+ '=' dimension {
|
360
|
-
def build
|
362
|
+
def build
|
361
363
|
Node::Anonymous.new text_value
|
362
364
|
end
|
363
365
|
} / [-a-zA-Z0-9_%$/.&=:;#+?]+ {
|
364
|
-
def build
|
366
|
+
def build
|
365
367
|
Node::String.new text_value
|
366
368
|
end
|
367
369
|
}
|
@@ -12,12 +12,12 @@ module Less
|
|
12
12
|
include Enumerable
|
13
13
|
include Entity
|
14
14
|
|
15
|
-
attr_accessor :rules, :selector, :partial, :file
|
15
|
+
attr_accessor :rules, :selector, :partial, :file, :set
|
16
16
|
|
17
17
|
def initialize name = "", selector = ''
|
18
|
-
super name
|
19
|
-
|
20
|
-
@
|
18
|
+
super name
|
19
|
+
|
20
|
+
@set = []
|
21
21
|
@rules = [] # Holds all the nodes under this element's hierarchy
|
22
22
|
@selector = Selector[selector.strip].new # descendant | child | adjacent
|
23
23
|
end
|
@@ -32,7 +32,7 @@ module Less
|
|
32
32
|
|
33
33
|
# Top-most node?
|
34
34
|
def root?
|
35
|
-
|
35
|
+
parent.nil?
|
36
36
|
end
|
37
37
|
|
38
38
|
def empty?
|
@@ -42,6 +42,43 @@ module Less
|
|
42
42
|
def leaf?
|
43
43
|
elements.empty?
|
44
44
|
end
|
45
|
+
|
46
|
+
# Group similar rulesets together
|
47
|
+
# This is horrible, horrible code,
|
48
|
+
# but it'll have to do until I find
|
49
|
+
# a proper way to do it.
|
50
|
+
def group
|
51
|
+
matched = false
|
52
|
+
stack, result = elements.dup, []
|
53
|
+
return self unless elements.size > 1
|
54
|
+
|
55
|
+
elements.each do
|
56
|
+
e = stack.first
|
57
|
+
result << e unless matched
|
58
|
+
|
59
|
+
matched = stack[1..-1].each do |ee|
|
60
|
+
if e.rules.size == ee.rules.size and
|
61
|
+
e.elements.size == 0 and
|
62
|
+
!e.rules.zip(ee.rules).map {|a, b|
|
63
|
+
a.to_css == b.to_css
|
64
|
+
}.include?(false)
|
65
|
+
|
66
|
+
# Add to set unless it's a duplicate
|
67
|
+
if e == ee
|
68
|
+
# Do something with dups
|
69
|
+
else
|
70
|
+
self[e].set << ee
|
71
|
+
end
|
72
|
+
stack.shift
|
73
|
+
else
|
74
|
+
stack.shift
|
75
|
+
break false
|
76
|
+
end
|
77
|
+
end if stack.size > 1
|
78
|
+
end
|
79
|
+
@rules -= (elements - result)
|
80
|
+
self
|
81
|
+
end
|
45
82
|
|
46
83
|
#
|
47
84
|
# Accessors for the different nodes in @rules
|
@@ -84,7 +121,7 @@ module Less
|
|
84
121
|
|
85
122
|
def last; elements.last end
|
86
123
|
def first; elements.first end
|
87
|
-
def to_s; super end
|
124
|
+
def to_s; root?? '*' : super end
|
88
125
|
|
89
126
|
#
|
90
127
|
# Entry point for the css conversion
|
@@ -95,15 +132,15 @@ module Less
|
|
95
132
|
content = properties.map do |i|
|
96
133
|
' ' * 2 + i.to_css
|
97
134
|
end.compact.reject(&:empty?) * "\n"
|
98
|
-
|
135
|
+
|
99
136
|
content = content.include?("\n") ?
|
100
137
|
"\n#{content}\n" : " #{content.strip} "
|
101
138
|
ruleset = !content.strip.empty??
|
102
|
-
"#{path.reject(&:empty?).join.strip} {#{content}}\n" : ""
|
103
|
-
|
139
|
+
"#{[path.reject(&:empty?).join.strip, *@set] * ', '} {#{content}}\n" : ""
|
140
|
+
|
104
141
|
css = ruleset + elements.map do |i|
|
105
142
|
i.to_css(path)
|
106
|
-
end.reject(&:empty?).join
|
143
|
+
end.reject(&:empty?).join
|
107
144
|
path.pop; path.pop
|
108
145
|
css
|
109
146
|
end
|
@@ -132,7 +169,6 @@ module Less
|
|
132
169
|
end
|
133
170
|
self
|
134
171
|
end
|
135
|
-
alias :traverse :each
|
136
172
|
|
137
173
|
def inspect depth = 0
|
138
174
|
indent = lambda {|i| '. ' * i }
|
@@ -7,12 +7,13 @@ module Less
|
|
7
7
|
|
8
8
|
def initialize key, value = nil
|
9
9
|
super key
|
10
|
-
@value = Expression.new(value ? [value] : [])
|
10
|
+
@value = Expression.new(value ? [value].flatten : [])
|
11
11
|
@eval = false # Store the first evaluation in here
|
12
12
|
end
|
13
13
|
|
14
14
|
def << token
|
15
15
|
token = Node::Anonymous.new(*token) unless token.is_a? Entity or token.is_a? Operator
|
16
|
+
token.parent = self if token.respond_to? :parent
|
16
17
|
@value << token
|
17
18
|
end
|
18
19
|
|
@@ -27,9 +28,13 @@ module Less
|
|
27
28
|
super
|
28
29
|
end
|
29
30
|
|
31
|
+
def nearest node
|
32
|
+
parent.nearest node
|
33
|
+
end
|
34
|
+
|
30
35
|
# TODO: @eval and @value should be merged
|
31
36
|
def evaluate
|
32
|
-
@eval
|
37
|
+
@eval ||= value.evaluate
|
33
38
|
end
|
34
39
|
|
35
40
|
def to_css
|
@@ -37,8 +42,11 @@ module Less
|
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
40
|
-
class Variable < Property
|
41
|
-
|
45
|
+
class Variable < Property
|
46
|
+
attr_reader :declaration
|
47
|
+
|
48
|
+
def initialize key, value = nil
|
49
|
+
@declaration = value ? true : false
|
42
50
|
super key.delete('@'), value
|
43
51
|
end
|
44
52
|
|
@@ -50,16 +58,28 @@ module Less
|
|
50
58
|
"@#{super}"
|
51
59
|
end
|
52
60
|
|
61
|
+
def evaluate
|
62
|
+
if declaration
|
63
|
+
@eval ||= value.evaluate
|
64
|
+
else
|
65
|
+
@eval ||= self.parent.nearest(to_s).evaluate
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
53
69
|
def to_ruby
|
54
|
-
|
70
|
+
evaluate.to_ruby
|
55
71
|
end
|
56
72
|
|
57
73
|
def to_css
|
58
|
-
|
74
|
+
evaluate.to_css
|
59
75
|
end
|
60
76
|
end
|
61
77
|
|
62
78
|
class Expression < Array
|
79
|
+
def initialize ary
|
80
|
+
super [ary].flatten
|
81
|
+
end
|
82
|
+
|
63
83
|
def operators; select {|i| i.is_a? Operator } end
|
64
84
|
def entities; select {|i| i.kind_of? Entity } end
|
65
85
|
def literals; select {|i| i.kind_of? Literal } end
|
data/lib/less/engine/nodes.rb
CHANGED
data/lib/less/engine/parser.rb
CHANGED
@@ -339,7 +339,7 @@ module Less
|
|
339
339
|
module Ruleset1
|
340
340
|
def build env
|
341
341
|
# Build the ruleset for each selector
|
342
|
-
selectors.build(env, :
|
342
|
+
selectors.build(env, :ruleset).each do |sel|
|
343
343
|
primary.build sel
|
344
344
|
end
|
345
345
|
end
|
@@ -361,7 +361,7 @@ module Less
|
|
361
361
|
|
362
362
|
module Ruleset3
|
363
363
|
def build env
|
364
|
-
selectors.build(env, :
|
364
|
+
selectors.build(env, :mixin).each do |path|
|
365
365
|
rules = path.inject(env.root) do |current, node|
|
366
366
|
current.descend(node.selector, node) or raise MixinNameError, path.join
|
367
367
|
end.rules
|
@@ -492,7 +492,7 @@ module Less
|
|
492
492
|
module Import1
|
493
493
|
def build env
|
494
494
|
path = File.join(env.root.file, url.value)
|
495
|
-
path += '.less' unless path =~ /\.
|
495
|
+
path += '.less' unless path =~ /\.(le|c)ss$/
|
496
496
|
if File.exist? path
|
497
497
|
imported = Less::Engine.new(File.new path).to_tree
|
498
498
|
env.rules += imported.rules
|
@@ -925,15 +925,22 @@ module Less
|
|
925
925
|
end
|
926
926
|
|
927
927
|
module Selector1
|
928
|
-
def
|
929
|
-
elements
|
928
|
+
def sel
|
929
|
+
elements[0]
|
930
|
+
end
|
931
|
+
|
932
|
+
end
|
933
|
+
|
934
|
+
module Selector2
|
935
|
+
def ruleset env
|
936
|
+
sel.elements.inject(env) do |node, e|
|
930
937
|
node << Node::Element.new(e.element.text_value, e.select.text_value)
|
931
938
|
node.last
|
932
939
|
end
|
933
940
|
end
|
934
941
|
|
935
|
-
def
|
936
|
-
elements.map do |e|
|
942
|
+
def mixin env
|
943
|
+
sel.elements.map do |e|
|
937
944
|
Node::Element.new(e.element.text_value, e.select.text_value)
|
938
945
|
end
|
939
946
|
end
|
@@ -947,42 +954,60 @@ module Less
|
|
947
954
|
return cached
|
948
955
|
end
|
949
956
|
|
950
|
-
|
957
|
+
i0, s0 = index, []
|
958
|
+
s1, i1 = [], index
|
951
959
|
loop do
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
if
|
956
|
-
|
957
|
-
|
958
|
-
if
|
959
|
-
|
960
|
-
|
961
|
-
if
|
962
|
-
|
963
|
-
|
960
|
+
i2, s2 = index, []
|
961
|
+
r3 = _nt_s
|
962
|
+
s2 << r3
|
963
|
+
if r3
|
964
|
+
r4 = _nt_select
|
965
|
+
s2 << r4
|
966
|
+
if r4
|
967
|
+
r5 = _nt_element
|
968
|
+
s2 << r5
|
969
|
+
if r5
|
970
|
+
r6 = _nt_s
|
971
|
+
s2 << r6
|
964
972
|
end
|
965
973
|
end
|
966
974
|
end
|
967
|
-
if
|
968
|
-
|
969
|
-
|
975
|
+
if s2.last
|
976
|
+
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
|
977
|
+
r2.extend(Selector0)
|
970
978
|
else
|
971
|
-
@index =
|
972
|
-
|
979
|
+
@index = i2
|
980
|
+
r2 = nil
|
973
981
|
end
|
974
|
-
if
|
975
|
-
|
982
|
+
if r2
|
983
|
+
s1 << r2
|
976
984
|
else
|
977
985
|
break
|
978
986
|
end
|
979
987
|
end
|
980
|
-
if
|
981
|
-
@index =
|
982
|
-
|
988
|
+
if s1.empty?
|
989
|
+
@index = i1
|
990
|
+
r1 = nil
|
983
991
|
else
|
992
|
+
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
993
|
+
end
|
994
|
+
s0 << r1
|
995
|
+
if r1
|
996
|
+
r8 = _nt_arguments
|
997
|
+
if r8
|
998
|
+
r7 = r8
|
999
|
+
else
|
1000
|
+
r7 = instantiate_node(SyntaxNode,input, index...index)
|
1001
|
+
end
|
1002
|
+
s0 << r7
|
1003
|
+
end
|
1004
|
+
if s0.last
|
984
1005
|
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
985
1006
|
r0.extend(Selector1)
|
1007
|
+
r0.extend(Selector2)
|
1008
|
+
else
|
1009
|
+
@index = i0
|
1010
|
+
r0 = nil
|
986
1011
|
end
|
987
1012
|
|
988
1013
|
node_cache[:selector][start_index] = r0
|
@@ -1029,7 +1054,7 @@ module Less
|
|
1029
1054
|
|
1030
1055
|
module Declaration2
|
1031
1056
|
def build env
|
1032
|
-
env << (name.text_value =~ /^@/ ? Node::Variable : Node::Property).new(name.text_value)
|
1057
|
+
env << (name.text_value =~ /^@/ ? Node::Variable : Node::Property).new(name.text_value, [])
|
1033
1058
|
expression.build env
|
1034
1059
|
end
|
1035
1060
|
# Empty rule
|
@@ -1601,7 +1626,7 @@ module Less
|
|
1601
1626
|
|
1602
1627
|
module Variable1
|
1603
1628
|
def build env
|
1604
|
-
env.identifiers.last <<
|
1629
|
+
env.identifiers.last << Node::Variable.new(text_value)
|
1605
1630
|
end
|
1606
1631
|
end
|
1607
1632
|
|
@@ -3245,15 +3270,13 @@ module Less
|
|
3245
3270
|
end
|
3246
3271
|
|
3247
3272
|
def arguments
|
3248
|
-
elements[
|
3273
|
+
elements[1]
|
3249
3274
|
end
|
3250
|
-
|
3251
3275
|
end
|
3252
3276
|
|
3253
3277
|
module Color4
|
3254
3278
|
def build env
|
3255
|
-
|
3256
|
-
env.identifiers.last << Node::Function.new(fn.text_value, args.flatten)
|
3279
|
+
env.identifiers.last << Node::Function.new(fn.text_value, arguments.build.flatten)
|
3257
3280
|
end
|
3258
3281
|
end
|
3259
3282
|
|
@@ -3342,28 +3365,8 @@ module Less
|
|
3342
3365
|
end
|
3343
3366
|
s4 << r5
|
3344
3367
|
if r5
|
3345
|
-
|
3346
|
-
r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3347
|
-
@index += 1
|
3348
|
-
else
|
3349
|
-
terminal_parse_failure('(')
|
3350
|
-
r11 = nil
|
3351
|
-
end
|
3368
|
+
r11 = _nt_arguments
|
3352
3369
|
s4 << r11
|
3353
|
-
if r11
|
3354
|
-
r12 = _nt_arguments
|
3355
|
-
s4 << r12
|
3356
|
-
if r12
|
3357
|
-
if has_terminal?(')', false, index)
|
3358
|
-
r13 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3359
|
-
@index += 1
|
3360
|
-
else
|
3361
|
-
terminal_parse_failure(')')
|
3362
|
-
r13 = nil
|
3363
|
-
end
|
3364
|
-
s4 << r13
|
3365
|
-
end
|
3366
|
-
end
|
3367
3370
|
end
|
3368
3371
|
if s4.last
|
3369
3372
|
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
|
@@ -3584,15 +3587,13 @@ module Less
|
|
3584
3587
|
end
|
3585
3588
|
|
3586
3589
|
def arguments
|
3587
|
-
elements[
|
3590
|
+
elements[1]
|
3588
3591
|
end
|
3589
|
-
|
3590
3592
|
end
|
3591
3593
|
|
3592
3594
|
module Function1
|
3593
3595
|
def build env
|
3594
|
-
|
3595
|
-
env.identifiers.last << Node::Function.new(name.text_value, [args].flatten)
|
3596
|
+
env.identifiers.last << Node::Function.new(name.text_value, [arguments.build].flatten)
|
3596
3597
|
end
|
3597
3598
|
end
|
3598
3599
|
|
@@ -3627,28 +3628,8 @@ module Less
|
|
3627
3628
|
end
|
3628
3629
|
s0 << r1
|
3629
3630
|
if r1
|
3630
|
-
|
3631
|
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3632
|
-
@index += 1
|
3633
|
-
else
|
3634
|
-
terminal_parse_failure('(')
|
3635
|
-
r3 = nil
|
3636
|
-
end
|
3631
|
+
r3 = _nt_arguments
|
3637
3632
|
s0 << r3
|
3638
|
-
if r3
|
3639
|
-
r4 = _nt_arguments
|
3640
|
-
s0 << r4
|
3641
|
-
if r4
|
3642
|
-
if has_terminal?(')', false, index)
|
3643
|
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3644
|
-
@index += 1
|
3645
|
-
else
|
3646
|
-
terminal_parse_failure(')')
|
3647
|
-
r5 = nil
|
3648
|
-
end
|
3649
|
-
s0 << r5
|
3650
|
-
end
|
3651
|
-
end
|
3652
3633
|
end
|
3653
3634
|
if s0.last
|
3654
3635
|
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
@@ -3665,29 +3646,48 @@ module Less
|
|
3665
3646
|
end
|
3666
3647
|
|
3667
3648
|
module Arguments0
|
3649
|
+
def s
|
3650
|
+
elements[1]
|
3651
|
+
end
|
3652
|
+
|
3668
3653
|
def argument
|
3669
|
-
elements[
|
3654
|
+
elements[2]
|
3670
3655
|
end
|
3671
3656
|
|
3657
|
+
def s
|
3658
|
+
elements[3]
|
3659
|
+
end
|
3660
|
+
end
|
3661
|
+
|
3662
|
+
module Arguments1
|
3672
3663
|
def s
|
3673
3664
|
elements[1]
|
3674
3665
|
end
|
3675
3666
|
|
3667
|
+
def argument
|
3668
|
+
elements[2]
|
3669
|
+
end
|
3670
|
+
|
3676
3671
|
def s
|
3677
3672
|
elements[3]
|
3678
3673
|
end
|
3679
3674
|
|
3680
|
-
def
|
3675
|
+
def tail
|
3681
3676
|
elements[4]
|
3682
3677
|
end
|
3678
|
+
|
3683
3679
|
end
|
3684
3680
|
|
3685
|
-
module
|
3686
|
-
def build
|
3687
|
-
|
3688
|
-
e.build
|
3681
|
+
module Arguments2
|
3682
|
+
def build
|
3683
|
+
all.map do |e|
|
3684
|
+
e.build if e.respond_to? :build
|
3689
3685
|
end.compact
|
3690
3686
|
end
|
3687
|
+
|
3688
|
+
def all
|
3689
|
+
[argument] + tail.elements.map {|e| e.argument }
|
3690
|
+
end
|
3691
3691
|
end
|
3692
3692
|
|
3693
3693
|
def _nt_arguments
|
@@ -3698,51 +3698,85 @@ module Less
|
|
3698
3698
|
return cached
|
3699
3699
|
end
|
3700
3700
|
|
3701
|
-
i0 = index
|
3702
|
-
|
3703
|
-
|
3704
|
-
|
3705
|
-
if r2
|
3706
|
-
r3 = _nt_s
|
3707
|
-
s1 << r3
|
3708
|
-
if r3
|
3709
|
-
if has_terminal?(',', false, index)
|
3710
|
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3711
|
-
@index += 1
|
3712
|
-
else
|
3713
|
-
terminal_parse_failure(',')
|
3714
|
-
r4 = nil
|
3715
|
-
end
|
3716
|
-
s1 << r4
|
3717
|
-
if r4
|
3718
|
-
r5 = _nt_s
|
3719
|
-
s1 << r5
|
3720
|
-
if r5
|
3721
|
-
r6 = _nt_arguments
|
3722
|
-
s1 << r6
|
3723
|
-
end
|
3724
|
-
end
|
3725
|
-
end
|
3726
|
-
end
|
3727
|
-
if s1.last
|
3728
|
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
3729
|
-
r1.extend(Arguments0)
|
3730
|
-
r1.extend(Arguments1)
|
3701
|
+
i0, s0 = index, []
|
3702
|
+
if has_terminal?('(', false, index)
|
3703
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3704
|
+
@index += 1
|
3731
3705
|
else
|
3732
|
-
|
3706
|
+
terminal_parse_failure('(')
|
3733
3707
|
r1 = nil
|
3734
3708
|
end
|
3709
|
+
s0 << r1
|
3735
3710
|
if r1
|
3736
|
-
|
3737
|
-
|
3738
|
-
|
3739
|
-
|
3740
|
-
|
3741
|
-
|
3742
|
-
|
3743
|
-
|
3711
|
+
r2 = _nt_s
|
3712
|
+
s0 << r2
|
3713
|
+
if r2
|
3714
|
+
r3 = _nt_argument
|
3715
|
+
s0 << r3
|
3716
|
+
if r3
|
3717
|
+
r4 = _nt_s
|
3718
|
+
s0 << r4
|
3719
|
+
if r4
|
3720
|
+
s5, i5 = [], index
|
3721
|
+
loop do
|
3722
|
+
i6, s6 = index, []
|
3723
|
+
if has_terminal?(',', false, index)
|
3724
|
+
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3725
|
+
@index += 1
|
3726
|
+
else
|
3727
|
+
terminal_parse_failure(',')
|
3728
|
+
r7 = nil
|
3729
|
+
end
|
3730
|
+
s6 << r7
|
3731
|
+
if r7
|
3732
|
+
r8 = _nt_s
|
3733
|
+
s6 << r8
|
3734
|
+
if r8
|
3735
|
+
r9 = _nt_argument
|
3736
|
+
s6 << r9
|
3737
|
+
if r9
|
3738
|
+
r10 = _nt_s
|
3739
|
+
s6 << r10
|
3740
|
+
end
|
3741
|
+
end
|
3742
|
+
end
|
3743
|
+
if s6.last
|
3744
|
+
r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
|
3745
|
+
r6.extend(Arguments0)
|
3746
|
+
else
|
3747
|
+
@index = i6
|
3748
|
+
r6 = nil
|
3749
|
+
end
|
3750
|
+
if r6
|
3751
|
+
s5 << r6
|
3752
|
+
else
|
3753
|
+
break
|
3754
|
+
end
|
3755
|
+
end
|
3756
|
+
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
|
3757
|
+
s0 << r5
|
3758
|
+
if r5
|
3759
|
+
if has_terminal?(')', false, index)
|
3760
|
+
r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
3761
|
+
@index += 1
|
3762
|
+
else
|
3763
|
+
terminal_parse_failure(')')
|
3764
|
+
r11 = nil
|
3765
|
+
end
|
3766
|
+
s0 << r11
|
3767
|
+
end
|
3768
|
+
end
|
3769
|
+
end
|
3744
3770
|
end
|
3745
3771
|
end
|
3772
|
+
if s0.last
|
3773
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
3774
|
+
r0.extend(Arguments1)
|
3775
|
+
r0.extend(Arguments2)
|
3776
|
+
else
|
3777
|
+
@index = i0
|
3778
|
+
r0 = nil
|
3779
|
+
end
|
3746
3780
|
|
3747
3781
|
node_cache[:arguments][start_index] = r0
|
3748
3782
|
|
@@ -3750,7 +3784,7 @@ module Less
|
|
3750
3784
|
end
|
3751
3785
|
|
3752
3786
|
module Argument0
|
3753
|
-
def build
|
3787
|
+
def build
|
3754
3788
|
Node::Color.new text_value
|
3755
3789
|
end
|
3756
3790
|
end
|
@@ -3766,13 +3800,13 @@ module Less
|
|
3766
3800
|
end
|
3767
3801
|
|
3768
3802
|
module Argument2
|
3769
|
-
def build
|
3803
|
+
def build
|
3770
3804
|
Node::Number.new number.text_value, unit.text_value
|
3771
3805
|
end
|
3772
3806
|
end
|
3773
3807
|
|
3774
3808
|
module Argument3
|
3775
|
-
def build
|
3809
|
+
def build
|
3776
3810
|
Node::String.new text_value
|
3777
3811
|
end
|
3778
3812
|
end
|
@@ -3784,13 +3818,13 @@ module Less
|
|
3784
3818
|
end
|
3785
3819
|
|
3786
3820
|
module Argument5
|
3787
|
-
def build
|
3821
|
+
def build
|
3788
3822
|
Node::Anonymous.new text_value
|
3789
3823
|
end
|
3790
3824
|
end
|
3791
3825
|
|
3792
3826
|
module Argument6
|
3793
|
-
def build
|
3827
|
+
def build
|
3794
3828
|
Node::String.new text_value
|
3795
3829
|
end
|
3796
3830
|
end
|
data/lib/less/engine.rb
CHANGED
@@ -34,13 +34,13 @@ module Less
|
|
34
34
|
else
|
35
35
|
raise SyntaxError, @parser.failure_message
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
@tree
|
39
39
|
end
|
40
40
|
alias :to_tree :parse
|
41
41
|
|
42
42
|
def to_css
|
43
|
-
@css || @css = self.parse.to_css
|
43
|
+
@css || @css = self.parse.group.to_css
|
44
44
|
end
|
45
45
|
|
46
46
|
def prepare
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/css/css-3.css
ADDED
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
.lazy-eval { width: 100%; }
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,11 +1,8 @@
|
|
1
|
+
.whitespace, .white, .space, .mania, .no-semi-column { color: white; }
|
1
2
|
.whitespace { color: white; }
|
2
3
|
.whitespace { color: white; }
|
3
4
|
.whitespace { color: white; }
|
4
5
|
.whitespace { color: white; }
|
5
|
-
.whitespace { color: white; }
|
6
|
-
.white { color: white; }
|
7
|
-
.space { color: white; }
|
8
|
-
.mania { color: white; }
|
9
6
|
.no-semi-column { color: white; }
|
10
7
|
.no-semi-column {
|
11
8
|
color: white;
|
data/spec/engine_spec.rb
CHANGED
@@ -5,12 +5,12 @@ module LessEngineSpecHelper
|
|
5
5
|
if arg.is_a? String or arg.is_a? File
|
6
6
|
return Less::Engine.new(arg).to_css
|
7
7
|
else
|
8
|
-
lessify File.new("spec/less/#{arg}
|
8
|
+
lessify File.new("spec/less/#{arg.to_s.gsub('_', '-')}.less")
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def css file
|
13
|
-
File.read("spec/css/#{file}
|
13
|
+
File.read("spec/css/#{file.to_s.gsub('_', '-')}.css")
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -22,8 +22,12 @@ describe Less::Engine do
|
|
22
22
|
lessify(:css).should == css(:css)
|
23
23
|
end
|
24
24
|
|
25
|
+
it "should group selectors when it can" do
|
26
|
+
lessify(:selectors).should == css(:selectors)
|
27
|
+
end
|
28
|
+
|
25
29
|
it "should parse css 3" do
|
26
|
-
lessify(:
|
30
|
+
lessify(:css_3).should == css(:css_3)
|
27
31
|
end
|
28
32
|
|
29
33
|
it "should parse comments" do
|
@@ -65,6 +69,14 @@ describe Less::Engine do
|
|
65
69
|
it "should parse mixins" do
|
66
70
|
lessify(:mixins).should == css(:mixins)
|
67
71
|
end
|
72
|
+
|
73
|
+
it "should parse mixins with arguments" do
|
74
|
+
lessify(:mixins_args).should == css(:mixins_args)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should evaluate variables lazily" do
|
78
|
+
lessify(:lazy_eval).should == css(:lazy_eval)
|
79
|
+
end
|
68
80
|
|
69
81
|
it "should handle custom functions" do
|
70
82
|
module Less::Functions
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
#css { color: yellow; }
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/spec.css
CHANGED
@@ -40,9 +40,7 @@ body {
|
|
40
40
|
colorc: #777777;
|
41
41
|
}
|
42
42
|
#operations div { width: 80px; }
|
43
|
-
td { border-width: 88px; }
|
44
|
-
tr { border-width: 88px; }
|
45
|
-
table { border-width: 88px; }
|
43
|
+
td, tr, table { border-width: 88px; }
|
46
44
|
blockquote:before { content: ""; }
|
47
45
|
blockquote:after { content: ""; }
|
48
46
|
q:before { content: ""; }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudhead-less
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- cloudhead
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-07-
|
12
|
+
date: 2009-07-20 00:00:00 -07:00
|
13
13
|
default_executable: lessc
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -41,6 +41,7 @@ files:
|
|
41
41
|
- lib/less/engine/nodes/function.rb
|
42
42
|
- lib/less/engine/nodes/literal.rb
|
43
43
|
- lib/less/engine/nodes/property.rb
|
44
|
+
- lib/less/engine/nodes/ruleset.rb
|
44
45
|
- lib/less/engine/nodes/selector.rb
|
45
46
|
- lib/less/engine/parser.rb
|
46
47
|
- lib/vendor/treetop/.gitignore
|
@@ -134,41 +135,50 @@ files:
|
|
134
135
|
- lib/vendor/treetop/spec/spec_suite.rb
|
135
136
|
- lib/vendor/treetop/treetop.gemspec
|
136
137
|
- spec/command_spec.rb
|
137
|
-
- spec/css/accessors
|
138
|
-
- spec/css/big
|
139
|
-
- spec/css/colors
|
140
|
-
- spec/css/comments
|
141
|
-
- spec/css/css-
|
142
|
-
- spec/css/
|
143
|
-
- spec/css/
|
144
|
-
- spec/css/
|
145
|
-
- spec/css/
|
146
|
-
- spec/css/
|
147
|
-
- spec/css/
|
148
|
-
- spec/css/
|
149
|
-
- spec/css/
|
150
|
-
- spec/css/
|
138
|
+
- spec/css/accessors.css
|
139
|
+
- spec/css/big.css
|
140
|
+
- spec/css/colors.css
|
141
|
+
- spec/css/comments.css
|
142
|
+
- spec/css/css-3.css
|
143
|
+
- spec/css/css.css
|
144
|
+
- spec/css/functions.css
|
145
|
+
- spec/css/import.css
|
146
|
+
- spec/css/lazy-eval.css
|
147
|
+
- spec/css/mixins-args.css
|
148
|
+
- spec/css/mixins.css
|
149
|
+
- spec/css/operations.css
|
150
|
+
- spec/css/rulesets.css
|
151
|
+
- spec/css/scope.css
|
152
|
+
- spec/css/selectors.css
|
153
|
+
- spec/css/strings.css
|
154
|
+
- spec/css/variables.css
|
155
|
+
- spec/css/whitespace.css
|
151
156
|
- spec/engine_spec.rb
|
152
|
-
- spec/less/accessors
|
153
|
-
- spec/less/big
|
154
|
-
- spec/less/colors
|
155
|
-
- spec/less/comments
|
156
|
-
- spec/less/css-
|
157
|
+
- spec/less/accessors.less
|
158
|
+
- spec/less/big.less
|
159
|
+
- spec/less/colors.less
|
160
|
+
- spec/less/comments.less
|
161
|
+
- spec/less/css-3.less
|
162
|
+
- spec/less/css.less
|
157
163
|
- spec/less/exceptions/mixed-units-error.less
|
158
164
|
- spec/less/exceptions/name-error-1.0.less
|
159
165
|
- spec/less/exceptions/syntax-error-1.0.less
|
160
|
-
- spec/less/functions
|
161
|
-
- spec/less/import
|
166
|
+
- spec/less/functions.less
|
167
|
+
- spec/less/import.less
|
162
168
|
- spec/less/import/import-test-a.less
|
163
169
|
- spec/less/import/import-test-b.less
|
164
170
|
- spec/less/import/import-test-c.less
|
165
|
-
- spec/less/
|
166
|
-
- spec/less/
|
167
|
-
- spec/less/
|
168
|
-
- spec/less/
|
169
|
-
- spec/less/
|
170
|
-
- spec/less/
|
171
|
-
- spec/less/
|
171
|
+
- spec/less/import/import-test-d.css
|
172
|
+
- spec/less/lazy-eval.less
|
173
|
+
- spec/less/mixins-args.less
|
174
|
+
- spec/less/mixins.less
|
175
|
+
- spec/less/operations.less
|
176
|
+
- spec/less/rulesets.less
|
177
|
+
- spec/less/scope.less
|
178
|
+
- spec/less/selectors.less
|
179
|
+
- spec/less/strings.less
|
180
|
+
- spec/less/variables.less
|
181
|
+
- spec/less/whitespace.less
|
172
182
|
- spec/spec.css
|
173
183
|
- spec/spec.less
|
174
184
|
- spec/spec_helper.rb
|