praxis 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +15 -2
  4. data/CHANGELOG.md +54 -1
  5. data/bin/praxis +49 -2
  6. data/lib/api_browser/Gruntfile.js +247 -90
  7. data/lib/api_browser/app/bower_components/angular-mocks/.bower.json +19 -0
  8. data/lib/api_browser/app/bower_components/angular-mocks/README.md +57 -0
  9. data/lib/api_browser/app/bower_components/angular-mocks/angular-mocks.js +2193 -0
  10. data/lib/api_browser/app/bower_components/angular-mocks/bower.json +9 -0
  11. data/lib/api_browser/app/bower_components/angular-mocks/package.json +27 -0
  12. data/lib/api_browser/app/bower_components/angular/.bower.json +6 -5
  13. data/lib/api_browser/app/bower_components/angular/README.md +23 -4
  14. data/lib/api_browser/app/bower_components/angular/angular-csp.css +6 -0
  15. data/lib/api_browser/app/bower_components/angular/angular.js +2287 -1597
  16. data/lib/api_browser/app/bower_components/angular/angular.min.js +212 -205
  17. data/lib/api_browser/app/bower_components/angular/angular.min.js.gzip +0 -0
  18. data/lib/api_browser/app/bower_components/angular/angular.min.js.map +3 -3
  19. data/lib/api_browser/app/bower_components/angular/bower.json +2 -1
  20. data/lib/api_browser/app/bower_components/angular/package.json +25 -0
  21. data/lib/api_browser/app/bower_components/showdown/.bower.json +39 -0
  22. data/lib/api_browser/app/bower_components/showdown/.jshintignore +2 -0
  23. data/lib/api_browser/app/bower_components/showdown/.travis.yml +8 -0
  24. data/lib/api_browser/app/bower_components/showdown/Gruntfile.js +100 -0
  25. data/lib/api_browser/app/bower_components/showdown/README.md +317 -0
  26. data/lib/api_browser/app/bower_components/showdown/bower.json +26 -0
  27. data/lib/api_browser/app/bower_components/showdown/compressed/Showdown.js +1606 -0
  28. data/lib/api_browser/app/bower_components/showdown/compressed/Showdown.js.map +1 -0
  29. data/lib/api_browser/app/bower_components/showdown/compressed/Showdown.min.js +2 -0
  30. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/github.min.js +2 -0
  31. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/github.min.js.map +1 -0
  32. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/prettify.min.js +2 -0
  33. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/prettify.min.js.map +1 -0
  34. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/table.min.js +2 -0
  35. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/table.min.js.map +1 -0
  36. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/twitter.min.js +2 -0
  37. data/lib/api_browser/app/bower_components/showdown/compressed/extensions/twitter.min.js.map +1 -0
  38. data/lib/api_browser/app/bower_components/showdown/license.txt +34 -0
  39. data/lib/api_browser/app/bower_components/showdown/package.json +47 -0
  40. data/lib/api_browser/app/bower_components/showdown/src/extensions/github.js +25 -0
  41. data/lib/api_browser/app/bower_components/showdown/src/extensions/prettify.js +29 -0
  42. data/lib/api_browser/app/bower_components/showdown/src/extensions/table.js +106 -0
  43. data/lib/api_browser/app/bower_components/showdown/src/extensions/twitter.js +42 -0
  44. data/lib/api_browser/app/bower_components/showdown/src/ng-showdown.js +150 -0
  45. data/lib/api_browser/app/bower_components/showdown/src/showdown.js +1454 -0
  46. data/lib/api_browser/app/index.html +6 -4
  47. data/lib/api_browser/app/js/app.js +1 -2
  48. data/lib/api_browser/app/js/controllers/action.js +4 -4
  49. data/lib/api_browser/app/js/controllers/controller.js +1 -1
  50. data/lib/api_browser/app/js/controllers/menu.js +5 -3
  51. data/lib/api_browser/app/js/controllers/type.js +5 -5
  52. data/lib/api_browser/app/js/directives/attribute_description.js +5 -5
  53. data/lib/api_browser/app/js/directives/attribute_table.js +1 -1
  54. data/lib/api_browser/app/js/directives/attribute_table_row.js +2 -2
  55. data/lib/api_browser/app/js/directives/no_container.js +1 -1
  56. data/lib/api_browser/app/js/directives/request_body.js +5 -5
  57. data/lib/api_browser/app/js/directives/request_headers.js +3 -6
  58. data/lib/api_browser/app/js/directives/request_parameters.js +3 -6
  59. data/lib/api_browser/app/js/directives/type_label.js +4 -5
  60. data/lib/api_browser/app/js/factories/Documentation.js +4 -4
  61. data/lib/api_browser/app/js/factories/PayloadTemplates.js +2 -2
  62. data/lib/api_browser/app/js/factories/TypeTemplates.js +3 -3
  63. data/lib/api_browser/app/js/filters/markdown.js +6 -0
  64. data/lib/api_browser/app/js/filters/resource_name.js +2 -2
  65. data/lib/api_browser/app/sass/modules/_header.scss +2 -7
  66. data/lib/api_browser/app/sass/{main.scss → praxis.scss} +0 -0
  67. data/lib/api_browser/app/sass/variables/_bootstrap-variables.scss +370 -367
  68. data/lib/api_browser/app/views/action.html +2 -2
  69. data/lib/api_browser/app/views/controller.html +2 -2
  70. data/lib/api_browser/app/views/directives/attribute_description.html +1 -1
  71. data/lib/api_browser/app/views/layout.html +2 -11
  72. data/lib/api_browser/app/views/navbar.html +9 -0
  73. data/lib/api_browser/app/views/resource/_actions.html +1 -1
  74. data/lib/api_browser/app/views/type.html +2 -2
  75. data/lib/api_browser/app/views/type/_details.html +2 -1
  76. data/lib/api_browser/bower.json +5 -0
  77. data/lib/api_browser/package.json +18 -7
  78. data/lib/praxis.rb +8 -3
  79. data/lib/praxis/action_definition.rb +28 -6
  80. data/lib/praxis/api_definition.rb +30 -2
  81. data/lib/praxis/api_general_info.rb +36 -0
  82. data/lib/praxis/bootloader.rb +1 -0
  83. data/lib/praxis/collection.rb +34 -0
  84. data/lib/praxis/controller.rb +7 -0
  85. data/lib/praxis/dispatcher.rb +3 -0
  86. data/lib/praxis/links.rb +2 -8
  87. data/lib/praxis/media_type.rb +6 -24
  88. data/lib/praxis/media_type_collection.rb +6 -2
  89. data/lib/praxis/plugin_concern.rb +2 -1
  90. data/lib/praxis/request.rb +24 -15
  91. data/lib/praxis/request_stages/request_stage.rb +19 -4
  92. data/lib/praxis/request_stages/validate_params_and_headers.rb +1 -1
  93. data/lib/praxis/request_stages/validate_payload.rb +1 -1
  94. data/lib/praxis/resource_definition.rb +45 -10
  95. data/lib/praxis/response_definition.rb +46 -27
  96. data/lib/praxis/restful_doc_generator.rb +94 -7
  97. data/lib/praxis/simple_media_type.rb +2 -9
  98. data/lib/praxis/stage.rb +1 -4
  99. data/lib/praxis/tasks/api_docs.rb +51 -19
  100. data/lib/praxis/tasks/routes.rb +19 -15
  101. data/lib/praxis/types/media_type_common.rb +31 -0
  102. data/lib/praxis/types/multipart.rb +4 -4
  103. data/lib/praxis/version.rb +1 -1
  104. data/praxis.gemspec +2 -2
  105. data/spec/api_browser/factories/documentation_spec.js +50 -0
  106. data/spec/api_browser/filters/attribute_name_spec.js +23 -0
  107. data/spec/functional_spec.rb +62 -10
  108. data/spec/praxis/action_definition_spec.rb +12 -4
  109. data/spec/praxis/api_definition_spec.rb +159 -0
  110. data/spec/praxis/api_general_info_spec.rb +36 -0
  111. data/spec/praxis/bootloader_spec.rb +10 -1
  112. data/spec/praxis/media_type_collection_spec.rb +46 -53
  113. data/spec/praxis/media_type_spec.rb +6 -6
  114. data/spec/praxis/request_stage_spec.rb +7 -2
  115. data/spec/praxis/request_stages_validate_spec.rb +12 -7
  116. data/spec/praxis/resource_definition_spec.rb +62 -0
  117. data/spec/praxis/response_definition_spec.rb +26 -16
  118. data/spec/praxis/stage_spec.rb +4 -8
  119. data/spec/praxis/types/collection_spec.rb +144 -0
  120. data/spec/spec_app/app/controllers/instances.rb +8 -2
  121. data/spec/spec_app/design/api.rb +11 -0
  122. data/spec/spec_app/design/media_types/instance.rb +12 -0
  123. data/spec/spec_app/design/media_types/volume.rb +9 -2
  124. data/spec/spec_app/design/media_types/volume_snapshot.rb +9 -6
  125. data/spec/spec_app/design/resources/instances.rb +25 -10
  126. data/spec/support/spec_media_types.rb +1 -1
  127. data/spec/support/spec_resource_definitions.rb +2 -0
  128. data/tasks/thor/app.rb +15 -10
  129. data/tasks/thor/example.rb +115 -115
  130. data/tasks/thor/templates/generator/empty_app/.gitignore +2 -0
  131. data/tasks/thor/templates/generator/empty_app/docs/app.js +1 -0
  132. data/tasks/thor/templates/generator/empty_app/docs/styles.scss +3 -0
  133. metadata +50 -9
  134. data/lib/api_browser/app/css/main.css +0 -4511
  135. data/lib/praxis/types/collection.rb +0 -17
@@ -12,7 +12,7 @@
12
12
  <p ng-repeat="url in action.urls">
13
13
  {{ url.verb }} {{ url.path }}
14
14
  </p>
15
- <p>{{ action.description }}</p>
15
+ <p ng-bind-html="action.description | markdown"></p>
16
16
  </div>
17
17
  </div>
18
18
 
@@ -65,7 +65,7 @@
65
65
  {{response.name}}
66
66
  </td>
67
67
  <td>
68
- {{response.media_type.name || response.media_type.identifier}}
68
+ {{response.media_type.id || response.media_type.identifier}}
69
69
  </td>
70
70
  <td>
71
71
  <rs-attribute-description attribute="response"></rs-attribute-description>
@@ -7,9 +7,9 @@
7
7
  <div class="row">
8
8
  <div class="col-lg-12">
9
9
  <h1 class="page-header">
10
- {{ controllerName | resourceName }}
10
+ {{ controller.name | resourceName }}
11
11
  </h1>
12
- <p>{{ controller.description }}</p>
12
+ <p ng-bind-html="controller.description | markdown"></p>
13
13
  </div>
14
14
  </div>
15
15
  <div class="row" ng-if="controller.actions.length">
@@ -1,2 +1,2 @@
1
- {{attribute.description}}
1
+ <p ng-bind-html="attribute.description | markdown"></p>
2
2
  <dl></dl>
@@ -1,19 +1,10 @@
1
1
  <!-- layout -->
2
-
3
- <div class="header">
4
- <div class="navbar navbar-default navbar-fixed-top" role="navigation">
5
- <div class="container">
6
- <div class="navbar-header">
7
- <a class="navbar-brand" href="#">API Browser</a>
8
- </div>
9
- </div>
10
- </div>
11
- </div>
2
+ <ng-include src="'views/navbar.html'"></ng-include>
12
3
 
13
4
  <div class="container" ng-cloak>
14
5
  <div class="row">
15
6
  <div class="col-sm-3" ng-controller="MenuCtrl">
16
- <div class="sidebar affix">
7
+ <div class="sidebar">
17
8
  <div class="row">
18
9
  <div class="col-sm-12">
19
10
  <p>
@@ -0,0 +1,9 @@
1
+ <div class="header">
2
+ <div class="navbar navbar-default navbar-fixed-top" role="navigation">
3
+ <div class="container">
4
+ <div class="navbar-header">
5
+ <a class="navbar-brand" href="#">API Browser</a>
6
+ </div>
7
+ </div>
8
+ </div>
9
+ </div>
@@ -19,7 +19,7 @@
19
19
  </div>
20
20
  </td>
21
21
  <td style="font-size: 110%;">
22
- {{ action.description }}
22
+ <p ng-bind-html="action.description | markdown"></p>
23
23
  </td>
24
24
  </tr>
25
25
  </tbody>
@@ -7,7 +7,7 @@
7
7
  <div class="row">
8
8
  <div class="col-lg-12">
9
9
  <h1>
10
- {{ typeName | resourceName }}
10
+ {{ type.name | resourceName }}
11
11
  </h1>
12
12
  </div>
13
13
  </div>
@@ -16,7 +16,7 @@
16
16
  <h3>Served by</h3>
17
17
  <ul>
18
18
  <li ng-repeat="controller in controllers">
19
- <a ui-sref="root.controller({version: apiVersion, controller: controller.controller})">{{ controller.controller | resourceName }}</a>
19
+ <a ui-sref="root.controller({version: apiVersion, controller: controller.controller})">{{ controller.name | resourceName }}</a>
20
20
  </li>
21
21
  </ul>
22
22
  </div>
@@ -2,7 +2,8 @@
2
2
  <div class="col-lg-12">
3
3
  <h2>Media Type</h2>
4
4
  <p ng-if="type.identifier"><b>Identifier: {{ type.identifier }}</b></p>
5
- <p ng-if="type.description">{{type.description}}</p>
5
+ <p ng-if="type.description" ng-bind-html="type.description | markdown"></p>
6
+
6
7
  <rs-attribute-table attributes="type.attributes"></rs-attribute-table>
7
8
  </div>
8
9
  </div>
@@ -21,6 +21,11 @@
21
21
  "bootstrap-sass": "~3.0.2",
22
22
  "angular-ui-router": "~0.2.10",
23
23
  "angular-ui-bootstrap-bower": "~0.11.0",
24
+ "angular-sanitize": "~1.2.16",
25
+ "showdown": "~0.4.0",
24
26
  "angular-sanitize": "~1.2.16"
27
+ },
28
+ "devDependencies": {
29
+ "angular-mocks": "~1.2.6"
25
30
  }
26
31
  }
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "api_doc_browser",
3
- "version": "0.0.0",
4
- "description": "",
3
+ "version": "0.13.0",
4
+ "description": "Praxis API Browser app",
5
+ "repository": "https://github.com/rightscale/praxis",
6
+ "private": true,
5
7
  "scripts": {
6
- "test": "echo \"Error: no test specified\" && exit 1"
8
+ "test": "node_modules/.bin/grunt ci"
7
9
  },
8
10
  "author": "",
9
11
  "license": "BSD",
10
- "devDependencies": {
12
+ "dependencies": {
11
13
  "grunt": "~0.4.2",
12
14
  "grunt-angular-templates": "^0.5.5",
15
+ "grunt-cli": "^0.1.13",
13
16
  "grunt-contrib-clean": "^0.5.0",
14
17
  "grunt-contrib-concat": "^0.4.0",
15
18
  "grunt-contrib-connect": "^0.7.1",
@@ -20,11 +23,19 @@
20
23
  "grunt-file-blocks": "^0.3.0",
21
24
  "grunt-filerev": "^0.2.1",
22
25
  "grunt-ngmin": "0.0.3",
23
- "grunt-sass": "^0.12.1",
26
+ "grunt-sass": "^0.17.0",
24
27
  "grunt-usemin": "^2.1.1",
25
28
  "grunt-wiredep": "^1.7.0",
26
- "load-grunt-tasks": "^0.4.0",
27
- "requirejs": "^2.1.13",
29
+ "load-grunt-tasks": "^0.4.0"
30
+ },
31
+ "devDependencies": {
32
+ "grunt-contrib-jshint": "^0.11.0",
33
+ "grunt-karma": "^0.10.1",
34
+ "jasmine-core": "^2.2.0",
35
+ "karma": "^0.12.31",
36
+ "karma-jasmine": "^0.3.5",
37
+ "karma-phantomjs-launcher": "^0.1.4",
38
+ "quick_check": "^0.4.2",
28
39
  "time-grunt": "^0.3.1"
29
40
  }
30
41
  }
data/lib/praxis.rb CHANGED
@@ -28,6 +28,7 @@ end
28
28
  module Praxis
29
29
 
30
30
  autoload :ActionDefinition, 'praxis/action_definition'
31
+ autoload :ApiGeneralInfo, 'praxis/api_general_info'
31
32
  autoload :ApiDefinition, 'praxis/api_definition'
32
33
  autoload :Application, 'praxis/application'
33
34
  autoload :Bootloader, 'praxis/bootloader'
@@ -53,15 +54,19 @@ module Praxis
53
54
 
54
55
  autoload :Stats, 'praxis/stats'
55
56
  autoload :Notifications, 'praxis/notifications'
56
-
57
+
57
58
  autoload :RestfulDocGenerator, 'praxis/restful_doc_generator'
58
-
59
+
59
60
  # types
61
+ module Types
62
+ autoload :MediaTypeCommon, 'praxis/types/media_type_common'
63
+ end
64
+
60
65
  autoload :Links, 'praxis/links'
61
66
  autoload :MediaType, 'praxis/media_type'
62
67
  autoload :MediaTypeCollection, 'praxis/media_type_collection'
63
68
  autoload :Multipart, 'praxis/types/multipart'
64
- autoload :Collection, 'praxis/types/collection'
69
+ autoload :Collection, 'praxis/collection'
65
70
 
66
71
  autoload :MultipartParser, 'praxis/multipart/parser'
67
72
  autoload :MultipartPart, 'praxis/multipart/part'
@@ -21,7 +21,7 @@ module Praxis
21
21
  attr_reader :metadata
22
22
 
23
23
  class << self
24
- attr_accessor :doc_decorations
24
+ attr_accessor :doc_decorations
25
25
  end
26
26
 
27
27
  @doc_decorations = []
@@ -35,9 +35,10 @@ module Praxis
35
35
  @resource_definition = resource_definition
36
36
  @responses = Hash.new
37
37
  @metadata = Hash.new
38
+ @routes = []
38
39
 
39
40
  if (media_type = resource_definition.media_type)
40
- if media_type.kind_of?(Class) && media_type < Praxis::MediaType
41
+ if media_type.kind_of?(Class) && media_type < Praxis::Types::MediaTypeCommon
41
42
  @reference_media_type = media_type
42
43
  end
43
44
  end
@@ -104,13 +105,14 @@ module Praxis
104
105
  end
105
106
  end
106
107
 
107
- def headers(type=Attributor::Hash.of(key:String), **opts, &block)
108
+ def headers(type=nil, **opts, &block)
108
109
  return @headers unless block
109
110
  if @headers
110
111
  update_attribute(@headers, opts, block)
111
112
  else
113
+ type = Attributor::Hash.of(key:String) unless type
112
114
  @headers = create_attribute(type,
113
- dsl_compiler: HeadersDSLCompiler, case_insensitive_load: true,
115
+ dsl_compiler: HeadersDSLCompiler, case_insensitive_load: true,
114
116
  **opts, &block)
115
117
  end
116
118
  @precomputed_header_keys_for_rack = nil #clear memoized data
@@ -128,7 +130,7 @@ module Praxis
128
130
  end
129
131
  end
130
132
  end
131
-
133
+
132
134
 
133
135
  def routing(&block)
134
136
  routing_config = Skeletor::RestfulRoutingConfig.new(name, resource_definition, &block)
@@ -156,7 +158,9 @@ module Praxis
156
158
  # FIXME: change to :routes along with api browser
157
159
  hash[:urls] = routes.collect(&:describe)
158
160
  hash[:headers] = headers.describe if headers
159
- hash[:params] = params.describe if params
161
+ if params
162
+ hash[:params] = params_description
163
+ end
160
164
  hash[:payload] = payload.describe if payload
161
165
  hash[:responses] = responses.inject({}) do |memo, (response_name, response)|
162
166
  memo[response.name] = response.describe
@@ -168,6 +172,24 @@ module Praxis
168
172
  end
169
173
  end
170
174
 
175
+ def params_description
176
+ route_params = primary_route.path.
177
+ named_captures.
178
+ keys.
179
+ collect(&:to_sym)
180
+
181
+ desc = params.describe
182
+ desc[:type][:attributes].keys.each do |k|
183
+ source = if route_params.include? k
184
+ 'url'
185
+ else
186
+ 'query'
187
+ end
188
+ desc[:type][:attributes][k][:source] = source
189
+ end
190
+ desc
191
+ end
192
+
171
193
  def nodoc!
172
194
  metadata[:doc_visibility] = :none
173
195
  end
@@ -9,6 +9,7 @@ module Praxis
9
9
 
10
10
  attr_reader :traits
11
11
  attr_reader :responses
12
+ attr_reader :infos
12
13
 
13
14
  def self.define(&block)
14
15
  if block.arity == 0
@@ -18,10 +19,12 @@ module Praxis
18
19
  end
19
20
  end
20
21
 
21
-
22
22
  def initialize
23
23
  @responses = Hash.new
24
24
  @traits = Hash.new
25
+ @infos = Hash.new do |hash, version|
26
+ hash[version] = ApiGeneralInfo.new
27
+ end
25
28
  end
26
29
 
27
30
  def response_template(name, &block)
@@ -41,7 +44,32 @@ module Praxis
41
44
  self.traits[name] = block
42
45
  end
43
46
 
44
-
47
+ # Setting info to the nil version, means setting it for all versions (if they don't override them)
48
+ def info( version=nil, &block)
49
+ i = @infos[version]
50
+ i.instance_eval(&block)
51
+ i
52
+ end
53
+
54
+ def describe
55
+ global_info = @infos[nil].describe
56
+ data = Hash.new do |hash, version|
57
+ hash[version] = Hash.new
58
+ end
59
+ # Fill in the "info" portion
60
+ @infos.each do |version,info|
61
+ next unless version
62
+ info_hash = global_info.merge(info.describe)
63
+ [:name, :title].each do |attr|
64
+ raise "Error: API Global information for version '#{version}' does not have '#{attr}' defined. " unless info_hash.key? attr
65
+ end
66
+ data[version][:info] = info_hash
67
+ end
68
+
69
+ # Maybe report the traits?...or somehow the registered response_templates ...
70
+ data
71
+ end
72
+
45
73
  define do |api|
46
74
  api.response_template :ok do |media_type: |
47
75
  media_type media_type
@@ -0,0 +1,36 @@
1
+ module Praxis
2
+ class ApiGeneralInfo
3
+
4
+ def name(val=nil)
5
+ return @name unless val
6
+ @name = val
7
+ end
8
+
9
+ def title(val=nil)
10
+ return @title unless val
11
+ @title = val
12
+ end
13
+
14
+ def description(val=nil)
15
+ return @description unless val
16
+ @description = val
17
+ end
18
+
19
+ def base_path(val=nil)
20
+ return @base_path unless val
21
+ @base_path = val
22
+ end
23
+
24
+ def describe
25
+ hash = { schema_version: "1.0".freeze }
26
+
27
+ [:name, :title, :description, :base_path].each do |attr|
28
+ val = self.__send__(attr)
29
+ hash[attr] = val unless val.nil?
30
+ end
31
+ hash
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -114,6 +114,7 @@ module Praxis
114
114
 
115
115
  def run
116
116
  stages.each do |stage|
117
+ stage.setup!
117
118
  stage.run
118
119
  end
119
120
  end
@@ -0,0 +1,34 @@
1
+ module Praxis
2
+ class Collection < Attributor::Collection
3
+ include Types::MediaTypeCommon
4
+
5
+ def self.of(type)
6
+ if defined?(type::Collection)
7
+ return type::Collection
8
+ end
9
+
10
+ klass = super
11
+
12
+ if type < Praxis::Types::MediaTypeCommon
13
+ unless type.identifier.nil?
14
+ klass.identifier(type.identifier + ';type=collection')
15
+ end
16
+
17
+ type.const_set :Collection, klass
18
+ else
19
+ warn "DEPRECATION: Praxis::Collection.of() for non-MediaTypes will be unsupported in 1.0. Use Attributor::Collection.of() instead."
20
+ Attributor::Collection.of(type)
21
+ end
22
+
23
+ end
24
+
25
+ def self.member_type(type=nil)
26
+ unless type.nil?
27
+ @member_type = type
28
+ end
29
+
30
+ @member_type
31
+ end
32
+
33
+ end
34
+ end
@@ -22,6 +22,10 @@ module Praxis
22
22
  definition.controller = self
23
23
  Application.instance.controllers << self
24
24
  end
25
+
26
+ def id
27
+ self.name.gsub('::'.freeze,'-'.freeze)
28
+ end
25
29
  end
26
30
 
27
31
  def initialize(request, response=Responses::Ok.new)
@@ -29,5 +33,8 @@ module Praxis
29
33
  @response = response
30
34
  end
31
35
 
36
+ def definition
37
+ self.class.definition
38
+ end
32
39
  end
33
40
  end
@@ -43,6 +43,9 @@ module Praxis
43
43
  @stages << RequestStages::Validate.new(:validate, self)
44
44
  @stages << RequestStages::Action.new(:action, self)
45
45
  @stages << RequestStages::Response.new(:response, self)
46
+ @stages.each do |s|
47
+ s.setup!
48
+ end
46
49
  setup_deferred_callbacks!
47
50
  end
48
51