radiant 0.6.6 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of radiant might be problematic. Click here for more details.
- data/CHANGELOG +15 -0
- data/CONTRIBUTORS +8 -0
- data/app/controllers/admin/page_controller.rb +1 -11
- data/app/controllers/admin/welcome_controller.rb +5 -6
- data/app/controllers/application.rb +2 -0
- data/app/controllers/site_controller.rb +1 -0
- data/app/helpers/admin/page_helper.rb +36 -0
- data/app/helpers/admin/regions_helper.rb +28 -0
- data/app/helpers/admin/user_helper.rb +6 -0
- data/app/helpers/application_helper.rb +2 -1
- data/app/models/user.rb +7 -8
- data/app/views/admin/extension/index.html.haml +28 -0
- data/app/views/admin/layout/edit.html.haml +44 -0
- data/app/views/admin/layout/index.html.haml +25 -0
- data/app/views/admin/layout/remove.html.haml +16 -0
- data/app/views/admin/page/_meta_row.html.haml +6 -0
- data/app/views/admin/page/_node.html.haml +25 -0
- data/app/views/admin/page/_part.html.haml +17 -0
- data/app/views/admin/page/_tag_reference.html.haml +3 -0
- data/app/views/admin/page/children.html.haml +2 -0
- data/app/views/admin/page/edit.html.haml +114 -0
- data/app/views/admin/page/index.html.haml +28 -0
- data/app/views/admin/page/remove.html.haml +20 -0
- data/app/views/admin/snippet/edit.html.haml +36 -0
- data/app/views/admin/snippet/index.html.haml +20 -0
- data/app/views/admin/snippet/remove.html.haml +19 -0
- data/app/views/admin/user/edit.html.haml +80 -0
- data/app/views/admin/user/index.html.haml +23 -0
- data/app/views/admin/user/preferences.html.haml +28 -0
- data/app/views/admin/user/remove.html.haml +18 -0
- data/app/views/admin/welcome/login.html.haml +44 -0
- data/app/views/layouts/application.html.haml +54 -0
- data/app/views/site/not_found.html.haml +3 -0
- data/db/migrate/019_add_salt_to_users.rb +11 -0
- data/db/schema.rb +2 -1
- data/lib/login_system.rb +1 -0
- data/lib/radiant.rb +1 -1
- data/lib/radiant/admin_ui.rb +65 -0
- data/lib/radiant/admin_ui/region_partials.rb +18 -0
- data/lib/radiant/admin_ui/region_set.rb +35 -0
- data/lib/tasks/extensions.rake +33 -0
- data/public/javascripts/admin/admin.js +8 -2
- data/public/javascripts/admin/sitemap.js +2 -1
- data/public/stylesheets/admin/main.css +4 -0
- data/spec/controllers/admin/abstract_model_controller_spec.rb +2 -0
- data/spec/controllers/admin/page_controller_spec.rb +3 -28
- data/spec/controllers/admin/user_controller_spec.rb +1 -1
- data/spec/controllers/admin/welcome_controller_spec.rb +26 -0
- data/spec/helpers/admin/page_helper_spec.rb +4 -0
- data/spec/helpers/admin/regions_helper_spec.rb +47 -0
- data/spec/helpers/admin/user_helper_spec.rb +7 -0
- data/spec/helpers/application_helper_spec.rb +7 -3
- data/spec/lib/login_system_spec.rb +5 -0
- data/spec/lib/radiant/admin_ui/region_partials_spec.rb +35 -0
- data/spec/lib/radiant/admin_ui/region_set_spec.rb +61 -0
- data/spec/lib/radiant/admin_ui_spec.rb +74 -18
- data/spec/models/user_spec.rb +11 -4
- data/spec/scenarios/users_scenario.rb +2 -2
- data/vendor/plugins/haml/MIT-LICENSE +20 -0
- data/vendor/plugins/haml/README.rdoc +319 -0
- data/vendor/plugins/haml/Rakefile +158 -0
- data/vendor/plugins/haml/TODO +9 -0
- data/vendor/plugins/haml/VERSION +1 -0
- data/vendor/plugins/haml/bin/css2sass +7 -0
- data/vendor/plugins/haml/bin/haml +8 -0
- data/vendor/plugins/haml/bin/html2haml +7 -0
- data/vendor/plugins/haml/bin/sass +8 -0
- data/vendor/plugins/haml/extra/haml-mode.el +328 -0
- data/vendor/plugins/haml/extra/sass-mode.el +88 -0
- data/vendor/plugins/haml/init.rb +2 -0
- data/vendor/plugins/haml/lib/haml.rb +977 -0
- data/vendor/plugins/haml/lib/haml/buffer.rb +229 -0
- data/vendor/plugins/haml/lib/haml/engine.rb +274 -0
- data/vendor/plugins/haml/lib/haml/error.rb +23 -0
- data/vendor/plugins/haml/lib/haml/exec.rb +347 -0
- data/vendor/plugins/haml/lib/haml/filters.rb +249 -0
- data/vendor/plugins/haml/lib/haml/helpers.rb +413 -0
- data/vendor/plugins/haml/lib/haml/helpers/action_view_extensions.rb +45 -0
- data/vendor/plugins/haml/lib/haml/helpers/action_view_mods.rb +122 -0
- data/vendor/plugins/haml/lib/haml/html.rb +188 -0
- data/vendor/plugins/haml/lib/haml/precompiler.rb +757 -0
- data/vendor/plugins/haml/lib/haml/template.rb +43 -0
- data/vendor/plugins/haml/lib/haml/template/patch.rb +58 -0
- data/vendor/plugins/haml/lib/haml/template/plugin.rb +72 -0
- data/vendor/plugins/haml/lib/sass.rb +833 -0
- data/vendor/plugins/haml/lib/sass/constant.rb +245 -0
- data/vendor/plugins/haml/lib/sass/constant/color.rb +101 -0
- data/vendor/plugins/haml/lib/sass/constant/literal.rb +53 -0
- data/vendor/plugins/haml/lib/sass/constant/number.rb +87 -0
- data/vendor/plugins/haml/lib/sass/constant/operation.rb +30 -0
- data/vendor/plugins/haml/lib/sass/constant/string.rb +22 -0
- data/vendor/plugins/haml/lib/sass/css.rb +378 -0
- data/vendor/plugins/haml/lib/sass/engine.rb +459 -0
- data/vendor/plugins/haml/lib/sass/error.rb +35 -0
- data/vendor/plugins/haml/lib/sass/plugin.rb +165 -0
- data/vendor/plugins/haml/lib/sass/plugin/merb.rb +56 -0
- data/vendor/plugins/haml/lib/sass/plugin/rails.rb +24 -0
- data/vendor/plugins/haml/lib/sass/tree/attr_node.rb +53 -0
- data/vendor/plugins/haml/lib/sass/tree/comment_node.rb +20 -0
- data/vendor/plugins/haml/lib/sass/tree/directive_node.rb +46 -0
- data/vendor/plugins/haml/lib/sass/tree/node.rb +42 -0
- data/vendor/plugins/haml/lib/sass/tree/rule_node.rb +89 -0
- data/vendor/plugins/haml/lib/sass/tree/value_node.rb +16 -0
- data/vendor/plugins/haml/test/benchmark.rb +82 -0
- data/vendor/plugins/haml/test/haml/engine_test.rb +587 -0
- data/vendor/plugins/haml/test/haml/helper_test.rb +187 -0
- data/vendor/plugins/haml/test/haml/html2haml_test.rb +60 -0
- data/vendor/plugins/haml/test/haml/markaby/standard.mab +52 -0
- data/vendor/plugins/haml/test/haml/mocks/article.rb +6 -0
- data/vendor/plugins/haml/test/haml/results/content_for_layout.xhtml +16 -0
- data/vendor/plugins/haml/test/haml/results/eval_suppressed.xhtml +11 -0
- data/vendor/plugins/haml/test/haml/results/filters.xhtml +82 -0
- data/vendor/plugins/haml/test/haml/results/helpers.xhtml +94 -0
- data/vendor/plugins/haml/test/haml/results/helpful.xhtml +10 -0
- data/vendor/plugins/haml/test/haml/results/just_stuff.xhtml +64 -0
- data/vendor/plugins/haml/test/haml/results/list.xhtml +12 -0
- data/vendor/plugins/haml/test/haml/results/original_engine.xhtml +22 -0
- data/vendor/plugins/haml/test/haml/results/partials.xhtml +21 -0
- data/vendor/plugins/haml/test/haml/results/silent_script.xhtml +74 -0
- data/vendor/plugins/haml/test/haml/results/standard.xhtml +42 -0
- data/vendor/plugins/haml/test/haml/results/tag_parsing.xhtml +28 -0
- data/vendor/plugins/haml/test/haml/results/very_basic.xhtml +7 -0
- data/vendor/plugins/haml/test/haml/results/whitespace_handling.xhtml +94 -0
- data/vendor/plugins/haml/test/haml/rhtml/_av_partial_1.rhtml +12 -0
- data/vendor/plugins/haml/test/haml/rhtml/_av_partial_2.rhtml +8 -0
- data/vendor/plugins/haml/test/haml/rhtml/action_view.rhtml +62 -0
- data/vendor/plugins/haml/test/haml/rhtml/standard.rhtml +54 -0
- data/vendor/plugins/haml/test/haml/template_test.rb +168 -0
- data/vendor/plugins/haml/test/haml/templates/_av_partial_1.haml +9 -0
- data/vendor/plugins/haml/test/haml/templates/_av_partial_2.haml +5 -0
- data/vendor/plugins/haml/test/haml/templates/_partial.haml +8 -0
- data/vendor/plugins/haml/test/haml/templates/_text_area.haml +3 -0
- data/vendor/plugins/haml/test/haml/templates/action_view.haml +47 -0
- data/vendor/plugins/haml/test/haml/templates/breakage.haml +8 -0
- data/vendor/plugins/haml/test/haml/templates/content_for_layout.haml +10 -0
- data/vendor/plugins/haml/test/haml/templates/eval_suppressed.haml +11 -0
- data/vendor/plugins/haml/test/haml/templates/filters.haml +81 -0
- data/vendor/plugins/haml/test/haml/templates/helpers.haml +69 -0
- data/vendor/plugins/haml/test/haml/templates/helpful.haml +11 -0
- data/vendor/plugins/haml/test/haml/templates/just_stuff.haml +77 -0
- data/vendor/plugins/haml/test/haml/templates/list.haml +12 -0
- data/vendor/plugins/haml/test/haml/templates/original_engine.haml +17 -0
- data/vendor/plugins/haml/test/haml/templates/partialize.haml +1 -0
- data/vendor/plugins/haml/test/haml/templates/partials.haml +12 -0
- data/vendor/plugins/haml/test/haml/templates/silent_script.haml +40 -0
- data/vendor/plugins/haml/test/haml/templates/standard.haml +42 -0
- data/vendor/plugins/haml/test/haml/templates/tag_parsing.haml +24 -0
- data/vendor/plugins/haml/test/haml/templates/very_basic.haml +4 -0
- data/vendor/plugins/haml/test/haml/templates/whitespace_handling.haml +87 -0
- data/vendor/plugins/haml/test/haml/test_helper.rb +15 -0
- data/vendor/plugins/haml/test/profile.rb +65 -0
- data/vendor/plugins/haml/test/sass/engine_test.rb +276 -0
- data/vendor/plugins/haml/test/sass/plugin_test.rb +159 -0
- data/vendor/plugins/haml/test/sass/results/alt.css +4 -0
- data/vendor/plugins/haml/test/sass/results/basic.css +9 -0
- data/vendor/plugins/haml/test/sass/results/compact.css +5 -0
- data/vendor/plugins/haml/test/sass/results/complex.css +87 -0
- data/vendor/plugins/haml/test/sass/results/compressed.css +1 -0
- data/vendor/plugins/haml/test/sass/results/constants.css +14 -0
- data/vendor/plugins/haml/test/sass/results/expanded.css +19 -0
- data/vendor/plugins/haml/test/sass/results/import.css +29 -0
- data/vendor/plugins/haml/test/sass/results/mixins.css +95 -0
- data/vendor/plugins/haml/test/sass/results/multiline.css +24 -0
- data/vendor/plugins/haml/test/sass/results/nested.css +22 -0
- data/vendor/plugins/haml/test/sass/results/parent_ref.css +13 -0
- data/vendor/plugins/haml/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
- data/vendor/plugins/haml/test/sass/results/subdir/subdir.css +1 -0
- data/vendor/plugins/haml/test/sass/templates/_partial.sass +2 -0
- data/vendor/plugins/haml/test/sass/templates/alt.sass +16 -0
- data/vendor/plugins/haml/test/sass/templates/basic.sass +23 -0
- data/vendor/plugins/haml/test/sass/templates/bork.sass +2 -0
- data/vendor/plugins/haml/test/sass/templates/bork2.sass +2 -0
- data/vendor/plugins/haml/test/sass/templates/compact.sass +17 -0
- data/vendor/plugins/haml/test/sass/templates/complex.sass +310 -0
- data/vendor/plugins/haml/test/sass/templates/compressed.sass +15 -0
- data/vendor/plugins/haml/test/sass/templates/constants.sass +97 -0
- data/vendor/plugins/haml/test/sass/templates/expanded.sass +17 -0
- data/vendor/plugins/haml/test/sass/templates/import.sass +11 -0
- data/vendor/plugins/haml/test/sass/templates/importee.sass +14 -0
- data/vendor/plugins/haml/test/sass/templates/mixins.sass +76 -0
- data/vendor/plugins/haml/test/sass/templates/multiline.sass +20 -0
- data/vendor/plugins/haml/test/sass/templates/nested.sass +25 -0
- data/vendor/plugins/haml/test/sass/templates/parent_ref.sass +25 -0
- data/vendor/plugins/haml/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
- data/vendor/plugins/haml/test/sass/templates/subdir/subdir.sass +6 -0
- metadata +185 -24
- data/app/views/admin/extension/index.html.erb +0 -40
- data/app/views/admin/layout/edit.html.erb +0 -39
- data/app/views/admin/layout/index.html.erb +0 -38
- data/app/views/admin/layout/remove.html.erb +0 -17
- data/app/views/admin/page/_meta_row.html.erb +0 -4
- data/app/views/admin/page/_node.html.erb +0 -28
- data/app/views/admin/page/_part.html.erb +0 -13
- data/app/views/admin/page/_tag_reference.html.erb +0 -4
- data/app/views/admin/page/children.html.erb +0 -4
- data/app/views/admin/page/edit.html.erb +0 -140
- data/app/views/admin/page/index.html.erb +0 -31
- data/app/views/admin/page/remove.html.erb +0 -14
- data/app/views/admin/snippet/edit.html.erb +0 -29
- data/app/views/admin/snippet/index.html.erb +0 -36
- data/app/views/admin/snippet/remove.html.erb +0 -16
- data/app/views/admin/user/edit.html.erb +0 -54
- data/app/views/admin/user/index.html.erb +0 -43
- data/app/views/admin/user/preferences.html.erb +0 -29
- data/app/views/admin/user/remove.html.erb +0 -16
- data/app/views/admin/welcome/login.html.erb +0 -51
- data/app/views/layouts/application.html.erb +0 -83
- data/app/views/site/not_found.html.erb +0 -3
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'sass/constant/string'
|
2
|
+
require 'sass/constant/number'
|
3
|
+
require 'sass/constant/color'
|
4
|
+
|
5
|
+
module Sass::Constant # :nodoc:
|
6
|
+
class Operation # :nodoc:
|
7
|
+
def initialize(operand1, operand2, operator)
|
8
|
+
@operand1 = operand1
|
9
|
+
@operand2 = operand2
|
10
|
+
@operator = operator
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
self.perform.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def perform
|
20
|
+
literal1 = @operand1.perform
|
21
|
+
literal2 = @operand2.perform
|
22
|
+
begin
|
23
|
+
literal1.send(@operator, literal2)
|
24
|
+
rescue NoMethodError => e
|
25
|
+
raise e unless e.name.to_s == @operator.to_s
|
26
|
+
raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'sass/constant/literal'
|
2
|
+
|
3
|
+
module Sass::Constant # :nodoc:
|
4
|
+
class String < Literal # :nodoc:
|
5
|
+
|
6
|
+
def parse(value)
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def plus(other)
|
11
|
+
Sass::Constant::String.from_value(self.to_s + other.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
def funcall(other)
|
15
|
+
Sass::Constant::String.from_value("#{self.to_s}(#{other.to_s})")
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
@value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,378 @@
|
|
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 ValueNode
|
21
|
+
def to_sass(tabs)
|
22
|
+
"#{value}\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class RuleNode
|
27
|
+
def to_sass(tabs, opts = {})
|
28
|
+
str = "\n#{' ' * tabs}#{rule}#{children.any? { |c| c.is_a? AttrNode } ? "\n" : ''}"
|
29
|
+
|
30
|
+
children.each do |child|
|
31
|
+
str << "#{child.to_sass(tabs + 1, opts)}"
|
32
|
+
end
|
33
|
+
|
34
|
+
str
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class AttrNode
|
39
|
+
def to_sass(tabs, opts = {})
|
40
|
+
"#{' ' * tabs}#{opts[:alternate] ? '' : ':'}#{name}#{opts[:alternate] ? ':' : ''} #{value}\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('Node', :key, :value, :next)
|
50
|
+
include Enumerable
|
51
|
+
|
52
|
+
def initialize
|
53
|
+
@hash = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def [](key)
|
57
|
+
@hash[key] && @hash[key].value
|
58
|
+
end
|
59
|
+
|
60
|
+
def []=(key, value)
|
61
|
+
node = Node.new(key, value, nil)
|
62
|
+
if @first.nil?
|
63
|
+
@first = @last = node
|
64
|
+
else
|
65
|
+
@last.next = node
|
66
|
+
@last = node
|
67
|
+
end
|
68
|
+
@hash[key] = node
|
69
|
+
value
|
70
|
+
end
|
71
|
+
|
72
|
+
def each
|
73
|
+
return unless @first
|
74
|
+
yield [@first.key, @first.value]
|
75
|
+
node = @first
|
76
|
+
yield [node.key, node.value] while node = node.next
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def values
|
81
|
+
self.map { |k, v| v }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# :startdoc:
|
86
|
+
|
87
|
+
# This class contains the functionality used in the +css2sass+ utility,
|
88
|
+
# namely converting CSS documents to Sass templates.
|
89
|
+
class CSS
|
90
|
+
|
91
|
+
# Creates a new instance of Sass::CSS that will compile the given document
|
92
|
+
# to a Sass string when +render+ is called.
|
93
|
+
def initialize(template, options = {})
|
94
|
+
if template.is_a? IO
|
95
|
+
template = template.read
|
96
|
+
end
|
97
|
+
|
98
|
+
@options = options
|
99
|
+
@template = StringScanner.new(template)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Processes the document and returns the result as a string
|
103
|
+
# containing the CSS template.
|
104
|
+
def render
|
105
|
+
begin
|
106
|
+
build_tree.to_sass(@options).lstrip
|
107
|
+
rescue Exception => err
|
108
|
+
line = @template.string[0...@template.pos].split("\n").size
|
109
|
+
|
110
|
+
err.backtrace.unshift "(css):#{line}"
|
111
|
+
raise err
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def build_tree
|
118
|
+
root = Tree::Node.new(nil)
|
119
|
+
whitespace
|
120
|
+
directives root
|
121
|
+
rules root
|
122
|
+
expand_commas root
|
123
|
+
parent_ref_rules root
|
124
|
+
remove_parent_refs root
|
125
|
+
flatten_rules root
|
126
|
+
fold_commas root
|
127
|
+
root
|
128
|
+
end
|
129
|
+
|
130
|
+
def directives(root)
|
131
|
+
while @template.scan(/@/)
|
132
|
+
name = @template.scan /[^\s;]+/
|
133
|
+
whitespace
|
134
|
+
value = @template.scan /[^;]+/
|
135
|
+
assert_match /;/
|
136
|
+
whitespace
|
137
|
+
|
138
|
+
if name == "import" && value =~ /^(url\()?"?([^\s\(\)\"]+)\.css"?\)?$/
|
139
|
+
value = $2
|
140
|
+
end
|
141
|
+
|
142
|
+
root << Tree::ValueNode.new("@#{name} #{value};", nil)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def rules(root)
|
147
|
+
rules = []
|
148
|
+
while @template.scan(/[^\{\s]+/)
|
149
|
+
rules << @template[0]
|
150
|
+
whitespace
|
151
|
+
|
152
|
+
if @template.scan(/\{/)
|
153
|
+
result = Tree::RuleNode.new(rules.join(' '), nil)
|
154
|
+
root << result
|
155
|
+
rules = []
|
156
|
+
|
157
|
+
whitespace
|
158
|
+
attributes(result)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def attributes(rule)
|
164
|
+
while @template.scan(/[^:\}\s]+/)
|
165
|
+
name = @template[0]
|
166
|
+
whitespace
|
167
|
+
|
168
|
+
assert_match /:/
|
169
|
+
|
170
|
+
value = ''
|
171
|
+
while @template.scan(/[^;\s\}]+/)
|
172
|
+
value << @template[0] << whitespace
|
173
|
+
end
|
174
|
+
|
175
|
+
assert_match /(;|(?=\}))/
|
176
|
+
rule << Tree::AttrNode.new(name, value, nil)
|
177
|
+
end
|
178
|
+
|
179
|
+
assert_match /\}/
|
180
|
+
end
|
181
|
+
|
182
|
+
def whitespace
|
183
|
+
space = @template.scan(/\s*/) || ''
|
184
|
+
|
185
|
+
# If we've hit a comment,
|
186
|
+
# go past it and look for more whitespace
|
187
|
+
if @template.scan(/\/\*/)
|
188
|
+
@template.scan_until(/\*\//)
|
189
|
+
return space + whitespace
|
190
|
+
end
|
191
|
+
return space
|
192
|
+
end
|
193
|
+
|
194
|
+
def assert_match(re)
|
195
|
+
if !@template.scan(re)
|
196
|
+
line = @template.string[0..@template.pos].count "\n"
|
197
|
+
# Display basic regexps as plain old strings
|
198
|
+
expected = re.source == Regexp.escape(re.source) ? "\"#{re.source}\"" : re.inspect
|
199
|
+
raise Exception.new("Invalid CSS on line #{line}: expected #{expected}")
|
200
|
+
end
|
201
|
+
whitespace
|
202
|
+
end
|
203
|
+
|
204
|
+
# Transform
|
205
|
+
#
|
206
|
+
# foo, bar, baz
|
207
|
+
# color: blue
|
208
|
+
#
|
209
|
+
# into
|
210
|
+
#
|
211
|
+
# foo
|
212
|
+
# color: blue
|
213
|
+
# bar
|
214
|
+
# color: blue
|
215
|
+
# baz
|
216
|
+
# color: blue
|
217
|
+
#
|
218
|
+
# Yes, this expands the amount of code,
|
219
|
+
# but it's necessary to get nesting to work properly.
|
220
|
+
def expand_commas(root)
|
221
|
+
root.children.map! do |child|
|
222
|
+
next child unless Tree::RuleNode === child && child.rule.include?(',')
|
223
|
+
child.rule.split(',').map do |rule|
|
224
|
+
node = Tree::RuleNode.new(rule, nil)
|
225
|
+
node.children = child.children
|
226
|
+
node
|
227
|
+
end
|
228
|
+
end
|
229
|
+
root.children.flatten!
|
230
|
+
end
|
231
|
+
|
232
|
+
# Make rules use parent refs so that
|
233
|
+
#
|
234
|
+
# foo
|
235
|
+
# color: green
|
236
|
+
# foo.bar
|
237
|
+
# color: blue
|
238
|
+
#
|
239
|
+
# becomes
|
240
|
+
#
|
241
|
+
# foo
|
242
|
+
# color: green
|
243
|
+
# &.bar
|
244
|
+
# color: blue
|
245
|
+
#
|
246
|
+
# This has the side effect of nesting rules,
|
247
|
+
# so that
|
248
|
+
#
|
249
|
+
# foo
|
250
|
+
# color: green
|
251
|
+
# foo bar
|
252
|
+
# color: red
|
253
|
+
# foo baz
|
254
|
+
# color: blue
|
255
|
+
#
|
256
|
+
# becomes
|
257
|
+
#
|
258
|
+
# foo
|
259
|
+
# color: green
|
260
|
+
# & bar
|
261
|
+
# color: red
|
262
|
+
# & baz
|
263
|
+
# color: blue
|
264
|
+
#
|
265
|
+
def parent_ref_rules(root)
|
266
|
+
rules = OrderedHash.new
|
267
|
+
root.children.select { |c| Tree::RuleNode === c }.each do |child|
|
268
|
+
root.children.delete child
|
269
|
+
first, rest = child.rule.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
|
270
|
+
rules[first] ||= Tree::RuleNode.new(first, nil)
|
271
|
+
if rest
|
272
|
+
child.rule = "&" + rest
|
273
|
+
rules[first] << child
|
274
|
+
else
|
275
|
+
rules[first].children += child.children
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
rules.values.each { |v| parent_ref_rules(v) }
|
280
|
+
root.children += rules.values
|
281
|
+
end
|
282
|
+
|
283
|
+
# Remove useless parent refs so that
|
284
|
+
#
|
285
|
+
# foo
|
286
|
+
# & bar
|
287
|
+
# color: blue
|
288
|
+
#
|
289
|
+
# becomes
|
290
|
+
#
|
291
|
+
# foo
|
292
|
+
# bar
|
293
|
+
# color: blue
|
294
|
+
#
|
295
|
+
def remove_parent_refs(root)
|
296
|
+
root.children.each do |child|
|
297
|
+
if child.is_a?(Tree::RuleNode)
|
298
|
+
child.rule.gsub! /^& /, ''
|
299
|
+
remove_parent_refs child
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# Flatten rules so that
|
305
|
+
#
|
306
|
+
# foo
|
307
|
+
# bar
|
308
|
+
# baz
|
309
|
+
# color: red
|
310
|
+
#
|
311
|
+
# becomes
|
312
|
+
#
|
313
|
+
# foo bar baz
|
314
|
+
# color: red
|
315
|
+
#
|
316
|
+
# and
|
317
|
+
#
|
318
|
+
# foo
|
319
|
+
# &.bar
|
320
|
+
# color: blue
|
321
|
+
#
|
322
|
+
# becomes
|
323
|
+
#
|
324
|
+
# foo.bar
|
325
|
+
# color: blue
|
326
|
+
#
|
327
|
+
def flatten_rules(root)
|
328
|
+
root.children.each { |child| flatten_rule(child) if child.is_a?(Tree::RuleNode) }
|
329
|
+
end
|
330
|
+
|
331
|
+
def flatten_rule(rule)
|
332
|
+
while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
|
333
|
+
child = rule.children.first
|
334
|
+
|
335
|
+
if child.rule[0] == ?&
|
336
|
+
rule.rule = child.rule.gsub /^&/, rule.rule
|
337
|
+
else
|
338
|
+
rule.rule = "#{rule.rule} #{child.rule}"
|
339
|
+
end
|
340
|
+
|
341
|
+
rule.children = child.children
|
342
|
+
end
|
343
|
+
|
344
|
+
flatten_rules(rule)
|
345
|
+
end
|
346
|
+
|
347
|
+
# Transform
|
348
|
+
#
|
349
|
+
# foo
|
350
|
+
# bar
|
351
|
+
# color: blue
|
352
|
+
# baz
|
353
|
+
# color: blue
|
354
|
+
#
|
355
|
+
# into
|
356
|
+
#
|
357
|
+
# foo
|
358
|
+
# bar, baz
|
359
|
+
# color: blue
|
360
|
+
#
|
361
|
+
def fold_commas(root)
|
362
|
+
prev_rule = nil
|
363
|
+
root.children.map! do |child|
|
364
|
+
next child unless Tree::RuleNode === child
|
365
|
+
|
366
|
+
if prev_rule && prev_rule.children == child.children
|
367
|
+
prev_rule.rule << ", #{child.rule}"
|
368
|
+
next nil
|
369
|
+
end
|
370
|
+
|
371
|
+
fold_commas(child)
|
372
|
+
prev_rule = child
|
373
|
+
child
|
374
|
+
end
|
375
|
+
root.children.compact!
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
@@ -0,0 +1,459 @@
|
|
1
|
+
require 'sass/tree/node'
|
2
|
+
require 'sass/tree/value_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/constant'
|
8
|
+
require 'sass/error'
|
9
|
+
|
10
|
+
module Sass
|
11
|
+
# This is the class where all the parsing and processing of the Sass
|
12
|
+
# template is done. It can be directly used by the user by creating a
|
13
|
+
# new instance and calling <tt>render</tt> to render the template. For example:
|
14
|
+
#
|
15
|
+
# template = File.load('stylesheets/sassy.sass')
|
16
|
+
# sass_engine = Sass::Engine.new(template)
|
17
|
+
# output = sass_engine.render
|
18
|
+
# puts output
|
19
|
+
class Engine
|
20
|
+
# The character that begins a CSS attribute.
|
21
|
+
ATTRIBUTE_CHAR = ?:
|
22
|
+
|
23
|
+
# The character that designates that
|
24
|
+
# an attribute should be assigned to the result of constant arithmetic.
|
25
|
+
SCRIPT_CHAR = ?=
|
26
|
+
|
27
|
+
# The character that designates the beginning of a comment,
|
28
|
+
# either Sass or CSS.
|
29
|
+
COMMENT_CHAR = ?/
|
30
|
+
|
31
|
+
# The character that follows the general COMMENT_CHAR and designates a Sass comment,
|
32
|
+
# which is not output as a CSS comment.
|
33
|
+
SASS_COMMENT_CHAR = ?/
|
34
|
+
|
35
|
+
# The character that follows the general COMMENT_CHAR and designates a CSS comment,
|
36
|
+
# which is embedded in the CSS document.
|
37
|
+
CSS_COMMENT_CHAR = ?*
|
38
|
+
|
39
|
+
# The character used to denote a compiler directive.
|
40
|
+
DIRECTIVE_CHAR = ?@
|
41
|
+
|
42
|
+
# Designates a non-parsed rule.
|
43
|
+
ESCAPE_CHAR = ?\\
|
44
|
+
|
45
|
+
# Designates block as mixin definition rather than CSS rules to output
|
46
|
+
MIXIN_DEFINITION_CHAR = ?=
|
47
|
+
|
48
|
+
# Includes named mixin declared using MIXIN_DEFINITION_CHAR
|
49
|
+
MIXIN_INCLUDE_CHAR = ?+
|
50
|
+
|
51
|
+
# The regex that matches and extracts data from
|
52
|
+
# attributes of the form <tt>:name attr</tt>.
|
53
|
+
ATTRIBUTE = /^:([^\s=:]+)\s*(=?)(?:\s+|$)(.*)/
|
54
|
+
|
55
|
+
# The regex that matches attributes of the form <tt>name: attr</tt>.
|
56
|
+
ATTRIBUTE_ALTERNATE_MATCHER = /^[^\s:]+\s*[=:](\s|$)/
|
57
|
+
|
58
|
+
# The regex that matches and extracts data from
|
59
|
+
# attributes of the form <tt>name: attr</tt>.
|
60
|
+
ATTRIBUTE_ALTERNATE = /^([^\s=:]+)(\s*=|:)(?:\s+|$)(.*)/
|
61
|
+
|
62
|
+
# Creates a new instace of Sass::Engine that will compile the given
|
63
|
+
# template string when <tt>render</tt> is called.
|
64
|
+
# See README.rdoc for available options.
|
65
|
+
#
|
66
|
+
#--
|
67
|
+
#
|
68
|
+
# TODO: Add current options to REFRENCE. Remember :filename!
|
69
|
+
#
|
70
|
+
# When adding options, remember to add information about them
|
71
|
+
# to README.rdoc!
|
72
|
+
#++
|
73
|
+
#
|
74
|
+
def initialize(template, options={})
|
75
|
+
@options = {
|
76
|
+
:style => :nested,
|
77
|
+
:load_paths => ['.']
|
78
|
+
}.merge! options
|
79
|
+
@template = template.split(/\n?\r|\r?\n/)
|
80
|
+
@lines = []
|
81
|
+
@constants = {"important" => "!important"}
|
82
|
+
@mixins = {}
|
83
|
+
end
|
84
|
+
|
85
|
+
# Processes the template and returns the result as a string.
|
86
|
+
def render
|
87
|
+
begin
|
88
|
+
render_to_tree.to_s
|
89
|
+
rescue SyntaxError => err
|
90
|
+
unless err.sass_filename
|
91
|
+
err.add_backtrace_entry(@options[:filename])
|
92
|
+
end
|
93
|
+
raise err
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
alias_method :to_css, :render
|
98
|
+
|
99
|
+
protected
|
100
|
+
|
101
|
+
def constants
|
102
|
+
@constants
|
103
|
+
end
|
104
|
+
|
105
|
+
def mixins
|
106
|
+
@mixins
|
107
|
+
end
|
108
|
+
|
109
|
+
def render_to_tree
|
110
|
+
split_lines
|
111
|
+
|
112
|
+
root = Tree::Node.new(@options[:style])
|
113
|
+
index = 0
|
114
|
+
while @lines[index]
|
115
|
+
child, index = build_tree(index)
|
116
|
+
|
117
|
+
if child.is_a? Tree::Node
|
118
|
+
child.line = index
|
119
|
+
root << child
|
120
|
+
elsif child.is_a? Array
|
121
|
+
child.each do |c|
|
122
|
+
root << c
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
@lines.clear
|
127
|
+
|
128
|
+
root
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
# Readies each line in the template for parsing,
|
134
|
+
# and computes the tabulation of the line.
|
135
|
+
def split_lines
|
136
|
+
@line = 0
|
137
|
+
old_tabs = 0
|
138
|
+
@template.each_with_index do |line, index|
|
139
|
+
@line += 1
|
140
|
+
|
141
|
+
tabs = count_tabs(line)
|
142
|
+
|
143
|
+
if line[0] == COMMENT_CHAR && line[1] == SASS_COMMENT_CHAR && tabs == 0
|
144
|
+
tabs = old_tabs
|
145
|
+
end
|
146
|
+
|
147
|
+
if tabs # if line isn't blank
|
148
|
+
if tabs - old_tabs > 1
|
149
|
+
raise SyntaxError.new("#{tabs * 2} spaces were used for indentation. Sass must be indented using two spaces.", @line)
|
150
|
+
end
|
151
|
+
@lines << [line.strip, tabs]
|
152
|
+
|
153
|
+
old_tabs = tabs
|
154
|
+
else
|
155
|
+
@lines << ['//', old_tabs]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
@line = nil
|
160
|
+
end
|
161
|
+
|
162
|
+
# Counts the tabulation of a line.
|
163
|
+
def count_tabs(line)
|
164
|
+
return nil if line.strip.empty?
|
165
|
+
return nil unless spaces = line.index(/[^ ]/)
|
166
|
+
|
167
|
+
if spaces % 2 == 1
|
168
|
+
raise SyntaxError.new(<<END.strip, @line)
|
169
|
+
#{spaces} space#{spaces == 1 ? ' was' : 's were'} used for indentation. Sass must be indented using two spaces.
|
170
|
+
END
|
171
|
+
elsif line[spaces] == ?\t
|
172
|
+
raise SyntaxError.new(<<END.strip, @line)
|
173
|
+
A tab character was used for indentation. Sass must be indented using two spaces.
|
174
|
+
Are you sure you have soft tabs enabled in your editor?
|
175
|
+
END
|
176
|
+
end
|
177
|
+
spaces / 2
|
178
|
+
end
|
179
|
+
|
180
|
+
def build_tree(index)
|
181
|
+
line, tabs = @lines[index]
|
182
|
+
index += 1
|
183
|
+
@line = index
|
184
|
+
node = parse_line(line)
|
185
|
+
|
186
|
+
has_children = has_children?(index, tabs)
|
187
|
+
|
188
|
+
# Node is a symbol if it's non-outputting, like a constant assignment
|
189
|
+
unless node.is_a? Tree::Node
|
190
|
+
if has_children
|
191
|
+
if node == :constant
|
192
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath constants.", @line + 1)
|
193
|
+
elsif node.is_a? Array
|
194
|
+
# arrays can either be full of import statements
|
195
|
+
# or attributes from mixin includes
|
196
|
+
# in either case they shouldn't have children.
|
197
|
+
# Need to peek into the array in order to give meaningful errors
|
198
|
+
directive_type = (node.first.is_a?(Tree::DirectiveNode) ? "import" : "mixin")
|
199
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath #{directive_type} directives.", @line + 1)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
index = @line if node == :mixin
|
204
|
+
return node, index
|
205
|
+
end
|
206
|
+
|
207
|
+
node.line = @line
|
208
|
+
|
209
|
+
if node.is_a? Tree::CommentNode
|
210
|
+
while has_children
|
211
|
+
line, index = raw_next_line(index)
|
212
|
+
node << line
|
213
|
+
|
214
|
+
has_children = has_children?(index, tabs)
|
215
|
+
end
|
216
|
+
|
217
|
+
return node, index
|
218
|
+
end
|
219
|
+
|
220
|
+
# Resolve multiline rules
|
221
|
+
if node.is_a?(Tree::RuleNode)
|
222
|
+
if node.continued?
|
223
|
+
child, index = build_tree(index) if @lines[old_index = index]
|
224
|
+
if @lines[old_index].nil? || has_children?(old_index, tabs) || !child.is_a?(Tree::RuleNode)
|
225
|
+
raise SyntaxError.new("Rules can't end in commas.", @line)
|
226
|
+
end
|
227
|
+
|
228
|
+
node.add_rules child
|
229
|
+
end
|
230
|
+
node.children = child.children if child
|
231
|
+
end
|
232
|
+
|
233
|
+
while has_children
|
234
|
+
child, index = build_tree(index)
|
235
|
+
|
236
|
+
validate_and_append_child(node, child)
|
237
|
+
|
238
|
+
has_children = has_children?(index, tabs)
|
239
|
+
end
|
240
|
+
|
241
|
+
return node, index
|
242
|
+
end
|
243
|
+
|
244
|
+
def validate_and_append_child(parent, child)
|
245
|
+
case child
|
246
|
+
when :constant
|
247
|
+
raise SyntaxError.new("Constants may only be declared at the root of a document.", @line)
|
248
|
+
when :mixin
|
249
|
+
raise SyntaxError.new("Mixins may only be defined at the root of a document.", @line)
|
250
|
+
when Array
|
251
|
+
child.each do |c|
|
252
|
+
if c.is_a?(Tree::DirectiveNode)
|
253
|
+
raise SyntaxError.new("Import directives may only be used at the root of a document.", @line)
|
254
|
+
end
|
255
|
+
parent << c
|
256
|
+
end
|
257
|
+
when Tree::Node
|
258
|
+
parent << child
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def has_children?(index, tabs)
|
263
|
+
next_line = ['//', 0]
|
264
|
+
while !next_line.nil? && next_line[0] == '//' && next_line[1] = 0
|
265
|
+
next_line = @lines[index]
|
266
|
+
index += 1
|
267
|
+
end
|
268
|
+
next_line && next_line[1] > tabs
|
269
|
+
end
|
270
|
+
|
271
|
+
def raw_next_line(index)
|
272
|
+
[@lines[index][0], index + 1]
|
273
|
+
end
|
274
|
+
|
275
|
+
def parse_line(line)
|
276
|
+
case line[0]
|
277
|
+
when ATTRIBUTE_CHAR
|
278
|
+
parse_attribute(line, ATTRIBUTE)
|
279
|
+
when Constant::CONSTANT_CHAR
|
280
|
+
parse_constant(line)
|
281
|
+
when COMMENT_CHAR
|
282
|
+
parse_comment(line)
|
283
|
+
when DIRECTIVE_CHAR
|
284
|
+
parse_directive(line)
|
285
|
+
when ESCAPE_CHAR
|
286
|
+
Tree::RuleNode.new(line[1..-1], @options[:style])
|
287
|
+
when MIXIN_DEFINITION_CHAR
|
288
|
+
parse_mixin_definition(line)
|
289
|
+
when MIXIN_INCLUDE_CHAR
|
290
|
+
parse_mixin_include(line)
|
291
|
+
else
|
292
|
+
if line =~ ATTRIBUTE_ALTERNATE_MATCHER
|
293
|
+
parse_attribute(line, ATTRIBUTE_ALTERNATE)
|
294
|
+
else
|
295
|
+
Tree::RuleNode.new(line, @options[:style])
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def parse_attribute(line, attribute_regx)
|
301
|
+
if @options[:attribute_syntax] == :normal &&
|
302
|
+
attribute_regx == ATTRIBUTE_ALTERNATE
|
303
|
+
raise SyntaxError.new("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.")
|
304
|
+
elsif @options[:attribute_syntax] == :alternate &&
|
305
|
+
attribute_regx == ATTRIBUTE
|
306
|
+
raise SyntaxError.new("Illegal attribute syntax: can't use normal syntax when :attribute_syntax => :alternate is set.")
|
307
|
+
end
|
308
|
+
|
309
|
+
name, eq, value = line.scan(attribute_regx)[0]
|
310
|
+
|
311
|
+
if name.nil? || value.nil?
|
312
|
+
raise SyntaxError.new("Invalid attribute: \"#{line}\".", @line)
|
313
|
+
end
|
314
|
+
|
315
|
+
if eq.strip[0] == SCRIPT_CHAR
|
316
|
+
value = Sass::Constant.parse(value, @constants, @line).to_s
|
317
|
+
end
|
318
|
+
|
319
|
+
Tree::AttrNode.new(name, value, @options[:style])
|
320
|
+
end
|
321
|
+
|
322
|
+
def parse_constant(line)
|
323
|
+
name, op, value = line.scan(Sass::Constant::MATCH)[0]
|
324
|
+
unless name && value
|
325
|
+
raise SyntaxError.new("Invalid constant: \"#{line}\".", @line)
|
326
|
+
end
|
327
|
+
|
328
|
+
constant = Sass::Constant.parse(value, @constants, @line)
|
329
|
+
if op == '||='
|
330
|
+
@constants[name] ||= constant
|
331
|
+
else
|
332
|
+
@constants[name] = constant
|
333
|
+
end
|
334
|
+
|
335
|
+
:constant
|
336
|
+
end
|
337
|
+
|
338
|
+
def parse_comment(line)
|
339
|
+
if line[1] == SASS_COMMENT_CHAR
|
340
|
+
:comment
|
341
|
+
elsif line[1] == CSS_COMMENT_CHAR
|
342
|
+
Tree::CommentNode.new(line, @options[:style])
|
343
|
+
else
|
344
|
+
Tree::RuleNode.new(line, @options[:style])
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def parse_directive(line)
|
349
|
+
directive, value = line[1..-1].split(/\s+/, 2)
|
350
|
+
|
351
|
+
# If value begins with url( or ",
|
352
|
+
# it's a CSS @import rule and we don't want to touch it.
|
353
|
+
if directive == "import" && value !~ /^(url\(|")/
|
354
|
+
import(value)
|
355
|
+
else
|
356
|
+
Tree::DirectiveNode.new(line, @options[:style])
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def parse_mixin_definition(line)
|
361
|
+
mixin_name = line[1..-1]
|
362
|
+
@mixins[mixin_name] = []
|
363
|
+
index = @line
|
364
|
+
line, tabs = @lines[index]
|
365
|
+
while !line.nil? && tabs > 0
|
366
|
+
child, index = build_tree(index)
|
367
|
+
validate_and_append_child(@mixins[mixin_name], child)
|
368
|
+
line, tabs = @lines[index]
|
369
|
+
end
|
370
|
+
:mixin
|
371
|
+
end
|
372
|
+
|
373
|
+
def parse_mixin_include(line)
|
374
|
+
mixin_name = line[1..-1]
|
375
|
+
unless @mixins.has_key?(mixin_name)
|
376
|
+
raise SyntaxError.new("Undefined mixin '#{mixin_name}'.", @line)
|
377
|
+
end
|
378
|
+
@mixins[mixin_name]
|
379
|
+
end
|
380
|
+
|
381
|
+
def import(files)
|
382
|
+
nodes = []
|
383
|
+
|
384
|
+
files.split(/,\s*/).each do |filename|
|
385
|
+
engine = nil
|
386
|
+
|
387
|
+
begin
|
388
|
+
filename = self.class.find_file_to_import(filename, @options[:load_paths])
|
389
|
+
rescue Exception => e
|
390
|
+
raise SyntaxError.new(e.message, @line)
|
391
|
+
end
|
392
|
+
|
393
|
+
if filename =~ /\.css$/
|
394
|
+
nodes << Tree::DirectiveNode.new("@import url(#{filename})", @options[:style])
|
395
|
+
else
|
396
|
+
File.open(filename) do |file|
|
397
|
+
new_options = @options.dup
|
398
|
+
new_options[:filename] = filename
|
399
|
+
engine = Sass::Engine.new(file.read, @options)
|
400
|
+
end
|
401
|
+
|
402
|
+
engine.constants.merge! @constants
|
403
|
+
engine.mixins.merge! @mixins
|
404
|
+
|
405
|
+
begin
|
406
|
+
root = engine.render_to_tree
|
407
|
+
rescue Sass::SyntaxError => err
|
408
|
+
err.add_backtrace_entry(filename)
|
409
|
+
raise err
|
410
|
+
end
|
411
|
+
root.children.each do |child|
|
412
|
+
child.filename = filename
|
413
|
+
nodes << child
|
414
|
+
end
|
415
|
+
@constants = engine.constants
|
416
|
+
@mixins = engine.mixins
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
nodes
|
421
|
+
end
|
422
|
+
|
423
|
+
def self.find_file_to_import(filename, load_paths)
|
424
|
+
was_sass = false
|
425
|
+
original_filename = filename
|
426
|
+
|
427
|
+
if filename[-5..-1] == ".sass"
|
428
|
+
filename = filename[0...-5]
|
429
|
+
was_sass = true
|
430
|
+
elsif filename[-4..-1] == ".css"
|
431
|
+
return filename
|
432
|
+
end
|
433
|
+
|
434
|
+
new_filename = find_full_path("#{filename}.sass", load_paths)
|
435
|
+
|
436
|
+
if new_filename.nil?
|
437
|
+
if was_sass
|
438
|
+
raise Exception.new("File to import not found or unreadable: #{original_filename}.")
|
439
|
+
else
|
440
|
+
return filename + '.css'
|
441
|
+
end
|
442
|
+
else
|
443
|
+
new_filename
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def self.find_full_path(filename, load_paths)
|
448
|
+
load_paths.each do |path|
|
449
|
+
["_#{filename}", filename].each do |name|
|
450
|
+
full_path = File.join(path, name)
|
451
|
+
if File.readable?(full_path)
|
452
|
+
return full_path
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
nil
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|