merb-core 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. data/LICENSE +20 -0
  2. data/README +21 -0
  3. data/Rakefile +285 -0
  4. data/TODO +0 -0
  5. data/bin/merb +8 -0
  6. data/bin/merb-specs +5 -0
  7. data/docs/bootloading.dox +57 -0
  8. data/docs/documentation_standards +40 -0
  9. data/docs/new_render_api +51 -0
  10. data/lib/merb-core.rb +304 -0
  11. data/lib/merb-core/autoload.rb +29 -0
  12. data/lib/merb-core/bootloader.rb +601 -0
  13. data/lib/merb-core/config.rb +284 -0
  14. data/lib/merb-core/constants.rb +43 -0
  15. data/lib/merb-core/controller/abstract_controller.rb +531 -0
  16. data/lib/merb-core/controller/exceptions.rb +257 -0
  17. data/lib/merb-core/controller/merb_controller.rb +214 -0
  18. data/lib/merb-core/controller/mime.rb +88 -0
  19. data/lib/merb-core/controller/mixins/controller.rb +262 -0
  20. data/lib/merb-core/controller/mixins/render.rb +324 -0
  21. data/lib/merb-core/controller/mixins/responder.rb +464 -0
  22. data/lib/merb-core/controller/template.rb +205 -0
  23. data/lib/merb-core/core_ext.rb +12 -0
  24. data/lib/merb-core/core_ext/class.rb +192 -0
  25. data/lib/merb-core/core_ext/hash.rb +422 -0
  26. data/lib/merb-core/core_ext/kernel.rb +304 -0
  27. data/lib/merb-core/core_ext/mash.rb +154 -0
  28. data/lib/merb-core/core_ext/object.rb +136 -0
  29. data/lib/merb-core/core_ext/object_space.rb +14 -0
  30. data/lib/merb-core/core_ext/rubygems.rb +28 -0
  31. data/lib/merb-core/core_ext/set.rb +41 -0
  32. data/lib/merb-core/core_ext/string.rb +69 -0
  33. data/lib/merb-core/dispatch/cookies.rb +92 -0
  34. data/lib/merb-core/dispatch/dispatcher.rb +233 -0
  35. data/lib/merb-core/dispatch/exceptions.html.erb +297 -0
  36. data/lib/merb-core/dispatch/request.rb +560 -0
  37. data/lib/merb-core/dispatch/router.rb +141 -0
  38. data/lib/merb-core/dispatch/router/behavior.rb +777 -0
  39. data/lib/merb-core/dispatch/router/cached_proc.rb +52 -0
  40. data/lib/merb-core/dispatch/router/route.rb +212 -0
  41. data/lib/merb-core/dispatch/session.rb +28 -0
  42. data/lib/merb-core/dispatch/session/cookie.rb +166 -0
  43. data/lib/merb-core/dispatch/session/memcached.rb +161 -0
  44. data/lib/merb-core/dispatch/session/memory.rb +234 -0
  45. data/lib/merb-core/gem_ext/erubis.rb +19 -0
  46. data/lib/merb-core/logger.rb +230 -0
  47. data/lib/merb-core/plugins.rb +25 -0
  48. data/lib/merb-core/rack.rb +15 -0
  49. data/lib/merb-core/rack/adapter.rb +42 -0
  50. data/lib/merb-core/rack/adapter/ebb.rb +22 -0
  51. data/lib/merb-core/rack/adapter/evented_mongrel.rb +24 -0
  52. data/lib/merb-core/rack/adapter/fcgi.rb +16 -0
  53. data/lib/merb-core/rack/adapter/irb.rb +108 -0
  54. data/lib/merb-core/rack/adapter/mongrel.rb +25 -0
  55. data/lib/merb-core/rack/adapter/runner.rb +27 -0
  56. data/lib/merb-core/rack/adapter/thin.rb +27 -0
  57. data/lib/merb-core/rack/adapter/webrick.rb +35 -0
  58. data/lib/merb-core/rack/application.rb +77 -0
  59. data/lib/merb-core/rack/handler/mongrel.rb +97 -0
  60. data/lib/merb-core/server.rb +184 -0
  61. data/lib/merb-core/test.rb +10 -0
  62. data/lib/merb-core/test/helpers.rb +9 -0
  63. data/lib/merb-core/test/helpers/controller_helper.rb +8 -0
  64. data/lib/merb-core/test/helpers/multipart_request_helper.rb +175 -0
  65. data/lib/merb-core/test/helpers/request_helper.rb +257 -0
  66. data/lib/merb-core/test/helpers/route_helper.rb +33 -0
  67. data/lib/merb-core/test/helpers/view_helper.rb +121 -0
  68. data/lib/merb-core/test/matchers.rb +9 -0
  69. data/lib/merb-core/test/matchers/controller_matchers.rb +269 -0
  70. data/lib/merb-core/test/matchers/route_matchers.rb +136 -0
  71. data/lib/merb-core/test/matchers/view_matchers.rb +293 -0
  72. data/lib/merb-core/test/run_specs.rb +38 -0
  73. data/lib/merb-core/test/tasks/spectasks.rb +39 -0
  74. data/lib/merb-core/test/test_ext/hpricot.rb +32 -0
  75. data/lib/merb-core/test/test_ext/object.rb +14 -0
  76. data/lib/merb-core/vendor/facets.rb +2 -0
  77. data/lib/merb-core/vendor/facets/dictionary.rb +433 -0
  78. data/lib/merb-core/vendor/facets/inflect.rb +211 -0
  79. data/lib/merb-core/version.rb +11 -0
  80. data/spec/private/config/adapter_spec.rb +32 -0
  81. data/spec/private/config/config_spec.rb +139 -0
  82. data/spec/private/config/environment_spec.rb +13 -0
  83. data/spec/private/config/spec_helper.rb +1 -0
  84. data/spec/private/core_ext/hash_spec.rb +506 -0
  85. data/spec/private/core_ext/kernel_spec.rb +46 -0
  86. data/spec/private/core_ext/object_spec.rb +39 -0
  87. data/spec/private/core_ext/set_spec.rb +26 -0
  88. data/spec/private/core_ext/string_spec.rb +9 -0
  89. data/spec/private/dispatch/cookies_spec.rb +107 -0
  90. data/spec/private/dispatch/dispatch_spec.rb +26 -0
  91. data/spec/private/dispatch/fixture/app/controllers/application.rb +4 -0
  92. data/spec/private/dispatch/fixture/app/controllers/exceptions.rb +27 -0
  93. data/spec/private/dispatch/fixture/app/controllers/foo.rb +21 -0
  94. data/spec/private/dispatch/fixture/app/helpers/global_helpers.rb +8 -0
  95. data/spec/private/dispatch/fixture/app/views/exeptions/client_error.html.erb +37 -0
  96. data/spec/private/dispatch/fixture/app/views/exeptions/internal_server_error.html.erb +216 -0
  97. data/spec/private/dispatch/fixture/app/views/exeptions/not_acceptable.html.erb +38 -0
  98. data/spec/private/dispatch/fixture/app/views/exeptions/not_found.html.erb +40 -0
  99. data/spec/private/dispatch/fixture/app/views/foo/bar.html.erb +0 -0
  100. data/spec/private/dispatch/fixture/app/views/layout/application.html.erb +11 -0
  101. data/spec/private/dispatch/fixture/config/environments/development.rb +6 -0
  102. data/spec/private/dispatch/fixture/config/environments/production.rb +5 -0
  103. data/spec/private/dispatch/fixture/config/environments/test.rb +6 -0
  104. data/spec/private/dispatch/fixture/config/init.rb +45 -0
  105. data/spec/private/dispatch/fixture/config/rack.rb +1 -0
  106. data/spec/private/dispatch/fixture/config/router.rb +35 -0
  107. data/spec/private/dispatch/fixture/log/development.log +1 -0
  108. data/spec/private/dispatch/fixture/log/merb.4000.pid +1 -0
  109. data/spec/private/dispatch/fixture/log/merb_test.log +2040 -0
  110. data/spec/private/dispatch/fixture/log/production.log +1 -0
  111. data/spec/private/dispatch/fixture/merb.4000.pid +1 -0
  112. data/spec/private/dispatch/fixture/public/images/merb.jpg +0 -0
  113. data/spec/private/dispatch/fixture/public/merb.fcgi +4 -0
  114. data/spec/private/dispatch/fixture/public/stylesheets/master.css +119 -0
  115. data/spec/private/dispatch/route_params_spec.rb +24 -0
  116. data/spec/private/dispatch/spec_helper.rb +1 -0
  117. data/spec/private/plugins/plugin_spec.rb +81 -0
  118. data/spec/private/rack/application_spec.rb +43 -0
  119. data/spec/public/DEFINITIONS +11 -0
  120. data/spec/public/abstract_controller/controllers/alt_views/layout/application.erb +1 -0
  121. data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_string_controller_layout.erb +1 -0
  122. data/spec/public/abstract_controller/controllers/alt_views/layout/merb/test/fixtures/abstract/render_template_controller_layout.erb +1 -0
  123. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/index.erb +1 -0
  124. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/display_object_with_multiple_roots/show.erb +1 -0
  125. data/spec/public/abstract_controller/controllers/alt_views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
  126. data/spec/public/abstract_controller/controllers/alt_views/partial/basic_partial_with_multiple_roots/_partial.erb +1 -0
  127. data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_and_custom_location/index.erb +1 -0
  128. data/spec/public/abstract_controller/controllers/alt_views/render_template_multiple_roots_inherited/index.erb +1 -0
  129. data/spec/public/abstract_controller/controllers/display.rb +54 -0
  130. data/spec/public/abstract_controller/controllers/filters.rb +167 -0
  131. data/spec/public/abstract_controller/controllers/helpers.rb +31 -0
  132. data/spec/public/abstract_controller/controllers/partial.rb +106 -0
  133. data/spec/public/abstract_controller/controllers/render.rb +86 -0
  134. data/spec/public/abstract_controller/controllers/views/helpers/capture/index.erb +1 -0
  135. data/spec/public/abstract_controller/controllers/views/helpers/concat/index.erb +1 -0
  136. data/spec/public/abstract_controller/controllers/views/layout/alt.erb +1 -0
  137. data/spec/public/abstract_controller/controllers/views/layout/custom.erb +1 -0
  138. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object/index.erb +1 -0
  139. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/display_object_with_action/new.erb +1 -0
  140. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template/index.erb +1 -0
  141. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_app_layout/index.erb +0 -0
  142. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_custom_layout/index.erb +1 -0
  143. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/index.erb +1 -0
  144. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_template_multiple_roots/show.erb +1 -0
  145. data/spec/public/abstract_controller/controllers/views/partial/another_directory/_partial.erb +1 -0
  146. data/spec/public/abstract_controller/controllers/views/partial/basic_partial/_partial.erb +1 -0
  147. data/spec/public/abstract_controller/controllers/views/partial/basic_partial/index.erb +1 -0
  148. data/spec/public/abstract_controller/controllers/views/partial/basic_partial_with_multiple_roots/index.erb +1 -0
  149. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_first.erb +1 -0
  150. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/_second.erb +1 -0
  151. data/spec/public/abstract_controller/controllers/views/partial/nested_partial/index.erb +1 -0
  152. data/spec/public/abstract_controller/controllers/views/partial/partial_in_another_directory/index.erb +1 -0
  153. data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/_collection.erb +1 -0
  154. data/spec/public/abstract_controller/controllers/views/partial/partial_with_both/index.erb +1 -0
  155. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/_collection.erb +1 -0
  156. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections/index.erb +1 -0
  157. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/_collection.erb +1 -0
  158. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_as/index.erb +1 -0
  159. data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/_variables.erb +1 -0
  160. data/spec/public/abstract_controller/controllers/views/partial/partial_with_locals/index.erb +1 -0
  161. data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/_both.erb +1 -0
  162. data/spec/public/abstract_controller/controllers/views/partial/partial_with_with_and_locals/index.erb +1 -0
  163. data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/_with_partial.erb +1 -0
  164. data/spec/public/abstract_controller/controllers/views/partial/with_as_partial/index.erb +1 -0
  165. data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/_with_partial.erb +1 -0
  166. data/spec/public/abstract_controller/controllers/views/partial/with_nil_partial/index.erb +1 -0
  167. data/spec/public/abstract_controller/controllers/views/partial/with_partial/_with_partial.erb +1 -0
  168. data/spec/public/abstract_controller/controllers/views/partial/with_partial/index.erb +1 -0
  169. data/spec/public/abstract_controller/controllers/views/test_display/foo.html.erb +1 -0
  170. data/spec/public/abstract_controller/controllers/views/test_render/foo.html.erb +0 -0
  171. data/spec/public/abstract_controller/controllers/views/wonderful/index.erb +1 -0
  172. data/spec/public/abstract_controller/display_spec.rb +33 -0
  173. data/spec/public/abstract_controller/filter_spec.rb +80 -0
  174. data/spec/public/abstract_controller/helper_spec.rb +13 -0
  175. data/spec/public/abstract_controller/partial_spec.rb +53 -0
  176. data/spec/public/abstract_controller/render_spec.rb +70 -0
  177. data/spec/public/abstract_controller/spec_helper.rb +27 -0
  178. data/spec/public/boot_loader/boot_loader_spec.rb +33 -0
  179. data/spec/public/boot_loader/spec_helper.rb +1 -0
  180. data/spec/public/controller/base_spec.rb +31 -0
  181. data/spec/public/controller/controllers/base.rb +41 -0
  182. data/spec/public/controller/controllers/display.rb +40 -0
  183. data/spec/public/controller/controllers/responder.rb +67 -0
  184. data/spec/public/controller/controllers/url.rb +7 -0
  185. data/spec/public/controller/controllers/views/layout/custom.html.erb +1 -0
  186. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.html.erb +1 -0
  187. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.xml.erb +1 -0
  188. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/index.html.erb +1 -0
  189. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/html_default/index.html.erb +1 -0
  190. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/layout/custom.html.erb +1 -0
  191. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.html.erb +1 -0
  192. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/local_provides/index.xml.erb +1 -0
  193. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.html.erb +1 -0
  194. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/multi_provides/index.js.erb +1 -0
  195. data/spec/public/controller/display_spec.rb +34 -0
  196. data/spec/public/controller/log/merb.4000.pid +1 -0
  197. data/spec/public/controller/responder_spec.rb +95 -0
  198. data/spec/public/controller/spec_helper.rb +9 -0
  199. data/spec/public/controller/url_spec.rb +152 -0
  200. data/spec/public/directory_structure/directory/app/controllers/application.rb +3 -0
  201. data/spec/public/directory_structure/directory/app/controllers/base.rb +13 -0
  202. data/spec/public/directory_structure/directory/app/controllers/custom.rb +19 -0
  203. data/spec/public/directory_structure/directory/app/views/base/template.html.erb +1 -0
  204. data/spec/public/directory_structure/directory/app/views/wonderful/template.erb +1 -0
  205. data/spec/public/directory_structure/directory/config/router.rb +3 -0
  206. data/spec/public/directory_structure/directory/log/merb.4000.pid +1 -0
  207. data/spec/public/directory_structure/directory/log/merb_test.log +265 -0
  208. data/spec/public/directory_structure/directory/merb.4000.pid +1 -0
  209. data/spec/public/directory_structure/directory_spec.rb +44 -0
  210. data/spec/public/logger/logger_spec.rb +175 -0
  211. data/spec/public/logger/spec_helper.rb +1 -0
  212. data/spec/public/reloading/directory/app/controllers/application.rb +3 -0
  213. data/spec/public/reloading/directory/app/controllers/reload.rb +6 -0
  214. data/spec/public/reloading/directory/config/init.rb +2 -0
  215. data/spec/public/reloading/directory/log/merb.4000.pid +1 -0
  216. data/spec/public/reloading/directory/log/merb_test.log +59 -0
  217. data/spec/public/reloading/directory/merb.4000.pid +1 -0
  218. data/spec/public/reloading/reload_spec.rb +80 -0
  219. data/spec/public/request/multipart_spec.rb +15 -0
  220. data/spec/public/request/request_spec.rb +207 -0
  221. data/spec/public/router/default_spec.rb +21 -0
  222. data/spec/public/router/deferred_spec.rb +22 -0
  223. data/spec/public/router/namespace_spec.rb +113 -0
  224. data/spec/public/router/nested_resources_spec.rb +34 -0
  225. data/spec/public/router/resource_spec.rb +45 -0
  226. data/spec/public/router/resources_spec.rb +57 -0
  227. data/spec/public/router/spec_helper.rb +72 -0
  228. data/spec/public/router/special_spec.rb +44 -0
  229. data/spec/public/router/string_spec.rb +61 -0
  230. data/spec/public/template/template_spec.rb +92 -0
  231. data/spec/public/template/templates/error.html.erb +2 -0
  232. data/spec/public/template/templates/template.html.erb +1 -0
  233. data/spec/public/template/templates/template.html.myt +1 -0
  234. data/spec/public/test/controller_matchers_spec.rb +378 -0
  235. data/spec/public/test/controllers/controller_assertion_mock.rb +7 -0
  236. data/spec/public/test/controllers/dispatch_controller.rb +11 -0
  237. data/spec/public/test/controllers/spec_helper_controller.rb +30 -0
  238. data/spec/public/test/multipart_request_helper_spec.rb +159 -0
  239. data/spec/public/test/multipart_upload_text_file.txt +1 -0
  240. data/spec/public/test/request_helper_spec.rb +153 -0
  241. data/spec/public/test/route_helper_spec.rb +54 -0
  242. data/spec/public/test/route_matchers_spec.rb +133 -0
  243. data/spec/public/test/view_helper_spec.rb +96 -0
  244. data/spec/public/test/view_matchers_spec.rb +107 -0
  245. data/spec/spec_helper.rb +71 -0
  246. metadata +488 -0
@@ -0,0 +1,284 @@
1
+ require "optparse"
2
+ require "yaml"
3
+
4
+ module Merb
5
+
6
+ class Config
7
+
8
+ class << self
9
+
10
+ # ==== Returns
11
+ # Hash:: The defaults for the config.
12
+ def defaults
13
+ @defaults ||= {
14
+ :host => "0.0.0.0",
15
+ :port => "4000",
16
+ :adapter => "runner",
17
+ :reload_classes => true,
18
+ :environment => "development",
19
+ :merb_root => Dir.pwd,
20
+ :use_mutex => true,
21
+ :session_id_key => "_session_id",
22
+ :log_delimiter => " ~ ",
23
+ :log_auto_flush => false,
24
+ :disabled_components => []
25
+ }
26
+ end
27
+
28
+ # Yields the configuration.
29
+ #
30
+ # ==== Block parameters
31
+ # c<Hash>:: The configuration parameters.
32
+ #
33
+ # ==== Examples
34
+ # Merb::Config.use do |config|
35
+ # config[:exception_details] = false
36
+ # end
37
+ def use
38
+ @configuration ||= {}
39
+ yield @configuration
40
+ end
41
+
42
+ # ==== Parameters
43
+ # key<Object>:: The key to check.
44
+ #
45
+ # ==== Returns
46
+ # Boolean:: True if the key exists in the config.
47
+ def key?(key)
48
+ @configuration.key?(key)
49
+ end
50
+
51
+ # ==== Parameters
52
+ # key<Object>:: The key to retrieve the parameter for.
53
+ #
54
+ # ==== Returns
55
+ # Object:: The value of the configuration parameter.
56
+ def [](key)
57
+ (@configuration||={})[key]
58
+ end
59
+
60
+ # ==== Parameters
61
+ # key<Object>:: The key to set the parameter for.
62
+ # val<Object>:: The value of the parameter.
63
+ def []=(key,val)
64
+ @configuration[key] = val
65
+ end
66
+
67
+ # ==== Parameters
68
+ # key<Object>:: The key of the parameter to delete.
69
+ def delete(key)
70
+ @configuration.delete(key)
71
+ end
72
+
73
+ # ==== Parameters
74
+ # key<Object>:: The key to retrieve the parameter for.
75
+ # default<Object>::
76
+ # The default value to return if the parameter is not set.
77
+ #
78
+ # ==== Returns
79
+ # Object:: The value of the configuration parameter or the default.
80
+ def fetch(key, default)
81
+ @configuration.fetch(key, default)
82
+ end
83
+
84
+ # ==== Returns
85
+ # Hash:: The config as a hash.
86
+ def to_hash
87
+ @configuration
88
+ end
89
+
90
+ # ==== Returns
91
+ # String:: The config as YAML.
92
+ def to_yaml
93
+ @configuration.to_yaml
94
+ end
95
+
96
+ # Sets up the configuration by storing the given settings.
97
+ #
98
+ # ==== Parameters
99
+ # settings<Hash>::
100
+ # Configuration settings to use. These are merged with the defaults.
101
+ def setup(settings = {})
102
+ @configuration = defaults.merge(settings)
103
+ end
104
+
105
+ # Parses the command line arguments and stores them in the config.
106
+ #
107
+ # ==== Parameters
108
+ # argv<String>:: The command line arguments. Defaults to +ARGV+.
109
+ def parse_args(argv = ARGV)
110
+ @configuration ||= {}
111
+ # Our primary configuration hash for the length of this method
112
+ options = {}
113
+
114
+ # Environment variables always win
115
+ options[:environment] = ENV["MERB_ENV"] if ENV["MERB_ENV"]
116
+
117
+ # Build a parser for the command line arguments
118
+ opts = OptionParser.new do |opts|
119
+ opts.version = Merb::VERSION
120
+ opts.release = Merb::RELEASE
121
+
122
+ opts.banner = "Usage: merb [uGdcIpPhmailLerkKX] [argument]"
123
+ opts.define_head "Merb Mongrel+ Erb. Lightweight replacement for ActionPack."
124
+ opts.separator '*'*80
125
+ opts.separator 'If no flags are given, Merb starts in the foreground on port 4000.'
126
+ opts.separator '*'*80
127
+
128
+ opts.on("-u", "--user USER", "This flag is for having merb run as a user other than the one currently logged in. Note: if you set this you must also provide a --group option for it to take effect.") do |user|
129
+ options[:user] = user
130
+ end
131
+
132
+ opts.on("-G", "--group GROUP", "This flag is for having merb run as a group other than the one currently logged in. Note: if you set this you must also provide a --user option for it to take effect.") do |group|
133
+ options[:group] = group
134
+ end
135
+
136
+ opts.on("-d", "--daemonize", "This will run a single merb in the background.") do |daemon|
137
+ options[:daemonize] = true
138
+ end
139
+
140
+ opts.on("-c", "--cluster-nodes NUM_MERBS", "Number of merb daemons to run.") do |nodes|
141
+ options[:cluster] = nodes
142
+ end
143
+
144
+ opts.on("-I", "--init-file FILE", "Name of the file to load first") do |init_file|
145
+ options[:init_file] = init_file
146
+ end
147
+
148
+ opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000.") do |port|
149
+ options[:port] = port
150
+ end
151
+
152
+ opts.on("-P", "--pid PIDFILE", "PID file, defaults to [Merb.root]/log/merb.[port_number].pid") do |pid_file|
153
+ options[:pid_file] = pid_file
154
+ end
155
+
156
+ opts.on("-h", "--host HOSTNAME", "Host to bind to (default is 0.0.0.0).") do |host|
157
+ options[:host] = host
158
+ end
159
+
160
+ opts.on("-m", "--merb-root /path/to/approot", "The path to the Merb.root for the app you want to run (default is current working dir).") do |root|
161
+ options[:merb_root] = File.expand_path(root)
162
+ end
163
+
164
+ opts.on("-a", "--adapter mongrel", "The rack adapter to use to run merb[mongrel, emongrel, thin, fastcgi, webrick, runner, irb]") do |adapter|
165
+ options[:adapter] = adapter
166
+ end
167
+
168
+ opts.on("-i", "--irb-console", "This flag will start merb in irb console mode. All your models and other classes will be available for you in an irb session.") do |console|
169
+ options[:adapter] = 'irb'
170
+ end
171
+
172
+ opts.on("-S", "--sandbox", "This flag will enable a sandboxed irb console. If your ORM supports transactions, all edits will be rolled back on exit.") do |sandbox|
173
+ options[:sandbox] = true
174
+ end
175
+
176
+ opts.on("-l", "--log-level LEVEL", "Log levels can be set to any of these options: debug < info < warn < error < fatal") do |log_level|
177
+ options[:log_level] = log_level.to_sym
178
+ end
179
+
180
+ opts.on("-L", "--log LOGFILE", "A string representing the logfile to use.") do |log_file|
181
+ options[:log_file] = log_file
182
+ end
183
+
184
+ opts.on("-e", "--environment STRING", "Run merb in the correct mode(development, production, testing)") do |env|
185
+ options[:environment] = env
186
+ end
187
+
188
+ opts.on("-r", "--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]",
189
+ "Command-line option to run scripts and/or code in the merb app.") do |code_or_file|
190
+ options[:runner_code] = code_or_file
191
+ options[:adapter] = 'runner'
192
+ end
193
+
194
+ opts.on("-K", "--graceful PORT or all", "Gracefully kill one merb proceses by port number. Use merb -K all to gracefully kill all merbs.") do |ports|
195
+ @configuration = defaults.merge(options)
196
+ Merb::Server.kill(ports, 1)
197
+ end
198
+
199
+ opts.on("-k", "--kill PORT or all", "Kill one merb proceses by port number. Use merb -k all to kill all merbs.") do |port|
200
+ @configuration = defaults.merge(options)
201
+ Merb::Server.kill(port, 9)
202
+ end
203
+
204
+ opts.on("-X", "--mutex on/off", "This flag is for turning the mutex lock on and off.") do |mutex|
205
+ if mutex == "off"
206
+ options[:use_mutex] = false
207
+ else
208
+ options[:use_mutex] = true
209
+ end
210
+ end
211
+
212
+ opts.on("-D", "--debugger", "Run merb using rDebug.") do
213
+ begin
214
+ require "ruby-debug"
215
+ Debugger.start
216
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
217
+ puts "Debugger enabled"
218
+ rescue LoadError
219
+ puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
220
+ exit
221
+ end
222
+ end
223
+
224
+ opts.on("-?", "-H", "--help", "Show this help message") do
225
+ puts opts
226
+ exit
227
+ end
228
+ end
229
+
230
+ # Parse what we have on the command line
231
+ opts.parse!(argv)
232
+ Merb::Config.setup(options)
233
+ end
234
+
235
+ attr_accessor :configuration #:nodoc:
236
+
237
+ # Set configuration parameters from a code block, where each method
238
+ # evaluates to a config parameter.
239
+ #
240
+ # ==== Parameters
241
+ # &block:: Configuration parameter block.
242
+ #
243
+ # ==== Examples
244
+ # # Set environment and log level.
245
+ # Merb::Config.configure do
246
+ # environment "development"
247
+ # log_level "debug"
248
+ # end
249
+ def configure(&block)
250
+ ConfigBlock.new(self, &block) if block_given?
251
+ end
252
+
253
+ # Allows retrieval of single key config values via Merb.config.<key>
254
+ # Allows single key assignment via Merb.config.<key> = ...
255
+ #
256
+ # ==== Parameters
257
+ # method<~to_s>:: Method name as hash key value.
258
+ # *args:: Value to set the configuration parameter to.
259
+ def method_missing(method, *args) #:nodoc:
260
+ if method.to_s[-1,1] == '='
261
+ @configuration[method.to_s.tr('=','').to_sym] = *args
262
+ else
263
+ @configuration[method]
264
+ end
265
+ end
266
+
267
+ end # class << self
268
+
269
+ class ConfigBlock #:nodoc:
270
+
271
+ def initialize(klass, &block) #:nodoc:
272
+ @klass = klass
273
+ instance_eval(&block)
274
+ end
275
+
276
+ def method_missing(method, *args) #:nodoc:
277
+ @klass[method] = *args
278
+ end
279
+
280
+ end # class Configurator
281
+
282
+ end # Config
283
+
284
+ end # Merb
@@ -0,0 +1,43 @@
1
+ # Most of this list is simply constants frozen for efficiency
2
+ module Merb
3
+ module Const
4
+
5
+ DEFAULT_SEND_FILE_OPTIONS = {
6
+ :type => 'application/octet-stream'.freeze,
7
+ :disposition => 'attachment'.freeze
8
+ }.freeze
9
+
10
+ SET_COOKIE = " %s=%s; path=/; expires=%s".freeze
11
+ COOKIE_EXPIRATION_FORMAT = "%a, %d-%b-%Y %H:%M:%S GMT".freeze
12
+ COOKIE_SPLIT = /[;,] */n.freeze
13
+ COOKIE_REGEXP = /\s*(.+)=(.*)\s*/.freeze
14
+ COOKIE_EXPIRED_TIME = Time.at(0).freeze
15
+ HOUR = 60 * 60
16
+ DAY = HOUR * 24
17
+ WEEK = DAY * 7
18
+ MULTIPART_REGEXP = /\Amultipart\/form-data.*boundary=\"?([^\";,]+)/n.freeze
19
+ HTTP_COOKIE = 'HTTP_COOKIE'.freeze
20
+ QUERY_STRING = 'QUERY_STRING'.freeze
21
+ JSON_MIME_TYPE_REGEXP = %r{^application/json|^text/x-json}.freeze
22
+ XML_MIME_TYPE_REGEXP = %r{^application/xml|^text/xml}.freeze
23
+ FORM_URL_ENCODED_REGEXP = %r{^application/x-www-form-urlencoded}.freeze
24
+ UPCASE_CONTENT_TYPE = 'CONTENT_TYPE'.freeze
25
+ CONTENT_TYPE = "Content-Type".freeze
26
+ LAST_MODIFIED = "Last-Modified".freeze
27
+ SLASH = "/".freeze
28
+ REQUEST_METHOD = "REQUEST_METHOD".freeze
29
+ GET = "GET".freeze
30
+ POST = "POST".freeze
31
+ HEAD = "HEAD".freeze
32
+ CONTENT_LENGTH = "CONTENT_LENGTH".freeze
33
+ HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
34
+ HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
35
+ HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
36
+ UPLOAD_ID = "upload_id".freeze
37
+ PATH_INFO = "PATH_INFO".freeze
38
+ SCRIPT_NAME = "SCRIPT_NAME".freeze
39
+ REQUEST_URI = "REQUEST_URI".freeze
40
+ REQUEST_PATH = "REQUEST_PATH".freeze
41
+ REMOTE_ADDR = "REMOTE_ADDR".freeze
42
+ end
43
+ end
@@ -0,0 +1,531 @@
1
+ # Note that the over-use of "_" in Controller methods is to avoid collisions
2
+ # with helpers, which will be pulled directly into controllers from now on.
3
+ #
4
+ # ==== Filters
5
+ # #before is a class method that allows you to specify before filters in
6
+ # your controllers. Filters can either be a symbol or string that
7
+ # corresponds to a method name to call, or a proc object. if it is a method
8
+ # name that method will be called and if it is a proc it will be called
9
+ # with an argument of self where self is the current controller object.
10
+ # When you use a proc as a filter it needs to take one parameter.
11
+ #
12
+ # #after is identical, but the filters are run after the action is invoked.
13
+ #
14
+ # ==== Examples
15
+ # before :some_filter
16
+ # before :authenticate, :exclude => [:login, :signup]
17
+ # before Proc.new {|c| c.some_method }, :only => :foo
18
+ # before :authorize, :unless => logged_in?
19
+ #
20
+ # You can use either :only => :actionname or :exclude => [:this, :that]
21
+ # but not both at once. :only will only run before the listed actions
22
+ # and :exclude will run for every action that is not listed.
23
+ #
24
+ # Merb's before filter chain is very flexible. To halt the filter chain you
25
+ # use throw :halt. If throw is called with only one argument of :halt the
26
+ # return of the method filters_halted will be what is rendered to the view.
27
+ # You can overide filters_halted in your own controllers to control what it
28
+ # outputs. But the throw construct is much more powerful then just that.
29
+ # throw :halt can also take a second argument. Here is what that second arg
30
+ # can be and the behavior each type can have:
31
+ #
32
+ # * +String+:
33
+ # when the second arg is a string then that string will be what
34
+ # is rendered to the browser. Since merb's render method returns
35
+ # a string you can render a template or just use a plain string:
36
+ #
37
+ # throw :halt, "You don't have permissions to do that!"
38
+ # throw :halt, render(:action => :access_denied)
39
+ #
40
+ # * +Symbol+:
41
+ # If the second arg is a symbol then the method named after that
42
+ # symbol will be called
43
+ #
44
+ # throw :halt, :must_click_disclaimer
45
+ #
46
+ # * +Proc+:
47
+ #
48
+ # If the second arg is a Proc, it will be called and its return
49
+ # value will be what is rendered to the browser:
50
+ #
51
+ # throw :halt, proc {|c| c.access_denied }
52
+ # throw :halt, proc {|c| Tidy.new(c.index) }
53
+ #
54
+ # ==== Filter Options (.before, .after, .add_filter, .if, .unless)
55
+ # :only<Symbol, Array[Symbol]>::
56
+ # A list of actions that this filter should apply to
57
+ #
58
+ # :exclude<Symbol, Array[Symbol]::
59
+ # A list of actions that this filter should *not* apply to
60
+ #
61
+ # :if<Symbol, Proc>::
62
+ # Only apply the filter if the method named after the symbol or calling the proc evaluates to true
63
+ #
64
+ # :unless<Symbol, Proc>::
65
+ # Only apply the filter if the method named after the symbol or calling the proc evaluates to false
66
+ #
67
+ # ==== Types (shortcuts for use in this file)
68
+ # Filter:: <Array[Symbol, (Symbol, String, Proc)]>
69
+ class Merb::AbstractController
70
+ include Merb::RenderMixin
71
+ include Merb::InlineTemplates
72
+
73
+ class_inheritable_accessor :_before_filters, :_after_filters, :_layout, :_template_root
74
+
75
+ # ==== Returns
76
+ # String:: The controller name in path form, e.g. "admin/items".
77
+ #---
78
+ # @public
79
+ def self.controller_name() @controller_name ||= self.name.to_const_path end
80
+
81
+ # ==== Returns
82
+ # String:: The controller name in path form, e.g. "admin/items".
83
+ def controller_name() self.class.controller_name end
84
+
85
+ self._before_filters, self._after_filters = [], []
86
+
87
+ # This is called after the controller is instantiated to figure out where to
88
+ # for templates under the _template_root. Override this to define a new
89
+ # structure for your app.
90
+ #
91
+ # ==== Parameters
92
+ # action<~to_s>:: The controller action.
93
+ # type<~to_s>:: The content type. Defaults to nil.
94
+ # controller<~to_s>::
95
+ # The name of the controller. Defaults to controller_name.
96
+ #
97
+ #
98
+ # ==== Returns
99
+ # String::
100
+ # Indicating where to look for the template for the current controller,
101
+ # action, and content-type.
102
+ #
103
+ # ==== Note
104
+ # The type is irrelevant for controller-types that don't support
105
+ # content-type negotiation, so we default to not include it in the
106
+ # superclass.
107
+ #
108
+ # ==== Examples
109
+ # def _template_location
110
+ # "#{params[:controller]}.#{params[:action]}.#{content_type}"
111
+ # end
112
+ #
113
+ # This would look for templates at controller.action.mime.type instead
114
+ # of controller/action.mime.type
115
+ #---
116
+ # @public
117
+ def _template_location(action, type = nil, controller = controller_name)
118
+ "#{controller}/#{action}"
119
+ end
120
+
121
+ # ==== Returns
122
+ # roots<Array[Array]>::
123
+ # Template roots as pairs of template root path and template location
124
+ # method.
125
+ def self._template_roots
126
+ read_inheritable_attribute(:template_roots) ||
127
+ write_inheritable_attribute(:template_roots, [[self._template_root, :_template_location]])
128
+ end
129
+
130
+ # ==== Parameters
131
+ # roots<Array[Array]>::
132
+ # Template roots as pairs of template root path and template location
133
+ # method.
134
+ def self._template_roots=(roots)
135
+ write_inheritable_attribute(:template_roots, roots)
136
+ end
137
+
138
+ cattr_accessor :_abstract_subclasses, :_template_path_cache
139
+ #---
140
+ # We're using abstract_subclasses so that Merb::Controller can have its
141
+ # own subclasses. We're using a Set so we don't have to worry about
142
+ # uniqueness.
143
+ self._abstract_subclasses = Set.new
144
+
145
+ # ==== Returns
146
+ # Set:: The subclasses.
147
+ def self.subclasses_list() _abstract_subclasses end
148
+
149
+ class << self
150
+ # ==== Parameters
151
+ # klass<Merb::AbstractController>::
152
+ # The controller that is being inherited from Merb::AbstractController
153
+ def inherited(klass)
154
+ _abstract_subclasses << klass.to_s
155
+ Object.make_module "Merb::#{klass}Helper" unless klass.to_s =~ /^Merb::/
156
+ klass.class_eval <<-HERE
157
+ include Object.full_const_get("Merb::#{klass}Helper") rescue nil
158
+ HERE
159
+ super
160
+ end
161
+
162
+ # ==== Parameters
163
+ # layout<~to_s>:: The layout that should be used for this class
164
+ #
165
+ # ==== Returns
166
+ # ~to_s:: The layout that was passed in
167
+ def layout(layout)
168
+ self._layout = layout
169
+ end
170
+ end
171
+
172
+ attr_accessor :_benchmarks, :_thrown_content
173
+
174
+ #---
175
+ # @semipublic
176
+ attr_accessor :body
177
+
178
+ attr_accessor :action_name
179
+
180
+ # ==== Parameters
181
+ # *args:: The args are ignored.
182
+ def initialize(*args)
183
+ @_benchmarks = {}
184
+ @_caught_content = {}
185
+ @_template_stack = []
186
+ end
187
+
188
+ # This will dispatch the request, calling setup_session and finalize_session
189
+ #
190
+ # ==== Parameters
191
+ # action<~to_s>::
192
+ # The action to dispatch to. This will be #send'ed in _call_action.
193
+ # Defaults to :to_s.
194
+ #
195
+ # ==== Raises
196
+ # MerbControllerError:: Invalid body content caught.
197
+ def _dispatch(action=:to_s)
198
+ setup_session
199
+ self.action_name = action
200
+
201
+ caught = catch(:halt) do
202
+ start = Time.now
203
+ result = _call_filters(_before_filters)
204
+ @_benchmarks[:before_filters_time] = Time.now - start if _before_filters
205
+ result
206
+ end
207
+
208
+ @body = case caught
209
+ when :filter_chain_completed then _call_action(action_name)
210
+ when String then caught
211
+ when nil then _filters_halted
212
+ when Symbol then __send__(caught)
213
+ when Proc then caught.call(self)
214
+ else
215
+ raise MerbControllerError, "The before filter chain is broken dude. wtf?"
216
+ end
217
+ start = Time.now
218
+ _call_filters(_after_filters)
219
+ @_benchmarks[:after_filters_time] = Time.now - start if _after_filters
220
+ finalize_session
221
+ end
222
+
223
+ # This method exists to provide an overridable hook for ActionArgs
224
+ #
225
+ # ==== Parameters
226
+ # action<~to_s>:: the action method to dispatch to
227
+ def _call_action(action)
228
+ send(action)
229
+ end
230
+
231
+ # ==== Parameters
232
+ # filter_set<Array[Filter]>::
233
+ # A set of filters in the form [[:filter, rule], [:filter, rule]]
234
+ #
235
+ # ==== Returns
236
+ # Symbol:: :filter_chain_completed.
237
+ #
238
+ # ==== Notes
239
+ # Filter rules can be Symbols, Strings, or Procs.
240
+ #
241
+ # Symbols or Strings::
242
+ # Call the method represented by the +Symbol+ or +String+.
243
+ # Procs::
244
+ # Execute the +Proc+, in the context of the controller (self will be the
245
+ # controller)
246
+ def _call_filters(filter_set)
247
+ (filter_set || []).each do |filter, rule|
248
+ if _call_filter_for_action?(rule, action_name) && _filter_condition_met?(rule)
249
+ case filter
250
+ when Symbol, String then send(filter)
251
+ when Proc then self.instance_eval(&filter)
252
+ end
253
+ end
254
+ end
255
+ return :filter_chain_completed
256
+ end
257
+
258
+ # ==== Parameters
259
+ # rule<Hash>:: Rules for the filter (see below).
260
+ # action_name<~to_s>:: The name of the action to be called.
261
+ #
262
+ # ==== Options (rule)
263
+ # :only<Array>::
264
+ # Optional list of actions to fire. If given, action_name must be a part of
265
+ # it for this function to return true.
266
+ # :exclude<Array>::
267
+ # Optional list of actions not to fire. If given, action_name must not be a
268
+ # part of it for this function to return true.
269
+ #
270
+ # ==== Returns
271
+ # Boolean:: True if the action should be called.
272
+ def _call_filter_for_action?(rule, action_name)
273
+ # Both:
274
+ # * no :only or the current action is in the :only list
275
+ # * no :exclude or the current action is not in the :exclude list
276
+ (!rule.key?(:only) || rule[:only].include?(action_name)) &&
277
+ (!rule.key?(:exclude) || !rule[:exclude].include?(action_name))
278
+ end
279
+
280
+ # ==== Parameters
281
+ # rule<Hash>:: Rules for the filter (see below).
282
+ #
283
+ # ==== Options (rule)
284
+ # :if<Array>:: Optional conditions that must be met for the filter to fire.
285
+ # :unless<Array>::
286
+ # Optional conditions that must not be met for the filter to fire.
287
+ #
288
+ # ==== Returns
289
+ # Boolean:: True if the conditions are met.
290
+ def _filter_condition_met?(rule)
291
+ # Both:
292
+ # * no :if or the if condition evaluates to true
293
+ # * no :unless or the unless condition evaluates to false
294
+ (!rule.key?(:if) || _evaluate_condition(rule[:if])) &&
295
+ (!rule.key?(:unless) || ! _evaluate_condition(rule[:unless]))
296
+ end
297
+
298
+ # ==== Parameters
299
+ # condition<Symbol, Proc>:: The condition to evaluate.
300
+ #
301
+ # ==== Raises
302
+ # ArgumentError:: condition not a Symbol or Proc.
303
+ #
304
+ # ==== Returns
305
+ # Boolean:: True if the condition is met.
306
+ #
307
+ # ==== Alternatives
308
+ # If condition is a symbol, it will be send'ed. If it is a Proc it will be
309
+ # called directly with self as an argument.
310
+ def _evaluate_condition(condition)
311
+ case condition
312
+ when Symbol : self.send(condition)
313
+ when Proc : condition.call(self)
314
+ else
315
+ raise ArgumentError,
316
+ 'Filter condtions need to be either a Symbol or a Proc'
317
+ end
318
+ end
319
+
320
+ # ==== Parameters
321
+ # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
322
+ # opts<Hash>::
323
+ # Filter options (see class documentation under <tt>Filter Options</tt>).
324
+ # &block:: Currently ignored.
325
+ #
326
+ # ==== Note
327
+ # If the filter already exists, its options will be replaced with opts.
328
+ def self.after(filter = nil, opts = {}, &block)
329
+ add_filter(self._after_filters, filter, opts)
330
+ end
331
+
332
+ # ==== Parameters
333
+ # filter<Symbol, Proc>:: The filter to add. Defaults to nil.
334
+ # opts<Hash>::
335
+ # Filter options (see class documentation under <tt>Filter Options</tt>).
336
+ # &block:: A block to use as a filter if filter is nil.
337
+ #
338
+ # ==== Note
339
+ # If the filter already exists, its options will be replaced with opts.
340
+ def self.before(filter = nil, opts = {}, &block)
341
+ add_filter(self._before_filters, filter || block, opts)
342
+ end
343
+
344
+ # Skip an after filter that has been previously defined (perhaps in a
345
+ # superclass)
346
+ #
347
+ # ==== Parameters
348
+ # filter<Symbol>:: A filter name to skip.
349
+ def self.skip_after(filter)
350
+ skip_filter(self._after_filters, filter)
351
+ end
352
+
353
+ # Skip a before filter that has been previously defined (perhaps in a
354
+ # superclass).
355
+ #
356
+ # ==== Parameters
357
+ # filter<Symbol>:: A filter name to skip.
358
+ def self.skip_before(filter)
359
+ skip_filter(self._before_filters , filter)
360
+ end
361
+
362
+ #---
363
+ # Defaults that can be overridden by plugins, other mixins, or subclasses
364
+ def _filters_halted() "<html><body><h1>Filter Chain Halted!</h1></body></html>" end
365
+
366
+ # Method stub for setting up the session. This will be overriden by session
367
+ # modules.
368
+ def setup_session() end
369
+
370
+ # Method stub for finalizing up the session. This will be overriden by
371
+ # session modules.
372
+ def finalize_session() end
373
+
374
+ # Stub so content-type support in RenderMixin doesn't throw errors
375
+ attr_accessor :content_type
376
+
377
+ # Handles the template cache (which is used by BootLoader to cache the list
378
+ # of all templates).
379
+ #
380
+ # ==== Parameters
381
+ # template<String>::
382
+ # The full path to a template to add to the list of available templates
383
+ def self.add_path_to_template_cache(template)
384
+ return false if template.blank? || template.split("/").last.split(".").size != 3
385
+ key = template.match(/(.*)\.(.*)$/)[1]
386
+ self._template_path_cache[key] = template
387
+ end
388
+
389
+ # Resets the template_path_cache to an empty hash
390
+ def self.reset_template_path_cache!
391
+ self._template_path_cache = {}
392
+ end
393
+
394
+ # ==== Parameters
395
+ # name<~to_sym, Hash>:: The name of the URL to generate.
396
+ # rparams<Hash>:: Parameters for the route generation.
397
+ #
398
+ # ==== Returns
399
+ # String:: The generated URL.
400
+ #
401
+ # ==== Alternatives
402
+ # If a hash is used as the first argument, a default route will be
403
+ # generated based on it and rparams.
404
+ def url(name, rparams={})
405
+ uri = Merb::Router.generate(name, rparams,
406
+ { :controller => controller_name,
407
+ :action => action_name,
408
+ :format => params[:format]
409
+ }
410
+ )
411
+ uri = Merb::Config[:path_prefix] + uri if Merb::Config[:path_prefix]
412
+ uri
413
+ end
414
+ alias_method :relative_url, :url
415
+
416
+ # ==== Parameters
417
+ # name<~to_sym, Hash>:: The name of the URL to generate.
418
+ # rparams<Hash>:: Parameters for the route generation.
419
+ #
420
+ # ==== Returns
421
+ # String:: The generated url with protocol + hostname + URL.
422
+ #
423
+ # ==== Alternatives
424
+ # If a hash is used as the first argument, a default route will be
425
+ # generated based on it and rparams.
426
+ def absolute_url(name, rparams={})
427
+ request.protocol + request.host + url(name, rparams)
428
+ end
429
+
430
+ private
431
+ # ==== Parameters
432
+ # filters<Array[Filter]>:: The filter list that this should be added to.
433
+ # filter<Filter>:: A filter that should be added.
434
+ # opts<Hash>::
435
+ # Filter options (see class documentation under <tt>Filter Options</tt>).
436
+ #
437
+ # ==== Raises
438
+ # ArgumentError::
439
+ # Both :only and :exclude, or :if and :unless given, or filter is not a
440
+ # Symbol, String or Proc.
441
+ def self.add_filter(filters, filter, opts={})
442
+ raise(ArgumentError,
443
+ "You can specify either :only or :exclude but
444
+ not both at the same time for the same filter.") if opts.key?(:only) && opts.key?(:exclude)
445
+
446
+ raise(ArgumentError,
447
+ "You can specify either :if or :unless but
448
+ not both at the same time for the same filter.") if opts.key?(:if) && opts.key?(:unless)
449
+
450
+ opts = normalize_filters!(opts)
451
+
452
+ case filter
453
+ when Symbol, Proc, String
454
+ if existing_filter = filters.find {|f| f.first.to_s[filter.to_s]}
455
+ existing_filter.last.replace(opts)
456
+ else
457
+ filters << [filter, opts]
458
+ end
459
+ else
460
+ raise(ArgumentError,
461
+ 'Filters need to be either a Symbol, String or a Proc'
462
+ )
463
+ end
464
+ end
465
+
466
+ # Skip a filter that was previously added to the filter chain. Useful in
467
+ # inheritence hierarchies.
468
+ #
469
+ # ==== Parameters
470
+ # filters<Array[Filter]>:: The filter list that this should be removed from.
471
+ # filter<Filter>:: A filter that should be removed.
472
+ #
473
+ # ==== Raises
474
+ # ArgumentError:: filter not Symbol or String.
475
+ def self.skip_filter(filters, filter)
476
+ raise(ArgumentError, 'You can only skip filters that have a String or Symbol name.') unless
477
+ [Symbol, String].include? filter.class
478
+
479
+ Merb.logger.warn("Filter #{filter} was not found in your filter chain.") unless
480
+ filters.reject! {|f| f.first.to_s[filter.to_s] }
481
+ end
482
+
483
+ # Ensures that the passed in hash values are always arrays.
484
+ #
485
+ # ==== Parameters
486
+ # opts<Hash>:: Options for the filters (see below).
487
+ #
488
+ # ==== Options (opts)
489
+ # :only<Symbol, Array[Symbol]>:: A list of actions.
490
+ # :exclude<Symbol, Array[Symbol]>:: A list of actions.
491
+ #
492
+ # ==== Examples
493
+ # normalize_filters!(:only => :new) #=> {:only => [:new]}
494
+ def self.normalize_filters!(opts={})
495
+ opts[:only] = Array(opts[:only]).map {|x| x.to_s} if opts[:only]
496
+ opts[:exclude] = Array(opts[:exclude]).map {|x| x.to_s} if opts[:exclude]
497
+ return opts
498
+ end
499
+
500
+ # Calls the capture method for the selected template engine.
501
+ #
502
+ # ==== Parameters
503
+ # *args:: Arguments to pass to the block.
504
+ # &block:: The template block to call.
505
+ #
506
+ # ==== Returns
507
+ # String:: The output of the block.
508
+ def capture(*args, &block)
509
+ send("capture_#{@_engine}", *args, &block)
510
+ end
511
+
512
+ # Calls the concatenate method for the selected template engine.
513
+ #
514
+ # ==== Parameters
515
+ # str<String>:: The string to concatenate to the buffer.
516
+ # binding<Binding>:: The binding to use for the buffer.
517
+ def concat(str, binding)
518
+ send("concat_#{@_engine}", str, binding)
519
+ end
520
+
521
+ # Attempts to return the partial local variable corresponding to sym.
522
+ #
523
+ # ==== Paramteres
524
+ # sym<Symbol>:: Method name.
525
+ # *arg:: Arguments to pass to the method.
526
+ # &blk:: A block to pass to the method.
527
+ def method_missing(sym, *args, &blk)
528
+ return @_merb_partial_locals[sym] if @_merb_partial_locals && @_merb_partial_locals.key?(sym)
529
+ super
530
+ end
531
+ end