unboxed-less 1.2.12

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 (75) 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 +60 -0
  6. data/VERSION +1 -0
  7. data/bin/lessc +92 -0
  8. data/lib/ext.rb +31 -0
  9. data/lib/less.rb +32 -0
  10. data/lib/less/command.rb +98 -0
  11. data/lib/less/engine.rb +55 -0
  12. data/lib/less/engine/grammar/common.tt +29 -0
  13. data/lib/less/engine/grammar/entity.tt +130 -0
  14. data/lib/less/engine/grammar/less.tt +326 -0
  15. data/lib/less/engine/nodes.rb +9 -0
  16. data/lib/less/engine/nodes/element.rb +278 -0
  17. data/lib/less/engine/nodes/entity.rb +79 -0
  18. data/lib/less/engine/nodes/function.rb +84 -0
  19. data/lib/less/engine/nodes/literal.rb +171 -0
  20. data/lib/less/engine/nodes/property.rb +231 -0
  21. data/lib/less/engine/nodes/ruleset.rb +12 -0
  22. data/lib/less/engine/nodes/selector.rb +44 -0
  23. data/spec/command_spec.rb +102 -0
  24. data/spec/css/accessors.css +18 -0
  25. data/spec/css/big.css +3768 -0
  26. data/spec/css/colors.css +14 -0
  27. data/spec/css/comments.css +9 -0
  28. data/spec/css/css-3.css +17 -0
  29. data/spec/css/css.css +50 -0
  30. data/spec/css/functions.css +6 -0
  31. data/spec/css/import.css +12 -0
  32. data/spec/css/lazy-eval.css +1 -0
  33. data/spec/css/mixins-args.css +32 -0
  34. data/spec/css/mixins.css +28 -0
  35. data/spec/css/operations.css +28 -0
  36. data/spec/css/parens.css +20 -0
  37. data/spec/css/rulesets.css +17 -0
  38. data/spec/css/scope.css +11 -0
  39. data/spec/css/selectors.css +13 -0
  40. data/spec/css/strings.css +12 -0
  41. data/spec/css/variables.css +7 -0
  42. data/spec/css/whitespace.css +7 -0
  43. data/spec/engine_spec.rb +112 -0
  44. data/spec/less/accessors.less +20 -0
  45. data/spec/less/big.less +4810 -0
  46. data/spec/less/colors.less +35 -0
  47. data/spec/less/comments.less +46 -0
  48. data/spec/less/css-3.less +45 -0
  49. data/spec/less/css.less +104 -0
  50. data/spec/less/exceptions/mixed-units-error.less +3 -0
  51. data/spec/less/exceptions/name-error-1.0.less +3 -0
  52. data/spec/less/exceptions/syntax-error-1.0.less +3 -0
  53. data/spec/less/functions.less +6 -0
  54. data/spec/less/hidden.less +25 -0
  55. data/spec/less/import.less +8 -0
  56. data/spec/less/import/import-test-a.less +2 -0
  57. data/spec/less/import/import-test-b.less +8 -0
  58. data/spec/less/import/import-test-c.less +7 -0
  59. data/spec/less/import/import-test-d.css +1 -0
  60. data/spec/less/lazy-eval.less +6 -0
  61. data/spec/less/literal-css.less +11 -0
  62. data/spec/less/mixins-args.less +59 -0
  63. data/spec/less/mixins.less +43 -0
  64. data/spec/less/operations.less +39 -0
  65. data/spec/less/parens.less +26 -0
  66. data/spec/less/rulesets.less +30 -0
  67. data/spec/less/scope.less +32 -0
  68. data/spec/less/selectors.less +24 -0
  69. data/spec/less/strings.less +14 -0
  70. data/spec/less/variables.less +24 -0
  71. data/spec/less/whitespace.less +34 -0
  72. data/spec/spec.css +50 -0
  73. data/spec/spec_helper.rb +8 -0
  74. data/unboxed-less.gemspec +121 -0
  75. metadata +140 -0
@@ -0,0 +1,9 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'engine/nodes/entity'
4
+ require 'engine/nodes/function'
5
+ require 'engine/nodes/ruleset'
6
+ require 'engine/nodes/element'
7
+ require 'engine/nodes/property'
8
+ require 'engine/nodes/literal'
9
+ require 'engine/nodes/selector'
@@ -0,0 +1,278 @@
1
+ module Less
2
+ module Node
3
+ #
4
+ # Element
5
+ #
6
+ # div {...}
7
+ #
8
+ # TODO: Look into making @rules its own hash-like class
9
+ # TODO: Look into whether selector should be child by default
10
+ #
11
+ class Element
12
+ include Enumerable
13
+ include Entity
14
+
15
+ attr_accessor :rules, :selector, :file,
16
+ :set, :imported, :name
17
+
18
+ def initialize name = "", selector = ''
19
+ @name = name
20
+ @set, @imported = [], []
21
+ @rules = [] # Holds all the nodes under this element's hierarchy
22
+ @selector = Selector[selector.strip].new # descendant | child | adjacent
23
+ end
24
+
25
+ def class?; name =~ /^\./ end
26
+ def id?; name =~ /^#/ end
27
+ def universal?; name == '*' end
28
+
29
+ def tag?
30
+ not id? || class? || universal?
31
+ end
32
+
33
+ # Top-most node?
34
+ def root?
35
+ parent.nil?
36
+ end
37
+
38
+ def empty?
39
+ @rules.empty?
40
+ end
41
+
42
+ def leaf?
43
+ elements.empty?
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.equiv? ee and e.elements.size == 0
61
+ self[e].set << ee
62
+ stack.shift
63
+ else
64
+ stack.shift
65
+ break false
66
+ end
67
+ end if stack.size > 1
68
+ end
69
+ @rules -= (elements - result)
70
+ self
71
+ end
72
+
73
+ #
74
+ # Accessors for the different nodes in @rules
75
+ #
76
+ def identifiers; @rules.select {|r| r.kind_of? Property } end
77
+ def properties; @rules.select {|r| r.instance_of? Property } end
78
+ def variables; @rules.select {|r| r.instance_of? Variable } end
79
+ def elements; @rules.select {|r| r.kind_of? Element } end
80
+ def mixins; @rules.select {|r| r.instance_of? Mixin::Call} end
81
+ def parameters; [] end
82
+
83
+ # Select a child element
84
+ # TODO: Implement full selector syntax & merge with descend()
85
+ def [] key
86
+ case key
87
+ when Entity
88
+ @rules.find {|i| i.eql? key }
89
+ when String
90
+ @rules.find {|i| i.to_s == key }
91
+ else raise ArgumentError
92
+ end
93
+ end
94
+
95
+ def == other
96
+ name == other.name
97
+ end
98
+
99
+ def eql? other
100
+ super and self.equiv? other
101
+ end
102
+
103
+ def equiv? other
104
+ rules.size == other.rules.size and
105
+ !rules.zip(other.rules).map do |a, b|
106
+ a.to_css == b.to_css
107
+ end.include?(false)
108
+ end
109
+
110
+ # Same as above, except with a specific selector
111
+ # TODO: clean this up or implement it differently
112
+ def descend selector, element
113
+ if selector.is_a? Child
114
+ s = self[element.name].selector
115
+ self[element.name] if s.is_a? Child or s.is_a? Descendant
116
+ elsif selector.is_a? Descendant
117
+ self[element.name]
118
+ else
119
+ self[element.name] if self[element.name].selector.class == selector.class
120
+ end
121
+ end
122
+
123
+ def mix arr = []
124
+ @rules += arr.map do |r|
125
+ n = r.copy
126
+ n.parent = self
127
+ n
128
+ end
129
+ end
130
+
131
+ #
132
+ # Add an arbitrary node to this element
133
+ #
134
+ def << obj
135
+ if obj.kind_of? Node::Entity
136
+ obj.parent = self
137
+ @rules << obj
138
+ else
139
+ raise ArgumentError, "argument can't be a #{obj.class}"
140
+ end
141
+ end
142
+
143
+ def last; elements.last end
144
+ def first; elements.first end
145
+ def to_s; root?? '*' : name end
146
+
147
+ #
148
+ # Entry point for the css conversion
149
+ #
150
+ def to_css path = [], env = nil
151
+ path << @selector.to_css << name unless root?
152
+
153
+ # puts "to_css env: #{env ? env.variables : "nil"}"
154
+
155
+ content = (properties + mixins).map do |i|
156
+ ' ' * 2 + i.to_css(env)
157
+ end.compact.reject(&:empty?) * "\n"
158
+
159
+ content = content.include?("\n") ? "\n#{content}\n" : " #{content.strip} "
160
+ ruleset = if is_a?(Mixin::Def)
161
+ content.strip
162
+ else
163
+ !content.strip.empty??
164
+ "#{[path.reject(&:empty?).join.strip,
165
+ *@set.map(&:name)].uniq * ', '} {#{content}}\n" : ""
166
+ end
167
+
168
+ css = ruleset + elements.
169
+ reject {|e| e.is_a? Mixin::Def }.map do |i|
170
+ i.to_css(path, env)
171
+ end.reject(&:empty?).join
172
+ 2.times {path.pop}
173
+ css
174
+ end
175
+
176
+ #
177
+ # Find the nearest node in the hierarchy or raise a NameError
178
+ #
179
+ def nearest ident, type = nil
180
+ ary = type || ident =~ /^[.#]/ ? :elements : :variables
181
+ result = path.map do |node|
182
+ node.send(ary).find {|i| i.to_s == ident }
183
+ end.compact.first
184
+ raise VariableNameError, ("#{ident} in #{self.to_s}") unless result
185
+ result
186
+ end
187
+
188
+ #
189
+ # Traverse the whole tree, returning each leaf (recursive)
190
+ #
191
+ def each path = [], &blk
192
+ elements.each do |element|
193
+ path << element
194
+ yield element, path if element.leaf?
195
+ element.each path, &blk
196
+ path.pop
197
+ end
198
+ self
199
+ end
200
+
201
+ def inspect depth = 0
202
+ indent = lambda {|i| '. ' * i }
203
+ put = lambda {|ary| ary.map {|i| indent[ depth + 1 ] + i.inspect } * "\n"}
204
+
205
+ (root?? "\n" : "") + [
206
+ indent[ depth ] + self.to_s,
207
+ put[ variables ],
208
+ put[ properties ],
209
+ put[ mixins ],
210
+ elements.map {|i| i.inspect( depth + 1 ) } * "\n"
211
+ ].reject(&:empty?).join("\n") + "\n" + indent[ depth ]
212
+ end
213
+ end
214
+
215
+ module Mixin
216
+ class Call
217
+ include Entity
218
+
219
+ def initialize mixin, params, parent
220
+ # puts "Initializing a Mixin::Call #{mixin}"
221
+ @mixin = mixin
222
+ self.parent = parent
223
+ @params = params.each do |e|
224
+ e.parent = self.parent
225
+ end
226
+ end
227
+
228
+ def to_css env = nil
229
+ # puts "\n\n"
230
+ # puts "call .#{@mixin.name} #{@params} <#{@params.class}>"
231
+ @mixin.call(@params.map {|e| e.evaluate(env) })
232
+ end
233
+
234
+ def inspect
235
+ "#{@mixin.to_s} (#{@params})"
236
+ end
237
+ end
238
+
239
+ class Def < Element
240
+ attr_accessor :params
241
+
242
+ def initialize name, params = []
243
+ super name
244
+ @params = params.each do |param|
245
+ param.parent = self
246
+ end
247
+ end
248
+
249
+ def call args = []
250
+ env = Element.new
251
+
252
+ @params.zip(args).each do |param, val|
253
+ env << (val ? Variable.new(param.to_s, Expression.new([val])) : param)
254
+ end
255
+
256
+ #b ? Node::Variable.new(a.to_s, Expression.new([b])) : a
257
+
258
+ # puts "#{self.inspect}"
259
+ # puts "env: #{env.variables} root?: #{env.root?}"
260
+ # puts "\nTOCSS"
261
+ to_css([], env)
262
+ end
263
+
264
+ def variables
265
+ params + super
266
+ end
267
+
268
+ def to_s
269
+ '.' + name
270
+ end
271
+
272
+ def to_css path, env
273
+ super(path, env)
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end
@@ -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,84 @@
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
+ #
70
+ # Call the function
71
+ #
72
+ # If the function isn't found, we just print it out,
73
+ # this is the case for url(), for example,
74
+ #
75
+ def evaluate context = nil
76
+ if Functions.available.include? self.to_sym
77
+ send to_sym, *@args
78
+ else
79
+ Node::Anonymous.new("#{to_sym}(#{@args.map(&:to_css) * ', '})")
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end