hobo 0.7.5 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (212) hide show
  1. data/{hobo_files/plugin/CHANGES.txt → CHANGES.txt} +391 -0
  2. data/Manifest +146 -0
  3. data/{hobo_files/plugin/README → README} +0 -0
  4. data/bin/hobo +13 -26
  5. data/dryml_generators/rapid/cards.dryml.erb +55 -0
  6. data/dryml_generators/rapid/forms.dryml.erb +43 -0
  7. data/dryml_generators/rapid/pages.dryml.erb +284 -0
  8. data/hobo.gemspec +168 -0
  9. data/init.rb +9 -0
  10. data/lib/action_view_extensions/helpers/tag_helper.rb +7 -0
  11. data/lib/active_record/association_collection.rb +54 -0
  12. data/{hobo_files/plugin/lib → lib}/active_record/association_proxy.rb +12 -4
  13. data/{hobo_files/plugin/lib → lib}/active_record/association_reflection.rb +7 -1
  14. data/{hobo_files/plugin/lib → lib}/extensions/test_case.rb +17 -17
  15. data/{hobo_files/plugin/lib → lib}/hobo.rb +193 -100
  16. data/{hobo_files/plugin/lib → lib}/hobo/authentication_support.rb +8 -8
  17. data/{hobo_files/plugin/lib → lib}/hobo/bundle.rb +90 -89
  18. data/{hobo_files/plugin/lib → lib}/hobo/composite_model.rb +21 -21
  19. data/{hobo_files/plugin/lib → lib}/hobo/controller.rb +38 -25
  20. data/{hobo_files/plugin/lib → lib}/hobo/dev_controller.rb +10 -6
  21. data/lib/hobo/dryml.rb +167 -0
  22. data/{hobo_files/plugin/lib → lib}/hobo/dryml/dryml_builder.rb +28 -25
  23. data/lib/hobo/dryml/dryml_generator.rb +210 -0
  24. data/{hobo_files/plugin/lib → lib}/hobo/dryml/dryml_support_controller.rb +1 -1
  25. data/lib/hobo/dryml/parser.rb +3 -0
  26. data/{hobo_files/plugin/lib → lib}/hobo/dryml/parser/attribute.rb +6 -6
  27. data/{hobo_files/plugin/lib → lib}/hobo/dryml/parser/base_parser.rb +16 -16
  28. data/lib/hobo/dryml/parser/document.rb +57 -0
  29. data/{hobo_files/plugin/lib → lib}/hobo/dryml/parser/element.rb +7 -7
  30. data/{hobo_files/plugin/lib → lib}/hobo/dryml/parser/elements.rb +9 -9
  31. data/{hobo_files/plugin/lib → lib}/hobo/dryml/parser/source.rb +3 -3
  32. data/{hobo_files/plugin/lib → lib}/hobo/dryml/parser/text.rb +3 -3
  33. data/{hobo_files/plugin/lib → lib}/hobo/dryml/parser/tree_parser.rb +3 -3
  34. data/{hobo_files/plugin/lib → lib}/hobo/dryml/part_context.rb +26 -26
  35. data/{hobo_files/plugin/lib → lib}/hobo/dryml/scoped_variables.rb +15 -15
  36. data/{hobo_files/plugin/lib → lib}/hobo/dryml/tag_parameters.rb +10 -10
  37. data/{hobo_files/plugin/lib → lib}/hobo/dryml/taglib.rb +43 -37
  38. data/{hobo_files/plugin/lib → lib}/hobo/dryml/template.rb +290 -208
  39. data/{hobo_files/plugin/lib → lib}/hobo/dryml/template_environment.rb +173 -115
  40. data/{hobo_files/plugin/lib → lib}/hobo/dryml/template_handler.rb +19 -24
  41. data/lib/hobo/find_for.rb +95 -0
  42. data/{hobo_files/plugin/lib → lib}/hobo/generator.rb +2 -1
  43. data/{hobo_files/plugin/lib → lib}/hobo/guest.rb +12 -4
  44. data/{hobo_files/plugin/lib → lib}/hobo/hobo_helper.rb +146 -117
  45. data/lib/hobo/include_in_save.rb +43 -0
  46. data/lib/hobo/lifecycles.rb +94 -0
  47. data/lib/hobo/lifecycles/actions.rb +73 -0
  48. data/lib/hobo/lifecycles/creator.rb +76 -0
  49. data/lib/hobo/lifecycles/lifecycle.rb +205 -0
  50. data/lib/hobo/lifecycles/state.rb +23 -0
  51. data/lib/hobo/lifecycles/transition.rb +66 -0
  52. data/{hobo_files/plugin/lib → lib}/hobo/model.rb +306 -217
  53. data/{hobo_files/plugin/lib → lib}/hobo/model_controller.rb +342 -213
  54. data/{hobo_files/plugin/lib → lib}/hobo/model_router.rb +151 -120
  55. data/{hobo_files/plugin/lib → lib}/hobo/model_support.rb +9 -9
  56. data/{hobo_files/plugin/lib → lib}/hobo/rapid_helper.rb +30 -23
  57. data/{hobo_files/plugin/lib → lib}/hobo/scopes.rb +22 -68
  58. data/{hobo_files/plugin/lib → lib}/hobo/scopes/apply_scopes.rb +5 -5
  59. data/lib/hobo/scopes/association_proxy_extensions.rb +47 -0
  60. data/{hobo_files/plugin/lib → lib}/hobo/scopes/automatic_scopes.rb +104 -79
  61. data/lib/hobo/scopes/named_scope_extensions.rb +27 -0
  62. data/{hobo_files/plugin/lib → lib}/hobo/static_tags +1 -11
  63. data/{hobo_files/plugin/lib → lib}/hobo/undefined.rb +1 -1
  64. data/{hobo_files/plugin/lib → lib}/hobo/undefined_access_error.rb +0 -0
  65. data/{hobo_files/plugin/lib → lib}/hobo/user.rb +27 -25
  66. data/{hobo_files/plugin/lib → lib}/hobo/user_controller.rb +80 -34
  67. data/{hobo_files/plugin/generators → rails_generators}/hobo/hobo_generator.rb +7 -7
  68. data/rails_generators/hobo/templates/application.css +0 -0
  69. data/{hobo_files/plugin/generators → rails_generators}/hobo/templates/application.dryml +0 -2
  70. data/{hobo_files/plugin/generators → rails_generators}/hobo/templates/dryml-support.js +0 -0
  71. data/{hobo_files/plugin/generators → rails_generators}/hobo/templates/guest.rb +0 -0
  72. data/rails_generators/hobo/templates/initializer.rb +9 -0
  73. data/{hobo_files/plugin/generators → rails_generators}/hobo_front_controller/USAGE +0 -0
  74. data/{hobo_files/plugin/generators → rails_generators}/hobo_front_controller/hobo_front_controller_generator.rb +1 -3
  75. data/{hobo_files/plugin/generators → rails_generators}/hobo_front_controller/templates/controller.rb +1 -1
  76. data/{hobo_files/plugin/generators → rails_generators}/hobo_front_controller/templates/functional_test.rb +0 -0
  77. data/{hobo_files/plugin/generators → rails_generators}/hobo_front_controller/templates/helper.rb +0 -0
  78. data/rails_generators/hobo_front_controller/templates/index.dryml +25 -0
  79. data/{hobo_files/plugin/generators → rails_generators}/hobo_model/USAGE +0 -0
  80. data/{hobo_files/plugin/generators → rails_generators}/hobo_model/hobo_model_generator.rb +0 -0
  81. data/{hobo_files/plugin/generators → rails_generators}/hobo_model/templates/fixtures.yml +0 -0
  82. data/{hobo_files/plugin/generators → rails_generators}/hobo_model/templates/model.rb +0 -0
  83. data/{hobo_files/plugin/generators → rails_generators}/hobo_model/templates/unit_test.rb +0 -0
  84. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_controller/USAGE +0 -0
  85. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_controller/hobo_model_controller_generator.rb +0 -7
  86. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_controller/templates/controller.rb +0 -0
  87. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_controller/templates/functional_test.rb +0 -0
  88. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_controller/templates/helper.rb +0 -0
  89. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_resource/hobo_model_resource_generator.rb +0 -0
  90. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_resource/templates/controller.rb +0 -0
  91. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_resource/templates/functional_test.rb +0 -0
  92. data/{hobo_files/plugin/generators → rails_generators}/hobo_model_resource/templates/helper.rb +0 -0
  93. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/hobo_rapid_generator.rb +21 -11
  94. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/IE7.js +1 -1
  95. data/rails_generators/hobo_rapid/templates/blank.gif +0 -0
  96. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/hobo-rapid.css +0 -0
  97. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/hobo-rapid.js +175 -104
  98. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/lowpro.js +0 -0
  99. data/rails_generators/hobo_rapid/templates/nicEditorIcons.gif +0 -0
  100. data/rails_generators/hobo_rapid/templates/nicedit.js +91 -0
  101. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/reset.css +0 -0
  102. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/themes/clean/public/images/fieldbg.gif +0 -0
  103. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/themes/clean/public/images/pencil.png +0 -0
  104. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/themes/clean/public/images/small_close.png +0 -0
  105. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/themes/clean/public/images/spinner.gif +0 -0
  106. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +80 -71
  107. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +6 -1
  108. data/{hobo_files/plugin/generators → rails_generators}/hobo_rapid/templates/themes/clean/views/clean.dryml +4 -4
  109. data/rails_generators/hobo_subsite/hobo_subsite_generator.rb +73 -0
  110. data/rails_generators/hobo_subsite/templates/application.dryml +1 -0
  111. data/rails_generators/hobo_subsite/templates/controller.rb +5 -0
  112. data/rails_generators/hobo_subsite/templates/site_taglib.dryml +13 -0
  113. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_controller/USAGE +0 -0
  114. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_controller/hobo_user_controller_generator.rb +0 -0
  115. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_controller/templates/controller.rb +0 -0
  116. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_controller/templates/functional_test.rb +0 -0
  117. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_controller/templates/helper.rb +0 -0
  118. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_model/USAGE +0 -0
  119. data/rails_generators/hobo_user_model/hobo_user_model_generator.rb +30 -0
  120. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_model/templates/fixtures.yml +0 -0
  121. data/rails_generators/hobo_user_model/templates/forgot_password.erb +10 -0
  122. data/rails_generators/hobo_user_model/templates/mailer.rb +14 -0
  123. data/rails_generators/hobo_user_model/templates/model.rb +55 -0
  124. data/{hobo_files/plugin/generators → rails_generators}/hobo_user_model/templates/unit_test.rb +0 -0
  125. data/script/destroy +14 -0
  126. data/script/generate +14 -0
  127. data/{hobo_files/plugin/taglibs → taglibs}/core.dryml +6 -7
  128. data/{hobo_files/plugin/taglibs → taglibs}/rapid.dryml +36 -67
  129. data/{hobo_files/plugin/taglibs → taglibs}/rapid_document_tags.dryml +7 -24
  130. data/{hobo_files/plugin/taglibs → taglibs}/rapid_editing.dryml +51 -50
  131. data/{hobo_files/plugin/taglibs → taglibs}/rapid_forms.dryml +62 -56
  132. data/taglibs/rapid_generics.dryml +33 -0
  133. data/taglibs/rapid_lifecycles.dryml +43 -0
  134. data/{hobo_files/plugin/taglibs → taglibs}/rapid_navigation.dryml +23 -23
  135. data/taglibs/rapid_pages.dryml +183 -0
  136. data/{hobo_files/plugin/taglibs → taglibs}/rapid_plus.dryml +30 -5
  137. data/{hobo_files/plugin/taglibs → taglibs}/rapid_support.dryml +3 -4
  138. data/taglibs/rapid_user_pages.dryml +179 -0
  139. data/{hobo_files/plugin/tasks → tasks}/environments.rake +0 -0
  140. data/{hobo_files/plugin/tasks → tasks}/fix_dryml.rake +0 -0
  141. data/{hobo_files/plugin/tasks → tasks}/generate_tag_reference.rb +21 -22
  142. data/tasks/hobo_tasks.rake +32 -0
  143. data/test/test_generator_helper.rb +29 -0
  144. data/test/test_helper.rb +1 -0
  145. data/test/test_hobo_model_controller_generator.rb +56 -0
  146. data/{hobo_files/plugin/uninstall.rb → uninstall.rb} +0 -0
  147. metadata +240 -225
  148. data/README.txt +0 -18
  149. data/hobo_files/plugin/LICENSE.txt +0 -22
  150. data/hobo_files/plugin/Rakefile +0 -96
  151. data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +0 -24
  152. data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +0 -19
  153. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/banner.gif +0 -0
  154. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-bodytop.gif +0 -0
  155. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-corner-01.gif +0 -0
  156. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-corner-02.gif +0 -0
  157. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-corner-03.gif +0 -0
  158. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-corner-04.gif +0 -0
  159. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-shadow-bottom.gif +0 -0
  160. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-shadow-left.gif +0 -0
  161. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-shadow-right.gif +0 -0
  162. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg-shadow-top.gif +0 -0
  163. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header-blue.gif +0 -0
  164. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header-dblue.gif +0 -0
  165. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header-green.gif +0 -0
  166. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header-purple.gif +0 -0
  167. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header-red.gif +0 -0
  168. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/logo.gif +0 -0
  169. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/plus.png +0 -0
  170. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/spinner.gif +0 -0
  171. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt-list-img-dblue.gif +0 -0
  172. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt-list-img-green.gif +0 -0
  173. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt-list-img-purple.gif +0 -0
  174. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt-list-img-red.gif +0 -0
  175. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-corner-01.gif +0 -0
  176. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-corner-02.gif +0 -0
  177. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-corner-03.gif +0 -0
  178. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-corner-04.gif +0 -0
  179. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-shadow-bottom.gif +0 -0
  180. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-shadow-left.gif +0 -0
  181. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-shadow-right.gif +0 -0
  182. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window-shadow-top.gif +0 -0
  183. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +0 -400
  184. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +0 -96
  185. data/hobo_files/plugin/generators/hobo_user_model/hobo_user_model_generator.rb +0 -25
  186. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +0 -56
  187. data/hobo_files/plugin/init.rb +0 -101
  188. data/hobo_files/plugin/lib/action_view_extensions/base.rb +0 -15
  189. data/hobo_files/plugin/lib/active_record/has_many_association.rb +0 -55
  190. data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +0 -20
  191. data/hobo_files/plugin/lib/hobo/dryml.rb +0 -165
  192. data/hobo_files/plugin/lib/hobo/dryml/parser/document.rb +0 -53
  193. data/hobo_files/plugin/lib/hobo/scopes/association_proxy_extensions.rb +0 -33
  194. data/hobo_files/plugin/lib/hobo/scopes/defined_scope_proxy_extender.rb +0 -90
  195. data/hobo_files/plugin/lib/hobo/scopes/scope_reflection.rb +0 -18
  196. data/hobo_files/plugin/lib/hobo/scopes/scoped_proxy.rb +0 -55
  197. data/hobo_files/plugin/taglib-docs/core.markdown +0 -165
  198. data/hobo_files/plugin/taglib-docs/rapid.markdown +0 -677
  199. data/hobo_files/plugin/taglib-docs/rapid_document_tags.markdown +0 -240
  200. data/hobo_files/plugin/taglib-docs/rapid_editing.markdown +0 -418
  201. data/hobo_files/plugin/taglib-docs/rapid_forms.markdown +0 -562
  202. data/hobo_files/plugin/taglib-docs/rapid_generics.markdown +0 -187
  203. data/hobo_files/plugin/taglib-docs/rapid_navigation.markdown +0 -214
  204. data/hobo_files/plugin/taglib-docs/rapid_pages.markdown +0 -530
  205. data/hobo_files/plugin/taglib-docs/rapid_plus.markdown +0 -65
  206. data/hobo_files/plugin/taglib-docs/rapid_support.markdown +0 -50
  207. data/hobo_files/plugin/taglib-docs/rapid_user_pages.markdown +0 -129
  208. data/hobo_files/plugin/taglibs/rapid_generics.dryml +0 -117
  209. data/hobo_files/plugin/taglibs/rapid_pages.dryml +0 -359
  210. data/hobo_files/plugin/taglibs/rapid_user_pages.dryml +0 -104
  211. data/hobo_files/plugin/tasks/dump_fixtures.rake +0 -70
  212. data/hobo_files/plugin/tasks/hobo_tasks.rake +0 -17
@@ -1,8 +1,8 @@
1
1
  module Hobo::Dryml::Parser
2
-
2
+
3
3
  # A REXML source that keeps track of where in the buffer it is
4
4
  class Source < REXML::Source
5
-
5
+
6
6
  def initialize(src)
7
7
  super(src)
8
8
  @buffer_offset = 0
@@ -50,7 +50,7 @@ module Hobo::Dryml::Parser
50
50
 
51
51
  def current_line
52
52
  pos = last_match_offset || 0
53
- [0, 0, @orig[0..pos].count("\n") + 1]
53
+ [0, 0, @orig[0..pos].count("\n") + 1]
54
54
  end
55
55
 
56
56
  end
@@ -1,7 +1,7 @@
1
1
  module Hobo::Dryml::Parser
2
-
2
+
3
3
  class Text < REXML::Text
4
-
4
+
5
5
  def parent=(parent)
6
6
  # Bypass immediate super
7
7
  REXML::Child.instance_method(:parent=).bind(self).call(parent)
@@ -9,5 +9,5 @@ module Hobo::Dryml::Parser
9
9
  end
10
10
 
11
11
  end
12
-
12
+
13
13
  end
@@ -6,7 +6,7 @@ module Hobo::Dryml::Parser
6
6
  @parser = Hobo::Dryml::Parser::BaseParser.new(source)
7
7
  end
8
8
 
9
-
9
+
10
10
  def parse
11
11
  tag_stack = []
12
12
  in_doctype = false
@@ -39,8 +39,8 @@ module Hobo::Dryml::Parser
39
39
  if @build_context[-1].instance_of? Text
40
40
  @build_context[-1] << event[1]
41
41
  else
42
- @build_context.add(
43
- Hobo::Dryml::Parser::Text.new(event[1], @build_context.whitespace, nil, true)
42
+ @build_context.add(
43
+ Hobo::Dryml::Parser::Text.new(event[1], @build_context.whitespace, nil, true)
44
44
  ) unless (
45
45
  @build_context.ignore_whitespace_nodes and
46
46
  event[1].strip.size==0
@@ -1,20 +1,20 @@
1
1
  module Hobo
2
-
2
+
3
3
  module Dryml
4
-
4
+
5
5
  # Raised when the part context fails its integrity check.
6
6
  class PartContext
7
-
7
+
8
8
  class TamperedWithPartContext < StandardError; end
9
-
9
+
10
10
  class Id < String; end
11
-
11
+
12
12
  class << self
13
13
  attr_accessor :secret, :digest
14
14
  end
15
15
  self.digest = 'SHA1'
16
-
17
-
16
+
17
+
18
18
  def self.client_side_storage(contexts, session)
19
19
  return "" if contexts.empty?
20
20
 
@@ -23,15 +23,15 @@ module Hobo
23
23
  "hoboParts['#{dom_id}'] = (#{code});\n"
24
24
  end.join
25
25
  end
26
-
27
-
26
+
27
+
28
28
  def initialize(part_name, this_id, locals)
29
29
  @part_name = part_name
30
30
  @this_id = this_id
31
31
  @locals = locals.map { |l| pre_marshal(l) }
32
32
  end
33
-
34
-
33
+
34
+
35
35
  def pre_marshal(x)
36
36
  if x.is_a?(ActiveRecord::Base) && x.respond_to?(:typed_id)
37
37
  Id.new(x.typed_id)
@@ -39,26 +39,26 @@ module Hobo
39
39
  x
40
40
  end
41
41
  end
42
-
43
-
42
+
43
+
44
44
  def marshal(session)
45
45
  context = [@part_name, @this_id, @locals]
46
46
  data = Base64.encode64(Marshal.dump(context)).strip
47
47
  digest = self.class.generate_digest(data, session)
48
48
  "#{data}--#{digest}"
49
49
  end
50
-
50
+
51
51
 
52
52
  class << self
53
-
53
+
54
54
  # Generate the HMAC keyed message digest. Uses SHA1 by default.
55
55
  def generate_digest(data, session)
56
56
  secret = self.secret || ActionController::Base.cached_session_options.first[:secret]
57
57
  key = secret.respond_to?(:call) ? secret.call(session) : secret
58
58
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(digest), key, data)
59
59
  end
60
-
61
-
60
+
61
+
62
62
  # Unmarshal part context to a hash and verify its integrity.
63
63
  def unmarshal(client_store, this, session)
64
64
  data, digest = CGI.unescape(client_store).strip.split('--')
@@ -70,7 +70,7 @@ module Hobo
70
70
 
71
71
  [part_name, restore_part_this(this_id, this), restore_locals(locals)]
72
72
  end
73
-
73
+
74
74
  def restore_part_this(this_id, this)
75
75
  if this_id == "this" or this_id.blank?
76
76
  this
@@ -78,10 +78,10 @@ module Hobo
78
78
  nil
79
79
  else
80
80
  Hobo.object_from_dom_id(this_id)
81
- end
81
+ end
82
82
  end
83
-
84
-
83
+
84
+
85
85
  def restore_locals(locals)
86
86
  locals.map do |l|
87
87
  if l.is_a?(Id)
@@ -91,11 +91,11 @@ module Hobo
91
91
  end
92
92
  end
93
93
  end
94
-
94
+
95
95
  end
96
-
96
+
97
97
  end
98
-
99
- end
100
-
98
+
99
+ end
100
+
101
101
  end
@@ -1,34 +1,34 @@
1
1
  module Hobo::Dryml
2
-
2
+
3
3
  class ScopedVariables
4
-
5
- def initialize
6
- @scopes = [{}]
4
+
5
+ def initialize(variables=nil)
6
+ @scopes = variables ? [variables] : []
7
7
  end
8
-
8
+
9
9
  def [](key)
10
10
  s = scope_with_key(key) and s[key]
11
11
  end
12
-
12
+
13
13
  def []=(key, val)
14
- s = scope_with_key(key) || @scopes.last
14
+ s = scope_with_key(key) or raise ArgumentError, "no such scoped variable: #{key}"
15
15
  s[key] = val
16
16
  end
17
-
18
- def new_scope
19
- @scopes << {}
17
+
18
+ def new_scope(variables)
19
+ @scopes << variables.dup
20
20
  res = yield
21
21
  @scopes.pop
22
22
  res
23
23
  end
24
-
24
+
25
25
  def scope_with_key(key)
26
26
  @scopes.reverse_each do |s|
27
27
  return s if s.has_key?(key)
28
- end
28
+ end
29
29
  nil
30
30
  end
31
-
31
+
32
32
  def method_missing(name, *args)
33
33
  if name.to_s =~ /=$/
34
34
  self[name.to_s[0..-2].to_sym] = args.first
@@ -36,7 +36,7 @@ module Hobo::Dryml
36
36
  self[name]
37
37
  end
38
38
  end
39
-
39
+
40
40
  end
41
-
41
+
42
42
  end
@@ -1,11 +1,11 @@
1
1
  module Hobo
2
-
2
+
3
3
  module Dryml
4
-
4
+
5
5
  class NoParameterError < RuntimeError; end
6
-
6
+
7
7
  class TagParameters < Hash
8
-
8
+
9
9
  def initialize(parameters, exclude_names=nil)
10
10
  if exclude_names.blank?
11
11
  update(parameters)
@@ -13,7 +13,7 @@ module Hobo
13
13
  parameters.each_pair { |k, v| self[k] = v unless k.in?(exclude_names) }
14
14
  end
15
15
  end
16
-
16
+
17
17
  def method_missing(name, default_content="")
18
18
  if name.to_s =~ /\?$/
19
19
  has_key?(name.to_s[0..-2].to_sym)
@@ -21,15 +21,15 @@ module Hobo
21
21
  self[name]._?.call(default_content) || ""
22
22
  end
23
23
  end
24
-
24
+
25
25
  undef_method :default
26
-
26
+
27
27
  def [](param_name)
28
28
  fetch(param_name, nil)
29
29
  end
30
-
30
+
31
31
  end
32
-
32
+
33
33
  end
34
-
34
+
35
35
  end
@@ -1,93 +1,99 @@
1
1
  module Hobo
2
-
2
+
3
3
  module Dryml
4
4
 
5
5
  class Taglib
6
-
6
+
7
7
  @cache = {}
8
-
8
+
9
9
  class << self
10
-
10
+
11
11
  def get(options)
12
- taglib = @cache[options]
12
+ cache_key = options.inspect
13
+ taglib = @cache[cache_key]
13
14
  if taglib
14
15
  taglib.reload
15
16
  else
16
17
  src_file = taglib_filename(options)
17
18
  bundle = options[:bundle] && Bundle.bundles[options[:bundle]]
18
-
19
+
19
20
  taglib = Taglib.new(src_file, bundle)
20
- @cache[options] = taglib
21
+ @cache[cache_key] = taglib
21
22
  end
22
23
  taglib
23
24
  end
24
-
25
+
25
26
  def clear_cache
26
27
  @cache = {}
27
28
  end
28
-
29
+
29
30
  private
30
-
31
+
31
32
  def taglib_filename(options)
32
- base = if (plugin = options[:plugin])
33
- "vendor/plugins/#{plugin}/taglibs"
33
+ plugin = options[:plugin]
34
+ base = if plugin == "hobo"
35
+ "#{HOBO_ROOT}/taglibs"
36
+ elsif plugin
37
+ "#{RAILS_ROOT}/vendor/plugins/#{plugin}/taglibs"
34
38
  elsif (bundle_name = options[:bundle])
35
- bundle = Bundle.bundles[bundle_name]
36
- "vendor/plugins/#{bundle.plugin}/taglibs"
39
+ bundle = Bundle.bundles[bundle_name] or raise ArgumentError, "No such bundle: #{options[:bundle]}"
40
+ "#{RAILS_ROOT}/vendor/plugins/#{bundle.plugin}/taglibs"
37
41
  elsif options[:src] =~ /\//
38
- "app/views"
42
+ "#{RAILS_ROOT}/app/views"
43
+ elsif options[:template_dir] =~ /^#{HOBO_ROOT}/
44
+ options[:template_dir]
39
45
  else
40
- options[:template_dir].gsub(/^\//, "") # remove leading / if there is one
46
+ "#{RAILS_ROOT}/#{options[:template_dir].gsub(/^\//, '')}" # remove leading / if there is one
41
47
  end
42
-
43
- filename = "#{RAILS_ROOT}/#{base}/#{options[:src]}.dryml"
44
- raise DrymlException, "No such taglib: #{options.inspect} #{filename}" unless File.exists?(filename)
48
+
49
+ filename = "#{base}/#{options[:src]}.dryml"
50
+ raise DrymlException, "No such taglib: #{base} #{options.inspect} #{filename}" unless File.exists?(filename)
45
51
  filename
46
52
  end
47
-
53
+
48
54
  end
49
-
55
+
50
56
  def initialize(src_file, bundle)
51
57
  @src_file = src_file
52
58
  @bundle = bundle
53
59
  load
54
60
  end
55
-
61
+
56
62
  def reload
57
63
  load if File.mtime(@src_file) > @last_load_time
58
64
  end
59
-
65
+
60
66
  def load
61
67
  @module = Module.new do
62
-
68
+
63
69
  @tag_attrs = {}
64
70
  @tag_aliases = {}
65
-
71
+
66
72
  class << self
67
-
73
+
68
74
  def included(base)
69
75
  @tag_aliases.each do |tag, feature|
70
76
  base.send(:alias_method_chain, tag, feature)
71
77
  end
72
78
  end
73
-
79
+
74
80
  def _register_tag_attrs(tag, attrs)
75
81
  @tag_attrs[tag] = attrs
76
82
  end
77
83
  attr_reader :tag_attrs
78
-
79
- def delayed_alias_method_chain(tag, feature)
84
+
85
+ def alias_method_chain_on_include(tag, feature)
80
86
  @tag_aliases[tag] = feature
81
87
  end
82
-
88
+
83
89
  end
84
-
90
+
85
91
  end
86
92
  template = Template.new(File.read(@src_file), @module, @src_file, @bundle)
87
93
  template.compile([], [])
88
94
  @last_load_time = File.mtime(@src_file)
89
95
  end
90
-
96
+
91
97
  def import_into(class_or_module, as)
92
98
  if as
93
99
  # Define a method on class_or_module named whatever 'as'
@@ -95,10 +101,10 @@ module Hobo
95
101
  # returns an object that provides the taglib's tags as
96
102
  # methods. On subsequent calls the object is cached in an
97
103
  # instance variable "@_#{as}_taglib"
98
-
104
+
99
105
  taglib_module = @module
100
106
  ivar = "@_#{as}_taglib"
101
- class_or_module.send(:define_method, as) do
107
+ class_or_module.send(:define_method, as) do
102
108
  instance_variable_get(ivar) or begin
103
109
  as_class = Class.new(TemplateEnvironment) { include taglib_module }
104
110
  as_object = as_class.new
@@ -111,9 +117,9 @@ module Hobo
111
117
  class_or_module.tag_attrs.update(@module.tag_attrs) if @module.respond_to?(:tag_attrs)
112
118
  end
113
119
  end
114
-
120
+
115
121
  end
116
-
122
+
117
123
  end
118
-
124
+
119
125
  end
@@ -1,4 +1,5 @@
1
1
  require 'rexml/document'
2
+ require 'pathname'
2
3
 
3
4
  module Hobo::Dryml
4
5
 
@@ -9,21 +10,21 @@ module Hobo::Dryml
9
10
 
10
11
  RUBY_NAME = "[a-zA-Z_][a-zA-Z0-9_]*"
11
12
  RUBY_NAME_RX = /^#{RUBY_NAME}$/
12
-
13
+
13
14
  CODE_ATTRIBUTE_CHAR = "&"
14
-
15
+
15
16
  NO_METADATA_TAGS = %w(doctype if else unless repeat do with name type-name)
16
-
17
- SPECIAL_ATTRIBUTES = %w(param merge merge-params merge-attrs
18
- for-type
19
- if unless repeat
17
+
18
+ SPECIAL_ATTRIBUTES = %w(param merge merge-params merge-attrs
19
+ for-type
20
+ if unless repeat
20
21
  part part-locals
21
22
  restore)
22
-
23
+
23
24
  VALID_PARAMETER_TAG_ATTRIBUTES = %w(param replace)
24
25
 
25
26
  @build_cache = {}
26
-
27
+
27
28
  class << self
28
29
  attr_reader :build_cache
29
30
 
@@ -35,7 +36,7 @@ module Hobo::Dryml
35
36
  def initialize(src, environment, template_path, bundle=nil)
36
37
  @src = src
37
38
  @environment = environment # a class or a module
38
- @template_path = template_path.sub(/^#{Regexp.escape(RAILS_ROOT)}/, "")
39
+ @template_path = template_path.sub(%r(^#{Regexp.escape(RAILS_ROOT)}/), "")
39
40
  @bundle = bundle
40
41
 
41
42
  @builder = Template.build_cache[@template_path] || DRYMLBuilder.new(self)
@@ -45,49 +46,49 @@ module Hobo::Dryml
45
46
  end
46
47
 
47
48
  attr_reader :tags, :template_path, :bundle
48
-
49
+
49
50
  def compile(local_names=[], auto_taglibs=[])
50
51
  now = Time.now
51
52
 
52
53
  unless @template_path.ends_with?(EMPTY_PAGE)
53
- filename = RAILS_ROOT + (@template_path.starts_with?("/") ? @template_path : "/" + @template_path)
54
- mtime = File.stat(filename).mtime rescue nil
55
- end
56
-
57
- if mtime.nil? || !@builder.ready?(mtime)
58
- @builder.clear_instructions
59
- parsed = true
60
- # parse the DRYML file creating a list of build instructions
61
- if is_taglib?
62
- process_src
63
- else
64
- create_render_page_method
65
- end
54
+ p = Pathname.new template_path
55
+ p = Pathname.new(RAILS_ROOT) + p unless p.absolute?
56
+ mtime = p.mtime
57
+
58
+ if !@builder.ready?(mtime)
59
+ @builder.start
60
+ parsed = true
61
+ # parse the DRYML file creating a list of build instructions
62
+ if is_taglib?
63
+ process_src
64
+ else
65
+ create_render_page_method
66
+ end
66
67
 
67
- # store build instructions in the cache
68
- Template.build_cache[@template_path] = @builder
68
+ # store build instructions in the cache
69
+ Template.build_cache[@template_path] = @builder
70
+ end
69
71
  end
70
-
72
+
71
73
  # compile the build instructions
72
74
  @builder.build(local_names, auto_taglibs, mtime)
73
75
 
74
- from_cache = (parsed ? '' : ' (from cache)')
75
- logger.info(" DRYML: Compiled#{from_cache} #{template_path} in %.2fs" % (Time.now - now))
76
+ logger.info(" DRYML: Compiled #{template_path} in %.2fs" % (Time.now - now)) if parsed
76
77
  end
77
-
78
+
78
79
 
79
80
  def create_render_page_method
80
81
  erb_src = process_src
81
-
82
+
82
83
  @builder.add_build_instruction(:render_page, :src => erb_src, :line_num => 1)
83
84
  end
84
85
 
85
-
86
+
86
87
  def is_taglib?
87
88
  @environment.class == Module
88
89
  end
89
90
 
90
-
91
+
91
92
  def process_src
92
93
  @doc = Hobo::Dryml::Parser::Document.new(@src, @template_path)
93
94
  result = children_to_erb(@doc.root)
@@ -99,11 +100,11 @@ module Hobo::Dryml
99
100
  @doc.restore_erb_scriptlets(src)
100
101
  end
101
102
 
102
-
103
+
103
104
  def children_to_erb(nodes)
104
105
  nodes.map{|x| node_to_erb(x)}.join
105
106
  end
106
-
107
+
107
108
 
108
109
  def node_to_erb(node)
109
110
  case node
@@ -111,7 +112,7 @@ module Hobo::Dryml
111
112
  # v important this comes before REXML::Text, as REXML::CData < REXML::Text
112
113
  when REXML::CData
113
114
  REXML::CData::START + node.to_s + REXML::CData::STOP
114
-
115
+
115
116
  when REXML::Comment
116
117
  REXML::Comment::START + node.to_s + REXML::Comment::STOP
117
118
 
@@ -127,8 +128,8 @@ module Hobo::Dryml
127
128
  def strip_suppressed_whiteaspace(s)
128
129
  s # s.gsub(/ -(\s*\n\s*)/, '<% \1 %>')
129
130
  end
130
-
131
-
131
+
132
+
132
133
  def element_to_erb(el)
133
134
  dryml_exception("old-style parameter tag (<#{el.name}>)", el) if el.name.starts_with?(":")
134
135
 
@@ -140,7 +141,7 @@ module Hobo::Dryml
140
141
  # return just the newlines to keep line-number matching - the
141
142
  # include has no presence in the erb source
142
143
  tag_newlines(el)
143
-
144
+
144
145
  when "set-theme"
145
146
  require_attribute(el, "name", /^#{DRYML_NAME}$/)
146
147
  @builder.add_build_instruction(:set_theme, :name => el.attributes['name'])
@@ -150,16 +151,19 @@ module Hobo::Dryml
150
151
 
151
152
  when "def"
152
153
  def_element(el)
153
-
154
+
155
+ when "extend"
156
+ extend_element(el)
157
+
154
158
  when "set"
155
159
  set_element(el)
156
-
160
+
157
161
  when "set-scoped"
158
162
  set_scoped_element(el)
159
-
163
+
160
164
  when "param-content"
161
165
  param_content_element(el)
162
-
166
+
163
167
  else
164
168
  if el.dryml_name.not_in?(Hobo.static_tags) || el.attributes['param'] || el.attributes['restore']
165
169
  tag_call(el)
@@ -179,7 +183,7 @@ module Hobo::Dryml
179
183
  end
180
184
  @builder.add_build_instruction(:include, options)
181
185
  end
182
-
186
+
183
187
 
184
188
  def import_module(mod, as=nil)
185
189
  @builder.import_module(mod, as)
@@ -188,23 +192,24 @@ module Hobo::Dryml
188
192
 
189
193
  def set_element(el)
190
194
  assigns = el.attributes.map do |name, value|
195
+ next if name.in?(SPECIAL_ATTRIBUTES)
191
196
  dryml_exception("invalid name in <set>", el) unless name =~ /^#{DRYML_NAME}(\.#{DRYML_NAME})*$/
192
197
  "#{ruby_name name} = #{attribute_to_ruby(value)}; "
193
198
  end.join
194
199
  code = apply_control_attributes("begin; #{assigns}; end", el)
195
- "<% #{assigns}#{tag_newlines(el)} %>"
200
+ "<% #{code}#{tag_newlines(el)} %>"
196
201
  end
197
-
198
-
202
+
203
+
199
204
  def set_scoped_element(el)
200
- assigns = el.attributes.map do |name, value|
205
+ variables = el.attributes.map do |name, value|
201
206
  dryml_exception("invalid name in <set-scoped>", el) unless name =~ DRYML_NAME_RX
202
- "scope[:#{ruby_name name}] = #{attribute_to_ruby(value)}; "
203
- end.join
204
- "<% scope.new_scope { #{assigns}#{tag_newlines(el)} %>#{children_to_erb(el)}<% } %>"
207
+ ":#{ruby_name name} => #{attribute_to_ruby(value)} "
208
+ end
209
+ "<% scope.new_scope(#{variables * ', '}) { #{tag_newlines(el)} %>#{children_to_erb(el)}<% } %>"
205
210
  end
206
-
207
-
211
+
212
+
208
213
  def declared_attributes(def_element)
209
214
  attrspec = def_element.attributes["attrs"]
210
215
  attr_names = attrspec ? attrspec.split(/\s*,\s*/).map{ |n| n.underscore.to_sym } : []
@@ -212,13 +217,13 @@ module Hobo::Dryml
212
217
  dryml_exception("invalid attrs in def: #{invalids * ', '}", def_element) unless invalids.empty?
213
218
  attr_names
214
219
  end
215
-
216
-
220
+
221
+
217
222
  def ruby_name(dryml_name)
218
223
  dryml_name.gsub('-', '_')
219
224
  end
220
-
221
-
225
+
226
+
222
227
  def with_containing_tag_name(el)
223
228
  old = @containing_tag_name
224
229
  @containing_tag_name = el.dryml_name
@@ -227,57 +232,86 @@ module Hobo::Dryml
227
232
  end
228
233
 
229
234
 
230
- def def_element(el)
231
- require_toplevel(el)
232
- require_attribute(el, "tag", DRYML_NAME_RX)
233
- require_attribute(el, "attrs", /^\s*#{DRYML_NAME}(\s*,\s*#{DRYML_NAME})*\s*$/, true)
234
- require_attribute(el, "alias-of", DRYML_NAME_RX, true)
235
- require_attribute(el, "extend-with", DRYML_NAME_RX, true)
236
-
237
- unsafe_name = el.attributes["tag"]
238
- name = Hobo::Dryml.unreserve(unsafe_name)
239
- if (for_type = el.attributes['for'])
235
+ def define_polymorphic_dispatcher(el, name)
236
+ # FIXME: The new erb context ends up being set-up twice
237
+ src = %(
238
+ def #{name}(attributes={}, parameters={})
239
+ _tag_context(attributes) do
240
+ attributes.delete :with
241
+ attributes.delete :field
242
+ call_polymorphic_tag('#{name}', attributes, parameters) { #{name}__base(attributes.except, parameters) }
243
+ end
244
+ end
245
+ )
246
+ @builder.add_build_instruction(:eval, :src => src, :line_num => element_line_num(el))
247
+ end
248
+
249
+
250
+ def extend_element(el)
251
+ def_element(el, true)
252
+ end
253
+
254
+
255
+ def type_specific_suffix
256
+ el = @def_element
257
+ for_type = el.attributes['for']
258
+ if for_type
240
259
  type_name = if defined?(HoboFields) && for_type =~ /^[a-z]/
241
260
  # It's a symbolic type name - look up the Ruby type name
242
- klass = HoboFields.to_class(for_type)
243
- dryml_exception("No such type in polymorphic tag definition: '#{for_type}'", el) unless klass
261
+ klass = HoboFields.to_class(for_type) or
262
+ dryml_exception("No such type in polymorphic tag definition: '#{for_type}'", el)
244
263
  klass.name
245
264
  elsif for_type =~ /^_.*_$/
246
265
  rename_class(for_type)
247
266
  else
248
267
  for_type
249
268
  end.underscore.gsub('/', '__')
250
- suffix = "__for_#{type_name}"
269
+ "__for_#{type_name}"
270
+ end
271
+ end
272
+
273
+
274
+ def def_element(el, extend_tag=false)
275
+ require_toplevel(el)
276
+ require_attribute(el, "tag", DRYML_NAME_RX)
277
+ require_attribute(el, "attrs", /^\s*#{DRYML_NAME}(\s*,\s*#{DRYML_NAME})*\s*$/, true)
278
+ require_attribute(el, "alias-of", DRYML_NAME_RX, true)
279
+
280
+ @def_element = el
281
+
282
+ unsafe_name = el.attributes["tag"]
283
+ name = Hobo::Dryml.unreserve(unsafe_name)
284
+ suffix = type_specific_suffix
285
+ if suffix
251
286
  name += suffix
252
287
  unsafe_name += suffix
253
288
  end
254
289
 
255
- @def_element = el
256
-
257
- alias_of = el.attributes['alias-of']
258
- extend_with = el.attributes['extend-with']
290
+ if el.attributes['polymorphic']
291
+ %w(for alias-of).each do |attr|
292
+ dryml_exception("def cannot have both 'polymorphic' and '#{attr}' attributes") if el.attributes[attr]
293
+ end
294
+
295
+ define_polymorphic_dispatcher(el, ruby_name(name))
296
+ name += "__base"
297
+ unsafe_name += "__base"
298
+ end
259
299
 
260
- dryml_exception("def cannot have both alias-of and extend-with", el) if alias_of && extend_with
300
+ alias_of = el.attributes['alias-of']
261
301
  dryml_exception("def with alias-of must be empty", el) if alias_of and el.size > 0
262
-
263
-
264
- @builder.add_build_instruction(:alias_method,
265
- :new => ruby_name(name).to_sym,
266
- :old => ruby_name(Hobo::Dryml.unreserve(alias_of)).to_sym) if alias_of
267
-
302
+
303
+ alias_of and @builder.add_build_instruction(:alias_method,
304
+ :new => ruby_name(name).to_sym,
305
+ :old => ruby_name(Hobo::Dryml.unreserve(alias_of)).to_sym)
306
+
268
307
  res = if alias_of
269
308
  "<% #{tag_newlines(el)} %>"
270
309
  else
271
- src = ""
272
- if extend_with
273
- src << "<% delayed_alias_method_chain :#{ruby_name name}, :#{ruby_name extend_with} %>"
274
- name = "#{name}-with-#{extend_with}"
275
- end
276
- src << tag_method(name, el) +
310
+ src = tag_method(name, el, extend_tag) +
277
311
  "<% _register_tag_attrs(:#{ruby_name name}, #{declared_attributes(el).inspect.underscore}) %>"
278
-
312
+
279
313
  logger.debug(restore_erb_scriptlets(src)) if el.attributes["debug-source"]
280
-
314
+
281
315
  @builder.add_build_instruction(:def,
282
316
  :src => restore_erb_scriptlets(src),
283
317
  :line_num => element_line_num(el))
@@ -287,47 +321,56 @@ module Hobo::Dryml
287
321
  @def_element = nil
288
322
  res
289
323
  end
290
-
291
-
324
+
325
+
292
326
  def param_names_in_definition(el)
293
327
  REXML::XPath.match(el, ".//*[@param]").map do |e|
294
328
  name = get_param_name(e)
295
- dryml_exception("invalid param name: #{name.inspect}", e) unless
329
+ dryml_exception("invalid param name: #{name.inspect}", e) unless
296
330
  is_code_attribute?(name) || name =~ RUBY_NAME_RX || name =~ /#\{/
297
331
  name.to_sym unless is_code_attribute?(name)
298
332
  end.compact
299
333
  end
300
-
301
-
302
- def tag_method(name, el)
334
+
335
+
336
+ def tag_method(name, el, extend_tag=false)
337
+ name = ruby_name name
303
338
  param_names = param_names_in_definition(el)
304
339
 
305
- "<% def #{ruby_name name}(all_attributes={}, all_parameters={}); " +
340
+ if extend_tag
341
+ @extend_key = 'a' + Digest::SHA1.hexdigest(el.to_s)[0..10]
342
+ alias_statement = "; alias_method_chain_on_include :#{name}, :#{@extend_key}"
343
+ name = "#{name}_with_#{@extend_key}"
344
+ end
345
+
346
+ src = "<% def #{name}(all_attributes={}, all_parameters={}); " +
306
347
  "parameters = Hobo::Dryml::TagParameters.new(all_parameters, #{param_names.inspect.underscore}); " +
307
348
  "all_parameters = Hobo::Dryml::TagParameters.new(all_parameters); " +
308
349
  tag_method_body(el) +
309
- "; end %>"
350
+ "; end#{alias_statement} %>"
351
+ @extend_key = nil
352
+ src
310
353
  end
311
-
312
-
354
+
355
+
313
356
  def tag_method_body(el)
314
357
  attrs = declared_attributes(el)
315
-
358
+
316
359
  # A statement to assign values to local variables named after the tag's attrs
317
360
  # The trailing comma on `attributes` is supposed to be there!
318
361
  setup_locals = attrs.map{|a| "#{Hobo::Dryml.unreserve(a).underscore}, "}.join + "attributes, = " +
319
362
  "_tag_locals(all_attributes, #{attrs.inspect})"
320
363
 
321
364
  start = "_tag_context(all_attributes) do #{setup_locals}"
322
-
365
+
323
366
  "#{start} " +
324
367
  # reproduce any line breaks in the start-tag so that line numbers are preserved
325
368
  tag_newlines(el) + "%>" +
326
369
  wrap_tag_method_body_with_metadata(children_to_erb(el)) +
327
370
  "<% _erbout; end"
328
371
  end
329
-
330
-
372
+
373
+
331
374
  def wrap_source_with_metadata(content, kind, name, *args)
332
375
  if (!include_source_metadata) || name.in?(NO_METADATA_TAGS)
333
376
  content
@@ -336,32 +379,35 @@ module Hobo::Dryml
336
379
  "<!--[DRYML|#{metadata * '|'}[-->" + content + "<!--]DRYML]-->"
337
380
  end
338
381
  end
339
-
340
-
382
+
383
+
341
384
  def wrap_tag_method_body_with_metadata(content)
342
385
  name = @def_element.attributes['tag']
343
- extend = @def_element.attributes['extend-with']
344
386
  for_ = @def_element.attributes['for']
345
- name = extend ? "#{name}-with-#{extend}" : name
346
387
  name += " for #{for_}" if for_
347
388
  wrap_source_with_metadata(content, "def", name, element_line_num(@def_element))
348
389
  end
349
-
350
-
390
+
391
+
351
392
  def wrap_tag_call_with_metadata(el, content)
352
393
  name = el.expanded_name
353
394
  param = el.attributes['param']
354
-
395
+
355
396
  if param == "&true"
356
397
  name += " param"
357
398
  elsif param
358
- name += " param='#{param}'"
399
+ name += " param='#{param}'"
359
400
  end
360
-
401
+
361
402
  wrap_source_with_metadata(content, "call", name, element_line_num(el))
362
403
  end
363
-
364
-
404
+
405
+
406
+ def param_content_local_name(name)
407
+ "_#{ruby_name name}__default_content"
408
+ end
409
+
410
+
365
411
  def param_content_element(name_or_el)
366
412
  name = if name_or_el.is_a?(String)
367
413
  name_or_el
@@ -376,7 +422,7 @@ module Hobo::Dryml
376
422
 
377
423
  def part_element(el, content)
378
424
  require_attribute(el, "part", DRYML_NAME_RX)
379
-
425
+
380
426
  if contains_param?(el)
381
427
  delegated_part_element(el, content)
382
428
  else
@@ -384,13 +430,13 @@ module Hobo::Dryml
384
430
  end
385
431
  end
386
432
 
387
-
433
+
388
434
  def simple_part_element(el, content)
389
435
  part_name = el.attributes['part']
390
436
  dom_id = el.attributes['id'] || part_name
391
437
  part_name = ruby_name(part_name)
392
438
  part_locals = el.attributes["part-locals"]
393
-
439
+
394
440
  part_src = "<% def #{part_name}_part(#{part_locals._?.gsub('@', '')}) #{tag_newlines(el)}; new_context do %>" +
395
441
  content +
396
442
  "<% end; end %>"
@@ -400,31 +446,36 @@ module Hobo::Dryml
400
446
  args = [attribute_to_ruby(dom_id), ":#{part_name}", "nil", part_locals].compact
401
447
  "<%= call_part(#{args * ', '}) #{newlines} %>"
402
448
  end
403
-
404
-
449
+
450
+
405
451
  def delegated_part_element(el, content)
406
- # TODO
452
+ # TODO
407
453
  end
408
-
409
-
454
+
455
+
410
456
  def contains_param?(el)
411
457
  # TODO
412
458
  false
413
459
  end
414
-
415
-
460
+
461
+
416
462
  def part_delegate_tag_name(el)
417
463
  "#{@def_name}_#{el.attributes['part']}__part_delegate"
418
464
  end
419
465
 
420
466
 
467
+ def current_def_name
468
+ @def_element && @def_element.attributes['tag']
469
+ end
470
+
471
+
421
472
  def get_param_name(el)
422
473
  param_name = el.attributes["param"]
423
-
474
+
424
475
  if param_name
425
- def_tag = find_ancestor(el) {|e| e.name == "def"}
476
+ def_tag = find_ancestor(el) {|e| e.name == "def" || e.name == "extend" }
426
477
  dryml_exception("param is not allowed outside of tag definitions", el) if def_tag.nil?
427
-
478
+
428
479
  ruby_name(param_name == "&true" ? el.dryml_name : param_name)
429
480
  else
430
481
  nil
@@ -432,12 +483,37 @@ module Hobo::Dryml
432
483
  end
433
484
 
434
485
 
486
+ def inside_def_for_type?
487
+ @def_element && @def_element.attributes['for']
488
+ end
489
+
490
+
435
491
  def call_name(el)
436
492
  dryml_exception("invalid tag name", el) unless el.dryml_name =~ /^#{DRYML_NAME}(\.#{DRYML_NAME})*$/
437
- Hobo::Dryml.unreserve(ruby_name(el.dryml_name))
493
+
494
+ name = Hobo::Dryml.unreserve(ruby_name(el.dryml_name))
495
+ if call_to_self_from_type_specific_def?(el)
496
+ "#{name}__base"
497
+ elsif old_tag_call?(el)
498
+ name = name[4..-1] # remove 'old-' prefix
499
+ name += type_specific_suffix if inside_def_for_type?
500
+ "#{name}_without_#{@extend_key}"
501
+ else
502
+ name
503
+ end
504
+ end
505
+
506
+
507
+ def old_tag_call?(el)
508
+ @def_element && el.dryml_name == "old-#{current_def_name}"
509
+ end
510
+
511
+
512
+ def call_to_self_from_type_specific_def?(el)
513
+ inside_def_for_type? && el.dryml_name == current_def_name &&!el.attributes['for-type']
438
514
  end
515
+
439
516
 
440
-
441
517
  def polymorphic_call_type(el)
442
518
  t = el.attributes['for-type']
443
519
  if t.nil?
@@ -454,18 +530,18 @@ module Hobo::Dryml
454
530
  dryml_exception("invalid for-type attribute", el)
455
531
  end
456
532
  end
457
-
458
-
533
+
534
+
459
535
  def tag_call(el)
460
536
  name = call_name(el)
461
537
  param_name = get_param_name(el)
462
538
  attributes = tag_attributes(el)
463
539
  newlines = tag_newlines(el)
464
-
540
+
465
541
  parameters = tag_newlines(el) + parameter_tags_hash(el)
466
-
542
+
467
543
  is_param_restore = el.attributes['restore']
468
-
544
+
469
545
  call = if param_name
470
546
  param_name = attribute_to_ruby(param_name, :symbolize => true)
471
547
  args = "#{attributes}, #{parameters}, all_parameters, #{param_name}"
@@ -502,18 +578,18 @@ module Hobo::Dryml
502
578
  call = maybe_make_part_call(el, "<% _output(#{call}) %>")
503
579
  wrap_tag_call_with_metadata(el, call)
504
580
  end
505
-
506
-
581
+
582
+
507
583
  def merge_attribute(el)
508
584
  merge = el.attributes['merge']
509
585
  dryml_exception("merge cannot have a RHS", el) if merge && merge != "&true"
510
586
  merge
511
587
  end
512
-
588
+
513
589
 
514
590
  def parameter_tags_hash(el, containing_tag_name=nil)
515
591
  call_type = nil
516
-
592
+
517
593
  metadata_name = containing_tag_name || el.expanded_name
518
594
 
519
595
  param_items = el.map do |node|
@@ -528,7 +604,7 @@ module Hobo::Dryml
528
604
  when REXML::Element
529
605
  e = node
530
606
  is_parameter_tag = e.parameter_tag?
531
-
607
+
532
608
  # Make sure there isn't a mix of parameter tags and normal content
533
609
  case call_type
534
610
  when nil
@@ -538,19 +614,21 @@ module Hobo::Dryml
538
614
  when :default_param_only
539
615
  dryml_exception("mixed parameter tags and non-parameter tags", el) if is_parameter_tag
540
616
  end
541
-
617
+
542
618
  if is_parameter_tag
543
619
  parameter_tag_hash_item(e, metadata_name) + ", "
544
620
  end
545
621
  end
546
622
  end.join
547
-
548
- if call_type == :default_param_only || (el.children.empty? && el.has_end_tag?)
623
+
624
+ if call_type == :default_param_only || (call_type.nil? && param_items.length > 0) || (el.children.empty? && el.has_end_tag?)
549
625
  with_containing_tag_name(el) do
550
626
  param_items = " :default => #{default_param_proc(el, containing_tag_name)}, "
551
627
  end
552
628
  end
553
629
 
630
+ param_items.concat without_parameters(el)
631
+
554
632
  merge_params = el.attributes['merge-params'] || merge_attribute(el)
555
633
  if merge_params
556
634
  extra_params = if merge_params == "&true"
@@ -567,6 +645,12 @@ module Hobo::Dryml
567
645
  end
568
646
  end
569
647
 
648
+
649
+ def without_parameters(el)
650
+ without_names = el.attributes.keys.map { |name| name =~ /^without-(.*)/ and $1 }.compact
651
+ without_names.map { |name| ":#{ruby_name name}_replacement => proc {|__discard__| '' }, " }.join
652
+ end
653
+
570
654
 
571
655
  def parameter_tag_hash_item(el, metadata_name)
572
656
  name = el.name.dup
@@ -588,8 +672,8 @@ module Hobo::Dryml
588
672
  end
589
673
  end
590
674
  end
591
-
592
-
675
+
676
+
593
677
  def before_parameter_tag_hash_item(name, el, metadata_name)
594
678
  param_name = get_param_name(el)
595
679
  dryml_exception("param declaration not allowed on 'before' parameters", el) if param_name
@@ -597,59 +681,63 @@ module Hobo::Dryml
597
681
  ":#{ruby_name name}_replacement => #{replace_parameter_proc(el, metadata_name, content)}"
598
682
  end
599
683
 
600
-
684
+
601
685
  def after_parameter_tag_hash_item(name, el, metadata_name)
602
686
  param_name = get_param_name(el)
603
687
  dryml_exception("param declaration not allowed on 'after' parameters", el) if param_name
604
- content = "<% _output(#{param_restore_local_name(name)}.call({}, {})) %>" + children_to_erb(el)
688
+ content = "<% _output(#{param_restore_local_name(name)}.call({}, {})) %>" + children_to_erb(el)
605
689
  ":#{ruby_name name}_replacement => #{replace_parameter_proc(el, metadata_name, content)}"
606
690
  end
607
-
608
-
691
+
692
+
609
693
  def append_parameter_tag_hash_item(name, el, metadata_name)
610
- ":#{ruby_name name} => proc { [{}, { :default => proc { |#{param_content_local_name(name)}| new_context { %>" +
694
+ ":#{ruby_name name} => proc { [{}, { :default => proc { |#{param_content_local_name(name)}| new_context { %>" +
611
695
  param_content_element(name) + children_to_erb(el) +
612
696
  "<% } } } ] }"
613
697
  end
614
-
615
-
698
+
699
+
616
700
  def prepend_parameter_tag_hash_item(name, el, metadata_name)
617
- ":#{ruby_name name} => proc { [{}, { :default => proc { |#{param_content_local_name(name)}| new_context { %>" +
701
+ ":#{ruby_name name} => proc { [{}, { :default => proc { |#{param_content_local_name(name)}| new_context { %>" +
618
702
  children_to_erb(el) + param_content_element(name) +
619
703
  "<% } } } ] }"
620
704
  end
621
705
 
622
-
706
+
623
707
  def default_param_proc(el, containing_param_name=nil)
624
708
  content = children_to_erb(el)
625
709
  content = wrap_source_with_metadata(content, "param", containing_param_name,
626
710
  element_line_num(el)) if containing_param_name
627
711
  "proc { |#{param_content_local_name(el.dryml_name)}| new_context { %>#{content}<% } #{tag_newlines(el)}}"
628
712
  end
629
-
630
-
713
+
714
+
631
715
  def param_restore_local_name(name)
632
716
  "_#{ruby_name name}_restore"
633
717
  end
634
-
635
-
718
+
719
+
636
720
  def wrap_replace_parameter(el, name)
637
721
  wrap_source_with_metadata(children_to_erb(el), "replace", name, element_line_num(el))
638
722
  end
639
-
640
-
723
+
724
+
641
725
  def param_proc(el, metadata_name_prefix)
642
726
  metadata_name = "#{metadata_name_prefix}><#{el.name}"
643
-
727
+
644
728
  nl = tag_newlines(el)
645
-
729
+
646
730
  if (repl = el.attribute("replace"))
647
731
  dryml_exception("replace attribute must not have a value", el) if repl.has_rhs?
648
732
  dryml_exception("replace parameters must not have attributes", el) if el.attributes.length > 1
649
-
733
+
650
734
  replace_parameter_proc(el, metadata_name)
651
735
  else
652
- attributes = el.attributes.map do |name, value|
736
+ attributes = el.attributes.dup
737
+ # Providing one of 'with' or 'field' but not the other should cancel out the other
738
+ attributes[:with] = "&nil" if attributes.key?(:field) && !attributes.key?(:with)
739
+ attributes[:field] = "&nil" if !attributes.key?(:field) && attributes.key?(:with)
740
+ attribute_items = attributes.map do |name, value|
653
741
  if name.in?(VALID_PARAMETER_TAG_ATTRIBUTES)
654
742
  # just ignore
655
743
  elsif name.in?(SPECIAL_ATTRIBUTES)
@@ -658,56 +746,51 @@ module Hobo::Dryml
658
746
  ":#{ruby_name name} => #{attribute_to_ruby(value, el)}"
659
747
  end
660
748
  end.compact
661
-
749
+
662
750
  nested_parameters_hash = parameter_tags_hash(el, metadata_name)
663
- "proc { [{#{attributes * ', '}}, #{nested_parameters_hash}] #{nl}}"
751
+ "proc { [{#{attribute_items * ', '}}, #{nested_parameters_hash}] #{nl}}"
664
752
  end
665
753
  end
666
-
667
-
754
+
755
+
668
756
  def replace_parameter_proc(el, metadata_name, content=nil)
669
757
  content ||= wrap_replace_parameter(el, metadata_name)
670
758
  param_name = el.dryml_name.sub(/^(before|after|append|prepend)-/, "")
671
759
  "proc { |#{param_restore_local_name(param_name)}| new_context { %>#{content}<% } #{tag_newlines(el)}}"
672
760
  end
673
-
674
-
675
- def param_content_local_name(name)
676
- "_#{ruby_name name}__default_content"
677
- end
678
-
679
-
761
+
762
+
680
763
  def maybe_make_part_call(el, call)
681
764
  part_name = el.attributes['part']
682
765
  if part_name
683
766
  part_id = part_name && "<%= #{attribute_to_ruby(el.attributes['id'] || part_name)} %>"
684
- "<span class='part-wrapper' id='#{part_id}'>" + part_element(el, call) + "</span>"
767
+ "<div class='part-wrapper' id='#{part_id}'>" + part_element(el, call) + "</div>"
685
768
  else
686
769
  call
687
770
  end
688
771
  end
689
-
690
-
772
+
773
+
691
774
  def field_shorthand_element?(el)
692
775
  el.expanded_name =~ /:./
693
776
  end
694
-
695
-
777
+
778
+
696
779
  def tag_attributes(el)
697
780
  attributes = el.attributes
698
781
  items = attributes.map do |n,v|
699
782
  dryml_exception("invalid attribute name '#{n}'", el) unless n =~ DRYML_NAME_RX
700
-
701
- unless n.in?(SPECIAL_ATTRIBUTES)
783
+
784
+ unless n.in?(SPECIAL_ATTRIBUTES) || n =~ /^without-/
702
785
  ":#{ruby_name n} => #{attribute_to_ruby(v)}"
703
786
  end
704
787
  end.compact
705
-
788
+
706
789
  # if there's a ':' el.name is just the part after the ':'
707
790
  items << ":field => \"#{ruby_name el.name}\"" if field_shorthand_element?(el)
708
-
791
+
709
792
  items = items.join(", ")
710
-
793
+
711
794
  merge_attrs = attributes['merge-attrs'] || merge_attribute(el)
712
795
  if merge_attrs
713
796
  extra_attributes = if merge_attrs == "&true"
@@ -730,46 +813,46 @@ module Hobo::Dryml
730
813
  val = restore_erb_scriptlets(v).gsub('"', '\"').gsub(/<%=(.*?)%>/, '#{\1}')
731
814
  %('#{n}' => "#{val}")
732
815
  end.compact
733
-
816
+
734
817
  # If there's a part but no id, the id defaults to the part name
735
818
  if part && !el.attributes["id"]
736
819
  attrs << ":id => '#{part}'"
737
820
  end
738
-
821
+
739
822
  # Convert the attributes hash to a call to merge_attrs if
740
823
  # there's a merge-attrs attribute
741
824
  attrs = if (merge_attrs = el.attributes['merge-attrs'])
742
825
  dryml_exception("merge-attrs was given a string", el) unless is_code_attribute?(merge_attrs)
743
-
826
+
744
827
  "merge_attrs({#{attrs * ', '}}, " +
745
828
  "((__merge_attrs__ = (#{merge_attrs[1..-1]})) == true ? attributes : __merge_attrs__))"
746
829
  else
747
830
  "{" + attrs.join(', ') + "}"
748
831
  end
749
-
832
+
750
833
  if el.children.empty?
751
834
  dryml_exception("part attribute on empty static tag", el) if part
752
835
 
753
- "<%= " + apply_control_attributes("element(:#{el.name}, #{attrs} #{tag_newlines(el)})", el) + " %>"
836
+ "<%= " + apply_control_attributes("element(:#{el.name}, #{attrs}, nil, true, #{!el.has_end_tag?} #{tag_newlines(el)})", el) + " %>"
754
837
  else
755
838
  if part
756
839
  body = part_element(el, children_to_erb(el))
757
840
  else
758
- body = children_to_erb(el)
841
+ body = children_to_erb(el)
759
842
  end
760
843
 
761
844
  output_tag = "element(:#{el.name}, #{attrs}, new_context { %>#{body}<% })"
762
845
  "<% _output(" + apply_control_attributes(output_tag, el) + ") %>"
763
846
  end
764
847
  end
765
-
766
-
848
+
849
+
767
850
  def static_element_to_erb(el)
768
851
  if promote_static_tag_to_method_call?(el)
769
852
  static_tag_to_method_call(el)
770
853
  else
771
854
  start_tag_src = el.start_tag_source.gsub(REXML::CData::START, "").gsub(REXML::CData::STOP, "")
772
-
855
+
773
856
  # Allow #{...} as an alternate to <%= ... %>
774
857
  start_tag_src.gsub!(/=\s*('.*?'|".*?")/) do |s|
775
858
  s.gsub(/#\{(.*?)\}/, '<%= \1 %>')
@@ -782,19 +865,19 @@ module Hobo::Dryml
782
865
  end
783
866
  end
784
867
  end
785
-
786
-
868
+
869
+
787
870
  def promote_static_tag_to_method_call?(el)
788
871
  %w(part merge-attrs if unless repeat).any? {|x| el.attributes[x]}
789
872
  end
790
-
791
-
873
+
874
+
792
875
  def apply_control_attributes(expression, el)
793
876
  controls = %w(if unless repeat).map_hash { |x| el.attributes[x] }.compact
794
-
877
+
795
878
  dryml_exception("You can't have multiple control attributes on the same element", el) if
796
879
  controls.length > 1
797
-
880
+
798
881
  attr = controls.keys.first
799
882
  val = controls.values.first
800
883
  if val.nil?
@@ -805,15 +888,15 @@ module Hobo::Dryml
805
888
  elsif is_code_attribute?(val)
806
889
  "#{val[1..-1]}"
807
890
  else
808
- "this.#{val}"
891
+ attr == "repeat" ? %("#{val}") : "this.#{val}"
809
892
  end
810
-
893
+
811
894
  x = gensym
812
895
  case attr
813
896
  when "if"
814
897
  "(if !(#{control}).blank?; (#{x} = #{expression}; Hobo::Dryml.last_if = true; #{x}) " +
815
898
  "else (Hobo::Dryml.last_if = false; ''); end)"
816
- when "unless"
899
+ when "unless"
817
900
  "(if (#{control}).blank?; (#{x} = #{expression}; Hobo::Dryml.last_if = true; #{x}) " +
818
901
  "else (Hobo::Dryml.last_if = false; ''); end)"
819
902
  when "repeat"
@@ -821,12 +904,12 @@ module Hobo::Dryml
821
904
  end
822
905
  end
823
906
  end
824
-
907
+
825
908
 
826
909
  def attribute_to_ruby(*args)
827
910
  options = args.extract_options!
828
911
  attr, el = args
829
-
912
+
830
913
  dryml_exception('erb scriptlet not allowed in this attribute (use #{ ... } instead)', el) if
831
914
  attr.is_a?(String) && attr.index("[![HOBO-ERB")
832
915
 
@@ -845,8 +928,7 @@ module Hobo::Dryml
845
928
  else
846
929
  dryml_exception("invalid quote(s) in attribute value")
847
930
  end
848
- #attr.starts_with?("++") ? "attr_extension(#{str})" : str
849
- end
931
+ end
850
932
  options[:symbolize] ? (res + ".to_sym") : res
851
933
  end
852
934
  end
@@ -895,17 +977,17 @@ module Hobo::Dryml
895
977
  def logger
896
978
  ActionController::Base.logger rescue nil
897
979
  end
898
-
980
+
899
981
  def gensym(name="__tmp")
900
982
  @gensym_counter ||= 0
901
983
  @gensym_counter += 1
902
984
  "#{name}_#{@gensym_counter}"
903
985
  end
904
-
986
+
905
987
  def rename_class(name)
906
988
  @bundle && name.starts_with?("_") ? @bundle.send(name) : name
907
989
  end
908
-
990
+
909
991
  def include_source_metadata
910
992
  # disabled for now -- we're still getting broken rendering with this feature on
911
993
  return false