spree 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of spree might be problematic. Click here for more details.

Files changed (181) hide show
  1. data/CHANGELOG +4 -0
  2. data/config/environment.rb +3 -3
  3. data/lib/spree.rb +1 -1
  4. data/public/stylesheets/compiled/screen.css +59 -267
  5. metadata +4 -207
  6. data/vendor/gems/haml-2.1.0/FAQ +0 -138
  7. data/vendor/gems/haml-2.1.0/MIT-LICENSE +0 -20
  8. data/vendor/gems/haml-2.1.0/README.rdoc +0 -332
  9. data/vendor/gems/haml-2.1.0/REVISION +0 -1
  10. data/vendor/gems/haml-2.1.0/Rakefile +0 -185
  11. data/vendor/gems/haml-2.1.0/VERSION +0 -1
  12. data/vendor/gems/haml-2.1.0/bin/css2sass +0 -7
  13. data/vendor/gems/haml-2.1.0/bin/haml +0 -9
  14. data/vendor/gems/haml-2.1.0/bin/html2haml +0 -7
  15. data/vendor/gems/haml-2.1.0/bin/sass +0 -8
  16. data/vendor/gems/haml-2.1.0/extra/haml-mode.el +0 -434
  17. data/vendor/gems/haml-2.1.0/extra/sass-mode.el +0 -98
  18. data/vendor/gems/haml-2.1.0/init.rb +0 -8
  19. data/vendor/gems/haml-2.1.0/lib/haml.rb +0 -1042
  20. data/vendor/gems/haml-2.1.0/lib/haml/buffer.rb +0 -255
  21. data/vendor/gems/haml-2.1.0/lib/haml/engine.rb +0 -268
  22. data/vendor/gems/haml-2.1.0/lib/haml/error.rb +0 -22
  23. data/vendor/gems/haml-2.1.0/lib/haml/exec.rb +0 -395
  24. data/vendor/gems/haml-2.1.0/lib/haml/filters.rb +0 -276
  25. data/vendor/gems/haml-2.1.0/lib/haml/helpers.rb +0 -468
  26. data/vendor/gems/haml-2.1.0/lib/haml/helpers/action_view_extensions.rb +0 -45
  27. data/vendor/gems/haml-2.1.0/lib/haml/helpers/action_view_mods.rb +0 -181
  28. data/vendor/gems/haml-2.1.0/lib/haml/html.rb +0 -218
  29. data/vendor/gems/haml-2.1.0/lib/haml/precompiler.rb +0 -889
  30. data/vendor/gems/haml-2.1.0/lib/haml/shared.rb +0 -45
  31. data/vendor/gems/haml-2.1.0/lib/haml/template.rb +0 -51
  32. data/vendor/gems/haml-2.1.0/lib/haml/template/patch.rb +0 -58
  33. data/vendor/gems/haml-2.1.0/lib/haml/template/plugin.rb +0 -72
  34. data/vendor/gems/haml-2.1.0/lib/haml/util.rb +0 -77
  35. data/vendor/gems/haml-2.1.0/lib/haml/version.rb +0 -47
  36. data/vendor/gems/haml-2.1.0/lib/sass.rb +0 -1062
  37. data/vendor/gems/haml-2.1.0/lib/sass/css.rb +0 -388
  38. data/vendor/gems/haml-2.1.0/lib/sass/engine.rb +0 -499
  39. data/vendor/gems/haml-2.1.0/lib/sass/environment.rb +0 -33
  40. data/vendor/gems/haml-2.1.0/lib/sass/error.rb +0 -35
  41. data/vendor/gems/haml-2.1.0/lib/sass/plugin.rb +0 -203
  42. data/vendor/gems/haml-2.1.0/lib/sass/plugin/merb.rb +0 -56
  43. data/vendor/gems/haml-2.1.0/lib/sass/plugin/rails.rb +0 -24
  44. data/vendor/gems/haml-2.1.0/lib/sass/repl.rb +0 -51
  45. data/vendor/gems/haml-2.1.0/lib/sass/script.rb +0 -38
  46. data/vendor/gems/haml-2.1.0/lib/sass/script/bool.rb +0 -13
  47. data/vendor/gems/haml-2.1.0/lib/sass/script/color.rb +0 -97
  48. data/vendor/gems/haml-2.1.0/lib/sass/script/funcall.rb +0 -28
  49. data/vendor/gems/haml-2.1.0/lib/sass/script/functions.rb +0 -122
  50. data/vendor/gems/haml-2.1.0/lib/sass/script/lexer.rb +0 -152
  51. data/vendor/gems/haml-2.1.0/lib/sass/script/literal.rb +0 -60
  52. data/vendor/gems/haml-2.1.0/lib/sass/script/number.rb +0 -231
  53. data/vendor/gems/haml-2.1.0/lib/sass/script/operation.rb +0 -30
  54. data/vendor/gems/haml-2.1.0/lib/sass/script/parser.rb +0 -142
  55. data/vendor/gems/haml-2.1.0/lib/sass/script/string.rb +0 -42
  56. data/vendor/gems/haml-2.1.0/lib/sass/script/unary_operation.rb +0 -21
  57. data/vendor/gems/haml-2.1.0/lib/sass/script/variable.rb +0 -20
  58. data/vendor/gems/haml-2.1.0/lib/sass/tree/attr_node.rb +0 -64
  59. data/vendor/gems/haml-2.1.0/lib/sass/tree/comment_node.rb +0 -34
  60. data/vendor/gems/haml-2.1.0/lib/sass/tree/debug_node.rb +0 -22
  61. data/vendor/gems/haml-2.1.0/lib/sass/tree/directive_node.rb +0 -50
  62. data/vendor/gems/haml-2.1.0/lib/sass/tree/file_node.rb +0 -27
  63. data/vendor/gems/haml-2.1.0/lib/sass/tree/for_node.rb +0 -29
  64. data/vendor/gems/haml-2.1.0/lib/sass/tree/if_node.rb +0 -27
  65. data/vendor/gems/haml-2.1.0/lib/sass/tree/mixin_def_node.rb +0 -18
  66. data/vendor/gems/haml-2.1.0/lib/sass/tree/mixin_node.rb +0 -34
  67. data/vendor/gems/haml-2.1.0/lib/sass/tree/node.rb +0 -99
  68. data/vendor/gems/haml-2.1.0/lib/sass/tree/rule_node.rb +0 -120
  69. data/vendor/gems/haml-2.1.0/lib/sass/tree/variable_node.rb +0 -24
  70. data/vendor/gems/haml-2.1.0/lib/sass/tree/while_node.rb +0 -20
  71. data/vendor/gems/haml-2.1.0/rails/init.rb +0 -1
  72. data/vendor/gems/haml-2.1.0/test/benchmark.rb +0 -99
  73. data/vendor/gems/haml-2.1.0/test/haml/engine_test.rb +0 -734
  74. data/vendor/gems/haml-2.1.0/test/haml/helper_test.rb +0 -224
  75. data/vendor/gems/haml-2.1.0/test/haml/html2haml_test.rb +0 -92
  76. data/vendor/gems/haml-2.1.0/test/haml/markaby/standard.mab +0 -52
  77. data/vendor/gems/haml-2.1.0/test/haml/mocks/article.rb +0 -6
  78. data/vendor/gems/haml-2.1.0/test/haml/results/content_for_layout.xhtml +0 -15
  79. data/vendor/gems/haml-2.1.0/test/haml/results/eval_suppressed.xhtml +0 -9
  80. data/vendor/gems/haml-2.1.0/test/haml/results/filters.xhtml +0 -62
  81. data/vendor/gems/haml-2.1.0/test/haml/results/helpers.xhtml +0 -93
  82. data/vendor/gems/haml-2.1.0/test/haml/results/helpful.xhtml +0 -10
  83. data/vendor/gems/haml-2.1.0/test/haml/results/just_stuff.xhtml +0 -68
  84. data/vendor/gems/haml-2.1.0/test/haml/results/list.xhtml +0 -12
  85. data/vendor/gems/haml-2.1.0/test/haml/results/nuke_inner_whitespace.xhtml +0 -40
  86. data/vendor/gems/haml-2.1.0/test/haml/results/nuke_outer_whitespace.xhtml +0 -148
  87. data/vendor/gems/haml-2.1.0/test/haml/results/original_engine.xhtml +0 -20
  88. data/vendor/gems/haml-2.1.0/test/haml/results/partial_layout.xhtml +0 -5
  89. data/vendor/gems/haml-2.1.0/test/haml/results/partials.xhtml +0 -21
  90. data/vendor/gems/haml-2.1.0/test/haml/results/render_layout.xhtml +0 -3
  91. data/vendor/gems/haml-2.1.0/test/haml/results/silent_script.xhtml +0 -74
  92. data/vendor/gems/haml-2.1.0/test/haml/results/standard.xhtml +0 -42
  93. data/vendor/gems/haml-2.1.0/test/haml/results/tag_parsing.xhtml +0 -23
  94. data/vendor/gems/haml-2.1.0/test/haml/results/very_basic.xhtml +0 -5
  95. data/vendor/gems/haml-2.1.0/test/haml/results/whitespace_handling.xhtml +0 -89
  96. data/vendor/gems/haml-2.1.0/test/haml/rhtml/_av_partial_1.rhtml +0 -12
  97. data/vendor/gems/haml-2.1.0/test/haml/rhtml/_av_partial_2.rhtml +0 -8
  98. data/vendor/gems/haml-2.1.0/test/haml/rhtml/action_view.rhtml +0 -62
  99. data/vendor/gems/haml-2.1.0/test/haml/rhtml/standard.rhtml +0 -54
  100. data/vendor/gems/haml-2.1.0/test/haml/template_test.rb +0 -204
  101. data/vendor/gems/haml-2.1.0/test/haml/templates/_av_partial_1.haml +0 -9
  102. data/vendor/gems/haml-2.1.0/test/haml/templates/_av_partial_1_ugly.haml +0 -9
  103. data/vendor/gems/haml-2.1.0/test/haml/templates/_av_partial_2.haml +0 -5
  104. data/vendor/gems/haml-2.1.0/test/haml/templates/_av_partial_2_ugly.haml +0 -5
  105. data/vendor/gems/haml-2.1.0/test/haml/templates/_layout.erb +0 -3
  106. data/vendor/gems/haml-2.1.0/test/haml/templates/_layout_for_partial.haml +0 -3
  107. data/vendor/gems/haml-2.1.0/test/haml/templates/_partial.haml +0 -8
  108. data/vendor/gems/haml-2.1.0/test/haml/templates/_text_area.haml +0 -3
  109. data/vendor/gems/haml-2.1.0/test/haml/templates/action_view.haml +0 -47
  110. data/vendor/gems/haml-2.1.0/test/haml/templates/action_view_ugly.haml +0 -47
  111. data/vendor/gems/haml-2.1.0/test/haml/templates/breakage.haml +0 -8
  112. data/vendor/gems/haml-2.1.0/test/haml/templates/content_for_layout.haml +0 -10
  113. data/vendor/gems/haml-2.1.0/test/haml/templates/eval_suppressed.haml +0 -11
  114. data/vendor/gems/haml-2.1.0/test/haml/templates/filters.haml +0 -66
  115. data/vendor/gems/haml-2.1.0/test/haml/templates/helpers.haml +0 -95
  116. data/vendor/gems/haml-2.1.0/test/haml/templates/helpful.haml +0 -11
  117. data/vendor/gems/haml-2.1.0/test/haml/templates/just_stuff.haml +0 -83
  118. data/vendor/gems/haml-2.1.0/test/haml/templates/list.haml +0 -12
  119. data/vendor/gems/haml-2.1.0/test/haml/templates/nuke_inner_whitespace.haml +0 -32
  120. data/vendor/gems/haml-2.1.0/test/haml/templates/nuke_outer_whitespace.haml +0 -144
  121. data/vendor/gems/haml-2.1.0/test/haml/templates/original_engine.haml +0 -17
  122. data/vendor/gems/haml-2.1.0/test/haml/templates/partial_layout.haml +0 -3
  123. data/vendor/gems/haml-2.1.0/test/haml/templates/partialize.haml +0 -1
  124. data/vendor/gems/haml-2.1.0/test/haml/templates/partials.haml +0 -12
  125. data/vendor/gems/haml-2.1.0/test/haml/templates/render_layout.haml +0 -2
  126. data/vendor/gems/haml-2.1.0/test/haml/templates/silent_script.haml +0 -40
  127. data/vendor/gems/haml-2.1.0/test/haml/templates/standard.haml +0 -42
  128. data/vendor/gems/haml-2.1.0/test/haml/templates/standard_ugly.haml +0 -42
  129. data/vendor/gems/haml-2.1.0/test/haml/templates/tag_parsing.haml +0 -21
  130. data/vendor/gems/haml-2.1.0/test/haml/templates/very_basic.haml +0 -4
  131. data/vendor/gems/haml-2.1.0/test/haml/templates/whitespace_handling.haml +0 -87
  132. data/vendor/gems/haml-2.1.0/test/linked_rails.rb +0 -12
  133. data/vendor/gems/haml-2.1.0/test/sass/css2sass_test.rb +0 -193
  134. data/vendor/gems/haml-2.1.0/test/sass/engine_test.rb +0 -769
  135. data/vendor/gems/haml-2.1.0/test/sass/functions_test.rb +0 -96
  136. data/vendor/gems/haml-2.1.0/test/sass/more_results/more1.css +0 -9
  137. data/vendor/gems/haml-2.1.0/test/sass/more_results/more1_with_line_comments.css +0 -26
  138. data/vendor/gems/haml-2.1.0/test/sass/more_results/more_import.css +0 -29
  139. data/vendor/gems/haml-2.1.0/test/sass/more_templates/_more_partial.sass +0 -2
  140. data/vendor/gems/haml-2.1.0/test/sass/more_templates/more1.sass +0 -23
  141. data/vendor/gems/haml-2.1.0/test/sass/more_templates/more_import.sass +0 -11
  142. data/vendor/gems/haml-2.1.0/test/sass/plugin_test.rb +0 -208
  143. data/vendor/gems/haml-2.1.0/test/sass/results/alt.css +0 -4
  144. data/vendor/gems/haml-2.1.0/test/sass/results/basic.css +0 -9
  145. data/vendor/gems/haml-2.1.0/test/sass/results/compact.css +0 -5
  146. data/vendor/gems/haml-2.1.0/test/sass/results/complex.css +0 -87
  147. data/vendor/gems/haml-2.1.0/test/sass/results/compressed.css +0 -1
  148. data/vendor/gems/haml-2.1.0/test/sass/results/expanded.css +0 -19
  149. data/vendor/gems/haml-2.1.0/test/sass/results/import.css +0 -29
  150. data/vendor/gems/haml-2.1.0/test/sass/results/line_numbers.css +0 -49
  151. data/vendor/gems/haml-2.1.0/test/sass/results/mixins.css +0 -95
  152. data/vendor/gems/haml-2.1.0/test/sass/results/multiline.css +0 -24
  153. data/vendor/gems/haml-2.1.0/test/sass/results/nested.css +0 -22
  154. data/vendor/gems/haml-2.1.0/test/sass/results/parent_ref.css +0 -13
  155. data/vendor/gems/haml-2.1.0/test/sass/results/script.css +0 -16
  156. data/vendor/gems/haml-2.1.0/test/sass/results/subdir/nested_subdir/nested_subdir.css +0 -1
  157. data/vendor/gems/haml-2.1.0/test/sass/results/subdir/subdir.css +0 -3
  158. data/vendor/gems/haml-2.1.0/test/sass/results/units.css +0 -11
  159. data/vendor/gems/haml-2.1.0/test/sass/script_test.rb +0 -153
  160. data/vendor/gems/haml-2.1.0/test/sass/templates/_partial.sass +0 -2
  161. data/vendor/gems/haml-2.1.0/test/sass/templates/alt.sass +0 -16
  162. data/vendor/gems/haml-2.1.0/test/sass/templates/basic.sass +0 -23
  163. data/vendor/gems/haml-2.1.0/test/sass/templates/bork.sass +0 -2
  164. data/vendor/gems/haml-2.1.0/test/sass/templates/bork2.sass +0 -2
  165. data/vendor/gems/haml-2.1.0/test/sass/templates/compact.sass +0 -17
  166. data/vendor/gems/haml-2.1.0/test/sass/templates/complex.sass +0 -309
  167. data/vendor/gems/haml-2.1.0/test/sass/templates/compressed.sass +0 -15
  168. data/vendor/gems/haml-2.1.0/test/sass/templates/expanded.sass +0 -17
  169. data/vendor/gems/haml-2.1.0/test/sass/templates/import.sass +0 -11
  170. data/vendor/gems/haml-2.1.0/test/sass/templates/importee.sass +0 -19
  171. data/vendor/gems/haml-2.1.0/test/sass/templates/line_numbers.sass +0 -13
  172. data/vendor/gems/haml-2.1.0/test/sass/templates/mixins.sass +0 -76
  173. data/vendor/gems/haml-2.1.0/test/sass/templates/multiline.sass +0 -20
  174. data/vendor/gems/haml-2.1.0/test/sass/templates/nested.sass +0 -25
  175. data/vendor/gems/haml-2.1.0/test/sass/templates/parent_ref.sass +0 -25
  176. data/vendor/gems/haml-2.1.0/test/sass/templates/script.sass +0 -101
  177. data/vendor/gems/haml-2.1.0/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +0 -2
  178. data/vendor/gems/haml-2.1.0/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +0 -3
  179. data/vendor/gems/haml-2.1.0/test/sass/templates/subdir/subdir.sass +0 -6
  180. data/vendor/gems/haml-2.1.0/test/sass/templates/units.sass +0 -11
  181. data/vendor/gems/haml-2.1.0/test/test_helper.rb +0 -21
@@ -1,388 +0,0 @@
1
- require File.dirname(__FILE__) + '/../sass'
2
- require 'sass/tree/node'
3
- require 'strscan'
4
-
5
- module Sass
6
- # :stopdoc:
7
- module Tree
8
- class Node
9
- def to_sass(opts = {})
10
- result = ''
11
-
12
- children.each do |child|
13
- result << "#{child.to_sass(0, opts)}\n"
14
- end
15
-
16
- result
17
- end
18
- end
19
-
20
- class RuleNode
21
- def to_sass(tabs, opts = {})
22
- str = "\n#{' ' * tabs}#{rule}#{children.any? { |c| c.is_a? AttrNode } ? "\n" : ''}"
23
-
24
- children.each do |child|
25
- str << "#{child.to_sass(tabs + 1, opts)}"
26
- end
27
-
28
- str
29
- end
30
- end
31
-
32
- class AttrNode
33
- def to_sass(tabs, opts = {})
34
- "#{' ' * tabs}#{opts[:alternate] ? '' : ':'}#{name}#{opts[:alternate] ? ':' : ''} #{value}\n"
35
- end
36
- end
37
-
38
- class DirectiveNode
39
- def to_sass(tabs, opts = {})
40
- "#{' ' * tabs}#{value}#{children.map {|c| c.to_sass(tabs + 1, opts)}}\n"
41
- end
42
- end
43
- end
44
-
45
- # This class is based on the Ruby 1.9 ordered hashes.
46
- # It keeps the semantics and most of the efficiency of normal hashes
47
- # while also keeping track of the order in which elements were set.
48
- class OrderedHash
49
- Node = Struct.new(:key, :value, :next, :prev)
50
- include Enumerable
51
-
52
- def initialize
53
- @hash = {}
54
- end
55
-
56
- def initialize_copy(other)
57
- @hash = other.instance_variable_get('@hash').clone
58
- end
59
-
60
- def [](key)
61
- @hash[key] && @hash[key].value
62
- end
63
-
64
- def []=(key, value)
65
- node = Node.new(key, value)
66
-
67
- if old = @hash[key]
68
- if old.prev
69
- old.prev.next = old.next
70
- else # old is @first and @last
71
- @first = @last = nil
72
- end
73
- end
74
-
75
- if @first.nil?
76
- @first = @last = node
77
- else
78
- node.prev = @last
79
- @last.next = node
80
- @last = node
81
- end
82
-
83
- @hash[key] = node
84
- value
85
- end
86
-
87
- def each
88
- return unless @first
89
- yield [@first.key, @first.value]
90
- node = @first
91
- yield [node.key, node.value] while node = node.next
92
- self
93
- end
94
-
95
- def values
96
- self.map { |k, v| v }
97
- end
98
- end
99
-
100
- # :startdoc:
101
-
102
- # This class contains the functionality used in the +css2sass+ utility,
103
- # namely converting CSS documents to Sass templates.
104
- class CSS
105
-
106
- # Creates a new instance of Sass::CSS that will compile the given document
107
- # to a Sass string when +render+ is called.
108
- def initialize(template, options = {})
109
- if template.is_a? IO
110
- template = template.read
111
- end
112
-
113
- @options = options
114
- @template = StringScanner.new(template)
115
- end
116
-
117
- # Processes the document and returns the result as a string
118
- # containing the CSS template.
119
- def render
120
- begin
121
- build_tree.to_sass(@options).strip + "\n"
122
- rescue Exception => err
123
- line = @template.string[0...@template.pos].split("\n").size
124
-
125
- err.backtrace.unshift "(css):#{line}"
126
- raise err
127
- end
128
- end
129
-
130
- private
131
-
132
- def build_tree
133
- root = Tree::Node.new({})
134
- whitespace
135
- rules root
136
- expand_commas root
137
- parent_ref_rules root
138
- remove_parent_refs root
139
- flatten_rules root
140
- fold_commas root
141
- root
142
- end
143
-
144
- def rules(root)
145
- while r = rule
146
- root << r
147
- whitespace
148
- end
149
- end
150
-
151
- def rule
152
- return unless rule = @template.scan(/[^\{\};]+/)
153
- rule.strip!
154
- directive = rule[0] == ?@
155
-
156
- if directive
157
- node = Tree::DirectiveNode.new(rule, {})
158
- return node if @template.scan(/;/)
159
-
160
- assert_match /\{/
161
- whitespace
162
-
163
- rules(node)
164
- return node
165
- end
166
-
167
- assert_match /\{/
168
- node = Tree::RuleNode.new(rule, {})
169
- attributes(node)
170
- return node
171
- end
172
-
173
- def attributes(rule)
174
- while @template.scan(/[^:\}\s]+/)
175
- name = @template[0]
176
- whitespace
177
-
178
- assert_match /:/
179
-
180
- value = ''
181
- while @template.scan(/[^;\s\}]+/)
182
- value << @template[0] << whitespace
183
- end
184
-
185
- assert_match /(;|(?=\}))/
186
- rule << Tree::AttrNode.new(name, value, {})
187
- end
188
-
189
- assert_match /\}/
190
- end
191
-
192
- def whitespace
193
- space = @template.scan(/\s*/) || ''
194
-
195
- # If we've hit a comment,
196
- # go past it and look for more whitespace
197
- if @template.scan(/\/\*/)
198
- @template.scan_until(/\*\//)
199
- return space + whitespace
200
- end
201
- return space
202
- end
203
-
204
- def assert_match(re)
205
- if !@template.scan(re)
206
- line = @template.string[0..@template.pos].count "\n"
207
- # Display basic regexps as plain old strings
208
- expected = re.source == Regexp.escape(re.source) ? "\"#{re.source}\"" : re.inspect
209
- raise Exception.new("Invalid CSS on line #{line}: expected #{expected}")
210
- end
211
- whitespace
212
- end
213
-
214
- # Transform
215
- #
216
- # foo, bar, baz
217
- # color: blue
218
- #
219
- # into
220
- #
221
- # foo
222
- # color: blue
223
- # bar
224
- # color: blue
225
- # baz
226
- # color: blue
227
- #
228
- # Yes, this expands the amount of code,
229
- # but it's necessary to get nesting to work properly.
230
- def expand_commas(root)
231
- root.children.map! do |child|
232
- next child unless Tree::RuleNode === child && child.rule.include?(',')
233
- child.rule.split(',').map do |rule|
234
- node = Tree::RuleNode.new(rule.strip, {})
235
- node.children = child.children
236
- node
237
- end
238
- end
239
- root.children.flatten!
240
- end
241
-
242
- # Make rules use parent refs so that
243
- #
244
- # foo
245
- # color: green
246
- # foo.bar
247
- # color: blue
248
- #
249
- # becomes
250
- #
251
- # foo
252
- # color: green
253
- # &.bar
254
- # color: blue
255
- #
256
- # This has the side effect of nesting rules,
257
- # so that
258
- #
259
- # foo
260
- # color: green
261
- # foo bar
262
- # color: red
263
- # foo baz
264
- # color: blue
265
- #
266
- # becomes
267
- #
268
- # foo
269
- # color: green
270
- # & bar
271
- # color: red
272
- # & baz
273
- # color: blue
274
- #
275
- def parent_ref_rules(root)
276
- rules = OrderedHash.new
277
- root.children.select { |c| Tree::RuleNode === c }.each do |child|
278
- root.children.delete child
279
- first, rest = child.rule.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
280
- rules[first] ||= Tree::RuleNode.new(first, {})
281
- if rest
282
- child.rule = "&" + rest
283
- rules[first] << child
284
- else
285
- rules[first].children += child.children
286
- end
287
- end
288
-
289
- rules.values.each { |v| parent_ref_rules(v) }
290
- root.children += rules.values
291
- end
292
-
293
- # Remove useless parent refs so that
294
- #
295
- # foo
296
- # & bar
297
- # color: blue
298
- #
299
- # becomes
300
- #
301
- # foo
302
- # bar
303
- # color: blue
304
- #
305
- def remove_parent_refs(root)
306
- root.children.each do |child|
307
- if child.is_a?(Tree::RuleNode)
308
- child.rule.gsub! /^& +/, ''
309
- remove_parent_refs child
310
- end
311
- end
312
- end
313
-
314
- # Flatten rules so that
315
- #
316
- # foo
317
- # bar
318
- # baz
319
- # color: red
320
- #
321
- # becomes
322
- #
323
- # foo bar baz
324
- # color: red
325
- #
326
- # and
327
- #
328
- # foo
329
- # &.bar
330
- # color: blue
331
- #
332
- # becomes
333
- #
334
- # foo.bar
335
- # color: blue
336
- #
337
- def flatten_rules(root)
338
- root.children.each { |child| flatten_rule(child) if child.is_a?(Tree::RuleNode) }
339
- end
340
-
341
- def flatten_rule(rule)
342
- while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
343
- child = rule.children.first
344
-
345
- if child.rule[0] == ?&
346
- rule.rule = child.rule.gsub /^&/, rule.rule
347
- else
348
- rule.rule = "#{rule.rule} #{child.rule}"
349
- end
350
-
351
- rule.children = child.children
352
- end
353
-
354
- flatten_rules(rule)
355
- end
356
-
357
- # Transform
358
- #
359
- # foo
360
- # bar
361
- # color: blue
362
- # baz
363
- # color: blue
364
- #
365
- # into
366
- #
367
- # foo
368
- # bar, baz
369
- # color: blue
370
- #
371
- def fold_commas(root)
372
- prev_rule = nil
373
- root.children.map! do |child|
374
- next child unless child.is_a?(Tree::RuleNode)
375
-
376
- if prev_rule && prev_rule.children == child.children
377
- prev_rule.rule << ", #{child.rule}"
378
- next nil
379
- end
380
-
381
- fold_commas(child)
382
- prev_rule = child
383
- child
384
- end
385
- root.children.compact!
386
- end
387
- end
388
- end
@@ -1,499 +0,0 @@
1
- require 'strscan'
2
- require 'sass/tree/node'
3
- require 'sass/tree/rule_node'
4
- require 'sass/tree/comment_node'
5
- require 'sass/tree/attr_node'
6
- require 'sass/tree/directive_node'
7
- require 'sass/tree/variable_node'
8
- require 'sass/tree/mixin_def_node'
9
- require 'sass/tree/mixin_node'
10
- require 'sass/tree/if_node'
11
- require 'sass/tree/while_node'
12
- require 'sass/tree/for_node'
13
- require 'sass/tree/debug_node'
14
- require 'sass/tree/file_node'
15
- require 'sass/environment'
16
- require 'sass/script'
17
- require 'sass/error'
18
- require 'haml/shared'
19
-
20
- module Sass
21
- # :stopdoc:
22
- Mixin = Struct.new(:name, :args, :environment, :tree)
23
- # :startdoc:
24
-
25
- # This is the class where all the parsing and processing of the Sass
26
- # template is done. It can be directly used by the user by creating a
27
- # new instance and calling <tt>render</tt> to render the template. For example:
28
- #
29
- # template = File.load('stylesheets/sassy.sass')
30
- # sass_engine = Sass::Engine.new(template)
31
- # output = sass_engine.render
32
- # puts output
33
- class Engine
34
- include Haml::Util
35
- Line = Struct.new(:text, :tabs, :index, :offset, :filename, :children)
36
-
37
- # The character that begins a CSS attribute.
38
- ATTRIBUTE_CHAR = ?:
39
-
40
- # The character that designates that
41
- # an attribute should be assigned to a SassScript expression.
42
- SCRIPT_CHAR = ?=
43
-
44
- # The character that designates the beginning of a comment,
45
- # either Sass or CSS.
46
- COMMENT_CHAR = ?/
47
-
48
- # The character that follows the general COMMENT_CHAR and designates a Sass comment,
49
- # which is not output as a CSS comment.
50
- SASS_COMMENT_CHAR = ?/
51
-
52
- # The character that follows the general COMMENT_CHAR and designates a CSS comment,
53
- # which is embedded in the CSS document.
54
- CSS_COMMENT_CHAR = ?*
55
-
56
- # The character used to denote a compiler directive.
57
- DIRECTIVE_CHAR = ?@
58
-
59
- # Designates a non-parsed rule.
60
- ESCAPE_CHAR = ?\\
61
-
62
- # Designates block as mixin definition rather than CSS rules to output
63
- MIXIN_DEFINITION_CHAR = ?=
64
-
65
- # Includes named mixin declared using MIXIN_DEFINITION_CHAR
66
- MIXIN_INCLUDE_CHAR = ?+
67
-
68
- # The regex that matches and extracts data from
69
- # attributes of the form <tt>:name attr</tt>.
70
- ATTRIBUTE = /^:([^\s=:]+)\s*(=?)(?:\s+|$)(.*)/
71
-
72
- # The regex that matches attributes of the form <tt>name: attr</tt>.
73
- ATTRIBUTE_ALTERNATE_MATCHER = /^[^\s:]+\s*[=:](\s|$)/
74
-
75
- # The regex that matches and extracts data from
76
- # attributes of the form <tt>name: attr</tt>.
77
- ATTRIBUTE_ALTERNATE = /^([^\s=:]+)(\s*=|:)(?:\s+|$)(.*)/
78
-
79
- # Creates a new instace of Sass::Engine that will compile the given
80
- # template string when <tt>render</tt> is called.
81
- # See README.rdoc for available options.
82
- #
83
- #--
84
- #
85
- # TODO: Add current options to REFRENCE. Remember :filename!
86
- #
87
- # When adding options, remember to add information about them
88
- # to README.rdoc!
89
- #++
90
- #
91
- def initialize(template, options={})
92
- @options = {
93
- :style => :nested,
94
- :load_paths => ['.']
95
- }.merge! options
96
- @template = template
97
- @environment = Environment.new
98
- @environment.set_var("important", Script::String.new("!important"))
99
- end
100
-
101
- # Processes the template and returns the result as a string.
102
- def render
103
- begin
104
- render_to_tree.perform(@environment).to_s
105
- rescue SyntaxError => err
106
- err.sass_line = @line unless err.sass_line
107
- unless err.sass_filename
108
- err.add_backtrace_entry(@options[:filename])
109
- end
110
- raise err
111
- end
112
- end
113
-
114
- alias_method :to_css, :render
115
-
116
- protected
117
-
118
- def environment
119
- @environment
120
- end
121
-
122
- def render_to_tree
123
- root = Tree::Node.new(@options)
124
- append_children(root, tree(tabulate(@template)).first, true)
125
- root
126
- end
127
-
128
- private
129
-
130
- def tabulate(string)
131
- tab_str = nil
132
- first = true
133
- enum_with_index(string.gsub(/\r|\n|\r\n|\r\n/, "\n").scan(/^.*?$/)).map do |line, index|
134
- index += 1
135
- next if line.strip.empty?
136
-
137
- line_tab_str = line[/^\s*/]
138
- unless line_tab_str.empty?
139
- tab_str ||= line_tab_str
140
-
141
- raise SyntaxError.new("Indenting at the beginning of the document is illegal.", index) if first
142
- if tab_str.include?(?\s) && tab_str.include?(?\t)
143
- raise SyntaxError.new("Indentation can't use both tabs and spaces.", index)
144
- end
145
- end
146
- first &&= !tab_str.nil?
147
- next Line.new(line.strip, 0, index, 0, @options[:filename], []) if tab_str.nil?
148
-
149
- line_tabs = line_tab_str.scan(tab_str).size
150
- raise SyntaxError.new(<<END.strip.gsub("\n", ' '), index) if tab_str * line_tabs != line_tab_str
151
- Inconsistent indentation: #{Haml::Shared.human_indentation line_tab_str, true} used for indentation,
152
- but the rest of the document was indented using #{Haml::Shared.human_indentation tab_str}.
153
- END
154
- Line.new(line.strip, line_tabs, index, tab_str.size, @options[:filename], [])
155
- end.compact
156
- end
157
-
158
- def tree(arr, i = 0)
159
- return [], i if arr[i].nil?
160
-
161
- base = arr[i].tabs
162
- nodes = []
163
- while (line = arr[i]) && line.tabs >= base
164
- if line.tabs > base
165
- if line.tabs > base + 1
166
- raise SyntaxError.new("The line was indented #{line.tabs - base} levels deeper than the previous line.", line.index)
167
- end
168
-
169
- nodes.last.children, i = tree(arr, i)
170
- else
171
- nodes << line
172
- i += 1
173
- end
174
- end
175
- return nodes, i
176
- end
177
-
178
- def build_tree(parent, line, root = false)
179
- @line = line.index
180
- node = parse_line(parent, line, root)
181
-
182
- # Node is a symbol if it's non-outputting, like a variable assignment,
183
- # or an array if it's a group of nodes to add
184
- return node unless node.is_a? Tree::Node
185
-
186
- node.line = line.index
187
- node.filename = line.filename
188
-
189
- unless node.is_a?(Tree::CommentNode)
190
- append_children(node, line.children, false)
191
- else
192
- node.children = line.children
193
- end
194
- return node
195
- end
196
-
197
- def append_children(parent, children, root)
198
- continued_rule = nil
199
- children.each do |line|
200
- child = build_tree(parent, line, root)
201
-
202
- if child.is_a?(Tree::RuleNode) && child.continued?
203
- raise SyntaxError.new("Rules can't end in commas.", child.line) unless child.children.empty?
204
- if continued_rule
205
- continued_rule.add_rules child
206
- else
207
- continued_rule = child
208
- end
209
- next
210
- end
211
-
212
- if continued_rule
213
- raise SyntaxError.new("Rules can't end in commas.", continued_rule.line) unless child.is_a?(Tree::RuleNode)
214
- continued_rule.add_rules child
215
- continued_rule.children = child.children
216
- continued_rule, child = nil, continued_rule
217
- end
218
-
219
- validate_and_append_child(parent, child, line, root)
220
- end
221
-
222
- raise SyntaxError.new("Rules can't end in commas.", continued_rule.line) if continued_rule
223
-
224
- parent
225
- end
226
-
227
- def validate_and_append_child(parent, child, line, root)
228
- unless root
229
- case child
230
- when Tree::MixinDefNode
231
- raise SyntaxError.new("Mixins may only be defined at the root of a document.", line.index)
232
- when Tree::DirectiveNode
233
- raise SyntaxError.new("Import directives may only be used at the root of a document.", line.index)
234
- end
235
- end
236
-
237
- case child
238
- when Array
239
- child.each {|c| validate_and_append_child(parent, c, line, root)}
240
- when Tree::Node
241
- parent << child
242
- end
243
- end
244
-
245
- def parse_line(parent, line, root)
246
- case line.text[0]
247
- when ATTRIBUTE_CHAR
248
- if line.text[1] != ATTRIBUTE_CHAR
249
- parse_attribute(line, ATTRIBUTE)
250
- else
251
- # Support CSS3-style pseudo-elements,
252
- # which begin with ::
253
- Tree::RuleNode.new(line.text, @options)
254
- end
255
- when Script::VARIABLE_CHAR
256
- parse_variable(line)
257
- when COMMENT_CHAR
258
- parse_comment(line.text)
259
- when DIRECTIVE_CHAR
260
- parse_directive(parent, line, root)
261
- when ESCAPE_CHAR
262
- Tree::RuleNode.new(line.text[1..-1], @options)
263
- when MIXIN_DEFINITION_CHAR
264
- parse_mixin_definition(line)
265
- when MIXIN_INCLUDE_CHAR
266
- if line.text[1].nil?
267
- Tree::RuleNode.new(line.text, @options)
268
- else
269
- parse_mixin_include(line, root)
270
- end
271
- else
272
- if line.text =~ ATTRIBUTE_ALTERNATE_MATCHER
273
- parse_attribute(line, ATTRIBUTE_ALTERNATE)
274
- else
275
- Tree::RuleNode.new(line.text, @options)
276
- end
277
- end
278
- end
279
-
280
- def parse_attribute(line, attribute_regx)
281
- if @options[:attribute_syntax] == :normal &&
282
- attribute_regx == ATTRIBUTE_ALTERNATE
283
- raise SyntaxError.new("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.")
284
- elsif @options[:attribute_syntax] == :alternate &&
285
- attribute_regx == ATTRIBUTE
286
- raise SyntaxError.new("Illegal attribute syntax: can't use normal syntax when :attribute_syntax => :alternate is set.")
287
- end
288
-
289
- name, eq, value = line.text.scan(attribute_regx)[0]
290
-
291
- if name.nil? || value.nil?
292
- raise SyntaxError.new("Invalid attribute: \"#{line.text}\".", @line)
293
- end
294
- expr = if (eq.strip[0] == SCRIPT_CHAR)
295
- parse_script(value, :offset => line.offset + line.text.index(value))
296
- else
297
- value
298
- end
299
- Tree::AttrNode.new(name, expr, @options)
300
- end
301
-
302
- def parse_variable(line)
303
- name, op, value = line.text.scan(Script::MATCH)[0]
304
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.", @line + 1) unless line.children.empty?
305
- raise SyntaxError.new("Invalid variable: \"#{line.text}\".", @line) unless name && value
306
-
307
- Tree::VariableNode.new(name, parse_script(value, :offset => line.offset + line.text.index(value)), op == '||=', @options)
308
- end
309
-
310
- def parse_comment(line)
311
- if line[1] == CSS_COMMENT_CHAR || line[1] == SASS_COMMENT_CHAR
312
- Tree::CommentNode.new(line, @options.merge(:silent => (line[1] == SASS_COMMENT_CHAR)))
313
- else
314
- Tree::RuleNode.new(line, @options)
315
- end
316
- end
317
-
318
- def parse_directive(parent, line, root)
319
- directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
320
- offset = directive.size + whitespace.size + 1 if whitespace
321
-
322
- # If value begins with url( or ",
323
- # it's a CSS @import rule and we don't want to touch it.
324
- if directive == "import" && value !~ /^(url\(|")/
325
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.", @line + 1) unless line.children.empty?
326
- import(value)
327
- elsif directive == "for"
328
- parse_for(line, root, value)
329
- elsif directive == "else"
330
- parse_else(parent, line, value)
331
- elsif directive == "while"
332
- raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
333
- Tree::WhileNode.new(parse_script(value, :offset => offset), @options)
334
- elsif directive == "if"
335
- raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
336
- Tree::IfNode.new(parse_script(value, :offset => offset), @options)
337
- elsif directive == "debug"
338
- raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
339
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.", @line + 1) unless line.children.empty?
340
- offset = line.offset + line.text.index(value).to_i
341
- Tree::DebugNode.new(parse_script(value, :offset => offset), @options)
342
- else
343
- Tree::DirectiveNode.new(line.text, @options)
344
- end
345
- end
346
-
347
- def parse_for(line, root, text)
348
- var, from_expr, to_name, to_expr = text.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
349
-
350
- if var.nil? # scan failed, try to figure out why for error message
351
- if text !~ /^[^\s]+/
352
- expected = "variable name"
353
- elsif text !~ /^[^\s]+\s+from\s+.+/
354
- expected = "'from <expr>'"
355
- else
356
- expected = "'to <expr>' or 'through <expr>'"
357
- end
358
- raise SyntaxError.new("Invalid for directive '@for #{text}': expected #{expected}.", @line)
359
- end
360
- raise SyntaxError.new("Invalid variable \"#{var}\".", @line) unless var =~ Script::VALIDATE
361
-
362
- parsed_from = parse_script(from_expr, :offset => line.offset + line.text.index(from_expr))
363
- parsed_to = parse_script(to_expr, :offset => line.offset + line.text.index(to_expr))
364
- Tree::ForNode.new(var[1..-1], parsed_from, parsed_to, to_name == 'to', @options)
365
- end
366
-
367
- def parse_else(parent, line, text)
368
- previous = parent.last
369
- raise SyntaxError.new("@else must come after @if.") unless previous.is_a?(Tree::IfNode)
370
-
371
- if text
372
- if text !~ /^if\s+(.+)/
373
- raise SyntaxError.new("Invalid else directive '@else #{text}': expected 'if <expr>'.", @line)
374
- end
375
- expr = parse_script($1, :offset => line.offset + line.text.index($1))
376
- end
377
-
378
- node = Tree::IfNode.new(expr, @options)
379
- append_children(node, line.children, false)
380
- previous.add_else node
381
- nil
382
- end
383
-
384
- # parses out the arguments between the commas and cleans up the mixin arguments
385
- # returns nil if it fails to parse, otherwise an array.
386
- def parse_mixin_arguments(arg_string)
387
- arg_string = arg_string.strip
388
- return [] if arg_string.empty?
389
- return nil unless (arg_string[0] == ?( && arg_string[-1] == ?))
390
- arg_string = arg_string[1...-1]
391
- arg_string.split(",", -1).map {|a| a.strip}
392
- end
393
-
394
- def parse_mixin_definition(line)
395
- name, arg_string = line.text.scan(/^=\s*([^(]+)(.*)$/).first
396
- args = parse_mixin_arguments(arg_string)
397
- raise SyntaxError.new("Invalid mixin \"#{line.text[1..-1]}\".", @line) if name.nil? || args.nil?
398
- default_arg_found = false
399
- required_arg_count = 0
400
- args.map! do |arg|
401
- raise SyntaxError.new("Mixin arguments can't be empty.", @line) if arg.empty? || arg == "!"
402
- unless arg[0] == Script::VARIABLE_CHAR
403
- raise SyntaxError.new("Mixin argument \"#{arg}\" must begin with an exclamation point (!).", @line)
404
- end
405
- arg, default = arg.split(/\s*=\s*/, 2)
406
- required_arg_count += 1 unless default
407
- default_arg_found ||= default
408
- raise SyntaxError.new("Invalid variable \"#{arg}\".", @line) unless arg =~ Script::VALIDATE
409
- raise SyntaxError.new("Required arguments must not follow optional arguments \"#{arg}\".", @line) if default_arg_found && !default
410
- default = parse_script(default, :offset => line.offset + line.text.index(default)) if default
411
- { :name => arg[1..-1], :default_value => default }
412
- end
413
- Tree::MixinDefNode.new(name, args, @options)
414
- end
415
-
416
- def parse_mixin_include(line, root)
417
- name, arg_string = line.text.scan(/^\+\s*([^(]+)(.*)$/).first
418
- args = parse_mixin_arguments(arg_string)
419
- raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath mixin directives.", @line + 1) unless line.children.empty?
420
- raise SyntaxError.new("Invalid mixin include \"#{line.text}\".", @line) if name.nil? || args.nil?
421
- args.each {|a| raise SyntaxError.new("Mixin arguments can't be empty.", @line) if a.empty?}
422
-
423
- Tree::MixinNode.new(name, args.map {|s| parse_script(s, :offset => line.offset + line.text.index(s))}, @options)
424
- end
425
-
426
- def parse_script(script, options = {})
427
- line = options[:line] || @line
428
- offset = options[:offset] || 0
429
- Script.parse(script, line, offset, @options[:filename])
430
- end
431
-
432
- def import_paths
433
- paths = @options[:load_paths] || []
434
- paths.unshift(File.dirname(@options[:filename])) if @options[:filename]
435
- paths
436
- end
437
-
438
- def import(files)
439
- files.split(/,\s*/).map do |filename|
440
- engine = nil
441
-
442
- begin
443
- filename = self.class.find_file_to_import(filename, import_paths)
444
- rescue Exception => e
445
- raise SyntaxError.new(e.message, @line)
446
- end
447
-
448
- next Tree::DirectiveNode.new("@import url(#{filename})", @options) if filename =~ /\.css$/
449
-
450
- File.open(filename) do |file|
451
- new_options = @options.dup
452
- new_options[:filename] = filename
453
- engine = Sass::Engine.new(file.read, new_options)
454
- end
455
-
456
- begin
457
- root = engine.render_to_tree
458
- rescue Sass::SyntaxError => err
459
- err.add_backtrace_entry(filename)
460
- raise err
461
- end
462
- Tree::FileNode.new(filename, root.children, @options)
463
- end.flatten
464
- end
465
-
466
- def self.find_file_to_import(filename, load_paths)
467
- was_sass = false
468
- original_filename = filename
469
-
470
- if filename[-5..-1] == ".sass"
471
- filename = filename[0...-5]
472
- was_sass = true
473
- elsif filename[-4..-1] == ".css"
474
- return filename
475
- end
476
-
477
- new_filename = find_full_path("#{filename}.sass", load_paths)
478
-
479
- return new_filename if new_filename
480
- return filename + '.css' unless was_sass
481
- raise SyntaxError.new("File to import not found or unreadable: #{original_filename}.", @line)
482
- end
483
-
484
- def self.find_full_path(filename, load_paths)
485
- segments = filename.split(File::SEPARATOR)
486
- segments.push "_#{segments.pop}"
487
- partial_name = segments.join(File::SEPARATOR)
488
- load_paths.each do |path|
489
- [partial_name, filename].each do |name|
490
- full_path = File.join(path, name)
491
- if File.readable?(full_path)
492
- return full_path
493
- end
494
- end
495
- end
496
- nil
497
- end
498
- end
499
- end