fortitude 0.0.1

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 (332) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.rspec-local +4 -0
  4. data/.travis.yml +26 -0
  5. data/Gemfile +5 -0
  6. data/LICENSE.txt +22 -0
  7. data/README-erector.md +246 -0
  8. data/README.md +15 -0
  9. data/Rakefile +67 -0
  10. data/ext/FortitudeJrubyNativeExtService.java +11 -0
  11. data/ext/com/fortituderuby/ext/fortitude/FortitudeNativeLibrary.java +223 -0
  12. data/ext/fortitude_native_ext/extconf.rb +4 -0
  13. data/ext/fortitude_native_ext/fortitude_native_ext.c +333 -0
  14. data/fortitude.gemspec +37 -0
  15. data/lib/fortitude/assign_locals_from_template.rb.smpl +22 -0
  16. data/lib/fortitude/assigns_proxy.rb +75 -0
  17. data/lib/fortitude/class_inheritable_attributes.rb +96 -0
  18. data/lib/fortitude/doctypes/base.rb +38 -0
  19. data/lib/fortitude/doctypes/html4.rb +20 -0
  20. data/lib/fortitude/doctypes/html4_frameset.rb +18 -0
  21. data/lib/fortitude/doctypes/html4_strict.rb +17 -0
  22. data/lib/fortitude/doctypes/html4_tags_frameset.rb +52 -0
  23. data/lib/fortitude/doctypes/html4_tags_strict.rb +273 -0
  24. data/lib/fortitude/doctypes/html4_tags_transitional.rb +114 -0
  25. data/lib/fortitude/doctypes/html4_transitional.rb +18 -0
  26. data/lib/fortitude/doctypes/html5.rb +372 -0
  27. data/lib/fortitude/doctypes/unknown_doctype.rb +19 -0
  28. data/lib/fortitude/doctypes/xhtml10.rb +19 -0
  29. data/lib/fortitude/doctypes/xhtml10_frameset.rb +17 -0
  30. data/lib/fortitude/doctypes/xhtml10_strict.rb +17 -0
  31. data/lib/fortitude/doctypes/xhtml10_transitional.rb +17 -0
  32. data/lib/fortitude/doctypes/xhtml11.rb +29 -0
  33. data/lib/fortitude/doctypes.rb +46 -0
  34. data/lib/fortitude/errors.rb +153 -0
  35. data/lib/fortitude/fortitude_ruby_ext.rb +71 -0
  36. data/lib/fortitude/instance_variable_set.rb +74 -0
  37. data/lib/fortitude/need_assignment_template.rb.smpl +16 -0
  38. data/lib/fortitude/need_method_template.rb.smpl +4 -0
  39. data/lib/fortitude/non_rails_widget_methods.rb +15 -0
  40. data/lib/fortitude/partial_tag_placeholder.rb +17 -0
  41. data/lib/fortitude/rails/helpers.rb +153 -0
  42. data/lib/fortitude/rails/renderer.rb +43 -0
  43. data/lib/fortitude/rails/template_handler.rb +23 -0
  44. data/lib/fortitude/rails/widget_methods.rb +17 -0
  45. data/lib/fortitude/rails/yielded_object_outputter.rb +31 -0
  46. data/lib/fortitude/railtie.rb +254 -0
  47. data/lib/fortitude/rendering_context.rb +205 -0
  48. data/lib/fortitude/simple_template.rb +45 -0
  49. data/lib/fortitude/staticized_method.rb +85 -0
  50. data/lib/fortitude/tag.rb +162 -0
  51. data/lib/fortitude/tag_method_template.rb.smpl +68 -0
  52. data/lib/fortitude/tag_return_value.rb +11 -0
  53. data/lib/fortitude/tag_store.rb +48 -0
  54. data/lib/fortitude/tag_support.rb +48 -0
  55. data/lib/fortitude/tags_module.rb +14 -0
  56. data/lib/fortitude/text_method_template.rb.smpl +17 -0
  57. data/lib/fortitude/tilt/fortitude_template.rb +169 -0
  58. data/lib/fortitude/version.rb +3 -0
  59. data/lib/fortitude/widget.rb +904 -0
  60. data/lib/fortitude/widgets/html4_frameset.rb +9 -0
  61. data/lib/fortitude/widgets/html4_strict.rb +9 -0
  62. data/lib/fortitude/widgets/html4_transitional.rb +9 -0
  63. data/lib/fortitude/widgets/html5.rb +9 -0
  64. data/lib/fortitude/widgets/xhtml10_frameset.rb +9 -0
  65. data/lib/fortitude/widgets/xhtml10_strict.rb +9 -0
  66. data/lib/fortitude/widgets/xhtml10_transitional.rb +9 -0
  67. data/lib/fortitude/widgets/xhtml11.rb +9 -0
  68. data/lib/fortitude.rb +93 -0
  69. data/lib/fortitude_jruby_native_ext.jar +0 -0
  70. data/spec/helpers/global_helper.rb +8 -0
  71. data/spec/helpers/rails_helpers.rb +85 -0
  72. data/spec/helpers/rails_server.rb +386 -0
  73. data/spec/helpers/system_helpers.rb +117 -0
  74. data/spec/rails/basic_rails_system_spec.rb +7 -0
  75. data/spec/rails/capture_system_spec.rb +75 -0
  76. data/spec/rails/class_loading_system_spec.rb +63 -0
  77. data/spec/rails/complex_helpers_system_spec.rb +33 -0
  78. data/spec/rails/data_passing_system_spec.rb +96 -0
  79. data/spec/rails/default_layout_system_spec.rb +15 -0
  80. data/spec/rails/development_mode_system_spec.rb +67 -0
  81. data/spec/rails/erb_integration_system_spec.rb +23 -0
  82. data/spec/rails/helpers_include_all_off_system_spec.rb +7 -0
  83. data/spec/rails/helpers_system_spec.rb +79 -0
  84. data/spec/rails/helpers_unrefined_system_spec.rb +7 -0
  85. data/spec/rails/layouts_system_spec.rb +60 -0
  86. data/spec/rails/localization_system_spec.rb +38 -0
  87. data/spec/rails/production_mode_system_spec.rb +13 -0
  88. data/spec/rails/rendering_context_system_spec.rb +64 -0
  89. data/spec/rails/rendering_system_spec.rb +158 -0
  90. data/spec/rails/rules_system_spec.rb +23 -0
  91. data/spec/rails/static_method_system_spec.rb +12 -0
  92. data/spec/rails/templates/base/app/controllers/application_controller.rb +15 -0
  93. data/spec/rails/templates/base/app/controllers/working_controller.rb +5 -0
  94. data/spec/rails/templates/base/app/views/layouts/application.html.erb +11 -0
  95. data/spec/rails/templates/base/config/routes.rb +4 -0
  96. data/spec/rails/templates/base/config/secrets.yml +22 -0
  97. data/spec/rails/templates/basic_rails_system_spec/app/controllers/basic_rails_system_spec_controller.rb +8 -0
  98. data/spec/rails/templates/basic_rails_system_spec/app/views/basic_rails_system_spec/trivial_widget.rb +5 -0
  99. data/spec/rails/templates/capture_system_spec/app/controllers/capture_system_spec_controller.rb +37 -0
  100. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/_some_erb_partial.html.erb +1 -0
  101. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/another_widget.rb +7 -0
  102. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/capture_erb_from_widget.rb +11 -0
  103. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/capture_widget_from_erb.html.erb +9 -0
  104. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/capture_widget_from_widget.rb +17 -0
  105. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/some_widget.rb +5 -0
  106. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/widget_content_for.rb +19 -0
  107. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/widget_layout_needing_content_yield_with_erb.html.erb +13 -0
  108. data/spec/rails/templates/capture_system_spec/app/views/capture_system_spec/widget_provide.rb +13 -0
  109. data/spec/rails/templates/capture_system_spec/app/views/layouts/erb_layout_needing_content.html.erb +15 -0
  110. data/spec/rails/templates/capture_system_spec/app/views/layouts/widget_layout_needing_content_content_for.rb +23 -0
  111. data/spec/rails/templates/capture_system_spec/app/views/layouts/widget_layout_needing_content_yield.rb +23 -0
  112. data/spec/rails/templates/class_loading_system_spec/app/controllers/class_loading_system_spec_controller.rb +74 -0
  113. data/spec/rails/templates/class_loading_system_spec/app/models/views/app_models_helper.rb +5 -0
  114. data/spec/rails/templates/class_loading_system_spec/app/models/views/models_widget.rb +5 -0
  115. data/spec/rails/templates/class_loading_system_spec/app/views/autoload_namespace/autoload_widget.rb +11 -0
  116. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/_loaded_underscore_widget.rb +11 -0
  117. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/_underscore_view.rb +5 -0
  118. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/_underscore_widget.rb +11 -0
  119. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/app_models.rb +6 -0
  120. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/autoload_one_widget_from_another.rb +7 -0
  121. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/class_should_not_load.rb +9 -0
  122. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/lib_views.rb +8 -0
  123. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/use_lib_widget_from_view_widget.rb +9 -0
  124. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/use_models_widget_from_view_widget.rb +7 -0
  125. data/spec/rails/templates/class_loading_system_spec/app/views/some_namespace/some_other_namespace/.git_keep +0 -0
  126. data/spec/rails/templates/class_loading_system_spec/app/views/sub_widget.rb +5 -0
  127. data/spec/rails/templates/class_loading_system_spec/lib/arbitrary_name/some_widget.rb +7 -0
  128. data/spec/rails/templates/class_loading_system_spec/lib/views/class_loading_system_spec/lib_views_helper.rb +5 -0
  129. data/spec/rails/templates/class_loading_system_spec/lib/views/class_loading_system_spec/widget_defined_outside_app_views.rb +5 -0
  130. data/spec/rails/templates/class_loading_system_spec/lib/views/lib_widget.rb +5 -0
  131. data/spec/rails/templates/complex_helpers_system_spec/app/controllers/complex_helpers_system_spec_controller.rb +14 -0
  132. data/spec/rails/templates/complex_helpers_system_spec/app/views/complex_helpers_system_spec/cache_test.rb +12 -0
  133. data/spec/rails/templates/complex_helpers_system_spec/app/views/complex_helpers_system_spec/fields_for_test.rb +14 -0
  134. data/spec/rails/templates/complex_helpers_system_spec/app/views/complex_helpers_system_spec/form_for_test.rb +14 -0
  135. data/spec/rails/templates/complex_helpers_system_spec/config/environments/development.rb +31 -0
  136. data/spec/rails/templates/data_passing_system_spec/app/controllers/data_passing_system_spec_controller.rb +101 -0
  137. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/_erb_to_parallel_widget_handoff_erb.html.erb +3 -0
  138. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/_implicit_erb_to_widget_handoff_erb.html.erb +3 -0
  139. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/_implicit_variable_write_erb.html.erb +1 -0
  140. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/_widget_to_parallel_erb_handoff_erb.html.erb +1 -0
  141. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/erb_copied_variables.html.erb +1 -0
  142. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/erb_to_parallel_widget_handoff.html.erb +2 -0
  143. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/erb_to_parallel_widget_handoff_widget.rb +5 -0
  144. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/explicit_controller_variable_read.rb +6 -0
  145. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/extra_variables.rb +23 -0
  146. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/extra_variables_requested.rb +24 -0
  147. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_erb_to_widget_handoff.html.erb +2 -0
  148. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_erb_to_widget_handoff_widget.rb +7 -0
  149. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_shared_variable_access.rb +5 -0
  150. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_shared_variable_access_inheritance.rb +6 -0
  151. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_shared_variable_access_inheritance_child_one.rb +7 -0
  152. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_shared_variable_access_inheritance_child_two.rb +5 -0
  153. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_shared_variable_access_inheritance_parent.rb +3 -0
  154. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_shared_variable_access_inner.rb +8 -0
  155. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_variable_read.rb +5 -0
  156. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_variable_read_inner.rb +7 -0
  157. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_variable_write.html.erb +2 -0
  158. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/implicit_variable_write_widget.rb +7 -0
  159. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/parent_to_child_passing.rb +7 -0
  160. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/parent_to_child_passing_child.rb +7 -0
  161. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/parent_to_child_passing_partial.rb +7 -0
  162. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/parent_to_child_passing_partial_child.rb +7 -0
  163. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/passing_data_widget.rb +8 -0
  164. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/passing_locals_and_controller_variables_widget.rb +9 -0
  165. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/passing_locals_widget.rb +8 -0
  166. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/variables_to_layout.rb +7 -0
  167. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/widget_copied_variables.rb +9 -0
  168. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/widget_to_parallel_erb_handoff.html.erb +2 -0
  169. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/widget_to_parallel_erb_handoff_widget.rb +5 -0
  170. data/spec/rails/templates/data_passing_system_spec/app/views/layouts/data_layout.rb +14 -0
  171. data/spec/rails/templates/default_layout_system_spec/app/controllers/default_layout_system_spec_controller.rb +9 -0
  172. data/spec/rails/templates/default_layout_system_spec/app/views/default_layout_system_spec/erb_with_widget_default_layout.html.erb +1 -0
  173. data/spec/rails/templates/default_layout_system_spec/app/views/default_layout_system_spec/widget_with_widget_default_layout.rb +5 -0
  174. data/spec/rails/templates/default_layout_system_spec/app/views/layouts/application.rb +12 -0
  175. data/spec/rails/templates/development_mode_system_spec/app/controllers/development_mode_system_spec_controller.rb +9 -0
  176. data/spec/rails/templates/development_mode_system_spec/app/views/development_mode_system_spec/reload_widget.rb +7 -0
  177. data/spec/rails/templates/development_mode_system_spec/app/views/development_mode_system_spec/sample_output.rb +9 -0
  178. data/spec/rails/templates/erb_integration_system_spec/app/controllers/erb_integration_system_spec_controller.rb +10 -0
  179. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/_erb_partial_from_widget_partial.html.erb +1 -0
  180. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/_fortitude_partial_with_underscore_partial.rb +5 -0
  181. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/_prefers_erb_partial_partial.html.erb +1 -0
  182. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/erb_partial_from_widget.rb +7 -0
  183. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/erb_to_widget_with_render_partial.html.erb +3 -0
  184. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/erb_to_widget_with_render_partial_widget.rb +5 -0
  185. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/fortitude_partial_with_underscore.html.erb +3 -0
  186. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/prefers_erb_partial.html.erb +3 -0
  187. data/spec/rails/templates/erb_integration_system_spec/app/views/erb_integration_system_spec/prefers_erb_partial_partial.rb +5 -0
  188. data/spec/rails/templates/helpers_include_all_off_system_spec/app/controllers/helpers_include_all_off_system_spec_controller.rb +13 -0
  189. data/spec/rails/templates/helpers_include_all_off_system_spec/app/helpers/application_helper.rb +5 -0
  190. data/spec/rails/templates/helpers_include_all_off_system_spec/app/helpers/some_helper.rb +5 -0
  191. data/spec/rails/templates/helpers_include_all_off_system_spec/app/views/helpers_include_all_off_system_spec/include_all_off.rb +23 -0
  192. data/spec/rails/templates/helpers_include_all_off_system_spec/config/application.rb +28 -0
  193. data/spec/rails/templates/helpers_system_spec/app/controllers/helpers_system_spec_controller.rb +86 -0
  194. data/spec/rails/templates/helpers_system_spec/app/helpers/some_helper.rb +21 -0
  195. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/automatic_helpers_disabled.rb +37 -0
  196. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/automatic_helpers_inheritance.rb +6 -0
  197. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/automatic_helpers_inheritance_child_one.rb +34 -0
  198. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/automatic_helpers_inheritance_child_two.rb +36 -0
  199. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/automatic_helpers_inheritance_parent.rb +4 -0
  200. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/basic_helpers.rb +13 -0
  201. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/block_helpers.rb +7 -0
  202. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/built_in_outputting_helpers.rb +13 -0
  203. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/built_in_outputting_to_returning.rb +8 -0
  204. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/built_in_returning_to_outputting.rb +10 -0
  205. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/controller_helper_method.rb +5 -0
  206. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/controller_helper_module.rb +5 -0
  207. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/custom_helper_outputs.rb +6 -0
  208. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/custom_helpers_basic.rb +5 -0
  209. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/custom_helpers_with_a_block.rb +6 -0
  210. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/custom_outputting_to_returning.rb +7 -0
  211. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/custom_returning_to_outputting.rb +10 -0
  212. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/helper_settings_inheritance.rb +10 -0
  213. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/helper_settings_inheritance_parent.rb +4 -0
  214. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/helpers_that_output_when_refined.rb +9 -0
  215. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/private_helper_erb.html.erb +1 -0
  216. data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/private_helper_fortitude.rb +5 -0
  217. data/spec/rails/templates/helpers_system_spec/lib/some_stuff.rb +5 -0
  218. data/spec/rails/templates/helpers_unrefined_system_spec/app/controllers/helpers_unrefined_system_spec_controller.rb +7 -0
  219. data/spec/rails/templates/helpers_unrefined_system_spec/app/views/helpers_unrefined_system_spec/helpers_that_output_when_refined.rb +9 -0
  220. data/spec/rails/templates/helpers_unrefined_system_spec/config/environments/production.rb +31 -0
  221. data/spec/rails/templates/layouts_system_spec/app/controllers/layouts_system_spec_controller.rb +31 -0
  222. data/spec/rails/templates/layouts_system_spec/app/views/layouts/alternate.html.erb +11 -0
  223. data/spec/rails/templates/layouts_system_spec/app/views/layouts/application.html.erb +26 -0
  224. data/spec/rails/templates/layouts_system_spec/app/views/layouts/explicit_yield.rb +12 -0
  225. data/spec/rails/templates/layouts_system_spec/app/views/layouts/widget_layout.rb +22 -0
  226. data/spec/rails/templates/layouts_system_spec/app/views/layouts_system_spec/erb_inside_widget_layout.html.erb +8 -0
  227. data/spec/rails/templates/layouts_system_spec/app/views/layouts_system_spec/the_render_widget.rb +5 -0
  228. data/spec/rails/templates/layouts_system_spec/app/views/layouts_system_spec/widget_inside_erb_layout.rb +8 -0
  229. data/spec/rails/templates/layouts_system_spec/app/views/layouts_system_spec/widget_inside_widget_layout.rb +8 -0
  230. data/spec/rails/templates/layouts_system_spec/app/views/layouts_system_spec/yield_from_widget_explicitly.rb +5 -0
  231. data/spec/rails/templates/localization_system_spec/app/controllers/localization_system_spec_controller.rb +31 -0
  232. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/content_method.rb +13 -0
  233. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/dot_notation.rb +5 -0
  234. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/explicit_html.rb +13 -0
  235. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/i18n_t.rb +5 -0
  236. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/native_support.rb +7 -0
  237. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/readjust_base.rb +7 -0
  238. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/t.rb +5 -0
  239. data/spec/rails/templates/localization_system_spec/config/locales/en.yml +21 -0
  240. data/spec/rails/templates/localization_system_spec/config/locales/fr.yml +14 -0
  241. data/spec/rails/templates/localization_system_spec/config/locales/pt.yml +2 -0
  242. data/spec/rails/templates/production_mode_system_spec/app/controllers/production_mode_system_spec_controller.rb +5 -0
  243. data/spec/rails/templates/production_mode_system_spec/app/views/production_mode_system_spec/sample_output.rb +9 -0
  244. data/spec/rails/templates/rendering_context_system_spec/app/controllers/rendering_context_system_spec_controller.rb +72 -0
  245. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/_start_end_widget_through_partials_partial.html.erb +1 -0
  246. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/_uses_direct_context_for_all_widgets_partial.html.erb +1 -0
  247. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/_uses_specified_context_through_nesting_partial.html.erb +2 -0
  248. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/render_widget.rb +5 -0
  249. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/start_end_widget_basic.rb +12 -0
  250. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/start_end_widget_basic_inner.rb +7 -0
  251. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/start_end_widget_through_partials.rb +16 -0
  252. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/start_end_widget_through_partials_partial_widget.rb +7 -0
  253. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_direct_context_for_all_widgets.rb +7 -0
  254. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_direct_context_for_all_widgets_widget.rb +5 -0
  255. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_direct_context_in_view.rb +5 -0
  256. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_specified_context_in_partials.html.erb +3 -0
  257. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_specified_context_in_partials_partial.rb +5 -0
  258. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_specified_context_in_view.rb +5 -0
  259. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_specified_context_through_nesting.rb +6 -0
  260. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/uses_specified_context_through_nesting_inner_partial.rb +5 -0
  261. data/spec/rails/templates/rendering_context_system_spec/lib/simple_rc.rb +17 -0
  262. data/spec/rails/templates/rendering_system_spec/app/controllers/rendering_system_spec_controller.rb +111 -0
  263. data/spec/rails/templates/rendering_system_spec/app/views/layouts/application.html.erb +19 -0
  264. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/_layout_for_partial.html.erb +3 -0
  265. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/_the_partial.html.erb +1 -0
  266. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/partial_with_layout.rb +5 -0
  267. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_collection.html.erb +3 -0
  268. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_collection_as.html.erb +3 -0
  269. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_file_from_widget.rb +7 -0
  270. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_html_safe_strings.rb +16 -0
  271. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_inline_from_widget.rb +11 -0
  272. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_object.html.erb +3 -0
  273. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_partial_from_widget.rb +7 -0
  274. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_partial_with_layout.html.erb +3 -0
  275. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_partial_with_widget_layout.html.erb +3 -0
  276. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_template_from_widget.rb +7 -0
  277. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_text_from_widget.rb +7 -0
  278. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/stream_widget.rb +13 -0
  279. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/trivial_widget.rb +5 -0
  280. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/widget_layout_for_partial.rb +7 -0
  281. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/widget_with_name.rb +7 -0
  282. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/word.rb +7 -0
  283. data/spec/rails/templates/rendering_system_spec/app/views/widget_to_render.rb +7 -0
  284. data/spec/rails/templates/rules_system_spec/app/controllers/rules_system_spec_controller.rb +22 -0
  285. data/spec/rails/templates/rules_system_spec/app/views/layouts/fortitude_layout_with_p.rb +19 -0
  286. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/_intervening_partial_erb_partial.html.erb +1 -0
  287. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/intervening_partial.rb +9 -0
  288. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/intervening_partial_fortitude_partial.rb +9 -0
  289. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/invalid_start_tag_in_partial.html.erb +3 -0
  290. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/invalid_start_tag_in_partial_partial.rb +9 -0
  291. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/invalid_start_tag_in_view.rb +9 -0
  292. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/invalidly_nested_tag.rb +11 -0
  293. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/invalidly_nested_tag_in_partial.html.erb +3 -0
  294. data/spec/rails/templates/rules_system_spec/app/views/rules_system_spec/invalidly_nested_tag_in_partial_partial.rb +11 -0
  295. data/spec/rails/templates/static_method_system_spec/app/controllers/static_method_system_spec_controller.rb +15 -0
  296. data/spec/rails/templates/static_method_system_spec/app/helpers/some_helper.rb +10 -0
  297. data/spec/rails/templates/static_method_system_spec/app/views/static_method_system_spec/allows_helper_access.rb +8 -0
  298. data/spec/rails/templates/static_method_system_spec/app/views/static_method_system_spec/localization.rb +7 -0
  299. data/spec/rails/templates/static_method_system_spec/config/locales/en.yml +4 -0
  300. data/spec/rails/templates/static_method_system_spec/config/locales/fr.yml +4 -0
  301. data/spec/system/around_content_system_spec.rb +399 -0
  302. data/spec/system/assigns_system_spec.rb +316 -0
  303. data/spec/system/attribute_rules_system_spec.rb +227 -0
  304. data/spec/system/basic_system_spec.rb +9 -0
  305. data/spec/system/content_inheritance_system_spec.rb +13 -0
  306. data/spec/system/convenience_methods_system_spec.rb +30 -0
  307. data/spec/system/doctypes_system_spec.rb +213 -0
  308. data/spec/system/erector_compatibility_system_spec.rb +84 -0
  309. data/spec/system/escaping_system_spec.rb +43 -0
  310. data/spec/system/formatting_system_spec.rb +63 -0
  311. data/spec/system/helpers_system_spec.rb +235 -0
  312. data/spec/system/id_uniqueness_system_spec.rb +205 -0
  313. data/spec/system/localization_system_spec.rb +94 -0
  314. data/spec/system/method_precedence_system_spec.rb +48 -0
  315. data/spec/system/needs_system_spec.rb +368 -0
  316. data/spec/system/other_outputters_system_spec.rb +117 -0
  317. data/spec/system/rails_not_available_spec.rb +11 -0
  318. data/spec/system/rebuild_notifications_system_spec.rb +208 -0
  319. data/spec/system/rendering_context_system_spec.rb +83 -0
  320. data/spec/system/setting_inheritance_system_spec.rb +585 -0
  321. data/spec/system/shared_variable_system_spec.rb +120 -0
  322. data/spec/system/start_end_comments_system_spec.rb +363 -0
  323. data/spec/system/static_method_system_spec.rb +348 -0
  324. data/spec/system/tag_rendering_system_spec.rb +253 -0
  325. data/spec/system/tag_return_value_system_spec.rb +41 -0
  326. data/spec/system/tag_rules_system_spec.rb +196 -0
  327. data/spec/system/tag_updating_system_spec.rb +171 -0
  328. data/spec/system/tilt_system_spec.rb +378 -0
  329. data/spec/system/unparsed_data_system_spec.rb +16 -0
  330. data/spec/system/void_tags_system_spec.rb +51 -0
  331. data/spec/system/widget_return_values_system_spec.rb +89 -0
  332. metadata +736 -0
@@ -0,0 +1,904 @@
1
+ require 'fortitude/class_inheritable_attributes'
2
+ require 'fortitude/tag'
3
+ require 'fortitude/tags_module'
4
+ require 'fortitude/errors'
5
+ require 'fortitude/assigns_proxy'
6
+ require 'fortitude/doctypes'
7
+ require 'fortitude/partial_tag_placeholder'
8
+ require 'fortitude/staticized_method'
9
+ require 'fortitude/rendering_context'
10
+ require 'fortitude/tag_store'
11
+ require 'fortitude/rails/yielded_object_outputter'
12
+ require 'active_support/core_ext/hash'
13
+ require 'active_support/notifications'
14
+
15
+ module Fortitude
16
+ # TODO: rename all non-interface methods as _fortitude_*
17
+ # TODO: Make 'element' vs. 'tag' naming consistent
18
+ # TODO: Make naming consistent across enforcement/validation/rules (tag nesting, attributes, ID uniqueness)
19
+ class Widget
20
+ # CLASS INHERITABLE ATTRIBUTES =================================================================================
21
+ include Fortitude::ClassInheritableAttributes
22
+
23
+ _fortitude_class_inheritable_attribute :format_output, false, [ true, false ]
24
+ _fortitude_class_inheritable_attribute :extra_assigns, :ignore, [ :error, :ignore, :use ]
25
+ _fortitude_class_inheritable_attribute :automatic_helper_access, true, [ true, false ]
26
+ _fortitude_class_inheritable_attribute :implicit_shared_variable_access, false, [ true, false ]
27
+ _fortitude_class_inheritable_attribute :enforce_element_nesting_rules, false, [ true, false ]
28
+ _fortitude_class_inheritable_attribute :enforce_attribute_rules, false, [ true, false ]
29
+ _fortitude_class_inheritable_attribute :enforce_id_uniqueness, false, [ true, false ]
30
+ _fortitude_class_inheritable_attribute :use_instance_variables_for_assigns, false, [ true, false ]
31
+ _fortitude_class_inheritable_attribute :start_and_end_comments, false, [ true, false ]
32
+ _fortitude_class_inheritable_attribute :translation_base, nil, lambda { |s| s.kind_of?(String) || s.kind_of?(Symbol) || s == nil }
33
+ _fortitude_class_inheritable_attribute :close_void_tags, true, [ true, false ]
34
+ _fortitude_class_inheritable_attribute :debug, false, [ true, false ]
35
+
36
+
37
+ # TAGS ==========================================================================================================
38
+ extend Fortitude::TagStore
39
+
40
+ class << self
41
+ # INTERNAL USE ONLY
42
+ def tags_changed!(tags)
43
+ rebuild_tag_methods!(:tags_declared, tags)
44
+ end
45
+ private :tags_changed!
46
+
47
+ # INTERNAL USE ONLY
48
+ def delegate_tag_stores
49
+ out = [ doctype ]
50
+
51
+ out += superclass.delegate_tag_stores if superclass.respond_to?(:delegate_tag_stores)
52
+ out << superclass if superclass.respond_to?(:tags)
53
+
54
+ out.compact.uniq
55
+ end
56
+
57
+ # INTERNAL USE ONLY
58
+ def rebuild_tag_methods!(why, which_tags_in = nil, klass = self)
59
+ rebuilding(:tag_methods, why, klass) do
60
+ all_tags = tags.values
61
+
62
+ which_tags = Array(which_tags_in || all_tags)
63
+ which_tags.each do |tag_object|
64
+ tag_object.define_method_on!(tags_module,
65
+ :enable_formatting => self.format_output,
66
+ :enforce_element_nesting_rules => self.enforce_element_nesting_rules,
67
+ :enforce_attribute_rules => self.enforce_attribute_rules,
68
+ :enforce_id_uniqueness => self.enforce_id_uniqueness,
69
+ :close_void_tags => self.close_void_tags)
70
+ end
71
+
72
+ direct_subclasses.each { |s| s.rebuild_tag_methods!(why, which_tags_in, klass) }
73
+ end
74
+ end
75
+ end
76
+
77
+ # NEEDS =========================================================================================================
78
+ # INTERNAL USE ONLY
79
+ REQUIRED_NEED = Object.new
80
+ # INTERNAL USE ONLY
81
+ NOT_PRESENT_NEED = Object.new
82
+
83
+ # INTERNAL USE ONLY
84
+ attr_reader :_fortitude_default_assigns
85
+
86
+ class << self
87
+ # PUBLIC API
88
+ def needs(*names)
89
+ previous_needs = needs_as_hash
90
+ return previous_needs if names.length == 0
91
+
92
+ @this_class_needs ||= { }
93
+
94
+ with_defaults_raw = { }
95
+ with_defaults_raw = names.pop if names[-1] && names[-1].kind_of?(Hash)
96
+
97
+ names = names.map { |n| n.to_s.strip.downcase.to_sym }
98
+ with_defaults = { }
99
+ with_defaults_raw.each { |k,v| with_defaults[k.to_s.strip.downcase.to_sym] = v }
100
+
101
+ bad_names = names.select { |n| ! is_valid_ruby_method_name?(n.to_s) }
102
+ raise ArgumentError, "Needs in a Fortitude widget class must be valid Ruby method names; these are not: #{bad_names.inspect}" if bad_names.length > 0
103
+
104
+ names.each do |name|
105
+ @this_class_needs[name] = REQUIRED_NEED
106
+ end
107
+
108
+ with_defaults.each do |name, default_value|
109
+ @this_class_needs[name] = default_value
110
+ end
111
+
112
+ rebuild_needs!(:need_declared)
113
+
114
+ needs_as_hash
115
+ end
116
+
117
+ # INTERNAL USE ONLY
118
+ def is_valid_ruby_method_name?(s)
119
+ s.to_s =~ /^[A-Za-z_][A-Za-z0-9_]*[\?\!]?$/
120
+ end
121
+
122
+ # INTERNAL USE ONLY
123
+ def needs_as_hash
124
+ @_fortitude_needs_as_hash ||= begin
125
+ out = { }
126
+ out = superclass.needs_as_hash if superclass.respond_to?(:needs_as_hash)
127
+ out.merge(@this_class_needs || { })
128
+ end
129
+ end
130
+
131
+ # INTERNAL USE ONLY
132
+ def rebuild_needs!(why, klass = self)
133
+ rebuilding(:needs, why, klass) do
134
+ @_fortitude_needs_as_hash = nil
135
+ rebuild_my_needs_methods!
136
+ direct_subclasses.each { |s| s.rebuild_needs!(why, klass) }
137
+ end
138
+ end
139
+
140
+ # PUBLIC API
141
+ def extract_needed_assigns_from(input)
142
+ input = input.with_indifferent_access
143
+
144
+ out = { }
145
+ needs_as_hash.keys.each do |name|
146
+ out[name] = input[name] if input.has_key?(name)
147
+ end
148
+ out
149
+ end
150
+
151
+ # INTERNAL USE ONLY
152
+ STANDARD_INSTANCE_VARIABLE_PREFIX = "_fortitude_assign_"
153
+
154
+ # INTERNAL USE ONLY
155
+ def instance_variable_name_for_need(need_name)
156
+ effective_name = need_name.to_s
157
+ effective_name.gsub!("!", "_fortitude_bang")
158
+ effective_name.gsub!("?", "_fortitude_question")
159
+ "@" + (use_instance_variables_for_assigns ? "" : STANDARD_INSTANCE_VARIABLE_PREFIX) + effective_name
160
+ end
161
+
162
+ # INTERNAL USE ONLY
163
+ def rebuild_my_needs_methods!
164
+ n = needs_as_hash
165
+
166
+ needs_text = n.map do |need, default_value|
167
+ Fortitude::SimpleTemplate.template('need_assignment_template').result(:extra_assigns => extra_assigns,
168
+ :need => need, :has_default => (default_value != REQUIRED_NEED),
169
+ :ivar_name => instance_variable_name_for_need(need)
170
+ )
171
+ end.join("\n\n")
172
+
173
+ assign_locals_from_text = Fortitude::SimpleTemplate.template('assign_locals_from_template').result(
174
+ :extra_assigns => extra_assigns, :needs_text => needs_text)
175
+ class_eval(assign_locals_from_text)
176
+
177
+ n.each do |need, default_value|
178
+ text = Fortitude::SimpleTemplate.template('need_method_template').result(
179
+ :need => need, :ivar_name => instance_variable_name_for_need(need),
180
+ :debug => self.debug)
181
+ needs_module.module_eval(text)
182
+ end
183
+ end
184
+ private :rebuild_my_needs_methods!
185
+ end
186
+
187
+ # PUBLIC API
188
+ def shared_variables
189
+ @_fortitude_rendering_context.instance_variable_set
190
+ end
191
+
192
+ # INTERNAL USE ONLY
193
+ def instance_variable_name_for_need(need)
194
+ self.class.instance_variable_name_for_need(need)
195
+ end
196
+
197
+ # INTERNAL USE ONLY
198
+ def needs_as_hash
199
+ @_fortitude_needs_as_hash ||= self.class.needs_as_hash
200
+ end
201
+
202
+ # PUBLIC API
203
+ def assigns
204
+ @_fortitude_assigns_proxy ||= begin
205
+ keys = needs_as_hash.keys
206
+ keys |= (@_fortitude_raw_assigns.keys.map(&:to_sym)) if self.class.extra_assigns == :use
207
+
208
+ Fortitude::AssignsProxy.new(self, keys)
209
+ end
210
+ end
211
+
212
+ # INTERNAL USE ONLY
213
+ def widget_extra_assigns
214
+ (@_fortitude_extra_assigns || { })
215
+ end
216
+
217
+ # INTERNAL USE ONLY
218
+ def transfer_shared_variables(*args, &block)
219
+ if self.class.implicit_shared_variable_access
220
+ @_fortitude_rendering_context.instance_variable_set.with_instance_variable_copying(self, *args, &block)
221
+ else
222
+ block.call(*args)
223
+ end
224
+ end
225
+ private :transfer_shared_variables
226
+
227
+ # RAILS =========================================================================================================
228
+ if defined?(::Rails)
229
+ include Fortitude::Rails::WidgetMethods
230
+ else
231
+ include Fortitude::NonRailsWidgetMethods
232
+ end
233
+
234
+ # MODULES AND SUBCLASSES ========================================================================================
235
+ class << self
236
+ # INTERNAL USE ONLY
237
+ def direct_subclasses
238
+ @direct_subclasses || [ ]
239
+ end
240
+ private :direct_subclasses
241
+
242
+ # INTERNAL USE ONLY -- RUBY CALLBACK
243
+ def inherited(subclass)
244
+ @direct_subclasses ||= [ ]
245
+ @direct_subclasses |= [ subclass ]
246
+ end
247
+
248
+ # INTERNAL USE ONLY
249
+ def create_modules!
250
+ raise "We already seem to have created our modules" if @tags_module || @needs_module || @helpers_module
251
+ @tags_module = Fortitude::TagsModule.new(self)
252
+ @helpers_module = Module.new
253
+ include @helpers_module
254
+ @needs_module = Module.new
255
+ include @needs_module
256
+ end
257
+ private :create_modules!
258
+
259
+ # INTERNAL USE ONLY
260
+ def tags_module
261
+ create_modules! unless @tags_module
262
+ @tags_module
263
+ end
264
+ private :tags_module
265
+
266
+ # INTERNAL USE ONLY
267
+ def needs_module
268
+ create_modules! unless @needs_module
269
+ @needs_module
270
+ end
271
+ private :needs_module
272
+
273
+ # INTERNAL USE ONLY
274
+ def helpers_module
275
+ create_modules! unless @helpers_module
276
+ @helpers_module
277
+ end
278
+ private :helpers_module
279
+ end
280
+
281
+ # DOCTYPES ======================================================================================================
282
+ class << self
283
+ # PUBLIC API
284
+ def doctype(new_doctype = nil)
285
+ if new_doctype
286
+ new_doctype = case new_doctype
287
+ when Fortitude::Doctypes::Base then new_doctype
288
+ when Symbol then Fortitude::Doctypes.standard_doctype(new_doctype)
289
+ else raise ArgumentError, "You must supply a Symbol or an instance of Fortitude::Doctypes::Base, not: #{new_doctype.inspect}"
290
+ end
291
+
292
+ current_doctype = doctype
293
+ if current_doctype
294
+ if new_doctype != current_doctype
295
+ raise ArgumentError, "The doctype has already been set to #{current_doctype} on this widget class or a superclass. You can't set it to #{new_doctype}; if you want to use a different doctype, you will need to make a new subclass that has no doctype set yet."
296
+ end
297
+ end
298
+
299
+ self.close_void_tags(new_doctype.close_void_tags?)
300
+
301
+ @_fortitude_doctype = new_doctype
302
+ tags_added!(new_doctype.tags.values)
303
+ else
304
+ return @_fortitude_doctype if @_fortitude_doctype
305
+ return superclass.doctype if superclass.respond_to?(:doctype)
306
+ nil
307
+ end
308
+ end
309
+ end
310
+
311
+ # PUBLIC API
312
+ def doctype(s)
313
+ tag_rawtext "<!DOCTYPE #{s}>"
314
+ end
315
+
316
+ # PUBLIC API
317
+ def doctype!
318
+ dt = self.class.doctype
319
+ raise "You must set a doctype at the class level, using something like 'doctype :html5', before you can use this method." unless dt
320
+ dt.declare!(self)
321
+ end
322
+
323
+ # START AND END COMMENTS ========================================================================================
324
+
325
+ # INTERNAL USE ONLY
326
+ def widget_nesting_depth
327
+ @_fortitude_widget_nesting_depth ||= @_fortitude_rendering_context.current_widget_depth
328
+ end
329
+ private :widget_nesting_depth
330
+
331
+ MAX_START_COMMENT_VALUE_STRING_LENGTH = 100
332
+ START_COMMENT_VALUE_STRING_TOO_LONG_ELLIPSIS = "...".freeze
333
+ MAX_ASSIGNS_LENGTH_BEFORE_MULTIPLE_LINES = 200
334
+ START_COMMENT_EXTRA_INDENT_FOR_NEXT_LINE = " " * 5
335
+
336
+ # INTERNAL USE ONLY
337
+ def start_and_end_comments
338
+ if self.class.start_and_end_comments
339
+ fo = self.class.format_output
340
+
341
+ comment_text = "BEGIN #{self.class.name} depth #{widget_nesting_depth}"
342
+
343
+ assign_keys = assigns.keys
344
+ if assign_keys.length > 0
345
+
346
+ assign_text = assign_keys.map do |assign|
347
+ value = assigns[assign]
348
+ out = ":#{assign} => "
349
+ out << "(DEFAULT) " if assigns.is_default?(assign)
350
+
351
+ value_string = if value.respond_to?(:to_fortitude_comment_string) then value.to_fortitude_comment_string else value.inspect end
352
+ if value_string.length > MAX_START_COMMENT_VALUE_STRING_LENGTH
353
+ value_string = value_string[0..(MAX_START_COMMENT_VALUE_STRING_LENGTH - START_COMMENT_VALUE_STRING_TOO_LONG_ELLIPSIS.length)] + START_COMMENT_VALUE_STRING_TOO_LONG_ELLIPSIS
354
+ end
355
+ out << value_string
356
+ out
357
+ end
358
+
359
+ total_length = assign_text.map(&:length).inject(0, &:+)
360
+ if total_length > MAX_ASSIGNS_LENGTH_BEFORE_MULTIPLE_LINES
361
+ newline_and_indent = "\n#{@_fortitude_rendering_context.current_indent}"
362
+ newline_and_extra_indent = newline_and_indent + START_COMMENT_EXTRA_INDENT_FOR_NEXT_LINE
363
+
364
+ comment_text << ":"
365
+ assign_text.each do |at|
366
+ comment_text << newline_and_extra_indent
367
+ comment_text << at
368
+ end
369
+ comment_text << newline_and_indent
370
+ else
371
+ comment_text << ": "
372
+ comment_text << assign_text.join(", ")
373
+ end
374
+ end
375
+ tag_comment comment_text
376
+ yield
377
+ tag_comment "END #{self.class.name} depth #{widget_nesting_depth}"
378
+ else
379
+ yield
380
+ end
381
+ end
382
+ private :start_and_end_comments
383
+
384
+ # OTHER TAG-LIKE METHODS ========================================================================================
385
+ # From http://www.w3.org/TR/html5/syntax.html#comments:
386
+ #
387
+ # Comments must start with the four character sequence U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK,
388
+ # U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS (<!--). Following this sequence, the comment may have text,
389
+ # with the additional restriction that the text must not start with a single ">" (U+003E) character,
390
+ # nor start with a U+002D HYPHEN-MINUS character (-) followed by a ">" (U+003E) character, nor contain
391
+ # two consecutive U+002D HYPHEN-MINUS characters (--), nor end with a U+002D HYPHEN-MINUS character (-).
392
+ # Finally, the comment must be ended by the three character sequence U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS,
393
+ # U+003E GREATER-THAN SIGN (-->).
394
+
395
+ # INTERNAL USE ONLY
396
+ def comment_escape(string)
397
+ string = "_#{string}" if string =~ /^\s*(>|->)/
398
+ string = string.gsub("--", "- - ") if string =~ /\-\-/ # don't gsub if it doesn't match to avoid generating garbage
399
+ string = "#{string}_" if string =~ /\-\s*$/i
400
+ string
401
+ end
402
+ private :comment_escape
403
+
404
+ # PUBLIC API
405
+ def tag_comment(s)
406
+ fo = self.class.format_output
407
+ @_fortitude_rendering_context.needs_newline! if fo
408
+ raise ArgumentError, "You cannot pass a block to a comment" if block_given?
409
+ tag_rawtext "<!-- "
410
+ tag_rawtext comment_escape(s)
411
+ tag_rawtext " -->"
412
+ @_fortitude_rendering_context.needs_newline! if fo
413
+ end
414
+
415
+ # PUBLIC API
416
+ def tag_javascript(content = nil, &block)
417
+ args = if content.kind_of?(Hash)
418
+ [ self.class.doctype.default_javascript_tag_attributes.merge(content) ]
419
+ elsif content
420
+ if block
421
+ raise ArgumentError, "You can't supply JavaScript content both via text and a block"
422
+ else
423
+ block = lambda { tag_rawtext content }
424
+ [ self.class.doctype.default_javascript_tag_attributes.dup ]
425
+ end
426
+ else
427
+ [ self.class.doctype.default_javascript_tag_attributes.dup ]
428
+ end
429
+
430
+ actual_block = block
431
+ if self.class.doctype.needs_cdata_in_javascript_tag?
432
+ actual_block = lambda do
433
+ tag_rawtext "\n//#{CDATA_START}\n"
434
+ block.call
435
+ tag_rawtext "\n//#{CDATA_END}\n"
436
+ end
437
+ end
438
+
439
+ @_fortitude_rendering_context.with_indenting_disabled do
440
+ script(*args, &actual_block)
441
+ end
442
+ end
443
+
444
+ %w{comment javascript}.each do |non_tag_method|
445
+ alias_method non_tag_method, "tag_#{non_tag_method}"
446
+ end
447
+
448
+ CDATA_START = "<![CDATA[".freeze
449
+ CDATA_END = "]]>".freeze
450
+
451
+ # PUBLIC API
452
+ def cdata(s = nil, &block)
453
+ if s
454
+ raise ArgumentError, "You can only pass literal text or a block, not both" if block
455
+
456
+ components = s.split("]]>")
457
+
458
+ if components.length > 1
459
+ components.each_with_index do |s, i|
460
+ this_component = s
461
+ this_component = ">#{this_component}" if i > 0
462
+ this_component = "#{this_component}]]" if i < (components.length - 1)
463
+ cdata(this_component)
464
+ end
465
+ else
466
+ tag_rawtext CDATA_START
467
+ tag_rawtext s
468
+ tag_rawtext CDATA_END
469
+ end
470
+ else
471
+ tag_rawtext CDATA_START
472
+ yield
473
+ tag_rawtext CDATA_END
474
+ end
475
+ end
476
+
477
+ # STATICIZATION =================================================================================================
478
+ class << self
479
+ # PUBLIC API
480
+ def static(*method_names)
481
+ options = method_names.extract_options!
482
+
483
+ method_names.each do |method_name|
484
+ method_name = method_name.to_sym
485
+ staticized_method = Fortitude::StaticizedMethod.new(self, method_name, options)
486
+ staticized_method.create_method!
487
+ end
488
+ end
489
+ end
490
+
491
+ METHODS_TO_DISABLE_WHEN_STATIC = [ :assigns, :shared_variables ]
492
+
493
+ # INTERNAL USE ONLY
494
+ def with_staticness_enforced(static_method_name, &block)
495
+ methods_to_disable = METHODS_TO_DISABLE_WHEN_STATIC + self.class.needs_as_hash.keys
496
+ metaclass = (class << self; self; end)
497
+
498
+ methods_to_disable.each do |method_name|
499
+ metaclass.class_eval do
500
+ alias_method "_static_disabled_#{method_name}", method_name
501
+ define_method(method_name) { raise Fortitude::Errors::DynamicAccessFromStaticMethod.new(self, static_method_name, method_name) }
502
+ end
503
+ end
504
+
505
+ begin
506
+ block.call
507
+ ensure
508
+ methods_to_disable.each do |method_name|
509
+ metaclass.class_eval do
510
+ alias_method method_name, "_static_disabled_#{method_name}"
511
+ end
512
+ end
513
+ end
514
+ end
515
+
516
+ # INTEGRATION ===================================================================================================
517
+ class << self
518
+ # INTERNAL USE ONLY
519
+ def rebuilding(what, why, klass, &block)
520
+ ActiveSupport::Notifications.instrument("fortitude.rebuilding", :what => what, :why => why, :originating_class => klass, :class => self, &block)
521
+ end
522
+ private :rebuilding
523
+
524
+ # INTERNAL USE ONLY
525
+ def rebuild_text_methods!(why, klass = self)
526
+ rebuilding(:text_methods, why, klass) do
527
+ class_eval(Fortitude::SimpleTemplate.template('text_method_template').result(:format_output => format_output, :needs_element_rules => self.enforce_element_nesting_rules))
528
+ direct_subclasses.each { |s| s.rebuild_text_methods!(why, klass) }
529
+ end
530
+ end
531
+ end
532
+
533
+ # RUBY CALLBACK
534
+ def method_missing(name, *args, &block)
535
+ if self.class.extra_assigns == :use
536
+ ivar_name = self.class.instance_variable_name_for_need(name)
537
+ return instance_variable_get(ivar_name) if instance_variable_defined?(ivar_name)
538
+ end
539
+
540
+ if self.class.automatic_helper_access && @_fortitude_rendering_context && @_fortitude_rendering_context.helpers_object && @_fortitude_rendering_context.helpers_object.respond_to?(name, true)
541
+ @_fortitude_rendering_context.helpers_object.send(name, *args, &block)
542
+ else
543
+ super(name, *args, &block)
544
+ end
545
+ end
546
+
547
+ _fortitude_on_class_inheritable_attribute_change(
548
+ :format_output, :enforce_element_nesting_rules) do |attribute_name, old_value, new_value|
549
+ rebuild_text_methods!(:"#{attribute_name}_changed")
550
+ end
551
+
552
+ _fortitude_on_class_inheritable_attribute_change(
553
+ :format_output, :close_void_tags, :enforce_element_nesting_rules,
554
+ :enforce_attribute_rules, :enforce_id_uniqueness) do |attribute_name, old_value, new_value|
555
+ rebuild_tag_methods!(:"#{attribute_name}_changed")
556
+ end
557
+
558
+ _fortitude_on_class_inheritable_attribute_change(
559
+ :debug, :extra_assigns, :use_instance_variables_for_assigns) do |attribute_name, old_value, new_value|
560
+ rebuild_needs!(:"#{attribute_name}_changed")
561
+ end
562
+
563
+ _fortitude_on_class_inheritable_attribute_change(:implicit_shared_variable_access) do |attribute_name, old_value, new_value|
564
+ if new_value
565
+ around_content :transfer_shared_variables
566
+ else
567
+ remove_around_content :transfer_shared_variables, :fail_if_not_present => false
568
+ end
569
+ end
570
+
571
+ _fortitude_on_class_inheritable_attribute_change(:start_and_end_comments) do |attribute_name, old_value, new_value|
572
+ if new_value
573
+ around_content :start_and_end_comments
574
+ else
575
+ remove_around_content :start_and_end_comments, :fail_if_not_present => false
576
+ end
577
+ end
578
+
579
+ # CONTENT ======================================================================================================
580
+ # PUBLIC API
581
+ def content
582
+ raise "Must override in #{self.class.name}"
583
+ end
584
+
585
+ class << self
586
+ # INTERNAL USE ONLY
587
+ def rebuild_run_content!(why, klass = self)
588
+ rebuilding(:run_content, why, klass) do
589
+ acm = around_content_methods
590
+ text = "def run_content(*args, &block)\n"
591
+ text += " out = nil\n"
592
+ acm.each_with_index do |method_name, index|
593
+ text += " " + (" " * index) + "#{method_name}(*args) do\n"
594
+ end
595
+
596
+ if has_localized_content_methods?
597
+ text += " " + (" " * acm.length) + "the_locale = widget_locale\n"
598
+ text += " " + (" " * acm.length) + "locale_method_name = \"localized_content_\#{the_locale}\" if the_locale\n"
599
+ text += " " + (" " * acm.length) + "out = if locale_method_name && respond_to?(locale_method_name)\n"
600
+ text += " " + (" " * acm.length) + " send(locale_method_name, *args, &block)\n"
601
+ text += " " + (" " * acm.length) + "else\n"
602
+ text += " " + (" " * acm.length) + " content(*args, &block)\n"
603
+ text += " " + (" " * acm.length) + "end\n"
604
+ else
605
+ text += " " + (" " * acm.length) + "out = content(*args, &block)\n"
606
+ end
607
+
608
+ (0..(acm.length - 1)).each do |index|
609
+ text += " " + (" " * (acm.length - (index + 1))) + "end\n"
610
+ end
611
+ text += " out\n"
612
+ text += "end"
613
+
614
+ class_eval(text)
615
+
616
+ direct_subclasses.each { |s| s.rebuild_run_content!(why, klass) }
617
+ end
618
+ end
619
+ end
620
+
621
+ # AROUND_CONTENT ================================================================================================
622
+ class << self
623
+ # PUBLIC API
624
+ def around_content(*method_names)
625
+ return if method_names.length == 0
626
+ @_fortitude_around_content_methods ||= [ ]
627
+ @_fortitude_around_content_methods += method_names.map { |x| x.to_s.strip.downcase.to_sym }
628
+ rebuild_run_content!(:around_content_added)
629
+ end
630
+
631
+ # PUBLIC API
632
+ def remove_around_content(*method_names)
633
+ options = method_names.extract_options!
634
+ options.assert_valid_keys(:fail_if_not_present)
635
+
636
+ not_found = [ ]
637
+ method_names.each do |method_name|
638
+ not_found << method_name unless (@_fortitude_around_content_methods || [ ]).delete(method_name)
639
+ end
640
+
641
+ rebuild_run_content!(:around_content_removed)
642
+ unless (not_found.length == 0) || (options.has_key?(:fail_if_not_present) && (! options[:fail_if_not_present]))
643
+ raise ArgumentError, "no such methods: #{not_found.inspect}"
644
+ end
645
+ end
646
+
647
+ # INTERNAL USE ONLY
648
+ def around_content_methods
649
+ superclass_methods = if superclass.respond_to?(:around_content_methods)
650
+ superclass.around_content_methods
651
+ else
652
+ [ ]
653
+ end
654
+
655
+ (superclass_methods + this_class_around_content_methods).uniq
656
+ end
657
+
658
+ # INTERNAL USE ONLY
659
+ def this_class_around_content_methods
660
+ @_fortitude_around_content_methods ||= [ ]
661
+ end
662
+ private :this_class_around_content_methods
663
+ end
664
+
665
+ # LOCALIZATION ==================================================================================================
666
+ class << self
667
+ # RUBY CALLBACK
668
+ def method_added(method_name)
669
+ super(method_name)
670
+ check_localized_methods!
671
+ end
672
+
673
+ # RUBY CALLBACK
674
+ def method_removed(method_name)
675
+ super(method_name)
676
+ check_localized_methods!
677
+ end
678
+
679
+ # RUBY CALL
680
+ def include(*args)
681
+ super(*args)
682
+ check_localized_methods!
683
+ end
684
+
685
+ LOCALIZED_CONTENT_PREFIX = "localized_content_"
686
+
687
+ # INTERNAL USE ONLY
688
+ def check_localized_methods!(original_class = self)
689
+ currently_has = instance_methods(true).detect { |i| i =~ /^#{LOCALIZED_CONTENT_PREFIX}/i }
690
+ if currently_has != @last_localized_methods_check_has
691
+ @last_localized_methods_check_has = currently_has
692
+ rebuild_run_content!(:localized_methods_presence_changed, original_class)
693
+ end
694
+ direct_subclasses.each { |s| s.check_localized_methods!(original_class) }
695
+ end
696
+
697
+ # INTERNAL USE ONLY
698
+ def has_localized_content_methods?
699
+ !! (instance_methods(true).detect { |i| i =~ /^#{LOCALIZED_CONTENT_PREFIX}/i })
700
+ end
701
+ private :has_localized_content_methods?
702
+ end
703
+
704
+ # PUBLIC API
705
+ def t(key, *args)
706
+ base = self.class.translation_base
707
+ if base && key.to_s =~ /^\./
708
+ super("#{base}#{key}", *args)
709
+ else
710
+ super(key, *args)
711
+ end
712
+ end
713
+
714
+ # PUBLIC API
715
+ def ttext(key, *args)
716
+ tag_text t(".#{key}", *args)
717
+ end
718
+
719
+ # HELPERS =======================================================================================================
720
+ class << self
721
+ # PUBLIC API
722
+ def helper(*args)
723
+ options = args.extract_options!
724
+ options.assert_valid_keys(:transform, :call, :output_yielded_methods)
725
+
726
+ args.each do |name|
727
+ source_method_name = options[:call] || name
728
+
729
+ prefix = "return"
730
+ suffix = ""
731
+ case (transform = options[:transform])
732
+ when :output_return_value
733
+ prefix = "text"
734
+ suffix = "; nil"
735
+ when :return_output
736
+ prefix = "return capture { "
737
+ suffix = " }"
738
+ when :none, nil, false then nil
739
+ else raise ArgumentError, "Invalid value for :transform: #{transform.inspect}"
740
+ end
741
+
742
+ block_transform = "effective_block = block"
743
+
744
+ yielded_methods = options[:output_yielded_methods]
745
+ if yielded_methods
746
+ block_transform = <<-EOS
747
+ effective_block = lambda do |yielded_object|
748
+ block.call(Fortitude::Rails::YieldedObjectOutputter.new(self, yielded_object, #{yielded_methods.inspect}))
749
+ end
750
+ EOS
751
+ end
752
+
753
+ text = <<-EOS
754
+ def #{name}(*args, &block)
755
+ #{block_transform}
756
+ #{prefix}(@_fortitude_rendering_context.helpers_object.#{source_method_name}(*args, &effective_block))#{suffix}
757
+ end
758
+ EOS
759
+
760
+ helpers_module.module_eval(text)
761
+ end
762
+ end
763
+ end
764
+
765
+ # PUBLIC API
766
+ def invoke_helper(name, *args, &block)
767
+ @_fortitude_rendering_context.helpers_object.send(name, *args, &block)
768
+ end
769
+
770
+ # CAPTURING =====================================================================================================
771
+ # PUBLIC API
772
+ def capture(&block)
773
+ helpers = @_fortitude_rendering_context.helpers_object
774
+ if helpers && helpers.respond_to?(:capture, true) &&
775
+ [ 0, -1].include?(helpers.method(:capture).arity)
776
+ helpers.capture(&block)
777
+ else
778
+ _fortitude_builtin_capture(&block)
779
+ end
780
+ end
781
+
782
+ # INTERNAL USE ONLY
783
+ def _fortitude_builtin_capture(&block)
784
+ old_buffer = nil
785
+ new_buffer = nil
786
+ begin
787
+ new_buffer = _fortitude_new_buffer
788
+ old_buffer, @_fortitude_output_buffer_holder.output_buffer = @_fortitude_output_buffer_holder.output_buffer, new_buffer
789
+ _fortitude_new_buffer.force_encoding(old_buffer.encoding) if old_buffer && old_buffer.respond_to?(:encoding)
790
+ block.call
791
+ new_buffer
792
+ ensure
793
+ @_fortitude_output_buffer_holder.output_buffer = old_buffer
794
+ end
795
+ end
796
+ private :_fortitude_builtin_capture
797
+
798
+ # RENDERING =============================================================================================
799
+ # PUBLIC API
800
+ def render(*args, &block)
801
+ call_through = lambda do
802
+ @_fortitude_rendering_context.record_widget(args) do
803
+ tag_rawtext(invoke_helper(:render, *args, &block))
804
+ end
805
+ end
806
+
807
+ if self.class.enforce_element_nesting_rules && args[0].kind_of?(Hash) && args[0].has_key?(:partial)
808
+ @_fortitude_rendering_context.record_tag(self, Fortitude::PartialTagPlaceholder.instance, &call_through)
809
+ else
810
+ call_through.call
811
+ end
812
+ end
813
+
814
+ # PUBLIC API
815
+ def to_html(rendering_context)
816
+ @_fortitude_rendering_context = rendering_context
817
+ @_fortitude_output_buffer_holder = rendering_context.output_buffer_holder
818
+
819
+ block = lambda { |*args| @_fortitude_rendering_context.yield_from_widget(*args) }
820
+
821
+ rendering_context.record_widget(self) do
822
+ begin
823
+ run_content(&block)
824
+ ensure
825
+ @_fortitude_rendering_context = nil
826
+ end
827
+ end
828
+ end
829
+
830
+ # PUBLIC API
831
+ def rendering_context
832
+ @_fortitude_rendering_context
833
+ end
834
+
835
+ # PUBLIC API
836
+ def widget(w)
837
+ w.to_html(@_fortitude_rendering_context)
838
+ end
839
+
840
+ # PUBLIC API
841
+ def output_buffer
842
+ @_fortitude_output_buffer_holder.output_buffer
843
+ end
844
+
845
+ # PUBLIC API
846
+ def initialize(assigns = { })
847
+ assign_locals_from(assigns)
848
+ end
849
+
850
+ # INTERNAL USE ONLY
851
+ def _fortitude_new_buffer
852
+ _fortitude_class_for_new_buffer.new
853
+ end
854
+ private :_fortitude_new_buffer
855
+
856
+ POTENTIAL_NEW_BUFFER_CLASSES = %w{ActionView::OutputBuffer ActiveSupport::SafeBuffer String}
857
+
858
+ # INTERNAL USE ONLY
859
+ def _fortitude_class_for_new_buffer
860
+ @_fortitude_class_for_new_buffer ||= begin
861
+ out = nil
862
+ POTENTIAL_NEW_BUFFER_CLASSES.each do |class_name|
863
+ klass = eval(class_name) rescue nil
864
+ if klass
865
+ out = klass
866
+ break
867
+ end
868
+ end
869
+ raise "Huh? NONE of the following classes appear to be defined?!? #{POTENTIAL_NEW_BUFFER_CLASSES.inspect}" unless out
870
+ out
871
+ end
872
+ end
873
+ private :_fortitude_class_for_new_buffer
874
+
875
+ # PUBLIC API
876
+ def yield_from_widget(*args)
877
+ @_fortitude_rendering_context.yield_from_widget(*args)
878
+ end
879
+
880
+ # TEMPORARY OVERRIDES ===========================================================================================
881
+ # PUBLIC API
882
+ def with_element_nesting_rules(on_or_off)
883
+ raise ArgumentError, "We aren't even enforcing nesting rules in the first place" if on_or_off && (! self.class.enforce_element_nesting_rules)
884
+ @_fortitude_rendering_context.with_element_nesting_validation(on_or_off) { yield }
885
+ end
886
+
887
+ # PUBLIC API
888
+ def with_attribute_rules(on_or_off)
889
+ raise ArgumentError, "We aren't even enforcing attribute rules in the first place" if on_or_off && (! self.class.enforce_attribute_rules)
890
+ @_fortitude_rendering_context.with_attribute_validation(on_or_off) { yield }
891
+ end
892
+
893
+ # PUBLIC API
894
+ def with_id_uniqueness(on_or_off)
895
+ raise ArgumentError, "We aren't even enforcing ID uniqueness in the first place" if on_or_off && (! self.class.enforce_id_uniqueness)
896
+ @_fortitude_rendering_context.with_id_uniqueness(on_or_off) { yield }
897
+ end
898
+
899
+ # CODA ==========================================================================================================
900
+ rebuild_run_content!(:initial_setup)
901
+ rebuild_needs!(:initial_setup)
902
+ rebuild_text_methods!(:initial_setup)
903
+ end
904
+ end