praxis 0.13.0 → 0.14.0

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 (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