zena 1.2.1 → 1.2.2

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 (202) hide show
  1. data/History.txt +38 -1
  2. data/app/controllers/documents_controller.rb +7 -5
  3. data/app/controllers/nodes_controller.rb +47 -6
  4. data/app/controllers/user_sessions_controller.rb +12 -3
  5. data/app/controllers/virtual_classes_controller.rb +8 -2
  6. data/app/models/acl.rb +5 -2
  7. data/app/models/cached_page.rb +5 -5
  8. data/app/models/column.rb +27 -4
  9. data/app/models/group.rb +1 -1
  10. data/app/models/node.rb +106 -24
  11. data/app/models/note.rb +2 -1
  12. data/app/models/relation.rb +9 -4
  13. data/app/models/relation_proxy.rb +2 -2
  14. data/app/models/role.rb +12 -5
  15. data/app/models/site.rb +10 -9
  16. data/app/models/skin.rb +8 -0
  17. data/app/models/string_hash.rb +65 -0
  18. data/app/models/text_document.rb +1 -1
  19. data/app/models/user.rb +2 -0
  20. data/app/models/virtual_class.rb +43 -10
  21. data/app/views/comments/create.rjs +1 -32
  22. data/app/views/comments/edit.rjs +1 -1
  23. data/app/views/comments/update.rjs +1 -1
  24. data/app/views/documents/show.rhtml +1 -1
  25. data/app/views/groups/_form.rhtml +7 -0
  26. data/app/views/groups/_li.rhtml +1 -1
  27. data/app/views/nodes/500.html +2 -1
  28. data/app/views/nodes/destroy.rjs +2 -0
  29. data/app/views/sites/jobs.erb +2 -3
  30. data/app/views/templates/document_create_tabs/_file.rhtml +1 -1
  31. data/app/views/templates/document_create_tabs/_import.rhtml +4 -1
  32. data/app/views/templates/document_create_tabs/_template.rhtml +3 -0
  33. data/app/views/templates/document_create_tabs/_text_document.rhtml +3 -0
  34. data/app/views/versions/custom_tab.rhtml +1 -1
  35. data/app/views/versions/edit.rhtml +1 -1
  36. data/bricks/acls/lib/bricks/acls.rb +3 -3
  37. data/bricks/acls/zena/test/unit/acl_test.rb +15 -0
  38. data/bricks/fs_skin/lib/bricks/fs_skin.rb +190 -0
  39. data/bricks/fs_skin/zena/init.rb +1 -0
  40. data/bricks/fs_skin/zena/migrate/20110702010330_add_fs_skin_to_idx_templates.rb +12 -0
  41. data/bricks/{static → fs_skin}/zena/skins/blog/Image-edit.zafu +0 -0
  42. data/bricks/{static → fs_skin}/zena/skins/blog/Image.zafu +0 -0
  43. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+index.zafu +0 -0
  44. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+notFound.zafu +0 -0
  45. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+search.zafu +0 -0
  46. data/bricks/{static → fs_skin}/zena/skins/blog/Node.zafu +1 -1
  47. data/bricks/{static → fs_skin}/zena/skins/blog/Post.zafu +0 -0
  48. data/bricks/{static → fs_skin}/zena/skins/blog/Project--kml.zafu +0 -0
  49. data/bricks/{static → fs_skin}/zena/skins/blog/Project.zafu +0 -0
  50. data/bricks/{static → fs_skin}/zena/skins/blog/comments.zafu +0 -0
  51. data/bricks/{static → fs_skin}/zena/skins/blog/dict.yml +0 -0
  52. data/bricks/{static → fs_skin}/zena/skins/blog/img/dateBg.jpg +0 -0
  53. data/bricks/{static → fs_skin}/zena/skins/blog/img/header.png +0 -0
  54. data/bricks/{static → fs_skin}/zena/skins/blog/img/mapPin.png +0 -0
  55. data/bricks/{static → fs_skin}/zena/skins/blog/img/menu.gif +0 -0
  56. data/bricks/{static → fs_skin}/zena/skins/blog/img/menuover.gif +0 -0
  57. data/bricks/{static → fs_skin}/zena/skins/blog/img/style.css +0 -0
  58. data/bricks/fs_skin/zena/tasks.rb +26 -0
  59. data/bricks/{static/zena/test/integration/static_integration_test.rb → fs_skin/zena/test/integration/fs_skin_integration_test.rb} +6 -6
  60. data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +33 -0
  61. data/bricks/grid/lib/bricks/grid.rb +4 -3
  62. data/bricks/tags/lib/bricks/tags.rb +1 -7
  63. data/bricks/zena/zena/migrate/20120605091558_add_ssl_login_to_site.rb +7 -0
  64. data/bricks/zena/zena/migrate/20120630123551_add_auto_publish_to_group.rb +9 -0
  65. data/config/bricks.yml +3 -3
  66. data/config/gems.yml +2 -3
  67. data/lib/tasks/zena.rake +7 -3
  68. data/lib/zafu.rb +7 -0
  69. data/lib/zafu/all.rb +21 -0
  70. data/lib/zafu/compiler.rb +7 -0
  71. data/lib/zafu/controller_methods.rb +58 -0
  72. data/lib/zafu/handler.rb +57 -0
  73. data/lib/zafu/info.rb +4 -0
  74. data/lib/zafu/markup.rb +309 -0
  75. data/lib/zafu/mock_helper.rb +42 -0
  76. data/lib/zafu/node_context.rb +203 -0
  77. data/lib/zafu/ordered_hash.rb +53 -0
  78. data/lib/zafu/parser.rb +676 -0
  79. data/lib/zafu/parsing_rules.rb +382 -0
  80. data/lib/zafu/process/ajax.rb +530 -0
  81. data/lib/zafu/process/conditional.rb +92 -0
  82. data/lib/zafu/process/context.rb +186 -0
  83. data/lib/zafu/process/forms.rb +143 -0
  84. data/lib/zafu/process/html.rb +186 -0
  85. data/lib/zafu/process/ruby_less_processing.rb +321 -0
  86. data/lib/zafu/security.rb +15 -0
  87. data/lib/zafu/template.rb +25 -0
  88. data/lib/zafu/test_helper.rb +19 -0
  89. data/lib/zafu/view_methods.rb +6 -0
  90. data/lib/zena.rb +1 -1
  91. data/lib/zena/acts/enrollable.rb +1 -1
  92. data/lib/zena/app.rb +4 -17
  93. data/lib/zena/console.rb +18 -1
  94. data/lib/zena/core_ext/file_utils.rb +13 -1
  95. data/lib/zena/core_ext/fixnum.rb +4 -0
  96. data/lib/zena/core_ext/float.rb +7 -0
  97. data/lib/zena/deploy.rb +4 -2
  98. data/lib/zena/deploy/app_init.rhtml +2 -1
  99. data/lib/zena/deploy/database.rhtml +1 -1
  100. data/lib/zena/info.rb +1 -1
  101. data/lib/zena/parser/zazen_rules.rb +4 -4
  102. data/lib/zena/routes.rb +1 -1
  103. data/lib/zena/test_controller.rb +1 -1
  104. data/lib/zena/use.rb +14 -1
  105. data/lib/zena/use/action.rb +4 -2
  106. data/lib/zena/use/ajax.rb +86 -38
  107. data/lib/zena/use/authlogic.rb +16 -1
  108. data/lib/zena/use/calendar.rb +37 -17
  109. data/lib/zena/use/conditional.rb +2 -2
  110. data/lib/zena/use/context.rb +30 -9
  111. data/lib/zena/use/dates.rb +39 -3
  112. data/lib/zena/use/display.rb +6 -19
  113. data/lib/zena/use/forms.rb +100 -79
  114. data/lib/zena/use/i18n.rb +40 -16
  115. data/lib/zena/use/query_builder.rb +0 -6
  116. data/lib/zena/use/query_node.rb +17 -4
  117. data/lib/zena/use/relations.rb +1 -3
  118. data/lib/zena/use/rendering.rb +10 -8
  119. data/lib/zena/use/scope_index.rb +5 -1
  120. data/lib/zena/use/search.rb +2 -1
  121. data/lib/zena/use/urls.rb +82 -77
  122. data/lib/zena/use/workflow.rb +12 -4
  123. data/lib/zena/use/zafu_safe_definitions.rb +37 -9
  124. data/lib/zena/use/zafu_templates.rb +49 -20
  125. data/lib/zena/use/zazen.rb +6 -2
  126. data/locale/it/LC_MESSAGES/zena.mo +0 -0
  127. data/locale/it/zena.mo +0 -0
  128. data/locale/it/zena.po +1982 -0
  129. data/public/images/arrow_back.png +0 -0
  130. data/public/images/remove_tag.png +0 -0
  131. data/public/javascripts/grid.js +800 -199
  132. data/public/javascripts/window.js +1 -1
  133. data/public/javascripts/zena.js +130 -21
  134. data/public/stylesheets/grid.css +11 -2
  135. data/public/stylesheets/zena.css +2 -1
  136. data/test/custom_queries/complex.host.yml +5 -0
  137. data/test/fixtures/files/TestNode.zafu +36 -0
  138. data/test/functional/nodes_controller_test.rb +18 -1
  139. data/test/integration/zafu_compiler/action.yml +2 -2
  140. data/test/integration/zafu_compiler/ajax.yml +44 -26
  141. data/test/integration/zafu_compiler/asset.yml +12 -2
  142. data/test/integration/zafu_compiler/basic.yml +0 -16
  143. data/test/integration/zafu_compiler/calendar.yml +6 -6
  144. data/test/integration/zafu_compiler/complex_ok.yml +23 -1
  145. data/test/integration/zafu_compiler/conditional.yml +5 -5
  146. data/test/integration/zafu_compiler/context.yml +6 -5
  147. data/test/integration/zafu_compiler/dates.yml +23 -2
  148. data/test/integration/zafu_compiler/display.yml +46 -2
  149. data/test/integration/zafu_compiler/errors.yml +2 -2
  150. data/test/integration/zafu_compiler/eval.yml +35 -7
  151. data/test/integration/zafu_compiler/forms.yml +47 -13
  152. data/test/integration/zafu_compiler/i18n.yml +2 -2
  153. data/test/integration/zafu_compiler/meta.yml +35 -1
  154. data/test/integration/zafu_compiler/query.yml +23 -4
  155. data/test/integration/zafu_compiler/relations.yml +10 -6
  156. data/test/integration/zafu_compiler/roles.yml +4 -4
  157. data/test/integration/zafu_compiler/rubyless.yml +11 -1
  158. data/test/integration/zafu_compiler/safe_definitions.yml +23 -5
  159. data/test/integration/zafu_compiler/security.yml +10 -6
  160. data/test/integration/zafu_compiler/urls.yml +23 -6
  161. data/test/integration/zafu_compiler/zafu_attributes.yml +1 -1
  162. data/test/integration/zafu_compiler/zazen.yml +14 -0
  163. data/test/selenium/Add/add3.rsel +8 -8
  164. data/test/selenium/Destroy/0setup.rsel +12 -0
  165. data/test/selenium/Destroy/destroy1.rsel +16 -0
  166. data/test/selenium/Edit/edit2.rsel +9 -9
  167. data/test/selenium/Edit/edit5.rsel +9 -9
  168. data/test/selenium/Edit/edit6.rsel +9 -9
  169. data/test/selenium/Form/form4.rsel +17 -0
  170. data/test/selenium/Toggle/toggle1.rsel +2 -0
  171. data/test/selenium/Toggle/toggle2.rsel +18 -0
  172. data/test/sites/zena/columns.yml +3 -0
  173. data/test/sites/zena/versions.yml +7 -0
  174. data/test/unit/cached_page_test.rb +13 -13
  175. data/test/unit/column_test.rb +26 -0
  176. data/test/unit/node_test.rb +16 -1
  177. data/test/unit/project_test.rb +6 -1
  178. data/test/unit/relation_test.rb +1 -1
  179. data/test/unit/role_test.rb +1 -1
  180. data/test/unit/string_hash_test.rb +30 -0
  181. data/test/unit/virtual_class_test.rb +31 -17
  182. data/test/unit/zafu_markup_test.rb +414 -0
  183. data/test/unit/zafu_node_context_test.rb +375 -0
  184. data/test/unit/zafu_ordered_hash_test.rb +69 -0
  185. data/test/unit/zena/acts/enrollable_test.rb +1 -1
  186. data/test/unit/zena/parser/zafu_asset.yml +0 -10
  187. data/test/unit/zena/parser/zazen.yml +1 -1
  188. data/test/unit/zena/parser_test.rb +1 -72
  189. data/test/unit/zena/use/dates_test.rb +1 -1
  190. data/test/unit/zena/use/rendering_test.rb +24 -7
  191. data/test/unit/zena/use/scope_index_test.rb +17 -0
  192. data/test/unit/zena/use/zazen_test.rb +2 -1
  193. data/zena.gemspec +71 -37
  194. metadata +104 -83
  195. data/app/views/nodes/destroy.erb +0 -0
  196. data/bricks/static/lib/bricks/static.rb +0 -151
  197. data/bricks/static/zena/init.rb +0 -1
  198. data/bricks/static/zena/migrate/20110702010330_add_static_to_idx_templates.rb +0 -12
  199. data/bricks/static/zena/test/unit/static_test.rb +0 -33
  200. data/lib/zena/parser/zafu_rules.rb +0 -244
  201. data/lib/zena/parser/zafu_tags.rb +0 -198
  202. data/lib/zena/parser/zena_rules.rb +0 -23
@@ -0,0 +1,321 @@
1
+ require 'rubyless'
2
+
3
+ module Zafu
4
+ module Process
5
+ module RubyLessProcessing
6
+ include RubyLess
7
+
8
+ def self.included(base)
9
+ base.process_unknown :rubyless_eval
10
+
11
+ base.class_eval do
12
+ def do_method(sym)
13
+ super
14
+ rescue RubyLess::Error => err
15
+ parser_error(err.message)
16
+ end
17
+ end
18
+ end
19
+
20
+ # Actual method resolution. The lookup first starts in the current helper. If nothing is found there, it
21
+ # searches inside a 'helpers' module and finally looks into the current node_context.
22
+ # If nothing is found at this stage, we prepend the method with the current node and start over again.
23
+ def safe_method_type(signature, receiver = nil)
24
+ super || get_method_type(signature, false)
25
+ end
26
+
27
+ # Resolve unknown methods by using RubyLess in the current compilation context (the
28
+ # translate method in RubyLess will call 'safe_method_type' in this module).
29
+ def rubyless_eval(params = @params)
30
+ if @method =~ /^([A-Z]\w+?)\?$/
31
+ return rubyless_class_scope($1)
32
+ end
33
+
34
+ rubyless_render(@method, params)
35
+ rescue RubyLess::NoMethodError => err
36
+ parser_continue("#{err.error_message} <span class='type'>#{err.method_with_arguments}</span> (#{node.klass} context)")
37
+ rescue RubyLess::Error => err
38
+ parser_continue(err.message)
39
+ end
40
+
41
+ # Print documentation on the current node type.
42
+ def r_m
43
+ if @params[:helper] == 'true'
44
+ klass = helper.class
45
+ else
46
+ klass = node.klass
47
+ end
48
+
49
+ out "<div class='rubyless-m'><h3>Documentation for <b>#{klass}</b></h3>"
50
+ out "<ul>"
51
+ RubyLess::SafeClass.safe_methods_for(klass).each do |signature, opts|
52
+ opts = opts.dup
53
+ opts.delete(:method)
54
+ if opts.keys == [:class]
55
+ opts = opts[:class]
56
+ end
57
+ out "<li>#{signature.inspect} => #{opts.inspect}</li>"
58
+ end
59
+ out "</ul></div>"
60
+ end
61
+
62
+ # TEMPORARY METHOD DURING HACKING...
63
+ # def r_erb
64
+ # "<pre><%= @erb.gsub('<','&lt;').gsub('>','&gt;') %></pre>"
65
+ # end
66
+
67
+ def rubyless_render(method, params)
68
+ # We need to set this here because we cannot pass options to RubyLess or get them back
69
+ # when we evaluate the method to see if we can use blocks as arguments.
70
+ @rendering_block_owner = true
71
+ code = method_with_arguments(method, params)
72
+ # It is strange that we need to freeze code... But if we don't, we
73
+ # get double ##{} on some systems (Linux).
74
+ rubyless_expand RubyLess.translate(self, code.freeze)
75
+ ensure
76
+ @rendering_block_owner = false
77
+ end
78
+
79
+ def set_markup_attr(markup, key, value)
80
+ value = value.kind_of?(RubyLess::TypedString) ? value : RubyLess.translate_string(self, value)
81
+ if value.literal
82
+ markup.set_param(key, form_quote(value.literal))
83
+ else
84
+ markup.set_dyn_param(key, "<%= #{value} %>")
85
+ end
86
+ end
87
+
88
+ def append_markup_attr(markup, key, value)
89
+ value = RubyLess.translate_string(self, value)
90
+ if value.literal
91
+ markup.append_param(key, form_quote(value.literal))
92
+ else
93
+ markup.append_dyn_param(key, "<%= #{value} %>")
94
+ end
95
+ end
96
+
97
+ def get_attribute_or_eval(use_string_block = true)
98
+ if @params[:date] && method != 'link'
99
+ return parser_continue("'date' parameter is deprecated. Please use 'attr' or 'eval'.")
100
+ elsif attribute = @params[:attr]
101
+ code = "this.#{attribute}"
102
+ elsif code = @params[:eval] || @params[:test]
103
+ elsif code = @params[:param]
104
+ code = "params[:#{code}]"
105
+ elsif text = @params[:text]
106
+ code = "%Q{#{text}}"
107
+ elsif text = @params[:t]
108
+ code = "t(%Q{#{text}})"
109
+ # elsif var = @params[:var]
110
+ # if code = get_context_var('set_var', var)
111
+ # return code
112
+ # else
113
+ # return parser_continue("Var #{var.inspect} not declared.")
114
+ # end
115
+ elsif use_string_block && @blocks.size == 1 && @blocks.first.kind_of?(String)
116
+ return RubyLess::TypedString.new(@blocks.first.inspect, :class => String, :literal => @blocks.first)
117
+ else
118
+ return parser_continue("Missing attribute/eval parameter")
119
+ end
120
+
121
+ RubyLess.translate(self, code)
122
+ rescue RubyLess::Error => err
123
+ return parser_continue(err.message, code)
124
+ end
125
+
126
+ # Pass default values as parameters in @context as :param_XXXX
127
+ def r_default
128
+ cont = {}
129
+ @params.each do |k, v|
130
+ cont[:"params_#{k}"] = v
131
+ end
132
+ expand_with cont
133
+ end
134
+
135
+ private
136
+ # Extract arguments from params (evaluates params as RubyLess strings).
137
+ def extract_from_params(*keys)
138
+ res = []
139
+
140
+ keys.each do |key|
141
+ next unless value = param(key.to_sym)
142
+ res << ":#{key} => #{RubyLess.translate_string(self, value)}"
143
+ end
144
+
145
+ res.empty? ? nil : res
146
+ end
147
+
148
+ def param(key, default = nil)
149
+ @params[key] || @context[:"params_#{key}"] || default
150
+ end
151
+
152
+ # Method resolution. The first matching method is returned. Order of evaluation is
153
+ # 1. find node_context (@page, @image, self)
154
+ # 2. set var (set_xxx = '...')
155
+ # 3. template helper methods
156
+ # 4. contextual node methods (var1.xxx)
157
+ # 5. contextual first node of list method ([...].first.xxx)
158
+ # 6. append block as argument (restart 1-5 with xxx(block_string))
159
+ def get_method_type(signature, added_options = false)
160
+ node = self.node
161
+
162
+ if type = node_context_from_signature(signature)
163
+ # Resolve this, @page, @node
164
+ type
165
+ elsif type = get_var_from_signature(signature)
166
+ # Resolved stored set_xxx='something' in context.
167
+ type
168
+ elsif type = safe_method_from(helper, signature)
169
+ # Resolve template helper methods
170
+ type
171
+ elsif helper.respond_to?(:helpers) && type = safe_method_from(helper.helpers, signature)
172
+ # Resolve by looking at the included helpers
173
+ type
174
+ elsif node && !node.list_context? && type = safe_method_from(node.klass, signature, node)
175
+ # not a list_contex
176
+ # Resolve node context methods: xxx.foo, xxx.bar
177
+ # All direct methods from nodes should be html escaped:
178
+ type = type[:class].call(self, node.klass, signature) if type[:class].kind_of?(Proc)
179
+ type.merge(:receiver => RubyLess::TypedString.new(node.name, :class => node.klass, :h => true))
180
+ elsif node && node.list_context? && type = safe_method_from(Array, signature, node)
181
+ # FIXME: why do we need this here ? Remove with related code in zafu_safe_definitions ?
182
+ type = type[:class].call(self, node.klass, signature) if type[:class].kind_of?(Proc)
183
+ type.merge(:receiver => RubyLess::TypedString.new(node.name, :class => Array, :elem => node.klass.first))
184
+ elsif node && node.list_context? && type = safe_method_from(node.klass.first, signature, node)
185
+ type = type[:class].call(self, node.klass, signature) if type[:class].kind_of?(Proc)
186
+ type.merge(:receiver => RubyLess::TypedString.new("#{node.name}.first", :class => node.klass.first, :h => true))
187
+ elsif @rendering_block_owner && @blocks.first.kind_of?(String) && !added_options
188
+ # Insert the block content into the method: <r:trans>blah</r:trans> becomes trans("blah")
189
+ signature_with_block = signature.dup
190
+ signature_with_block << String
191
+ if type = get_method_type(signature_with_block, true)
192
+ type.merge(:prepend_args => RubyLess::TypedString.new(@blocks.first.inspect, :class => String, :literal => @blocks.first))
193
+ else
194
+ nil
195
+ end
196
+ elsif node && !added_options
197
+ # Try prepending current node before arguments: link("foo") becomes link(var1, "foo")
198
+ signature_with_node = signature.dup
199
+ signature_with_node.insert(1, node.real_class) # node.klass ?
200
+ if type = get_method_type(signature_with_node, true)
201
+ type.merge(:prepend_args => RubyLess::TypedString.new(node.name, :class => node.klass))
202
+ else
203
+ nil
204
+ end
205
+ else
206
+ nil
207
+ end
208
+ end
209
+
210
+ def method_with_arguments(method, params)
211
+ hash_arguments = []
212
+ arguments = []
213
+ params.keys.sort {|a,b| a.to_s <=> b.to_s}.each do |k|
214
+ if k =~ /\A_/
215
+ arguments << "%Q{#{params[k]}}"
216
+ else
217
+ hash_arguments << ":#{k} => %Q{#{params[k]}}"
218
+ end
219
+ end
220
+
221
+ if hash_arguments != []
222
+ arguments << hash_arguments.join(', ')
223
+ end
224
+
225
+ if arguments != []
226
+ if method =~ /^(.*)\((.*)\)$/
227
+ if $2 == ''
228
+ "#{$1}(#{arguments.join(', ')})"
229
+ else
230
+ "#{$1}(#{$2}, #{arguments.join(', ')})"
231
+ end
232
+ else
233
+ "#{method}(#{arguments.join(', ')})"
234
+ end
235
+ else
236
+ method
237
+ end
238
+ end
239
+
240
+ def rubyless_expand(res)
241
+ if res.klass == String && !@blocks.detect {|b| !b.kind_of?(String)}
242
+ if lit = res.literal
243
+ out erb_escape(lit)
244
+ # TODO: Enable this when we have time to ensure tests/functionality work correctly.
245
+ #elsif res.opts[:h]
246
+ # show_string(res)
247
+ else
248
+ out "<%= #{res} %>"
249
+ end
250
+ elsif res.klass == Boolean
251
+ expand_if(res)
252
+ elsif @blocks.empty?
253
+ out "<%= #{res} %>"
254
+ else
255
+ expand_with_finder(:method => res, :class => res.klass, :query => res.opts[:query], :nil => res.could_be_nil?)
256
+ end
257
+ end
258
+
259
+ def rubyless_class_scope(class_name)
260
+ return parser_error("Cannot scope class in list (use each before filtering).") if node.list_context?
261
+
262
+ # capital letter ==> class conditional
263
+ klass = Module.const_get(class_name)
264
+ if klass.ancestors.include?(node.klass)
265
+ expand_if("#{node}.kind_of?(#{klass})")
266
+ else
267
+ # render nothing: incompatible classes
268
+ ''
269
+ end
270
+ rescue
271
+ parser_error("Invalid class name '#{class_name}'")
272
+ end
273
+
274
+ # Find a class or behavior based on a name. The returned class should implement
275
+ # 'safe_method_type'.
276
+ def get_class(class_name)
277
+ Module.const_get(class_name)
278
+ rescue
279
+ nil
280
+ end
281
+
282
+ # This is used to resolve 'this' (current NodeContext), '@node' as NodeContext with class Node,
283
+ # '@page' as first NodeContext of type Page, etc.
284
+ def node_context_from_signature(signature)
285
+ return nil unless signature.size == 1
286
+ ivar = signature.first
287
+ if ivar == 'this'
288
+ node.opts.merge(:class => node.klass, :method => node.name)
289
+ elsif ivar[0..0] == '@' && klass = get_class(ivar[1..-1].capitalize)
290
+ if node = self.node(klass)
291
+ node.opts.merge(:class => node.klass, :method => node.name)
292
+ else
293
+ nil
294
+ end
295
+ else
296
+ nil
297
+ end
298
+ end
299
+
300
+ # Find stored variables back. Stored elements are set with set_xxx='something to eval'.
301
+ def get_var_from_signature(signature)
302
+ return nil unless signature.size == 1
303
+ if var = get_context_var('set_var', signature.first)
304
+ {:method => var, :class => var.klass, :nil => var.could_be_nil?, :query => var.opts[:query]}
305
+ else
306
+ nil
307
+ end
308
+ end
309
+
310
+ def safe_method_from(solver, signature, receiver = nil)
311
+
312
+ if solver.respond_to?(:safe_method_type)
313
+ solver.safe_method_type(signature, receiver)
314
+ else
315
+ RubyLess::SafeClass.safe_method_type_for(solver, signature)
316
+ end
317
+ end
318
+
319
+ end # RubyLessProcessing
320
+ end # Process
321
+ end # Zafu
@@ -0,0 +1,15 @@
1
+ module Zafu
2
+ module Security
3
+ SECURE_REGEXP = %r{<%|%>|<\Z}
4
+ SAFE_CODE = {'<%' => '&lt;%', '%>' => '%&gt;', '<' => '&lt;'}
5
+ # Make sure translations and other literal values cannot be used to build erb.
6
+ def erb_escape(text)
7
+ # Do not only replace '<%' ! or <r:t>min</r:t>% ==> <% ...
8
+ text.gsub(SECURE_REGEXP) {|code| SAFE_CODE[code]}
9
+ end
10
+
11
+ def form_quote(text)
12
+ erb_escape(text).gsub("'", "&apos;")
13
+ end
14
+ end # Security
15
+ end # Zafu
@@ -0,0 +1,25 @@
1
+ require 'zafu/compiler'
2
+
3
+ module Zafu
4
+ class Template
5
+ def initialize(template, src_helper = nil, compiler = Zafu::Compiler)
6
+ if template.kind_of?(String)
7
+ @ast = compiler.new(template)
8
+ else
9
+ @ast = compiler.new_with_url(template.path, :helper => src_helper)
10
+ end
11
+ end
12
+
13
+ def to_erb(context = {})
14
+ @ast.to_erb(context)
15
+ end
16
+
17
+ def to_ruby(context = {})
18
+ src = ::ERB.new("<% __in_erb_template=true %>#{to_erb(context)}", nil, '-').src
19
+
20
+ # Ruby 1.9 prepends an encoding to the source. However this is
21
+ # useless because you can only set an encoding on the first line
22
+ RUBY_VERSION >= '1.9' ? src.sub(/\A#coding:.*\n/, '') : src
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require 'zafu/template'
2
+
3
+ module Zafu
4
+ module TestHelper
5
+ include RubyLess::SafeClass
6
+
7
+ def zafu_erb(source, src_helper = self, compiler = Zafu::Compiler)
8
+ Zafu::Template.new(source, src_helper, compiler).to_erb(compilation_context)
9
+ end
10
+
11
+ def zafu_render(source, src_helper = self, compiler = Zafu::Compiler)
12
+ eval Zafu::Template.new(source, src_helper, compiler).to_ruby(compilation_context)
13
+ end
14
+
15
+ def compilation_context
16
+ {:node => @node_context, :helper => self}
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ require 'zafu/controller_methods'
2
+ module Zafu
3
+ module ViewMethods
4
+ include Zafu::ControllerMethods::Common
5
+ end
6
+ end
@@ -222,7 +222,7 @@ module Zena
222
222
  def init
223
223
  config = Rails.configuration
224
224
  enable_tools
225
- puts "** zena #{Zena::VERSION} starting (c) Gaspard Bucher 2011"
225
+ puts "** zena #{Zena::VERSION} starting (c) Gaspard Bucher 2012"
226
226
  puts "** Bricks: #{Bricks::CONFIG.map{|k,v| k}.sort.join(', ')}"
227
227
 
228
228
  add_load_paths(config)
@@ -101,7 +101,7 @@ module Zena
101
101
  next unless role.class == Role && role.id
102
102
  role_ids << role.id if role.column_names & keys != []
103
103
  end
104
-
104
+
105
105
  prop['cached_role_ids'] = role_ids
106
106
  end
107
107
 
@@ -55,24 +55,11 @@ module Zena
55
55
  end
56
56
  Bricks.apply_patches('application_controller.rb')
57
57
  Bricks.apply_patches('application_helper.rb')
58
-
59
- ::User.class_eval do
60
- Zena::Use.each_module_for('User') do |mod|
61
- include mod
62
- end
63
- end
64
-
65
- ::Site.class_eval do
66
- Zena::Use.each_module_for('Site') do |mod|
67
- include mod
68
- end
69
- end
70
58
 
71
- ::Skin.class_eval do
72
- Zena::Use.each_module_for('Skin') do |mod|
73
- include mod
74
- end
75
- end
59
+ Zena::Use.upgrade_class('User')
60
+ Zena::Use.upgrade_class('Site')
61
+ Zena::Use.upgrade_class('Skin')
62
+
76
63
  end
77
64
  end
78
65
  end
@@ -195,7 +195,9 @@ module Zena
195
195
  page_count = (count.to_f / limit).ceil
196
196
  puts "#{count} nodes, #{page_count} chunk(s) (100 items)"
197
197
  curr_page = 1
198
- for curr_page in (1..page_count)
198
+ # We walk pages in reverse order in case objects are deleted
199
+
200
+ for curr_page in (1..page_count).to_a.reverse
199
201
  query.offset = " OFFSET #{limit * (curr_page - 1)}"
200
202
  if list = Node.do_find(:all, eval(query.to_s(:find)))
201
203
  puts "Page #{curr_page}/#{page_count}"
@@ -206,5 +208,20 @@ module Zena
206
208
  end
207
209
  nil
208
210
  end
211
+
212
+ def profile(node_id)
213
+ require 'ruby-prof'
214
+ ctrl = NodesController.new
215
+ ctrl.request = Struct.new(:format).new(Mime::HTML)
216
+ ctrl.instance_variable_set(:@node, nodes(node_id))
217
+ start = Time.now
218
+ result = RubyProf.profile do
219
+ yield(ctrl)
220
+ end
221
+ puts(Time.now - start)
222
+ File.open('grind.log', 'wb') do |f|
223
+ RubyProf::CallTreePrinter.new(result).print(f)
224
+ end
225
+ end
209
226
  end # Console
210
227
  end # Zena