nirvdrum-less 1.1.4

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 (164) hide show
  1. data/.gitignore +4 -0
  2. data/LICENSE +179 -0
  3. data/README.md +39 -0
  4. data/Rakefile +90 -0
  5. data/VERSION +1 -0
  6. data/bin/lessc +86 -0
  7. data/less.gemspec +205 -0
  8. data/lib/ext.rb +62 -0
  9. data/lib/less.rb +33 -0
  10. data/lib/less/command.rb +106 -0
  11. data/lib/less/engine.rb +54 -0
  12. data/lib/less/engine/builder.rb +8 -0
  13. data/lib/less/engine/grammar/common.tt +29 -0
  14. data/lib/less/engine/grammar/entity.tt +139 -0
  15. data/lib/less/engine/grammar/less.tt +271 -0
  16. data/lib/less/engine/nodes.rb +9 -0
  17. data/lib/less/engine/nodes/element.rb +186 -0
  18. data/lib/less/engine/nodes/entity.rb +79 -0
  19. data/lib/less/engine/nodes/function.rb +79 -0
  20. data/lib/less/engine/nodes/literal.rb +167 -0
  21. data/lib/less/engine/nodes/property.rb +156 -0
  22. data/lib/less/engine/nodes/ruleset.rb +12 -0
  23. data/lib/less/engine/nodes/selector.rb +39 -0
  24. data/lib/vendor/treetop/.gitignore +7 -0
  25. data/lib/vendor/treetop/LICENSE +19 -0
  26. data/lib/vendor/treetop/README +164 -0
  27. data/lib/vendor/treetop/Rakefile +19 -0
  28. data/lib/vendor/treetop/benchmark/seqpar.gnuplot +15 -0
  29. data/lib/vendor/treetop/benchmark/seqpar.treetop +16 -0
  30. data/lib/vendor/treetop/benchmark/seqpar_benchmark.rb +107 -0
  31. data/lib/vendor/treetop/bin/tt +28 -0
  32. data/lib/vendor/treetop/lib/treetop.rb +8 -0
  33. data/lib/vendor/treetop/lib/treetop/bootstrap_gen_1_metagrammar.rb +45 -0
  34. data/lib/vendor/treetop/lib/treetop/compiler.rb +6 -0
  35. data/lib/vendor/treetop/lib/treetop/compiler/grammar_compiler.rb +42 -0
  36. data/lib/vendor/treetop/lib/treetop/compiler/lexical_address_space.rb +17 -0
  37. data/lib/vendor/treetop/lib/treetop/compiler/metagrammar.rb +3097 -0
  38. data/lib/vendor/treetop/lib/treetop/compiler/metagrammar.treetop +408 -0
  39. data/lib/vendor/treetop/lib/treetop/compiler/node_classes.rb +19 -0
  40. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/anything_symbol.rb +18 -0
  41. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/atomic_expression.rb +14 -0
  42. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/character_class.rb +24 -0
  43. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/choice.rb +31 -0
  44. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/declaration_sequence.rb +24 -0
  45. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/grammar.rb +28 -0
  46. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/inline_module.rb +27 -0
  47. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/nonterminal.rb +13 -0
  48. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/optional.rb +19 -0
  49. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parenthesized_expression.rb +9 -0
  50. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parsing_expression.rb +138 -0
  51. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/parsing_rule.rb +55 -0
  52. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/predicate.rb +45 -0
  53. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/repetition.rb +55 -0
  54. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/sequence.rb +68 -0
  55. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/terminal.rb +20 -0
  56. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/transient_prefix.rb +9 -0
  57. data/lib/vendor/treetop/lib/treetop/compiler/node_classes/treetop_file.rb +9 -0
  58. data/lib/vendor/treetop/lib/treetop/compiler/ruby_builder.rb +113 -0
  59. data/lib/vendor/treetop/lib/treetop/ruby_extensions.rb +2 -0
  60. data/lib/vendor/treetop/lib/treetop/ruby_extensions/string.rb +42 -0
  61. data/lib/vendor/treetop/lib/treetop/runtime.rb +5 -0
  62. data/lib/vendor/treetop/lib/treetop/runtime/compiled_parser.rb +105 -0
  63. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list.rb +4 -0
  64. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/head_node.rb +15 -0
  65. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb +200 -0
  66. data/lib/vendor/treetop/lib/treetop/runtime/interval_skip_list/node.rb +164 -0
  67. data/lib/vendor/treetop/lib/treetop/runtime/syntax_node.rb +72 -0
  68. data/lib/vendor/treetop/lib/treetop/runtime/terminal_parse_failure.rb +16 -0
  69. data/lib/vendor/treetop/lib/treetop/runtime/terminal_syntax_node.rb +17 -0
  70. data/lib/vendor/treetop/lib/treetop/version.rb +9 -0
  71. data/lib/vendor/treetop/spec/compiler/and_predicate_spec.rb +36 -0
  72. data/lib/vendor/treetop/spec/compiler/anything_symbol_spec.rb +44 -0
  73. data/lib/vendor/treetop/spec/compiler/character_class_spec.rb +182 -0
  74. data/lib/vendor/treetop/spec/compiler/choice_spec.rb +80 -0
  75. data/lib/vendor/treetop/spec/compiler/circular_compilation_spec.rb +28 -0
  76. data/lib/vendor/treetop/spec/compiler/failure_propagation_functional_spec.rb +21 -0
  77. data/lib/vendor/treetop/spec/compiler/grammar_compiler_spec.rb +84 -0
  78. data/lib/vendor/treetop/spec/compiler/grammar_spec.rb +41 -0
  79. data/lib/vendor/treetop/spec/compiler/nonterminal_symbol_spec.rb +40 -0
  80. data/lib/vendor/treetop/spec/compiler/not_predicate_spec.rb +38 -0
  81. data/lib/vendor/treetop/spec/compiler/one_or_more_spec.rb +35 -0
  82. data/lib/vendor/treetop/spec/compiler/optional_spec.rb +37 -0
  83. data/lib/vendor/treetop/spec/compiler/parenthesized_expression_spec.rb +19 -0
  84. data/lib/vendor/treetop/spec/compiler/parsing_rule_spec.rb +32 -0
  85. data/lib/vendor/treetop/spec/compiler/sequence_spec.rb +115 -0
  86. data/lib/vendor/treetop/spec/compiler/terminal_spec.rb +81 -0
  87. data/lib/vendor/treetop/spec/compiler/terminal_symbol_spec.rb +37 -0
  88. data/lib/vendor/treetop/spec/compiler/test_grammar.treetop +7 -0
  89. data/lib/vendor/treetop/spec/compiler/test_grammar.tt +7 -0
  90. data/lib/vendor/treetop/spec/compiler/test_grammar_do.treetop +7 -0
  91. data/lib/vendor/treetop/spec/compiler/zero_or_more_spec.rb +56 -0
  92. data/lib/vendor/treetop/spec/composition/a.treetop +11 -0
  93. data/lib/vendor/treetop/spec/composition/b.treetop +11 -0
  94. data/lib/vendor/treetop/spec/composition/c.treetop +10 -0
  95. data/lib/vendor/treetop/spec/composition/d.treetop +10 -0
  96. data/lib/vendor/treetop/spec/composition/f.treetop +17 -0
  97. data/lib/vendor/treetop/spec/composition/grammar_composition_spec.rb +40 -0
  98. data/lib/vendor/treetop/spec/composition/subfolder/e_includes_c.treetop +15 -0
  99. data/lib/vendor/treetop/spec/ruby_extensions/string_spec.rb +32 -0
  100. data/lib/vendor/treetop/spec/runtime/compiled_parser_spec.rb +101 -0
  101. data/lib/vendor/treetop/spec/runtime/interval_skip_list/delete_spec.rb +147 -0
  102. data/lib/vendor/treetop/spec/runtime/interval_skip_list/expire_range_spec.rb +349 -0
  103. data/lib/vendor/treetop/spec/runtime/interval_skip_list/insert_and_delete_node.rb +385 -0
  104. data/lib/vendor/treetop/spec/runtime/interval_skip_list/insert_spec.rb +660 -0
  105. data/lib/vendor/treetop/spec/runtime/interval_skip_list/interval_skip_list_spec.graffle +6175 -0
  106. data/lib/vendor/treetop/spec/runtime/interval_skip_list/interval_skip_list_spec.rb +58 -0
  107. data/lib/vendor/treetop/spec/runtime/interval_skip_list/palindromic_fixture.rb +23 -0
  108. data/lib/vendor/treetop/spec/runtime/interval_skip_list/palindromic_fixture_spec.rb +164 -0
  109. data/lib/vendor/treetop/spec/runtime/interval_skip_list/spec_helper.rb +84 -0
  110. data/lib/vendor/treetop/spec/runtime/syntax_node_spec.rb +53 -0
  111. data/lib/vendor/treetop/spec/spec_helper.rb +106 -0
  112. data/lib/vendor/treetop/spec/spec_suite.rb +4 -0
  113. data/lib/vendor/treetop/treetop.gemspec +17 -0
  114. data/spec/command_spec.rb +102 -0
  115. data/spec/css/accessors.css +18 -0
  116. data/spec/css/big.css +3768 -0
  117. data/spec/css/colors.css +11 -0
  118. data/spec/css/comments.css +9 -0
  119. data/spec/css/css-3.css +2 -0
  120. data/spec/css/css.css +45 -0
  121. data/spec/css/functions.css +6 -0
  122. data/spec/css/import.css +12 -0
  123. data/spec/css/lazy-eval.css +1 -0
  124. data/spec/css/mixins-args.css +0 -0
  125. data/spec/css/mixins.css +28 -0
  126. data/spec/css/operations.css +28 -0
  127. data/spec/css/parens.css +16 -0
  128. data/spec/css/rulesets.css +17 -0
  129. data/spec/css/scope.css +11 -0
  130. data/spec/css/selectors.css +8 -0
  131. data/spec/css/strings.css +12 -0
  132. data/spec/css/variables.css +6 -0
  133. data/spec/css/whitespace.css +11 -0
  134. data/spec/engine_spec.rb +111 -0
  135. data/spec/less/accessors.less +20 -0
  136. data/spec/less/big.less +4810 -0
  137. data/spec/less/colors.less +34 -0
  138. data/spec/less/comments.less +46 -0
  139. data/spec/less/css-3.less +11 -0
  140. data/spec/less/css.less +98 -0
  141. data/spec/less/exceptions/mixed-units-error.less +3 -0
  142. data/spec/less/exceptions/name-error-1.0.less +3 -0
  143. data/spec/less/exceptions/syntax-error-1.0.less +3 -0
  144. data/spec/less/functions.less +6 -0
  145. data/spec/less/import.less +7 -0
  146. data/spec/less/import/import-test-a.less +2 -0
  147. data/spec/less/import/import-test-b.less +8 -0
  148. data/spec/less/import/import-test-c.less +6 -0
  149. data/spec/less/import/import-test-d.css +1 -0
  150. data/spec/less/lazy-eval.less +6 -0
  151. data/spec/less/mixins-args.less +0 -0
  152. data/spec/less/mixins.less +43 -0
  153. data/spec/less/operations.less +39 -0
  154. data/spec/less/parens.less +21 -0
  155. data/spec/less/rulesets.less +30 -0
  156. data/spec/less/scope.less +32 -0
  157. data/spec/less/selectors.less +15 -0
  158. data/spec/less/strings.less +14 -0
  159. data/spec/less/variables.less +18 -0
  160. data/spec/less/whitespace.less +30 -0
  161. data/spec/spec.css +82 -0
  162. data/spec/spec.less +148 -0
  163. data/spec/spec_helper.rb +8 -0
  164. metadata +219 -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,186 @@
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, :set
16
+
17
+ def initialize name = "", selector = ''
18
+ super name
19
+
20
+ @set = []
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
+ 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.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
82
+
83
+ #
84
+ # Accessors for the different nodes in @rules
85
+ #
86
+ def identifiers; @rules.select {|r| r.kind_of? Property } end
87
+ def properties; @rules.select {|r| r.instance_of? Property } end
88
+ def variables; @rules.select {|r| r.instance_of? Variable } end
89
+ def elements; @rules.select {|r| r.instance_of? Element } end
90
+
91
+ # Select a child element
92
+ # TODO: Implement full selector syntax & merge with descend()
93
+ def [] key
94
+ @rules.find {|i| i.to_s == key }
95
+ end
96
+
97
+ # Same as above, except with a specific selector
98
+ # TODO: clean this up or implement it differently
99
+ def descend selector, element
100
+ if selector.is_a? Child
101
+ s = self[element].selector
102
+ self[element] if s.is_a? Child or s.is_a? Descendant
103
+ elsif selector.is_a? Descendant
104
+ self[element]
105
+ else
106
+ self[element] if self[element].selector.class == selector.class
107
+ end
108
+ end
109
+
110
+ #
111
+ # Add an arbitrary node to this element
112
+ #
113
+ def << obj
114
+ if obj.kind_of? Node::Entity
115
+ obj.parent = self
116
+ @rules << obj
117
+ else
118
+ raise ArgumentError, "argument can't be a #{obj.class}"
119
+ end
120
+ end
121
+
122
+ def last; elements.last end
123
+ def first; elements.first end
124
+ def to_s; root?? '*' : super end
125
+
126
+ #
127
+ # Entry point for the css conversion
128
+ #
129
+ def to_css path = []
130
+ path << @selector.to_css << self unless root?
131
+
132
+ content = properties.map do |i|
133
+ ' ' * 2 + i.to_css
134
+ end.compact.reject(&:empty?) * "\n"
135
+
136
+ content = content.include?("\n") ?
137
+ "\n#{content}\n" : " #{content.strip} "
138
+ ruleset = !content.strip.empty??
139
+ "#{[path.reject(&:empty?).join.strip, *@set] * ', '} {#{content}}\n" : ""
140
+
141
+ css = ruleset + elements.map do |i|
142
+ i.to_css(path)
143
+ end.reject(&:empty?).join
144
+ path.pop; path.pop
145
+ css
146
+ end
147
+
148
+ #
149
+ # Find the nearest variable in the hierarchy or raise a NameError
150
+ #
151
+ def nearest ident
152
+ ary = ident =~ /^[.#]/ ? :elements : :variables
153
+ path.map do |node|
154
+ node.send(ary).find {|i| i.to_s == ident }
155
+ end.compact.first.tap do |result|
156
+ raise VariableNameError, ident unless result
157
+ end
158
+ end
159
+
160
+ #
161
+ # Traverse the whole tree, returning each leaf (recursive)
162
+ #
163
+ def each path = [], &blk
164
+ elements.each do |element|
165
+ path << element
166
+ yield element, path if element.leaf?
167
+ element.each path, &blk
168
+ path.pop
169
+ end
170
+ self
171
+ end
172
+
173
+ def inspect depth = 0
174
+ indent = lambda {|i| '. ' * i }
175
+ put = lambda {|ary| ary.map {|i| indent[ depth + 1 ] + i.inspect } * "\n"}
176
+
177
+ (root?? "\n" : "") + [
178
+ indent[ depth ] + (self == '' ? '*' : self.to_s),
179
+ put[ properties ],
180
+ put[ variables ],
181
+ elements.map {|i| i.inspect( depth + 1 ) } * "\n"
182
+ ].reject(&:empty?).join("\n") + "\n" + indent[ depth ]
183
+ end
184
+ end
185
+ end
186
+ 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,79 @@
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
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 = args.flatten
57
+ super name
58
+ end
59
+
60
+ def to_css
61
+ self.evaluate.to_css
62
+ end
63
+
64
+ #
65
+ # Call the function
66
+ #
67
+ # If the function isn't found, we just print it out,
68
+ # this is the case for url(), for example,
69
+ #
70
+ def evaluate
71
+ if Functions.available.include? self.to_sym
72
+ send to_sym, *@args
73
+ else
74
+ Node::Anonymous.new("#{to_sym}(#{@args.map(&:to_css) * ', '})")
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,167 @@
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 to_ruby
99
+ self.to_f
100
+ end
101
+
102
+ def inspect
103
+ to_s
104
+ end
105
+
106
+ def to_css
107
+ "#{(self % 1).zero?? "#{self.to_i}#@unit" : self}"
108
+ end
109
+ end
110
+
111
+ #
112
+ # "hello world"
113
+ #
114
+ class String < ::String
115
+ include Literal
116
+
117
+ attr_reader :quotes, :content
118
+
119
+ # Strip quotes if necessary, and save them in @quotes
120
+ def initialize str
121
+ @quotes, @content = unless str.nil? or str.empty?
122
+ str.match(/('|")(.*?)(\1)/).captures rescue [nil, str]
123
+ else
124
+ [nil, ""]
125
+ end
126
+ super @content
127
+ end
128
+
129
+ def to_css
130
+ "#@quotes#{@content}#@quotes"
131
+ end
132
+ end
133
+
134
+ class Font
135
+ include Literal
136
+ end
137
+
138
+ class FontFamily
139
+ include Literal
140
+
141
+ def initialize family = []
142
+ @family = family
143
+ end
144
+
145
+ def to_css
146
+ @family.map(&:to_css) * ', '
147
+ end
148
+ end
149
+
150
+ #
151
+ # Any un-quoted word
152
+ #
153
+ # ex: red, small, border-collapse
154
+ #
155
+ class Keyword < ::String
156
+ include Entity
157
+
158
+ def to_css
159
+ self
160
+ end
161
+
162
+ def inspect
163
+ "#{self}"
164
+ end
165
+ end
166
+ end
167
+ end