cloudhead-less 0.8.12 → 1.0.0

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 (66) hide show
  1. data/README.md +10 -1
  2. data/Rakefile +21 -2
  3. data/VERSION +1 -1
  4. data/bin/lessc +0 -8
  5. data/less.gemspec +48 -15
  6. data/lib/less/command.rb +24 -25
  7. data/lib/less/engine/builder.rb +13 -0
  8. data/lib/less/engine/less.tt +379 -0
  9. data/lib/less/engine/nodes/element.rb +153 -0
  10. data/lib/less/engine/nodes/entity.rb +59 -0
  11. data/lib/less/engine/nodes/function.rb +61 -0
  12. data/lib/less/engine/nodes/literal.rb +132 -0
  13. data/lib/less/engine/nodes/property.rb +120 -0
  14. data/lib/less/engine/nodes/selector.rb +39 -0
  15. data/lib/less/engine/nodes.rb +8 -0
  16. data/lib/less/engine/parser.rb +3854 -0
  17. data/lib/less/engine.rb +42 -139
  18. data/lib/less.rb +65 -10
  19. data/spec/command_spec.rb +2 -6
  20. data/spec/css/accessors-1.0.css +20 -0
  21. data/spec/css/big-1.0.css +3770 -0
  22. data/spec/css/comments-1.0.css +11 -0
  23. data/spec/css/css-1.0.css +40 -0
  24. data/spec/css/functions-1.0.css +8 -0
  25. data/spec/css/import-1.0.css +13 -0
  26. data/spec/css/mixins-1.0.css +30 -0
  27. data/spec/css/operations-1.0.css +30 -0
  28. data/spec/css/rulesets-1.0.css +19 -0
  29. data/spec/css/scope-1.0.css +16 -0
  30. data/spec/css/strings-1.0.css +14 -0
  31. data/spec/css/variables-1.0.css +7 -0
  32. data/spec/css/whitespace-1.0.css +11 -0
  33. data/spec/engine_spec.rb +66 -18
  34. data/spec/less/accessors-1.0.less +20 -0
  35. data/spec/less/big-1.0.less +4810 -0
  36. data/spec/less/colors-1.0.less +0 -0
  37. data/spec/less/comments-1.0.less +46 -0
  38. data/spec/less/css-1.0.less +82 -0
  39. data/spec/less/exceptions/mixed-units-error.less +0 -0
  40. data/spec/less/exceptions/name-error-1.0.less +0 -0
  41. data/spec/less/exceptions/syntax-error-1.0.less +0 -0
  42. data/spec/less/functions-1.0.less +6 -0
  43. data/spec/less/import/import-test-a.less +2 -0
  44. data/spec/less/import/import-test-b.less +8 -0
  45. data/spec/less/import/import-test-c.less +5 -0
  46. data/spec/less/import-1.0.less +7 -0
  47. data/spec/less/mixins-1.0.less +43 -0
  48. data/spec/less/operations-1.0.less +39 -0
  49. data/spec/less/rulesets-1.0.less +30 -0
  50. data/spec/less/scope-1.0.less +33 -0
  51. data/spec/less/strings-1.0.less +14 -0
  52. data/spec/less/variables-1.0.less +16 -0
  53. data/spec/less/whitespace-1.0.less +21 -0
  54. data/spec/spec.css +81 -23
  55. data/spec/spec.less +3 -4
  56. data/spec/spec_helper.rb +4 -1
  57. metadata +46 -13
  58. data/lib/less/tree.rb +0 -82
  59. data/spec/css/less-0.8.10.css +0 -30
  60. data/spec/css/less-0.8.11.css +0 -31
  61. data/spec/css/less-0.8.12.css +0 -28
  62. data/spec/css/less-0.8.5.css +0 -24
  63. data/spec/css/less-0.8.6.css +0 -24
  64. data/spec/css/less-0.8.7.css +0 -24
  65. data/spec/css/less-0.8.8.css +0 -25
  66. data/spec/tree_spec.rb +0 -5
@@ -0,0 +1,153 @@
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 < ::String
12
+ include Enumerable
13
+ include Entity
14
+
15
+ attr_accessor :rules, :selector, :partial, :file
16
+
17
+ def initialize name = "", selector = ''
18
+ super name
19
+
20
+ @partial = false
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?; self =~ /^\./ end
26
+ def id?; self =~ /^#/ end
27
+ def universal?; self == '*' end
28
+
29
+ def tag?
30
+ not id? || class? || universal?
31
+ end
32
+
33
+ # Top-most node?
34
+ def root?
35
+ self == '' && parent.nil?
36
+ end
37
+
38
+ def empty?
39
+ @rules.empty?
40
+ end
41
+
42
+ def leaf?
43
+ elements.empty?
44
+ end
45
+
46
+ #
47
+ # Accessors for the different nodes in @rules
48
+ #
49
+ def identifiers; @rules.select {|r| r.kind_of? Property } end
50
+ def properties; @rules.select {|r| r.instance_of? Property } end
51
+ def variables; @rules.select {|r| r.instance_of? Variable } end
52
+ def elements; @rules.select {|r| r.instance_of? Element } end
53
+
54
+ # Select a child element
55
+ # TODO: Implement full selector syntax
56
+ def [] key
57
+ @rules.find {|i| i.to_s == key }
58
+ end
59
+
60
+ # Same as above, except with a specific selector
61
+ # TODO: clean this up or implement it differently
62
+ def descend selector, element
63
+ if selector.is_a? Child
64
+ s = self[element].selector
65
+ self[element] if s.is_a? Child or s.is_a? Descendant
66
+ elsif selector.is_a? Descendant
67
+ self[element]
68
+ else
69
+ self[element] if self[element].selector.class == selector.class
70
+ end
71
+ end
72
+
73
+ #
74
+ # Add an arbitrary node to this element
75
+ #
76
+ def << obj
77
+ if obj.kind_of? Node::Entity
78
+ obj.parent = self
79
+ @rules << obj
80
+ else
81
+ raise ArgumentError, "argument can't be a #{obj.class}"
82
+ end
83
+ end
84
+
85
+ def last; elements.last end
86
+ def first; elements.first end
87
+ def to_s; super end
88
+
89
+ # Entry point for the css conversion
90
+ def to_css path = []
91
+ path << @selector.to_css << self unless root?
92
+
93
+ content = properties.map do |i|
94
+ ' ' * 2 + i.to_css
95
+ end.compact.reject(&:empty?) * "\n"
96
+
97
+ content = content.include?("\n") ?
98
+ "\n#{content}\n" : " #{content.strip} "
99
+ ruleset = !content.strip.empty??
100
+ "#{path.reject(&:empty?).join.strip} {#{content}}\n" : ""
101
+
102
+ css = ruleset + elements.map do |i|
103
+ i.to_css(path)
104
+ end.reject(&:empty?).join
105
+ path.pop; path.pop
106
+ css
107
+ end
108
+
109
+ #
110
+ # Find the nearest variable in the hierarchy or raise a NameError
111
+ #
112
+ def nearest ident
113
+ ary = ident =~ /^[.#]/ ? :elements : :variables
114
+ path.map do |node|
115
+ node.send(ary).find {|i| i.to_s == ident }
116
+ end.compact.first.tap do |result|
117
+ raise VariableNameError, ident unless result
118
+ end
119
+ end
120
+
121
+ def each path = [], &blk
122
+ #
123
+ # Traverse the whole tree, returning each leaf or branch (recursive)
124
+ #
125
+ ###
126
+ # Aside from the key & value, we yield the full path of the leaf,
127
+ # aswell as the branch which contains it (self).
128
+ # Note that in :branch mode, we only return 'twigs', branches which contain leaves.
129
+ #
130
+ elements.each do |element|
131
+ path << element
132
+ yield element, path if element.leaf?
133
+ element.each path, &blk
134
+ path.pop
135
+ end
136
+ self
137
+ end
138
+ alias :traverse :each
139
+
140
+ def inspect depth = 0
141
+ indent = lambda {|i| '. ' * i }
142
+ put = lambda {|ary| ary.map {|i| indent[ depth + 1 ] + i.inspect } * "\n"}
143
+
144
+ (root?? "\n" : "") + [
145
+ indent[ depth ] + (self == '' ? '*' : self.to_s),
146
+ put[ properties ],
147
+ put[ variables ],
148
+ elements.map {|i| i.inspect( depth + 1 ) } * "\n"
149
+ ].reject(&:empty?).join("\n") + "\n" + indent[ depth ]
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,59 @@
1
+ module Less
2
+ #
3
+ # Node::Entity
4
+ #
5
+ # TODO: Use delegate class -> @rules
6
+ #
7
+ # 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
+ module Node
23
+ module Entity
24
+ attr_accessor :parent
25
+
26
+ def initialize value, parent = nil
27
+ super value
28
+ @parent = parent
29
+ end
30
+
31
+ def path node = self
32
+ path = []
33
+ while node do
34
+ path << node
35
+ node = node.parent
36
+ end
37
+ path
38
+ end
39
+
40
+ def root
41
+ path.last
42
+ end
43
+
44
+ def inspect; to_s end
45
+ def to_css; to_s end
46
+ def to_s; super end
47
+ end
48
+
49
+ class Anonymous < ::String
50
+ include Entity
51
+ end
52
+
53
+ class Operator < ::String
54
+ def to_ruby
55
+ self
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,61 @@
1
+ module Less
2
+ module Functions
3
+ def rgb *rgb
4
+ rgba rgb, 1.0
5
+ end
6
+
7
+ def hsl *args
8
+ hsla args, 1.0
9
+ end
10
+
11
+ def rgba *rgba
12
+ r, g, b, a = rgba.flatten
13
+ hex = [r, g, b].inject("") do |str, c|
14
+ c = c.to_i.to_s(16)
15
+ c = '0' + c if c.length < 2
16
+ str + c
17
+ end
18
+ Node::Color.new hex, a
19
+ end
20
+
21
+ def hsla h, s, l, a = 1.0
22
+ m2 = ( l <= 0.5 ) ? l * ( s + 1 ) : l + s - l * s
23
+ m1 = l * 2 - m2;
24
+
25
+ hue = lambda do |h|
26
+ h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h)
27
+ if h * 6 < 1 then m1 + (m2 - m1) * h * 6
28
+ elsif h * 2 < 1 then m2
29
+ elsif h * 3 < 2 then m1 + (m2 - m1) * (2/3 - h) * 6
30
+ else m1
31
+ end
32
+ end
33
+
34
+ rgba hue[ h + 1/3 ], hue[ h ], hue[ h - 1/3 ], a
35
+ end
36
+ end
37
+
38
+ module Node
39
+ class Function < ::String
40
+ include Functions
41
+ include Entity
42
+
43
+ def initialize name, *args
44
+ @args = args.flatten
45
+ super name
46
+ end
47
+
48
+ def to_css
49
+ self.evaluate.to_css
50
+ end
51
+
52
+ def evaluate
53
+ send self.to_sym, *@args
54
+ end
55
+
56
+ def method_missing meth, *args
57
+ Node::Anonymous.new("#{meth}(#{args.map(&:to_css) * ', '})")
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,132 @@
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 < DelegateClass(Fixnum)
15
+ include Literal
16
+ attr_reader :color
17
+
18
+ def initialize color = nil, opacity = 1.0
19
+ @color = if color.is_a? Array
20
+ rgba color
21
+ elsif color.is_a? ::String
22
+ color.delete! unit
23
+ (color * ( color.length < 6 ? 6 / color.length : 1 )).to_i 16
24
+ else
25
+ color
26
+ end
27
+ super @color.to_i
28
+ end
29
+
30
+ def unit
31
+ '#'
32
+ end
33
+
34
+ def to_css
35
+ unit + (self <= 0 ? '0' * 6 : self.to_i.to_s(16))
36
+ end
37
+
38
+ def to_ruby
39
+ color
40
+ end
41
+
42
+ def to_s
43
+ "#{unit}#{super}"
44
+ end
45
+
46
+ def inspect; to_s end
47
+ end
48
+
49
+ #
50
+ # 6 10px 125%
51
+ #
52
+ class Number < DelegateClass(Float)
53
+ include Literal
54
+
55
+ attr_accessor :unit
56
+
57
+ def initialize value, unit = nil
58
+ super value.to_f
59
+ @unit = (unit.nil? || unit.empty?) ? nil : unit
60
+ end
61
+
62
+ def to_s
63
+ "#{super}#@unit"
64
+ end
65
+
66
+ def to_ruby
67
+ self.to_f
68
+ end
69
+
70
+ def inspect
71
+ to_s
72
+ end
73
+
74
+ def to_css
75
+ "#{(self % 1).zero?? self.to_i.to_s : self.to_s}#@unit"
76
+ end
77
+ end
78
+
79
+ #
80
+ # "hello world"
81
+ #
82
+ class String < ::String
83
+ include Literal
84
+
85
+ attr_reader :quotes, :content
86
+
87
+ def initialize str
88
+ @quotes, @content = unless str.nil? or str.empty?
89
+ str.match(/('|")(.*?)(\1)/).captures rescue [nil, str]
90
+ else
91
+ [nil, ""]
92
+ end
93
+ super @content
94
+ end
95
+
96
+ def to_css
97
+ "#@quotes#{@content}#@quotes"
98
+ end
99
+ end
100
+
101
+ class Font
102
+ include Literal
103
+ end
104
+
105
+ class FontFamily < Array
106
+ include Literal
107
+
108
+ def initialize family = []
109
+ super family
110
+ end
111
+
112
+ def to_css
113
+ self.map(&:to_css) * ', '
114
+ end
115
+ end
116
+
117
+ #
118
+ # red small border-collapse
119
+ #
120
+ class Keyword < ::String
121
+ include Entity
122
+
123
+ def to_css
124
+ self
125
+ end
126
+
127
+ def inspect
128
+ "#{self}"
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,120 @@
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
9
+ super key
10
+ log "\n[new] #{self.class} `#{key}`\n"
11
+ @value = Expression.new(value ? [value] : [])
12
+ @eval = false # Store the first evaluation in here
13
+ end
14
+
15
+ def << token
16
+ log "[adding] to #{self.to_s}: '#{token.to_s}' <#{token.class}>\n"
17
+ token = Node::Anonymous.new(*token) unless token.is_a? Entity or token.is_a? Operator
18
+ @value << token
19
+ end
20
+
21
+ def empty?; !@value || @value.empty? end
22
+ def eval?; @eval end
23
+
24
+ def inspect
25
+ self + (empty?? "" : ": `#{value.map {|i| i.to_s } * ' | '}`")
26
+ end
27
+
28
+ def to_s
29
+ super
30
+ end
31
+
32
+ # TODO: @eval and @value should be merged
33
+ def evaluate
34
+ @eval || @eval = value.evaluate
35
+ end
36
+
37
+ def to_css
38
+ "#{self}: #{evaluate.to_css};"
39
+ end
40
+ end
41
+
42
+ class Variable < Property
43
+ def initialize key, value = nil
44
+ super key.delete('@'), value
45
+ end
46
+
47
+ def inspect
48
+ "@#{super}"
49
+ end
50
+
51
+ def to_s
52
+ "@#{super}"
53
+ end
54
+
55
+ def to_ruby
56
+ value.evaluate.to_ruby
57
+ end
58
+
59
+ def to_css
60
+ value.evaluate.to_css
61
+ end
62
+ end
63
+
64
+ class Expression < Array
65
+ def operators; select {|i| i.is_a? Operator } end
66
+ def entities; select {|i| i.kind_of? Entity } end
67
+ def literals; select {|i| i.kind_of? Literal } end
68
+
69
+ def inspect
70
+ '[' + map {|i| i.inspect }.join(', ') + ']'
71
+ end
72
+
73
+ def to_css
74
+ map {|i| i.to_css } * ' '
75
+ end
76
+
77
+ #
78
+ # Evaluates the expression and instantiates a new Literal with the result
79
+ # ex: [#111, +, #111] will evaluate to a Color node, with value #222
80
+ #
81
+ def evaluate
82
+ log "evaluating #{self}"
83
+ log "#{self.select{|i| i.is_a? Entity }}"
84
+ if size > 2 && (entities.size == operators.size + 1)
85
+ # Create a sub-expression with all the variables/properties evaluated
86
+ evaluated = Expression.new map {|e| e.respond_to?(:evaluate) ? e.evaluate : e }
87
+
88
+ unit = evaluated.literals.map do |node|
89
+ node.unit
90
+ end.compact.uniq.tap do |ary|
91
+ raise MixedUnitsError, self * ' ' if ary.size > 1
92
+ end.join
93
+
94
+ entity = evaluated.literals.find {|e| e.unit == unit } || evaluated.first
95
+ ruby = map {|e| e.to_ruby if e.respond_to? :to_ruby }
96
+
97
+ unless ruby.include? nil
98
+ log "ruby(#{unit}): " + ruby.join(' ') + "\n"
99
+
100
+ if entity
101
+ log "\n# => #{eval(ruby.join)} <#{entity.class}>\n"
102
+ entity.class.new(eval(ruby.join), *(unit if entity.class == Node::Number))
103
+ else
104
+ log "\n# => not evaluated"
105
+ first
106
+ end
107
+ else
108
+ log "some elements dont respond to to_ruby: #{ruby}"
109
+ self
110
+ end
111
+ elsif size == 1
112
+ log "not evaluating, size == 1"
113
+ first
114
+ else
115
+ self
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,39 @@
1
+ module Less
2
+ module Node
3
+ class Selector < ::String
4
+ include Entity
5
+
6
+ Selectors = {
7
+ :Descendant => '',
8
+ :Child => '>',
9
+ :Adjacent => '+',
10
+ :Pseudo => ':',
11
+ :Sibling => '~'
12
+ }
13
+
14
+ def initialize
15
+ super Selectors[ self.class.to_s.split('::').last.to_sym ]
16
+ end
17
+
18
+ def self.[] key
19
+ Node.const_get(Selectors.find {|k, v| v == key }.first)
20
+ end
21
+ end
22
+
23
+ class Descendant < Selector
24
+ def to_css; " " end
25
+ end
26
+
27
+ class Child < Selector
28
+ def to_css; " #{self} " end
29
+ end
30
+
31
+ class Adjacent < Selector
32
+ def to_css; " #{self} " end
33
+ end
34
+
35
+ class Pseudo < Selector
36
+ def to_css; self end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'engine/nodes/entity'
4
+ require 'engine/nodes/element'
5
+ require 'engine/nodes/property'
6
+ require 'engine/nodes/literal'
7
+ require 'engine/nodes/function'
8
+ require 'engine/nodes/selector'