haml-edge 2.3.209 → 2.3.210
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +2 -0
- data/EDGE_GEM_VERSION +1 -1
- data/Rakefile +24 -2
- data/VERSION +1 -1
- data/lib/haml/exec.rb +11 -4
- data/lib/haml/filters.rb +3 -0
- data/lib/haml/helpers/action_view_extensions.rb +4 -2
- data/lib/haml/helpers/action_view_mods.rb +6 -4
- data/lib/haml/helpers.rb +2 -10
- data/lib/haml/html.rb +0 -1
- data/lib/haml/precompiler.rb +37 -30
- data/lib/haml/railtie.rb +6 -2
- data/lib/haml/root.rb +4 -0
- data/lib/haml/template.rb +2 -0
- data/lib/haml/util/subset_map.rb +101 -0
- data/lib/haml/util.rb +74 -0
- data/lib/haml.rb +5 -2
- data/lib/sass/engine.rb +36 -31
- data/lib/sass/files.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +9 -9
- data/lib/sass/plugin.rb +21 -0
- data/lib/sass/script/color.rb +4 -3
- data/lib/sass/script/css_lexer.rb +11 -1
- data/lib/sass/script/css_parser.rb +4 -1
- data/lib/sass/script/funcall.rb +9 -0
- data/lib/sass/script/interpolation.rb +21 -0
- data/lib/sass/script/lexer.rb +30 -13
- data/lib/sass/script/node.rb +1 -1
- data/lib/sass/script/number.rb +4 -5
- data/lib/sass/script/parser.rb +13 -14
- data/lib/sass/script/string.rb +8 -2
- data/lib/sass/script/string_interpolation.rb +27 -4
- data/lib/sass/script.rb +1 -2
- data/lib/sass/scss/css_parser.rb +5 -3
- data/lib/sass/scss/parser.rb +146 -64
- data/lib/sass/scss/rx.rb +9 -1
- data/lib/sass/scss/sass_parser.rb +11 -0
- data/lib/sass/scss/script_lexer.rb +2 -0
- data/lib/sass/scss/static_parser.rb +48 -0
- data/lib/sass/scss.rb +3 -0
- data/lib/sass/selector/abstract_sequence.rb +40 -0
- data/lib/sass/selector/comma_sequence.rb +80 -0
- data/lib/sass/selector/sequence.rb +194 -0
- data/lib/sass/selector/simple.rb +107 -0
- data/lib/sass/selector/simple_sequence.rb +161 -0
- data/lib/sass/selector.rb +353 -0
- data/lib/sass/tree/comment_node.rb +1 -0
- data/lib/sass/tree/debug_node.rb +1 -0
- data/lib/sass/tree/directive_node.rb +1 -0
- data/lib/sass/tree/extend_node.rb +60 -0
- data/lib/sass/tree/for_node.rb +1 -0
- data/lib/sass/tree/if_node.rb +2 -0
- data/lib/sass/tree/import_node.rb +2 -0
- data/lib/sass/tree/mixin_def_node.rb +1 -0
- data/lib/sass/tree/mixin_node.rb +21 -5
- data/lib/sass/tree/node.rb +59 -12
- data/lib/sass/tree/prop_node.rb +20 -21
- data/lib/sass/tree/root_node.rb +8 -17
- data/lib/sass/tree/rule_node.rb +49 -100
- data/lib/sass/tree/variable_node.rb +1 -0
- data/lib/sass/tree/warn_node.rb +1 -0
- data/lib/sass/tree/while_node.rb +1 -0
- data/lib/sass.rb +1 -0
- data/test/haml/engine_test.rb +185 -3
- data/test/haml/helper_test.rb +25 -2
- data/test/haml/template_test.rb +2 -2
- data/test/haml/templates/helpers.haml +13 -0
- data/test/haml/util/subset_map_test.rb +91 -0
- data/test/haml/util_test.rb +25 -0
- data/test/sass/conversion_test.rb +23 -3
- data/test/sass/engine_test.rb +50 -7
- data/test/sass/extend_test.rb +1045 -0
- data/test/sass/results/complex.css +0 -1
- data/test/sass/results/script.css +1 -1
- data/test/sass/script_conversion_test.rb +16 -0
- data/test/sass/script_test.rb +37 -4
- data/test/sass/scss/css_test.rb +17 -3
- data/test/sass/scss/rx_test.rb +1 -1
- data/test/sass/scss/scss_test.rb +30 -0
- data/test/sass/templates/complex.sass +0 -2
- data/test/test_helper.rb +5 -0
- metadata +17 -3
data/.yardopts
CHANGED
data/EDGE_GEM_VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3.
|
1
|
+
2.3.210
|
data/Rakefile
CHANGED
@@ -239,7 +239,7 @@ end
|
|
239
239
|
begin
|
240
240
|
require 'yard'
|
241
241
|
|
242
|
-
namespace :
|
242
|
+
namespace :doc do
|
243
243
|
task :sass do
|
244
244
|
require scope('lib/sass')
|
245
245
|
Dir[scope("yard/default/**/*.sass")].each do |sass|
|
@@ -248,12 +248,27 @@ begin
|
|
248
248
|
end
|
249
249
|
end
|
250
250
|
end
|
251
|
+
|
252
|
+
desc "List all undocumented methods and classes."
|
253
|
+
task :undocumented do
|
254
|
+
opts = ENV["YARD_OPTS"] || ""
|
255
|
+
ENV["YARD_OPTS"] = opts.dup + <<OPTS
|
256
|
+
--list --query "
|
257
|
+
object.docstring.blank? &&
|
258
|
+
!(object.type == :method && object.is_alias?)"
|
259
|
+
OPTS
|
260
|
+
Rake::Task['yard'].execute
|
261
|
+
end
|
251
262
|
end
|
252
263
|
|
253
264
|
YARD::Rake::YardocTask.new do |t|
|
254
265
|
t.files = FileList.new(scope('lib/**/*.rb')) do |list|
|
255
266
|
list.exclude('lib/haml/template/*.rb')
|
267
|
+
list.exclude('lib/haml/railtie.rb')
|
256
268
|
list.exclude('lib/haml/helpers/action_view_mods.rb')
|
269
|
+
list.exclude('lib/haml/helpers/xss_mods.rb')
|
270
|
+
list.exclude('lib/sass/plugin/merb.rb')
|
271
|
+
list.exclude('lib/sass/plugin/rails.rb')
|
257
272
|
end.to_a
|
258
273
|
t.options << '--incremental' if Rake.application.top_level_tasks.include?('redoc')
|
259
274
|
t.options += FileList.new(scope('yard/*.rb')).to_a.map {|f| ['-e', f]}.flatten
|
@@ -261,8 +276,15 @@ begin
|
|
261
276
|
t.options << '--files' << files.join(',')
|
262
277
|
t.options << '--template-path' << scope('yard')
|
263
278
|
t.options << '--title' << ENV["YARD_TITLE"] if ENV["YARD_TITLE"]
|
279
|
+
|
280
|
+
t.before = lambda do
|
281
|
+
if ENV["YARD_OPTS"]
|
282
|
+
require 'shellwords'
|
283
|
+
t.options.concat(Shellwords.shellwords(ENV["YARD_OPTS"]))
|
284
|
+
end
|
285
|
+
end
|
264
286
|
end
|
265
|
-
Rake::Task['yard'].prerequisites.insert(0, '
|
287
|
+
Rake::Task['yard'].prerequisites.insert(0, 'doc:sass')
|
266
288
|
Rake::Task['yard'].instance_variable_set('@comment', nil)
|
267
289
|
|
268
290
|
desc "Generate Documentation"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3.
|
1
|
+
2.3.210
|
data/lib/haml/exec.rb
CHANGED
@@ -115,7 +115,6 @@ module Haml
|
|
115
115
|
@options[:input], @options[:output] = input, output
|
116
116
|
end
|
117
117
|
|
118
|
-
# @private
|
119
118
|
COLORS = { :red => 31, :green => 32, :yellow => 33 }
|
120
119
|
|
121
120
|
# Prints a status message about performing the given action,
|
@@ -298,7 +297,7 @@ END
|
|
298
297
|
@options[:for_engine][:cache_location] = loc
|
299
298
|
end
|
300
299
|
opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
|
301
|
-
@options[:for_engine][:
|
300
|
+
@options[:for_engine][:read_cache] = false
|
302
301
|
end
|
303
302
|
end
|
304
303
|
|
@@ -569,8 +568,9 @@ END
|
|
569
568
|
# @param args [Array<String>] The command-line arguments
|
570
569
|
def initialize(args)
|
571
570
|
super
|
571
|
+
require 'sass'
|
572
572
|
@options[:for_tree] = {}
|
573
|
-
@options[:for_engine] = {}
|
573
|
+
@options[:for_engine] = {:cache => false, :read_cache => true}
|
574
574
|
end
|
575
575
|
|
576
576
|
# Tells optparse how to parse the arguments.
|
@@ -630,7 +630,7 @@ END
|
|
630
630
|
end
|
631
631
|
|
632
632
|
opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
|
633
|
-
@options[:for_engine][:
|
633
|
+
@options[:for_engine][:read_cache] = false
|
634
634
|
end
|
635
635
|
|
636
636
|
super
|
@@ -654,6 +654,8 @@ END
|
|
654
654
|
process_file(input, output)
|
655
655
|
end
|
656
656
|
|
657
|
+
private
|
658
|
+
|
657
659
|
def process_directory
|
658
660
|
input = @options[:input] = @args.shift
|
659
661
|
output = @options[:output] = @args.shift
|
@@ -665,6 +667,11 @@ END
|
|
665
667
|
end
|
666
668
|
@options[:output] ||= @options[:input]
|
667
669
|
|
670
|
+
if @options[:to] == @options[:from] && !@options[:in_place]
|
671
|
+
fmt = @options[:from]
|
672
|
+
raise "Error: converting from #{fmt} to #{fmt} without --in-place"
|
673
|
+
end
|
674
|
+
|
668
675
|
ext = @options[:from]
|
669
676
|
ext = :sass if ext == :sass2
|
670
677
|
Dir.glob("#{@options[:input]}/**/*.#{ext}") do |f|
|
data/lib/haml/filters.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'haml/helpers/action_view_mods'
|
2
|
-
|
3
1
|
module Haml
|
4
2
|
module Helpers
|
3
|
+
@@action_view_defined = true
|
4
|
+
|
5
5
|
# This module contains various useful helper methods
|
6
6
|
# that either tie into ActionView or the rest of the ActionPack stack,
|
7
7
|
# or are only useful in that context.
|
@@ -51,5 +51,7 @@ module Haml
|
|
51
51
|
@_haml_concat_raw = old
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
include ActionViewExtensions
|
54
56
|
end
|
55
57
|
end
|
@@ -126,7 +126,11 @@ module ActionView
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def content_tag(*args)
|
129
|
-
content_tag_with_haml(*args)
|
129
|
+
html_tag = content_tag_with_haml(*args)
|
130
|
+
return html_tag unless respond_to?(:error_wrapping)
|
131
|
+
return error_wrapping(html_tag) if method(:error_wrapping).arity == 1
|
132
|
+
return html_tag unless object.respond_to?(:errors) && object.errors.respond_to?(:on)
|
133
|
+
return error_wrapping(html_tag, object.errors.on(@method_name))
|
130
134
|
end
|
131
135
|
end
|
132
136
|
|
@@ -156,9 +160,7 @@ module ActionView
|
|
156
160
|
def form_for_with_haml(object_name, *args, &proc)
|
157
161
|
if block_given? && is_haml?
|
158
162
|
oldproc = proc
|
159
|
-
proc =
|
160
|
-
with_tabs(1) {oldproc.call(*args)}
|
161
|
-
end
|
163
|
+
proc = proc {|*args| with_tabs(1) {oldproc.call(*args)}}
|
162
164
|
end
|
163
165
|
res = form_for_without_haml(object_name, *args, &proc)
|
164
166
|
res << "\n" if block_given? && is_haml?
|
data/lib/haml/helpers.rb
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
if defined?(ActionView)
|
2
|
-
require 'haml/helpers/action_view_mods'
|
3
|
-
require 'haml/helpers/action_view_extensions'
|
4
|
-
end
|
5
|
-
|
6
1
|
module Haml
|
7
2
|
# This module contains various helpful methods to make it easier to do various tasks.
|
8
3
|
# {Haml::Helpers} is automatically included in the context
|
@@ -52,8 +47,7 @@ MESSAGE
|
|
52
47
|
|
53
48
|
self.extend self
|
54
49
|
|
55
|
-
@@action_view_defined =
|
56
|
-
@@force_no_action_view = false
|
50
|
+
@@action_view_defined = false
|
57
51
|
|
58
52
|
# @return [Boolean] Whether or not ActionView is loaded
|
59
53
|
def self.action_view?
|
@@ -500,7 +494,6 @@ MESSAGE
|
|
500
494
|
end
|
501
495
|
|
502
496
|
# Characters that need to be escaped to HTML entities from user input
|
503
|
-
# @private
|
504
497
|
HTML_ESCAPE = { '&'=>'&', '<'=>'<', '>'=>'>', '"'=>'"', "'"=>''', }
|
505
498
|
|
506
499
|
# Returns a copy of `text` with ampersands, angle brackets and quotes
|
@@ -594,11 +587,10 @@ MESSAGE
|
|
594
587
|
_erbout = _hamlout.buffer
|
595
588
|
proc { |*args| proc.call(*args) }
|
596
589
|
end
|
597
|
-
|
598
|
-
include ActionViewExtensions if self.const_defined? "ActionViewExtensions"
|
599
590
|
end
|
600
591
|
end
|
601
592
|
|
593
|
+
# @private
|
602
594
|
class Object
|
603
595
|
# Haml overrides various `ActionView` helpers,
|
604
596
|
# which call an \{#is\_haml?} method
|
data/lib/haml/html.rb
CHANGED
data/lib/haml/precompiler.rb
CHANGED
@@ -8,60 +8,46 @@ module Haml
|
|
8
8
|
include Haml::Util
|
9
9
|
|
10
10
|
# Designates an XHTML/XML element.
|
11
|
-
# @private
|
12
11
|
ELEMENT = ?%
|
13
12
|
|
14
13
|
# Designates a `<div>` element with the given class.
|
15
|
-
# @private
|
16
14
|
DIV_CLASS = ?.
|
17
15
|
|
18
16
|
# Designates a `<div>` element with the given id.
|
19
|
-
# @private
|
20
17
|
DIV_ID = ?#
|
21
18
|
|
22
19
|
# Designates an XHTML/XML comment.
|
23
|
-
# @private
|
24
20
|
COMMENT = ?/
|
25
21
|
|
26
22
|
# Designates an XHTML doctype or script that is never HTML-escaped.
|
27
|
-
# @private
|
28
23
|
DOCTYPE = ?!
|
29
24
|
|
30
25
|
# Designates script, the result of which is output.
|
31
|
-
# @private
|
32
26
|
SCRIPT = ?=
|
33
27
|
|
34
28
|
# Designates script that is always HTML-escaped.
|
35
|
-
# @private
|
36
29
|
SANITIZE = ?&
|
37
30
|
|
38
31
|
# Designates script, the result of which is flattened and output.
|
39
|
-
# @private
|
40
32
|
FLAT_SCRIPT = ?~
|
41
33
|
|
42
34
|
# Designates script which is run but not output.
|
43
|
-
# @private
|
44
35
|
SILENT_SCRIPT = ?-
|
45
36
|
|
46
37
|
# When following SILENT_SCRIPT, designates a comment that is not output.
|
47
|
-
# @private
|
48
38
|
SILENT_COMMENT = ?#
|
49
39
|
|
50
40
|
# Designates a non-parsed line.
|
51
|
-
# @private
|
52
41
|
ESCAPE = ?\\
|
53
42
|
|
54
43
|
# Designates a block of filtered text.
|
55
|
-
# @private
|
56
44
|
FILTER = ?:
|
57
45
|
|
58
46
|
# Designates a non-parsed line. Not actually a character.
|
59
|
-
# @private
|
60
47
|
PLAIN_TEXT = -1
|
61
48
|
|
62
49
|
# Keeps track of the ASCII values of the characters that begin a
|
63
50
|
# specially-interpreted line.
|
64
|
-
# @private
|
65
51
|
SPECIAL_CHARACTERS = [
|
66
52
|
ELEMENT,
|
67
53
|
DIV_CLASS,
|
@@ -78,7 +64,6 @@ module Haml
|
|
78
64
|
|
79
65
|
# The value of the character that designates that a line is part
|
80
66
|
# of a multiline string.
|
81
|
-
# @private
|
82
67
|
MULTILINE_CHAR_VALUE = ?|
|
83
68
|
|
84
69
|
# Regex to match keywords that appear in the middle of a Ruby block
|
@@ -94,15 +79,12 @@ module Haml
|
|
94
79
|
#
|
95
80
|
# The block is ended after `%p no!`, because `else`
|
96
81
|
# is a member of this array.
|
97
|
-
# @private
|
98
82
|
MID_BLOCK_KEYWORD_REGEX = /^-\s*(#{%w[else elsif rescue ensure when end].join('|')})\b/
|
99
83
|
|
100
84
|
# The Regex that matches a Doctype command.
|
101
|
-
# @private
|
102
85
|
DOCTYPE_REGEX = /(\d(?:\.\d)?)?[\s]*([a-z]*)/i
|
103
86
|
|
104
87
|
# The Regex that matches a literal string or symbol value
|
105
|
-
# @private
|
106
88
|
LITERAL_VALUE_REGEX = /:(\w*)|(["'])((?![\\#]|\2).|\\.)*\2/
|
107
89
|
|
108
90
|
private
|
@@ -146,6 +128,7 @@ END
|
|
146
128
|
class Line < Struct.new(:text, :unstripped, :full, :index, :precompiler, :eod)
|
147
129
|
alias_method :eod?, :eod
|
148
130
|
|
131
|
+
# @private
|
149
132
|
def tabs
|
150
133
|
line = self
|
151
134
|
@tabs ||= precompiler.instance_eval do
|
@@ -252,6 +235,7 @@ You don't need to use "- end" in Haml. Un-indent to close a block:
|
|
252
235
|
%p This line is un-indented, so it isn't part of the "if" block
|
253
236
|
END
|
254
237
|
|
238
|
+
text = handle_ruby_multiline(text)
|
255
239
|
push_silent(text[1..-1], true)
|
256
240
|
newline_now
|
257
241
|
|
@@ -395,6 +379,7 @@ END
|
|
395
379
|
# the result before it is added to `@buffer`
|
396
380
|
def push_script(text, opts = {})
|
397
381
|
raise SyntaxError.new("There's no Ruby code for = to evaluate.") if text.empty?
|
382
|
+
text = handle_ruby_multiline(text)
|
398
383
|
return if options[:suppress_eval]
|
399
384
|
opts[:escape_html] = options[:escape_html] if opts[:escape_html].nil?
|
400
385
|
|
@@ -781,10 +766,13 @@ END
|
|
781
766
|
end.compact!
|
782
767
|
|
783
768
|
raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", @next_line.index) if block_opened? && self_closing
|
784
|
-
raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", @next_line.index) if block_opened? && !value.empty?
|
785
769
|
raise SyntaxError.new("There's no Ruby code for #{action} to evaluate.", last_line - 1) if parse && value.empty?
|
786
770
|
raise SyntaxError.new("Self-closing tags can't have content.", last_line - 1) if self_closing && !value.empty?
|
787
771
|
|
772
|
+
if block_opened? && !value.empty? && !is_ruby_multiline?(value)
|
773
|
+
raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", @next_line.index)
|
774
|
+
end
|
775
|
+
|
788
776
|
self_closing ||= !!(!block_opened? && value.empty? && @options[:autoclose].any? {|t| t === tag_name})
|
789
777
|
value = nil if value.empty? && (block_opened? || self_closing)
|
790
778
|
|
@@ -984,18 +972,17 @@ END
|
|
984
972
|
end
|
985
973
|
|
986
974
|
def handle_multiline(line)
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
end
|
996
|
-
un_next_line new_line
|
997
|
-
resolve_newlines
|
975
|
+
return unless is_multiline?(line.text)
|
976
|
+
line.text.slice!(-1)
|
977
|
+
while new_line = raw_next_line.first
|
978
|
+
break if new_line == :eod
|
979
|
+
newline and next if new_line.strip.empty?
|
980
|
+
break unless is_multiline?(new_line.strip)
|
981
|
+
line.text << new_line.strip[0...-1]
|
982
|
+
newline
|
998
983
|
end
|
984
|
+
un_next_line new_line
|
985
|
+
resolve_newlines
|
999
986
|
end
|
1000
987
|
|
1001
988
|
# Checks whether or not +line+ is in a multiline sequence.
|
@@ -1003,6 +990,26 @@ END
|
|
1003
990
|
text && text.length > 1 && text[-1] == MULTILINE_CHAR_VALUE && text[-2] == ?\s
|
1004
991
|
end
|
1005
992
|
|
993
|
+
def handle_ruby_multiline(text)
|
994
|
+
text = text.rstrip
|
995
|
+
return text unless is_ruby_multiline?(text)
|
996
|
+
un_next_line @next_line.full
|
997
|
+
begin
|
998
|
+
new_line = raw_next_line.first
|
999
|
+
break if new_line == :eod
|
1000
|
+
newline and next if new_line.strip.empty?
|
1001
|
+
text << " " << new_line.strip
|
1002
|
+
newline
|
1003
|
+
end while is_ruby_multiline?(new_line.strip)
|
1004
|
+
next_line
|
1005
|
+
resolve_newlines
|
1006
|
+
text
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def is_ruby_multiline?(text)
|
1010
|
+
text && text.length > 1 && text[-1] == ?, && text[-2] != ?? && text[-3..-2] != "?\\"
|
1011
|
+
end
|
1012
|
+
|
1006
1013
|
def contains_interpolation?(str)
|
1007
1014
|
str.include?('#{')
|
1008
1015
|
end
|
data/lib/haml/railtie.rb
CHANGED
@@ -3,10 +3,14 @@
|
|
3
3
|
# Yehuda promises there will be soon,
|
4
4
|
# and once there is we should switch to that.
|
5
5
|
|
6
|
-
if defined?(
|
6
|
+
if defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load)
|
7
|
+
# Rails 3.0.0.beta.2+
|
8
|
+
ActiveSupport.on_load(:action_view) {Haml.init_rails(binding)}
|
9
|
+
elsif defined?(Rails::Railtie)
|
10
|
+
# Rails 3.0.0.beta1
|
7
11
|
module Haml
|
8
12
|
class Railtie < Rails::Railtie
|
9
|
-
|
13
|
+
ActiveSupport.on_load(:action_view) do
|
10
14
|
Haml.init_rails(binding)
|
11
15
|
end
|
12
16
|
end
|
data/lib/haml/root.rb
CHANGED
data/lib/haml/template.rb
CHANGED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Haml
|
4
|
+
module Util
|
5
|
+
# A map from sets to values.
|
6
|
+
# A value is \{#\[]= set} by providing a set (the "set-set") and a value,
|
7
|
+
# which is then recorded as corresponding to that set.
|
8
|
+
# Values are \{#\[] accessed} by providing a set (the "get-set")
|
9
|
+
# and returning all values that correspond to set-sets
|
10
|
+
# that are subsets of the get-set.
|
11
|
+
#
|
12
|
+
# SubsetMap preserves the order of values as they're inserted.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# ssm = SubsetMap.new
|
16
|
+
# ssm[Set[1, 2]] = "Foo"
|
17
|
+
# ssm[Set[2, 3]] = "Bar"
|
18
|
+
# ssm[Set[1, 2, 3]] = "Baz"
|
19
|
+
#
|
20
|
+
# ssm[Set[1, 2, 3]] #=> ["Foo", "Bar", "Baz"]
|
21
|
+
class SubsetMap
|
22
|
+
# Creates a new, empty SubsetMap.
|
23
|
+
def initialize
|
24
|
+
@hash = {}
|
25
|
+
@vals = []
|
26
|
+
end
|
27
|
+
|
28
|
+
# Whether or not this SubsetMap has any key-value pairs.
|
29
|
+
#
|
30
|
+
# @return [Boolean]
|
31
|
+
def empty?
|
32
|
+
@hash.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Associates a value with a set.
|
36
|
+
# When `set` or any of its supersets is accessed,
|
37
|
+
# `value` will be among the values returned.
|
38
|
+
#
|
39
|
+
# Note that if the same `set` is passed to this method multiple times,
|
40
|
+
# all given `value`s will be associated with that `set`.
|
41
|
+
#
|
42
|
+
# This runs in `O(n)` time, where `n` is the size of `set`.
|
43
|
+
#
|
44
|
+
# @param set [#to_set] The set to use as the map key. May not be empty.
|
45
|
+
# @param value [Object] The value to associate with `set`.
|
46
|
+
# @raise [ArgumentError] If `set` is empty.
|
47
|
+
def []=(set, value)
|
48
|
+
raise ArgumentError.new("SubsetMap keys may not be empty.") if set.empty?
|
49
|
+
|
50
|
+
index = @vals.size
|
51
|
+
@vals << value
|
52
|
+
set.each do |k|
|
53
|
+
@hash[k] ||= []
|
54
|
+
@hash[k] << [set, set.to_set, index]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns all values associated with subsets of `set`.
|
59
|
+
#
|
60
|
+
# In the worst case, this runs in `O(m*max(n, log m))` time,
|
61
|
+
# where `n` is the size of `set`
|
62
|
+
# and `m` is the number of assocations in the map.
|
63
|
+
# However, unless many keys in the map overlap with `set`,
|
64
|
+
# `m` will typically be much smaller.
|
65
|
+
#
|
66
|
+
# @param set [Set] The set to use as the map key.
|
67
|
+
# @return [Array<(Object, #to_set)>] An array of pairs,
|
68
|
+
# where the first value is the value associated with a subset of `set`,
|
69
|
+
# and the second value is that subset of `set`
|
70
|
+
# (or whatever `#to_set` object was used to set the value)
|
71
|
+
# This array is in insertion order.
|
72
|
+
# @see #[]
|
73
|
+
def get(set)
|
74
|
+
res = set.map do |k|
|
75
|
+
next unless subsets = @hash[k]
|
76
|
+
subsets.map do |subenum, subset, index|
|
77
|
+
next unless subset.subset?(set)
|
78
|
+
[index, subenum]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
res.flatten!(1)
|
82
|
+
res.compact!
|
83
|
+
res.uniq!
|
84
|
+
res.sort!
|
85
|
+
res.map! {|i, s| [@vals[i], s]}
|
86
|
+
return res
|
87
|
+
end
|
88
|
+
|
89
|
+
# Same as \{#get}, but doesn't return the subsets of the argument
|
90
|
+
# for which values were found.
|
91
|
+
#
|
92
|
+
# @param set [Set] The set to use as the map key.
|
93
|
+
# @return [Array] The array of all values
|
94
|
+
# associated with subsets of `set`, in insertion order.
|
95
|
+
# @see #get
|
96
|
+
def [](set)
|
97
|
+
get(set).map {|v, _| v}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/haml/util.rb
CHANGED
@@ -3,6 +3,7 @@ require 'set'
|
|
3
3
|
require 'enumerator'
|
4
4
|
require 'stringio'
|
5
5
|
require 'haml/root'
|
6
|
+
require 'haml/util/subset_map'
|
6
7
|
|
7
8
|
module Haml
|
8
9
|
# A module containing various useful functions.
|
@@ -10,6 +11,7 @@ module Haml
|
|
10
11
|
extend self
|
11
12
|
|
12
13
|
# An array of ints representing the Ruby version number.
|
14
|
+
# @api public
|
13
15
|
RUBY_VERSION = ::RUBY_VERSION.split(".").map {|s| s.to_i}
|
14
16
|
|
15
17
|
# Returns the path of a file relative to the Haml root directory.
|
@@ -135,6 +137,33 @@ module Haml
|
|
135
137
|
end
|
136
138
|
end
|
137
139
|
|
140
|
+
# Intersperses a value in an enumerable, as would be done with `Array#join`
|
141
|
+
# but without concatenating the array together afterwards.
|
142
|
+
#
|
143
|
+
# @param enum [Enumerable]
|
144
|
+
# @param val
|
145
|
+
# @return [Array]
|
146
|
+
def intersperse(enum, val)
|
147
|
+
enum.inject([]) {|a, e| a << e << val}[0...-1]
|
148
|
+
end
|
149
|
+
|
150
|
+
# Substitutes a sub-array of one array with another sub-array.
|
151
|
+
#
|
152
|
+
# @param ary [Array] The array in which to make the substitution
|
153
|
+
# @param from [Array] The sequence of elements to replace with `to`
|
154
|
+
# @param to [Array] The sequence of elements to replace `from` with
|
155
|
+
def substitute(ary, from, to)
|
156
|
+
res = ary.dup
|
157
|
+
i = 0
|
158
|
+
while i < res.size
|
159
|
+
if res[i...i+from.size] == from
|
160
|
+
res[i...i+from.size] = to
|
161
|
+
end
|
162
|
+
i += 1
|
163
|
+
end
|
164
|
+
res
|
165
|
+
end
|
166
|
+
|
138
167
|
# Destructively strips whitespace from the beginning and end
|
139
168
|
# of the first and last elements, respectively,
|
140
169
|
# in the array (if those elements are strings).
|
@@ -147,6 +176,23 @@ module Haml
|
|
147
176
|
arr
|
148
177
|
end
|
149
178
|
|
179
|
+
# Return an array of all possible paths through the given arrays.
|
180
|
+
#
|
181
|
+
# @param arrs [Array<Array>]
|
182
|
+
# @return [Array<Arrays>]
|
183
|
+
#
|
184
|
+
# @example
|
185
|
+
# paths([[1, 2], [3, 4], [5]]) #=>
|
186
|
+
# # [[1, 3, 5],
|
187
|
+
# # [2, 3, 5],
|
188
|
+
# # [1, 4, 5],
|
189
|
+
# # [2, 4, 5]]
|
190
|
+
def paths(arrs)
|
191
|
+
arrs.inject([[]]) do |paths, arr|
|
192
|
+
arr.map {|e| paths.map {|path| path + [e]}}.flatten(1)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
150
196
|
# Returns information about the caller of the previous method.
|
151
197
|
#
|
152
198
|
# @param entry [String] An entry in the `#caller` list, or a similarly formatted string
|
@@ -237,6 +283,30 @@ module Haml
|
|
237
283
|
ActionPack::VERSION::TINY == "0.beta")
|
238
284
|
end
|
239
285
|
|
286
|
+
# Returns whether this environment is using ActionPack
|
287
|
+
# version 3.0.0.beta.3 or greater.
|
288
|
+
#
|
289
|
+
# @return [Boolean]
|
290
|
+
def ap_geq_3_beta_3?
|
291
|
+
# The ActionPack module is always loaded automatically in Rails >= 3
|
292
|
+
return false unless defined?(ActionPack) && defined?(ActionPack::VERSION)
|
293
|
+
|
294
|
+
version =
|
295
|
+
if defined?(ActionPack::VERSION::MAJOR)
|
296
|
+
ActionPack::VERSION::MAJOR
|
297
|
+
else
|
298
|
+
# Rails 1.2
|
299
|
+
ActionPack::VERSION::Major
|
300
|
+
end
|
301
|
+
version >= 3 &&
|
302
|
+
((defined?(ActionPack::VERSION::TINY) &&
|
303
|
+
ActionPack::VERSION::TINY.is_a?(Fixnum) &&
|
304
|
+
ActionPack::VERSION::TINY >= 1) ||
|
305
|
+
(defined?(ActionPack::VERSION::BUILD) &&
|
306
|
+
ActionPack::VERSION::BUILD =~ /beta(\d+)/ &&
|
307
|
+
$1.to_i >= 3))
|
308
|
+
end
|
309
|
+
|
240
310
|
# Returns an ActionView::Template* class.
|
241
311
|
# In pre-3.0 versions of Rails, most of these classes
|
242
312
|
# were of the form `ActionView::TemplateFoo`,
|
@@ -282,6 +352,10 @@ module Haml
|
|
282
352
|
raise Haml::Error.new("Expected #{text.inspect} to be HTML-safe.")
|
283
353
|
end
|
284
354
|
|
355
|
+
# The class for the Rails SafeBuffer XSS protection class.
|
356
|
+
# This varies depending on Rails version.
|
357
|
+
#
|
358
|
+
# @return [Class]
|
285
359
|
def rails_safe_buffer_class
|
286
360
|
return ActionView::SafeBuffer if defined?(ActionView::SafeBuffer)
|
287
361
|
ActiveSupport::SafeBuffer
|
data/lib/haml.rb
CHANGED
@@ -17,6 +17,7 @@ module Haml
|
|
17
17
|
|
18
18
|
# A string representing the version of Haml.
|
19
19
|
# A more fine-grained representation is available from Haml.version.
|
20
|
+
# @api public
|
20
21
|
VERSION = version[:string] unless defined?(Haml::VERSION)
|
21
22
|
|
22
23
|
# Initializes Haml for Rails.
|
@@ -37,5 +38,7 @@ module Haml
|
|
37
38
|
end
|
38
39
|
|
39
40
|
require 'haml/util'
|
40
|
-
|
41
|
-
require 'haml/
|
41
|
+
unless $0 =~ /sass(-convert)?$/
|
42
|
+
require 'haml/engine'
|
43
|
+
require 'haml/railtie'
|
44
|
+
end
|