radiant 0.6.6 → 0.6.7

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 (208) hide show
  1. data/CHANGELOG +15 -0
  2. data/CONTRIBUTORS +8 -0
  3. data/app/controllers/admin/page_controller.rb +1 -11
  4. data/app/controllers/admin/welcome_controller.rb +5 -6
  5. data/app/controllers/application.rb +2 -0
  6. data/app/controllers/site_controller.rb +1 -0
  7. data/app/helpers/admin/page_helper.rb +36 -0
  8. data/app/helpers/admin/regions_helper.rb +28 -0
  9. data/app/helpers/admin/user_helper.rb +6 -0
  10. data/app/helpers/application_helper.rb +2 -1
  11. data/app/models/user.rb +7 -8
  12. data/app/views/admin/extension/index.html.haml +28 -0
  13. data/app/views/admin/layout/edit.html.haml +44 -0
  14. data/app/views/admin/layout/index.html.haml +25 -0
  15. data/app/views/admin/layout/remove.html.haml +16 -0
  16. data/app/views/admin/page/_meta_row.html.haml +6 -0
  17. data/app/views/admin/page/_node.html.haml +25 -0
  18. data/app/views/admin/page/_part.html.haml +17 -0
  19. data/app/views/admin/page/_tag_reference.html.haml +3 -0
  20. data/app/views/admin/page/children.html.haml +2 -0
  21. data/app/views/admin/page/edit.html.haml +114 -0
  22. data/app/views/admin/page/index.html.haml +28 -0
  23. data/app/views/admin/page/remove.html.haml +20 -0
  24. data/app/views/admin/snippet/edit.html.haml +36 -0
  25. data/app/views/admin/snippet/index.html.haml +20 -0
  26. data/app/views/admin/snippet/remove.html.haml +19 -0
  27. data/app/views/admin/user/edit.html.haml +80 -0
  28. data/app/views/admin/user/index.html.haml +23 -0
  29. data/app/views/admin/user/preferences.html.haml +28 -0
  30. data/app/views/admin/user/remove.html.haml +18 -0
  31. data/app/views/admin/welcome/login.html.haml +44 -0
  32. data/app/views/layouts/application.html.haml +54 -0
  33. data/app/views/site/not_found.html.haml +3 -0
  34. data/db/migrate/019_add_salt_to_users.rb +11 -0
  35. data/db/schema.rb +2 -1
  36. data/lib/login_system.rb +1 -0
  37. data/lib/radiant.rb +1 -1
  38. data/lib/radiant/admin_ui.rb +65 -0
  39. data/lib/radiant/admin_ui/region_partials.rb +18 -0
  40. data/lib/radiant/admin_ui/region_set.rb +35 -0
  41. data/lib/tasks/extensions.rake +33 -0
  42. data/public/javascripts/admin/admin.js +8 -2
  43. data/public/javascripts/admin/sitemap.js +2 -1
  44. data/public/stylesheets/admin/main.css +4 -0
  45. data/spec/controllers/admin/abstract_model_controller_spec.rb +2 -0
  46. data/spec/controllers/admin/page_controller_spec.rb +3 -28
  47. data/spec/controllers/admin/user_controller_spec.rb +1 -1
  48. data/spec/controllers/admin/welcome_controller_spec.rb +26 -0
  49. data/spec/helpers/admin/page_helper_spec.rb +4 -0
  50. data/spec/helpers/admin/regions_helper_spec.rb +47 -0
  51. data/spec/helpers/admin/user_helper_spec.rb +7 -0
  52. data/spec/helpers/application_helper_spec.rb +7 -3
  53. data/spec/lib/login_system_spec.rb +5 -0
  54. data/spec/lib/radiant/admin_ui/region_partials_spec.rb +35 -0
  55. data/spec/lib/radiant/admin_ui/region_set_spec.rb +61 -0
  56. data/spec/lib/radiant/admin_ui_spec.rb +74 -18
  57. data/spec/models/user_spec.rb +11 -4
  58. data/spec/scenarios/users_scenario.rb +2 -2
  59. data/vendor/plugins/haml/MIT-LICENSE +20 -0
  60. data/vendor/plugins/haml/README.rdoc +319 -0
  61. data/vendor/plugins/haml/Rakefile +158 -0
  62. data/vendor/plugins/haml/TODO +9 -0
  63. data/vendor/plugins/haml/VERSION +1 -0
  64. data/vendor/plugins/haml/bin/css2sass +7 -0
  65. data/vendor/plugins/haml/bin/haml +8 -0
  66. data/vendor/plugins/haml/bin/html2haml +7 -0
  67. data/vendor/plugins/haml/bin/sass +8 -0
  68. data/vendor/plugins/haml/extra/haml-mode.el +328 -0
  69. data/vendor/plugins/haml/extra/sass-mode.el +88 -0
  70. data/vendor/plugins/haml/init.rb +2 -0
  71. data/vendor/plugins/haml/lib/haml.rb +977 -0
  72. data/vendor/plugins/haml/lib/haml/buffer.rb +229 -0
  73. data/vendor/plugins/haml/lib/haml/engine.rb +274 -0
  74. data/vendor/plugins/haml/lib/haml/error.rb +23 -0
  75. data/vendor/plugins/haml/lib/haml/exec.rb +347 -0
  76. data/vendor/plugins/haml/lib/haml/filters.rb +249 -0
  77. data/vendor/plugins/haml/lib/haml/helpers.rb +413 -0
  78. data/vendor/plugins/haml/lib/haml/helpers/action_view_extensions.rb +45 -0
  79. data/vendor/plugins/haml/lib/haml/helpers/action_view_mods.rb +122 -0
  80. data/vendor/plugins/haml/lib/haml/html.rb +188 -0
  81. data/vendor/plugins/haml/lib/haml/precompiler.rb +757 -0
  82. data/vendor/plugins/haml/lib/haml/template.rb +43 -0
  83. data/vendor/plugins/haml/lib/haml/template/patch.rb +58 -0
  84. data/vendor/plugins/haml/lib/haml/template/plugin.rb +72 -0
  85. data/vendor/plugins/haml/lib/sass.rb +833 -0
  86. data/vendor/plugins/haml/lib/sass/constant.rb +245 -0
  87. data/vendor/plugins/haml/lib/sass/constant/color.rb +101 -0
  88. data/vendor/plugins/haml/lib/sass/constant/literal.rb +53 -0
  89. data/vendor/plugins/haml/lib/sass/constant/number.rb +87 -0
  90. data/vendor/plugins/haml/lib/sass/constant/operation.rb +30 -0
  91. data/vendor/plugins/haml/lib/sass/constant/string.rb +22 -0
  92. data/vendor/plugins/haml/lib/sass/css.rb +378 -0
  93. data/vendor/plugins/haml/lib/sass/engine.rb +459 -0
  94. data/vendor/plugins/haml/lib/sass/error.rb +35 -0
  95. data/vendor/plugins/haml/lib/sass/plugin.rb +165 -0
  96. data/vendor/plugins/haml/lib/sass/plugin/merb.rb +56 -0
  97. data/vendor/plugins/haml/lib/sass/plugin/rails.rb +24 -0
  98. data/vendor/plugins/haml/lib/sass/tree/attr_node.rb +53 -0
  99. data/vendor/plugins/haml/lib/sass/tree/comment_node.rb +20 -0
  100. data/vendor/plugins/haml/lib/sass/tree/directive_node.rb +46 -0
  101. data/vendor/plugins/haml/lib/sass/tree/node.rb +42 -0
  102. data/vendor/plugins/haml/lib/sass/tree/rule_node.rb +89 -0
  103. data/vendor/plugins/haml/lib/sass/tree/value_node.rb +16 -0
  104. data/vendor/plugins/haml/test/benchmark.rb +82 -0
  105. data/vendor/plugins/haml/test/haml/engine_test.rb +587 -0
  106. data/vendor/plugins/haml/test/haml/helper_test.rb +187 -0
  107. data/vendor/plugins/haml/test/haml/html2haml_test.rb +60 -0
  108. data/vendor/plugins/haml/test/haml/markaby/standard.mab +52 -0
  109. data/vendor/plugins/haml/test/haml/mocks/article.rb +6 -0
  110. data/vendor/plugins/haml/test/haml/results/content_for_layout.xhtml +16 -0
  111. data/vendor/plugins/haml/test/haml/results/eval_suppressed.xhtml +11 -0
  112. data/vendor/plugins/haml/test/haml/results/filters.xhtml +82 -0
  113. data/vendor/plugins/haml/test/haml/results/helpers.xhtml +94 -0
  114. data/vendor/plugins/haml/test/haml/results/helpful.xhtml +10 -0
  115. data/vendor/plugins/haml/test/haml/results/just_stuff.xhtml +64 -0
  116. data/vendor/plugins/haml/test/haml/results/list.xhtml +12 -0
  117. data/vendor/plugins/haml/test/haml/results/original_engine.xhtml +22 -0
  118. data/vendor/plugins/haml/test/haml/results/partials.xhtml +21 -0
  119. data/vendor/plugins/haml/test/haml/results/silent_script.xhtml +74 -0
  120. data/vendor/plugins/haml/test/haml/results/standard.xhtml +42 -0
  121. data/vendor/plugins/haml/test/haml/results/tag_parsing.xhtml +28 -0
  122. data/vendor/plugins/haml/test/haml/results/very_basic.xhtml +7 -0
  123. data/vendor/plugins/haml/test/haml/results/whitespace_handling.xhtml +94 -0
  124. data/vendor/plugins/haml/test/haml/rhtml/_av_partial_1.rhtml +12 -0
  125. data/vendor/plugins/haml/test/haml/rhtml/_av_partial_2.rhtml +8 -0
  126. data/vendor/plugins/haml/test/haml/rhtml/action_view.rhtml +62 -0
  127. data/vendor/plugins/haml/test/haml/rhtml/standard.rhtml +54 -0
  128. data/vendor/plugins/haml/test/haml/template_test.rb +168 -0
  129. data/vendor/plugins/haml/test/haml/templates/_av_partial_1.haml +9 -0
  130. data/vendor/plugins/haml/test/haml/templates/_av_partial_2.haml +5 -0
  131. data/vendor/plugins/haml/test/haml/templates/_partial.haml +8 -0
  132. data/vendor/plugins/haml/test/haml/templates/_text_area.haml +3 -0
  133. data/vendor/plugins/haml/test/haml/templates/action_view.haml +47 -0
  134. data/vendor/plugins/haml/test/haml/templates/breakage.haml +8 -0
  135. data/vendor/plugins/haml/test/haml/templates/content_for_layout.haml +10 -0
  136. data/vendor/plugins/haml/test/haml/templates/eval_suppressed.haml +11 -0
  137. data/vendor/plugins/haml/test/haml/templates/filters.haml +81 -0
  138. data/vendor/plugins/haml/test/haml/templates/helpers.haml +69 -0
  139. data/vendor/plugins/haml/test/haml/templates/helpful.haml +11 -0
  140. data/vendor/plugins/haml/test/haml/templates/just_stuff.haml +77 -0
  141. data/vendor/plugins/haml/test/haml/templates/list.haml +12 -0
  142. data/vendor/plugins/haml/test/haml/templates/original_engine.haml +17 -0
  143. data/vendor/plugins/haml/test/haml/templates/partialize.haml +1 -0
  144. data/vendor/plugins/haml/test/haml/templates/partials.haml +12 -0
  145. data/vendor/plugins/haml/test/haml/templates/silent_script.haml +40 -0
  146. data/vendor/plugins/haml/test/haml/templates/standard.haml +42 -0
  147. data/vendor/plugins/haml/test/haml/templates/tag_parsing.haml +24 -0
  148. data/vendor/plugins/haml/test/haml/templates/very_basic.haml +4 -0
  149. data/vendor/plugins/haml/test/haml/templates/whitespace_handling.haml +87 -0
  150. data/vendor/plugins/haml/test/haml/test_helper.rb +15 -0
  151. data/vendor/plugins/haml/test/profile.rb +65 -0
  152. data/vendor/plugins/haml/test/sass/engine_test.rb +276 -0
  153. data/vendor/plugins/haml/test/sass/plugin_test.rb +159 -0
  154. data/vendor/plugins/haml/test/sass/results/alt.css +4 -0
  155. data/vendor/plugins/haml/test/sass/results/basic.css +9 -0
  156. data/vendor/plugins/haml/test/sass/results/compact.css +5 -0
  157. data/vendor/plugins/haml/test/sass/results/complex.css +87 -0
  158. data/vendor/plugins/haml/test/sass/results/compressed.css +1 -0
  159. data/vendor/plugins/haml/test/sass/results/constants.css +14 -0
  160. data/vendor/plugins/haml/test/sass/results/expanded.css +19 -0
  161. data/vendor/plugins/haml/test/sass/results/import.css +29 -0
  162. data/vendor/plugins/haml/test/sass/results/mixins.css +95 -0
  163. data/vendor/plugins/haml/test/sass/results/multiline.css +24 -0
  164. data/vendor/plugins/haml/test/sass/results/nested.css +22 -0
  165. data/vendor/plugins/haml/test/sass/results/parent_ref.css +13 -0
  166. data/vendor/plugins/haml/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  167. data/vendor/plugins/haml/test/sass/results/subdir/subdir.css +1 -0
  168. data/vendor/plugins/haml/test/sass/templates/_partial.sass +2 -0
  169. data/vendor/plugins/haml/test/sass/templates/alt.sass +16 -0
  170. data/vendor/plugins/haml/test/sass/templates/basic.sass +23 -0
  171. data/vendor/plugins/haml/test/sass/templates/bork.sass +2 -0
  172. data/vendor/plugins/haml/test/sass/templates/bork2.sass +2 -0
  173. data/vendor/plugins/haml/test/sass/templates/compact.sass +17 -0
  174. data/vendor/plugins/haml/test/sass/templates/complex.sass +310 -0
  175. data/vendor/plugins/haml/test/sass/templates/compressed.sass +15 -0
  176. data/vendor/plugins/haml/test/sass/templates/constants.sass +97 -0
  177. data/vendor/plugins/haml/test/sass/templates/expanded.sass +17 -0
  178. data/vendor/plugins/haml/test/sass/templates/import.sass +11 -0
  179. data/vendor/plugins/haml/test/sass/templates/importee.sass +14 -0
  180. data/vendor/plugins/haml/test/sass/templates/mixins.sass +76 -0
  181. data/vendor/plugins/haml/test/sass/templates/multiline.sass +20 -0
  182. data/vendor/plugins/haml/test/sass/templates/nested.sass +25 -0
  183. data/vendor/plugins/haml/test/sass/templates/parent_ref.sass +25 -0
  184. data/vendor/plugins/haml/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  185. data/vendor/plugins/haml/test/sass/templates/subdir/subdir.sass +6 -0
  186. metadata +185 -24
  187. data/app/views/admin/extension/index.html.erb +0 -40
  188. data/app/views/admin/layout/edit.html.erb +0 -39
  189. data/app/views/admin/layout/index.html.erb +0 -38
  190. data/app/views/admin/layout/remove.html.erb +0 -17
  191. data/app/views/admin/page/_meta_row.html.erb +0 -4
  192. data/app/views/admin/page/_node.html.erb +0 -28
  193. data/app/views/admin/page/_part.html.erb +0 -13
  194. data/app/views/admin/page/_tag_reference.html.erb +0 -4
  195. data/app/views/admin/page/children.html.erb +0 -4
  196. data/app/views/admin/page/edit.html.erb +0 -140
  197. data/app/views/admin/page/index.html.erb +0 -31
  198. data/app/views/admin/page/remove.html.erb +0 -14
  199. data/app/views/admin/snippet/edit.html.erb +0 -29
  200. data/app/views/admin/snippet/index.html.erb +0 -36
  201. data/app/views/admin/snippet/remove.html.erb +0 -16
  202. data/app/views/admin/user/edit.html.erb +0 -54
  203. data/app/views/admin/user/index.html.erb +0 -43
  204. data/app/views/admin/user/preferences.html.erb +0 -29
  205. data/app/views/admin/user/remove.html.erb +0 -16
  206. data/app/views/admin/welcome/login.html.erb +0 -51
  207. data/app/views/layouts/application.html.erb +0 -83
  208. data/app/views/site/not_found.html.erb +0 -3
@@ -0,0 +1,229 @@
1
+ module Haml
2
+ # This class is used only internally. It holds the buffer of XHTML that
3
+ # is eventually output by Haml::Engine's to_html method. It's called
4
+ # from within the precompiled code, and helps reduce the amount of
5
+ # processing done within instance_eval'd code.
6
+ class Buffer
7
+ include Haml::Helpers
8
+
9
+ # The string that holds the compiled XHTML. This is aliased as
10
+ # _erbout for compatibility with ERB-specific code.
11
+ attr_accessor :buffer
12
+
13
+ # The options hash passed in from Haml::Engine.
14
+ attr_accessor :options
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
+
57
+ # Gets the current tabulation of the document.
58
+ def tabulation
59
+ @real_tabs + @tabulation
60
+ end
61
+
62
+ # Sets the current tabulation of the document.
63
+ def tabulation=(val)
64
+ val = val - @real_tabs
65
+ @tabulation = val > -1 ? val : 0
66
+ end
67
+
68
+ # Creates a new buffer.
69
+ def initialize(upper = nil, options = {})
70
+ @active = true
71
+ @upper = upper
72
+ @options = {
73
+ :attr_wrapper => "'",
74
+ :ugly => false,
75
+ :format => :xhtml
76
+ }.merge options
77
+ @buffer = ""
78
+ @tabulation = 0
79
+
80
+ # The number of tabs that Engine thinks we should have
81
+ # @real_tabs + @tabulation is the number of tabs actually output
82
+ @real_tabs = 0
83
+ end
84
+
85
+ # Renders +text+ with the proper tabulation. This also deals with
86
+ # making a possible one-line tag one line or not.
87
+ def push_text(text, tab_change = 0)
88
+ if @tabulation > 0 && !@options[:ugly]
89
+ # Have to push every line in by the extra user set tabulation
90
+ text.gsub!(/^/m, ' ' * @tabulation)
91
+ end
92
+
93
+ @buffer << text
94
+ @real_tabs += tab_change
95
+ end
96
+
97
+ # Properly formats the output of a script that was run in the
98
+ # instance_eval.
99
+ def push_script(result, preserve_script, close_tag = nil, preserve_tag = false, escape_html = false)
100
+ tabulation = @real_tabs
101
+
102
+ if preserve_tag
103
+ result = Haml::Helpers.preserve(result)
104
+ elsif preserve_script
105
+ result = Haml::Helpers.find_and_preserve(result)
106
+ end
107
+
108
+ result = result.to_s
109
+ while result[-1] == ?\n
110
+ # String#chomp is slow
111
+ result = result[0...-1]
112
+ end
113
+
114
+ result = html_escape(result) if escape_html
115
+
116
+ if close_tag && (@options[:ugly] || !result.include?("\n") || preserve_tag)
117
+ @buffer << "#{result}</#{close_tag}>\n"
118
+ @real_tabs -= 1
119
+ else
120
+ if close_tag
121
+ @buffer << "\n"
122
+ end
123
+
124
+ result = result.gsub(/^/m, tabs(tabulation)) unless @options[:ugly]
125
+ @buffer << "#{result}\n"
126
+
127
+ if close_tag
128
+ # We never get here if @options[:ugly] is true
129
+ @buffer << "#{tabs(tabulation-1)}</#{close_tag}>\n"
130
+ @real_tabs -= 1
131
+ end
132
+ end
133
+ nil
134
+ end
135
+
136
+ # Takes the various information about the opening tag for an
137
+ # element, formats it, and adds it to the buffer.
138
+ def open_tag(name, self_closing, try_one_line, preserve_tag, escape_html, class_id, obj_ref, content, *attributes_hashes)
139
+ tabulation = @real_tabs
140
+
141
+ attributes = class_id
142
+ attributes_hashes.each do |attributes_hash|
143
+ attributes_hash.keys.each { |key| attributes_hash[key.to_s] = attributes_hash.delete(key) }
144
+ self.class.merge_attrs(attributes, attributes_hash)
145
+ end
146
+ self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
147
+
148
+ if self_closing
149
+ str = " />\n"
150
+ elsif try_one_line || preserve_tag
151
+ str = ">"
152
+ else
153
+ str = ">\n"
154
+ end
155
+
156
+ attributes = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
157
+ @buffer << "#{@options[:ugly] ? '' : tabs(tabulation)}<#{name}#{attributes}#{str}"
158
+
159
+ if content
160
+ if @options[:ugly] || !content.include?("\n")
161
+ @buffer << "#{content}</#{name}>\n"
162
+ else
163
+ @buffer << "\n#{tabs(@real_tabs+1)}#{content}\n#{tabs(@real_tabs)}</#{name}>\n"
164
+ end
165
+ elsif !self_closing
166
+ @real_tabs += 1
167
+ end
168
+ end
169
+
170
+ def self.merge_attrs(to, from)
171
+ if to['id'] && from['id']
172
+ to['id'] << '_' << from.delete('id')
173
+ elsif to['id'] || from['id']
174
+ from['id'] ||= to['id']
175
+ end
176
+
177
+ if to['class'] && from['class']
178
+ # Make sure we don't duplicate class names
179
+ from['class'] = (from['class'].split(' ') | to['class'].split(' ')).join(' ')
180
+ elsif to['class'] || from['class']
181
+ from['class'] ||= to['class']
182
+ end
183
+
184
+ to.merge!(from)
185
+ end
186
+
187
+ private
188
+
189
+ # Some of these methods are exposed as public class methods
190
+ # so they can be re-used in helpers.
191
+
192
+ @@tab_cache = {}
193
+ # Gets <tt>count</tt> tabs. Mostly for internal use.
194
+ def tabs(count)
195
+ tabs = count + @tabulation
196
+ @@tab_cache[tabs] ||= ' ' * tabs
197
+ end
198
+
199
+ # Takes an array of objects and uses the class and id of the first
200
+ # one to create an attributes hash.
201
+ # The second object, if present, is used as a prefix,
202
+ # just like you can do with dom_id() and dom_class() in Rails
203
+ def parse_object_ref(ref)
204
+ prefix = ref[1]
205
+ ref = ref[0]
206
+ # Let's make sure the value isn't nil. If it is, return the default Hash.
207
+ return {} if ref.nil?
208
+ class_name = underscore(ref.class)
209
+ id = "#{class_name}_#{ref.id || 'new'}"
210
+ if prefix
211
+ class_name = "#{ prefix }_#{ class_name}"
212
+ id = "#{ prefix }_#{ id }"
213
+ end
214
+
215
+ {'id' => id, 'class' => class_name}
216
+ end
217
+
218
+ # Changes a word from camel case to underscores.
219
+ # Based on the method of the same name in Rails' Inflector,
220
+ # but copied here so it'll run properly without Rails.
221
+ def underscore(camel_cased_word)
222
+ camel_cased_word.to_s.gsub(/::/, '_').
223
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
224
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
225
+ tr("-", "_").
226
+ downcase
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,274 @@
1
+ require 'haml/helpers'
2
+ require 'haml/buffer'
3
+ require 'haml/precompiler'
4
+ require 'haml/filters'
5
+ require 'haml/error'
6
+
7
+ module Haml
8
+ # This is the class where all the parsing and processing of the Haml
9
+ # template is done. It can be directly used by the user by creating a
10
+ # new instance and calling <tt>to_html</tt> to render the template. For example:
11
+ #
12
+ # template = File.read('templates/really_cool_template.haml')
13
+ # haml_engine = Haml::Engine.new(template)
14
+ # output = haml_engine.to_html
15
+ # puts output
16
+ class Engine
17
+ include Precompiler
18
+
19
+ # Allow reading and writing of the options hash
20
+ attr :options, true
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
+
46
+ # Creates a new instace of Haml::Engine that will compile the given
47
+ # template string when <tt>render</tt> is called.
48
+ # See README.rdoc for available options.
49
+ #
50
+ #--
51
+ # When adding options, remember to add information about them
52
+ # to README.rdoc!
53
+ #++
54
+ #
55
+ def initialize(template, options = {})
56
+ @options = {
57
+ :suppress_eval => false,
58
+ :attr_wrapper => "'",
59
+
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],
63
+
64
+ :filters => {
65
+ 'sass' => Haml::Filters::Sass,
66
+ 'plain' => Haml::Filters::Plain,
67
+ 'javascript' => Haml::Filters::Javascript,
68
+ 'preserve' => Haml::Filters::Preserve,
69
+ 'redcloth' => Haml::Filters::RedCloth,
70
+ 'textile' => Haml::Filters::Textile,
71
+ 'markdown' => Haml::Filters::Markdown },
72
+ :filename => '(haml)',
73
+ :line => 1,
74
+ :ugly => false,
75
+ :format => :xhtml,
76
+ :escape_html => false
77
+ }
78
+ @options[:filters].merge! options.delete(:filters) if options[:filters]
79
+ @options.merge! options
80
+
81
+ unless [:xhtml, :html4, :html5].include?(@options[:format])
82
+ raise Haml::Error, "Invalid format #{@options[:format].inspect}"
83
+ end
84
+
85
+ unless @options[:suppress_eval]
86
+ @options[:filters].merge!({
87
+ 'erb' => Haml::Filters::ERB,
88
+ 'ruby' => Haml::Filters::Ruby
89
+ })
90
+ end
91
+
92
+ if @options[:locals]
93
+ warn <<END
94
+ DEPRECATION WARNING:
95
+ The Haml :locals option is deprecated and will be removed in version 2.0.
96
+ Use the locals option for Haml::Engine#render instead.
97
+ END
98
+ end
99
+
100
+ @template = template.rstrip #String
101
+ @to_close_stack = []
102
+ @output_tabs = 0
103
+ @template_tabs = 0
104
+ @index = 0
105
+ @flat_spaces = -1
106
+ @newlines = 0
107
+
108
+ precompile
109
+ rescue Haml::Error
110
+ $!.backtrace.unshift "#{@options[:filename]}:#{@index + $!.line_offset + @options[:line] - 1}" if @index
111
+ raise
112
+ end
113
+
114
+ # Processes the template and returns the result as a string.
115
+ #
116
+ # +scope+ is the context in which the template is evaluated.
117
+ # If it's a Binding or Proc object,
118
+ # Haml uses it as the second argument to Kernel#eval;
119
+ # otherwise, Haml just uses its #instance_eval context.
120
+ #
121
+ # Note that Haml modifies the evaluation context
122
+ # (either the scope object or the "self" object of the scope binding).
123
+ # It extends Haml::Helpers, and various instance variables are set
124
+ # (all prefixed with "haml").
125
+ # For example:
126
+ #
127
+ # s = "foobar"
128
+ # Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"
129
+ #
130
+ # # s now extends Haml::Helpers
131
+ # s.responds_to?(:html_attrs) #=> true
132
+ #
133
+ # +locals+ is a hash of local variables to make available to the template.
134
+ # For example:
135
+ #
136
+ # Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "<p>Hello, world!</p>"
137
+ #
138
+ # If a block is passed to render,
139
+ # that block is run when +yield+ is called
140
+ # within the template.
141
+ #
142
+ # Due to some Ruby quirks,
143
+ # if scope is a Binding or Proc object and a block is given,
144
+ # the evaluation context may not be quite what the user expects.
145
+ # In particular, it's equivalent to passing <tt>eval("self", scope)</tt> as scope.
146
+ # This won't have an effect in most cases,
147
+ # but if you're relying on local variables defined in the context of scope,
148
+ # they won't work.
149
+ def render(scope = Object.new, locals = {}, &block)
150
+ locals = (@options[:locals] || {}).merge(locals)
151
+ buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)
152
+
153
+ if scope.is_a?(Binding) || scope.is_a?(Proc)
154
+ scope_object = eval("self", scope)
155
+ scope = scope_object.instance_eval{binding} if block_given?
156
+ else
157
+ scope_object = scope
158
+ scope = scope_object.instance_eval{binding}
159
+ end
160
+
161
+ set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)
162
+
163
+ scope_object.instance_eval do
164
+ extend Haml::Helpers
165
+ @haml_buffer = buffer
166
+ end
167
+
168
+ eval(@precompiled, scope, @options[:filename], @options[:line])
169
+
170
+ # Get rid of the current buffer
171
+ scope_object.instance_eval do
172
+ @haml_buffer = buffer.upper
173
+ end
174
+
175
+ buffer.buffer
176
+ end
177
+ alias_method :to_html, :render
178
+
179
+ # Returns a proc that, when called,
180
+ # renders the template and returns the result as a string.
181
+ #
182
+ # +scope+ works the same as it does for render.
183
+ #
184
+ # The first argument of the returned proc is a hash of local variable names to values.
185
+ # However, due to an unfortunate Ruby quirk,
186
+ # the local variables which can be assigned must be pre-declared.
187
+ # This is done with the +local_names+ argument.
188
+ # For example:
189
+ #
190
+ # # This works
191
+ # Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!"
192
+ # #=> "<p>Hello!</p>"
193
+ #
194
+ # # This doesn't
195
+ # Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
196
+ # #=> NameError: undefined local variable or method `foo'
197
+ #
198
+ # The proc doesn't take a block;
199
+ # any yields in the template will fail.
200
+ def render_proc(scope = Object.new, *local_names)
201
+ if scope.is_a?(Binding) || scope.is_a?(Proc)
202
+ scope_object = eval("self", scope)
203
+ else
204
+ scope_object = scope
205
+ scope = scope_object.instance_eval{binding}
206
+ end
207
+
208
+ eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
209
+ precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
210
+ end
211
+
212
+ # Defines a method on +object+
213
+ # with the given name
214
+ # that renders the template and returns the result as a string.
215
+ #
216
+ # If +object+ is a class or module,
217
+ # the method will instead by defined as an instance method.
218
+ # For example:
219
+ #
220
+ # t = Time.now
221
+ # Haml::Engine.new("%p\n Today's date is\n .date= self.to_s").def_method(t, :render)
222
+ # t.render #=> "<p>\n Today's date is\n <div class='date'>Fri Nov 23 18:28:29 -0800 2007</div>\n</p>\n"
223
+ #
224
+ # Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
225
+ # "foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"
226
+ #
227
+ # The first argument of the defined method is a hash of local variable names to values.
228
+ # However, due to an unfortunate Ruby quirk,
229
+ # the local variables which can be assigned must be pre-declared.
230
+ # This is done with the +local_names+ argument.
231
+ # For example:
232
+ #
233
+ # # This works
234
+ # obj = Object.new
235
+ # Haml::Engine.new("%p= foo").def_method(obj, :render, :foo)
236
+ # obj.render(:foo => "Hello!") #=> "<p>Hello!</p>"
237
+ #
238
+ # # This doesn't
239
+ # obj = Object.new
240
+ # Haml::Engine.new("%p= foo").def_method(obj, :render)
241
+ # obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'
242
+ #
243
+ # Note that Haml modifies the evaluation context
244
+ # (either the scope object or the "self" object of the scope binding).
245
+ # It extends Haml::Helpers, and various instance variables are set
246
+ # (all prefixed with "haml").
247
+ def def_method(object, name, *local_names)
248
+ method = object.is_a?(Module) ? :module_eval : :instance_eval
249
+
250
+ object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
251
+ @options[:filename], @options[:line])
252
+ end
253
+
254
+ private
255
+
256
+ def set_locals(locals, scope, scope_object)
257
+ scope_object.send(:instance_variable_set, '@_haml_locals', locals)
258
+ set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
259
+ eval(set_locals, scope)
260
+ end
261
+
262
+ # Returns a hash of options that Haml::Buffer cares about.
263
+ # This should remain loadable from #inspect.
264
+ def options_for_buffer
265
+ {
266
+ :autoclose => @options[:autoclose],
267
+ :preserve => @options[:preserve],
268
+ :attr_wrapper => @options[:attr_wrapper],
269
+ :ugly => @options[:ugly],
270
+ :format => @options[:format]
271
+ }
272
+ end
273
+ end
274
+ end