respect-rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data/FAQ.md +98 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +291 -0
  4. data/RELATED_WORK.md +47 -0
  5. data/RELEASE_NOTES.md +20 -0
  6. data/Rakefile +32 -0
  7. data/app/assets/javascripts/respect/rails/schemas.js +32 -0
  8. data/app/assets/stylesheets/respect/rails/schemas.css +160 -0
  9. data/app/controllers/respect/rails/schemas_controller.rb +36 -0
  10. data/app/helpers/respect/rails/schemas_helper.rb +78 -0
  11. data/app/views/layouts/respect/rails/schemas.html.erb +14 -0
  12. data/app/views/respect/rails/request_validation_exception.html.erb +38 -0
  13. data/app/views/respect/rails/schemas/doc.html.erb +158 -0
  14. data/app/views/respect/rails/schemas/index.html.erb +4 -0
  15. data/config/routes.rb +4 -0
  16. data/lib/respect/rails/action_def.rb +37 -0
  17. data/lib/respect/rails/action_schema.rb +41 -0
  18. data/lib/respect/rails/application_info.rb +26 -0
  19. data/lib/respect/rails/controller_helper.rb +107 -0
  20. data/lib/respect/rails/engine.rb +63 -0
  21. data/lib/respect/rails/engine_info.rb +27 -0
  22. data/lib/respect/rails/headers_helper.rb +11 -0
  23. data/lib/respect/rails/headers_simplifier.rb +31 -0
  24. data/lib/respect/rails/info.rb +72 -0
  25. data/lib/respect/rails/request_def.rb +38 -0
  26. data/lib/respect/rails/request_helper.rb +101 -0
  27. data/lib/respect/rails/request_schema.rb +102 -0
  28. data/lib/respect/rails/response_def.rb +43 -0
  29. data/lib/respect/rails/response_helper.rb +67 -0
  30. data/lib/respect/rails/response_schema.rb +84 -0
  31. data/lib/respect/rails/response_schema_set.rb +60 -0
  32. data/lib/respect/rails/route_info.rb +101 -0
  33. data/lib/respect/rails/version.rb +5 -0
  34. data/lib/respect/rails.rb +74 -0
  35. data/lib/tasks/respect_tasks.rake +4 -0
  36. data/test/dummy/README.rdoc +261 -0
  37. data/test/dummy/Rakefile +7 -0
  38. data/test/dummy/app/assets/javascripts/application.js +15 -0
  39. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  40. data/test/dummy/app/controllers/application_controller.rb +3 -0
  41. data/test/dummy/app/controllers/automatic_validation_controller.rb +300 -0
  42. data/test/dummy/app/controllers/caught_exception_controller.rb +58 -0
  43. data/test/dummy/app/controllers/disabled_controller.rb +37 -0
  44. data/test/dummy/app/controllers/manual_validation_controller.rb +63 -0
  45. data/test/dummy/app/controllers/no_schema_controller.rb +17 -0
  46. data/test/dummy/app/controllers/skipped_automatic_validation_controller.rb +35 -0
  47. data/test/dummy/app/helpers/application_helper.rb +2 -0
  48. data/test/dummy/app/helpers/respect/application_macros.rb +10 -0
  49. data/test/dummy/app/helpers/respect/circle_schema.rb +16 -0
  50. data/test/dummy/app/helpers/respect/point_schema.rb +19 -0
  51. data/test/dummy/app/helpers/respect/rgba_schema.rb +18 -0
  52. data/test/dummy/app/views/automatic_validation/request_format.html.erb +1 -0
  53. data/test/dummy/app/views/automatic_validation/request_format.pdf.erb +1 -0
  54. data/test/dummy/app/views/caught_exception/response_validator.html.erb +1 -0
  55. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  56. data/test/dummy/config/application.rb +58 -0
  57. data/test/dummy/config/boot.rb +10 -0
  58. data/test/dummy/config/database.yml +25 -0
  59. data/test/dummy/config/environment.rb +5 -0
  60. data/test/dummy/config/environments/development.rb +37 -0
  61. data/test/dummy/config/environments/production.rb +67 -0
  62. data/test/dummy/config/environments/test.rb +37 -0
  63. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  64. data/test/dummy/config/initializers/inflections.rb +15 -0
  65. data/test/dummy/config/initializers/mime_types.rb +5 -0
  66. data/test/dummy/config/initializers/respect.rb +9 -0
  67. data/test/dummy/config/initializers/secret_token.rb +7 -0
  68. data/test/dummy/config/initializers/session_store.rb +8 -0
  69. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  70. data/test/dummy/config/locales/en.yml +5 -0
  71. data/test/dummy/config/routes.rb +38 -0
  72. data/test/dummy/config.ru +4 -0
  73. data/test/dummy/db/development.sqlite3 +0 -0
  74. data/test/dummy/db/schema.rb +16 -0
  75. data/test/dummy/db/test.sqlite3 +0 -0
  76. data/test/dummy/lib/exts/Rgba.rb +11 -0
  77. data/test/dummy/lib/exts/circle.rb +11 -0
  78. data/test/dummy/lib/exts/point.rb +11 -0
  79. data/test/dummy/log/development.log +6 -0
  80. data/test/dummy/log/test.log +851 -0
  81. data/test/dummy/public/404.html +26 -0
  82. data/test/dummy/public/422.html +26 -0
  83. data/test/dummy/public/500.html +25 -0
  84. data/test/dummy/public/favicon.ico +0 -0
  85. data/test/dummy/script/rails +6 -0
  86. data/test/functional/automatic_validation_controller_test.rb +131 -0
  87. data/test/functional/caught_exception_controller_test.rb +50 -0
  88. data/test/functional/disabled_controller_test.rb +16 -0
  89. data/test/functional/manual_validation_controller_test.rb +24 -0
  90. data/test/functional/no_schema_controller_test.rb +12 -0
  91. data/test/functional/respect/rails/schemas_controller_test.rb +18 -0
  92. data/test/functional/skipped_automatic_validation_controller_test.rb +12 -0
  93. data/test/headers_can_dumped_in_json.sh +33 -0
  94. data/test/integration/navigation_test.rb +38 -0
  95. data/test/request_headers_validation_in_dev_mode.sh +33 -0
  96. data/test/test_helper.rb +17 -0
  97. data/test/unit/action_schema_test.rb +21 -0
  98. data/test/unit/application_info_test.rb +11 -0
  99. data/test/unit/controller_helper_test.rb +4 -0
  100. data/test/unit/engine_info_test.rb +11 -0
  101. data/test/unit/engine_test.rb +7 -0
  102. data/test/unit/info_test.rb +42 -0
  103. data/test/unit/request_def_test.rb +22 -0
  104. data/test/unit/request_helper_test.rb +67 -0
  105. data/test/unit/request_schema_test.rb +164 -0
  106. data/test/unit/response_def_test.rb +9 -0
  107. data/test/unit/response_helper_test.rb +73 -0
  108. data/test/unit/response_schema_set_test.rb +18 -0
  109. data/test/unit/response_schema_test.rb +147 -0
  110. metadata +334 -0
@@ -0,0 +1,36 @@
1
+ module Respect
2
+ module Rails
3
+ # Controller to get all the information relative to the
4
+ # REST API of this application.
5
+ class SchemasController < ActionController::Base
6
+ def_action_schema :index do |s|
7
+ s.request do |r|
8
+ r.path_parameters do |s|
9
+ s.string "format", in: %w{html json}
10
+ end
11
+ end
12
+ end
13
+
14
+ def index
15
+ respond_to do |format|
16
+ format.html # index.html.erb
17
+ end
18
+ end
19
+
20
+ def_action_schema :doc do |s|
21
+ s.request do |r|
22
+ r.path_parameters do |s|
23
+ s.string "format", in: %w{html json}
24
+ end
25
+ end
26
+ end
27
+
28
+ def doc
29
+ @info = Respect::Rails::Info.new
30
+ respond_to do |format|
31
+ format.html # doc.html.erb
32
+ end
33
+ end
34
+ end
35
+ end # module Rails
36
+ end # module Respect
@@ -0,0 +1,78 @@
1
+ module Respect
2
+ module Rails
3
+ module SchemasHelper
4
+
5
+ def highlight_json_schema(json_schema)
6
+ Respect::JSONSchemaHTMLFormatter.new(json_schema).dump.html_safe
7
+ end
8
+
9
+ # FIXME(Nicolas Despres): Test me.
10
+ def describe_option(name, value)
11
+ result = describe_option_internal(name, value)
12
+ result.html_safe if result
13
+ end
14
+
15
+ def toggler(text, &block)
16
+ @toggler_id ||= -1
17
+ @toggler_id += 1
18
+ toggler_key = "toggle_#@toggler_id"
19
+ content_tag :div do
20
+ result = content_tag(:div, class: "summary") do
21
+ content_tag :a, text, href: "#", onclick: "return toggle(#@toggler_id)", id: "#{toggler_key}_toggle"
22
+ end
23
+ result << content_tag(:div, capture(&block), id: toggler_key, style: "display:none")
24
+ end
25
+ end
26
+
27
+ # FIXME(Nicolas Despres): Make me more generic to all enumerable and test me.
28
+ def flat_each(hash, &block)
29
+ flat_each_rec([], hash, &block)
30
+ end
31
+
32
+ # FIXME(Nicolas Despres): Test me
33
+ def build_parameter_name(path)
34
+ path.first.to_s + path[1..-1].reduce(""){|r, x| r + "[#{x}]" }
35
+ end
36
+
37
+ private
38
+
39
+ def describe_option_internal(name, value)
40
+ case name
41
+ when :doc, :required
42
+ nil
43
+ when :default
44
+ if value.nil?
45
+ nil
46
+ else
47
+ "default to #{value.inspect}"
48
+ end
49
+ when :equal_to
50
+ "Must be equal to #{value.inspect}"
51
+ when :allow_nil
52
+ if value
53
+ "May be null"
54
+ else
55
+ nil
56
+ end
57
+ when :strict
58
+ if value
59
+ "Must contains exactly these parameters"
60
+ else
61
+ nil
62
+ end
63
+ else
64
+ "#{name}: #{value.inspect}"
65
+ end
66
+ end
67
+
68
+ def flat_each_rec(path, hash, &block)
69
+ hash.each do |k, v|
70
+ block.call(path + [k], v)
71
+ if v.is_a?(Respect::HashSchema)
72
+ flat_each_rec(path + [k], v, &block)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%= content_tag :title, "#{Respect::Rails::Engine.doc_app_name} API" %>
5
+ <%= stylesheet_link_tag "respect/rails/schemas", :media => "all" %>
6
+ <%= javascript_include_tag "respect/rails/schemas" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Request validation error caught</title>
6
+ <style>
7
+ body { background-color: #fff; color: #333; }
8
+
9
+ body, p, ol, ul, td {
10
+ font-family: helvetica, verdana, arial, sans-serif;
11
+ font-size: 13px;
12
+ line-height: 18px;
13
+ }
14
+
15
+ pre {
16
+ background-color: #eee;
17
+ padding: 10px;
18
+ font-size: 11px;
19
+ white-space: pre-wrap;
20
+ }
21
+
22
+ a { color: #000; }
23
+ a:visited { color: #666; }
24
+ a:hover { color: #fff; background-color:#000; }
25
+ </style>
26
+ </head>
27
+ <body>
28
+ <h1>Request validation error in <%= "#{controller_name.camelize}Controller##{action_name}" %></h1>
29
+ <p>
30
+ Invalid <%= @error.part %> parameters:
31
+ <pre><%= @error.context.join("\n") %></pre>
32
+ </p>
33
+ <p>
34
+ Processed object:
35
+ <%= Respect::JSONSchemaHTMLFormatter.new(@error.object).dump.html_safe %>
36
+ </p>
37
+ </body>
38
+ </html>
@@ -0,0 +1,158 @@
1
+ <h1><%= @info.app.name %> API Documentation</h1>
2
+
3
+ <%= content_tag :p, @info.app.title %>
4
+ <%= content_tag :p, @info.app.description %>
5
+ <p>
6
+ This document describes the <%= @info.app.name %> API interface. It is designed for developers
7
+ who wants to interoperate with <%= @info.app.name %> in their own application.
8
+ </p>
9
+
10
+ <div class="toc">
11
+ <h2 class="title">Table of content</h2>
12
+
13
+ <% @info.toc.keys.sort.each do |controller_name| %>
14
+ <%= content_tag :h3, controller_name.gsub(%r{/}, ' ').titleize %>
15
+ <table>
16
+ <% @info.toc[controller_name].keys.sort.each do |action_name| %>
17
+ <% route = @info.toc[controller_name][action_name] %>
18
+ <tr>
19
+ <%= content_tag :td do %>
20
+ <%= link_to route.spec, doc_path(anchor: route.anchor) %>
21
+ <% end %>
22
+ <%= content_tag :td, route.schema.title, width: "60%" %>
23
+ </tr>
24
+ <% end %>
25
+ </table>
26
+ <% end %>
27
+ </div>
28
+
29
+ <hr>
30
+
31
+ <div class="route">
32
+ <%
33
+ @info.toc.keys.sort.each do |controller_name|
34
+ @info.toc[controller_name].keys.sort.each do |action_name|
35
+
36
+ route = @info.toc[controller_name][action_name]
37
+ action_schema = route.schema
38
+ %>
39
+ <h2 class="title">
40
+ <%= content_tag :a, route.spec, id: route.anchor %>
41
+ </h2>
42
+
43
+ <%= content_tag :p, action_schema.title %>
44
+ <%= content_tag :p, action_schema.description %>
45
+
46
+ <%
47
+ if action_schema.request
48
+ request_schema = action_schema.request
49
+ %>
50
+ <h3>Request</h3>
51
+ <% unless request_schema.headers.documented_properties.empty? %>
52
+ <h4>Headers</h4>
53
+
54
+ <table>
55
+ <% request_schema.headers.each do |name, schema| %>
56
+ <tr>
57
+ <td width="30%">
58
+ <strong><%= name %></strong>
59
+ <br>
60
+ <span class="constraint">
61
+ <%= schema.optional? ? "optional" : "required" %>
62
+ <%= schema.class.statement_name %>
63
+ </span>
64
+ </td>
65
+ <td>
66
+ <% if schema.title %>
67
+ <%= schema.title %>
68
+ <br>
69
+ <% end %>
70
+ <% if schema.description %>
71
+ <%= schema.description %>
72
+ <br>
73
+ <% end %>
74
+ <ul>
75
+ <%
76
+ schema.options.each do |name, value|
77
+ desc = describe_option(name, value)
78
+ if desc %>
79
+ <li><span class="constraint"><%= desc %></span></li>
80
+ <% end %>
81
+ <% end %>
82
+ </ul>
83
+ </td>
84
+ </tr>
85
+ <% end %>
86
+ </table>
87
+
88
+ <%= toggler "Show headers schema" do %>
89
+ <%= highlight_json_schema request_schema.headers.to_h %>
90
+ <% end %>
91
+ <% end %>
92
+
93
+ <%
94
+ [ :path, :query, :body ].each do |name|
95
+ params_schema = request_schema.send("#{name}_parameters")
96
+ unless params_schema.documented_properties.empty? %>
97
+ <h4><%= name.capitalize %> parameters</h4>
98
+
99
+ <table>
100
+ <% flat_each(params_schema) do |path, schema| %>
101
+ <tr>
102
+ <td width="30%">
103
+ <strong><%= build_parameter_name path %></strong>
104
+ <br>
105
+ <span class="constraint">
106
+ <%= schema.optional? ? "optional" : "required" %>
107
+ <%= schema.class.statement_name %>
108
+ </span>
109
+ </td>
110
+ <td>
111
+ <% if schema.title %>
112
+ <%= schema.title %>
113
+ <br>
114
+ <% end %>
115
+ <% if schema.description %>
116
+ <%= schema.description %>
117
+ <br>
118
+ <% end %>
119
+ <ul>
120
+ <%
121
+ schema.options.each do |name, value|
122
+ desc = describe_option(name, value)
123
+ if desc %>
124
+ <li><span class="constraint"><%= desc %></span></li>
125
+ <% end %>
126
+ <% end %>
127
+ </ul>
128
+ </td>
129
+ </tr>
130
+ <% end %>
131
+ </table>
132
+
133
+ <%= toggler "Show #{name} parameters schema" do %>
134
+ <%= highlight_json_schema params_schema.to_h %>
135
+ <% end %>
136
+ <% end %>
137
+ <% end %>
138
+ <% end %>
139
+
140
+ <% unless action_schema.responses.empty? %>
141
+ <% action_schema.responses.each do |status, response_schema| %>
142
+ <h3>Response <%= response_schema.http_status %> [ <%= response_schema.status %> ]</h3>
143
+ <%= content_tag :p, response_schema.title %>
144
+ <%= content_tag :p, response_schema.description %>
145
+ <% unless response_schema.headers.documented_properties.empty? %>
146
+ <h4>Headers</h4>
147
+ <%= highlight_json_schema response_schema.headers.to_h %>
148
+ <% end %>
149
+ <% if response_schema.body %>
150
+ <h4>Body</h4>
151
+ <%= highlight_json_schema response_schema.body.to_h %>
152
+ <% end %>
153
+ <% end %>
154
+ <% end %>
155
+
156
+ <% end %>
157
+ <% end %>
158
+ </div>
@@ -0,0 +1,4 @@
1
+ <h1>Welcome to Respect</h1>
2
+ <ul>
3
+ <li><%= link_to "Documentation", doc_path %></li>
4
+ </ul>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ Respect::Rails::Engine.routes.draw do
2
+ root to: 'schemas#index', via: :get, format: 'html'
3
+ match '/doc' => 'schemas#doc', via: :get, as: 'doc'
4
+ end
@@ -0,0 +1,37 @@
1
+ module Respect
2
+ module Rails
3
+ class ActionDef
4
+
5
+ class << self
6
+ def eval(*args, &block)
7
+ new(*args).eval(&block)
8
+ end
9
+ end
10
+
11
+ def initialize(*args)
12
+ @action_schema = ActionSchema.new(*args)
13
+ end
14
+
15
+ def eval(&block)
16
+ block.call(self)
17
+ @action_schema
18
+ end
19
+
20
+ def request(&block)
21
+ @action_schema.request = RequestSchema.define(@action_schema.controller_name,
22
+ @action_schema.action_name, &block)
23
+ end
24
+
25
+ def response_for(&block)
26
+ block.call(@action_schema.responses)
27
+ @action_schema.responses
28
+ end
29
+
30
+ # Set the documentation to +text+.
31
+ def documentation(text)
32
+ @action_schema.documentation = text
33
+ end
34
+
35
+ end # class ActionDef
36
+ end # module Rails
37
+ end # module Respect
@@ -0,0 +1,41 @@
1
+ module Respect
2
+ module Rails
3
+ class ActionSchema
4
+ include Respect::DocHelper
5
+
6
+ class << self
7
+ def from_controller(controller_name, action_name)
8
+ klass = "#{controller_name}_controller".classify.safe_constantize
9
+ @schema = klass.new.action_schema(action_name) if klass
10
+ end
11
+
12
+ def define(*args, &block)
13
+ ActionDef.eval(*args, &block)
14
+ end
15
+ end
16
+
17
+ def initialize(controller, action_name)
18
+ @controller = controller
19
+ @action_name = action_name
20
+ @responses = ResponseSchemaSet.new(controller_name, @action_name)
21
+ end
22
+
23
+ attr_reader :controller, :action_name
24
+
25
+ def controller_name
26
+ @controller.controller_name
27
+ end
28
+
29
+ attr_accessor :request
30
+
31
+ attr_reader :responses
32
+
33
+ # Whether there is at least a request schema or one response schema for this action.
34
+ def has_schema?
35
+ request || !responses.empty? || documentation
36
+ end
37
+
38
+ attr_accessor :documentation
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ module Respect
2
+ module Rails
3
+ class ApplicationInfo < EngineInfo
4
+ include Respect::DocHelper
5
+
6
+ def initialize(app_class = ::Rails.application.class)
7
+ super(app_class)
8
+ unless app_class < ::Rails::Application
9
+ raise "'#{app_class}' must be an ancestor of ::Rails::Application."
10
+ end
11
+ @app_class = app_class
12
+ end
13
+
14
+ attr_reader :app_class
15
+
16
+ def name
17
+ Engine.doc_app_name
18
+ end
19
+
20
+ def documentation
21
+ Respect::Rails::Engine.app_documentation
22
+ end
23
+
24
+ end # class ApplicationInfo
25
+ end # module Rails
26
+ end # module Respect
@@ -0,0 +1,107 @@
1
+ module Respect
2
+ module Rails
3
+ module ControllerHelper
4
+ extend ActiveSupport::Concern
5
+
6
+ included do |base|
7
+ around_filter :load_schemas!
8
+ end
9
+
10
+ module ClassMethods
11
+ # Install a handler for {Respect::Rails::RequestValidationError}. It provides a more specific
12
+ # error report than the default exception handler in development. For instance you get the
13
+ # context of where the error happened in the JSON document.
14
+ #
15
+ # Example:
16
+ # # In your ApplicationController class.
17
+ # rescue_from_request_valiation_error if Rails.env.development?
18
+ def rescue_from_request_validation_error
19
+ rescue_from Respect::Rails::RequestValidationError do |exception|
20
+ respond_to do |format|
21
+ format.html do
22
+ @error = exception
23
+ render template: "respect/rails/request_validation_exception", layout: false, status: :internal_server_error
24
+ end
25
+ format.json do
26
+ render json: exception.to_json, status: :internal_server_error
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ # FIXME(Nicolas Despres): Document me.
33
+ def def_action_schema(action_name, &block)
34
+ define_method("#{action_name}_schema") do
35
+ Respect::Rails::ActionSchema.define(self, action_name, &block)
36
+ end
37
+ end
38
+ end
39
+
40
+ # FIXME(Nicolas Despres): Test me!!!
41
+ def action_schema(action = nil)
42
+ action ||= self.action_name
43
+ method_name = "#{action}_schema"
44
+ if self.respond_to?(method_name)
45
+ send(method_name)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ # This "around" filter calls +validation_request_schema+ and +validation_response_schema+
52
+ # respectively before and after the controller's action.
53
+ def validate_schemas!
54
+ validate_request_schema!
55
+ yield
56
+ validate_response_schema! if Respect::Rails::Engine.validate_response
57
+ end
58
+
59
+ # This "before" filter validates the request.
60
+ def validate_request_schema!
61
+ request.validate_schema
62
+ end
63
+
64
+ # This "after" filter validates the response with the schema associated to the
65
+ # response status if one is found.
66
+ def validate_response_schema!
67
+ load_response_schema!
68
+ response.validate_schema
69
+ end
70
+
71
+ # This "around" filter calls +load_request_schema+ and +load_response_schema+
72
+ # respectively before and after the controller's action. It is useful
73
+ # if you want to do the validation yourself. It only load the action schema
74
+ # and attach the request schema to the request object and the response schema to
75
+ # the response object.
76
+ def load_schemas!
77
+ load_request_schema!
78
+ yield
79
+ if Respect::Rails::Engine.validate_response
80
+ load_response_schema!
81
+ end
82
+ end
83
+
84
+ # This "before" filter load and attach the action schema to the request object.
85
+ # It is safe to call this method several times.
86
+ def load_request_schema!
87
+ request.send(:action_schema=, action_schema) unless request.has_schema?
88
+ end
89
+
90
+ # This "after" filter attach the response schema to the response object.
91
+ # You can safely call this filter multiple times (i.e. from other after
92
+ # filters callbacks).
93
+ def load_response_schema!
94
+ response.send(:schema=, request.response_schema(response.status)) unless response.has_schema?
95
+ end
96
+
97
+ # Before filter which sanitize all request parameters: +params+,
98
+ # +query_parameters+, +path_parameters+ and +request_parameters+.
99
+ # The request is validated first if it has not been yet.
100
+ def sanitize_params!
101
+ request.sanitize_params!
102
+ end
103
+ end # module ControllerHelper
104
+ end # module Rails
105
+ end # module Respect
106
+
107
+ ActionController::Base.send :include, Respect::Rails::ControllerHelper
@@ -0,0 +1,63 @@
1
+ require 'respect'
2
+
3
+ require 'respect/rails/headers_helper'
4
+ require 'respect/rails/request_helper'
5
+ require 'respect/rails/response_helper'
6
+ require 'respect/rails/controller_helper'
7
+
8
+ module Respect
9
+ module Rails
10
+ class Engine < ::Rails::Engine
11
+ isolate_namespace Respect::Rails
12
+ engine_name 'respect'
13
+
14
+ # Whether responses are validated by the +validate_schemas+ around filter.
15
+ # By default this is +true+ in development and test environment and +false+ otherwise.
16
+ mattr_accessor :validate_response
17
+ self.validate_response = (::Rails.env.development? || ::Rails.env.test?)
18
+
19
+ # Whether response validation error are caught. The exception will be rendered in JSON
20
+ # and the HTTP status will be set to 500.
21
+ # By default this is +true+ in development mode only.
22
+ mattr_accessor :catch_response_validation_error
23
+ self.catch_response_validation_error = ::Rails.env.development?
24
+
25
+ # Whether to validate request headers.
26
+ # This option is available because Rails 3 does not support headers well in test mode.
27
+ # It is +false+ by default in test mode to let you do non-headers related functional
28
+ # test anyway.
29
+ # See: https://github.com/rails/rails/issues/6513
30
+ mattr_accessor :disable_request_headers_validation
31
+ self.disable_request_headers_validation = ::Rails.env.test?
32
+
33
+ # Set the application name use in the documentation. By default it is the same
34
+ # as your application class.
35
+ mattr_writer :doc_app_name
36
+ def self.doc_app_name
37
+ @@doc_app_name ||= ::Rails.application.class.parent_name
38
+ end
39
+
40
+ # Default way to setup Respect for Rails.
41
+ def self.setup(&block)
42
+ block.call(self)
43
+ end
44
+
45
+ # Set the documentation of your application. The title would be the first line
46
+ # if followed by an empty line and the description would be the rest.
47
+ # If +text+ is +nil+ the current documentation is returned.
48
+ def self.app_documentation(text = nil)
49
+ if text
50
+ @@app_documentation = text
51
+ else
52
+ @@app_documentation
53
+ end
54
+ end
55
+
56
+ # Include all +helper_modules+ in the DSL definition classes, so that you can use its
57
+ # methods for defining schema.
58
+ def self.helpers(*helper_modules)
59
+ helper_modules.each{|m| Respect.extend_dsl_with(m) }
60
+ end
61
+ end # class Engine
62
+ end # module Rails
63
+ end # module Respect
@@ -0,0 +1,27 @@
1
+ module Respect
2
+ module Rails
3
+ class EngineInfo
4
+ include Comparable
5
+
6
+ def initialize(engine_class)
7
+ unless engine_class < ::Rails::Engine
8
+ raise "'#{engine_class}' must be an ancestor of ::Rails::Engine."
9
+ end
10
+ @engine_class = engine_class
11
+ end
12
+
13
+ attr_reader :engine_class
14
+
15
+ def name
16
+ @engine_class.engine_name.underscore
17
+ end
18
+
19
+ attr_accessor :routes
20
+
21
+ def <=>(other)
22
+ self.name <=> other.name
23
+ end
24
+
25
+ end # class EngineInfo
26
+ end # module Rails
27
+ end # module Respect
@@ -0,0 +1,11 @@
1
+ module Respect
2
+ module Rails
3
+ module HeadersHelper
4
+ def has_key?(header_name)
5
+ super || super(env_name(header_name))
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ ActionDispatch::Http::Headers.send :include, Respect::Rails::HeadersHelper
@@ -0,0 +1,31 @@
1
+ module Respect
2
+ module Rails
3
+ module HeadersSimplifier
4
+ # Copy the given +headers+ hash table but get rid of the
5
+ # _complex_ type at the same time.
6
+ #
7
+ # This is useful if you plan to serialize +headers+ and want to
8
+ # get rid of complex type which may raise errors when serializing.
9
+ def simplify_headers(headers)
10
+ case headers
11
+ when String, Numeric, TrueClass, FalseClass, Symbol, Mime::Type
12
+ headers
13
+ when Array
14
+ result = []
15
+ headers.each do |x|
16
+ v = simplify_headers(x)
17
+ result << v if v
18
+ end
19
+ result
20
+ when Hash
21
+ result = {}
22
+ headers.each do |k, v|
23
+ new_v = simplify_headers(v)
24
+ result[k] = new_v if new_v
25
+ end
26
+ result
27
+ end
28
+ end
29
+ end # module HeadersSimplifier
30
+ end # module Rails
31
+ end # module Respect