thorero 0.9.4.4 → 0.9.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. data/LICENSE +1 -1
  2. data/README +21 -0
  3. data/Rakefile +275 -108
  4. data/TODO +0 -0
  5. data/bin/merb +12 -0
  6. data/bin/merb-specs +5 -0
  7. data/docs/bootloading.dox +58 -0
  8. data/docs/documentation_standards +40 -0
  9. data/docs/merb-core-call-stack-diagram.mmap +0 -0
  10. data/docs/merb-core-call-stack-diagram.pdf +0 -0
  11. data/docs/merb-core-call-stack-diagram.png +0 -0
  12. data/docs/new_render_api +51 -0
  13. data/lib/merb-core.rb +603 -0
  14. data/lib/merb-core/autoload.rb +32 -0
  15. data/lib/merb-core/bootloader.rb +708 -0
  16. data/lib/merb-core/config.rb +303 -0
  17. data/lib/merb-core/constants.rb +43 -0
  18. data/lib/merb-core/controller/abstract_controller.rb +578 -0
  19. data/lib/merb-core/controller/exceptions.rb +302 -0
  20. data/lib/merb-core/controller/merb_controller.rb +256 -0
  21. data/lib/merb-core/controller/mime.rb +106 -0
  22. data/lib/merb-core/controller/mixins/authentication.rb +87 -0
  23. data/lib/merb-core/controller/mixins/controller.rb +290 -0
  24. data/lib/merb-core/controller/mixins/render.rb +481 -0
  25. data/lib/merb-core/controller/mixins/responder.rb +472 -0
  26. data/lib/merb-core/controller/template.rb +254 -0
  27. data/lib/merb-core/core_ext.rb +8 -0
  28. data/lib/merb-core/core_ext/kernel.rb +319 -0
  29. data/lib/merb-core/dispatch/cookies.rb +91 -0
  30. data/lib/merb-core/dispatch/dispatcher.rb +278 -0
  31. data/lib/merb-core/dispatch/exceptions.html.erb +303 -0
  32. data/lib/merb-core/dispatch/request.rb +603 -0
  33. data/lib/merb-core/dispatch/router.rb +179 -0
  34. data/lib/merb-core/dispatch/router/behavior.rb +867 -0
  35. data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
  36. data/lib/merb-core/dispatch/router/route.rb +321 -0
  37. data/lib/merb-core/dispatch/session.rb +78 -0
  38. data/lib/merb-core/dispatch/session/cookie.rb +168 -0
  39. data/lib/merb-core/dispatch/session/memcached.rb +184 -0
  40. data/lib/merb-core/dispatch/session/memory.rb +241 -0
  41. data/lib/merb-core/dispatch/worker.rb +28 -0
  42. data/lib/merb-core/gem_ext/erubis.rb +77 -0
  43. data/lib/{extlib → merb-core}/logger.rb +2 -2
  44. data/lib/merb-core/plugins.rb +59 -0
  45. data/lib/merb-core/rack.rb +21 -0
  46. data/lib/merb-core/rack/adapter.rb +44 -0
  47. data/lib/merb-core/rack/adapter/ebb.rb +25 -0
  48. data/lib/merb-core/rack/adapter/evented_mongrel.rb +26 -0
  49. data/lib/merb-core/rack/adapter/fcgi.rb +17 -0
  50. data/lib/merb-core/rack/adapter/irb.rb +118 -0
  51. data/lib/merb-core/rack/adapter/mongrel.rb +26 -0
  52. data/lib/merb-core/rack/adapter/runner.rb +28 -0
  53. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
  54. data/lib/merb-core/rack/adapter/thin.rb +39 -0
  55. data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
  56. data/lib/merb-core/rack/adapter/webrick.rb +36 -0
  57. data/lib/merb-core/rack/application.rb +18 -0
  58. data/lib/merb-core/rack/handler/mongrel.rb +97 -0
  59. data/lib/merb-core/rack/middleware.rb +26 -0
  60. data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
  61. data/lib/merb-core/rack/middleware/profiler.rb +19 -0
  62. data/lib/merb-core/rack/middleware/static.rb +45 -0
  63. data/lib/merb-core/server.rb +252 -0
  64. data/lib/merb-core/tasks/audit.rake +68 -0
  65. data/lib/merb-core/tasks/merb.rb +1 -0
  66. data/lib/merb-core/tasks/merb_rake_helper.rb +12 -0
  67. data/lib/merb-core/test.rb +11 -0
  68. data/lib/merb-core/test/helpers.rb +9 -0
  69. data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
  70. data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
  71. data/lib/merb-core/test/helpers/request_helper.rb +344 -0
  72. data/lib/merb-core/test/helpers/route_helper.rb +33 -0
  73. data/lib/merb-core/test/helpers/view_helper.rb +121 -0
  74. data/lib/merb-core/test/matchers.rb +9 -0
  75. data/lib/merb-core/test/matchers/controller_matchers.rb +319 -0
  76. data/lib/merb-core/test/matchers/route_matchers.rb +136 -0
  77. data/lib/merb-core/test/matchers/view_matchers.rb +335 -0
  78. data/lib/merb-core/test/run_specs.rb +47 -0
  79. data/lib/merb-core/test/tasks/spectasks.rb +68 -0
  80. data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
  81. data/lib/merb-core/test/test_ext/object.rb +14 -0
  82. data/lib/merb-core/test/test_ext/string.rb +14 -0
  83. data/lib/merb-core/vendor/facets.rb +2 -0
  84. data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
  85. data/lib/merb-core/vendor/facets/inflect.rb +345 -0
  86. data/lib/merb-core/version.rb +11 -0
  87. data/spec/private/config/adapter_spec.rb +32 -0
  88. data/spec/private/config/config_spec.rb +202 -0
  89. data/spec/private/config/environment_spec.rb +13 -0
  90. data/spec/private/config/spec_helper.rb +1 -0
  91. data/spec/private/core_ext/kernel_spec.rb +169 -0
  92. data/spec/private/dispatch/bootloader_spec.rb +24 -0
  93. data/spec/private/dispatch/cookies_spec.rb +107 -0
  94. data/spec/private/dispatch/dispatch_spec.rb +35 -0
  95. data/spec/private/dispatch/fixture/app/controllers/application.rb +4 -0
  96. data/spec/private/dispatch/fixture/app/controllers/exceptions.rb +27 -0
  97. data/spec/private/dispatch/fixture/app/controllers/foo.rb +21 -0
  98. data/spec/private/dispatch/fixture/app/helpers/global_helpers.rb +8 -0
  99. data/spec/private/dispatch/fixture/app/views/exeptions/client_error.html.erb +37 -0
  100. data/spec/private/dispatch/fixture/app/views/exeptions/internal_server_error.html.erb +216 -0
  101. data/spec/private/dispatch/fixture/app/views/exeptions/not_acceptable.html.erb +38 -0
  102. data/spec/private/dispatch/fixture/app/views/exeptions/not_found.html.erb +40 -0
  103. data/spec/private/dispatch/fixture/app/views/foo/bar.html.erb +0 -0
  104. data/spec/private/dispatch/fixture/app/views/layout/application.html.erb +11 -0
  105. data/spec/private/dispatch/fixture/config/black_hole.rb +12 -0
  106. data/spec/private/dispatch/fixture/config/environments/development.rb +6 -0
  107. data/spec/private/dispatch/fixture/config/environments/production.rb +5 -0
  108. data/spec/private/dispatch/fixture/config/environments/test.rb +6 -0
  109. data/spec/private/dispatch/fixture/config/init.rb +45 -0
  110. data/spec/private/dispatch/fixture/config/rack.rb +11 -0
  111. data/spec/private/dispatch/fixture/config/router.rb +35 -0
  112. data/spec/private/dispatch/fixture/log/merb_test.log +1874 -0
  113. data/spec/private/dispatch/fixture/public/images/merb.jpg +0 -0
  114. data/spec/private/dispatch/fixture/public/merb.fcgi +4 -0
  115. data/spec/private/dispatch/fixture/public/stylesheets/master.css +119 -0
  116. data/spec/private/dispatch/route_params_spec.rb +24 -0
  117. data/spec/private/dispatch/session_mixin_spec.rb +47 -0
  118. data/spec/private/dispatch/spec_helper.rb +1 -0
  119. data/spec/private/plugins/plugin_spec.rb +166 -0
  120. data/spec/private/rack/application_spec.rb +49 -0
  121. data/spec/private/router/behavior_spec.rb +60 -0
  122. data/spec/private/router/fixture/log/merb_test.log +139 -0
  123. data/spec/private/router/route_spec.rb +414 -0
  124. data/spec/private/router/router_spec.rb +175 -0
  125. data/spec/private/vendor/facets/plural_spec.rb +564 -0
  126. data/spec/private/vendor/facets/singular_spec.rb +489 -0
  127. data/spec/public/DEFINITIONS +11 -0
  128. data/spec/public/abstract_controller/controllers/alt_views/layout/application.erb +1 -0
  129. data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_string_controller_layout.erb +1 -0
  130. data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_template_controller_layout.erb +1 -0
  131. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/index.erb +1 -0
  132. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/show.erb +1 -0
  133. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
  134. data/spec/public/abstract_controller/controllers/alt_views/partial/basic_partial_with_multiple_roots/_partial.erb +1 -0
  135. data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_and_custom_location/index.erb +1 -0
  136. data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_inherited/index.erb +1 -0
  137. data/spec/public/abstract_controller/controllers/cousins.rb +41 -0
  138. data/spec/public/abstract_controller/controllers/display.rb +54 -0
  139. data/spec/public/abstract_controller/controllers/filters.rb +193 -0
  140. data/spec/public/abstract_controller/controllers/helpers.rb +41 -0
  141. data/spec/public/abstract_controller/controllers/partial.rb +121 -0
  142. data/spec/public/abstract_controller/controllers/render.rb +113 -0
  143. data/spec/public/abstract_controller/controllers/views/helpers/capture/index.erb +1 -0
  144. data/spec/public/abstract_controller/controllers/views/helpers/capture_eq/index.erb +1 -0
  145. data/spec/public/abstract_controller/controllers/views/helpers/capture_with_args/index.erb +1 -0
  146. data/spec/public/abstract_controller/controllers/views/helpers/concat/index.erb +1 -0
  147. data/spec/public/abstract_controller/controllers/views/layout/alt.erb +1 -0
  148. data/spec/public/abstract_controller/controllers/views/layout/custom.erb +1 -0
  149. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object/index.erb +1 -0
  150. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object_with_action/new.erb +1 -0
  151. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template/index.erb +1 -0
  152. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_app_layout/index.erb +0 -0
  153. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_custom_layout/index.erb +1 -0
  154. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
  155. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/show.erb +1 -0
  156. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_two_throw_contents/index.erb +1 -0
  157. data/spec/public/abstract_controller/controllers/views/partial/another_directory/_partial.erb +1 -0
  158. data/spec/public/abstract_controller/controllers/views/partial/basic_partial/_partial.erb +1 -0
  159. data/spec/public/abstract_controller/controllers/views/partial/basic_partial/index.erb +1 -0
  160. data/spec/public/abstract_controller/controllers/views/partial/basic_partial_with_multiple_roots/index.erb +1 -0
  161. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_first.erb +1 -0
  162. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_second.erb +1 -0
  163. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/index.erb +1 -0
  164. data/spec/public/abstract_controller/controllers/views/partial/partial_in_another_directory/index.erb +1 -0
  165. data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/_collection.erb +1 -0
  166. data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/index.erb +1 -0
  167. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/_collection.erb +1 -0
  168. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/index.erb +1 -0
  169. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/_collection.erb +1 -0
  170. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/index.erb +1 -0
  171. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/_collection.erb +1 -0
  172. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/index.erb +1 -0
  173. data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/_variables.erb +1 -0
  174. data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/index.erb +1 -0
  175. data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/_both.erb +1 -0
  176. data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/index.erb +1 -0
  177. data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/_partial.erb +1 -0
  178. data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/index.erb +1 -0
  179. data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/_with_partial.erb +1 -0
  180. data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/index.erb +1 -0
  181. data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/_with_partial.erb +1 -0
  182. data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/index.erb +1 -0
  183. data/spec/public/abstract_controller/controllers/views/partial/with_partial/_with_partial.erb +1 -0
  184. data/spec/public/abstract_controller/controllers/views/partial/with_partial/index.erb +1 -0
  185. data/spec/public/abstract_controller/controllers/views/test_display/foo.html.erb +1 -0
  186. data/spec/public/abstract_controller/controllers/views/test_render/foo.html.erb +0 -0
  187. data/spec/public/abstract_controller/controllers/views/wonderful/index.erb +1 -0
  188. data/spec/public/abstract_controller/display_spec.rb +33 -0
  189. data/spec/public/abstract_controller/filter_spec.rb +106 -0
  190. data/spec/public/abstract_controller/helper_spec.rb +21 -0
  191. data/spec/public/abstract_controller/partial_spec.rb +61 -0
  192. data/spec/public/abstract_controller/render_spec.rb +90 -0
  193. data/spec/public/abstract_controller/spec_helper.rb +31 -0
  194. data/spec/public/boot_loader/boot_loader_spec.rb +33 -0
  195. data/spec/public/boot_loader/spec_helper.rb +1 -0
  196. data/spec/public/controller/authentication_spec.rb +103 -0
  197. data/spec/public/controller/base_spec.rb +36 -0
  198. data/spec/public/controller/controllers/authentication.rb +45 -0
  199. data/spec/public/controller/controllers/base.rb +36 -0
  200. data/spec/public/controller/controllers/display.rb +118 -0
  201. data/spec/public/controller/controllers/redirect.rb +30 -0
  202. data/spec/public/controller/controllers/responder.rb +93 -0
  203. data/spec/public/controller/controllers/url.rb +7 -0
  204. data/spec/public/controller/controllers/views/layout/custom.html.erb +1 -0
  205. data/spec/public/controller/controllers/views/layout/custom_arg.html.erb +1 -0
  206. data/spec/public/controller/controllers/views/layout/custom_arg.json.erb +1 -0
  207. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.html.erb +1 -0
  208. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.xml.erb +1 -0
  209. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.html.erb +1 -0
  210. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.xml.erb +1 -0
  211. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/index.html.erb +1 -0
  212. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/no_layout.html.erb +1 -0
  213. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template_argument/index.html.erb +1 -0
  214. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/html_default/index.html.erb +1 -0
  215. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/layout/custom.html.erb +1 -0
  216. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.html.erb +1 -0
  217. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.xml.erb +1 -0
  218. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.html.erb +1 -0
  219. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.js.erb +1 -0
  220. data/spec/public/controller/display_spec.rb +84 -0
  221. data/spec/public/controller/redirect_spec.rb +27 -0
  222. data/spec/public/controller/responder_spec.rb +163 -0
  223. data/spec/public/controller/spec_helper.rb +11 -0
  224. data/spec/public/controller/url_spec.rb +180 -0
  225. data/spec/public/core/merb_core_spec.rb +45 -0
  226. data/spec/public/core_ext/class_spec.rb +91 -0
  227. data/spec/public/core_ext/fixtures/core_ext_dependency.rb +2 -0
  228. data/spec/public/core_ext/kernel_spec.rb +9 -0
  229. data/spec/public/core_ext/spec_helper.rb +1 -0
  230. data/spec/public/directory_structure/directory/app/controllers/application.rb +3 -0
  231. data/spec/public/directory_structure/directory/app/controllers/base.rb +13 -0
  232. data/spec/public/directory_structure/directory/app/controllers/custom.rb +19 -0
  233. data/spec/public/directory_structure/directory/app/views/base/template.html.erb +1 -0
  234. data/spec/public/directory_structure/directory/app/views/wonderful/template.erb +1 -0
  235. data/spec/public/directory_structure/directory/config/router.rb +3 -0
  236. data/spec/public/directory_structure/directory/log/merb_test.log +562 -0
  237. data/spec/public/directory_structure/directory_spec.rb +44 -0
  238. data/spec/public/logger/logger_spec.rb +181 -0
  239. data/spec/public/logger/spec_helper.rb +1 -0
  240. data/spec/public/reloading/directory/app/controllers/application.rb +3 -0
  241. data/spec/public/reloading/directory/app/controllers/reload.rb +6 -0
  242. data/spec/public/reloading/directory/config/init.rb +2 -0
  243. data/spec/public/reloading/directory/log/merb_test.log +138 -0
  244. data/spec/public/reloading/reload_spec.rb +103 -0
  245. data/spec/public/request/multipart_spec.rb +41 -0
  246. data/spec/public/request/request_spec.rb +228 -0
  247. data/spec/public/router/default_spec.rb +21 -0
  248. data/spec/public/router/deferred_spec.rb +22 -0
  249. data/spec/public/router/fixation_spec.rb +27 -0
  250. data/spec/public/router/fixture/log/merb_test.log +1556 -0
  251. data/spec/public/router/namespace_spec.rb +113 -0
  252. data/spec/public/router/nested_matches_spec.rb +97 -0
  253. data/spec/public/router/nested_resources_spec.rb +41 -0
  254. data/spec/public/router/resource_spec.rb +37 -0
  255. data/spec/public/router/resources_spec.rb +82 -0
  256. data/spec/public/router/spec_helper.rb +90 -0
  257. data/spec/public/router/special_spec.rb +61 -0
  258. data/spec/public/router/string_spec.rb +61 -0
  259. data/spec/public/template/template_spec.rb +104 -0
  260. data/spec/public/template/templates/error.html.erb +2 -0
  261. data/spec/public/template/templates/template.html.erb +1 -0
  262. data/spec/public/template/templates/template.html.myt +1 -0
  263. data/spec/public/test/controller_matchers_spec.rb +402 -0
  264. data/spec/public/test/controllers/controller_assertion_mock.rb +7 -0
  265. data/spec/public/test/controllers/dispatch_controller.rb +11 -0
  266. data/spec/public/test/controllers/spec_helper_controller.rb +38 -0
  267. data/spec/public/test/multipart_request_helper_spec.rb +159 -0
  268. data/spec/public/test/multipart_upload_text_file.txt +1 -0
  269. data/spec/public/test/request_helper_spec.rb +221 -0
  270. data/spec/public/test/route_helper_spec.rb +71 -0
  271. data/spec/public/test/route_matchers_spec.rb +162 -0
  272. data/spec/public/test/view_helper_spec.rb +96 -0
  273. data/spec/public/test/view_matchers_spec.rb +183 -0
  274. data/spec/spec_helper.rb +68 -0
  275. metadata +493 -41
  276. data/README.txt +0 -3
  277. data/lib/extlib.rb +0 -32
  278. data/lib/extlib/assertions.rb +0 -8
  279. data/lib/extlib/blank.rb +0 -42
  280. data/lib/extlib/class.rb +0 -175
  281. data/lib/extlib/hash.rb +0 -410
  282. data/lib/extlib/hook.rb +0 -366
  283. data/lib/extlib/inflection.rb +0 -141
  284. data/lib/extlib/lazy_array.rb +0 -106
  285. data/lib/extlib/mash.rb +0 -143
  286. data/lib/extlib/module.rb +0 -37
  287. data/lib/extlib/object.rb +0 -165
  288. data/lib/extlib/object_space.rb +0 -13
  289. data/lib/extlib/pathname.rb +0 -5
  290. data/lib/extlib/pooling.rb +0 -233
  291. data/lib/extlib/rubygems.rb +0 -38
  292. data/lib/extlib/simple_set.rb +0 -39
  293. data/lib/extlib/string.rb +0 -132
  294. data/lib/extlib/struct.rb +0 -8
  295. data/lib/extlib/tasks/release.rb +0 -9
  296. data/lib/extlib/time.rb +0 -12
  297. data/lib/extlib/version.rb +0 -3
  298. data/lib/extlib/virtual_file.rb +0 -10
@@ -1,366 +0,0 @@
1
- module Extlib
2
- #
3
- # TODO: Write more documentation!
4
- #
5
- # Overview
6
- # ========
7
- #
8
- # The Hook module is a very simple set of AOP helpers. Basically, it
9
- # allows the developer to specify a method or block that should run
10
- # before or after another method.
11
- #
12
- # Usage
13
- # =====
14
- #
15
- # Halting The Hook Stack
16
- #
17
- # Inheritance
18
- #
19
- # Other Goodies
20
- #
21
- # Please bring up any issues regarding Hooks with carllerche on IRC
22
- #
23
- module Hook
24
-
25
- def self.included(base)
26
- base.extend(ClassMethods)
27
- base.const_set("CLASS_HOOKS", {}) unless base.const_defined?("CLASS_HOOKS")
28
- base.const_set("INSTANCE_HOOKS", {}) unless base.const_defined?("INSTANCE_HOOKS")
29
- base.class_eval do
30
- class << self
31
- def method_added(name)
32
- process_method_added(name, :instance)
33
- end
34
-
35
- def singleton_method_added(name)
36
- process_method_added(name, :class)
37
- end
38
- end
39
- end
40
- end
41
-
42
- module ClassMethods
43
- include Extlib::Assertions
44
- # Inject code that executes before the target class method.
45
- #
46
- # @param target_method<Symbol> the name of the class method to inject before
47
- # @param method_sym<Symbol> the name of the method to run before the
48
- # target_method
49
- # @param block<Block> the code to run before the target_method
50
- #
51
- # @note
52
- # Either method_sym or block is required.
53
- # -
54
- # @api public
55
- def before_class_method(target_method, method_sym = nil, &block)
56
- install_hook :before, target_method, method_sym, :class, &block
57
- end
58
-
59
- #
60
- # Inject code that executes after the target class method.
61
- #
62
- # @param target_method<Symbol> the name of the class method to inject after
63
- # @param method_sym<Symbol> the name of the method to run after the target_method
64
- # @param block<Block> the code to run after the target_method
65
- #
66
- # @note
67
- # Either method_sym or block is required.
68
- # -
69
- # @api public
70
- def after_class_method(target_method, method_sym = nil, &block)
71
- install_hook :after, target_method, method_sym, :class, &block
72
- end
73
-
74
- #
75
- # Inject code that executes before the target instance method.
76
- #
77
- # @param target_method<Symbol> the name of the instance method to inject before
78
- # @param method_sym<Symbol> the name of the method to run before the
79
- # target_method
80
- # @param block<Block> the code to run before the target_method
81
- #
82
- # @note
83
- # Either method_sym or block is required.
84
- # -
85
- # @api public
86
- def before(target_method, method_sym = nil, &block)
87
- install_hook :before, target_method, method_sym, :instance, &block
88
- end
89
-
90
- #
91
- # Inject code that executes after the target instance method.
92
- #
93
- # @param target_method<Symbol> the name of the instance method to inject after
94
- # @param method_sym<Symbol> the name of the method to run after the
95
- # target_method
96
- # @param block<Block> the code to run after the target_method
97
- #
98
- # @note
99
- # Either method_sym or block is required.
100
- # -
101
- # @api public
102
- def after(target_method, method_sym = nil, &block)
103
- install_hook :after, target_method, method_sym, :instance, &block
104
- end
105
-
106
- # Register a class method as hookable. Registering a method means that
107
- # before hooks will be run immediately before the method is invoked and
108
- # after hooks will be called immediately after the method is invoked.
109
- #
110
- # @param hookable_method<Symbol> The name of the class method that should
111
- # be hookable
112
- # -
113
- # @api public
114
- def register_class_hooks(*hooks)
115
- hooks.each { |hook| register_hook(hook, :class) }
116
- end
117
-
118
- # Register aninstance method as hookable. Registering a method means that
119
- # before hooks will be run immediately before the method is invoked and
120
- # after hooks will be called immediately after the method is invoked.
121
- #
122
- # @param hookable_method<Symbol> The name of the instance method that should
123
- # be hookable
124
- # -
125
- # @api public
126
- def register_instance_hooks(*hooks)
127
- hooks.each { |hook| register_hook(hook, :instance) }
128
- end
129
-
130
- # Not yet implemented
131
- def reset_hook!(target_method, scope)
132
- raise NotImplementedError
133
- end
134
-
135
- # --- Alright kids... the rest is internal stuff ---
136
-
137
- # Returns the correct HOOKS Hash depending on whether we are
138
- # working with class methods or instance methods
139
- def hooks_with_scope(scope)
140
- case scope
141
- when :class then class_hooks
142
- when :instance then instance_hooks
143
- else raise ArgumentError, 'You need to pass :class or :instance as scope'
144
- end
145
- end
146
-
147
- def class_hooks
148
- self.const_get("CLASS_HOOKS")
149
- end
150
-
151
- def instance_hooks
152
- self.const_get("INSTANCE_HOOKS")
153
- end
154
-
155
- # Registers a method as hookable. Registering hooks involves the following
156
- # process
157
- #
158
- # * Create a blank entry in the HOOK Hash for the method.
159
- # * Define the methods that execute the before and after hook stack.
160
- # These methods will be no-ops at first, but everytime a new hook is
161
- # defined, the methods will be redefined to incorporate the new hook.
162
- # * Redefine the method that is to be hookable so that the hook stacks
163
- # are invoked approprietly.
164
- def register_hook(target_method, scope)
165
- if scope == :instance && !method_defined?(target_method)
166
- raise ArgumentError, "#{target_method} instance method does not exist"
167
- elsif scope == :class && !respond_to?(target_method)
168
- raise ArgumentError, "#{target_method} class method does not exist"
169
- end
170
-
171
- hooks = hooks_with_scope(scope)
172
-
173
- if hooks[target_method].nil?
174
- hooks[target_method] = {
175
- # We need to keep track of which class in the Inheritance chain the
176
- # method was declared hookable in. Every time a child declares a new
177
- # hook for the method, the hook stack invocations need to be redefined
178
- # in the original Class. See #define_hook_stack_execution_methods
179
- :before => [], :after => [], :in => self
180
- }
181
-
182
- define_hook_stack_execution_methods(target_method, scope)
183
- define_advised_method(target_method, scope)
184
- end
185
- end
186
-
187
- # Is the method registered as a hookable in the given scope.
188
- def registered_as_hook?(target_method, scope)
189
- ! hooks_with_scope(scope)[target_method].nil?
190
- end
191
-
192
- # Generates names for the various utility methods. We need to do this because
193
- # the various utility methods should not end in = so, while we're at it, we
194
- # might as well get rid of all punctuation.
195
- def hook_method_name(target_method, prefix, suffix)
196
- target_method = target_method.to_s
197
-
198
- case target_method[-1,1]
199
- when '?' then "#{prefix}_#{target_method[0..-2]}_ques_#{suffix}"
200
- when '!' then "#{prefix}_#{target_method[0..-2]}_bang_#{suffix}"
201
- when '=' then "#{prefix}_#{target_method[0..-2]}_eq_#{suffix}"
202
- # I add a _nan_ suffix here so that we don't ever encounter
203
- # any naming conflicts.
204
- else "#{prefix}_#{target_method[0..-1]}_nan_#{suffix}"
205
- end
206
- end
207
-
208
- # This will need to be refactored
209
- def process_method_added(method_name, scope)
210
- hooks_with_scope(scope).each do |target_method, hooks|
211
- if hooks[:before].any? { |hook| hook[:name] == method_name }
212
- define_hook_stack_execution_methods(target_method, scope)
213
- end
214
-
215
- if hooks[:after].any? { |hook| hook[:name] == method_name }
216
- define_hook_stack_execution_methods(target_method, scope)
217
- end
218
- end
219
- end
220
-
221
- # Defines two methods. One method executes the before hook stack. The other executes
222
- # the after hook stack. This method will be called many times during the Class definition
223
- # process. It should be called for each hook that is defined. It will also be called
224
- # when a hook is redefined (to make sure that the arity hasn't changed).
225
- def define_hook_stack_execution_methods(target_method, scope)
226
- unless registered_as_hook?(target_method, scope)
227
- raise ArgumentError, "#{target_method} has not be registered as a hookable #{scope} method"
228
- end
229
-
230
- hooks = hooks_with_scope(scope)
231
-
232
- before_hooks = hooks[target_method][:before]
233
- before_hooks = before_hooks.map{ |info| inline_call(info, scope) }.join("\n")
234
-
235
- after_hooks = hooks[target_method][:after]
236
- after_hooks = after_hooks.map{ |info| inline_call(info, scope) }.join("\n")
237
-
238
- source = %{
239
- private
240
-
241
- def #{hook_method_name(target_method, 'execute_before', 'hook_stack')}(*args)
242
- #{before_hooks}
243
- end
244
-
245
- def #{hook_method_name(target_method, 'execute_after', 'hook_stack')}(*args)
246
- #{after_hooks}
247
- end
248
- }
249
-
250
- source = %{class << self\n#{source}\nend} if scope == :class
251
-
252
- hooks[target_method][:in].class_eval(source, __FILE__, __LINE__)
253
- end
254
-
255
- # Returns ruby code that will invoke the hook. It checks the arity of the hook method
256
- # and passes arguments accordingly.
257
- def inline_call(method_info, scope)
258
- name = method_info[:name]
259
-
260
- if scope == :instance
261
- args = method_defined?(name) && instance_method(name).arity != 0 ? '*args' : ''
262
- %(#{name}(#{args}) if self.class <= ObjectSpace._id2ref(#{method_info[:from].object_id}))
263
- else
264
- args = respond_to?(name) && method(name).arity != 0 ? '*args' : ''
265
- %(#{name}(#{args}) if self <= ObjectSpace._id2ref(#{method_info[:from].object_id}))
266
- end
267
- end
268
-
269
- def define_advised_method(target_method, scope)
270
- args = args_for(method_with_scope(target_method, scope))
271
-
272
- renamed_target = hook_method_name(target_method, 'hookable_', 'before_advised')
273
-
274
- source = <<-EOD
275
- def #{target_method}(#{args})
276
- retval = nil
277
- catch(:halt) do
278
- #{hook_method_name(target_method, 'execute_before', 'hook_stack')}(#{args})
279
- retval = #{renamed_target}(#{args})
280
- #{hook_method_name(target_method, 'execute_after', 'hook_stack')}(retval, #{args})
281
- retval
282
- end
283
- end
284
- EOD
285
-
286
- if scope == :instance && !instance_methods(false).include?(target_method.to_s)
287
- send(:alias_method, renamed_target, target_method)
288
-
289
- proxy_module = Module.new
290
- proxy_module.class_eval(source, __FILE__, __LINE__)
291
- self.send(:include, proxy_module)
292
- else
293
- source = %{alias_method :#{renamed_target}, :#{target_method}\n#{source}}
294
- source = %{class << self\n#{source}\nend} if scope == :class
295
- class_eval(source, __FILE__, __LINE__)
296
- end
297
- end
298
-
299
- # --- Add a hook ---
300
-
301
- def install_hook(type, target_method, method_sym, scope, &block)
302
- assert_kind_of 'target_method', target_method, Symbol
303
- assert_kind_of 'method_sym', method_sym, Symbol unless method_sym.nil?
304
- assert_kind_of 'scope', scope, Symbol
305
-
306
- if !block_given? and method_sym.nil?
307
- raise ArgumentError, "You need to pass 2 arguments to \"#{type}\"."
308
- end
309
-
310
- if method_sym.to_s[-1,1] == '='
311
- raise ArgumentError, "Methods ending in = cannot be hooks"
312
- end
313
-
314
- unless [ :class, :instance ].include?(scope)
315
- raise ArgumentError, 'You need to pass :class or :instance as scope'
316
- end
317
-
318
- register_hook(target_method, scope) unless registered_as_hook?(target_method, scope)
319
-
320
- hooks = hooks_with_scope(scope)
321
-
322
- if block
323
- method_sym = "__hooks_#{type}_#{quote_method(target_method)}_#{hooks[target_method][type].length}".to_sym
324
- if scope == :class
325
- (class << self; self; end;).instance_eval do
326
- define_method(method_sym, &block)
327
- end
328
- else
329
- define_method(method_sym, &block)
330
- end
331
- end
332
-
333
- # Adds method to the stack an redefines the hook invocation method
334
- hooks[target_method][type] << { :name => method_sym, :from => self }
335
- define_hook_stack_execution_methods(target_method, scope)
336
- end
337
-
338
- # --- Helpers ---
339
-
340
- def args_for(method)
341
- if method.arity == 0
342
- "&block"
343
- elsif method.arity > 0
344
- "_" << (1 .. method.arity).to_a.join(", _") << ", &block"
345
- elsif (method.arity + 1) < 0
346
- "_" << (1 .. (method.arity).abs - 1).to_a.join(", _") << ", *args, &block"
347
- else
348
- "*args, &block"
349
- end
350
- end
351
-
352
- def method_with_scope(name, scope)
353
- case scope
354
- when :class then method(name)
355
- when :instance then instance_method(name)
356
- else raise ArgumentError, 'You need to pass :class or :instance as scope'
357
- end
358
- end
359
-
360
- def quote_method(name)
361
- name.to_s.gsub(/\?$/, '_q_').gsub(/!$/, '_b_').gsub(/=$/, '_eq_')
362
- end
363
- end
364
-
365
- end
366
- end
@@ -1,141 +0,0 @@
1
- # The original of this file was copied for the ActiveSupport project which is
2
- # part of the Ruby On Rails web-framework (http://rubyonrails.org)
3
- #
4
- # Methods have been modified or removed. English inflection is now provided via
5
- # the english gem (http://english.rubyforge.org)
6
- #
7
- # sudo gem install english
8
- #
9
- gem 'english', '>=0.2.0'
10
- require 'english/inflect'
11
-
12
- English::Inflect.word 'postgres'
13
-
14
- module Extlib
15
- module Inflection
16
- class << self
17
- # Take an underscored name and make it into a camelized name
18
- #
19
- # @example
20
- # "egg_and_hams".classify #=> "EggAndHam"
21
- # "post".classify #=> "Post"
22
- #
23
- def classify(name)
24
- camelize(singularize(name.to_s.sub(/.*\./, '')))
25
- end
26
-
27
- # By default, camelize converts strings to UpperCamelCase.
28
- #
29
- # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
30
- #
31
- # @example
32
- # "active_record".camelize #=> "ActiveRecord"
33
- # "active_record/errors".camelize #=> "ActiveRecord::Errors"
34
- #
35
- def camelize(lower_case_and_underscored_word, *args)
36
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
37
- end
38
-
39
-
40
- # The reverse of +camelize+. Makes an underscored form from the expression in the string.
41
- #
42
- # Changes '::' to '/' to convert namespaces to paths.
43
- #
44
- # @example
45
- # "ActiveRecord".underscore #=> "active_record"
46
- # "ActiveRecord::Errors".underscore #=> active_record/errors
47
- #
48
- def underscore(camel_cased_word)
49
- camel_cased_word.to_s.gsub(/::/, '/').
50
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
51
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
52
- tr("-", "_").
53
- downcase
54
- end
55
-
56
- # Capitalizes the first word and turns underscores into spaces and strips _id.
57
- # Like titleize, this is meant for creating pretty output.
58
- #
59
- # @example
60
- # "employee_salary" #=> "Employee salary"
61
- # "author_id" #=> "Author"
62
- def humanize(lower_case_and_underscored_word)
63
- lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
64
- end
65
-
66
- # Removes the module part from the expression in the string
67
- #
68
- # @example
69
- # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
70
- # "Inflections".demodulize #=> "Inflections"
71
- def demodulize(class_name_in_module)
72
- class_name_in_module.to_s.gsub(/^.*::/, '')
73
- end
74
-
75
- # Create the name of a table like Rails does for models to table names. This method
76
- # uses the pluralize method on the last word in the string.
77
- #
78
- # @example
79
- # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
80
- # "egg_and_ham".tableize #=> "egg_and_hams"
81
- # "fancyCategory".tableize #=> "fancy_categories"
82
- def tableize(class_name)
83
- pluralize(underscore(class_name))
84
- end
85
-
86
- # Creates a foreign key name from a class name.
87
- #
88
- # @example
89
- # "Message".foreign_key #=> "message_id"
90
- # "Admin::Post".foreign_key #=> "post_id"
91
- def foreign_key(class_name, key = "id")
92
- underscore(demodulize(class_name.to_s)) << "_" << key.to_s
93
- end
94
-
95
- # Constantize tries to find a declared constant with the name specified
96
- # in the string. It raises a NameError when the name is not in CamelCase
97
- # or is not initialized.
98
- #
99
- # @example
100
- # "Module".constantize #=> Module
101
- # "Class".constantize #=> Class
102
- def constantize(camel_cased_word)
103
- unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
104
- raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
105
- end
106
-
107
- Object.module_eval("::#{$1}", __FILE__, __LINE__)
108
- end
109
-
110
- # The reverse of pluralize, returns the singular form of a word in a string.
111
- # Wraps the English gem
112
- #
113
- # @example
114
- # "posts".singularize #=> "post"
115
- # "octopi".singularize #=> "octopus"
116
- # "sheep".singluarize #=> "sheep"
117
- # "word".singluarize #=> "word"
118
- # "the blue mailmen".singularize #=> "the blue mailman"
119
- # "CamelOctopi".singularize #=> "CamelOctopus"
120
- #
121
- def singularize(word)
122
- English::Inflect.singular(word)
123
- end
124
-
125
- # Returns the plural form of the word in the string.
126
- #
127
- # @example
128
- # "post".pluralize #=> "posts"
129
- # "octopus".pluralize #=> "octopi"
130
- # "sheep".pluralize #=> "sheep"
131
- # "words".pluralize #=> "words"
132
- # "the blue mailman".pluralize #=> "the blue mailmen"
133
- # "CamelOctopus".pluralize #=> "CamelOctopi"
134
- #
135
- def pluralize(word)
136
- English::Inflect.plural(word)
137
- end
138
-
139
- end
140
- end # module Inflection
141
- end # module Extlib