radiant 0.6.7 → 0.6.8

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.

Files changed (96) hide show
  1. data/CHANGELOG +35 -3
  2. data/CONTRIBUTORS +11 -1
  3. data/README +5 -3
  4. data/app/controllers/admin/welcome_controller.rb +7 -0
  5. data/app/migrate/020_add_session_info_to_users.rb +11 -0
  6. data/app/models/page.rb +22 -9
  7. data/app/models/standard_tags.rb +133 -10
  8. data/app/models/user.rb +9 -1
  9. data/app/views/admin/page/edit.html.haml +5 -4
  10. data/app/views/admin/welcome/login.html.haml +42 -24
  11. data/app/views/layouts/application.html.haml +1 -1
  12. data/config/environment.rb +4 -2
  13. data/db/migrate/020_add_session_info_to_users.rb +11 -0
  14. data/db/migrate/021_remove_session_expire_from_users.rb +9 -0
  15. data/db/schema.rb +3 -2
  16. data/lib/generators/instance/instance_generator.rb +2 -1
  17. data/lib/generators/instance/templates/instance_environment.rb +5 -3
  18. data/lib/login_system.rb +13 -0
  19. data/lib/radiant.rb +1 -1
  20. data/lib/radiant/admin_ui.rb +21 -21
  21. data/lib/radiant/extension/script.rb +251 -0
  22. data/lib/radiant/extension_loader.rb +22 -20
  23. data/lib/radiant/initializer.rb +1 -1
  24. data/lib/radiant/setup.rb +2 -0
  25. data/lib/tasks/framework.rake +39 -29
  26. data/public/500.html +1 -1
  27. data/public/javascripts/admin/admin.js +11 -9
  28. data/script/extension +5 -0
  29. data/spec/controllers/admin/user_controller_spec.rb +1 -1
  30. data/spec/controllers/admin/welcome_controller_spec.rb +31 -5
  31. data/spec/controllers/site_controller_spec.rb +15 -2
  32. data/spec/lib/login_system_spec.rb +106 -60
  33. data/spec/lib/radiant/extension/script_spec.rb +349 -0
  34. data/spec/lib/radiant/extension_loader_spec.rb +3 -0
  35. data/spec/models/page_spec.rb +62 -2
  36. data/spec/models/standard_tags_spec.rb +150 -3
  37. data/spec/models/user_spec.rb +28 -0
  38. data/spec/scenarios/file_not_found_scenario.rb +5 -0
  39. data/spec/scenarios/pages_scenario.rb +6 -0
  40. data/spec/scenarios/snippets_scenario.rb +4 -0
  41. data/test/fixtures/users.yml +11 -6
  42. data/vendor/plugins/haml/FAQ +138 -0
  43. data/vendor/plugins/haml/REVISION +1 -0
  44. data/vendor/plugins/haml/Rakefile +54 -62
  45. data/vendor/plugins/haml/VERSION +1 -1
  46. data/vendor/plugins/haml/init.rb +6 -1
  47. data/vendor/plugins/haml/lib/haml.rb +72 -12
  48. data/vendor/plugins/haml/lib/haml/buffer.rb +47 -40
  49. data/vendor/plugins/haml/lib/haml/engine.rb +20 -30
  50. data/vendor/plugins/haml/lib/haml/error.rb +4 -5
  51. data/vendor/plugins/haml/lib/haml/exec.rb +4 -2
  52. data/vendor/plugins/haml/lib/haml/filters.rb +30 -15
  53. data/vendor/plugins/haml/lib/haml/helpers.rb +47 -28
  54. data/vendor/plugins/haml/lib/haml/helpers/action_view_mods.rb +74 -25
  55. data/vendor/plugins/haml/lib/haml/precompiler.rb +92 -51
  56. data/vendor/plugins/haml/lib/haml/template.rb +11 -3
  57. data/vendor/plugins/haml/lib/haml/template/patch.rb +1 -1
  58. data/vendor/plugins/haml/lib/sass.rb +26 -3
  59. data/vendor/plugins/haml/lib/sass/constant.rb +26 -57
  60. data/vendor/plugins/haml/lib/sass/constant/literal.rb +1 -0
  61. data/vendor/plugins/haml/lib/sass/constant/nil.rb +9 -0
  62. data/vendor/plugins/haml/lib/sass/css.rb +17 -2
  63. data/vendor/plugins/haml/lib/sass/engine.rb +11 -5
  64. data/vendor/plugins/haml/test/haml/engine_test.rb +57 -39
  65. data/vendor/plugins/haml/test/haml/helper_test.rb +20 -4
  66. data/vendor/plugins/haml/test/haml/html2haml_test.rb +1 -3
  67. data/vendor/plugins/haml/test/haml/results/content_for_layout.xhtml +1 -2
  68. data/vendor/plugins/haml/test/haml/results/eval_suppressed.xhtml +2 -4
  69. data/vendor/plugins/haml/test/haml/results/filters.xhtml +12 -8
  70. data/vendor/plugins/haml/test/haml/results/helpers.xhtml +2 -5
  71. data/vendor/plugins/haml/test/haml/results/just_stuff.xhtml +1 -3
  72. data/vendor/plugins/haml/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  73. data/vendor/plugins/haml/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  74. data/vendor/plugins/haml/test/haml/results/original_engine.xhtml +2 -4
  75. data/vendor/plugins/haml/test/haml/results/tag_parsing.xhtml +1 -6
  76. data/vendor/plugins/haml/test/haml/results/very_basic.xhtml +2 -4
  77. data/vendor/plugins/haml/test/haml/results/whitespace_handling.xhtml +13 -21
  78. data/vendor/plugins/haml/test/haml/template_test.rb +31 -48
  79. data/vendor/plugins/haml/test/haml/templates/filters.haml +13 -0
  80. data/vendor/plugins/haml/test/haml/templates/helpers.haml +1 -1
  81. data/vendor/plugins/haml/test/haml/templates/just_stuff.haml +0 -1
  82. data/vendor/plugins/haml/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  83. data/vendor/plugins/haml/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  84. data/vendor/plugins/haml/test/haml/templates/partials.haml +1 -1
  85. data/vendor/plugins/haml/test/haml/templates/tag_parsing.haml +0 -3
  86. data/vendor/plugins/haml/test/haml/templates/whitespace_handling.haml +10 -10
  87. data/vendor/plugins/haml/test/sass/engine_test.rb +11 -5
  88. data/vendor/plugins/haml/test/sass/plugin_test.rb +2 -6
  89. data/vendor/plugins/haml/test/sass/results/constants.css +2 -0
  90. data/vendor/plugins/haml/test/sass/templates/constants.sass +3 -0
  91. data/vendor/plugins/haml/test/{haml/test_helper.rb → test_helper.rb} +4 -3
  92. metadata +21 -11
  93. data/vendor/plugins/haml/TODO +0 -9
  94. data/vendor/plugins/haml/extra/haml-mode.el +0 -328
  95. data/vendor/plugins/haml/extra/sass-mode.el +0 -88
  96. data/vendor/plugins/haml/test/profile.rb +0 -65
@@ -109,28 +109,15 @@ END
109
109
  end.join(';') + ';'
110
110
  end
111
111
 
112
- Line = Struct.new("Line", :text, :unstripped, :index, :spaces, :tabs)
112
+ Line = Struct.new(:text, :unstripped, :index, :spaces, :tabs)
113
113
 
114
114
  def precompile
115
- @precompiled = ''
116
- @merged_text = ''
117
- @tab_change = 0
118
-
119
115
  old_line = Line.new
120
- (@template + "\n-#\n-#").split(/\n?\r|\r?\n/).each_with_index do |text, index|
121
- line = Line.new text.strip, text.lstrip.chomp, index
116
+ @template.split(/\r\n|\r|\n/).each_with_index do |text, index|
117
+ @next_line = line = Line.new(text.strip, text.lstrip.chomp, index)
122
118
  line.spaces, line.tabs = count_soft_tabs(text)
123
119
 
124
- if line.text.empty?
125
- process_indent(old_line) if flat? && !old_line.text.empty?
126
-
127
- unless flat?
128
- newline
129
- next
130
- end
131
-
132
- push_flat(old_line)
133
- old_line.text, old_line.unstripped, old_line.spaces = '', '', 0
120
+ if line.text.empty? && !flat?
134
121
  newline
135
122
  next
136
123
  end
@@ -154,7 +141,7 @@ END
154
141
  end
155
142
 
156
143
  if old_line.spaces != old_line.tabs * 2
157
- raise SyntaxError.new(<<END.strip, 1 + old_line.index - @index)
144
+ raise SyntaxError.new(<<END.strip, old_line.index)
158
145
  #{old_line.spaces} space#{old_line.spaces == 1 ? ' was' : 's were'} used for indentation. Haml must be indented using two spaces.
159
146
  END
160
147
  end
@@ -165,7 +152,7 @@ END
165
152
  resolve_newlines
166
153
 
167
154
  if !flat? && line.tabs - old_line.tabs > 1
168
- raise SyntaxError.new(<<END.strip, 2 + old_line.index - @index)
155
+ raise SyntaxError.new(<<END.strip, line.index)
169
156
  #{line.spaces} spaces were used for indentation. Haml must be indented using two spaces.
170
157
  END
171
158
  end
@@ -199,12 +186,12 @@ END
199
186
  when ELEMENT; render_tag(text)
200
187
  when COMMENT; render_comment(text[1..-1].strip)
201
188
  when SANITIZE
202
- return push_script(unescape_interpolation(text[3..-1].strip), false, nil, false, true) if text[1..2] == "=="
203
- return push_script(text[2..-1].strip, false, nil, false, true) if text[1] == SCRIPT
189
+ return push_script(unescape_interpolation(text[3..-1].strip), false, false, false, true) if text[1..2] == "=="
190
+ return push_script(text[2..-1].strip, false, false, false, true) if text[1] == SCRIPT
204
191
  push_plain text
205
192
  when SCRIPT
206
193
  return push_script(unescape_interpolation(text[2..-1].strip), false) if text[1] == SCRIPT
207
- return push_script(text[1..-1], false, nil, false, true) if options[:escape_html]
194
+ return push_script(text[1..-1], false, false, false, true) if options[:escape_html]
208
195
  push_script(text[1..-1], false)
209
196
  when FLAT_SCRIPT; push_flat_script(text[1..-1])
210
197
  when SILENT_SCRIPT
@@ -277,8 +264,9 @@ END
277
264
 
278
265
  # Adds <tt>text</tt> to <tt>@buffer</tt> with appropriate tabulation
279
266
  # without parsing it.
280
- def push_merged_text(text, tab_change = 0, try_one_liner = false)
281
- @merged_text << (@options[:ugly] ? text : "#{' ' * @output_tabs}#{text}")
267
+ def push_merged_text(text, tab_change = 0, indent = true)
268
+ @merged_text << (!indent || @dont_indent_next_line || @options[:ugly] ? text : "#{' ' * @output_tabs}#{text}")
269
+ @dont_indent_next_line = false
282
270
  @tab_change += tab_change
283
271
  end
284
272
 
@@ -287,24 +275,29 @@ END
287
275
  @merged_text << text
288
276
  end
289
277
 
290
- def push_text(text, tab_change = 0, try_one_liner = false)
291
- push_merged_text("#{text}\n", tab_change, try_one_liner)
278
+ def push_text(text, tab_change = 0)
279
+ push_merged_text("#{text}\n", tab_change)
292
280
  end
293
281
 
294
282
  def flush_merged_text
295
283
  return if @merged_text.empty?
296
284
 
297
285
  @precompiled << "_hamlout.push_text(#{@merged_text.dump}"
286
+ @precompiled << ", #{@dont_tab_up_next_text.inspect}" if @dont_tab_up_next_text || @tab_change != 0
298
287
  @precompiled << ", #{@tab_change}" if @tab_change != 0
299
288
  @precompiled << ");"
300
289
  @merged_text = ''
290
+ @dont_tab_up_next_text = false
301
291
  @tab_change = 0
302
292
  end
303
293
 
304
294
  # Renders a block of text as plain text.
305
295
  # Also checks for an illegally opened block.
306
296
  def push_plain(text)
307
- raise SyntaxError.new("Illegal nesting: nesting within plain text is illegal.", 1) if @block_opened
297
+ if @block_opened
298
+ raise SyntaxError.new("Illegal nesting: nesting within plain text is illegal.", @next_line.index)
299
+ end
300
+
308
301
  push_text text
309
302
  end
310
303
 
@@ -324,7 +317,11 @@ END
324
317
  #
325
318
  # If <tt>preserve_script</tt> is true, Haml::Helpers#find_and_flatten is run on
326
319
  # the result before it is added to <tt>@buffer</tt>
327
- def push_script(text, preserve_script, close_tag = nil, preserve_tag = false, escape_html = false)
320
+ def push_script(text, preserve_script, in_tag = false, preserve_tag = false,
321
+ escape_html = false, nuke_inner_whitespace = false)
322
+ # Prerender tabulation unless we're in a tag
323
+ push_merged_text '' unless in_tag
324
+
328
325
  flush_merged_text
329
326
  return if options[:suppress_eval]
330
327
 
@@ -332,7 +329,9 @@ END
332
329
 
333
330
  push_silent "haml_temp = #{text}"
334
331
  newline_now
335
- out = "haml_temp = _hamlout.push_script(haml_temp, #{preserve_script.inspect}, #{close_tag.inspect}, #{preserve_tag.inspect}, #{escape_html.inspect});"
332
+ args = [preserve_script, in_tag, preserve_tag,
333
+ escape_html, nuke_inner_whitespace].map { |a| a.inspect }.join(', ')
334
+ out = "haml_temp = _hamlout.push_script(haml_temp, #{args});"
336
335
  if @block_opened
337
336
  push_and_tabulate([:loud, out])
338
337
  else
@@ -371,10 +370,14 @@ END
371
370
 
372
371
  # Puts a line in <tt>@precompiled</tt> that will add the closing tag of
373
372
  # the most recently opened tag.
374
- def close_tag(tag)
375
- @output_tabs -= 1
373
+ def close_tag(value)
374
+ tag, nuke_outer_whitespace, nuke_inner_whitespace = value
375
+ @output_tabs -= 1 unless nuke_inner_whitespace
376
376
  @template_tabs -= 1
377
- push_text("</#{tag}>", -1)
377
+ rstrip_buffer! if nuke_inner_whitespace
378
+ push_merged_text("</#{tag}>" + (nuke_outer_whitespace ? "" : "\n"),
379
+ nuke_inner_whitespace ? 0 : -1, !nuke_inner_whitespace)
380
+ @dont_indent_next_line = nuke_outer_whitespace
378
381
  end
379
382
 
380
383
  # Closes a Ruby block.
@@ -502,10 +505,14 @@ END
502
505
  if rest
503
506
  object_ref, rest = balance(rest, ?[, ?]) if rest[0] == ?[
504
507
  attributes_hash, rest = parse_attributes(rest) if rest[0] == ?{ && attributes_hash.nil?
505
- action, value = rest.scan(/([=\/\~&!]?)?(.*)?/)[0]
508
+ nuke_whitespace, action, value = rest.scan(/(<>|><|[><])?([=\/\~&!])?(.*)?/)[0]
509
+ nuke_whitespace ||= ''
510
+ nuke_outer_whitespace = nuke_whitespace.include? '>'
511
+ nuke_inner_whitespace = nuke_whitespace.include? '<'
506
512
  end
507
513
  value = value.to_s.strip
508
- [tag_name, attributes, attributes_hash, object_ref, action, value]
514
+ [tag_name, attributes, attributes_hash, object_ref, nuke_outer_whitespace,
515
+ nuke_inner_whitespace, action, value]
509
516
  end
510
517
 
511
518
  def parse_attributes(line)
@@ -518,11 +525,17 @@ END
518
525
  # Parses a line that will render as an XHTML tag, and adds the code that will
519
526
  # render that tag to <tt>@precompiled</tt>.
520
527
  def render_tag(line)
521
- tag_name, attributes, attributes_hash, object_ref, action, value = parse_tag(line)
528
+ tag_name, attributes, attributes_hash, object_ref, nuke_outer_whitespace,
529
+ nuke_inner_whitespace, action, value = parse_tag(line)
522
530
 
523
531
  raise SyntaxError.new("Illegal element: classes and ids must have values.") if attributes =~ /[\.#](\.|#|\z)/
524
532
 
533
+ # Get rid of whitespace outside of the tag if we need to
534
+ rstrip_buffer! if nuke_outer_whitespace
535
+
525
536
  preserve_tag = options[:preserve].include?(tag_name)
537
+ nuke_inner_whitespace ||= preserve_tag
538
+ preserve_tag &&= !options[:ugly]
526
539
 
527
540
  case action
528
541
  when '/'; self_closing = xhtml?
@@ -551,41 +564,58 @@ END
551
564
  attributes = parse_class_and_id(attributes)
552
565
  Buffer.merge_attrs(attributes, static_attributes) if static_attributes
553
566
 
554
- raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", 1) if @block_opened && self_closing
555
- raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", 1) if @block_opened && !value.empty?
567
+ raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", @next_line.index) if @block_opened && self_closing
568
+ 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?
556
569
  raise SyntaxError.new("There's no Ruby code for #{action} to evaluate.") if parse && value.empty?
557
570
  raise SyntaxError.new("Self-closing tags can't have content.") if self_closing && !value.empty?
558
571
 
559
572
  self_closing ||= !!( !@block_opened && value.empty? && @options[:autoclose].include?(tag_name) )
560
573
 
574
+ dont_indent_next_line =
575
+ (nuke_outer_whitespace && !@block_opened) ||
576
+ (nuke_inner_whitespace && @block_opened)
577
+
578
+ # Check if we can render the tag directly to text and not process it in the buffer
561
579
  if object_ref == "nil" && attributes_hash.nil? && !preserve_script
562
- # This means that we can render the tag directly to text and not process it in the buffer
563
- tag_closed = !value.empty? && !parse
580
+ tag_closed = !@block_opened && !self_closing && !parse
564
581
 
565
582
  open_tag = prerender_tag(tag_name, self_closing, attributes)
566
- open_tag << "#{value}</#{tag_name}>" if tag_closed
567
- open_tag << "\n" unless parse
583
+ if tag_closed
584
+ open_tag << "#{value}</#{tag_name}>"
585
+ open_tag << "\n" unless nuke_outer_whitespace
586
+ else
587
+ open_tag << "\n" unless parse || nuke_inner_whitespace || (self_closing && nuke_outer_whitespace)
588
+ end
589
+
590
+ push_merged_text(open_tag, tag_closed || self_closing || nuke_inner_whitespace ? 0 : 1,
591
+ !nuke_outer_whitespace)
568
592
 
569
- push_merged_text(open_tag, tag_closed || self_closing ? 0 : 1, parse)
593
+ @dont_indent_next_line = dont_indent_next_line
570
594
  return if tag_closed
571
595
  else
572
596
  flush_merged_text
573
597
  content = value.empty? || parse ? 'nil' : value.dump
574
598
  attributes_hash = ', ' + attributes_hash if attributes_hash
575
- push_silent "_hamlout.open_tag(#{tag_name.inspect}, #{self_closing.inspect}, #{(!value.empty?).inspect}, #{preserve_tag.inspect}, #{escape_html.inspect}, #{attributes.inspect}, #{object_ref}, #{content}#{attributes_hash})"
599
+ args = [tag_name, self_closing, !@block_opened, preserve_tag, escape_html,
600
+ attributes, nuke_outer_whitespace, nuke_inner_whitespace
601
+ ].map { |v| v.inspect }.join(', ')
602
+ push_silent "_hamlout.open_tag(#{args}, #{object_ref}, #{content}#{attributes_hash})"
603
+ @dont_tab_up_next_text = @dont_indent_next_line = dont_indent_next_line
576
604
  end
577
605
 
578
606
  return if self_closing
579
607
 
580
608
  if value.empty?
581
- push_and_tabulate([:element, tag_name])
582
- @output_tabs += 1
609
+ push_and_tabulate([:element, [tag_name, nuke_outer_whitespace, nuke_inner_whitespace]])
610
+ @output_tabs += 1 unless nuke_inner_whitespace
583
611
  return
584
612
  end
585
613
 
586
614
  if parse
587
615
  flush_merged_text
588
- push_script(value, preserve_script, tag_name, preserve_tag, escape_html)
616
+ push_script(value, preserve_script, true, preserve_tag, escape_html, nuke_inner_whitespace)
617
+ @dont_tab_up_next_text = true
618
+ concat_merged_text("</#{tag_name}>" + (nuke_outer_whitespace ? "" : "\n"))
589
619
  end
590
620
  end
591
621
 
@@ -602,7 +632,7 @@ END
602
632
  conditional << ">" if conditional
603
633
 
604
634
  if @block_opened && !line.empty?
605
- raise SyntaxError.new('Illegal nesting: nesting within a tag that already has content is illegal.', 1)
635
+ raise SyntaxError.new('Illegal nesting: nesting within a tag that already has content is illegal.', @next_line.index)
606
636
  end
607
637
 
608
638
  open = "<!--#{conditional} "
@@ -623,7 +653,7 @@ END
623
653
 
624
654
  # Renders an XHTML doctype or XML shebang.
625
655
  def render_doctype(line)
626
- raise SyntaxError.new("Illegal nesting: nesting within a header command is illegal.", 1) if @block_opened
656
+ raise SyntaxError.new("Illegal nesting: nesting within a header command is illegal.", @next_line.index) if @block_opened
627
657
  doctype = text_for_doctype(line)
628
658
  push_text doctype if doctype
629
659
  end
@@ -666,7 +696,7 @@ END
666
696
  def start_filtered(name)
667
697
  raise Error.new("Invalid filter name \":#{name}\".") unless name =~ /^\w+$/
668
698
 
669
- unless filter = options[:filters][name]
699
+ unless filter = Filters.defined[name]
670
700
  if filter == 'redcloth' || filter == 'markdown' || filter == 'textile'
671
701
  raise Error.new("You must have the RedCloth gem installed to use \"#{name}\" filter")
672
702
  end
@@ -719,8 +749,8 @@ END
719
749
  def count_soft_tabs(line)
720
750
  spaces = line.index(/([^ ]|$)/)
721
751
  if line[spaces] == ?\t
722
- return nil if line.strip.empty?
723
- raise SyntaxError.new(<<END.strip, 2)
752
+ return 0, 0 if line.strip.empty?
753
+ raise SyntaxError.new(<<END.strip, @next_line.index)
724
754
  A tab character was used for indentation. Haml must be indented using two spaces.
725
755
  Are you sure you have soft tabs enabled in your editor?
726
756
  END
@@ -753,5 +783,16 @@ END
753
783
  @precompiled << "\n" * @newlines
754
784
  @newlines = 0
755
785
  end
786
+
787
+ # Get rid of and whitespace at the end of the buffer
788
+ # or the merged text
789
+ def rstrip_buffer!
790
+ unless @merged_text.empty?
791
+ @merged_text.rstrip!
792
+ else
793
+ push_silent("_erbout.rstrip!", false)
794
+ @dont_tab_up_next_text = true
795
+ end
796
+ end
756
797
  end
757
798
  end
@@ -36,8 +36,16 @@ if defined?(RAILS_ROOT)
36
36
  # to not need updating.
37
37
  rails_init_file = File.join(RAILS_ROOT, 'vendor', 'plugins', 'haml', 'init.rb')
38
38
  haml_init_file = Haml.scope('init.rb')
39
- if File.exists?(rails_init_file)
40
- require 'fileutils'
41
- FileUtils.cp(haml_init_file, rails_init_file) unless FileUtils.cmp(rails_init_file, haml_init_file)
39
+ begin
40
+ if File.exists?(rails_init_file)
41
+ require 'fileutils'
42
+ FileUtils.cp(haml_init_file, rails_init_file) unless FileUtils.cmp(rails_init_file, haml_init_file)
43
+ end
44
+ rescue SystemCallError
45
+ warn <<END
46
+ HAML WARNING:
47
+ #{rails_init_file} is out of date and couldn't be automatically updated.
48
+ Please run `haml --rails #{File.expand_path(RAILS_ROOT)}' to update it.
49
+ END
42
50
  end
43
51
  end
@@ -35,7 +35,7 @@ module ActionView
35
35
  options[:filename] = file_name || 'compiled-template'
36
36
 
37
37
  begin
38
- Haml::Engine.new(template, options).def_method(CompiledTemplates, render_symbol, *locals)
38
+ Haml::Engine.new(template, options).def_method(CompiledTemplates, render_symbol, *locals_keys)
39
39
  rescue Exception => e
40
40
  if logger
41
41
  logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
@@ -253,6 +253,22 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
253
253
  # font-size: 30em;
254
254
  # font-weight: bold; }
255
255
  #
256
+ # === Rule Escaping
257
+ #
258
+ # In case, for whatever reason, you need to write a rule
259
+ # that begins with a Sass-meaningful character,
260
+ # you can escape it with a backslash (<tt>\</tt>).
261
+ # For example:
262
+ #
263
+ # #main
264
+ # \+div
265
+ # clear: both
266
+ #
267
+ # is compiled to:
268
+ #
269
+ # #main +div {
270
+ # clear: both; }
271
+ #
256
272
  # == Constants
257
273
  #
258
274
  # Sass has support for setting document-wide constants.
@@ -760,9 +776,16 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
760
776
  #
761
777
  # == Sass Options
762
778
  #
763
- # Options can be set by setting the hash <tt>Sass::Plugin.options</tt>
764
- # from <tt>environment.rb</tt> in Rails,
765
- # or by passing an options hash to Sass::Engine.
779
+ # Options can be set by setting the <tt>Sass::Plugin.options</tt> hash
780
+ # in <tt>environment.rb</tt> in Rails...
781
+ #
782
+ # Sass::Plugin.options[:style] = :compact
783
+ #
784
+ # ...or by setting the <tt>Merb::Config[:sass]</tt> hash in <tt>init.rb</tt> in Merb...
785
+ #
786
+ # Merb::Config[:sass][:style] = :compact
787
+ #
788
+ # ...or by passing an options hash to Sass::Engine.new.
766
789
  # Available options are:
767
790
  #
768
791
  # [<tt>:style</tt>] Sets the style of the CSS output.
@@ -119,17 +119,10 @@ module Sass
119
119
  next
120
120
  end
121
121
 
122
- # Is this a constant?
123
- if beginning_of_token && symbol == :const
124
- beginning_of_token = true
125
- to_return << :const
126
- next
127
- end
128
-
129
122
  # Are we looking at an operator?
130
123
  if symbol && (symbol != :mod || str.empty?)
131
124
  str = reset_str.call
132
- beginning_of_token = true
125
+ beginning_of_token = symbol != :close
133
126
  to_return << symbol
134
127
  next
135
128
  end
@@ -148,57 +141,30 @@ module Sass
148
141
  to_return
149
142
  end
150
143
 
151
- def parenthesize(value)
152
- parenthesize_helper(0, value, value.length)[0]
153
- end
154
-
155
- def parenthesize_helper(i, value, value_len, return_after_expr = false)
144
+ def parenthesize(value, return_after_expr = false)
156
145
  to_return = []
157
- beginning = i
158
- token = value[i]
159
-
160
- while i < value_len && token != :close
161
- if token == :open
162
- to_return.push(*value[beginning...i])
163
- sub, i = parenthesize_helper(i + 1, value, value_len)
164
- beginning = i
165
- to_return << sub
166
- elsif token == :neg
167
- if value[i + 1].nil?
168
- # This is never actually reached, but we'll leave it in just in case.
169
- raise Sass::SyntaxError.new("Unterminated unary minus.")
170
- elsif value[i + 1] == :open
171
- to_return.push(*value[beginning...i])
172
- sub, i = parenthesize_helper(i + 2, value, value_len)
173
- beginning = i
174
- to_return << [:neg, sub]
175
- elsif value[i + 1].is_a?(::Symbol)
176
- to_return.push(*value[beginning...i])
177
- sub, i = parenthesize_helper(i + 1, value, value_len, true)
178
- beginning = i
179
- to_return << [:neg, sub]
180
- else
181
- to_return.push(*value[beginning...i])
182
- to_return << [:neg, value[i + 1]]
183
- beginning = i = i + 2
184
- end
185
- return to_return[0], i if return_after_expr
186
- elsif token == :const
187
- raise Sass::SyntaxError.new("Unterminated constant.") if value[i + 1].nil?
188
- raise Sass::SyntaxError.new("Invalid constant.") unless value[i + 1].is_a?(::String)
189
-
190
- to_return.push(*value[beginning...i])
191
- to_return << [:const, value[i + 1]]
192
- beginning = i = i + 2
193
- return to_return[0], i if return_after_expr
146
+
147
+ while (token = value.shift) && token != :close
148
+ case token
149
+ when :open
150
+ to_return << parenthesize(value)
151
+ when :neg
152
+ # This is never actually reached, but we'll leave it in just in case.
153
+ raise Sass::SyntaxError.new("Unterminated unary minus.") if value.first.nil?
154
+ to_return << [:neg, parenthesize(value, true)]
155
+ when :const
156
+ raise Sass::SyntaxError.new("Unterminated constant.") if value.first.nil?
157
+ raise Sass::SyntaxError.new("Invalid constant.") unless value.first.is_a?(::String)
158
+
159
+ to_return << [:const, value.first]
160
+ value.shift
194
161
  else
195
- i += 1
162
+ to_return << token
196
163
  end
197
164
 
198
- token = value[i]
165
+ return to_return.first if return_after_expr
199
166
  end
200
- to_return.push(*value[beginning...i])
201
- return to_return, i + 1
167
+ return to_return
202
168
  end
203
169
 
204
170
  #--
@@ -207,7 +173,10 @@ module Sass
207
173
  #++
208
174
  def operationalize(value, constants)
209
175
  value = [value] unless value.is_a?(Array)
210
- if value.length == 1
176
+ case value.length
177
+ when 0
178
+ Sass::Constant::Nil.new
179
+ when 1
211
180
  value = value[0]
212
181
  if value.is_a? Array
213
182
  operationalize(value, constants)
@@ -216,7 +185,7 @@ module Sass
216
185
  else
217
186
  Literal.parse(value)
218
187
  end
219
- elsif value.length == 2
188
+ when 2
220
189
  if value[0] == :neg
221
190
  Operation.new(Sass::Constant::Number.new('0'), operationalize(value[1], constants), :minus)
222
191
  elsif value[0] == :const
@@ -224,7 +193,7 @@ module Sass
224
193
  else
225
194
  raise SyntaxError.new("Constant arithmetic error")
226
195
  end
227
- elsif value.length == 3
196
+ when 3
228
197
  Operation.new(operationalize(value[0], constants), operationalize(value[2], constants), value[1])
229
198
  else
230
199
  if SECOND_ORDER.include?(value[1]) && FIRST_ORDER.include?(value[3])