haml 1.8.0 → 2.0.3
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.
- data/FAQ +138 -0
- data/MIT-LICENSE +1 -1
- data/{README → README.rdoc} +66 -3
- data/REVISION +1 -0
- data/Rakefile +115 -147
- data/VERSION +1 -1
- data/bin/css2sass +0 -0
- data/bin/haml +2 -1
- data/bin/html2haml +0 -0
- data/bin/sass +0 -0
- data/init.rb +6 -1
- data/lib/haml/buffer.rb +122 -64
- data/lib/haml/engine.rb +77 -46
- data/lib/haml/error.rb +15 -6
- data/lib/haml/exec.rb +61 -10
- data/lib/haml/filters.rb +229 -74
- data/lib/haml/helpers/action_view_extensions.rb +1 -1
- data/lib/haml/helpers/action_view_mods.rb +109 -24
- data/lib/haml/helpers.rb +137 -76
- data/lib/haml/html.rb +8 -8
- data/lib/haml/precompiler.rb +280 -153
- data/lib/haml/template/patch.rb +10 -3
- data/lib/haml/template/plugin.rb +61 -10
- data/lib/haml/template.rb +14 -9
- data/lib/haml.rb +483 -214
- data/lib/sass/constant/color.rb +13 -13
- data/lib/sass/constant/literal.rb +8 -7
- data/lib/sass/constant/nil.rb +9 -0
- data/lib/sass/constant/number.rb +10 -10
- data/lib/sass/constant/operation.rb +4 -4
- data/lib/sass/constant/string.rb +3 -3
- data/lib/sass/constant.rb +46 -77
- data/lib/sass/css.rb +130 -56
- data/lib/sass/engine.rb +131 -43
- data/lib/sass/plugin/merb.rb +48 -12
- data/lib/sass/plugin/rails.rb +10 -4
- data/lib/sass/plugin.rb +33 -10
- data/lib/sass/tree/attr_node.rb +5 -5
- data/lib/sass/tree/directive_node.rb +2 -7
- data/lib/sass/tree/node.rb +1 -12
- data/lib/sass/tree/rule_node.rb +39 -31
- data/lib/sass/tree/value_node.rb +1 -1
- data/lib/sass.rb +194 -19
- data/rails/init.rb +1 -0
- data/test/benchmark.rb +67 -80
- data/test/haml/engine_test.rb +368 -152
- data/test/haml/helper_test.rb +68 -16
- data/test/haml/html2haml_test.rb +3 -4
- data/test/haml/results/content_for_layout.xhtml +1 -2
- data/test/haml/results/eval_suppressed.xhtml +2 -4
- data/test/haml/results/filters.xhtml +38 -30
- data/test/haml/results/helpers.xhtml +4 -8
- data/test/haml/results/just_stuff.xhtml +8 -7
- data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
- data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
- data/test/haml/results/original_engine.xhtml +3 -7
- data/test/haml/results/partials.xhtml +1 -0
- data/test/haml/results/tag_parsing.xhtml +1 -6
- data/test/haml/results/very_basic.xhtml +2 -4
- data/test/haml/results/whitespace_handling.xhtml +13 -21
- data/test/haml/template_test.rb +42 -57
- data/test/haml/templates/_partial.haml +1 -0
- data/test/haml/templates/filters.haml +39 -21
- data/test/haml/templates/helpers.haml +10 -10
- data/test/haml/templates/just_stuff.haml +8 -3
- data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/partials.haml +1 -1
- data/test/haml/templates/tag_parsing.haml +0 -3
- data/test/haml/templates/whitespace_handling.haml +10 -10
- data/test/sass/engine_test.rb +97 -39
- data/test/sass/plugin_test.rb +4 -7
- data/test/sass/results/constants.css +2 -0
- data/test/sass/results/import.css +2 -2
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/templates/constants.sass +3 -0
- data/test/sass/templates/import.sass +4 -1
- data/test/sass/templates/importee.sass +4 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- data/test/test_helper.rb +18 -0
- metadata +70 -53
- data/lib/haml/helpers/action_view_mods.rb.rej +0 -30
- data/lib/haml/util.rb +0 -18
- data/lib/sass/constant.rb.rej +0 -42
- data/test/haml/runner.rb +0 -16
- data/test/profile.rb +0 -65
- data/test/sass/engine_test.rb.rej +0 -18
data/lib/sass/plugin/merb.rb
CHANGED
|
@@ -1,20 +1,56 @@
|
|
|
1
1
|
unless defined?(Sass::MERB_LOADED)
|
|
2
2
|
Sass::MERB_LOADED = true
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
version = Merb::VERSION.split('.').map { |n| n.to_i }
|
|
5
|
+
if version[0] <= 0 && version[1] < 5
|
|
6
|
+
root = MERB_ROOT
|
|
7
|
+
env = MERB_ENV
|
|
8
|
+
else
|
|
9
|
+
root = Merb.root.to_s
|
|
10
|
+
env = Merb.environment
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Sass::Plugin.options.merge!(:template_location => root + '/public/stylesheets/sass',
|
|
14
|
+
:css_location => root + '/public/stylesheets',
|
|
15
|
+
:always_check => env != "production",
|
|
16
|
+
:full_exception => env != "production")
|
|
8
17
|
config = Merb::Plugins.config[:sass] || Merb::Plugins.config["sass"] || {}
|
|
9
|
-
|
|
18
|
+
|
|
19
|
+
if defined? config.symbolize_keys!
|
|
20
|
+
config.symbolize_keys!
|
|
21
|
+
end
|
|
22
|
+
|
|
10
23
|
Sass::Plugin.options.merge!(config)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
24
|
+
|
|
25
|
+
if version[0] > 0 || version[1] >= 9
|
|
26
|
+
|
|
27
|
+
class Merb::Rack::Application # :nodoc:
|
|
28
|
+
def call_with_sass(env)
|
|
29
|
+
if !Sass::Plugin.checked_for_updates ||
|
|
30
|
+
Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
|
|
31
|
+
Sass::Plugin.update_stylesheets
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
call_without_sass(env)
|
|
35
|
+
end
|
|
36
|
+
alias_method :call_without_sass, :call
|
|
37
|
+
alias_method :call, :call_with_sass
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
else
|
|
41
|
+
|
|
42
|
+
class MerbHandler # :nodoc:
|
|
43
|
+
def process_with_sass(request, response)
|
|
44
|
+
if !Sass::Plugin.checked_for_updates ||
|
|
45
|
+
Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
|
|
46
|
+
Sass::Plugin.update_stylesheets
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
process_without_sass(request, response)
|
|
50
|
+
end
|
|
51
|
+
alias_method :process_without_sass, :process
|
|
52
|
+
alias_method :process, :process_with_sass
|
|
16
53
|
end
|
|
17
|
-
|
|
18
|
-
alias_method :process, :process_with_sass
|
|
54
|
+
|
|
19
55
|
end
|
|
20
56
|
end
|
data/lib/sass/plugin/rails.rb
CHANGED
|
@@ -5,14 +5,20 @@ unless defined?(Sass::RAILS_LOADED)
|
|
|
5
5
|
:css_location => RAILS_ROOT + '/public/stylesheets',
|
|
6
6
|
:always_check => RAILS_ENV != "production",
|
|
7
7
|
:full_exception => RAILS_ENV != "production")
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
# :stopdoc:
|
|
10
|
+
module ActionController
|
|
11
|
+
class Base
|
|
11
12
|
alias_method :sass_old_process, :process
|
|
12
13
|
def process(*args)
|
|
13
|
-
|
|
14
|
+
if !Sass::Plugin.checked_for_updates ||
|
|
15
|
+
Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
|
|
16
|
+
Sass::Plugin.update_stylesheets
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
sass_old_process(*args)
|
|
15
20
|
end
|
|
16
21
|
end
|
|
17
22
|
end
|
|
23
|
+
# :startdoc:
|
|
18
24
|
end
|
data/lib/sass/plugin.rb
CHANGED
|
@@ -13,8 +13,15 @@ module Sass
|
|
|
13
13
|
:always_check => true,
|
|
14
14
|
:full_exception => true
|
|
15
15
|
}
|
|
16
|
+
@@checked_for_updates = false
|
|
16
17
|
|
|
17
|
-
#
|
|
18
|
+
# Whether or not Sass has *ever* checked if the stylesheets need updates
|
|
19
|
+
# (in this Ruby instance).
|
|
20
|
+
def checked_for_updates
|
|
21
|
+
@@checked_for_updates
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Gets various options for Sass. See README.rdoc for details.
|
|
18
25
|
#--
|
|
19
26
|
# TODO: *DOCUMENT OPTIONS*
|
|
20
27
|
#++
|
|
@@ -27,6 +34,13 @@ module Sass
|
|
|
27
34
|
@@options.merge!(value)
|
|
28
35
|
end
|
|
29
36
|
|
|
37
|
+
# Get the options ready to be passed to the Sass::Engine
|
|
38
|
+
def engine_options(additional_options = {})
|
|
39
|
+
opts = options.dup.merge(additional_options)
|
|
40
|
+
opts[:load_paths] = load_paths(opts)
|
|
41
|
+
opts
|
|
42
|
+
end
|
|
43
|
+
|
|
30
44
|
# Checks each stylesheet in <tt>options[:css_location]</tt>
|
|
31
45
|
# to see if it needs updating,
|
|
32
46
|
# and updates it using the corresponding template
|
|
@@ -35,6 +49,7 @@ module Sass
|
|
|
35
49
|
def update_stylesheets
|
|
36
50
|
return if options[:never_update]
|
|
37
51
|
|
|
52
|
+
@@checked_for_updates = true
|
|
38
53
|
Dir.glob(File.join(options[:template_location], "**", "*.sass")).entries.each do |file|
|
|
39
54
|
|
|
40
55
|
# Get the relative path to the file with no extension
|
|
@@ -45,10 +60,7 @@ module Sass
|
|
|
45
60
|
File.delete(css) if File.exists?(css)
|
|
46
61
|
|
|
47
62
|
filename = template_filename(name)
|
|
48
|
-
|
|
49
|
-
l_options[:filename] = filename
|
|
50
|
-
l_options[:load_paths] = load_paths
|
|
51
|
-
engine = Engine.new(File.read(filename), l_options)
|
|
63
|
+
engine = Engine.new(File.read(filename), engine_options(:filename => filename))
|
|
52
64
|
result = begin
|
|
53
65
|
engine.render
|
|
54
66
|
rescue Exception => e
|
|
@@ -56,7 +68,7 @@ module Sass
|
|
|
56
68
|
end
|
|
57
69
|
|
|
58
70
|
# Create any directories that might be necessary
|
|
59
|
-
dirs = [
|
|
71
|
+
dirs = [options[:css_location]]
|
|
60
72
|
name.split("/")[0...-1].each { |dir| dirs << "#{dirs[-1]}/#{dir}" }
|
|
61
73
|
dirs.each { |dir| Dir.mkdir(dir) unless File.exist?(dir) }
|
|
62
74
|
|
|
@@ -70,8 +82,8 @@ module Sass
|
|
|
70
82
|
|
|
71
83
|
private
|
|
72
84
|
|
|
73
|
-
def load_paths
|
|
74
|
-
(
|
|
85
|
+
def load_paths(opts = options)
|
|
86
|
+
(opts[:load_paths] || []) + [options[:template_location]]
|
|
75
87
|
end
|
|
76
88
|
|
|
77
89
|
def exception_string(e)
|
|
@@ -96,7 +108,18 @@ module Sass
|
|
|
96
108
|
end
|
|
97
109
|
end
|
|
98
110
|
end
|
|
99
|
-
|
|
111
|
+
<<END
|
|
112
|
+
/*
|
|
113
|
+
#{e_string}
|
|
114
|
+
|
|
115
|
+
Backtrace:\n#{e.backtrace.join("\n")}
|
|
116
|
+
*/
|
|
117
|
+
body:before {
|
|
118
|
+
white-space: pre;
|
|
119
|
+
font-family: monospace;
|
|
120
|
+
content: "#{e_string.gsub('"', '\"').gsub("\n", '\\A ')}"; }
|
|
121
|
+
END
|
|
122
|
+
# Fix an emacs syntax-highlighting hiccup: '
|
|
100
123
|
else
|
|
101
124
|
"/* Internal stylesheet error */"
|
|
102
125
|
end
|
|
@@ -111,7 +134,7 @@ module Sass
|
|
|
111
134
|
end
|
|
112
135
|
|
|
113
136
|
def forbid_update?(name)
|
|
114
|
-
name[0] == ?_
|
|
137
|
+
name.sub(/^.*\//, '')[0] == ?_
|
|
115
138
|
end
|
|
116
139
|
|
|
117
140
|
def stylesheet_needs_update?(name)
|
data/lib/sass/tree/attr_node.rb
CHANGED
|
@@ -3,21 +3,21 @@ require 'sass/tree/node'
|
|
|
3
3
|
module Sass::Tree
|
|
4
4
|
class AttrNode < ValueNode
|
|
5
5
|
attr_accessor :name
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def initialize(name, value, style)
|
|
8
8
|
@name = name
|
|
9
9
|
super(value, style)
|
|
10
10
|
end
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
def to_s(tabs, parent_name = nil)
|
|
13
13
|
if value[-1] == ?;
|
|
14
|
-
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump} (This isn't CSS!)", @line)
|
|
14
|
+
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump} (This isn't CSS!).", @line)
|
|
15
15
|
end
|
|
16
16
|
real_name = name
|
|
17
17
|
real_name = "#{parent_name}-#{real_name}" if parent_name
|
|
18
18
|
|
|
19
19
|
if value.empty? && children.empty?
|
|
20
|
-
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump}", @line)
|
|
20
|
+
raise Sass::SyntaxError.new("Invalid attribute: #{declaration.dump}.", @line)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
join_string = case @style
|
|
@@ -34,7 +34,7 @@ module Sass::Tree
|
|
|
34
34
|
children.each do |kid|
|
|
35
35
|
to_return << "#{kid.to_s(tabs, real_name)}" << join_string
|
|
36
36
|
end
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
(@style == :compressed && parent_name) ? to_return : to_return[0...-1]
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -15,11 +15,6 @@ module Sass::Tree
|
|
|
15
15
|
was_attr = false
|
|
16
16
|
first = true
|
|
17
17
|
children.each do |child|
|
|
18
|
-
if child.is_a?(RuleNode) && child.continued?
|
|
19
|
-
check_multiline_rule(child)
|
|
20
|
-
continued_rule = true
|
|
21
|
-
end
|
|
22
|
-
|
|
23
18
|
if @style == :compact
|
|
24
19
|
if child.is_a?(AttrNode)
|
|
25
20
|
result << "#{child.to_s(first || was_attr ? 1 : tabs + 1)} "
|
|
@@ -32,12 +27,12 @@ module Sass::Tree
|
|
|
32
27
|
result << rendered
|
|
33
28
|
end
|
|
34
29
|
was_attr = child.is_a?(AttrNode)
|
|
35
|
-
first =
|
|
30
|
+
first = false
|
|
36
31
|
elsif @style == :compressed
|
|
37
32
|
result << (was_attr ? ";#{child.to_s(1)}" : child.to_s(1))
|
|
38
33
|
was_attr = child.is_a?(AttrNode)
|
|
39
34
|
else
|
|
40
|
-
result << child.to_s(tabs + 1) +
|
|
35
|
+
result << child.to_s(tabs + 1) + "\n"
|
|
41
36
|
end
|
|
42
37
|
end
|
|
43
38
|
result.rstrip + if @style == :compressed
|
data/lib/sass/tree/node.rb
CHANGED
|
@@ -16,15 +16,12 @@ module Sass
|
|
|
16
16
|
end
|
|
17
17
|
@children << child
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
def to_s
|
|
21
21
|
result = String.new
|
|
22
22
|
children.each do |child|
|
|
23
23
|
if child.is_a? AttrNode
|
|
24
24
|
raise SyntaxError.new('Attributes aren\'t allowed at the root of a document.', child.line)
|
|
25
|
-
elsif child.is_a?(RuleNode) && child.continued?
|
|
26
|
-
check_multiline_rule(child)
|
|
27
|
-
result << child.to_s(1)
|
|
28
25
|
else
|
|
29
26
|
result << "#{child.to_s(1)}" + (@style == :compressed ? '' : "\n")
|
|
30
27
|
end
|
|
@@ -32,14 +29,6 @@ module Sass
|
|
|
32
29
|
@style == :compressed ? result+"\n" : result[0...-1]
|
|
33
30
|
end
|
|
34
31
|
|
|
35
|
-
protected
|
|
36
|
-
|
|
37
|
-
def check_multiline_rule(rule)
|
|
38
|
-
unless rule.children.empty?
|
|
39
|
-
raise SyntaxError.new('Rules can\'t end in commas.', rule.line)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
32
|
private
|
|
44
33
|
|
|
45
34
|
# This method should be overridden by subclasses to return an error message
|
data/lib/sass/tree/rule_node.rb
CHANGED
|
@@ -9,33 +9,50 @@ module Sass::Tree
|
|
|
9
9
|
alias_method :rule, :value
|
|
10
10
|
alias_method :rule=, :value=
|
|
11
11
|
|
|
12
|
+
def rules
|
|
13
|
+
Array(rule)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add_rules(node)
|
|
17
|
+
self.rule = rules
|
|
18
|
+
self.rule += node.rules
|
|
19
|
+
end
|
|
20
|
+
|
|
12
21
|
def continued?
|
|
13
22
|
rule[-1] == ?,
|
|
14
23
|
end
|
|
15
|
-
|
|
24
|
+
|
|
16
25
|
def to_s(tabs, super_rules = nil)
|
|
17
26
|
attributes = []
|
|
18
27
|
sub_rules = []
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
29
|
+
rule_split = /\s*,\s*/
|
|
30
|
+
rule_separator = @style == :compressed ? ',' : ', '
|
|
31
|
+
line_separator = [:nested, :expanded].include?(@style) ? ",\n" : rule_separator
|
|
32
|
+
rule_indent = ' ' * (tabs - 1)
|
|
23
33
|
total_rule = if super_rules
|
|
24
|
-
super_rules.split(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
super_rules.split(",\n").map do |super_line|
|
|
35
|
+
super_line.strip.split(rule_split).map do |super_rule|
|
|
36
|
+
self.rules.map do |line|
|
|
37
|
+
rule_indent + line.gsub(/,$/, '').split(rule_split).map do |rule|
|
|
38
|
+
if rule.include?(PARENT)
|
|
39
|
+
rule.gsub(PARENT, super_rule)
|
|
40
|
+
else
|
|
41
|
+
"#{super_rule} #{rule}"
|
|
42
|
+
end
|
|
43
|
+
end.join(rule_separator)
|
|
44
|
+
end.join(line_separator)
|
|
45
|
+
end.join(rule_separator)
|
|
46
|
+
end.join(line_separator)
|
|
47
|
+
elsif self.rules.any? { |r| r.include?(PARENT) }
|
|
48
|
+
raise Sass::SyntaxError.new("Base-level rules cannot contain the parent-selector-referencing character '#{PARENT}'.", line)
|
|
35
49
|
else
|
|
36
|
-
|
|
50
|
+
per_rule_indent, total_indent = [:nested, :expanded].include?(@style) ? [rule_indent, ''] : ['', rule_indent]
|
|
51
|
+
total_indent + self.rules.map do |r|
|
|
52
|
+
per_rule_indent + r.gsub(/,$/, '').gsub(rule_split, rule_separator).rstrip
|
|
53
|
+
end.join(line_separator)
|
|
37
54
|
end
|
|
38
|
-
|
|
55
|
+
|
|
39
56
|
children.each do |child|
|
|
40
57
|
if child.is_a? RuleNode
|
|
41
58
|
sub_rules << child
|
|
@@ -43,38 +60,29 @@ module Sass::Tree
|
|
|
43
60
|
attributes << child
|
|
44
61
|
end
|
|
45
62
|
end
|
|
46
|
-
|
|
63
|
+
|
|
47
64
|
to_return = ''
|
|
48
65
|
if !attributes.empty?
|
|
49
66
|
old_spaces = ' ' * (tabs - 1)
|
|
50
67
|
spaces = ' ' * tabs
|
|
51
68
|
if @style == :compact
|
|
52
69
|
attributes = attributes.map { |a| a.to_s(1) }.join(' ')
|
|
53
|
-
to_return << "#{
|
|
70
|
+
to_return << "#{total_rule} { #{attributes} }\n"
|
|
54
71
|
elsif @style == :compressed
|
|
55
72
|
attributes = attributes.map { |a| a.to_s(1) }.join(';')
|
|
56
73
|
to_return << "#{total_rule}{#{attributes}}"
|
|
57
74
|
else
|
|
58
75
|
attributes = attributes.map { |a| a.to_s(tabs + 1) }.join("\n")
|
|
59
76
|
end_attrs = (@style == :expanded ? "\n" + old_spaces : ' ')
|
|
60
|
-
to_return << "#{
|
|
77
|
+
to_return << "#{total_rule} {\n#{attributes}#{end_attrs}}\n"
|
|
61
78
|
end
|
|
62
|
-
elsif continued?
|
|
63
|
-
to_return << (' ' * (tabs - 1)) + total_rule + case @style
|
|
64
|
-
when :compressed; ''
|
|
65
|
-
when :compact; ' '
|
|
66
|
-
else "\n"
|
|
67
|
-
end
|
|
68
79
|
end
|
|
69
|
-
|
|
80
|
+
|
|
70
81
|
tabs += 1 unless attributes.empty? || @style != :nested
|
|
71
82
|
sub_rules.each do |sub|
|
|
72
|
-
if sub.continued?
|
|
73
|
-
check_multiline_rule(sub)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
83
|
to_return << sub.to_s(tabs, total_rule)
|
|
77
84
|
end
|
|
85
|
+
|
|
78
86
|
to_return
|
|
79
87
|
end
|
|
80
88
|
end
|