haml 1.8.0 → 2.0.0

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 (82) hide show
  1. data/FAQ +138 -0
  2. data/MIT-LICENSE +1 -1
  3. data/{README → README.rdoc} +66 -3
  4. data/Rakefile +111 -147
  5. data/VERSION +1 -1
  6. data/bin/css2sass +0 -0
  7. data/bin/haml +0 -0
  8. data/bin/html2haml +0 -0
  9. data/bin/sass +0 -0
  10. data/init.rb +6 -1
  11. data/lib/haml/buffer.rb +121 -63
  12. data/lib/haml/engine.rb +67 -44
  13. data/lib/haml/error.rb +16 -6
  14. data/lib/haml/exec.rb +37 -7
  15. data/lib/haml/filters.rb +213 -68
  16. data/lib/haml/helpers/action_view_extensions.rb +1 -1
  17. data/lib/haml/helpers/action_view_mods.rb +57 -9
  18. data/lib/haml/helpers.rb +105 -61
  19. data/lib/haml/html.rb +6 -6
  20. data/lib/haml/precompiler.rb +268 -132
  21. data/lib/haml/template/patch.rb +9 -2
  22. data/lib/haml/template/plugin.rb +61 -10
  23. data/lib/haml/template.rb +3 -6
  24. data/lib/haml.rb +464 -201
  25. data/lib/sass/constant/color.rb +13 -13
  26. data/lib/sass/constant/literal.rb +7 -7
  27. data/lib/sass/constant/number.rb +9 -9
  28. data/lib/sass/constant/operation.rb +4 -4
  29. data/lib/sass/constant/string.rb +3 -3
  30. data/lib/sass/constant.rb +22 -22
  31. data/lib/sass/css.rb +104 -31
  32. data/lib/sass/engine.rb +120 -39
  33. data/lib/sass/error.rb +1 -1
  34. data/lib/sass/plugin/merb.rb +48 -12
  35. data/lib/sass/plugin/rails.rb +10 -4
  36. data/lib/sass/plugin.rb +22 -3
  37. data/lib/sass/tree/attr_node.rb +5 -5
  38. data/lib/sass/tree/directive_node.rb +2 -7
  39. data/lib/sass/tree/node.rb +1 -12
  40. data/lib/sass/tree/rule_node.rb +39 -31
  41. data/lib/sass/tree/value_node.rb +1 -1
  42. data/lib/sass.rb +157 -12
  43. data/test/benchmark.rb +67 -80
  44. data/test/haml/engine_test.rb +318 -81
  45. data/test/haml/helper_test.rb +52 -16
  46. data/test/haml/results/content_for_layout.xhtml +1 -2
  47. data/test/haml/results/eval_suppressed.xhtml +2 -4
  48. data/test/haml/results/filters.xhtml +44 -15
  49. data/test/haml/results/helpers.xhtml +2 -3
  50. data/test/haml/results/just_stuff.xhtml +2 -6
  51. data/test/haml/results/nuke_inner_whitespace.xhtml +34 -0
  52. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  53. data/test/haml/results/original_engine.xhtml +3 -7
  54. data/test/haml/results/partials.xhtml +1 -0
  55. data/test/haml/results/tag_parsing.xhtml +1 -6
  56. data/test/haml/results/very_basic.xhtml +2 -4
  57. data/test/haml/results/whitespace_handling.xhtml +13 -21
  58. data/test/haml/template_test.rb +8 -15
  59. data/test/haml/templates/_partial.haml +1 -0
  60. data/test/haml/templates/filters.haml +48 -7
  61. data/test/haml/templates/helpers.haml +9 -9
  62. data/test/haml/templates/just_stuff.haml +1 -2
  63. data/test/haml/templates/nuke_inner_whitespace.haml +26 -0
  64. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  65. data/test/haml/templates/tag_parsing.haml +0 -3
  66. data/test/haml/test_helper.rb +15 -0
  67. data/test/sass/engine_test.rb +84 -34
  68. data/test/sass/plugin_test.rb +1 -1
  69. data/test/sass/results/import.css +2 -2
  70. data/test/sass/results/mixins.css +95 -0
  71. data/test/sass/results/multiline.css +24 -0
  72. data/test/sass/templates/import.sass +4 -1
  73. data/test/sass/templates/importee.sass +4 -0
  74. data/test/sass/templates/mixins.sass +76 -0
  75. data/test/sass/templates/multiline.sass +20 -0
  76. metadata +65 -53
  77. data/lib/haml/helpers/action_view_mods.rb.rej +0 -30
  78. data/lib/haml/util.rb +0 -18
  79. data/lib/sass/constant.rb.rej +0 -42
  80. data/test/haml/runner.rb +0 -16
  81. data/test/profile.rb +0 -65
  82. data/test/sass/engine_test.rb.rej +0 -18
data/lib/haml/buffer.rb CHANGED
@@ -6,11 +6,6 @@ module Haml
6
6
  class Buffer
7
7
  include Haml::Helpers
8
8
 
9
- # Set the maximum length for a line to be considered a one-liner.
10
- # Lines <= the maximum will be rendered on one line,
11
- # i.e. <tt><p>Hello world</p></tt>
12
- ONE_LINER_LENGTH = 50
13
-
14
9
  # The string that holds the compiled XHTML. This is aliased as
15
10
  # _erbout for compatibility with ERB-specific code.
16
11
  attr_accessor :buffer
@@ -18,6 +13,47 @@ module Haml
18
13
  # The options hash passed in from Haml::Engine.
19
14
  attr_accessor :options
20
15
 
16
+ # The Buffer for the enclosing Haml document.
17
+ # This is set for partials and similar sorts of nested templates.
18
+ # It's nil at the top level (see #toplevel?).
19
+ attr_accessor :upper
20
+
21
+ # See #active?
22
+ attr_writer :active
23
+
24
+ # True if the format is XHTML
25
+ def xhtml?
26
+ not html?
27
+ end
28
+
29
+ # True if the format is any flavor of HTML
30
+ def html?
31
+ html4? or html5?
32
+ end
33
+
34
+ # True if the format is HTML4
35
+ def html4?
36
+ @options[:format] == :html4
37
+ end
38
+
39
+ # True if the format is HTML5
40
+ def html5?
41
+ @options[:format] == :html5
42
+ end
43
+
44
+ # True if this buffer is a top-level template,
45
+ # as opposed to a nested partial.
46
+ def toplevel?
47
+ upper.nil?
48
+ end
49
+
50
+ # True if this buffer is currently being used to render a Haml template.
51
+ # However, this returns false if a subtemplate is being rendered,
52
+ # even if it's a subtemplate of this buffer's template.
53
+ def active?
54
+ @active
55
+ end
56
+
21
57
  # Gets the current tabulation of the document.
22
58
  def tabulation
23
59
  @real_tabs + @tabulation
@@ -30,9 +66,13 @@ module Haml
30
66
  end
31
67
 
32
68
  # Creates a new buffer.
33
- def initialize(options = {})
69
+ def initialize(upper = nil, options = {})
70
+ @active = true
71
+ @upper = upper
34
72
  @options = {
35
- :attr_wrapper => "'"
73
+ :attr_wrapper => "'",
74
+ :ugly => false,
75
+ :format => :xhtml
36
76
  }.merge options
37
77
  @buffer = ""
38
78
  @tabulation = 0
@@ -44,56 +84,72 @@ module Haml
44
84
 
45
85
  # Renders +text+ with the proper tabulation. This also deals with
46
86
  # making a possible one-line tag one line or not.
47
- def push_text(text, tab_change = 0)
48
- if(@tabulation > 0)
49
- # Have to push every line in by the extra user set tabulation
50
- text.gsub!(/^/m, ' ' * @tabulation)
87
+ def push_text(text, dont_tab_up = false, tab_change = 0)
88
+ if @tabulation > 0 && !@options[:ugly]
89
+ # Have to push every line in by the extra user set tabulation.
90
+ # Don't push lines with just whitespace, though,
91
+ # because that screws up precompiled indentation.
92
+ text.gsub!(/^(?!\s+$)/m, tabs)
93
+ text.sub!(tabs, '') if dont_tab_up
51
94
  end
52
-
53
- @buffer << "#{text}"
95
+
96
+ @buffer << text
54
97
  @real_tabs += tab_change
98
+ @dont_tab_up_next_line = false
55
99
  end
56
100
 
57
101
  # Properly formats the output of a script that was run in the
58
102
  # instance_eval.
59
- def push_script(result, flattened, close_tag = nil)
103
+ def push_script(result, preserve_script, in_tag = false, preserve_tag = false,
104
+ escape_html = false, nuke_inner_whitespace = false)
60
105
  tabulation = @real_tabs
61
-
62
- if flattened
63
- result = Haml::Helpers.find_and_preserve(result)
64
- end
65
-
66
- result = result.to_s
67
- while result[-1] == ?\n
68
- # String#chomp is slow
69
- result = result[0...-1]
106
+
107
+ if preserve_tag
108
+ result = Haml::Helpers.preserve(result)
109
+ elsif preserve_script
110
+ result = Haml::Helpers.find_and_preserve(result, options[:preserve])
70
111
  end
71
-
72
- if close_tag && Buffer.one_liner?(result)
112
+
113
+ result = result.to_s.rstrip
114
+ result = html_escape(result) if escape_html
115
+
116
+ has_newline = result.include?("\n")
117
+ if in_tag && (@options[:ugly] || !has_newline || preserve_tag)
73
118
  @buffer << result
74
- @buffer << "</#{close_tag}>\n"
75
119
  @real_tabs -= 1
76
- else
77
- if close_tag
78
- @buffer << "\n"
79
- end
80
-
81
- result = result.gsub(/^/m, tabs(tabulation))
82
- @buffer << "#{result}\n"
83
-
84
- if close_tag
85
- @buffer << "#{tabs(tabulation-1)}</#{close_tag}>\n"
86
- @real_tabs -= 1
87
- end
120
+ return
121
+ end
122
+
123
+ @buffer << "\n" if in_tag && !nuke_inner_whitespace
124
+
125
+ # Precompiled tabulation may be wrong
126
+ if @tabulation > 0 && !in_tag
127
+ result = tabs + result
128
+ end
129
+
130
+ if has_newline && !@options[:ugly]
131
+ result = result.gsub "\n", "\n" + tabs(tabulation)
132
+
133
+ # Add tabulation if it wasn't precompiled
134
+ result = tabs(tabulation) + result if in_tag && !nuke_inner_whitespace
135
+ end
136
+ @buffer << "#{result}"
137
+ @buffer << "\n" unless nuke_inner_whitespace
138
+
139
+ if in_tag && !nuke_inner_whitespace
140
+ # We never get here if @options[:ugly] is true
141
+ @buffer << tabs(tabulation-1)
142
+ @real_tabs -= 1
88
143
  end
89
144
  nil
90
145
  end
91
146
 
92
147
  # Takes the various information about the opening tag for an
93
148
  # element, formats it, and adds it to the buffer.
94
- def open_tag(name, atomic, try_one_line, class_id, obj_ref, content, *attributes_hashes)
149
+ def open_tag(name, self_closing, try_one_line, preserve_tag, escape_html, class_id,
150
+ nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
95
151
  tabulation = @real_tabs
96
-
152
+
97
153
  attributes = class_id
98
154
  attributes_hashes.each do |attributes_hash|
99
155
  attributes_hash.keys.each { |key| attributes_hash[key.to_s] = attributes_hash.delete(key) }
@@ -101,65 +157,67 @@ module Haml
101
157
  end
102
158
  self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
103
159
 
104
- if atomic
105
- str = " />\n"
106
- elsif try_one_line
107
- str = ">"
160
+ if self_closing
161
+ str = " />" + (nuke_outer_whitespace ? "" : "\n")
108
162
  else
109
- str = ">\n"
163
+ str = ">" + (try_one_line || preserve_tag || nuke_inner_whitespace ? "" : "\n")
110
164
  end
111
- @buffer << "#{tabs(tabulation)}<#{name}#{Precompiler.build_attributes(@options[:attr_wrapper], attributes)}#{str}"
165
+
166
+ attributes = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
167
+ @buffer << "#{nuke_outer_whitespace || @options[:ugly] ? '' : tabs(tabulation)}<#{name}#{attributes}#{str}"
168
+
112
169
  if content
113
- if Buffer.one_liner?(content)
114
- @buffer << "#{content}</#{name}>\n"
115
- else
116
- @buffer << "\n#{tabs(@real_tabs+1)}#{content}\n#{tabs(@real_tabs)}</#{name}>\n"
117
- end
118
- else
119
- @real_tabs += 1
170
+ @buffer << "#{content}</#{name}>" << (nuke_outer_whitespace ? "" : "\n")
171
+ return
120
172
  end
173
+
174
+ @real_tabs += 1 unless self_closing || nuke_inner_whitespace
121
175
  end
122
176
 
123
177
  def self.merge_attrs(to, from)
124
178
  if to['id'] && from['id']
125
179
  to['id'] << '_' << from.delete('id')
180
+ elsif to['id'] || from['id']
181
+ from['id'] ||= to['id']
126
182
  end
127
183
 
128
184
  if to['class'] && from['class']
129
185
  # Make sure we don't duplicate class names
130
186
  from['class'] = (from['class'].split(' ') | to['class'].split(' ')).join(' ')
187
+ elsif to['class'] || from['class']
188
+ from['class'] ||= to['class']
131
189
  end
132
190
 
133
191
  to.merge!(from)
134
192
  end
135
193
 
194
+ private
195
+
136
196
  # Some of these methods are exposed as public class methods
137
197
  # so they can be re-used in helpers.
138
198
 
139
- # Returns whether or not the given value is short enough to be rendered
140
- # on one line.
141
- def self.one_liner?(value)
142
- value.length <= ONE_LINER_LENGTH && value.scan(/\n/).empty?
143
- end
144
-
145
- private
146
-
147
199
  @@tab_cache = {}
148
200
  # Gets <tt>count</tt> tabs. Mostly for internal use.
149
- def tabs(count)
201
+ def tabs(count = 0)
150
202
  tabs = count + @tabulation
151
- ' ' * tabs
152
203
  @@tab_cache[tabs] ||= ' ' * tabs
153
204
  end
154
205
 
155
206
  # Takes an array of objects and uses the class and id of the first
156
207
  # one to create an attributes hash.
208
+ # The second object, if present, is used as a prefix,
209
+ # just like you can do with dom_id() and dom_class() in Rails
157
210
  def parse_object_ref(ref)
211
+ prefix = ref[1]
158
212
  ref = ref[0]
159
213
  # Let's make sure the value isn't nil. If it is, return the default Hash.
160
214
  return {} if ref.nil?
161
215
  class_name = underscore(ref.class)
162
216
  id = "#{class_name}_#{ref.id || 'new'}"
217
+ if prefix
218
+ class_name = "#{ prefix }_#{ class_name}"
219
+ id = "#{ prefix }_#{ id }"
220
+ end
163
221
 
164
222
  {'id' => id, 'class' => class_name}
165
223
  end
data/lib/haml/engine.rb CHANGED
@@ -3,7 +3,6 @@ require 'haml/buffer'
3
3
  require 'haml/precompiler'
4
4
  require 'haml/filters'
5
5
  require 'haml/error'
6
- require 'haml/util'
7
6
 
8
7
  module Haml
9
8
  # This is the class where all the parsing and processing of the Haml
@@ -20,57 +19,79 @@ module Haml
20
19
  # Allow reading and writing of the options hash
21
20
  attr :options, true
22
21
 
22
+ # This string contains the source code that is evaluated
23
+ # to produce the Haml document.
24
+ attr :precompiled, true
25
+
26
+ # True if the format is XHTML
27
+ def xhtml?
28
+ not html?
29
+ end
30
+
31
+ # True if the format is any flavor of HTML
32
+ def html?
33
+ html4? or html5?
34
+ end
35
+
36
+ # True if the format is HTML4
37
+ def html4?
38
+ @options[:format] == :html4
39
+ end
40
+
41
+ # True if the format is HTML5
42
+ def html5?
43
+ @options[:format] == :html5
44
+ end
45
+
23
46
  # Creates a new instace of Haml::Engine that will compile the given
24
47
  # template string when <tt>render</tt> is called.
25
- # See README for available options.
48
+ # See README.rdoc for available options.
26
49
  #
27
50
  #--
28
51
  # When adding options, remember to add information about them
29
- # to README!
52
+ # to README.rdoc!
30
53
  #++
31
54
  #
32
55
  def initialize(template, options = {})
33
56
  @options = {
34
57
  :suppress_eval => false,
35
58
  :attr_wrapper => "'",
36
- :autoclose => ['meta', 'img', 'link', 'br', 'hr', 'input', 'area'],
37
- :filters => {
38
- 'sass' => Sass::Engine,
39
- 'plain' => Haml::Filters::Plain,
40
- 'preserve' => Haml::Filters::Preserve,
41
- 'redcloth' => Haml::Filters::RedCloth,
42
- 'textile' => Haml::Filters::Textile,
43
- 'markdown' => Haml::Filters::Markdown },
44
- :filename => '(haml)'
45
- }
46
- @options.rec_merge! options
47
59
 
48
- unless @options[:suppress_eval]
49
- @options[:filters].merge!({
50
- 'erb' => ERB,
51
- 'ruby' => Haml::Filters::Ruby
52
- })
53
- end
54
- @options[:filters].rec_merge! options[:filters] if options[:filters]
60
+ # Don't forget to update the docs in lib/haml.rb if you update these
61
+ :autoclose => %w[meta img link br hr input area param col base],
62
+ :preserve => %w[textarea pre],
55
63
 
56
- if @options[:locals]
57
- warn <<END
58
- DEPRECATION WARNING:
59
- The Haml :locals option is deprecated and will be removed in version 2.0.
60
- Use the locals option for Haml::Engine#render instead.
61
- END
64
+ :filename => '(haml)',
65
+ :line => 1,
66
+ :ugly => false,
67
+ :format => :xhtml,
68
+ :escape_html => false
69
+ }
70
+ @options.merge! options
71
+
72
+ unless [:xhtml, :html4, :html5].include?(@options[:format])
73
+ raise Haml::Error, "Invalid format #{@options[:format].inspect}"
62
74
  end
63
75
 
64
- @template = template.strip #String
76
+ @template = template.rstrip #String
65
77
  @to_close_stack = []
66
78
  @output_tabs = 0
67
79
  @template_tabs = 0
68
80
  @index = 0
69
81
  @flat_spaces = -1
82
+ @newlines = 0
83
+
84
+ if @options[:filters]
85
+ warn <<END
86
+ DEPRECATION WARNING:
87
+ The Haml :filters option is deprecated and will be removed in version 2.1.
88
+ Filters are now automatically registered.
89
+ END
90
+ end
70
91
 
71
92
  precompile
72
93
  rescue Haml::Error
73
- $!.backtrace.unshift "#{@options[:filename]}:#{@index}"
94
+ $!.backtrace.unshift "#{@options[:filename]}:#{@index + $!.line_offset + @options[:line] - 1}" if @index
74
95
  raise
75
96
  end
76
97
 
@@ -80,7 +101,7 @@ END
80
101
  # If it's a Binding or Proc object,
81
102
  # Haml uses it as the second argument to Kernel#eval;
82
103
  # otherwise, Haml just uses its #instance_eval context.
83
- #
104
+ #
84
105
  # Note that Haml modifies the evaluation context
85
106
  # (either the scope object or the "self" object of the scope binding).
86
107
  # It extends Haml::Helpers, and various instance variables are set
@@ -110,8 +131,7 @@ END
110
131
  # but if you're relying on local variables defined in the context of scope,
111
132
  # they won't work.
112
133
  def render(scope = Object.new, locals = {}, &block)
113
- locals = (@options[:locals] || {}).merge(locals)
114
- buffer = Haml::Buffer.new(options_for_buffer)
134
+ buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)
115
135
 
116
136
  if scope.is_a?(Binding) || scope.is_a?(Proc)
117
137
  scope_object = eval("self", scope)
@@ -125,17 +145,14 @@ END
125
145
 
126
146
  scope_object.instance_eval do
127
147
  extend Haml::Helpers
128
- @haml_stack ||= Array.new
129
- @haml_stack.push(buffer)
130
- @haml_is_haml = true
148
+ @haml_buffer = buffer
131
149
  end
132
150
 
133
- eval(@precompiled, scope, @options[:filename], 0)
151
+ eval(@precompiled, scope, @options[:filename], @options[:line])
134
152
 
135
153
  # Get rid of the current buffer
136
154
  scope_object.instance_eval do
137
- @haml_stack.pop
138
- @haml_is_haml = false
155
+ @haml_buffer = buffer.upper
139
156
  end
140
157
 
141
158
  buffer.buffer
@@ -172,7 +189,7 @@ END
172
189
  end
173
190
 
174
191
  eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
175
- precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], 0)
192
+ precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
176
193
  end
177
194
 
178
195
  # Defines a method on +object+
@@ -189,7 +206,7 @@ END
189
206
  #
190
207
  # Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
191
208
  # "foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"
192
- #
209
+ #
193
210
  # The first argument of the defined method is a hash of local variable names to values.
194
211
  # However, due to an unfortunate Ruby quirk,
195
212
  # the local variables which can be assigned must be pre-declared.
@@ -205,7 +222,7 @@ END
205
222
  # obj = Object.new
206
223
  # Haml::Engine.new("%p= foo").def_method(obj, :render)
207
224
  # obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'
208
- #
225
+ #
209
226
  # Note that Haml modifies the evaluation context
210
227
  # (either the scope object or the "self" object of the scope binding).
211
228
  # It extends Haml::Helpers, and various instance variables are set
@@ -214,7 +231,7 @@ END
214
231
  method = object.is_a?(Module) ? :module_eval : :instance_eval
215
232
 
216
233
  object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
217
- @options[:filename], 0)
234
+ @options[:filename], @options[:line])
218
235
  end
219
236
 
220
237
  private
@@ -226,9 +243,15 @@ END
226
243
  end
227
244
 
228
245
  # Returns a hash of options that Haml::Buffer cares about.
229
- # This should remain loadable form #inspect.
246
+ # This should remain loadable from #inspect.
230
247
  def options_for_buffer
231
- {:attr_wrapper => @options[:attr_wrapper]}
248
+ {
249
+ :autoclose => @options[:autoclose],
250
+ :preserve => @options[:preserve],
251
+ :attr_wrapper => @options[:attr_wrapper],
252
+ :ugly => @options[:ugly],
253
+ :format => @options[:format]
254
+ }
232
255
  end
233
256
  end
234
257
  end
data/lib/haml/error.rb CHANGED
@@ -1,13 +1,23 @@
1
1
  module Haml
2
- # The abstract type of exception raised by Haml code.
3
- class Error < StandardError; end
2
+ # An exception raised by Haml code.
3
+ class Error < Exception
4
+ # :stopdoc:
5
+
6
+ # By default, an error is taken to refer to the line of the template
7
+ # that was being processed when the exception was raised.
8
+ # However, if line_offset is non-zero, it's added to that line number
9
+ # to get the line to report for the error.
10
+ attr_reader :line_offset
11
+
12
+ def initialize(message = nil, line_offset = 0)
13
+ super(message)
14
+ @line_offset = line_offset
15
+ end
16
+ # :startdoc:
17
+ end
4
18
 
5
19
  # SyntaxError is the type of exception raised when Haml encounters an
6
20
  # ill-formatted document.
7
21
  # It's not particularly interesting, except in that it includes Haml::Error.
8
22
  class SyntaxError < Haml::Error; end
9
-
10
- # HamlError is the type of exception raised when Haml encounters an error
11
- # not of a syntactical nature, such as an undefined Filter.
12
- class HamlError < Haml::Error; end
13
23
  end
data/lib/haml/exec.rb CHANGED
@@ -21,7 +21,7 @@ module Haml
21
21
  @opts.parse!(@args)
22
22
 
23
23
  process_result
24
-
24
+
25
25
  @options
26
26
  rescue Exception => e
27
27
  raise e if e.is_a? SystemExit
@@ -43,9 +43,13 @@ module Haml
43
43
  protected
44
44
 
45
45
  def get_line(exception)
46
+ # SyntaxErrors have weird line reporting
47
+ # when there's trailing whitespace,
48
+ # which there is for Haml documents.
49
+ return exception.message.scan(/:(\d+)/)[0] if exception.is_a?(::SyntaxError)
46
50
  exception.backtrace[0].scan(/:(\d+)/)[0]
47
51
  end
48
-
52
+
49
53
  private
50
54
 
51
55
  def set_opts(opts)
@@ -63,7 +67,7 @@ module Haml
63
67
  end
64
68
 
65
69
  opts.on_tail("-v", "--version", "Print version") do
66
- puts("Haml " + File.read(File.dirname(__FILE__) + '/../../VERSION'))
70
+ puts("Haml #{::Haml.version[:string]}")
67
71
  exit
68
72
  end
69
73
  end
@@ -110,7 +114,7 @@ Description:
110
114
 
111
115
  Options:
112
116
  END
113
-
117
+
114
118
  opts.on('--rails RAILS_DIR', "Install Haml and Sass from the Gem to a Rails project") do |dir|
115
119
  original_dir = dir
116
120
 
@@ -145,6 +149,7 @@ END
145
149
  end
146
150
 
147
151
  opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
152
+ require 'stringio'
148
153
  @options[:check_syntax] = true
149
154
  @options[:output] = StringIO.new
150
155
  end
@@ -170,7 +175,7 @@ END
170
175
  super
171
176
 
172
177
  opts.on('-t', '--style NAME',
173
- 'Output style. Can be nested (default), compact, or expanded.') do |name|
178
+ 'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
174
179
  @options[:for_engine][:style] = name.to_sym
175
180
  end
176
181
  end
@@ -206,6 +211,25 @@ END
206
211
  @name = "Haml"
207
212
  end
208
213
 
214
+ def set_opts(opts)
215
+ super
216
+
217
+ opts.on('-t', '--style NAME',
218
+ 'Output style. Can be indented (default) or ugly.') do |name|
219
+ @options[:for_engine][:ugly] = true if name.to_sym == :ugly
220
+ end
221
+
222
+ opts.on('-f', '--format NAME',
223
+ 'Output format. Can be xhtml (default), html4, or html5.') do |name|
224
+ @options[:for_engine][:format] = name.to_sym
225
+ end
226
+
227
+ opts.on('-e', '--escape-html',
228
+ 'Escape HTML characters (like ampersands and angle brackets) by default.') do
229
+ @options[:for_engine][:escape_html] = true
230
+ end
231
+ end
232
+
209
233
  def process_result
210
234
  super
211
235
  input = @options[:input]
@@ -226,7 +250,7 @@ END
226
250
 
227
251
  case e
228
252
  when ::Haml::SyntaxError; raise "Syntax error on line #{get_line e}: #{e.message}"
229
- when ::Haml::HamlError; raise "Haml error on line #{get_line e}: #{e.message}"
253
+ when ::Haml::Error; raise "Haml error on line #{get_line e}: #{e.message}"
230
254
  else raise "Exception on line #{get_line e}: #{e.message}\n Use --trace for backtrace."
231
255
  end
232
256
  end
@@ -289,6 +313,8 @@ END
289
313
  def initialize(args)
290
314
  super
291
315
 
316
+ @module_opts = {}
317
+
292
318
  require 'sass/css'
293
319
  end
294
320
 
@@ -301,6 +327,10 @@ Description: Transforms a CSS file into corresponding Sass code.
301
327
  Options:
302
328
  END
303
329
 
330
+ opts.on('-a', '--alternate', 'Output using alternative Sass syntax (margin: 1px)') do
331
+ @module_opts[:alternate] = true
332
+ end
333
+
304
334
  super
305
335
  end
306
336
 
@@ -310,7 +340,7 @@ END
310
340
  input = @options[:input]
311
341
  output = @options[:output]
312
342
 
313
- output.write(::Sass::CSS.new(input).render)
343
+ output.write(::Sass::CSS.new(input, @module_opts).render)
314
344
  end
315
345
  end
316
346
  end