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
@@ -3,7 +3,7 @@ require 'sass/tree/node'
3
3
  module Sass::Tree
4
4
  class ValueNode < Node
5
5
  attr_accessor :value
6
-
6
+
7
7
  def initialize(value, style)
8
8
  @value = value
9
9
  super(style)
data/lib/sass.rb CHANGED
@@ -11,7 +11,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
11
11
  # and implements various features that are useful
12
12
  # for creating manageable stylesheets.
13
13
  #
14
- # == Features
14
+ # == Features
15
15
  #
16
16
  # * Whitespace active
17
17
  # * Well-formatted output
@@ -32,13 +32,13 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
32
32
  #
33
33
  # To enable it as a Rails plugin,
34
34
  # then run
35
- #
35
+ #
36
36
  # haml --rails path/to/rails/app
37
- #
37
+ #
38
38
  # To enable Sass in Merb,
39
39
  # add
40
40
  #
41
- # dependency "haml"
41
+ # dependency "merb-haml"
42
42
  #
43
43
  # to config/dependencies.rb.
44
44
  #
@@ -128,7 +128,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
128
128
  #
129
129
  # By default, either attribute syntax may be used.
130
130
  # If you want to force one or the other,
131
- # see the :attribute_syntax option below.
131
+ # see the <tt>:attribute_syntax</tt> option below.
132
132
  #
133
133
  # === Nested Rules
134
134
  #
@@ -157,12 +157,12 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
157
157
  #
158
158
  # #main
159
159
  # :width 97%
160
- #
160
+ #
161
161
  # p, div
162
162
  # :font-size 2em
163
163
  # a
164
164
  # :font-weight bold
165
- #
165
+ #
166
166
  # pre
167
167
  # :font-size 3em
168
168
  #
@@ -363,6 +363,39 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
363
363
  # #main {
364
364
  # content: string(Hello, "Hubert" Bean.) }
365
365
  #
366
+ # === Optional Assignment
367
+ #
368
+ # You can assign Sass constants if they aren't already assigned
369
+ # using the ||= assignment operator.
370
+ # This means that if the constant has already been assigned to,
371
+ # it won't be re-assigned,
372
+ # but if it doesn't have a value yet,
373
+ # it will be given one.
374
+ # For example:
375
+ #
376
+ # !content = "First content"
377
+ # !content ||= "Second content?"
378
+ #
379
+ # #main
380
+ # content = content
381
+ #
382
+ # is compiled to:
383
+ #
384
+ # #main {
385
+ # content: First content; }
386
+ #
387
+ # However,
388
+ #
389
+ # !content ||= "Second content?"
390
+ #
391
+ # #main
392
+ # content = content
393
+ #
394
+ # is compiled to:
395
+ #
396
+ # #main {
397
+ # content: Second content?; }
398
+ #
366
399
  # === Default Concatenation
367
400
  #
368
401
  # All those plusses and quotes for concatenating strings
@@ -453,6 +486,40 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
453
486
  # might compile to either,
454
487
  # depending on whether a file called "foo.sass" existed.
455
488
  #
489
+ # === @font-face, @media, etc.
490
+ #
491
+ # Sass behaves as you'd expect for normal CSS @-directives.
492
+ # For example:
493
+ #
494
+ # @font-face
495
+ # font-family: "Bitstream Vera Sans"
496
+ # src: url(http://foo.bar/bvs")
497
+ #
498
+ # compiles to:
499
+ #
500
+ # @font-face {
501
+ # font-family: "Bitstream Vera Sans";
502
+ # src: url(http://foo.bar/bvs"); }
503
+ #
504
+ # and
505
+ #
506
+ # @media print
507
+ # #sidebar
508
+ # display: none
509
+ #
510
+ # #main
511
+ # background-color: white
512
+ #
513
+ # compiles to:
514
+ #
515
+ # @media print {
516
+ # #sidebar {
517
+ # display: none; }
518
+ #
519
+ # #main {
520
+ # background-color: white; }
521
+ # }
522
+ #
456
523
  # == Comments
457
524
  #
458
525
  # === Silent Comments
@@ -528,6 +595,84 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
528
595
  # background-image: url(/images/pbj.png);
529
596
  # color: red; }
530
597
  #
598
+ # == Mixins
599
+ #
600
+ # Mixins enable you to define groups of CSS attributes and
601
+ # then include them inline in any number of selectors
602
+ # throughout the document.
603
+ #
604
+ # === Defining a Mixin
605
+ #
606
+ # To define a mixin you use a slightly modified form of selector syntax.
607
+ # For example the 'large-text' mixin is defined as follows:
608
+ #
609
+ # =large-text
610
+ # :font
611
+ # :family Arial
612
+ # :size 20px
613
+ # :weight bold
614
+ # :color #ff0000
615
+ #
616
+ # The initial '=' marks this as a mixin rather than a standard selector.
617
+ # The CSS rules that follow won't be included until the mixin is referenced later on.
618
+ # Anything you can put into a standard selector,
619
+ # you can put into a mixin definition. e.g.
620
+ #
621
+ # =clearfix
622
+ # display: inline-block
623
+ # &:after
624
+ # content: "."
625
+ # display: block
626
+ # height: 0
627
+ # clear: both
628
+ # visibility: hidden
629
+ # * html &
630
+ # height: 1px
631
+ #
632
+ #
633
+ # === Mixing it in
634
+ #
635
+ # Inlining a defined mixin is simple,
636
+ # just prepend a '+' symbol to the name of a mixin defined earlier in the document.
637
+ # So to inline the 'large-text' defined earlier,
638
+ # we include the statment '+large-text' in our selector definition thus:
639
+ #
640
+ # .page-title
641
+ # +large-text
642
+ # :padding 4px
643
+ # :margin
644
+ # :top 10px
645
+ #
646
+ #
647
+ # This will produce the following CSS output:
648
+ #
649
+ # .page-title {
650
+ # font-family: Arial;
651
+ # font-size: 20px;
652
+ # font-weight: bold;
653
+ # color: #ff0000;
654
+ # padding: 4px;
655
+ # margin-top: 10px;
656
+ # }
657
+ #
658
+ # Any number of mixins may be defined and there is no limit on
659
+ # the number that can be included in a particular selector.
660
+ #
661
+ # Mixin definitions can also include references to other mixins defined earlier in the file.
662
+ # E.g.
663
+ #
664
+ # =highlighted-background
665
+ # background:
666
+ # color: #fc0
667
+ # =header-text
668
+ # font:
669
+ # size: 20px
670
+ #
671
+ # =compound
672
+ # +highlighted-background
673
+ # +header-text
674
+ #
675
+ #
531
676
  # == Output Style
532
677
  #
533
678
  # Although the default CSS style that Sass outputs is very nice,
@@ -601,7 +746,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
601
746
  # #main { color: #fff; background-color: #000; }
602
747
  # #main p { width: 10em; }
603
748
  #
604
- # .huge { font-size: 10em; font-weight: bold; text-decoration: underline; }
749
+ # .huge { font-size: 10em; font-weight: bold; text-decoration: underline; }
605
750
  #
606
751
  # === <tt>:compressed</tt>
607
752
  #
@@ -611,7 +756,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
611
756
  # It's not meant to be human-readable.
612
757
  # For example:
613
758
  #
614
- # #main{color:#fff;background-color:#000}#main p{width:10em}.huge{font-size:10em;font-weight:bold;text-decoration:underline}
759
+ # #main{color:#fff;background-color:#000}#main p{width:10em}.huge{font-size:10em;font-weight:bold;text-decoration:underline}
615
760
  #
616
761
  # == Sass Options
617
762
  #
@@ -634,7 +779,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
634
779
  # For example: <tt>color: #0f3</tt>
635
780
  # or <tt>width = !main_width</tt>.
636
781
  # By default, either syntax is valid.
637
- #
782
+ #
638
783
  # [<tt>:never_update</tt>] Whether the CSS files should never be updated,
639
784
  # even if the template file changes.
640
785
  # Setting this to true may give small performance gains.
@@ -646,7 +791,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
646
791
  # as opposed to only when the template has been modified.
647
792
  # Defaults to false.
648
793
  # Only has meaning within Ruby on Rails or Merb.
649
- #
794
+ #
650
795
  # [<tt>:always_check</tt>] Whether a Sass template should be checked for updates every
651
796
  # time a controller is accessed,
652
797
  # as opposed to only when the Rails server starts.
@@ -681,7 +826,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
681
826
  # for Sass templates imported with the "@import" directive.
682
827
  # This defaults to the working directory and, in Rails or Merb,
683
828
  # whatever <tt>:template_location</tt> is.
684
- #
829
+ #
685
830
  module Sass; end
686
831
 
687
832
  require 'sass/engine'
data/test/benchmark.rb CHANGED
@@ -1,95 +1,82 @@
1
- # There's a bizarre error where ActionController tries to load a benchmark file
2
- # and ends up finding this.
3
- # These declarations then cause it to break.
4
- # This only happens when running rcov, though, so we can avoid it.
5
- unless $0 =~ /rcov$/
6
- require File.dirname(__FILE__) + '/../lib/haml'
7
- require 'haml'
1
+ #!/usr/bin/env ruby
2
+
3
+ times = (ARGV.first || 1000).to_i
4
+
5
+ if times == 0 # Invalid parameter
6
+ puts <<END
7
+ ruby #$0 [times=1000]
8
+ Benchmark Haml against various other templating languages and Sass
9
+ on its own.
10
+ END
11
+ exit 1
12
+ end
13
+
14
+ require File.dirname(__FILE__) + '/../lib/haml'
15
+ %w[sass rubygems erb erubis markaby active_support action_controller
16
+ action_view haml/template].each(&method(:require))
17
+
18
+ begin
19
+ require 'benchwarmer'
20
+ rescue LoadError
21
+ # Since it's not as simple as gem install at the time of writing,
22
+ # we need to direct folks to the benchwarmer gem.
23
+ raise "The Haml benchmarks require the benchwarmer gem, available from http://github.com/wycats/benchwarmer"
8
24
  end
9
25
 
10
- require 'rubygems'
11
- require 'erb'
12
- require 'erubis'
13
- require 'markaby'
14
- require 'benchmark'
15
- require 'stringio'
16
- require 'open-uri'
17
-
18
- module Haml
19
- # Benchmarks Haml against ERB, Erubis, and Markaby and Sass on its own.
20
- def self.benchmark(runs = 100)
21
- template_name = 'standard'
22
- directory = File.dirname(__FILE__) + '/haml'
23
- haml_template = File.read("#{directory}/templates/#{template_name}.haml")
24
- erb_template = File.read("#{directory}/rhtml/#{template_name}.rhtml")
25
- markaby_template = File.read("#{directory}/markaby/#{template_name}.mab")
26
-
27
- puts '-'*51, "Haml and Friends: No Caching", '-'*51
28
-
29
- times = Benchmark.bmbm do |b|
30
- b.report("haml:") { runs.times { Haml::Engine.new(haml_template).render } }
31
- b.report("erb:") { runs.times { ERB.new(erb_template, nil, '-').render } }
32
- b.report("erubis:") { runs.times { Erubis::Eruby.new(erb_template).result } }
33
- b.report("mab:") { runs.times { Markaby::Template.new(markaby_template).render } }
34
- end
35
-
36
- print_result = proc do |s, n|
37
- printf "%1$*2$s %3$*4$g",
38
- "Haml/#{s}:", -13, times[0].to_a[5] / times[n].to_a[5], -17
39
- printf "%1$*2$s %3$g\n",
40
- "#{s}/Haml:", -13, times[n].to_a[5] / times[0].to_a[5]
41
- end
42
-
43
- print_result["ERB", 1]
44
- print_result["Erubis", 2]
45
- print_result["Markaby", 3]
46
-
47
- puts '', '-' * 50, 'Haml and Friends: Cached', '-' * 50
26
+ Benchmark.warmer(times) do
27
+ columns :haml, :erb, :erubis, :mab
28
+ titles :haml => "Haml", :erb => "ERB", :erubis => "Erubis", :mab => "Markaby"
48
29
 
30
+ template_name = 'standard'
31
+ directory = File.dirname(__FILE__) + '/haml'
32
+ haml_template = File.read("#{directory}/templates/#{template_name}.haml")
33
+ erb_template = File.read("#{directory}/rhtml/#{template_name}.rhtml")
34
+ markaby_template = File.read("#{directory}/markaby/#{template_name}.mab")
35
+
36
+ report "Uncached" do
37
+ haml { Haml::Engine.new(haml_template).render }
38
+ erb { ERB.new(erb_template, nil, '-').result }
39
+ erubis { Erubis::Eruby.new(erb_template).result }
40
+ mab { Markaby::Template.new(markaby_template).render }
41
+ end
42
+
43
+ report "Cached" do
49
44
  obj = Object.new
45
+
50
46
  Haml::Engine.new(haml_template).def_method(obj, :haml)
51
- erb = ERB.new(erb_template, nil, '-')
52
- obj.instance_eval("def erb; #{erb.src}; end")
53
47
  Erubis::Eruby.new(erb_template).def_method(obj, :erubis)
54
- times = Benchmark.bmbm do |b|
55
- b.report("haml:") { runs.times { obj.haml } }
56
- b.report("erb:") { runs.times { obj.erb } }
57
- b.report("erubis:") { runs.times { obj.erubis } }
58
- end
48
+ obj.instance_eval("def erb; #{ERB.new(erb_template, nil, '-').src}; end")
59
49
 
60
- print_result["ERB", 1]
61
- print_result["Erubis", 2]
62
-
63
- puts '', '-' * 50, 'Haml and ERB: Via ActionView', '-' * 50
64
-
65
- require 'active_support'
66
- require 'action_controller'
67
- require 'action_view'
68
- require 'haml/template'
50
+ haml { obj.haml }
51
+ erb { obj.erb }
52
+ erubis { obj.erubis }
53
+ end
69
54
 
55
+ report "ActionView" do
70
56
  @base = ActionView::Base.new(File.dirname(__FILE__))
71
- times = Benchmark.bmbm do |b|
72
- b.report("haml:") { runs.times { @base.render 'haml/templates/standard' } }
73
- b.report("erb:") { runs.times { @base.render 'haml/rhtml/standard' } }
74
- end
75
57
 
76
- print_result["ERB", 1]
58
+ # To cache the template
59
+ @base.render 'haml/templates/standard'
60
+ @base.render 'haml/rhtml/standard'
77
61
 
78
- puts '', '-' * 50, 'Haml and ERB: Via ActionView with deep partials', '-' * 50
62
+ haml { @base.render 'haml/templates/standard' }
63
+ erb { @base.render 'haml/rhtml/standard' }
64
+ end
79
65
 
66
+ report "ActionView with deep partials" do
80
67
  @base = ActionView::Base.new(File.dirname(__FILE__))
81
- times = Benchmark.bmbm do |b|
82
- b.report("haml:") { runs.times { @base.render 'haml/templates/action_view' } }
83
- b.report("erb:") { runs.times { @base.render 'haml/rhtml/action_view' } }
84
- end
85
-
86
- print_result["ERB", 1]
87
-
88
- puts '', '-' * 50, 'Sass', '-' * 50
89
- sass_template = File.read("#{File.dirname(__FILE__)}/sass/templates/complex.sass")
90
-
91
- Benchmark.bmbm do |b|
92
- b.report("sass:") { runs.times { Sass::Engine.new(sass_template).render } }
93
- end
68
+
69
+ # To cache the template
70
+ @base.render 'haml/templates/action_view'
71
+ @base.render 'haml/rhtml/action_view'
72
+
73
+ haml { @base.render 'haml/templates/action_view' }
74
+ erb { @base.render 'haml/rhtml/action_view' }
94
75
  end
95
76
  end
77
+
78
+ Benchmark.warmer(times) do
79
+ sass_template = File.read("#{File.dirname(__FILE__)}/sass/templates/complex.sass")
80
+
81
+ report("Sass") { Sass::Engine.new(sass_template).render }
82
+ end