drnic-haml 2.3.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.
- data/.yardopts +5 -0
- data/CONTRIBUTING +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +347 -0
- data/REVISION +1 -0
- data/Rakefile +371 -0
- data/VERSION +1 -0
- data/VERSION_NAME +1 -0
- data/bin/css2sass +7 -0
- data/bin/haml +9 -0
- data/bin/html2haml +7 -0
- data/bin/sass +8 -0
- data/extra/haml-mode.el +663 -0
- data/extra/sass-mode.el +205 -0
- data/extra/update_watch.rb +13 -0
- data/init.rb +8 -0
- data/lib/haml.rb +40 -0
- data/lib/haml/buffer.rb +307 -0
- data/lib/haml/engine.rb +301 -0
- data/lib/haml/error.rb +22 -0
- data/lib/haml/exec.rb +470 -0
- data/lib/haml/filters.rb +341 -0
- data/lib/haml/helpers.rb +560 -0
- data/lib/haml/helpers/action_view_extensions.rb +40 -0
- data/lib/haml/helpers/action_view_mods.rb +176 -0
- data/lib/haml/herb.rb +96 -0
- data/lib/haml/html.rb +308 -0
- data/lib/haml/precompiler.rb +997 -0
- data/lib/haml/shared.rb +78 -0
- data/lib/haml/template.rb +51 -0
- data/lib/haml/template/patch.rb +58 -0
- data/lib/haml/template/plugin.rb +71 -0
- data/lib/haml/util.rb +244 -0
- data/lib/haml/version.rb +64 -0
- data/lib/sass.rb +24 -0
- data/lib/sass/css.rb +423 -0
- data/lib/sass/engine.rb +491 -0
- data/lib/sass/environment.rb +79 -0
- data/lib/sass/error.rb +162 -0
- data/lib/sass/files.rb +133 -0
- data/lib/sass/plugin.rb +170 -0
- data/lib/sass/plugin/merb.rb +57 -0
- data/lib/sass/plugin/rails.rb +23 -0
- data/lib/sass/repl.rb +58 -0
- data/lib/sass/script.rb +55 -0
- data/lib/sass/script/bool.rb +17 -0
- data/lib/sass/script/color.rb +183 -0
- data/lib/sass/script/funcall.rb +50 -0
- data/lib/sass/script/functions.rb +199 -0
- data/lib/sass/script/lexer.rb +191 -0
- data/lib/sass/script/literal.rb +177 -0
- data/lib/sass/script/node.rb +14 -0
- data/lib/sass/script/number.rb +381 -0
- data/lib/sass/script/operation.rb +45 -0
- data/lib/sass/script/parser.rb +222 -0
- data/lib/sass/script/string.rb +12 -0
- data/lib/sass/script/unary_operation.rb +34 -0
- data/lib/sass/script/variable.rb +31 -0
- data/lib/sass/tree/comment_node.rb +84 -0
- data/lib/sass/tree/debug_node.rb +30 -0
- data/lib/sass/tree/directive_node.rb +70 -0
- data/lib/sass/tree/for_node.rb +48 -0
- data/lib/sass/tree/if_node.rb +54 -0
- data/lib/sass/tree/import_node.rb +69 -0
- data/lib/sass/tree/mixin_def_node.rb +29 -0
- data/lib/sass/tree/mixin_node.rb +48 -0
- data/lib/sass/tree/node.rb +252 -0
- data/lib/sass/tree/prop_node.rb +106 -0
- data/lib/sass/tree/root_node.rb +56 -0
- data/lib/sass/tree/rule_node.rb +220 -0
- data/lib/sass/tree/variable_node.rb +34 -0
- data/lib/sass/tree/while_node.rb +31 -0
- data/rails/init.rb +1 -0
- data/test/benchmark.rb +99 -0
- data/test/haml/engine_test.rb +1129 -0
- data/test/haml/helper_test.rb +282 -0
- data/test/haml/html2haml_test.rb +258 -0
- data/test/haml/markaby/standard.mab +52 -0
- data/test/haml/mocks/article.rb +6 -0
- data/test/haml/results/content_for_layout.xhtml +12 -0
- data/test/haml/results/eval_suppressed.xhtml +9 -0
- data/test/haml/results/filters.xhtml +62 -0
- data/test/haml/results/helpers.xhtml +93 -0
- data/test/haml/results/helpful.xhtml +10 -0
- data/test/haml/results/just_stuff.xhtml +68 -0
- data/test/haml/results/list.xhtml +12 -0
- data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
- data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
- data/test/haml/results/original_engine.xhtml +20 -0
- data/test/haml/results/partial_layout.xhtml +5 -0
- data/test/haml/results/partials.xhtml +21 -0
- data/test/haml/results/render_layout.xhtml +3 -0
- data/test/haml/results/silent_script.xhtml +74 -0
- data/test/haml/results/standard.xhtml +162 -0
- data/test/haml/results/tag_parsing.xhtml +23 -0
- data/test/haml/results/very_basic.xhtml +5 -0
- data/test/haml/results/whitespace_handling.xhtml +89 -0
- data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
- data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
- data/test/haml/rhtml/action_view.rhtml +62 -0
- data/test/haml/rhtml/standard.rhtml +54 -0
- data/test/haml/spec_test.rb +44 -0
- data/test/haml/template_test.rb +217 -0
- data/test/haml/templates/_av_partial_1.haml +9 -0
- data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
- data/test/haml/templates/_av_partial_2.haml +5 -0
- data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
- data/test/haml/templates/_layout.erb +3 -0
- data/test/haml/templates/_layout_for_partial.haml +3 -0
- data/test/haml/templates/_partial.haml +8 -0
- data/test/haml/templates/_text_area.haml +3 -0
- data/test/haml/templates/action_view.haml +47 -0
- data/test/haml/templates/action_view_ugly.haml +47 -0
- data/test/haml/templates/breakage.haml +8 -0
- data/test/haml/templates/content_for_layout.haml +8 -0
- data/test/haml/templates/eval_suppressed.haml +11 -0
- data/test/haml/templates/filters.haml +66 -0
- data/test/haml/templates/helpers.haml +95 -0
- data/test/haml/templates/helpful.haml +11 -0
- data/test/haml/templates/just_stuff.haml +83 -0
- data/test/haml/templates/list.haml +12 -0
- data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/original_engine.haml +17 -0
- data/test/haml/templates/partial_layout.haml +3 -0
- data/test/haml/templates/partialize.haml +1 -0
- data/test/haml/templates/partials.haml +12 -0
- data/test/haml/templates/render_layout.haml +2 -0
- data/test/haml/templates/silent_script.haml +40 -0
- data/test/haml/templates/standard.haml +42 -0
- data/test/haml/templates/standard_ugly.haml +42 -0
- data/test/haml/templates/tag_parsing.haml +21 -0
- data/test/haml/templates/very_basic.haml +4 -0
- data/test/haml/templates/whitespace_handling.haml +87 -0
- data/test/haml/util_test.rb +92 -0
- data/test/linked_rails.rb +12 -0
- data/test/sass/css2sass_test.rb +294 -0
- data/test/sass/engine_test.rb +956 -0
- data/test/sass/functions_test.rb +126 -0
- data/test/sass/more_results/more1.css +9 -0
- data/test/sass/more_results/more1_with_line_comments.css +26 -0
- data/test/sass/more_results/more_import.css +29 -0
- data/test/sass/more_templates/_more_partial.sass +2 -0
- data/test/sass/more_templates/more1.sass +23 -0
- data/test/sass/more_templates/more_import.sass +11 -0
- data/test/sass/plugin_test.rb +229 -0
- data/test/sass/results/alt.css +4 -0
- data/test/sass/results/basic.css +9 -0
- data/test/sass/results/compact.css +5 -0
- data/test/sass/results/complex.css +87 -0
- data/test/sass/results/compressed.css +1 -0
- data/test/sass/results/expanded.css +19 -0
- data/test/sass/results/import.css +29 -0
- data/test/sass/results/line_numbers.css +49 -0
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/results/nested.css +22 -0
- data/test/sass/results/parent_ref.css +13 -0
- data/test/sass/results/script.css +16 -0
- data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
- data/test/sass/results/subdir/subdir.css +3 -0
- data/test/sass/results/units.css +11 -0
- data/test/sass/script_test.rb +261 -0
- data/test/sass/templates/_partial.sass +2 -0
- data/test/sass/templates/alt.sass +16 -0
- data/test/sass/templates/basic.sass +23 -0
- data/test/sass/templates/bork1.sass +2 -0
- data/test/sass/templates/bork2.sass +2 -0
- data/test/sass/templates/bork3.sass +2 -0
- data/test/sass/templates/compact.sass +17 -0
- data/test/sass/templates/complex.sass +307 -0
- data/test/sass/templates/compressed.sass +15 -0
- data/test/sass/templates/expanded.sass +17 -0
- data/test/sass/templates/import.sass +11 -0
- data/test/sass/templates/importee.sass +19 -0
- data/test/sass/templates/line_numbers.sass +13 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- data/test/sass/templates/nested.sass +25 -0
- data/test/sass/templates/nested_bork1.sass +2 -0
- data/test/sass/templates/nested_bork2.sass +2 -0
- data/test/sass/templates/nested_bork3.sass +2 -0
- data/test/sass/templates/parent_ref.sass +25 -0
- data/test/sass/templates/script.sass +101 -0
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
- data/test/sass/templates/subdir/subdir.sass +6 -0
- data/test/sass/templates/units.sass +11 -0
- data/test/test_helper.rb +44 -0
- metadata +298 -0
data/extra/sass-mode.el
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
;;; sass-mode.el --- Major mode for editing Sass files
|
|
2
|
+
|
|
3
|
+
;; Copyright (c) 2007, 2008 Nathan Weizenbaum
|
|
4
|
+
|
|
5
|
+
;; Author: Nathan Weizenbaum
|
|
6
|
+
;; URL: http://github.com/nex3/haml/tree/master
|
|
7
|
+
;; Version: 2.2.6
|
|
8
|
+
;; Created: 2007-03-15
|
|
9
|
+
;; By: Nathan Weizenbaum
|
|
10
|
+
;; Keywords: markup, language, css
|
|
11
|
+
|
|
12
|
+
;;; Commentary:
|
|
13
|
+
|
|
14
|
+
;; Because Sass's indentation schema is similar
|
|
15
|
+
;; to that of YAML and Python, many indentation-related
|
|
16
|
+
;; functions are similar to those in yaml-mode and python-mode.
|
|
17
|
+
|
|
18
|
+
;; To install, save this on your load path and add the following to
|
|
19
|
+
;; your .emacs file:
|
|
20
|
+
;;
|
|
21
|
+
;; (require 'sass-mode)
|
|
22
|
+
|
|
23
|
+
;;; Code:
|
|
24
|
+
|
|
25
|
+
(require 'haml-mode)
|
|
26
|
+
|
|
27
|
+
;; User definable variables
|
|
28
|
+
|
|
29
|
+
(defgroup sass nil
|
|
30
|
+
"Support for the Sass template language."
|
|
31
|
+
:group 'languages
|
|
32
|
+
:prefix "sass-")
|
|
33
|
+
|
|
34
|
+
(defcustom sass-mode-hook nil
|
|
35
|
+
"Hook run when entering Sass mode."
|
|
36
|
+
:type 'hook
|
|
37
|
+
:group 'sass)
|
|
38
|
+
|
|
39
|
+
(defcustom sass-indent-offset 2
|
|
40
|
+
"Amount of offset per level of indentation."
|
|
41
|
+
:type 'integer
|
|
42
|
+
:group 'sass)
|
|
43
|
+
|
|
44
|
+
(defvar sass-non-block-openers
|
|
45
|
+
'("^ *:[^ \t]+[ \t]+[^ \t]"
|
|
46
|
+
"^ *[^ \t:]+[ \t]*[=:][ \t]*[^ \t]")
|
|
47
|
+
"A list of regexps that match lines of Sass that don't open blocks.
|
|
48
|
+
That is, a Sass line that can't have text nested beneath it
|
|
49
|
+
should be matched by a regexp in this list.")
|
|
50
|
+
|
|
51
|
+
;; Font lock
|
|
52
|
+
|
|
53
|
+
(defconst sass-selector-font-lock-keywords
|
|
54
|
+
'(;; Attribute selectors (e.g. p[foo=bar])
|
|
55
|
+
("\\[\\([^]=]+\\)" (1 font-lock-variable-name-face)
|
|
56
|
+
("[~|$^*]?=\\([^]=]+\\)" nil nil (1 font-lock-string-face)))
|
|
57
|
+
("&" 0 font-lock-constant-face)
|
|
58
|
+
("\\.\\w+" 0 font-lock-type-face)
|
|
59
|
+
("#\\w+" 0 font-lock-keyword-face)
|
|
60
|
+
;; Pseudo-selectors, optionally with arguments (e.g. :first, :nth-child(12))
|
|
61
|
+
("\\(::?\\w+\\)" (1 font-lock-function-name-face)
|
|
62
|
+
("(\\([^)]+\\))" nil nil (1 font-lock-string-face)))))
|
|
63
|
+
|
|
64
|
+
(defconst sass-script-font-lock-keywords
|
|
65
|
+
`(("\"\\([^\"\\\\]\\|\\\\.\\)*\"" 0 font-lock-string-face)
|
|
66
|
+
("!\\(\\w\\|_\\)+" 0 font-lock-variable-name-face)
|
|
67
|
+
("#[0-9a-fA-F]\\{0,6\\}" 0 font-lock-preprocessor-face)
|
|
68
|
+
(,(regexp-opt
|
|
69
|
+
'("true" "false" "black" "silver" "gray" "white" "maroon" "red"
|
|
70
|
+
"purple" "fuchsia" "green" "lime" "olive" "yellow" "navy"
|
|
71
|
+
"blue" "teal" "aqua"))
|
|
72
|
+
0 font-lock-constant-face)
|
|
73
|
+
(,(regexp-opt '("and" "or" "not")) 0 font-lock-keyword-face)))
|
|
74
|
+
|
|
75
|
+
(defconst sass-syntax-table
|
|
76
|
+
(let ((st (make-syntax-table)))
|
|
77
|
+
(modify-syntax-entry ?- "w" st)
|
|
78
|
+
(modify-syntax-entry ?_ "w" st)
|
|
79
|
+
st))
|
|
80
|
+
|
|
81
|
+
(defconst sass-script-syntax-table
|
|
82
|
+
(let ((st (make-syntax-table sass-syntax-table)))
|
|
83
|
+
(modify-syntax-entry ?- "." st)
|
|
84
|
+
st))
|
|
85
|
+
|
|
86
|
+
(defconst sass-font-lock-keywords
|
|
87
|
+
'((sass-highlight-line 1 nil nil t)))
|
|
88
|
+
|
|
89
|
+
(defconst sass-line-keywords
|
|
90
|
+
'(("@\\(\\w+\\)" 0 font-lock-keyword-face sass-highlight-directive)
|
|
91
|
+
("/[/*].*" 0 font-lock-comment-face)
|
|
92
|
+
("[=+]\\w+" 0 font-lock-function-name-face sass-highlight-script-after-match)
|
|
93
|
+
("!\\w+" 0 font-lock-variable-name-face sass-highlight-script-after-match)
|
|
94
|
+
(":\\w+" 0 font-lock-variable-name-face)
|
|
95
|
+
("\\w+\s*:" 0 font-lock-variable-name-face)
|
|
96
|
+
("\\(\\w+\\)\s*=" 1 font-lock-variable-name-face sass-highlight-script-after-match)
|
|
97
|
+
("\\(:\\w+\\)\s*=" 1 font-lock-variable-name-face sass-highlight-script-after-match)
|
|
98
|
+
(".*" sass-highlight-selector))
|
|
99
|
+
"A list of full-line Sass syntax to highlight, used by `sass-highlight-line'.
|
|
100
|
+
|
|
101
|
+
Each item is either of the form (REGEXP SUBEXP FACE), (REGEXP FN),
|
|
102
|
+
or (REGEXP SUBEXP FACE FN). Each REGEXP is run successively on the
|
|
103
|
+
beginning of non-whitespace on the current line until one matches.
|
|
104
|
+
If it has SUBEXP and FACE, then SUBEXP is highlighted using FACE.
|
|
105
|
+
If it has FN, FN is run.")
|
|
106
|
+
|
|
107
|
+
(defun sass-highlight-line (limit)
|
|
108
|
+
"Highlight a single line using some Sass single-line syntax.
|
|
109
|
+
This syntax is taken from `sass-line-keywords'.
|
|
110
|
+
LIMIT is the limit of the search."
|
|
111
|
+
(save-match-data
|
|
112
|
+
(when (re-search-forward "^ *\\(.+\\)$" limit t)
|
|
113
|
+
(goto-char (match-beginning 1))
|
|
114
|
+
(dolist (keyword sass-line-keywords)
|
|
115
|
+
(destructuring-bind (keyword subexp-or-fn &optional face fn) keyword
|
|
116
|
+
(when (looking-at keyword)
|
|
117
|
+
(if (integerp subexp-or-fn)
|
|
118
|
+
(put-text-property (match-beginning subexp-or-fn)
|
|
119
|
+
(match-end subexp-or-fn)
|
|
120
|
+
'face face)
|
|
121
|
+
(setq fn subexp-or-fn))
|
|
122
|
+
(when fn (funcall fn))
|
|
123
|
+
(end-of-line)
|
|
124
|
+
(return t)))))))
|
|
125
|
+
|
|
126
|
+
(defun sass-highlight-selector ()
|
|
127
|
+
"Highlight a CSS selector starting at `point' and ending at `end-of-line'."
|
|
128
|
+
(let ((font-lock-keywords sass-selector-font-lock-keywords)
|
|
129
|
+
font-lock-multiline)
|
|
130
|
+
(font-lock-fontify-region
|
|
131
|
+
(point) (progn (end-of-line) (point))))
|
|
132
|
+
t)
|
|
133
|
+
|
|
134
|
+
(defun sass-highlight-script (beg end)
|
|
135
|
+
"Highlight a section of SassScript between BEG and END."
|
|
136
|
+
(save-match-data
|
|
137
|
+
(with-syntax-table sass-script-syntax-table
|
|
138
|
+
(let ((font-lock-keywords sass-script-font-lock-keywords)
|
|
139
|
+
font-lock-syntax-table
|
|
140
|
+
font-lock-extend-region-functions)
|
|
141
|
+
(font-lock-fontify-region beg end)))))
|
|
142
|
+
|
|
143
|
+
(defun sass-highlight-script-after-match ()
|
|
144
|
+
"Highlight a section of SassScript after the last match."
|
|
145
|
+
(end-of-line)
|
|
146
|
+
(sass-highlight-script (match-end 0) (point)))
|
|
147
|
+
|
|
148
|
+
(defun sass-highlight-directive ()
|
|
149
|
+
"Highlight a Sass directive."
|
|
150
|
+
(goto-char (match-end 0))
|
|
151
|
+
(block nil
|
|
152
|
+
(case (intern (match-string 1))
|
|
153
|
+
(for
|
|
154
|
+
(unless (looking-at " +!\\w+") (return))
|
|
155
|
+
(put-text-property (match-beginning 0) (match-end 0)
|
|
156
|
+
'face font-lock-variable-name-face)
|
|
157
|
+
(goto-char (match-end 0))
|
|
158
|
+
(unless (looking-at " +from") (return))
|
|
159
|
+
(put-text-property (match-beginning 0) (match-end 0)
|
|
160
|
+
'face font-lock-keyword-face)
|
|
161
|
+
(goto-char (match-end 0))
|
|
162
|
+
(when (looking-at " +\\(.+?\\) +\\(to\\|through\\)")
|
|
163
|
+
(sass-highlight-script (match-beginning 1) (match-end 1))
|
|
164
|
+
(put-text-property (match-beginning 2) (match-end 2)
|
|
165
|
+
'face font-lock-keyword-face))
|
|
166
|
+
(sass-highlight-script-after-match))
|
|
167
|
+
|
|
168
|
+
(else
|
|
169
|
+
(unless (looking-at " +if") (return))
|
|
170
|
+
(put-text-property (match-beginning 0) (match-end 0)
|
|
171
|
+
'face font-lock-keyword-face)
|
|
172
|
+
(sass-highlight-script-after-match))
|
|
173
|
+
|
|
174
|
+
((if while debug) (sass-highlight-script-after-match)))))
|
|
175
|
+
|
|
176
|
+
;; Constants
|
|
177
|
+
|
|
178
|
+
;; Mode setup
|
|
179
|
+
|
|
180
|
+
;;;###autoload
|
|
181
|
+
(define-derived-mode sass-mode haml-mode "Sass"
|
|
182
|
+
"Major mode for editing Sass files."
|
|
183
|
+
(set-syntax-table sass-syntax-table)
|
|
184
|
+
(setq font-lock-extend-region-functions
|
|
185
|
+
'(font-lock-extend-region-wholelines font-lock-extend-region-multiline))
|
|
186
|
+
(setq font-lock-multiline nil)
|
|
187
|
+
(setq comment-start "/*")
|
|
188
|
+
(set (make-local-variable 'haml-indent-function) 'sass-indent-p)
|
|
189
|
+
(set (make-local-variable 'haml-indent-offset) sass-indent-offset)
|
|
190
|
+
(setq font-lock-defaults '(sass-font-lock-keywords t t)))
|
|
191
|
+
|
|
192
|
+
;; Indentation
|
|
193
|
+
|
|
194
|
+
(defun sass-indent-p ()
|
|
195
|
+
"Return non-nil if the current line can have lines nested beneath it."
|
|
196
|
+
(loop for opener in sass-non-block-openers
|
|
197
|
+
unless (looking-at opener) return t
|
|
198
|
+
return nil))
|
|
199
|
+
|
|
200
|
+
;;;###autoload
|
|
201
|
+
(add-to-list 'auto-mode-alist '("\\.sass$" . sass-mode))
|
|
202
|
+
|
|
203
|
+
;; Setup/Activation
|
|
204
|
+
(provide 'sass-mode)
|
|
205
|
+
;;; sass-mode.el ends here
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'sinatra'
|
|
3
|
+
require 'json'
|
|
4
|
+
set :port, 3123
|
|
5
|
+
set :environment, :production
|
|
6
|
+
enable :lock
|
|
7
|
+
Dir.chdir(File.dirname(__FILE__) + "/..")
|
|
8
|
+
|
|
9
|
+
post "/" do
|
|
10
|
+
puts "Recieved payload!"
|
|
11
|
+
puts "Rev: #{`git name-rev HEAD`.strip}"
|
|
12
|
+
system %{rake handle_update --trace REF=#{JSON.parse(params["payload"])["ref"].inspect}}
|
|
13
|
+
end
|
data/init.rb
ADDED
data/lib/haml.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
dir = File.dirname(__FILE__)
|
|
2
|
+
$LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
|
|
3
|
+
|
|
4
|
+
require 'haml/version'
|
|
5
|
+
|
|
6
|
+
# The module that contains everything Haml-related:
|
|
7
|
+
#
|
|
8
|
+
# * {Haml::Engine} is the class used to render Haml within Ruby code.
|
|
9
|
+
# * {Haml::Helpers} contains Ruby helpers available within Haml templates.
|
|
10
|
+
# * {Haml::Template} interfaces with web frameworks (Rails in particular).
|
|
11
|
+
# * {Haml::Error} is raised when Haml encounters an error.
|
|
12
|
+
# * {Haml::HTML} handles conversion of HTML to Haml.
|
|
13
|
+
#
|
|
14
|
+
# Also see the {file:HAML_REFERENCE.md full Haml reference}.
|
|
15
|
+
module Haml
|
|
16
|
+
extend Haml::Version
|
|
17
|
+
|
|
18
|
+
# A string representing the version of Haml.
|
|
19
|
+
# A more fine-grained representation is available from Haml.version.
|
|
20
|
+
VERSION = version[:string] unless defined?(Haml::VERSION)
|
|
21
|
+
|
|
22
|
+
# Initializes Haml for Rails.
|
|
23
|
+
#
|
|
24
|
+
# This method is called by `init.rb`,
|
|
25
|
+
# which is run by Rails on startup.
|
|
26
|
+
# We use it rather than putting stuff straight into `init.rb`
|
|
27
|
+
# so we can change the initialization behavior
|
|
28
|
+
# without modifying the file itself.
|
|
29
|
+
#
|
|
30
|
+
# @param binding [Binding] The context of the `init.rb` file.
|
|
31
|
+
# This isn't actually used;
|
|
32
|
+
# it's just passed in in case it needs to be used in the future
|
|
33
|
+
def self.init_rails(binding)
|
|
34
|
+
# No &method here for Rails 2.1 compatibility
|
|
35
|
+
%w[haml/template sass sass/plugin].each {|f| require f}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
require 'haml/util'
|
|
40
|
+
require 'haml/engine'
|
data/lib/haml/buffer.rb
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
module Haml
|
|
2
|
+
# This class is used only internally. It holds the buffer of HTML that
|
|
3
|
+
# is eventually output as the resulting document.
|
|
4
|
+
# It's called from within the precompiled code,
|
|
5
|
+
# and helps reduce the amount of processing done within `instance_eval`ed code.
|
|
6
|
+
class Buffer
|
|
7
|
+
include Haml::Helpers
|
|
8
|
+
include Haml::Util
|
|
9
|
+
|
|
10
|
+
# The string that holds the compiled HTML. This is aliased as
|
|
11
|
+
# `_erbout` for compatibility with ERB-specific code.
|
|
12
|
+
#
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_accessor :buffer
|
|
15
|
+
|
|
16
|
+
# The options hash passed in from {Haml::Engine}.
|
|
17
|
+
#
|
|
18
|
+
# @return [Hash<String, Object>]
|
|
19
|
+
# @see Haml::Engine#options_for_buffer
|
|
20
|
+
attr_accessor :options
|
|
21
|
+
|
|
22
|
+
# The {Buffer} for the enclosing Haml document.
|
|
23
|
+
# This is set for partials and similar sorts of nested templates.
|
|
24
|
+
# It's `nil` at the top level (see \{#toplevel?}).
|
|
25
|
+
#
|
|
26
|
+
# @return [Buffer]
|
|
27
|
+
attr_accessor :upper
|
|
28
|
+
|
|
29
|
+
# nil if there's no capture_haml block running,
|
|
30
|
+
# and the position at which it's beginning the capture if there is one.
|
|
31
|
+
#
|
|
32
|
+
# @return [Fixnum, nil]
|
|
33
|
+
attr_accessor :capture_position
|
|
34
|
+
|
|
35
|
+
# @return [Boolean]
|
|
36
|
+
# @see #active?
|
|
37
|
+
attr_writer :active
|
|
38
|
+
|
|
39
|
+
# @return [Boolean] Whether or not the format is XHTML
|
|
40
|
+
def xhtml?
|
|
41
|
+
not html?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @return [Boolean] Whether or not the format is any flavor of HTML
|
|
45
|
+
def html?
|
|
46
|
+
html4? or html5?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [Boolean] Whether or not the format is HTML4
|
|
50
|
+
def html4?
|
|
51
|
+
@options[:format] == :html4
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Boolean] Whether or not the format is HTML5.
|
|
55
|
+
def html5?
|
|
56
|
+
@options[:format] == :html5
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Boolean] Whether or not this buffer is a top-level template,
|
|
60
|
+
# as opposed to a nested partial
|
|
61
|
+
def toplevel?
|
|
62
|
+
upper.nil?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Whether or not this buffer is currently being used to render a Haml template.
|
|
66
|
+
# Returns `false` if a subtemplate is being rendered,
|
|
67
|
+
# even if it's a subtemplate of this buffer's template.
|
|
68
|
+
#
|
|
69
|
+
# @return [Boolean]
|
|
70
|
+
def active?
|
|
71
|
+
@active
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @return [Fixnum] The current indentation level of the document
|
|
75
|
+
def tabulation
|
|
76
|
+
@real_tabs + @tabulation
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Sets the current tabulation of the document.
|
|
80
|
+
#
|
|
81
|
+
# @param val [Fixnum] The new tabulation
|
|
82
|
+
def tabulation=(val)
|
|
83
|
+
val = val - @real_tabs
|
|
84
|
+
@tabulation = val > -1 ? val : 0
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @param upper [Buffer] The parent buffer
|
|
88
|
+
# @param options [Hash<Symbol, Object>] An options hash.
|
|
89
|
+
# See {Haml::Engine#options\_for\_buffer}
|
|
90
|
+
def initialize(upper = nil, options = {})
|
|
91
|
+
@active = true
|
|
92
|
+
@upper = upper
|
|
93
|
+
@options = options
|
|
94
|
+
@buffer = ruby1_8? ? "" : "".encode(Encoding.find(options[:encoding]))
|
|
95
|
+
@tabulation = 0
|
|
96
|
+
|
|
97
|
+
# The number of tabs that Engine thinks we should have
|
|
98
|
+
# @real_tabs + @tabulation is the number of tabs actually output
|
|
99
|
+
@real_tabs = 0
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Appends text to the buffer, properly tabulated.
|
|
103
|
+
# Also modifies the document's indentation.
|
|
104
|
+
#
|
|
105
|
+
# @param text [String] The text to append
|
|
106
|
+
# @param tab_change [Fixnum] The number of tabs by which to increase
|
|
107
|
+
# or decrease the document's indentation
|
|
108
|
+
# @param dont_tab_up [Boolean] If true, don't indent the first line of `text`
|
|
109
|
+
def push_text(text, tab_change, dont_tab_up)
|
|
110
|
+
if @tabulation > 0
|
|
111
|
+
# Have to push every line in by the extra user set tabulation.
|
|
112
|
+
# Don't push lines with just whitespace, though,
|
|
113
|
+
# because that screws up precompiled indentation.
|
|
114
|
+
text.gsub!(/^(?!\s+$)/m, tabs)
|
|
115
|
+
text.sub!(tabs, '') if dont_tab_up
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
@buffer << text
|
|
119
|
+
@real_tabs += tab_change
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Modifies the indentation of the document.
|
|
123
|
+
#
|
|
124
|
+
# @param tab_change [Fixnum] The number of tabs by which to increase
|
|
125
|
+
# or decrease the document's indentation
|
|
126
|
+
def adjust_tabs(tab_change)
|
|
127
|
+
@real_tabs += tab_change
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
Haml::Util.def_static_method(self, :format_script, [:result],
|
|
131
|
+
:preserve_script, :in_tag, :preserve_tag, :escape_html,
|
|
132
|
+
:nuke_inner_whitespace, :interpolated, :ugly, <<RUBY)
|
|
133
|
+
<% unless ugly %>
|
|
134
|
+
# If we're interpolated,
|
|
135
|
+
# then the custom tabulation is handled in #push_text.
|
|
136
|
+
# The easiest way to avoid it here is to reset @tabulation.
|
|
137
|
+
<% if interpolated %>
|
|
138
|
+
old_tabulation = @tabulation
|
|
139
|
+
@tabulation = 0
|
|
140
|
+
<% end %>
|
|
141
|
+
|
|
142
|
+
tabulation = @real_tabs
|
|
143
|
+
result = result.to_s.<% if nuke_inner_whitespace %>strip<% else %>rstrip<% end %>
|
|
144
|
+
<% else %>
|
|
145
|
+
result = result.to_s<% if nuke_inner_whitespace %>.strip<% end %>
|
|
146
|
+
<% end %>
|
|
147
|
+
|
|
148
|
+
<% if escape_html %> result = html_escape(result) <% end %>
|
|
149
|
+
|
|
150
|
+
<% if preserve_tag %>
|
|
151
|
+
result = Haml::Helpers.preserve(result)
|
|
152
|
+
<% elsif preserve_script %>
|
|
153
|
+
result = Haml::Helpers.find_and_preserve(result, options[:preserve])
|
|
154
|
+
<% end %>
|
|
155
|
+
|
|
156
|
+
<% if ugly %>
|
|
157
|
+
return result
|
|
158
|
+
<% else %>
|
|
159
|
+
|
|
160
|
+
has_newline = result.include?("\\n")
|
|
161
|
+
<% if in_tag && !nuke_inner_whitespace %>
|
|
162
|
+
<% unless preserve_tag %> if !has_newline <% end %>
|
|
163
|
+
@real_tabs -= 1
|
|
164
|
+
<% if interpolated %> @tabulation = old_tabulation <% end %>
|
|
165
|
+
return result
|
|
166
|
+
<% unless preserve_tag %> end <% end %>
|
|
167
|
+
<% end %>
|
|
168
|
+
|
|
169
|
+
# Precompiled tabulation may be wrong
|
|
170
|
+
<% if !interpolated && !in_tag %>
|
|
171
|
+
result = tabs + result if @tabulation > 0
|
|
172
|
+
<% end %>
|
|
173
|
+
|
|
174
|
+
if has_newline
|
|
175
|
+
result = result.gsub "\\n", "\\n" + tabs(tabulation)
|
|
176
|
+
|
|
177
|
+
# Add tabulation if it wasn't precompiled
|
|
178
|
+
<% if in_tag && !nuke_inner_whitespace %> result = tabs(tabulation) + result <% end %>
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
<% if in_tag && !nuke_inner_whitespace %>
|
|
182
|
+
result = "\\n\#{result}\\n\#{tabs(tabulation-1)}"
|
|
183
|
+
@real_tabs -= 1
|
|
184
|
+
<% end %>
|
|
185
|
+
<% if interpolated %> @tabulation = old_tabulation <% end %>
|
|
186
|
+
result
|
|
187
|
+
<% end %>
|
|
188
|
+
RUBY
|
|
189
|
+
|
|
190
|
+
# Takes the various information about the opening tag for an element,
|
|
191
|
+
# formats it, and appends it to the buffer.
|
|
192
|
+
def open_tag(name, self_closing, try_one_line, preserve_tag, escape_html, class_id,
|
|
193
|
+
nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
|
|
194
|
+
tabulation = @real_tabs
|
|
195
|
+
|
|
196
|
+
attributes = class_id
|
|
197
|
+
attributes_hashes.each do |old|
|
|
198
|
+
self.class.merge_attrs(attributes, to_hash(old.map {|k, v| [k.to_s, v]}))
|
|
199
|
+
end
|
|
200
|
+
self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
|
|
201
|
+
|
|
202
|
+
if self_closing && xhtml?
|
|
203
|
+
str = " />" + (nuke_outer_whitespace ? "" : "\n")
|
|
204
|
+
else
|
|
205
|
+
str = ">" + ((if self_closing && html?
|
|
206
|
+
nuke_outer_whitespace
|
|
207
|
+
else
|
|
208
|
+
try_one_line || preserve_tag || nuke_inner_whitespace
|
|
209
|
+
end) ? "" : "\n")
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
attributes = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
|
|
213
|
+
@buffer << "#{nuke_outer_whitespace || @options[:ugly] ? '' : tabs(tabulation)}<#{name}#{attributes}#{str}"
|
|
214
|
+
|
|
215
|
+
if content
|
|
216
|
+
@buffer << "#{content}</#{name}>" << (nuke_outer_whitespace ? "" : "\n")
|
|
217
|
+
return
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
@real_tabs += 1 unless self_closing || nuke_inner_whitespace
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Remove the whitespace from the right side of the buffer string.
|
|
224
|
+
# Doesn't do anything if we're at the beginning of a capture_haml block.
|
|
225
|
+
def rstrip!
|
|
226
|
+
if capture_position.nil?
|
|
227
|
+
buffer.rstrip!
|
|
228
|
+
return
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
buffer << buffer.slice!(capture_position..-1).rstrip
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Merges two attribute hashes.
|
|
235
|
+
# This is the same as `to.merge!(from)`,
|
|
236
|
+
# except that it merges id and class attributes.
|
|
237
|
+
#
|
|
238
|
+
# ids are concatenated with `"_"`,
|
|
239
|
+
# and classes are concatenated with `" "`.
|
|
240
|
+
#
|
|
241
|
+
# Destructively modifies both `to` and `from`.
|
|
242
|
+
#
|
|
243
|
+
# @param to [Hash<String, String>] The attribute hash to merge into
|
|
244
|
+
# @param from [Hash<String, String>] The attribute hash to merge from
|
|
245
|
+
# @return [Hash<String, String>] `to`, after being merged
|
|
246
|
+
def self.merge_attrs(to, from)
|
|
247
|
+
if to['id'] && from['id']
|
|
248
|
+
to['id'] << '_' << from.delete('id').to_s
|
|
249
|
+
elsif to['id'] || from['id']
|
|
250
|
+
from['id'] ||= to['id']
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
if to['class'] && from['class']
|
|
254
|
+
# Make sure we don't duplicate class names
|
|
255
|
+
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).sort.join(' ')
|
|
256
|
+
elsif to['class'] || from['class']
|
|
257
|
+
from['class'] ||= to['class']
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
to.merge!(from)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
private
|
|
264
|
+
|
|
265
|
+
@@tab_cache = {}
|
|
266
|
+
# Gets `count` tabs. Mostly for internal use.
|
|
267
|
+
def tabs(count = 0)
|
|
268
|
+
tabs = [count + @tabulation, 0].max
|
|
269
|
+
@@tab_cache[tabs] ||= ' ' * tabs
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Takes an array of objects and uses the class and id of the first
|
|
273
|
+
# one to create an attributes hash.
|
|
274
|
+
# The second object, if present, is used as a prefix,
|
|
275
|
+
# just like you can do with `dom_id()` and `dom_class()` in Rails
|
|
276
|
+
def parse_object_ref(ref)
|
|
277
|
+
prefix = ref[1]
|
|
278
|
+
ref = ref[0]
|
|
279
|
+
# Let's make sure the value isn't nil. If it is, return the default Hash.
|
|
280
|
+
return {} if ref.nil?
|
|
281
|
+
class_name =
|
|
282
|
+
if ref.respond_to?(:haml_object_ref)
|
|
283
|
+
ref.haml_object_ref
|
|
284
|
+
else
|
|
285
|
+
underscore(ref.class)
|
|
286
|
+
end
|
|
287
|
+
id = "#{class_name}_#{ref.id || 'new'}"
|
|
288
|
+
if prefix
|
|
289
|
+
class_name = "#{ prefix }_#{ class_name}"
|
|
290
|
+
id = "#{ prefix }_#{ id }"
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
{'id' => id, 'class' => class_name}
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Changes a word from camel case to underscores.
|
|
297
|
+
# Based on the method of the same name in Rails' Inflector,
|
|
298
|
+
# but copied here so it'll run properly without Rails.
|
|
299
|
+
def underscore(camel_cased_word)
|
|
300
|
+
camel_cased_word.to_s.gsub(/::/, '_').
|
|
301
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
|
302
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
|
303
|
+
tr("-", "_").
|
|
304
|
+
downcase
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|