zena 1.2.4 → 1.2.5

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 (104) hide show
  1. data/History.txt +18 -0
  2. data/app/controllers/nodes_controller.rb +11 -6
  3. data/app/controllers/sites_controller.rb +3 -2
  4. data/app/controllers/user_sessions_controller.rb +1 -1
  5. data/app/controllers/virtual_classes_controller.rb +3 -2
  6. data/app/models/document.rb +2 -2
  7. data/app/models/node.rb +6 -1
  8. data/app/models/note.rb +3 -27
  9. data/app/models/role.rb +11 -5
  10. data/app/models/site.rb +140 -43
  11. data/app/models/string_hash.rb +2 -0
  12. data/app/models/user.rb +9 -4
  13. data/app/models/user_session.rb +1 -1
  14. data/app/models/virtual_class.rb +49 -18
  15. data/app/views/sites/_form.erb +7 -4
  16. data/app/views/sites/_li.erb +15 -9
  17. data/app/views/users/_li.rhtml +3 -0
  18. data/app/views/users/index.rhtml +1 -1
  19. data/app/views/virtual_classes/_form.erb +1 -1
  20. data/bricks/acls/zena/init.rb +1 -2
  21. data/bricks/acls/zena/test/sites/erebus/roles.yml +4 -0
  22. data/bricks/activity/lib/bricks/activity.rb +24 -0
  23. data/bricks/activity/zena/migrate/20130711135905_add_activity_to_user.rb +9 -0
  24. data/bricks/activity/zena/test/integration/activity_integration_test.rb +29 -0
  25. data/bricks/captcha/zena/init.rb +0 -3
  26. data/bricks/fs_skin/lib/bricks/fs_skin.rb +3 -3
  27. data/bricks/fs_skin/zena/skins/blog/Node.zafu +1 -1
  28. data/bricks/fs_skin/zena/tasks.rb +2 -2
  29. data/bricks/fs_skin/zena/test/integration/fs_skin_integration_test.rb +2 -2
  30. data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +1 -1
  31. data/bricks/math/zena/init.rb +0 -3
  32. data/bricks/pdf/zena/init.rb +1 -5
  33. data/bricks/worker/zena/init.rb +0 -2
  34. data/bricks/zena/zena/migrate/20130617164527_add_master_id_to_site.rb +13 -0
  35. data/bricks/zena/zena/migrate/20130712081512_alter_login_users.rb +9 -0
  36. data/config/bricks.yml +4 -1
  37. data/lib/bricks/loader.rb +17 -9
  38. data/lib/tasks/zena.rake +40 -5
  39. data/lib/zafu/process/ruby_less_processing.rb +3 -5
  40. data/lib/zena.rb +2 -0
  41. data/lib/zena/acts/secure.rb +11 -2
  42. data/lib/zena/console.rb +5 -4
  43. data/lib/zena/core_ext/string.rb +2 -2
  44. data/lib/zena/deploy.rb +22 -6
  45. data/lib/zena/deploy/logrotate_app.rhtml +10 -7
  46. data/lib/zena/deploy/logrotate_host.rhtml +21 -26
  47. data/lib/zena/deploy/vhost.rhtml +3 -3
  48. data/lib/zena/foxy_parser.rb +1 -1
  49. data/lib/zena/info.rb +1 -1
  50. data/lib/zena/site_worker.rb +2 -2
  51. data/lib/zena/use.rb +0 -1
  52. data/lib/zena/use/ancestry.rb +1 -1
  53. data/lib/zena/use/authlogic.rb +2 -1
  54. data/lib/zena/use/display.rb +6 -0
  55. data/lib/zena/use/query_builder.rb +1 -1
  56. data/lib/zena/use/query_node.rb +3 -3
  57. data/lib/zena/use/rendering.rb +47 -13
  58. data/lib/zena/use/test_helper.rb +1 -1
  59. data/lib/zena/use/urls.rb +6 -104
  60. data/lib/zena/use/zafu_safe_definitions.rb +9 -4
  61. data/lib/zena/use/zafu_templates.rb +1 -0
  62. data/locale/app.pot +4 -0
  63. data/locale/de/LC_MESSAGES/zena.mo +0 -0
  64. data/locale/de/zena.po +6 -2
  65. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  66. data/locale/en/zena.po +6 -2
  67. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  68. data/locale/fr/zena.po +5 -1
  69. data/locale/it/LC_MESSAGES/zena.mo +0 -0
  70. data/locale/it/zena.po +6 -2
  71. data/locale/zena.pot +4 -0
  72. data/test/functional/nodes_controller_test.rb +2 -133
  73. data/test/functional/sites_controller_test.rb +1 -1
  74. data/test/integration/multiple_hosts_test.rb +2 -1
  75. data/test/integration/navigation_test.rb +37 -0
  76. data/test/integration/query_node/basic.yml +1 -1
  77. data/test/integration/zafu_compiler/ajax.yml +7 -0
  78. data/test/integration/zafu_compiler/comments.yml +2 -2
  79. data/test/integration/zafu_compiler/context.yml +6 -2
  80. data/test/integration/zafu_compiler/display.yml +16 -4
  81. data/test/integration/zafu_compiler/forms.yml +1 -0
  82. data/test/integration/zafu_compiler/query.yml +7 -1
  83. data/test/integration/zafu_compiler/relations.yml +12 -7
  84. data/test/integration/zafu_compiler/roles.yml +3 -3
  85. data/test/integration/zafu_compiler/rubyless.yml +1 -2
  86. data/test/integration/zafu_compiler/safe_definitions.yml +5 -0
  87. data/test/sites/complex/roles.yml +1 -1
  88. data/test/sites/ocean/roles.yml +4 -0
  89. data/test/sites/zena/columns.yml +3 -1
  90. data/test/sites/zena/roles.yml +5 -1
  91. data/test/sites/zena/sites.yml +22 -0
  92. data/test/unit/document_test.rb +14 -0
  93. data/test/unit/node_test.rb +14 -0
  94. data/test/unit/role_test.rb +19 -4
  95. data/test/unit/site_test.rb +67 -0
  96. data/test/unit/user_test.rb +20 -0
  97. data/test/unit/virtual_class_test.rb +116 -11
  98. data/test/unit/zena/use/rendering_test.rb +1 -1
  99. data/zena.gemspec +67 -66
  100. metadata +126 -125
  101. data/bricks/fs_skin/zena/init.rb +0 -1
  102. data/bricks/grid/zena/init.rb +0 -4
  103. data/bricks/single/zena/init.rb +0 -1
  104. data/bricks/spreadsheet/zena/init.rb +0 -3
@@ -1533,6 +1533,10 @@ msgstr ""
1533
1533
  msgid "site_img"
1534
1534
  msgstr ""
1535
1535
 
1536
+ #: app/views/sites/_li.erb:2 lib/gettext_strings.rb:34
1537
+ msgid "alias_img"
1538
+ msgstr ""
1539
+
1536
1540
  #: app/views/sites/index.erb:1 lib/zena/use/display.rb:279
1537
1541
  msgid "sites"
1538
1542
  msgstr ""
@@ -716,7 +716,8 @@ class NodesControllerTest < Zena::Controller::TestCase
716
716
  assert !File.exist?("#{SITES_ROOT}/test.host/public/en/image#{node.zip}.#{make_cachestamp(node,nil)}.jpg")
717
717
  # cache info ok
718
718
  get 'show', :prefix => 'en', :path => ["image#{node.zip}.#{make_cachestamp(node,nil)}.jpg"]
719
- assert_response :success
719
+ # This is the redirect to force apache serving
720
+ assert_redirected_to "/en/image#{node.zip}.#{make_cachestamp(node,nil)}.jpg?1"
720
721
  assert File.exist?("#{SITES_ROOT}/test.host/public/en/image#{node.zip}.#{make_cachestamp(node,nil)}.jpg")
721
722
  end
722
723
  end
@@ -1029,135 +1030,3 @@ END:VCALENDAR
1029
1030
  assert_equal nodes_id(:cleanWater), nodes.first.id
1030
1031
  end
1031
1032
  end
1032
-
1033
- =begin
1034
-
1035
- def test_import_archive
1036
- preserving_files('test.host/data') do
1037
- login(:tiger)
1038
- post 'import', :archive => uploaded_archive('import.tgz'), :id => nodes_zip(:status)
1039
- assert_response :success
1040
- assert_template 'import'
1041
- end
1042
- end
1043
-
1044
- def test_form_tabs
1045
- @controller = TestNodeController.new
1046
- init_controller
1047
- page = @controller.send(:secure, Node) { Node.find(nodes_id(:status)) }
1048
- @controller.instance_variable_set(:@node, page)
1049
- assert_equal [["drive", "drive"], ["links", "links"], ["help", "help"]], @controller.send(:form_tabs)
1050
- end
1051
-
1052
- def test_popup_page_not_found
1053
- get 'drive', :id=>99
1054
- assert_redirected_to :controller => 'node', :action=>'not_found'
1055
- get 'not_found'
1056
- assert_template 'node/not_found'
1057
- end
1058
-
1059
-
1060
- def test_add_link
1061
- login(:tiger)
1062
- node = secure!(Node) { nodes(:proposition) } # Post virtual class
1063
- assert_nil node.find(:all,'blogs')
1064
- assert_kind_of Relation, node.relation_proxy('blog')
1065
- post 'link', 'role'=>'blog', 'id'=>nodes_zip(:proposition), 'controller'=>'nodes', 'other_id'=>nodes_zip(:cleanWater)
1066
- assert_response :success
1067
- node = secure!(Node) { nodes(:proposition) } # reload
1068
- assert blogs = node.find(:all,'blogs')
1069
- assert_equal 1, blogs.size
1070
- assert_equal nodes_id(:cleanWater), blogs[0][:id]
1071
- end
1072
-
1073
- def test_tags_update_string
1074
- login(:lion)
1075
- post 'update', :id => nodes_zip(:art), :node => {'tagged_ids' => "#{nodes_zip(:status)}, #{nodes_zip(:people)}"}
1076
-
1077
- node = secure!(Node) { nodes(:art) }
1078
- assert_equal 2, node.tagged.size
1079
- stat = secure!(Node) { nodes(:status) }
1080
- peop = secure!(Node) { nodes(:people) }
1081
- assert_equal node[:id], stat.tags[0][:id]
1082
- assert_equal node[:id], peop.tags[0][:id]
1083
- end
1084
-
1085
- def test_tags_update_array
1086
- login(:lion)
1087
- post 'update', :id => nodes_zip(:art), :node => {:tagged_ids => [nodes_zip(:lion).to_i, nodes_zip(:cleanWater).to_s]}
1088
-
1089
- node = secure!(Node) { nodes(:art) }
1090
- assert_equal 2, node.tagged.size
1091
- lion = secure!(Node) { nodes(:lion) }
1092
- clea = secure!(Node) { nodes(:cleanWater) }
1093
- assert_equal node[:id], lion.tags[0][:id]
1094
- assert_equal node[:id], clea.tags[0][:id]
1095
- end
1096
-
1097
- def test_create_ok
1098
- login(:tiger)
1099
- post 'create', :node=>{:klass=>'Tracker', :parent_id=>nodes_zip(:zena), :name=>'test'}
1100
- assert_response :success
1101
- assert_kind_of Page, assigns['page']
1102
- assert assigns['page'].vkind_of?('Tracker')
1103
- assert !assigns['page'].new_record?, "Not a new record"
1104
- end
1105
-
1106
- def test_bad_skin_name
1107
- login(:anon)
1108
- without_files('zafu') do
1109
- Node.connection.execute "UPDATE nodes SET skin = 'bad' WHERE id = #{nodes_id(:status)}"
1110
- assert_nothing_raised do
1111
- get 'show', "prefix"=>"en",
1112
- "path"=>["projects", "cleanWater", "page22.html"]
1113
- end
1114
- end
1115
- assert_response :success
1116
- end
1117
-
1118
- def test_find_node
1119
- Node.connection.execute "UPDATE nodes SET name = '2006' where id = #{nodes_id(:projects)}"
1120
- Node.connection.execute "UPDATE nodes SET name = '25-10-2006' where id = #{nodes_id(:wiki)}"
1121
- Node.connection.execute "UPDATE nodes SET name = 'archive-1' where id = #{nodes_id(:bird_jpg)}"
1122
- [ ['section12.html',:success],
1123
- ['section12_tree.xml',:success],
1124
- ['2006','page18.html'],
1125
- ['2006.xml','page18.xml'],
1126
- ['p12','page12.html'],
1127
- ['25-10-2006','blog29.html'],
1128
- ['archive-1','image30.html'],
1129
- ['archive', 404],
1130
- ].each do |name, result|
1131
- puts name
1132
- get 'show', 'prefix' => 'en', 'path' => [name]
1133
- if result.kind_of?(String)
1134
- assert_redirected_to 'path' => [result]
1135
- else
1136
- assert_response result
1137
- end
1138
- end
1139
- end
1140
-
1141
- def test_cached_file
1142
- without_files('test.host/public') do
1143
- with_caching do
1144
- login(:anon)
1145
- page_path = visitor.site.public_path + '/en/section12.html'
1146
- file_path = "#{SITES_ROOT}#{page_path}"
1147
-
1148
- assert !File.exists?(file_path), "No cached file yet"
1149
- assert !CachedPage.find_by_path_and_site_id(page_path, sites_id(:zena)), "No cache info yet"
1150
-
1151
- get 'show', 'prefix' => 'en', 'path' => ['section12.html']
1152
- assert_response :success
1153
-
1154
- assert File.exists?(file_path), "Cache file created"
1155
- assert CachedPage.find_by_path_and_site_id(page_path, sites_id(:zena))
1156
- end
1157
- end
1158
- end
1159
-
1160
- # test edit_... mode only if can_write?
1161
-
1162
- end
1163
- =end
@@ -23,7 +23,7 @@ class SitesControllerTest < Zena::Controller::TestCase
23
23
  end
24
24
 
25
25
 
26
- test 'should clear cache with GET' do
26
+ test 'should clear cache with get' do
27
27
  with_caching do
28
28
  login(:anon)
29
29
  @node = secure!(Node) { nodes(:status) }
@@ -36,7 +36,8 @@ class MultipleHostsTest < ActionController::IntegrationTest
36
36
 
37
37
  def test_cache
38
38
  # We need the visitor to load VirtualClass cache.
39
- Thread.current[:visitor] = users(:anon)
39
+ anon_user = users(:anon)
40
+ setup_visitor(anon_user, anon_user.site)
40
41
  node_zip = nodes(:zena, :people).zip
41
42
  Thread.current[:visitor] = nil
42
43
 
@@ -473,6 +473,43 @@ class NavigationTest < Zena::Integration::TestCase
473
473
  end
474
474
  end
475
475
  end
476
+
477
+ def test_not_cache_on_redirect
478
+ login(:lion)
479
+ t = secure(Template) {
480
+ Template.create(
481
+ :parent_id => nodes_id(:default),
482
+ :title => 'Node-headers.zafu',
483
+ :text => %q{<r:headers Location='/login' Status='303'/>DUMMY BODY},
484
+ :v_status => Zena::Status::Pub
485
+ )
486
+ }
487
+
488
+ without_files('test.host/public') do
489
+ without_files('/test.host/zafu') do
490
+ preserving_files('/test.host/data') do
491
+ with_caching do
492
+ login(:anon)
493
+ base = "#{SITES_ROOT}#{visitor.site.public_path}"
494
+
495
+ c = '/fr/page18.html'
496
+ assert !File.exists?(base + c), "No cached file #{c} yet"
497
+ get "http://test.host#{c}"
498
+ assert_response :success
499
+ assert File.exists?(base + c), "Cached file #{c} created"
500
+
501
+ c = '/fr/page18_headers.html'
502
+ assert !File.exists?(base + c), "No cached file #{c} yet"
503
+ get "http://test.host#{c}"
504
+ assert_equal '<html><body>You are being <a href="http://test.host/login">redirected</a>.</body></html>', response.body
505
+ assert_response :redirect
506
+ assert_redirected_to '/login'
507
+ assert !File.exists?(base + c), "No cached file #{c} created"
508
+ end
509
+ end
510
+ end
511
+ end
512
+ end
476
513
 
477
514
  def test_should_not_change_session_lang_on_login
478
515
  get 'http://test.host/'
@@ -154,4 +154,4 @@ select_index_field:
154
154
  coalesce:
155
155
  src: "nodes in site order by parent_id.coalesce(0) asc limit 1"
156
156
  sql: "%Q{SELECT nodes.* FROM nodes WHERE #{secure_scope('nodes')} ORDER BY COALESCE(nodes.parent_id,0) ASC LIMIT 1}"
157
- res: "Zena the wild CMS"
157
+ res: "Zena the wild CMS"
@@ -386,6 +386,13 @@ link_page_next:
386
386
  src: "<div id='foo' do='block' do='nodes in site' limit='3' order='id asc' paginate='pak'><r:link page='previous'/> | <r:pak/> | <r:link update='foo' page='next'/></div>"
387
387
  res: "/<a href='/oo/projects-list/Clean-Water-project/page22.html\?pak=1'>1</a> \| 2 \| .*22/zafu\?dom_id=foo.*pak=3.*>3</a>/"
388
388
 
389
+ link_page_next_encode_params:
390
+ context:
391
+ pak: 2
392
+ foo: Hop
393
+ src: "<div id='foo' do='block' do='nodes in site' limit='3' order='id asc' paginate='pak'><r:link update='foo' page='next' encode_params='foo'/></div>"
394
+ res: "/Ajax.*foo=Hop/"
395
+
389
396
  link_page_list:
390
397
  context:
391
398
  pak: 2
@@ -13,8 +13,8 @@ comments_shown_if_empty_but_can_comment:
13
13
  tem: "/if \(var1 = @node.comments\) \|\| \(@node.can_comment\? && var1=\[\]\) %>/"
14
14
 
15
15
  discussion:
16
- src: "<r:discussion do='comments' do='title'></r:discussion>"
17
- tem: "<% if var1 = @node.discussion %><% if var2 = var1.comments %><%=h var2.first.title %><% end %><% end %>"
16
+ src: "<r:discussion do='comments' do='first.title'></r:discussion>"
17
+ tem: "<% if var1 = @node.discussion %><% if var2 = var1.comments %><%=h (var2.first ? var2.first.title : nil) %><% end %><% end %>"
18
18
  # no error
19
19
  res: "What about rivers ?"
20
20
 
@@ -5,7 +5,7 @@ default:
5
5
  node: 'cleanWater'
6
6
 
7
7
  each_group:
8
- src: "<r:nodes do='group' by='kpath'><p do='each_group'><r:kpath/>: <r:each join=', ' do='title'/></p></r:nodes>"
8
+ src: "<r:nodes do='group' by='kpath'><p do='each_group'><r:first do='kpath'/>: <r:each join=', ' do='title'/></p></r:nodes>"
9
9
  res: "<p>NP: crocodiles, status title</p><p>NDI: it&#39;s a lake</p><p>NRC: The lake we love</p><p>NNP: parc opening</p><p>ND: water</p>"
10
10
 
11
11
  # set_var tested in eval.yml
@@ -24,4 +24,8 @@ list_else:
24
24
  master_template_on_static_render:
25
25
  src: "<r:master_template><r:title/></r:master_template>"
26
26
  tem: ''
27
- # Master template on template rendering is tested in 'find master template', rendering_test.rb
27
+ # Master template on template rendering is tested in 'find master template', rendering_test.rb
28
+
29
+ login_info:
30
+ src: "<r:contacts in='site'><r:each do='login_info'><r:login/>, </r:each></r:contacts>"
31
+ res: "lion, tiger, ant, , "
@@ -326,10 +326,13 @@ admin_links_for_anon:
326
326
  src: "<r:admin_links>hello</r:admin_links>"
327
327
  res: ''
328
328
 
329
+ string_size:
330
+ src: "<div do='text.size'/>"
331
+ res: '<div>11</div>'
332
+
329
333
  string_limit:
330
- src: "<div do=\"text.limit(10, %Q{<a href='#{url}'>read more</a>})\"/>"
331
- tem: "<div><%= (@node.prop['text'] ? @node.prop['text'].limit(10, \"<a href='#{zen_url(@node)}'>read more</a>\") : nil) %></div>"
332
- res: "<div>status tex<a href='http://test.host/oo/projects-list/Clean-Water-project/page22.html'>read more</a></div>"
334
+ src: "<div do='text'><r:void do='limit(10,\"\")'/><r:if test='size > 10' do='link' href='@node' t='read more'/></div>"
335
+ res: "<div>status tex<a href='/oo/projects-list/Clean-Water-project/page22.html'>read more</a></div>"
333
336
 
334
337
  show_with_label_shortcut:
335
338
  context:
@@ -390,7 +393,7 @@ each_whitespace:
390
393
 
391
394
  set_class_before_query:
392
395
  # Uses list context
393
- src: "<div class='foo_#{title}' do='images in site'></div>"
396
+ src: "<div class='foo_#{first.title}' do='images in site'></div>"
394
397
  res: "<div class='foo_Autumn Tree'></div>"
395
398
 
396
399
  flash_messages:
@@ -509,3 +512,12 @@ with_a_custom_img_tag_field_with_JS:
509
512
  invalid_document:
510
513
  src: "<r:zazen text='!21!'/>"
511
514
  res: "/images/ext/project.png/"
515
+
516
+ uuid:
517
+ src: "<div id='foo#{uuid}'>hop</div>"
518
+ res: "/<div id='foou[a-z0-9]+'>hop</div>/"
519
+
520
+ use_first_in_list:
521
+ src: "<r:void do='contacts where id = 13 in site'><r:first do='link'/> // <r:first do='title'/></r:void>"
522
+ tem: "/var1.first.*var1.first/"
523
+ res: "<a href='/oo/contact13.html'>Solenopsis Invicta</a> // Solenopsis Invicta"
@@ -123,6 +123,7 @@ checkbox:
123
123
  checkbox_literal_auto_trans:
124
124
  context:
125
125
  node: 'people'
126
+ lang: 'fr'
126
127
  src: "<r:load dictionary='/Default skin/translations'><r:checkbox name='assigned' values='1,2'/></r:load>"
127
128
  tem: "/foo/"
128
129
  res: "/value='1'/> <span>foo</span>/"
@@ -104,6 +104,12 @@ interval_date_en:
104
104
  tem: "<%= query_parse('para' => %{2010/1/1..2010/12/31}) %>"
105
105
  res: "para >= '2009-12-31 23:00' and para <= '2010-12-30 23:00'"
106
106
 
107
+ interval_date_iso:
108
+ context:
109
+ lang: en
110
+ tem: "<%= query_parse('para' => %{2010-1-1..2010-12-31}) %>"
111
+ res: "para >= '2009-12-31 23:00' and para <= '2010-12-30 23:00'"
112
+
107
113
  like:
108
114
  tem: "<%= query_parse('para' => %{*bar}) %>"
109
115
  res: "para like \"%bar\""
@@ -265,7 +271,7 @@ select_in_from_saved:
265
271
  res: "<div>a wiki with Zena: bird, a wiki with Zena: flower, Clean Water project: it&#39;s a lake</div>"
266
272
 
267
273
  select_group:
268
- src: "<div do='images select title as it from projects select title as pt in site' do='group' by='pt' do='each_group' join=' / '><r:pt/>: <r:each join=', ' do='it'/></div>"
274
+ src: "<div do='images select title as it from projects select title as pt in site' do='group' by='pt' do='each_group' join=' / '><r:first do='pt'/>: <r:each join=', ' do='it'/></div>"
269
275
  res: "<div>a wiki with Zena: bird, flower / Clean Water project: it&#39;s a lake</div>"
270
276
 
271
277
  select_group_count:
@@ -392,23 +392,23 @@ where_with_param:
392
392
  group_by_secret_project:
393
393
  context:
394
394
  visitor: ant
395
- src: "<r:pages where='title like \"t%\"' in='site' order='title ASC' do='group' by='project'><b do='project' do='title'/>: <r:each join=',' do='title'/></r:pages>"
395
+ src: "<r:pages where='title like \"t%\"' in='site' order='title ASC' do='group' by='project'><b do='first.project' do='title'/>: <r:each join=',' do='title'/></r:pages>"
396
396
  res: ": Talk<b>Zena the wild CMS</b>: Top menu"
397
397
 
398
398
  group_by_project:
399
399
  context:
400
400
  visitor: lion
401
- src: "<r:notes in='site' order='title ASC' do='group' by='project'><b do='project' do='title'/>: <r:each join=',' do='title'/></r:notes>"
401
+ src: "<r:notes in='site' order='title ASC' do='group' by='project'><b do='first.project' do='title'/>: <r:each join=',' do='title'/></r:notes>"
402
402
  res: "<b>Clean Water project</b>: parc opening<b>Secret</b>: Proposition<b>Zena the wild CMS</b>: zena enhancements"
403
403
 
404
404
  group_by_project_sort_zip:
405
405
  context:
406
406
  visitor: ant
407
- src: "<r:images in='site' order='zip ASC' do='group' by='project' sort='id'><b do='project' do='title'/>: <r:each join=', ' do='title'/></r:images>"
407
+ src: "<r:images in='site' order='zip ASC' do='group' by='project' sort='id'><b do='first.project' do='title'/>: <r:each join=', ' do='title'/></r:images>"
408
408
  res: "<b>Clean Water project</b>: it&#39;s a lake<b>a wiki with Zena</b>: bird, flower<b>Zena the wild CMS</b>: Autumn Tree"
409
409
 
410
410
  group_by_parent_sort:
411
- src: "<r:images in='site' order='title ASC' do='group' by='parent' sort='title'><b do='parent' do='title'/>: <r:each join=', ' do='title'/></r:images>"
411
+ src: "<r:images in='site' order='title ASC' do='group' by='parent' sort='title'><b do='first.parent' do='title'/>: <r:each join=', ' do='title'/></r:images>"
412
412
  res: "<b>a wiki with Zena</b>: bird, flower<b>Clean Water project</b>: it&#39;s a lake"
413
413
 
414
414
  nodes_in_site_group_by_year:
@@ -466,12 +466,12 @@ array_count:
466
466
 
467
467
  first:
468
468
  src: "<div do='nodes in site'><r:first do='link'/></div>"
469
- tem: "/if var2 = var1.first %><a href='<%= zen_path\(var2\) %>'><%=h var2.prop\['title'\] %>/"
469
+ tem: "/var2 = var1.first %><a href='<%= zen_path\(var2\) %>'><%=h var2.prop\['title'\] %>/"
470
470
  res: '/a href.*a wiki with Zena/'
471
471
 
472
472
  rubyless_first:
473
473
  src: "<div do='nodes in site'><span do='first.title'/></div>"
474
- tem: "/span><%=h \(var1.first \? var1.first.prop\['title'\] : nil\) %>/"
474
+ tem: "/span><%=h var1.first.prop\['title'\] %>/"
475
475
  res: '<div><span>a wiki with Zena</span></div>'
476
476
 
477
477
  query_in_array:
@@ -493,4 +493,9 @@ core_context:
493
493
 
494
494
  find_less_then:
495
495
  src: <div do='projects where created_at < "2010-05-01" in site' do='each' do='title'/>
496
- tem: "/nodes.created_at < '2010-05-01'/"
496
+ tem: "/nodes.created_at < '2010-05-01'/"
497
+
498
+ l_status_sum_group_year:
499
+ src: '<r:void do="set_tags select l_status.sum as s from nodes select created_at as c in site group by c.month" do="each" join=", "><r:s/>: <r:c/></r:void>'
500
+ # tem: 'xxx'
501
+ res: '15: 2006-03-10 00:00:00'
@@ -79,13 +79,13 @@ vclass_roles:
79
79
  node: letter
80
80
  src: "<r:vclass do='roles' do='each' join=', '><r:name/> (<r:columns do='each' join=',' do='name'/>)</r:vclass>"
81
81
  tem: "/var1 = @node\.virtual_class .* var2 = var1.sorted_roles/"
82
- res: "Node (summary,text,title), Original (origin,settings,tz,weight), Task (assigned), Letter (paper,search,search_mono)"
82
+ res: "Node (summary,text,title), Original (origin,settings,tz,weight), Task (assigned), Note (info), Letter (paper,search,search_mono)"
83
83
 
84
84
  vclass_column_size:
85
85
  context:
86
86
  node: letter
87
87
  src: "<r:vclass do='roles' do='each' join=', '><r:name/> (<r:columns do='size'/>)</r:vclass>"
88
- res: "Node (3), Original (4), Task (1), Letter (3)"
88
+ res: "Node (3), Original (4), Task (1), Note (1), Letter (3)"
89
89
 
90
90
  vclass_context:
91
91
  src: "<r:Image><r:name/></r:Image>"
@@ -131,7 +131,7 @@ manual_select:
131
131
 
132
132
  inspect_display_links:
133
133
  src: |
134
- <r:Template do='relations' do='each' set_rel='name' do='main'>
134
+ <r:Template do='relations' do='each' do='main' set_rel='name'>
135
135
  <h3 do='rel'/>
136
136
  <ul do='query' default='nodes' select='#{rel}s'>
137
137
  <li do='each' do='link'/>
@@ -85,8 +85,7 @@ ancestors_on_root:
85
85
 
86
86
  prop_in_list_context:
87
87
  src: "<div do='nodes in site'><r:title/></div>"
88
- tem: "/var1.first.prop\['title'\]/"
89
- res: '<div>a wiki with Zena</div>'
88
+ tem: "/unknown method <span class='type'>title..</span> .\[Node\] context./"
90
89
 
91
90
  role_existing_class_name:
92
91
  # Should understand 'Comment' as a Role.
@@ -169,6 +169,11 @@ string_hash_with_params:
169
169
  src: "<b do='set' a='string_hash(:foo => \"men\")'>AAA<r:eval>a['foo']</r:eval></b>"
170
170
  res: "<b>AAAmen</b>"
171
171
  tem: "/StringHash.from_hash\(\{:foo => \"men\"\}\)/"
172
+
173
+ string_from_string:
174
+ src: "<b do='set' a='string_hash(%q[{\"pack\": 4}])'>AAA<r:eval>a['pack']</r:eval></b>"
175
+ res: "<b>AAA4</b>"
176
+ tem: "/StringHash.from_string/"
172
177
 
173
178
  aparams:
174
179
  context:
@@ -29,4 +29,4 @@ Course:
29
29
 
30
30
  Formation:
31
31
  kpath: NNF
32
- real_class: Note
32
+ real_class: Note