lesslateral 1.2.21

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.
Files changed (84) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG +62 -0
  3. data/LICENSE +179 -0
  4. data/README.md +48 -0
  5. data/Rakefile +52 -0
  6. data/VERSION +1 -0
  7. data/bin/lessc +103 -0
  8. data/less.gemspec +134 -0
  9. data/lib/less.rb +36 -0
  10. data/lib/less/command.rb +108 -0
  11. data/lib/less/engine.rb +52 -0
  12. data/lib/less/engine/grammar/common.tt +29 -0
  13. data/lib/less/engine/grammar/entity.tt +144 -0
  14. data/lib/less/engine/grammar/less.tt +341 -0
  15. data/lib/less/engine/nodes.rb +9 -0
  16. data/lib/less/engine/nodes/element.rb +281 -0
  17. data/lib/less/engine/nodes/entity.rb +79 -0
  18. data/lib/less/engine/nodes/function.rb +93 -0
  19. data/lib/less/engine/nodes/literal.rb +171 -0
  20. data/lib/less/engine/nodes/property.rb +232 -0
  21. data/lib/less/engine/nodes/ruleset.rb +12 -0
  22. data/lib/less/engine/nodes/selector.rb +44 -0
  23. data/lib/less/ext.rb +60 -0
  24. data/lib/less/notification.rb +59 -0
  25. data/spec/command_spec.rb +102 -0
  26. data/spec/css/accessors.css +18 -0
  27. data/spec/css/big.css +3768 -0
  28. data/spec/css/colors.css +14 -0
  29. data/spec/css/comments.css +9 -0
  30. data/spec/css/css-3.css +21 -0
  31. data/spec/css/css.css +50 -0
  32. data/spec/css/dash-prefix.css +12 -0
  33. data/spec/css/functions.css +6 -0
  34. data/spec/css/import-with-extra-paths.css +8 -0
  35. data/spec/css/import-with-partial-in-extra-path.css +6 -0
  36. data/spec/css/import.css +12 -0
  37. data/spec/css/lazy-eval.css +1 -0
  38. data/spec/css/mixins-args.css +32 -0
  39. data/spec/css/mixins.css +28 -0
  40. data/spec/css/operations.css +28 -0
  41. data/spec/css/parens.css +20 -0
  42. data/spec/css/rulesets.css +17 -0
  43. data/spec/css/scope.css +11 -0
  44. data/spec/css/selectors.css +13 -0
  45. data/spec/css/strings.css +12 -0
  46. data/spec/css/variables.css +8 -0
  47. data/spec/css/whitespace.css +7 -0
  48. data/spec/engine_spec.rb +127 -0
  49. data/spec/less/accessors.less +20 -0
  50. data/spec/less/big.less +1264 -0
  51. data/spec/less/colors.less +35 -0
  52. data/spec/less/comments.less +46 -0
  53. data/spec/less/css-3.less +52 -0
  54. data/spec/less/css.less +104 -0
  55. data/spec/less/dash-prefix.less +21 -0
  56. data/spec/less/exceptions/mixed-units-error.less +3 -0
  57. data/spec/less/exceptions/name-error-1.0.less +3 -0
  58. data/spec/less/exceptions/syntax-error-1.0.less +3 -0
  59. data/spec/less/extra_import_path/extra.less +1 -0
  60. data/spec/less/extra_import_path/import/import-test-a.css +1 -0
  61. data/spec/less/extra_import_path/import/import-test-a.less +4 -0
  62. data/spec/less/functions.less +6 -0
  63. data/spec/less/hidden.less +25 -0
  64. data/spec/less/import-with-extra-paths.less +4 -0
  65. data/spec/less/import.less +8 -0
  66. data/spec/less/import/import-test-a.less +2 -0
  67. data/spec/less/import/import-test-b.less +8 -0
  68. data/spec/less/import/import-test-c.less +7 -0
  69. data/spec/less/import/import-test-d.css +1 -0
  70. data/spec/less/lazy-eval.less +6 -0
  71. data/spec/less/literal-css.less +11 -0
  72. data/spec/less/mixins-args.less +59 -0
  73. data/spec/less/mixins.less +43 -0
  74. data/spec/less/operations.less +39 -0
  75. data/spec/less/parens.less +26 -0
  76. data/spec/less/rulesets.less +30 -0
  77. data/spec/less/scope.less +32 -0
  78. data/spec/less/selectors.less +24 -0
  79. data/spec/less/strings.less +14 -0
  80. data/spec/less/variables.less +29 -0
  81. data/spec/less/whitespace.less +34 -0
  82. data/spec/spec.css +50 -0
  83. data/spec/spec_helper.rb +8 -0
  84. metadata +159 -0
@@ -0,0 +1,79 @@
1
+ module Less
2
+ #
3
+ # Node::Entity
4
+ #
5
+ # Everything in the tree is an Entity
6
+ #
7
+ # Mixin/Class hierarchy
8
+ #
9
+ # - Entity
10
+ # - Element
11
+ # - Entity
12
+ # - Function
13
+ # - Keyword
14
+ # - Literal
15
+ # - Color
16
+ # - Number
17
+ # - String
18
+ # - FontFamily
19
+ # - Property
20
+ # - Variable
21
+ #
22
+ # TODO: Use delegate class -> @rules
23
+ #
24
+ module Node
25
+ module Entity
26
+ attr_accessor :parent
27
+
28
+ def initialize value, parent = nil
29
+ super value
30
+ @parent = parent
31
+ end
32
+
33
+ #
34
+ # Returns the path from any given node, to the root
35
+ #
36
+ # ex: ['color', 'p', '#header', 'body', '*']
37
+ #
38
+ def path node = self
39
+ path = []
40
+ while node do
41
+ path << node
42
+ node = node.parent
43
+ end
44
+ path
45
+ end
46
+
47
+ def root
48
+ path.last
49
+ end
50
+
51
+ def inspect; to_s end
52
+ def to_css; to_s end
53
+ def to_s; super end
54
+ end
55
+
56
+ #
57
+ # An anonymous node, for all the 'other' stuff
58
+ # which doesn't need any specific functionality.
59
+ #
60
+ class Anonymous < String
61
+ include Entity
62
+ end
63
+
64
+ #
65
+ # + * - /
66
+ #
67
+ class Operator < String
68
+ def to_ruby
69
+ self
70
+ end
71
+ end
72
+
73
+ class Paren < String
74
+ def to_ruby
75
+ self
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,93 @@
1
+ module Less
2
+ #
3
+ # Functions useable from within the style-sheet go here
4
+ #
5
+ module Functions
6
+ def rgb *rgb
7
+ rgba rgb, 1.0
8
+ end
9
+
10
+ def hsl *args
11
+ hsla *[args, 1.0].flatten
12
+ end
13
+
14
+ #
15
+ # RGBA to Node::Color
16
+ #
17
+ def rgba *rgba
18
+ Node::Color.new *rgba.flatten
19
+ end
20
+
21
+ #
22
+ # HSLA to RGBA
23
+ #
24
+ def hsla h, s, l, a = 1.0
25
+ m2 = ( l <= 0.5 ) ? l * ( s + 1 ) : l + s - l * s
26
+ m1 = l * 2 - m2;
27
+
28
+ hue = lambda do |h|
29
+ h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h)
30
+ if h * 6 < 1 then m1 + (m2 - m1) * h * 6
31
+ elsif h * 2 < 1 then m2
32
+ elsif h * 3 < 2 then m1 + (m2 - m1) * (2/3 - h) * 6
33
+ else m1
34
+ end
35
+ end
36
+
37
+ rgba hue[ h + 1/3 ], hue[ h ], hue[ h - 1/3 ], a
38
+ end
39
+
40
+ def self.available
41
+ self.instance_methods.map(&:to_sym)
42
+ end
43
+ end
44
+
45
+ module Node
46
+ #
47
+ # A CSS function, like rgb() or url()
48
+ #
49
+ # it calls functions from the Functions module
50
+ #
51
+ class Function < String
52
+ include Entity
53
+ include Functions
54
+
55
+ def initialize name, args
56
+ @args = if args.is_a? Array
57
+ args.map {|e| e.is_a?(Expression) ? e : Expression.new(e, self)}
58
+ else
59
+ [args]
60
+ end
61
+
62
+ super name
63
+ end
64
+
65
+ def to_css env = nil
66
+ self.evaluate(env).to_css
67
+ end
68
+
69
+ def nearest node
70
+ parent.nearest node
71
+ end
72
+
73
+ #
74
+ # Call the function
75
+ #
76
+ # If the function isn't found, we just print it out,
77
+ # this is the case for url(), for example,
78
+ #
79
+ def evaluate context = nil
80
+ if Functions.available.include? self.to_sym
81
+ send to_sym, *@args
82
+ else
83
+ args = @args.map { |e|
84
+ e.parent = self.parent
85
+ e = e.evaluate(context) if e.respond_to?(:evaluate)
86
+ e.to_css
87
+ } * ', '
88
+ Node::Anonymous.new("#{to_sym}(#{args})")
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,171 @@
1
+ module Less
2
+ module Node
3
+ module Literal
4
+ include Entity
5
+
6
+ def unit
7
+ nil
8
+ end
9
+ end
10
+
11
+ #
12
+ # rgb(255, 0, 0) #f0f0f0
13
+ #
14
+ class Color
15
+ include Literal
16
+ attr_reader :r, :g, :b, :a
17
+
18
+ def initialize r, g, b, a = 1.0
19
+ @r, @g, @b = [r, g, b].map do |c|
20
+ normalize(c.is_a?(String) ? c.to_i(16) : c)
21
+ end
22
+ @a = normalize(a, 1.0)
23
+ end
24
+
25
+ def alpha v
26
+ self.class.new r, g, b, v
27
+ end
28
+
29
+ def rgb
30
+ [r, g, b]
31
+ end
32
+
33
+ def operate op, other
34
+ color = if other.is_a? Numeric
35
+ rgb.map {|c| c.send(op, other) }
36
+ else
37
+ rgb.zip(other.rgb).map {|a, b| a.send(op, b) }
38
+ end
39
+ self.class.new *[color, @a].flatten # Ruby 1.8 hack
40
+ end
41
+
42
+ def + other; operate :+, other end
43
+ def - other; operate :-, other end
44
+ def * other; operate :*, other end
45
+ def / other; operate :/, other end
46
+
47
+ def coerce other
48
+ return self, other
49
+ end
50
+
51
+ def to_s
52
+ if a < 1.0
53
+ "rgba(#{r.to_i}, #{g.to_i}, #{b.to_i}, #{a})"
54
+ else
55
+ "#%02x%02x%02x" % [r, g, b]
56
+ end
57
+ end
58
+
59
+ def inspect
60
+ if a < 1.0
61
+ "rgba(#{r}, #{g}, #{b}, #{a})"
62
+ else
63
+ "rgb(#{r}, #{g}, #{b})"
64
+ end
65
+ end
66
+
67
+ def to_css
68
+ to_s
69
+ end
70
+
71
+ def to_ruby
72
+ "#{self.class}.new(#{r},#{g},#{b},#{a})"
73
+ end
74
+
75
+ protected
76
+ def normalize(v, max = 255, min = 0)
77
+ [[min, v].max, max].min
78
+ end
79
+ end
80
+
81
+ #
82
+ # 6 10px 125%
83
+ #
84
+ class Number < DelegateClass(Float)
85
+ include Literal
86
+
87
+ attr_accessor :unit
88
+
89
+ def initialize value, unit = nil
90
+ super value.to_f
91
+ @unit = (unit.nil? || unit.empty?) ? nil : unit
92
+ end
93
+
94
+ def to_s
95
+ "#{super}#@unit"
96
+ end
97
+
98
+ def dup
99
+ self
100
+ end
101
+
102
+ def to_ruby
103
+ self.to_f
104
+ end
105
+
106
+ def inspect
107
+ to_s
108
+ end
109
+
110
+ def to_css
111
+ "#{(self % 1).zero?? "#{self.to_i}#@unit" : self}"
112
+ end
113
+ end
114
+
115
+ #
116
+ # "hello world"
117
+ #
118
+ class Quoted < String
119
+ include Literal
120
+
121
+ attr_reader :quotes, :content
122
+
123
+ # Strip quotes if necessary, and save them in @quotes
124
+ def initialize str
125
+ @quotes, @content = unless str.nil? or str.empty?
126
+ str.match(/('|")(.*?)(\1)/).captures rescue [nil, str]
127
+ else
128
+ [nil, ""]
129
+ end
130
+ super @content
131
+ end
132
+
133
+ def to_css
134
+ "#@quotes#{@content}#@quotes"
135
+ end
136
+ end
137
+
138
+ class Font
139
+ include Literal
140
+ end
141
+
142
+ class FontFamily
143
+ include Literal
144
+
145
+ def initialize family = []
146
+ @family = family
147
+ end
148
+
149
+ def to_css
150
+ @family.map(&:to_css) * ', '
151
+ end
152
+ end
153
+
154
+ #
155
+ # Any un-quoted word
156
+ #
157
+ # ex: red, small, border-collapse
158
+ #
159
+ class Keyword < String
160
+ include Entity
161
+
162
+ def to_css
163
+ self
164
+ end
165
+
166
+ def inspect
167
+ "#{self}"
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,232 @@
1
+ module Less
2
+ module Node
3
+ class Property < String
4
+ include Entity
5
+
6
+ attr_accessor :value
7
+
8
+ def initialize key, value = nil, parent = nil
9
+ super key, parent
10
+ value = if value.is_a? Array
11
+ value.each {|v| v.parent = self if v.respond_to? :parent }.
12
+ map {|v| v.is_a?(Expression) ? v : Expression.new(v, self) }
13
+ elsif value.nil?
14
+ []
15
+ else
16
+ value
17
+ end
18
+ @value = value.is_a?(Expression) ? value : Expression.new(value, self)
19
+ @value.parent = self
20
+ @value.delimiter = ','
21
+ # puts "new property #{to_s}: #{value} => #{@value}, contains: #{@value[0].class}"
22
+ # puts
23
+ end
24
+
25
+ def parent= obj
26
+ @parent = obj
27
+ value.parent = self
28
+ end
29
+
30
+ def copy
31
+ clone.tap {|c| c.value = value.copy }
32
+ end
33
+
34
+ def << token
35
+ token = Node::Anonymous.new(*token) unless token.is_a? Entity or token.respond_to? :to_ruby
36
+ token.parent = self if token.respond_to? :parent
37
+ @value << token
38
+ end
39
+
40
+ def empty?; !@value || @value.empty? end
41
+
42
+ def inspect
43
+ self + (empty?? "" : ": `#{value.map {|i| i.to_s } * ' | '}`")
44
+ end
45
+
46
+ def == other
47
+ self.to_s == other.to_s
48
+ end
49
+
50
+ def eql? other
51
+ self == other and value.eql? other.value
52
+ end
53
+
54
+ def to_s
55
+ super
56
+ end
57
+
58
+ def nearest node
59
+ parent.nearest node
60
+ end
61
+
62
+ def evaluate env = nil
63
+ # puts "evaluating property `#{to_s}`: #{value.inspect}"
64
+ if value.is_a?(Expression) #Value
65
+ # puts "value is a Value"
66
+ value.map {|e| e.evaluate(env) } #6
67
+ else
68
+ # puts "value is a #{value.class}"
69
+ [value.evaluate(env)]
70
+ end
71
+
72
+
73
+ end
74
+
75
+ def to_css env = nil
76
+ # puts "property.to_css `#{to_s}` env:#{env ? env.variables : "nil"}"
77
+ val = evaluate(env)
78
+ "#{self}: #{if val.respond_to? :to_css
79
+ val.to_css
80
+ else
81
+ # p val
82
+ # puts "#{val.class} #{val.first.class}"
83
+ val.map {|i| i.to_css }.join(", ")
84
+ end};"
85
+ end
86
+ end
87
+
88
+ class Variable < Property
89
+ attr_reader :declaration
90
+
91
+ def initialize key, value = nil, parent = nil
92
+ @declaration = value ? true : false
93
+ super key.delete('@'), value, parent
94
+ end
95
+
96
+ def inspect
97
+ "@#{super}"
98
+ end
99
+
100
+ def to_s
101
+ "@#{super}"
102
+ end
103
+
104
+ def evaluate env = nil
105
+ if declaration
106
+ # puts "evaluating DEC"
107
+ value.evaluate #2
108
+ else
109
+ # puts "evaluating #{to_s} par: #{parent} env: #{env ? env.variables : "nil"}"
110
+ begin
111
+ var = (env || self.parent).nearest(to_s) #3
112
+ rescue VariableNameError
113
+ var = self.parent.nearest(to_s)
114
+ end
115
+ var.evaluate
116
+ end
117
+ end
118
+
119
+ def to_ruby
120
+ evaluate.to_ruby
121
+ end
122
+
123
+ def to_css env = nil
124
+ val = evaluate env
125
+ if val.respond_to? :to_css
126
+ env ? val.to_css(env) : val.to_css
127
+ else
128
+ val.map {|i| env ? i.to_css(env) : i.to_css }.join ', '
129
+ end
130
+ end
131
+ end
132
+
133
+ class Expression < Array
134
+ attr_accessor :parent, :delimiter
135
+
136
+ def initialize ary, parent = nil, delimiter = ' '
137
+ self.parent = parent
138
+ self.delimiter = delimiter
139
+ # puts "new expression #{ary} |#{delimiter}|"
140
+ super(ary.is_a?(Array) ? ary : [ary].flatten)
141
+ end
142
+
143
+ def expressions; select {|i| i.kind_of? Expression } end
144
+ def variables; select {|i| i.kind_of? Variable } end
145
+ def operators; select {|i| i.is_a? Operator } end
146
+ def entities; select {|i| i.kind_of? Entity } end
147
+ def literals; select {|i| i.kind_of? Literal } end
148
+
149
+ def parent= obj
150
+ @parent = obj
151
+ each {|e| e.parent = obj if e.respond_to? :parent }
152
+ end
153
+
154
+ def inspect
155
+ '[' + map {|i| i.inspect }.join(', ') + ']'
156
+ end
157
+
158
+ def delimiter= d
159
+ @delimiter = d.strip + ' '
160
+ end
161
+
162
+ def flatten
163
+ self
164
+ end
165
+
166
+ def terminal?
167
+ expressions.empty? #&& variables.empty?
168
+ end
169
+
170
+ def to_css env = nil
171
+ # puts "TOCSS, delim: |#{@delimiter}|"
172
+ map do |i|
173
+ i.parent = self.parent
174
+ i.respond_to?(:to_css) ? i.to_css() : i.to_s
175
+ end * @delimiter
176
+ end
177
+
178
+ def to_ruby
179
+ map do |i|
180
+ i.respond_to?(:to_ruby) ? i.to_ruby : i.to_s
181
+ end
182
+ end
183
+
184
+ #
185
+ # Evaluates the expression and instantiates a new Literal with the result
186
+ # ex: [#111, +, #111] will evaluate to a Color node, with value #222
187
+ #
188
+ def evaluate env = nil
189
+ # puts "expression #{self.inspect} env: #{env ? env.variables : "nil"}"
190
+ if size > 2 or !terminal?
191
+ # puts " SIZE > 2 or !terminal"
192
+
193
+ # puts "--- sub evaluation ---"
194
+
195
+ # Replace self with an evaluated sub-expression
196
+ evaled = self.class.new(map {|e| e.respond_to?(:evaluate) ? e.evaluate(env) : e }, parent, delimiter) #5
197
+
198
+ # puts "======================"
199
+ # puts "evaled => #{evaled.inspect}"
200
+
201
+ unit = evaled.literals.map do |node|
202
+ node.unit
203
+ end.compact.uniq.tap do |ary|
204
+ raise MixedUnitsError, evaled * ' ' if ary.size > 1 && !evaled.operators.empty?
205
+ end.join
206
+
207
+ entity = evaled.literals.find {|e| e.unit == unit } || evaled.literals.first || evaled.entities.first
208
+ result = evaled.operators.empty?? evaled : eval(evaled.to_ruby.join)
209
+
210
+ # puts "entity is a #{entity.class}"
211
+ # puts "delimiter is |#{@delimiter}|"
212
+
213
+ case result
214
+ when Entity then result
215
+ when Expression then result.one?? result.first : self.class.new(result, parent, delimiter)
216
+ else entity.class.new(result, *(unit if entity.class == Node::Number))
217
+ end
218
+ elsif size == 1
219
+ if first.is_a? Variable
220
+ first.evaluate(env)
221
+ elsif first.is_a? Function
222
+ first.evaluate(env)
223
+ else
224
+ first
225
+ end
226
+ else
227
+ self
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end