haml-edge 2.1.21 → 2.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/EDGE_GEM_VERSION +1 -1
  2. data/FAQ.md +142 -0
  3. data/{README.rdoc → README.md} +141 -141
  4. data/Rakefile +29 -17
  5. data/VERSION +1 -1
  6. data/lib/haml/buffer.rb +63 -27
  7. data/lib/haml/engine.rb +103 -80
  8. data/lib/haml/error.rb +7 -7
  9. data/lib/haml/exec.rb +80 -26
  10. data/lib/haml/filters.rb +106 -40
  11. data/lib/haml/helpers/action_view_extensions.rb +34 -39
  12. data/lib/haml/helpers/action_view_mods.rb +132 -139
  13. data/lib/haml/helpers.rb +207 -153
  14. data/lib/haml/html.rb +40 -21
  15. data/lib/haml/precompiler.rb +2 -0
  16. data/lib/haml/shared.rb +34 -3
  17. data/lib/haml/template/patch.rb +1 -1
  18. data/lib/haml/template/plugin.rb +0 -2
  19. data/lib/haml/template.rb +5 -0
  20. data/lib/haml/util.rb +136 -1
  21. data/lib/haml/version.rb +16 -4
  22. data/lib/haml.rb +502 -481
  23. data/lib/sass/css.rb +106 -68
  24. data/lib/sass/engine.rb +55 -22
  25. data/lib/sass/environment.rb +52 -21
  26. data/lib/sass/error.rb +23 -12
  27. data/lib/sass/files.rb +27 -0
  28. data/lib/sass/plugin/merb.rb +2 -2
  29. data/lib/sass/plugin/rails.rb +0 -2
  30. data/lib/sass/plugin.rb +32 -23
  31. data/lib/sass/repl.rb +7 -0
  32. data/lib/sass/script/bool.rb +9 -5
  33. data/lib/sass/script/color.rb +87 -1
  34. data/lib/sass/script/funcall.rb +23 -2
  35. data/lib/sass/script/functions.rb +93 -44
  36. data/lib/sass/script/lexer.rb +33 -3
  37. data/lib/sass/script/literal.rb +93 -1
  38. data/lib/sass/script/node.rb +14 -0
  39. data/lib/sass/script/number.rb +128 -4
  40. data/lib/sass/script/operation.rb +16 -1
  41. data/lib/sass/script/parser.rb +51 -21
  42. data/lib/sass/script/string.rb +7 -4
  43. data/lib/sass/script/unary_operation.rb +14 -1
  44. data/lib/sass/script/variable.rb +12 -1
  45. data/lib/sass/script.rb +26 -5
  46. data/lib/sass/tree/attr_node.rb +46 -9
  47. data/lib/sass/tree/comment_node.rb +41 -1
  48. data/lib/sass/tree/debug_node.rb +8 -0
  49. data/lib/sass/tree/directive_node.rb +20 -0
  50. data/lib/sass/tree/file_node.rb +12 -0
  51. data/lib/sass/tree/for_node.rb +15 -0
  52. data/lib/sass/tree/if_node.rb +22 -0
  53. data/lib/sass/tree/mixin_def_node.rb +12 -1
  54. data/lib/sass/tree/mixin_node.rb +13 -0
  55. data/lib/sass/tree/node.rb +136 -6
  56. data/lib/sass/tree/rule_node.rb +66 -7
  57. data/lib/sass/tree/variable_node.rb +10 -0
  58. data/lib/sass/tree/while_node.rb +11 -1
  59. data/lib/sass.rb +544 -534
  60. metadata +7 -6
  61. data/FAQ +0 -138
data/lib/haml/html.rb CHANGED
@@ -6,13 +6,19 @@ require 'hpricot'
6
6
  require 'cgi'
7
7
 
8
8
  module Haml
9
- # This class contains the functionality used in the +html2haml+ utility,
10
- # namely converting HTML documents to Haml templates.
11
- # It depends on Hpricot for HTML parsing (http://code.whytheluckystiff.net/hpricot/).
9
+ # Converts HTML documents into Haml templates.
10
+ # Depends on [Hpricot](http://code.whytheluckystiff.net/hpricot/) for HTML parsing.
11
+ #
12
+ # Example usage:
13
+ #
14
+ # Haml::Engine.new("<a href='http://google.com'>Blat</a>").render
15
+ # #=> "%a{:href => 'http://google.com'} Blat"
12
16
  class HTML
13
- # Creates a new instance of Haml::HTML that will compile the given template,
14
- # which can either be a string containing HTML or an Hpricot node,
15
- # to a Haml string when +render+ is called.
17
+ # @param template [String, Hpricot::Node] The HTML template to convert
18
+ # @option options :rhtml [Boolean] (false) Whether or not to parse
19
+ # ERB's `<%= %>` and `<% %>` into Haml's `=` and `-`
20
+ # @option options :xhtml [Boolean] (false) Whether or not to parse
21
+ # the HTML strictly as XHTML
16
22
  def initialize(template, options = {})
17
23
  @options = options
18
24
 
@@ -40,9 +46,13 @@ module Haml
40
46
  end
41
47
  alias_method :to_haml, :render
42
48
 
49
+ # Haml monkeypatches various Hpricot classes
50
+ # to add methods for conversion to Haml.
43
51
  module ::Hpricot::Node
44
- # Returns the Haml representation of the given node,
45
- # at the given tabulation.
52
+ # Returns the Haml representation of the given node.
53
+ #
54
+ # @param tabs [Fixnum] The indentation level of the resulting Haml.
55
+ # @option options (see Haml::HTML#initialize)
46
56
  def to_haml(tabs, options)
47
57
  parse_text(self.to_s, tabs)
48
58
  end
@@ -68,29 +78,35 @@ module Haml
68
78
  end
69
79
  end
70
80
 
71
- # :stopdoc:
72
-
73
81
  TEXT_REGEXP = /^(\s*).*$/
74
82
 
83
+ # @see Hpricot::Node
75
84
  class ::Hpricot::Doc
85
+ # @see Hpricot::Node#to_haml
76
86
  def to_haml(tabs, options)
77
87
  (children || []).inject('') {|s, c| s << c.to_haml(0, options)}
78
88
  end
79
89
  end
80
90
 
91
+ # @see Hpricot::Node
81
92
  class ::Hpricot::XMLDecl
93
+ # @see Hpricot::Node#to_haml
82
94
  def to_haml(tabs, options)
83
95
  "#{tabulate(tabs)}!!! XML\n"
84
96
  end
85
97
  end
86
98
 
99
+ # @see Hpricot::Node
87
100
  class ::Hpricot::CData
101
+ # @see Hpricot::Node#to_haml
88
102
  def to_haml(tabs, options)
89
103
  "#{tabulate(tabs)}:cdata\n#{parse_text(self.content, tabs + 1)}"
90
104
  end
91
105
  end
92
106
 
107
+ # @see Hpricot::Node
93
108
  class ::Hpricot::DocType
109
+ # @see Hpricot::Node#to_haml
94
110
  def to_haml(tabs, options)
95
111
  attrs = public_id.scan(/DTD\s+([^\s]+)\s*([^\s]*)\s*([^\s]*)\s*\/\//)[0]
96
112
  if attrs == nil
@@ -121,17 +137,21 @@ module Haml
121
137
  end
122
138
  end
123
139
 
140
+ # @see Hpricot::Node
124
141
  class ::Hpricot::Comment
142
+ # @see Hpricot::Node#to_haml
125
143
  def to_haml(tabs, options)
126
144
  "#{tabulate(tabs)}/\n#{parse_text(self.content, tabs + 1)}"
127
145
  end
128
146
  end
129
147
 
148
+ # @see Hpricot::Node
130
149
  class ::Hpricot::Elem
150
+ # @see Hpricot::Node#to_haml
131
151
  def to_haml(tabs, options)
132
152
  output = "#{tabulate(tabs)}"
133
153
  if options[:rhtml] && name[0...5] == 'haml:'
134
- return output + HTML.send("haml_tag_#{name[5..-1]}", CGI.unescapeHTML(self.inner_text))
154
+ return output + send("haml_tag_#{name[5..-1]}", CGI.unescapeHTML(self.inner_text))
135
155
  end
136
156
 
137
157
  output += "%#{name}" unless name == 'div' &&
@@ -170,7 +190,15 @@ module Haml
170
190
  end
171
191
  end
172
192
  end
173
-
193
+
194
+ def haml_tag_loud(text)
195
+ "= #{text.gsub(/\n\s*/, ' ').strip}\n"
196
+ end
197
+
198
+ def haml_tag_silent(text)
199
+ text.split("\n").map { |line| "- #{line.strip}\n" }.join
200
+ end
201
+
174
202
  def static_attribute?(name, options)
175
203
  attributes[name] and !dynamic_attribute?(name, options)
176
204
  end
@@ -199,14 +227,6 @@ module Haml
199
227
  end
200
228
  end
201
229
 
202
- def self.haml_tag_loud(text)
203
- "= #{text.gsub(/\n\s*/, ' ').strip}\n"
204
- end
205
-
206
- def self.haml_tag_silent(text)
207
- text.split("\n").map { |line| "- #{line.strip}\n" }.join
208
- end
209
-
210
230
  private
211
231
 
212
232
  def match_to_html(string, regex, tag)
@@ -214,6 +234,5 @@ module Haml
214
234
  "<haml:#{tag}>#{CGI.escapeHTML($1)}</haml:#{tag}>"
215
235
  end
216
236
  end
217
- # :startdoc:
218
237
  end
219
238
  end
@@ -2,6 +2,8 @@ require 'strscan'
2
2
  require 'haml/shared'
3
3
 
4
4
  module Haml
5
+ # Handles the internal pre-compilation from Haml into Ruby code,
6
+ # which then runs the final creation of the HTML string.
5
7
  module Precompiler
6
8
  include Haml::Util
7
9
 
data/lib/haml/shared.rb CHANGED
@@ -1,17 +1,43 @@
1
1
  require 'strscan'
2
2
 
3
- # :stopdoc:
4
3
  module Haml
5
- # This module contains functionality that's shared across Haml and Sass.
4
+ # This module contains functionality that's shared between Haml and Sass.
6
5
  module Shared
7
6
  extend self
8
7
 
8
+ # Scans through a string looking for the interoplation-opening `#{`
9
+ # and, when it's found, yields the scanner to the calling code
10
+ # so it can handle it properly.
11
+ #
12
+ # The scanner will have any backslashes immediately in front of the `#{`
13
+ # as the second capture group (`scan[2]`),
14
+ # and the text prior to that as the first (`scan[1]`).
15
+ #
16
+ # @yieldparam scan [StringScanner] The scanner scanning through the string
17
+ # @return [String] The text remaining in the scanner after all `#{`s have been processed
9
18
  def handle_interpolation(str)
10
19
  scan = StringScanner.new(str)
11
20
  yield scan while scan.scan(/(.*?)(\\*)\#\{/)
12
21
  scan.rest
13
22
  end
14
23
 
24
+ # Moves a scanner through a balanced pair of characters.
25
+ # For example:
26
+ #
27
+ # Foo (Bar (Baz bang) bop) (Bang (bop bip))
28
+ # ^ ^
29
+ # from to
30
+ #
31
+ # @param scanner [StringScanner] The string scanner to move
32
+ # @param start [Character] The character opening the balanced pair.
33
+ # A `Fixnum` in 1.8, a `String` in 1.9
34
+ # @param finish [Character] The character closing the balanced pair.
35
+ # A `Fixnum` in 1.8, a `String` in 1.9
36
+ # @param count [Fixnum] The number of opening characters matched
37
+ # before calling this method
38
+ # @return [(String, String)] The string matched within the balanced pair
39
+ # and the rest of the string.
40
+ # `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
15
41
  def balance(scanner, start, finish, count = 0)
16
42
  str = ''
17
43
  scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner
@@ -24,6 +50,12 @@ module Haml
24
50
  end
25
51
  end
26
52
 
53
+ # Formats a string for use in error messages about indentation.
54
+ #
55
+ # @param indentation [String] The string used for indentation
56
+ # @param was [Boolean] Whether or not to add `"was"` or `"were"`
57
+ # (depending on how many characters were in `indentation`)
58
+ # @return [String] The name of the indentation (e.g. `"12 spaces"`, `"1 tab"`)
27
59
  def human_indentation(indentation, was = false)
28
60
  if !indentation.include?(?\t)
29
61
  noun = 'space'
@@ -44,4 +76,3 @@ module Haml
44
76
  end
45
77
  end
46
78
  end
47
- # :startdoc:
@@ -9,7 +9,7 @@
9
9
  # The documentation can be found
10
10
  # here[http://rubyonrails.org/api/classes/ActionView/Base.html].
11
11
  module ActionView
12
- class Base # :nodoc:
12
+ class Base
13
13
  def delegate_template_exists_with_haml(template_path)
14
14
  template_exists?(template_path, :haml) && [:haml]
15
15
  end
@@ -1,4 +1,3 @@
1
- # :stopdoc:
2
1
  # This file makes Haml work with Rails
3
2
  # using the > 2.0.1 template handler API.
4
3
 
@@ -70,4 +69,3 @@ if ActionView::TemplateError.instance_method(:initialize).arity == 5
70
69
  end
71
70
  end
72
71
  end
73
- # :startdoc:
data/lib/haml/template.rb CHANGED
@@ -1,10 +1,15 @@
1
1
  require 'haml/engine'
2
2
 
3
3
  module Haml
4
+ # The class that keeps track of the global options for Haml within Rails.
4
5
  module Template
5
6
  extend self
6
7
 
7
8
  @options = {}
9
+ # The options hash for Haml when used within Rails.
10
+ # See [the Haml options documentation](../Haml.html#haml_options).
11
+ #
12
+ # @return [Hash<Symbol, Object>]
8
13
  attr_accessor :options
9
14
  end
10
15
  end
data/lib/haml/util.rb CHANGED
@@ -3,32 +3,94 @@ require 'set'
3
3
  require 'enumerator'
4
4
 
5
5
  module Haml
6
+ # A module containing various useful functions.
6
7
  module Util
7
8
  extend self
8
9
 
10
+ # An array of ints representing the Ruby version number.
9
11
  RUBY_VERSION = ::RUBY_VERSION.split(".").map {|s| s.to_i}
10
12
 
11
- # Returns the path of file relative to the Haml root.
13
+ # Returns the path of a file relative to the Haml root directory.
14
+ #
15
+ # @param file [String] The filename relative to the Haml root
16
+ # @return [String] The filename relative to the the working directory
12
17
  def scope(file)
13
18
  File.expand_path File.join(File.dirname(__FILE__), '..', '..', file)
14
19
  end
15
20
 
21
+ # Converts an array of `[key, value]` pairs to a hash.
22
+ # For example:
23
+ #
24
+ # to_hash([[:foo, "bar"], [:baz, "bang"]])
25
+ # #=> {:foo => "bar", :baz => "bang"}
26
+ #
27
+ # @param arr [Array<(Object, Object)>] An array of pairs
28
+ # @return [Hash] A hash
16
29
  def to_hash(arr)
17
30
  arr.compact.inject({}) {|h, (k, v)| h[k] = v; h}
18
31
  end
19
32
 
33
+ # Maps the keys in a hash according to a block.
34
+ # For example:
35
+ #
36
+ # map_keys({:foo => "bar", :baz => "bang"}) {|k| k.to_s}
37
+ # #=> {"foo" => "bar", "baz" => "bang"}
38
+ #
39
+ # @param hash [Hash] The hash to map
40
+ # @yield [key] A block in which the keys are transformed
41
+ # @yieldparam key [Object] The key that should be mapped
42
+ # @yieldreturn [Object] The new value for the key
43
+ # @return [Hash] The mapped hash
44
+ # @see #map_vals
45
+ # @see #map_hash
20
46
  def map_keys(hash)
21
47
  to_hash(hash.map {|k, v| [yield(k), v]})
22
48
  end
23
49
 
50
+ # Maps the values in a hash according to a block.
51
+ # For example:
52
+ #
53
+ # map_values({:foo => "bar", :baz => "bang"}) {|v| v.to_sym}
54
+ # #=> {:foo => :bar, :baz => :bang}
55
+ #
56
+ # @param hash [Hash] The hash to map
57
+ # @yield [value] A block in which the values are transformed
58
+ # @yieldparam value [Object] The value that should be mapped
59
+ # @yieldreturn [Object] The new value for the value
60
+ # @return [Hash] The mapped hash
61
+ # @see #map_keys
62
+ # @see #map_hash
24
63
  def map_vals(hash)
25
64
  to_hash(hash.map {|k, v| [k, yield(v)]})
26
65
  end
27
66
 
67
+ # Maps the key-value pairs of a hash according to a block.
68
+ # For example:
69
+ #
70
+ # map_hash({:foo => "bar", :baz => "bang"}) {|k, v| [k.to_s, v.to_sym]}
71
+ # #=> {"foo" => :bar, "baz" => :bang}
72
+ #
73
+ # @param hash [Hash] The hash to map
74
+ # @yield [key, value] A block in which the key-value pairs are transformed
75
+ # @yieldparam [key] The hash key
76
+ # @yieldparam [value] The hash value
77
+ # @yieldreturn [(Object, Object)] The new value for the `[key, value]` pair
78
+ # @return [Hash] The mapped hash
79
+ # @see #map_keys
80
+ # @see #map_vals
28
81
  def map_hash(hash, &block)
29
82
  to_hash(hash.map(&block))
30
83
  end
31
84
 
85
+ # Computes the powerset of the given array.
86
+ # This is the set of all subsets of the array.
87
+ # For example:
88
+ #
89
+ # powerset([1, 2, 3]) #=>
90
+ # Set[Set[], Set[1], Set[2], Set[3], Set[1, 2], Set[2, 3], Set[1, 3], Set[1, 2, 3]]
91
+ #
92
+ # @param arr [Enumerable]
93
+ # @return [Set<Set>] The subsets of `arr`
32
94
  def powerset(arr)
33
95
  arr.inject([Set.new].to_set) do |powerset, el|
34
96
  new_powerset = Set.new
@@ -40,6 +102,15 @@ module Haml
40
102
  end
41
103
  end
42
104
 
105
+ # Concatenates all strings that are adjacent in an array,
106
+ # while leaving other elements as they are.
107
+ # For example:
108
+ #
109
+ # merge_adjacent_strings([1, "foo", "bar", 2, "baz"])
110
+ # #=> [1, "foobar", 2, "baz"]
111
+ #
112
+ # @param enum [Enumerable]
113
+ # @return [Array] The enumerable with strings merged
43
114
  def merge_adjacent_strings(enum)
44
115
  e = enum.inject([]) do |a, e|
45
116
  if e.is_a?(String) && a.last.is_a?(String)
@@ -51,29 +122,88 @@ module Haml
51
122
  end
52
123
  end
53
124
 
125
+ # Whether or not this is running under Ruby 1.8 or lower.
126
+ #
127
+ # @return [Boolean]
54
128
  def ruby1_8?
55
129
  Haml::Util::RUBY_VERSION[0] == 1 && Haml::Util::RUBY_VERSION[1] < 9
56
130
  end
57
131
 
132
+ # Checks to see if a class has a given method.
133
+ # For example:
134
+ #
135
+ # Haml::Util.has?(:public_instance_method, String, :gsub) #=> true
136
+ #
137
+ # Method collections like `Class#instance_methods`
138
+ # return strings in Ruby 1.8 and symbols in Ruby 1.9 and on,
139
+ # so this handles checking for them in a compatible way.
140
+ #
141
+ # @param attr [#to_s] The (singular) name of the method-collection method
142
+ # (e.g. `:instance_methods`, `:private_methods`)
143
+ # @param klass [Module] The class to check the methods of which to check
144
+ # @param method [String, Symbol] The name of the method do check for
145
+ # @return [Boolean] Whether or not the given collection has the given method
58
146
  def has?(attr, klass, method)
59
147
  klass.send("#{attr}s").include?(ruby1_8? ? method.to_s : method.to_sym)
60
148
  end
61
149
 
150
+ # A version of `Enumerable#enum_with_index` that works in Ruby 1.8 and 1.9.
151
+ #
152
+ # @param enum [Enumerable] The enumerable to get the enumerator for
153
+ # @return [Enumerator] The with-index enumerator
62
154
  def enum_with_index(enum)
63
155
  ruby1_8? ? enum.enum_with_index : enum.each_with_index
64
156
  end
65
157
 
158
+ # The context in which the ERB for \{#def\_static\_method} will be run.
66
159
  class StaticConditionalContext
160
+ # @param set [#include?] The set of variables that are defined for this context.
67
161
  def initialize(set)
68
162
  @set = set
69
163
  end
70
164
 
165
+ # Checks whether or not a variable is defined for this context.
166
+ #
167
+ # @param name [Symbol] The name of the variable
168
+ # @return [Boolean]
71
169
  def method_missing(name, *args, &block)
72
170
  super unless args.empty? && block.nil?
73
171
  @set.include?(name)
74
172
  end
75
173
  end
76
174
 
175
+ # This is used for methods in {Haml::Buffer} that need to be very fast,
176
+ # and take a lot of boolean parameters
177
+ # that are known at compile-time.
178
+ # Instead of passing the parameters in normally,
179
+ # a separate method is defined for every possible combination of those parameters;
180
+ # these are then called using \{#static\_method\_name}.
181
+ #
182
+ # To define a static method, an ERB template for the method is provided.
183
+ # All conditionals based on the static parameters
184
+ # are done as embedded Ruby within this template.
185
+ # For example:
186
+ #
187
+ # def_static_method(Foo, :my_static_method, [:foo, :bar], :baz, :bang, <<RUBY)
188
+ # <% if baz && bang %>
189
+ # return foo + bar
190
+ # <% elsif baz || bang %>
191
+ # return foo - bar
192
+ # <% else %>
193
+ # return 17
194
+ # <% end %>
195
+ # RUBY
196
+ #
197
+ # \{#static\_method\_name} can be used to call static methods.
198
+ #
199
+ # @overload def_static_method(klass, name, args, *vars, erb)
200
+ # @param klass [Module] The class on which to define the static method
201
+ # @param name [#to_s] The (base) name of the static method
202
+ # @param args [Array<Symbol>] The names of the arguments to the defined methods
203
+ # (**not** to the ERB template)
204
+ # @param vars [Array<Symbol>] The names of the static boolean variables
205
+ # to be made available to the ERB template
206
+ # @param erb [String] The template for the method code
77
207
  def def_static_method(klass, name, args, *vars)
78
208
  erb = vars.pop
79
209
  powerset(vars).each do |set|
@@ -86,6 +216,11 @@ METHOD
86
216
  end
87
217
  end
88
218
 
219
+ # Computes the name for a method defined via \{#def\_static\_method}.
220
+ #
221
+ # @param name [String] The base name of the static method
222
+ # @param vars [Array<Boolean>] The static variable assignment
223
+ # @return [String] The real name of the static method
89
224
  def static_method_name(name, *vars)
90
225
  "#{name}_#{vars.map {|v| !!v}.join('_')}"
91
226
  end
data/lib/haml/version.rb CHANGED
@@ -1,14 +1,26 @@
1
1
  require 'haml/util'
2
2
 
3
3
  module Haml
4
+ # Handles Haml version-reporting.
5
+ # Haml not only reports the standard three version numbers,
6
+ # but its Git revision hash as well,
7
+ # if it was installed from Git.
4
8
  module Version
5
9
  include Haml::Util
6
10
 
7
11
  # Returns a hash representing the version of Haml.
8
- # The :major, :minor, and :teeny keys have their respective numbers.
9
- # The :string key contains a human-readable string representation of the version.
10
- # If Haml is checked out from Git,
11
- # the :rev key will have the revision hash.
12
+ # The `:major`, `:minor`, and `:teeny` keys have their respective numbers as Fixnums.
13
+ # The `:string` key contains a human-readable string representation of the version.
14
+ # If Haml is checked out from Git, the `:rev` key will have the revision hash.
15
+ # For example:
16
+ #
17
+ # {
18
+ # :string=>"2.1.0.9616393",
19
+ # :rev => "9616393b8924ef36639c7e82aa88a51a24d16949",
20
+ # :major => 2, :minor => 1, :teeny => 0
21
+ # }
22
+ #
23
+ # @return [Hash<Symbol, String/Symbol>] The version hash
12
24
  def version
13
25
  return @@version if defined?(@@version)
14
26