waw 0.2.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 (199) hide show
  1. data/LICENCE.rdoc +25 -0
  2. data/README.rdoc +32 -0
  3. data/bin/waw +32 -0
  4. data/bin/waw-profile +26 -0
  5. data/bin/waw-start +26 -0
  6. data/bin/wspec +33 -0
  7. data/layouts/empty/Rakefile +14 -0
  8. data/layouts/empty/config.ru +5 -0
  9. data/layouts/empty/config/commons.cfg +31 -0
  10. data/layouts/empty/config/devel.cfg +21 -0
  11. data/layouts/empty/ignore +7 -0
  12. data/layouts/empty/logs/dontforgetme +0 -0
  13. data/layouts/empty/resources/messages.rs +1 -0
  14. data/layouts/empty/test/wspec/site_respond.wspec +3 -0
  15. data/layouts/empty/test/wspec/test_all.rb +13 -0
  16. data/layouts/empty/waw.deploy +1 -0
  17. data/layouts/empty/waw.routing +6 -0
  18. data/layouts/static/dependencies +1 -0
  19. data/layouts/static/public/.wawaccess +18 -0
  20. data/layouts/static/public/css/style.css +0 -0
  21. data/layouts/static/public/images/dontforgetme +0 -0
  22. data/layouts/static/public/js/project.js +0 -0
  23. data/layouts/static/public/pages/.wawaccess +30 -0
  24. data/layouts/static/public/pages/404.wtpl +1 -0
  25. data/layouts/static/public/pages/index.wtpl +5 -0
  26. data/layouts/static/public/templates/.wawaccess +9 -0
  27. data/layouts/static/public/templates/layout.wtpl +17 -0
  28. data/layouts/static/test/wspec/static_pages_are_served.wspec +21 -0
  29. data/layouts/static/waw.routing +8 -0
  30. data/lib/waw.rb +99 -0
  31. data/lib/waw/commands/command.rb +115 -0
  32. data/lib/waw/commands/profile_command.rb +66 -0
  33. data/lib/waw/commands/start_command.rb +59 -0
  34. data/lib/waw/config.rb +110 -0
  35. data/lib/waw/controller.rb +25 -0
  36. data/lib/waw/controllers/action/action.rb +91 -0
  37. data/lib/waw/controllers/action/action_utils.rb +30 -0
  38. data/lib/waw/controllers/action/js_generation.rb +116 -0
  39. data/lib/waw/controllers/action_controller.rb +133 -0
  40. data/lib/waw/controllers/error/backtrace.rb +54 -0
  41. data/lib/waw/controllers/error_handler.rb +62 -0
  42. data/lib/waw/controllers/json_controller.rb +31 -0
  43. data/lib/waw/controllers/no_cache.rb +22 -0
  44. data/lib/waw/controllers/static/match.rb +80 -0
  45. data/lib/waw/controllers/static/waw_access.rb +235 -0
  46. data/lib/waw/controllers/static/waw_access_dsl.rb +48 -0
  47. data/lib/waw/controllers/static_controller.rb +37 -0
  48. data/lib/waw/default_config.cfg +14 -0
  49. data/lib/waw/environment_utils.rb +57 -0
  50. data/lib/waw/errors.rb +4 -0
  51. data/lib/waw/ext.rb +3 -0
  52. data/lib/waw/ext/core.rb +4 -0
  53. data/lib/waw/ext/core/hash.rb +47 -0
  54. data/lib/waw/ext/core/logger.rb +10 -0
  55. data/lib/waw/ext/core/module.rb +20 -0
  56. data/lib/waw/ext/core/object.rb +29 -0
  57. data/lib/waw/ext/rack.rb +19 -0
  58. data/lib/waw/ext/rack/builder.rb +43 -0
  59. data/lib/waw/ext/rack/delegator.rb +51 -0
  60. data/lib/waw/ext/rack/urlmap.rb +55 -0
  61. data/lib/waw/ext/wlang.rb +1 -0
  62. data/lib/waw/ext/wlang/hosted_language.rb +21 -0
  63. data/lib/waw/fullstate.rb +8 -0
  64. data/lib/waw/fullstate/on_class.rb +37 -0
  65. data/lib/waw/fullstate/on_instance.rb +27 -0
  66. data/lib/waw/fullstate/variable.rb +36 -0
  67. data/lib/waw/kern.rb +6 -0
  68. data/lib/waw/kern/app.rb +48 -0
  69. data/lib/waw/kern/empty/waw.deploy +0 -0
  70. data/lib/waw/kern/empty/waw.routing +1 -0
  71. data/lib/waw/kern/freezed_state.rb +32 -0
  72. data/lib/waw/kern/hooks.rb +53 -0
  73. data/lib/waw/kern/lifecycle.rb +248 -0
  74. data/lib/waw/kern/living_state.rb +87 -0
  75. data/lib/waw/kern/utils.rb +27 -0
  76. data/lib/waw/resource_collection.rb +100 -0
  77. data/lib/waw/restart.rb +32 -0
  78. data/lib/waw/routing.rb +43 -0
  79. data/lib/waw/routing/action_routing.rb +78 -0
  80. data/lib/waw/routing/dsl.rb +45 -0
  81. data/lib/waw/routing/feedback.rb +23 -0
  82. data/lib/waw/routing/form_validation_feedback.rb +36 -0
  83. data/lib/waw/routing/javascript.rb +17 -0
  84. data/lib/waw/routing/redirect.rb +26 -0
  85. data/lib/waw/routing/refresh.rb +17 -0
  86. data/lib/waw/routing/routing_rule.rb +16 -0
  87. data/lib/waw/scope_utils.rb +69 -0
  88. data/lib/waw/session.rb +51 -0
  89. data/lib/waw/testing.rb +1 -0
  90. data/lib/waw/tools/mail.rb +4 -0
  91. data/lib/waw/tools/mail/mail.rb +119 -0
  92. data/lib/waw/tools/mail/mail_agent.rb +123 -0
  93. data/lib/waw/tools/mail/mailbox.rb +62 -0
  94. data/lib/waw/tools/mail/template.rb +38 -0
  95. data/lib/waw/utils/dsl_helper.rb +116 -0
  96. data/lib/waw/validation.rb +175 -0
  97. data/lib/waw/validation/and_validator.rb +27 -0
  98. data/lib/waw/validation/array_validations.rb +38 -0
  99. data/lib/waw/validation/boolean_validator.rb +32 -0
  100. data/lib/waw/validation/comparison_validations.rb +45 -0
  101. data/lib/waw/validation/date_validator.rb +31 -0
  102. data/lib/waw/validation/default_validator.rb +30 -0
  103. data/lib/waw/validation/dsl_ruby_extensions.rb +11 -0
  104. data/lib/waw/validation/errors.rb +17 -0
  105. data/lib/waw/validation/ext.rb +3 -0
  106. data/lib/waw/validation/file_validator.rb +30 -0
  107. data/lib/waw/validation/float_validator.rb +19 -0
  108. data/lib/waw/validation/helpers.rb +67 -0
  109. data/lib/waw/validation/integer_validator.rb +16 -0
  110. data/lib/waw/validation/isin_validator.rb +24 -0
  111. data/lib/waw/validation/mandatory_validator.rb +17 -0
  112. data/lib/waw/validation/missing_validator.rb +17 -0
  113. data/lib/waw/validation/not_validator.rb +20 -0
  114. data/lib/waw/validation/or_validator.rb +34 -0
  115. data/lib/waw/validation/regexp_validator.rb +29 -0
  116. data/lib/waw/validation/same_validator.rb +16 -0
  117. data/lib/waw/validation/signature.rb +157 -0
  118. data/lib/waw/validation/size_validations.rb +44 -0
  119. data/lib/waw/validation/string_validator.rb +15 -0
  120. data/lib/waw/validation/validator.rb +48 -0
  121. data/lib/waw/wawgen.rb +2 -0
  122. data/lib/waw/wawgen/create.rb +166 -0
  123. data/lib/waw/wawgen/project.rb +25 -0
  124. data/lib/waw/wspec.rb +5 -0
  125. data/lib/waw/wspec/browser.rb +240 -0
  126. data/lib/waw/wspec/dsl.rb +201 -0
  127. data/lib/waw/wspec/html_analysis.rb +136 -0
  128. data/lib/waw/wspec/html_analysis/tag.rb +56 -0
  129. data/lib/waw/wspec/runner.rb +70 -0
  130. data/lib/waw/wspec/scenario.rb +35 -0
  131. data/lib/waw/wspec/suite.rb +54 -0
  132. data/test/bricks/error_handler/config/test.cfg +2 -0
  133. data/test/bricks/error_handler/logs/webapp.log +1411 -0
  134. data/test/bricks/error_handler/test/error_handler.wspec +16 -0
  135. data/test/bricks/error_handler/waw.deploy +1 -0
  136. data/test/bricks/error_handler/waw.routing +27 -0
  137. data/test/integration/waw_create_integration_test.rb +24 -0
  138. data/test/spec/assumptions_spec.rb +30 -0
  139. data/test/spec/controllers/action_controller_spec.rb +14 -0
  140. data/test/spec/controllers/static/waw_access_spec.rb +112 -0
  141. data/test/spec/environment_utils_spec.rb +15 -0
  142. data/test/spec/ext/core/hash_spec.rb +58 -0
  143. data/test/spec/fixtures.rb +41 -0
  144. data/test/spec/fixtures/action/config/default.cfg +2 -0
  145. data/test/spec/fixtures/action/lib/action_controller_test.rb +12 -0
  146. data/test/spec/fixtures/action/waw.deploy +1 -0
  147. data/test/spec/fixtures/action/waw.routing +6 -0
  148. data/test/spec/fixtures/empty/waw.deploy +0 -0
  149. data/test/spec/fixtures/empty/waw.routing +0 -0
  150. data/test/spec/fullstate/on_class_spec.rb +59 -0
  151. data/test/spec/fullstate/on_instance_spec.rb +59 -0
  152. data/test/spec/fullstate/session_spec.rb +43 -0
  153. data/test/spec/fullstate/variable_spec.rb +55 -0
  154. data/test/spec/resource_collection_spec.rb +50 -0
  155. data/test/spec/test_all.rb +9 -0
  156. data/test/spec/tools/mail/mail_agent_spec.rb +116 -0
  157. data/test/spec/tools/mail/mail_spec.rb +56 -0
  158. data/test/spec/tools/mail/mailbox_spec.rb +57 -0
  159. data/test/spec/tools/mail/template_spec.rb +47 -0
  160. data/test/spec/validation/array_validation_spec.rb +63 -0
  161. data/test/spec/validation/array_validator_spec.rb +17 -0
  162. data/test/spec/validation/date_validation_spec.rb +35 -0
  163. data/test/spec/validation/default_validation_spec.rb +37 -0
  164. data/test/spec/validation/disjuctive_validation_spec.rb +33 -0
  165. data/test/spec/validation/errors_spec.rb +37 -0
  166. data/test/spec/validation/file_validator_spec.rb +34 -0
  167. data/test/spec/validation/mail_validation_spec.rb +51 -0
  168. data/test/spec/validation/missing_validation_spec.rb +43 -0
  169. data/test/spec/validation/same_validation_spec.rb +24 -0
  170. data/test/spec/validation/signature_intuition_spec.rb +37 -0
  171. data/test/spec/validation/signature_spec.rb +164 -0
  172. data/test/spec/validation/validation_spec.rb +28 -0
  173. data/test/spec/wspec/html_analysis/tag_spec.rb +38 -0
  174. data/test/spec/wspec/html_analysis_spec.rb +170 -0
  175. data/test/unit/test_all.rb +8 -0
  176. data/test/unit/waw/app_test.rb +126 -0
  177. data/test/unit/waw/app_test/config/commons.cfg +2 -0
  178. data/test/unit/waw/app_test/config/devel.cfg +1 -0
  179. data/test/unit/waw/config_test.rb +54 -0
  180. data/test/unit/waw/controllers/action_controller_test.rb +76 -0
  181. data/test/unit/waw/controllers/action_test.rb +35 -0
  182. data/test/unit/waw/controllers/example_action_controller_test.rb +24 -0
  183. data/test/unit/waw/controllers/multiple_action_controller_test.rb +78 -0
  184. data/test/unit/waw/controllers/static/example/css/example.css +1 -0
  185. data/test/unit/waw/controllers/static/example/index.html +1 -0
  186. data/test/unit/waw/controllers/static/example/js/example.js +1 -0
  187. data/test/unit/waw/controllers/static/example/pages/hello.wtpl +1 -0
  188. data/test/unit/waw/controllers/static/waw_access_test.rb +76 -0
  189. data/test/unit/waw/ext/rack_test.rb +74 -0
  190. data/test/unit/waw/resource_collection_test.rb +49 -0
  191. data/test/unit/waw/resources.txt +4 -0
  192. data/test/unit/waw/routing/routing_test.rb +26 -0
  193. data/test/unit/waw/utils/dsl_helper_test.rb +79 -0
  194. data/test/unit/waw/utils/dsl_helper_test_extensions1.rb +4 -0
  195. data/test/unit/waw/validation/signature_test.rb +193 -0
  196. data/test/unit/waw/validation_test.rb +319 -0
  197. data/test/unit/waw/wspec/html_analysis_test.html +81 -0
  198. data/test/unit/waw/wspec/html_analysis_test.rb +26 -0
  199. metadata +272 -0
@@ -0,0 +1,30 @@
1
+ module Waw
2
+ class ActionController < Waw::Controller
3
+ #
4
+ # Common utilities about actions.
5
+ #
6
+ module ActionUtils
7
+
8
+ # Extracts the action name from a given path
9
+ def extract_action_name(path)
10
+ return $1.to_sym if path =~ /([a-zA-Z_]+)$/
11
+ nil
12
+ end
13
+
14
+ # Checks if an action exists
15
+ def has_action?(name)
16
+ name = extract_action_name(name) unless Symbol===name
17
+ return false unless name
18
+ actions.has_key?(name)
19
+ end
20
+
21
+ def find_action(name)
22
+ name = extract_action_name(name) unless Symbol===name
23
+ return nil unless name
24
+ actions[name]
25
+ end
26
+ alias :[] :find_action
27
+
28
+ end # module ActionUtils
29
+ end # class ActionController
30
+ end # module Waw
@@ -0,0 +1,116 @@
1
+ module Waw
2
+ class ActionController < ::Waw::Controller
3
+ class JSGeneration
4
+
5
+ # Header of the generated javascript file
6
+ HEADER = <<-EOF
7
+ /* This file is automatically generated by Waw. Any edit will probably be lost
8
+ * next time the application is started. */
9
+ EOF
10
+
11
+ # Strip n spaces at the begining of a string
12
+ def strip(str, n)
13
+ str.gsub(/\t/, " ").gsub(/^\s{#{n}}/, '')
14
+ end
15
+
16
+ # Raises a ConfigurationError
17
+ def error(msg)
18
+ raise ConfigurationError, msg
19
+ end
20
+
21
+ # Start hook start callback required by Waw. Generates the javascript code
22
+ # if the configuration variable 'code_at_startup' is true.
23
+ def run(waw_kernel)
24
+ return unless waw_kernel.config.code_at_startup
25
+
26
+ # Now, find the StaticController, that should be installed
27
+ static = waw_kernel.find_rack_app {|app| ::Waw::StaticController===app}
28
+ error("Code generation expects a ::Waw::StaticController being installed.") if static.nil?
29
+
30
+ # Find the folder now
31
+ folder = File.join(waw_kernel.root_folder, static.public_folder, 'js')
32
+ error("Code generation expects #{folder} to be an existing directory.") unless File.directory?(folder)
33
+
34
+ # Look for the application name
35
+ appname = waw_kernel.config.knows?(:application_name) ? waw_kernel.config.application_name : 'waw'
36
+
37
+ # And let's go now!
38
+ file = File.join(folder, "#{appname}_generated.js")
39
+ File.open(file, 'w') do |buffer|
40
+ generate_js(waw_kernel, buffer)
41
+ end
42
+ end
43
+
44
+ # Generate the javascript code for installed action controllers.
45
+ def generate_js(waw_kernel, buffer)
46
+ # 1) header first
47
+ buffer << strip(HEADER, 8) << "\n"
48
+
49
+ # 2) messages
50
+ generate_js_messages(waw_kernel, buffer)
51
+
52
+ # 3) controllers
53
+ generate_js_controllers(waw_kernel, buffer)
54
+ end
55
+
56
+ # Generates the javascript code for message resources.
57
+ def generate_js_messages(waw_kernel, buffer)
58
+ if waw_kernel.resources.has_resource?(:messages)
59
+ buffer << "/* Messages, from waw.resources.messages */\n"
60
+ messages = {}
61
+ waw_kernel.resources.messages.each do |name, value|
62
+ messages[name] = value
63
+ end
64
+ buffer << "var messages = new Array();\n"
65
+ messages.keys.sort{|k1, k2| k1.to_s <=> k2.to_s}.each do |name|
66
+ value = messages[name]
67
+ buffer << "messages['#{name}'] = \"#{value}\";\n"
68
+ end
69
+ buffer << "\n"
70
+ end
71
+ end
72
+
73
+ # Generates the js controllers
74
+ def generate_js_controllers(waw_kernel, buffer)
75
+ ActionController.controllers.sort{|c1, c2| c1.class.name <=> c2.class.name}.each do |controller|
76
+ # Let find the URL for this controller
77
+ app = waw_kernel.find_rack_app{|a| controller===a}
78
+ url = app ? app.find_url_of(app) : nil
79
+ unless url
80
+ waw_kernel.logger.warn("Skipping #{controller}, which does not seem to be mapped to an URL")
81
+ else
82
+ header = <<-EOF
83
+ /* Actions contributed by #{controller}, mapped to #{url} */
84
+ EOF
85
+ buffer << strip(header, 14)
86
+ controller.actions.keys.sort{|k1, k2| k1.to_s <=> k2.to_s}.each do |name|
87
+ action = controller.actions[name]
88
+ generate_js_for_action(waw_kernel, action, buffer)
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ # Generates the javascript code for a given action
95
+ def generate_js_for_action(waw_kernel, action, buffer)
96
+ action_js = <<-THEEND
97
+ function #{action.id}(request_data, form) {
98
+ $.ajax({type: "POST", url: "#{action.url}", data: request_data, dataType: "json",
99
+ error: function(data) {
100
+ window.location = '/feedback?mkey=server_error';
101
+ },
102
+ success: function(data) {
103
+ THEEND
104
+ action_js << action.routing.generate_js_routing(action, 0).gsub(/^/, " "*16) << "\n"
105
+ action_js << <<-THEEND
106
+ }
107
+ });
108
+ return false;
109
+ }
110
+ THEEND
111
+ buffer << strip(action_js, 10)
112
+ end
113
+
114
+ end # class JSGeneration
115
+ end # class ActionController
116
+ end # module Waw
@@ -0,0 +1,133 @@
1
+ require 'waw/controllers/action/action_utils'
2
+ require 'waw/controllers/action/action'
3
+ require 'waw/controllers/action/js_generation'
4
+ module Waw
5
+
6
+ #
7
+ # Defines a specific application controller for executing actions.
8
+ #
9
+ class ActionController < Waw::Controller
10
+ include ActionUtils
11
+ extend FullState::OnClass
12
+ extend FullState::OnInstance
13
+
14
+ # All subclasses
15
+ @@controllers = []
16
+
17
+ class << self
18
+
19
+ # Returns known controllers
20
+ def controllers
21
+ @@controllers
22
+ end
23
+
24
+ # When this class is inherited we track the new controller, it becomes a
25
+ # Singleton and we install code generation as start hook if not already done.
26
+ def inherited(child)
27
+ super(child)
28
+ # Adds the controller as a child
29
+ controllers << child
30
+
31
+ # Let it become a singleton
32
+ child.instance_eval { include Singleton }
33
+
34
+ # And install start hook for code generation
35
+ if controllers.size==1 && (k = Waw.kernel)
36
+ k.add_start_hook(JSGeneration.new)
37
+ k.add_unload_hook ::Kernel.lambda { @@controllers = [] }
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ # This is all about actions
44
+ class << self
45
+ include ActionUtils
46
+
47
+ # Returns the url on which this controller is mapped
48
+ def url
49
+ self.instance.url
50
+ end
51
+
52
+ # Returns installed actions
53
+ def actions
54
+ @actions ||= {}
55
+ end
56
+
57
+ # Fired when a signature will be next installed
58
+ def signature(signature=nil, &block)
59
+ signature = (signature.nil? ? Waw::Validation::Signature.new : signature)
60
+ signature = signature.merge(&block) if block
61
+ @signature = signature
62
+ end
63
+
64
+ # Installs a routing block for the next action
65
+ def routing(&block)
66
+ @routing = Waw::Routing::ActionRouting.new(&block)
67
+ end
68
+
69
+ # If a signature has been installed, let the next added method
70
+ # become an action
71
+ def method_added(name)
72
+ if @signature and not(@critical)
73
+ @critical = true
74
+
75
+ # Create the action instance
76
+ action = Waw::ActionController::Action.new(name, @signature, @routing, self, instance_method(name))
77
+ actions[name] = action
78
+
79
+ # Installs the class method that returns the action
80
+ instance_eval <<-EOF
81
+ class << self
82
+ def #{name}
83
+ actions[:#{name}]
84
+ end
85
+ end
86
+ EOF
87
+
88
+ # Installs the instance method that execute the action
89
+ define_method name do |params|
90
+ action.execute(params)
91
+ end
92
+ end
93
+ @signature, @routing, @critical = nil, nil, false
94
+ end
95
+
96
+ end # end of class methods
97
+
98
+ # Returns the url on which this controller is mapped
99
+ def url
100
+ find_kernel_context.find_url_of(self)
101
+ end
102
+
103
+ # Returns the actions installed on this controller
104
+ def actions
105
+ self.class.actions
106
+ end
107
+
108
+ # Ensapsules the action call
109
+ def encapsulate(action, actual_params, &block)
110
+ yield
111
+ end
112
+
113
+ # Executes the controller
114
+ def execute(env, request, response)
115
+ action_name = request.respond_to?(:path) ? request.path : request[:action]
116
+ logger.debug("Executing the action whose name is #{action_name}")
117
+ action = find_action(action_name)
118
+ if action
119
+ actual_params = request.params.symbolize_keys
120
+ result = encapsulate(action, actual_params) do
121
+ action.execute(actual_params)
122
+ end
123
+ logger.debug("ActionResult is #{result.inspect}")
124
+ [200, {}, result]
125
+ else
126
+ logger.warn("Action #{action_name} has not been found")
127
+ [200, {}, [:error, :action_not_found]]
128
+ end
129
+ end
130
+
131
+ end # class ActionController
132
+
133
+ end # module Waw
@@ -0,0 +1,54 @@
1
+ require 'cgi'
2
+ module Waw
3
+ class ErrorHandler < ::Waw::Controller
4
+ class Backtrace
5
+
6
+ # Converts a back-trace to a friendly HTML chunck
7
+ def ex_backtrace_to_html(backtrace)
8
+ "<div>" + backtrace.collect{|s| CGI.escapeHTML(s)}.join('</div><div>') + "</div>"
9
+ end
10
+
11
+ # Converts an exception to a friendly HTML chunck
12
+ def ex_to_html(ex, backtrace)
13
+ <<-EOF
14
+ <html>
15
+ <head>
16
+ <style type="text/css">
17
+ body {
18
+ font-size: 14px;
19
+ font-family: "Courier", "Arial", sans-serif;
20
+ }
21
+ p.message {
22
+ font-size: 16px;
23
+ font-weight: bold;
24
+ }
25
+ </style>
26
+ </head>
27
+ <body>
28
+ <h1>Internal server error (ruby exception)</h1>
29
+ <p class="message"><code>#{CGI.escapeHTML(ex.message)}</code></p>
30
+ <div style="margin-left:50px;">
31
+ #{ex_backtrace_to_html(backtrace)}
32
+ </div>
33
+ </body>
34
+ </html>
35
+ EOF
36
+ end
37
+
38
+ # Shows a page with a friendly presented backtrace for the error
39
+ # that occured
40
+ def call(kernel, ex)
41
+ backtrace = case ex
42
+ when ::WLang::Error
43
+ ex.wlang_backtrace
44
+ when ::Exception
45
+ ex.backtrace
46
+ else
47
+ []
48
+ end
49
+ [500, {'Content-Type' => 'text/html'}, ex_to_html(ex, backtrace)]
50
+ end
51
+
52
+ end # class Backtrace
53
+ end # module ErrorHandler
54
+ end # module Waw
@@ -0,0 +1,62 @@
1
+ require 'waw/controllers/error/backtrace'
2
+ module Waw
3
+ class ErrorHandler < ::Waw::Controller
4
+
5
+ # Creates an error handler rack application
6
+ def initialize(app)
7
+ @app = app
8
+ @validators, @handlers = [], []
9
+ end
10
+
11
+ # Handles arguments of push and unshift
12
+ def handle_args(args, &block)
13
+ validator, handler = args
14
+ handler = block if handler.nil?
15
+ validator, handler = nil, validator if handler.nil?
16
+ [validator, handler]
17
+ end
18
+
19
+ # Adds an error handler. The method accepts the following
20
+ # argument variants:
21
+ #
22
+ # add_error_handler{|k,ex| ... }
23
+ # add_error_handler(SomeValidator){|k,ex| ... }
24
+ # add_error_handler(SomeHandler)
25
+ # add_error_handler(SomeValidator, SomeHandler)
26
+ #
27
+ def add_error_handler(*args, &block)
28
+ validator, handler = handle_args(args, &block)
29
+ @validators << validator
30
+ @handlers << handler
31
+ end
32
+ alias :push :add_error_handler
33
+
34
+ # Same as add_error_handler but adds it at the begining of the
35
+ # chain
36
+ def unshift(*args, &block)
37
+ validator, handler = handle_args(args, &block)
38
+ @validators.unshift(validator)
39
+ @handlers.unshift(handler)
40
+ end
41
+
42
+ # Checks if a result seems a valid rack application result
43
+ def seems_valid_result?(result)
44
+ not(result.nil?) and Array===result and result.size==3
45
+ end
46
+
47
+ # Handles a call
48
+ def call(env)
49
+ @app.call(env)
50
+ rescue Exception => ex
51
+ kernel = find_kernel_context
52
+ @validators.each_with_index do |validator, i|
53
+ if (validator.nil? or (validator===ex))
54
+ result = @handlers[i].call(kernel, ex)
55
+ return result if seems_valid_result?(result)
56
+ end
57
+ end
58
+ raise ex
59
+ end
60
+
61
+ end # class ErrorHandler
62
+ end # module Waw
@@ -0,0 +1,31 @@
1
+ require 'json'
2
+ module Waw
3
+ #
4
+ # Decorates a given controller and convert result as JSON unless stated
5
+ # otherwise.
6
+ #
7
+ class JSONController
8
+ include ::Rack::Delegator
9
+
10
+ # Creates a controller instance
11
+ def initialize(app)
12
+ raise WAWError, "JSONController expects a delegation controller" if app.nil?
13
+ @app = app
14
+ end
15
+
16
+ # Calls the delegation controller and encode its result in JSON
17
+ def call(env)
18
+ status, headers, body = @app.call(env)
19
+ header = {} if headers.nil?
20
+ headers['Content-Type'] = 'application/json' if headers['Content-Type'].nil?
21
+ body = ::JSON.generate(body) if json_response?(headers)
22
+ [status, headers, body]
23
+ end
24
+
25
+ # Do i need to encode as JSON?
26
+ def json_response?(headers)
27
+ (headers['Content-Type'] == 'application/json')
28
+ end
29
+
30
+ end # class JSONController
31
+ end # module Waw
@@ -0,0 +1,22 @@
1
+ require 'time'
2
+ module Waw
3
+ class NoCache < ::Waw::Controller
4
+
5
+ # What is sent to the headers
6
+ NO_CACHE_HEADERS = {'Cache-control' => "no-store, no-cache, must-revalidate",
7
+ 'Pragma' => "no-cache"}
8
+
9
+ # Creates a application instance
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ # Manage calls
15
+ def call(env)
16
+ status, headers, body = @app.call(env)
17
+ headers = NO_CACHE_HEADERS.merge('Expires' => Time.now.rfc2822).merge(headers)
18
+ [status, headers, body]
19
+ end
20
+
21
+ end # class NoCache
22
+ end # module Waw