praxis 0.16.1 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (399) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +2 -1
  5. data/CHANGELOG.md +41 -0
  6. data/CONTRIBUTING.md +3 -0
  7. data/lib/api_browser/Gruntfile.js +20 -4
  8. data/lib/api_browser/app/bower_components/angular-mocks/.bower.json +6 -6
  9. data/lib/api_browser/app/bower_components/angular-mocks/README.md +11 -5
  10. data/lib/api_browser/app/bower_components/angular-mocks/angular-mocks.js +475 -216
  11. data/lib/api_browser/app/bower_components/angular-mocks/bower.json +2 -2
  12. data/lib/api_browser/app/bower_components/angular-mocks/ngAnimateMock.js +2 -0
  13. data/lib/api_browser/app/bower_components/angular-mocks/ngMock.js +2 -0
  14. data/lib/api_browser/app/bower_components/angular-mocks/ngMockE2E.js +2 -0
  15. data/lib/api_browser/app/bower_components/angular-mocks/package.json +1 -1
  16. data/lib/api_browser/app/bower_components/angular-sanitize/.bower.json +8 -8
  17. data/lib/api_browser/app/bower_components/angular-sanitize/README.md +19 -5
  18. data/lib/api_browser/app/bower_components/angular-sanitize/angular-sanitize.js +186 -127
  19. data/lib/api_browser/app/bower_components/angular-sanitize/angular-sanitize.min.js +12 -10
  20. data/lib/api_browser/app/bower_components/angular-sanitize/angular-sanitize.min.js.map +3 -3
  21. data/lib/api_browser/app/bower_components/angular-sanitize/bower.json +3 -2
  22. data/lib/api_browser/app/bower_components/angular-sanitize/index.js +2 -0
  23. data/lib/api_browser/app/bower_components/angular-sanitize/package.json +26 -0
  24. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/.bower.json +15 -8
  25. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/bower.json +11 -3
  26. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap-csp.css +6 -0
  27. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap-tpls.js +1177 -453
  28. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap-tpls.min.js +4 -4
  29. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap.js +1066 -404
  30. data/lib/api_browser/app/bower_components/angular-ui-bootstrap-bower/ui-bootstrap.min.js +3 -3
  31. data/lib/api_browser/app/bower_components/angular-ui-router/.bower.json +5 -6
  32. data/lib/api_browser/app/bower_components/angular-ui-router/CHANGELOG.md +208 -3
  33. data/lib/api_browser/app/bower_components/angular-ui-router/CONTRIBUTING.md +65 -0
  34. data/lib/api_browser/app/bower_components/angular-ui-router/LICENSE +1 -1
  35. data/lib/api_browser/app/bower_components/angular-ui-router/README.md +36 -71
  36. data/lib/api_browser/app/bower_components/angular-ui-router/api/angular-ui-router.d.ts +126 -0
  37. data/lib/api_browser/app/bower_components/angular-ui-router/bower.json +1 -1
  38. data/lib/api_browser/app/bower_components/angular-ui-router/release/angular-ui-router.js +1902 -755
  39. data/lib/api_browser/app/bower_components/angular-ui-router/release/angular-ui-router.min.js +2 -2
  40. data/lib/api_browser/app/bower_components/angular-ui-router/src/common.js +69 -23
  41. data/lib/api_browser/app/bower_components/angular-ui-router/src/resolve.js +15 -5
  42. data/lib/api_browser/app/bower_components/angular-ui-router/src/state.js +556 -295
  43. data/lib/api_browser/app/bower_components/angular-ui-router/src/stateDirectives.js +101 -42
  44. data/lib/api_browser/app/bower_components/angular-ui-router/src/stateFilters.js +6 -2
  45. data/lib/api_browser/app/bower_components/angular-ui-router/src/templateFactory.js +2 -2
  46. data/lib/api_browser/app/bower_components/angular-ui-router/src/urlMatcherFactory.js +822 -97
  47. data/lib/api_browser/app/bower_components/angular-ui-router/src/urlRouter.js +274 -120
  48. data/lib/api_browser/app/bower_components/angular-ui-router/src/viewDirective.js +33 -20
  49. data/lib/api_browser/app/bower_components/angular-ui-router/src/viewScroll.js +1 -1
  50. data/lib/api_browser/app/bower_components/angular/.bower.json +5 -5
  51. data/lib/api_browser/app/bower_components/angular/README.md +2 -5
  52. data/lib/api_browser/app/bower_components/angular/angular-csp.css +5 -8
  53. data/lib/api_browser/app/bower_components/angular/angular.js +12975 -6996
  54. data/lib/api_browser/app/bower_components/angular/angular.min.js +285 -213
  55. data/lib/api_browser/app/bower_components/angular/angular.min.js.gzip +0 -0
  56. data/lib/api_browser/app/bower_components/angular/angular.min.js.map +3 -3
  57. data/lib/api_browser/app/bower_components/angular/bower.json +1 -1
  58. data/lib/api_browser/app/bower_components/angular/index.js +2 -0
  59. data/lib/api_browser/app/bower_components/angular/package.json +2 -2
  60. data/lib/api_browser/app/bower_components/bootstrap-sass/.bower.json +31 -16
  61. data/lib/api_browser/app/bower_components/bootstrap-sass/CHANGELOG.md +108 -0
  62. data/lib/api_browser/app/bower_components/bootstrap-sass/CONTRIBUTING.md +55 -37
  63. data/lib/api_browser/app/bower_components/bootstrap-sass/README.md +147 -206
  64. data/lib/api_browser/app/bower_components/bootstrap-sass/bower.json +19 -8
  65. data/lib/api_browser/app/bower_components/bootstrap-sass/{dist/fonts → vendor/assets/fonts/bootstrap}/glyphicons-halflings-regular.eot +0 -0
  66. data/lib/api_browser/app/bower_components/bootstrap-sass/{dist/fonts → vendor/assets/fonts/bootstrap}/glyphicons-halflings-regular.svg +0 -0
  67. data/lib/api_browser/app/bower_components/bootstrap-sass/{dist/fonts → vendor/assets/fonts/bootstrap}/glyphicons-halflings-regular.ttf +0 -0
  68. data/lib/api_browser/app/bower_components/bootstrap-sass/{dist/fonts → vendor/assets/fonts/bootstrap}/glyphicons-halflings-regular.woff +0 -0
  69. data/lib/api_browser/app/bower_components/bootstrap-sass/vendor/assets/javascripts/bootstrap.js +12 -0
  70. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/affix.js +1 -1
  71. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/alert.js +1 -1
  72. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/button.js +11 -5
  73. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/carousel.js +5 -5
  74. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/collapse.js +1 -1
  75. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/dropdown.js +5 -5
  76. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/modal.js +1 -1
  77. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/popover.js +1 -1
  78. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/scrollspy.js +2 -2
  79. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/tab.js +1 -1
  80. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/tooltip.js +1 -1
  81. data/lib/api_browser/app/bower_components/bootstrap-sass/{js → vendor/assets/javascripts/bootstrap}/transition.js +1 -1
  82. data/lib/api_browser/app/bower_components/bootstrap-sass/vendor/assets/stylesheets/bootstrap.scss +1 -0
  83. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_alerts.scss +0 -0
  84. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_badges.scss +6 -6
  85. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_breadcrumbs.scss +0 -0
  86. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_button-groups.scss +7 -33
  87. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_buttons.scss +2 -5
  88. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_carousel.scss +1 -0
  89. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_close.scss +0 -0
  90. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_code.scss +0 -0
  91. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_component-animations.scss +0 -0
  92. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_dropdowns.scss +3 -8
  93. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_forms.scss +11 -0
  94. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_glyphicons.scss +5 -5
  95. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_grid.scss +12 -26
  96. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_input-groups.scss +1 -1
  97. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_jumbotron.scss +8 -2
  98. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_labels.scss +6 -0
  99. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_list-group.scss +0 -0
  100. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_media.scss +0 -0
  101. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_mixins.scss +38 -51
  102. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_modals.scss +2 -5
  103. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_navbar.scss +41 -53
  104. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_navs.scss +0 -20
  105. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_normalize.scss +0 -0
  106. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_pager.scss +0 -0
  107. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_pagination.scss +0 -0
  108. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_panels.scss +11 -1
  109. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_popovers.scss +0 -0
  110. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_print.scss +0 -0
  111. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_progress-bars.scss +0 -12
  112. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_responsive-utilities.scss +0 -0
  113. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_scaffolding.scss +0 -0
  114. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_tables.scss +5 -18
  115. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_theme.scss +2 -2
  116. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_thumbnails.scss +9 -3
  117. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_tooltip.scss +0 -0
  118. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_type.scss +54 -52
  119. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_utilities.scss +0 -0
  120. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_variables.scss +20 -11
  121. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/_wells.scss +0 -0
  122. data/lib/api_browser/app/bower_components/bootstrap-sass/{lib → vendor/assets/stylesheets/bootstrap}/bootstrap.scss +0 -0
  123. data/lib/api_browser/app/bower_components/lodash/.bower.json +9 -13
  124. data/lib/api_browser/app/bower_components/lodash/LICENSE.txt +3 -3
  125. data/lib/api_browser/app/bower_components/lodash/bower.json +4 -7
  126. data/lib/api_browser/app/bower_components/lodash/lodash.js +12235 -0
  127. data/lib/api_browser/app/bower_components/lodash/lodash.min.js +98 -0
  128. data/lib/api_browser/app/index.html +0 -1
  129. data/lib/api_browser/app/js/app.js +2 -5
  130. data/lib/api_browser/app/js/controllers/action.js +21 -37
  131. data/lib/api_browser/app/js/controllers/controller.js +23 -1
  132. data/lib/api_browser/app/js/controllers/menu.js +46 -14
  133. data/lib/api_browser/app/js/controllers/type.js +2 -9
  134. data/lib/api_browser/app/js/directives/attribute_description.js +15 -5
  135. data/lib/api_browser/app/js/directives/attribute_table.js +6 -6
  136. data/lib/api_browser/app/js/directives/fixed_if_fits.js +20 -0
  137. data/lib/api_browser/app/js/directives/no_container.js +6 -6
  138. data/lib/api_browser/app/js/directives/type_placeholder.js +21 -0
  139. data/lib/api_browser/app/js/factories/Configuration.js +13 -0
  140. data/lib/api_browser/app/js/factories/Documentation.js +0 -3
  141. data/lib/api_browser/app/js/factories/normalize_attributes.js +19 -0
  142. data/lib/api_browser/app/js/factories/template_for.js +113 -0
  143. data/lib/api_browser/app/sass/modules/_body.scss +26 -4
  144. data/lib/api_browser/app/sass/modules/_sidebar.scss +68 -1
  145. data/lib/api_browser/app/sass/praxis.scss +1 -5
  146. data/lib/api_browser/app/sass/variables/_bootstrap-variables.scss +13 -4
  147. data/lib/api_browser/app/views/action.html +13 -17
  148. data/lib/api_browser/app/views/controller.html +32 -4
  149. data/lib/api_browser/app/views/directives/attribute_description.html +1 -1
  150. data/lib/api_browser/app/views/directives/attribute_description/{_default.html → default.html} +0 -0
  151. data/lib/api_browser/app/views/directives/attribute_description/example.html +13 -0
  152. data/lib/api_browser/app/views/directives/attribute_description/headers.html +8 -0
  153. data/lib/api_browser/app/views/directives/attribute_description/member_options.html +4 -0
  154. data/lib/api_browser/app/views/directives/attribute_description/values.html +14 -0
  155. data/lib/api_browser/app/views/directives/attribute_table.html +2 -2
  156. data/lib/api_browser/app/views/home.html +1 -3
  157. data/lib/api_browser/app/views/layout.html +3 -36
  158. data/lib/api_browser/app/views/menu.html +45 -0
  159. data/lib/api_browser/app/views/navbar.html +1 -1
  160. data/lib/api_browser/app/views/type.html +2 -2
  161. data/lib/api_browser/app/views/type/{_details.html → details.html} +6 -6
  162. data/lib/api_browser/app/views/types/embedded/default.html +10 -0
  163. data/lib/api_browser/app/views/types/embedded/links.html +11 -0
  164. data/lib/api_browser/app/views/types/embedded/struct.html +2 -0
  165. data/lib/api_browser/app/views/types/label/link.html +1 -0
  166. data/lib/api_browser/app/views/types/label/primitive.html +1 -0
  167. data/lib/api_browser/app/views/types/label/primitive_collection.html +1 -0
  168. data/lib/api_browser/app/views/types/label/type.html +1 -0
  169. data/lib/api_browser/app/views/types/label/type_collection.html +1 -0
  170. data/lib/api_browser/app/views/{directives/request_body/_default.html → types/standalone/default.html} +1 -1
  171. data/lib/api_browser/app/views/types/standalone/struct.html +1 -0
  172. data/lib/api_browser/bower.json +9 -9
  173. data/lib/api_browser/package.json +1 -1
  174. data/lib/praxis.rb +10 -4
  175. data/lib/praxis/action_definition.rb +16 -4
  176. data/lib/praxis/action_definition/headers_dsl_compiler.rb +5 -2
  177. data/lib/praxis/api_definition.rb +3 -1
  178. data/lib/praxis/api_general_info.rb +49 -5
  179. data/lib/praxis/application.rb +12 -4
  180. data/lib/praxis/bootloader.rb +1 -0
  181. data/lib/praxis/bootloader_stages/environment.rb +2 -0
  182. data/lib/praxis/bootloader_stages/routing.rb +1 -1
  183. data/lib/praxis/bootloader_stages/subgroup_loader.rb +1 -0
  184. data/lib/praxis/exceptions/validation.rb +7 -0
  185. data/lib/praxis/handlers/plain.rb +16 -0
  186. data/lib/praxis/handlers/xml.rb +4 -4
  187. data/lib/praxis/links.rb +13 -3
  188. data/lib/praxis/media_type_identifier.rb +3 -0
  189. data/lib/praxis/multipart/parser.rb +41 -48
  190. data/lib/praxis/multipart/part.rb +196 -3
  191. data/lib/praxis/request.rb +14 -11
  192. data/lib/praxis/request_stages/request_stage.rb +4 -0
  193. data/lib/praxis/request_stages/response.rb +10 -9
  194. data/lib/praxis/request_stages/validate.rb +1 -7
  195. data/lib/praxis/request_stages/validate_params_and_headers.rb +30 -5
  196. data/lib/praxis/request_stages/validate_payload.rb +14 -5
  197. data/lib/praxis/resource_definition.rb +117 -15
  198. data/lib/praxis/response.rb +6 -5
  199. data/lib/praxis/response_definition.rb +51 -5
  200. data/lib/praxis/responses/http.rb +5 -0
  201. data/lib/praxis/responses/multipart_ok.rb +51 -0
  202. data/lib/praxis/responses/validation_error.rb +7 -7
  203. data/lib/praxis/restful_doc_generator.rb +9 -4
  204. data/lib/praxis/route.rb +3 -2
  205. data/lib/praxis/router.rb +26 -16
  206. data/lib/praxis/router/rack.rb +51 -0
  207. data/lib/praxis/router/simple.rb +146 -0
  208. data/lib/praxis/routing_config.rb +2 -2
  209. data/lib/praxis/trait.rb +1 -1
  210. data/lib/praxis/types/fuzzy_hash.rb +49 -0
  211. data/lib/praxis/types/media_type_common.rb +1 -1
  212. data/lib/praxis/types/multipart.rb +47 -12
  213. data/lib/praxis/types/multipart_array.rb +320 -0
  214. data/lib/praxis/types/multipart_array/part_definition.rb +52 -0
  215. data/lib/praxis/validation_handler.rb +10 -0
  216. data/lib/praxis/version.rb +2 -2
  217. data/praxis.gemspec +3 -3
  218. data/spec/api_browser/directives/type_placeholder_spec.js +134 -0
  219. data/spec/api_browser/factories/normalize_attributes_spec.js +97 -0
  220. data/spec/api_browser/factories/template_for_spec.js +67 -0
  221. data/spec/functional_spec.rb +111 -45
  222. data/spec/praxis/action_definition_spec.rb +31 -7
  223. data/spec/praxis/api_definition_spec.rb +2 -2
  224. data/spec/praxis/api_general_info_spec.rb +25 -0
  225. data/spec/praxis/application_spec.rb +24 -11
  226. data/spec/praxis/handlers/xml_spec.rb +55 -33
  227. data/spec/praxis/links_spec.rb +18 -1
  228. data/spec/praxis/media_type_collection_spec.rb +1 -1
  229. data/spec/praxis/media_type_spec.rb +2 -2
  230. data/spec/praxis/multipart/parser_spec.rb +21 -13
  231. data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +1 -1
  232. data/spec/praxis/request_spec.rb +52 -24
  233. data/spec/praxis/{request_stages_action_spec.rb → request_stages/action_spec.rb} +1 -1
  234. data/spec/praxis/{request_stage_spec.rb → request_stages/request_stage_spec.rb} +0 -0
  235. data/spec/praxis/{request_stages_validate_spec.rb → request_stages/validate_spec.rb} +1 -1
  236. data/spec/praxis/resource_definition_spec.rb +30 -4
  237. data/spec/praxis/response_definition_spec.rb +60 -19
  238. data/spec/praxis/response_spec.rb +2 -2
  239. data/spec/praxis/responses/validation_error_spec.rb +33 -16
  240. data/spec/praxis/route_spec.rb +4 -2
  241. data/spec/praxis/router_spec.rb +28 -12
  242. data/spec/praxis/routing_config_spec.rb +11 -5
  243. data/spec/praxis/types/collection_spec.rb +1 -1
  244. data/spec/praxis/types/fuzzy_hash_spec.rb +20 -0
  245. data/spec/praxis/types/multipart_array/part_definition_spec.rb +5 -0
  246. data/spec/praxis/types/multipart_array_spec.rb +334 -0
  247. data/spec/praxis/types/multipart_spec.rb +14 -5
  248. data/spec/spec_app/app/controllers/instances.rb +20 -10
  249. data/spec/spec_app/app/controllers/volumes.rb +8 -4
  250. data/spec/spec_app/app/responses/bulk_response.rb +0 -6
  251. data/spec/spec_app/config/environment.rb +13 -0
  252. data/spec/spec_app/design/api.rb +7 -10
  253. data/spec/spec_app/design/media_types/instance.rb +3 -1
  254. data/spec/spec_app/design/resources/instances.rb +50 -41
  255. data/spec/spec_app/design/resources/volume_snapshots.rb +39 -0
  256. data/spec/spec_app/design/resources/volumes.rb +11 -6
  257. data/spec/spec_helper.rb +3 -1
  258. metadata +125 -218
  259. data/lib/api_browser/app/bower_components/angular-ui-router/src/compat.js +0 -146
  260. data/lib/api_browser/app/bower_components/bootstrap-sass/CNAME +0 -1
  261. data/lib/api_browser/app/bower_components/bootstrap-sass/DOCS-LICENSE +0 -319
  262. data/lib/api_browser/app/bower_components/bootstrap-sass/Gemfile +0 -5
  263. data/lib/api_browser/app/bower_components/bootstrap-sass/Gemfile.lock +0 -14
  264. data/lib/api_browser/app/bower_components/bootstrap-sass/Gruntfile.js +0 -244
  265. data/lib/api_browser/app/bower_components/bootstrap-sass/LICENSE +0 -176
  266. data/lib/api_browser/app/bower_components/bootstrap-sass/LICENSE-MIT +0 -21
  267. data/lib/api_browser/app/bower_components/bootstrap-sass/Rakefile +0 -44
  268. data/lib/api_browser/app/bower_components/bootstrap-sass/_config.yml +0 -25
  269. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/ads.html +0 -1
  270. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/footer.html +0 -34
  271. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/header.html +0 -42
  272. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-about.html +0 -12
  273. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-components.html +0 -137
  274. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-css.html +0 -99
  275. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-customize.html +0 -40
  276. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-getting-started.html +0 -44
  277. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-javascript.html +0 -88
  278. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/nav-main.html +0 -37
  279. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/old-bs-docs.html +0 -8
  280. data/lib/api_browser/app/bower_components/bootstrap-sass/_includes/social-buttons.html +0 -16
  281. data/lib/api_browser/app/bower_components/bootstrap-sass/_layouts/default.html +0 -79
  282. data/lib/api_browser/app/bower_components/bootstrap-sass/_layouts/home.html +0 -47
  283. data/lib/api_browser/app/bower_components/bootstrap-sass/about.html +0 -93
  284. data/lib/api_browser/app/bower_components/bootstrap-sass/browserstack.json +0 -37
  285. data/lib/api_browser/app/bower_components/bootstrap-sass/components.html +0 -3689
  286. data/lib/api_browser/app/bower_components/bootstrap-sass/composer.json +0 -28
  287. data/lib/api_browser/app/bower_components/bootstrap-sass/css.html +0 -2674
  288. data/lib/api_browser/app/bower_components/bootstrap-sass/customize.html +0 -1715
  289. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap-theme.css +0 -427
  290. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap-theme.min.css +0 -1
  291. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap.css +0 -6350
  292. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/css/bootstrap.min.css +0 -1
  293. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/js/bootstrap.js +0 -2002
  294. data/lib/api_browser/app/bower_components/bootstrap-sass/dist/js/bootstrap.min.js +0 -9
  295. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/css/docs.css +0 -1195
  296. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/css/pygments-manni.css +0 -66
  297. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  298. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/ico/favicon.png +0 -0
  299. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/application.js +0 -103
  300. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/customizer.js +0 -332
  301. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/filesaver.js +0 -169
  302. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/holder.js +0 -404
  303. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/ie8-responsive-file-warning.js +0 -12
  304. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/jszip.js +0 -1467
  305. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/less.js +0 -9
  306. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/raw-files.js +0 -3
  307. data/lib/api_browser/app/bower_components/bootstrap-sass/docs-assets/js/uglify.js +0 -14
  308. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/carousel/carousel.css +0 -148
  309. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/carousel/index.html +0 -206
  310. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/grid/grid.css +0 -28
  311. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/grid/index.html +0 -148
  312. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron-narrow/index.html +0 -82
  313. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron-narrow/jumbotron-narrow.css +0 -79
  314. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron/index.html +0 -99
  315. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/jumbotron/jumbotron.css +0 -5
  316. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/justified-nav/index.html +0 -83
  317. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/justified-nav/justified-nav.css +0 -88
  318. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-fixed-top/index.html +0 -91
  319. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-fixed-top/navbar-fixed-top.css +0 -4
  320. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-static-top/index.html +0 -92
  321. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar-static-top/navbar-static-top.css +0 -7
  322. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar/index.html +0 -88
  323. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/navbar/navbar.css +0 -8
  324. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/non-responsive/index.html +0 -101
  325. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/non-responsive/non-responsive.css +0 -116
  326. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/offcanvas/index.html +0 -130
  327. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/offcanvas/offcanvas.css +0 -50
  328. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/offcanvas/offcanvas.js +0 -5
  329. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/carousel.jpg +0 -0
  330. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/grid.jpg +0 -0
  331. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/jumbotron-narrow.jpg +0 -0
  332. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/jumbotron.jpg +0 -0
  333. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/justified-nav.jpg +0 -0
  334. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/navbar-fixed.jpg +0 -0
  335. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/navbar-static.jpg +0 -0
  336. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/navbar.jpg +0 -0
  337. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/non-responsive.jpg +0 -0
  338. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/offcanvas.jpg +0 -0
  339. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/sign-in.jpg +0 -0
  340. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/starter-template.jpg +0 -0
  341. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/sticky-footer-navbar.jpg +0 -0
  342. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/sticky-footer.jpg +0 -0
  343. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/screenshots/theme.jpg +0 -0
  344. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/signin/index.html +0 -50
  345. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/signin/signin.css +0 -40
  346. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/starter-template/index.html +0 -68
  347. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/starter-template/starter-template.css +0 -7
  348. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer-navbar/index.html +0 -91
  349. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer-navbar/sticky-footer-navbar.css +0 -45
  350. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer/index.html +0 -55
  351. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/sticky-footer/sticky-footer.css +0 -38
  352. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/theme/index.html +0 -384
  353. data/lib/api_browser/app/bower_components/bootstrap-sass/examples/theme/theme.css +0 -14
  354. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.eot +0 -0
  355. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.svg +0 -229
  356. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.ttf +0 -0
  357. data/lib/api_browser/app/bower_components/bootstrap-sass/fonts/glyphicons-halflings-regular.woff +0 -0
  358. data/lib/api_browser/app/bower_components/bootstrap-sass/getting-started.html +0 -1021
  359. data/lib/api_browser/app/bower_components/bootstrap-sass/index.html +0 -16
  360. data/lib/api_browser/app/bower_components/bootstrap-sass/javascript.html +0 -1983
  361. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/index.html +0 -52
  362. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/affix.js +0 -25
  363. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/alert.js +0 -62
  364. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/button.js +0 -116
  365. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/carousel.js +0 -87
  366. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/collapse.js +0 -164
  367. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/dropdown.js +0 -219
  368. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/modal.js +0 -196
  369. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/phantom.js +0 -69
  370. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/popover.js +0 -133
  371. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/scrollspy.js +0 -37
  372. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/tab.js +0 -86
  373. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/tooltip.js +0 -437
  374. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/unit/transition.js +0 -13
  375. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/vendor/jquery.js +0 -6
  376. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/vendor/qunit.css +0 -232
  377. data/lib/api_browser/app/bower_components/bootstrap-sass/js/tests/vendor/qunit.js +0 -1510
  378. data/lib/api_browser/app/bower_components/bootstrap-sass/package.json +0 -40
  379. data/lib/api_browser/app/bower_components/lodash/dist/lodash.compat.js +0 -7157
  380. data/lib/api_browser/app/bower_components/lodash/dist/lodash.compat.min.js +0 -61
  381. data/lib/api_browser/app/bower_components/lodash/dist/lodash.js +0 -6785
  382. data/lib/api_browser/app/bower_components/lodash/dist/lodash.min.js +0 -56
  383. data/lib/api_browser/app/bower_components/lodash/dist/lodash.underscore.js +0 -4979
  384. data/lib/api_browser/app/bower_components/lodash/dist/lodash.underscore.min.js +0 -39
  385. data/lib/api_browser/app/js/directives/attribute_table_row.js +0 -17
  386. data/lib/api_browser/app/js/directives/request_body.js +0 -25
  387. data/lib/api_browser/app/js/directives/request_headers.js +0 -17
  388. data/lib/api_browser/app/js/directives/request_parameters.js +0 -17
  389. data/lib/api_browser/app/js/directives/type_label.js +0 -52
  390. data/lib/api_browser/app/js/factories/PayloadTemplates.js +0 -10
  391. data/lib/api_browser/app/js/factories/TemplateProvider.js +0 -45
  392. data/lib/api_browser/app/js/factories/TypeTemplates.js +0 -11
  393. data/lib/api_browser/app/views/directives/attribute_description/_example.html +0 -13
  394. data/lib/api_browser/app/views/directives/attribute_description/_headers.html +0 -8
  395. data/lib/api_browser/app/views/directives/attribute_table_row/_default.html +0 -10
  396. data/lib/api_browser/app/views/directives/attribute_table_row/_links.html +0 -11
  397. data/lib/api_browser/app/views/directives/attribute_table_row/_struct.html +0 -2
  398. data/lib/api_browser/app/views/directives/request_body/_struct.html +0 -1
  399. data/lib/api_browser/app/views/resource/_actions.html +0 -27
@@ -0,0 +1,52 @@
1
+ module Praxis
2
+ module Types
3
+ class MultipartArray < Attributor::Collection
4
+ class PartDefinition
5
+
6
+ attr_accessor :payload_attribute
7
+ attr_accessor :headers_attribute
8
+ attr_accessor :filename_attribute
9
+
10
+
11
+ def initialize(&block)
12
+ self.instance_eval(&block)
13
+ end
14
+
15
+ def update_attribute(attribute, options, block)
16
+ attribute.options.merge!(options)
17
+ attribute.type.attributes(options, &block)
18
+ end
19
+
20
+ def create_attribute(type=Attributor::Struct, **opts, &block)
21
+ # TODO: how do we want to handle any referenced types?
22
+ return Attributor::Attribute.new(type, opts, &block)
23
+ end
24
+
25
+ def payload(type=Attributor::Struct, **opts, &block)
26
+ #return @payload if !block_given? && type == Attributor::Struct
27
+ @payload_attribute = create_attribute(type, **opts, &block)
28
+ end
29
+
30
+ def header(name, val=nil, **options)
31
+ block = proc { header(name, val, **options) }
32
+
33
+ if @headers_attribute
34
+ update_attribute(@headers_attribute, options, block)
35
+ else
36
+ type = Attributor::Hash.of(key: String)
37
+ @headers_attribute = create_attribute(type,
38
+ dsl_compiler: Praxis::ActionDefinition::HeadersDSLCompiler,
39
+ case_insensitive_load: false, # :(
40
+ allow_extra: true,
41
+ &block)
42
+ end
43
+ end
44
+
45
+ def filename(type=String, **opts)
46
+ @filename_attribute = create_attribute(type, **opts)
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,10 @@
1
+ module Praxis
2
+ class ValidationHandler
3
+
4
+ # Should return the Response to send back
5
+ def handle!(summary:, request:, stage:, errors: nil, exception: nil, **opts)
6
+ Responses::ValidationError.new(summary: summary, errors: errors, exception: exception, **opts)
7
+ end
8
+
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Praxis
2
- VERSION = '0.16.1'
3
- end
2
+ VERSION = '0.17.0'
3
+ end
data/praxis.gemspec CHANGED
@@ -24,9 +24,9 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'mustermann', '~> 0'
25
25
  spec.add_dependency 'activesupport', '>= 3'
26
26
  spec.add_dependency 'mime', '~> 0'
27
- spec.add_dependency 'praxis-mapper', '~> 3.4'
28
- spec.add_dependency 'praxis-blueprints', '~> 1.3'
29
- spec.add_dependency 'attributor', '~> 2.6'
27
+ spec.add_dependency 'praxis-mapper', '>= 4.0.0'
28
+ spec.add_dependency 'praxis-blueprints', '>= 2.0.0'
29
+ spec.add_dependency 'attributor', '>= 4.0.0'
30
30
  spec.add_dependency 'thor', '~> 0.18'
31
31
  spec.add_dependency 'terminal-table', '~> 1.4'
32
32
  spec.add_dependency 'harness', '~> 2'
@@ -0,0 +1,134 @@
1
+ describe('typePlaceholder', function() {
2
+ describe('basic operation', function() {
3
+ var $scope, element, spy, fakeTemplate;
4
+ beforeEach(angular.mock.module('PraxisDocBrowser', function($provide) {
5
+ spy = jasmine.createSpy('templateFor').and.callFake(function() {
6
+ return fakeTemplate();
7
+ });
8
+ $provide.value('templateFor', spy);
9
+ }));
10
+
11
+ beforeEach(inject(function($compile, $rootScope, $q) {
12
+ fakeTemplate = function() {
13
+ return $q.when($compile('<div>result = <span>{{type.name}}</div>'));
14
+ };
15
+ $scope = $rootScope.$new();
16
+ $scope.type = {name: 'test'};
17
+ element = $compile('<div><type-placeholder type=type template=embedded></type-placeholder></div>')($scope);
18
+ $scope.$apply();
19
+ }));
20
+
21
+ it('calls template for', function() {
22
+ expect(spy).toHaveBeenCalledWith($scope.type, 'embedded');
23
+ });
24
+
25
+ it('replaces itself', function() {
26
+ expect(element.text()).toEqual('result = test');
27
+ });
28
+ });
29
+
30
+ describe('actual rendering', function() {
31
+ var $scope, element;
32
+
33
+ function rowLooksLike(n, vals) {
34
+ return function() {
35
+ var row = element.find('table tr').eq(n).children();
36
+ _.each(vals, function(val, i) {
37
+ if (_.isString(val)) {
38
+ expect(row.eq(i).text()).toEqual(val);
39
+ } else {
40
+ expect(row.eq(i).text()).toMatch(val);
41
+ }
42
+ });
43
+ expect(row.length).toBe(vals.length);
44
+ };
45
+ }
46
+
47
+ beforeEach(angular.mock.module('PraxisDocBrowser'));
48
+
49
+ describe('standalone', function() {
50
+ beforeEach(inject(function($compile, $rootScope) {
51
+ $scope = $rootScope.$new();
52
+ $scope.type = { // TODO figure out how to exercise the entire app
53
+ name: 'Struct',
54
+ family: 'hash',
55
+ attributes: {
56
+ view: {
57
+ options: {
58
+ default: 'default',
59
+ example: '"default"'
60
+ },
61
+ type: {
62
+ name: 'String'
63
+ }
64
+ }
65
+ }
66
+ };
67
+ element = $compile('<div><type-placeholder type="type" template="standalone" details="type.attributes"></type-placeholder></div>')($scope);
68
+ $scope.$apply();
69
+ }));
70
+
71
+ it('renders out a table', function() {
72
+ expect(element.find('table').length).toBe(1);
73
+ });
74
+
75
+ it('displays table headings', rowLooksLike(0,
76
+ ['Attribute', 'Type', 'Description']
77
+ ));
78
+
79
+ it('displays an optional heading', rowLooksLike(1,
80
+ ['Optional']
81
+ ));
82
+
83
+ it('has a table row for the attribute', rowLooksLike(2,
84
+ ['view', 'String', /default.*default.*example.*"default"/mi]
85
+ ));
86
+ });
87
+
88
+ describe('embedded', function() {
89
+ var compile;
90
+ beforeEach(inject(function($compile, $rootScope) {
91
+ $scope = $rootScope.$new();
92
+ compile = $compile('<div><table><tr type-placeholder type="item.type" template="embedded" details="item" name="item.name"></tr></table></div>');
93
+ }));
94
+
95
+ describe('struct', function() {
96
+ beforeEach(function() {
97
+ $scope.item = { // TODO figure out how to exercise the entire app
98
+ type: {
99
+ name: 'Struct',
100
+ family: 'hash',
101
+ attributes: {
102
+ view: {
103
+ options: {
104
+ default: 'default',
105
+ example: '"default"'
106
+ },
107
+ type: {
108
+ name: 'String'
109
+ }
110
+ }
111
+ }
112
+ },
113
+ name: 'Test1',
114
+ description: 'Heading'
115
+ };
116
+ element = compile($scope);
117
+ $scope.$apply();
118
+ });
119
+
120
+ it('renders out a table', function() {
121
+ expect(element.find('table').length).toBe(1);
122
+ });
123
+
124
+ it('displays a row fow the type', rowLooksLike(0,
125
+ ['Test1', 'Struct', /Heading/]
126
+ ));
127
+
128
+ it('displays a row for the subattribute', rowLooksLike(1,
129
+ ['Test1.view', 'String', /default.*default.*example.*"default"/mi]
130
+ ));
131
+ });
132
+ });
133
+ });
134
+ });
@@ -0,0 +1,97 @@
1
+ describe('normalizeAttributes', function() {
2
+ var normalizeAttributes;
3
+ beforeEach(angular.mock.module('PraxisDocBrowser'));
4
+
5
+ beforeEach(inject(function($rootScope, $injector) {
6
+ normalizeAttributes = $injector.get('normalizeAttributes');
7
+ }));
8
+
9
+ var type = {
10
+ attributes: {
11
+ test1: {
12
+ values: ['Hello'],
13
+ irrelevantFlag: true
14
+ },
15
+ test2: {
16
+ type: {
17
+ attributes: {
18
+ test3: {
19
+ default: 'Yeah'
20
+ },
21
+ moreRecursive: {
22
+ type: {
23
+ attributes: {
24
+ test4: {}
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ },
32
+ example: {
33
+ test1: 'Hello',
34
+ test2: {
35
+ test3: 'Yeah',
36
+ moreRecursive: {
37
+ test4: 3
38
+ }
39
+ }
40
+ }
41
+ };
42
+
43
+ var expected = {
44
+ test1: {
45
+ options: {
46
+ values: ['Hello'],
47
+ example: '"Hello"'
48
+ }
49
+ },
50
+ test2: {
51
+ options: {
52
+ example: '{\n "test3": "Yeah",\n "moreRecursive": {\n "test4": 3\n }\n}'
53
+ },
54
+ type: {
55
+ attributes: {
56
+ test3: {
57
+ options: {
58
+ default: 'Yeah',
59
+ example: '"Yeah"'
60
+ }
61
+ },
62
+ moreRecursive: {
63
+ options: {
64
+ example: '{\n "test4": 3\n}'
65
+ },
66
+ type: {
67
+ attributes: {
68
+ test4: {
69
+ options: {
70
+ example: '3'
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ };
80
+
81
+ expected = (function wrap(obj) { // this will wrap each object in objectContaining
82
+ if (_.isObject(obj)) {
83
+ return jasmine.objectContaining(_.mapValues(obj, wrap));
84
+ }
85
+ return obj;
86
+ })(expected);
87
+
88
+
89
+ it('normalizes attributes into options recursively', function() {
90
+ normalizeAttributes(type, type.attributes);
91
+ expect(type.attributes).toEqual(expected);
92
+ });
93
+
94
+ it('doesn\'t include irrelevant options', function() {
95
+ expect(type.attributes.test1.options.irrelevantFlag).toBeUndefined();
96
+ });
97
+ });
@@ -0,0 +1,67 @@
1
+ describe('templateFor service', function() {
2
+ var $scope, templateFor, $http, customResolver;
3
+
4
+ beforeEach(angular.mock.module('PraxisDocBrowser'));
5
+
6
+ beforeEach(function() {
7
+ customResolver = function() {};
8
+ angular.module('PraxisDocBrowser').config(function(templateForProvider) {
9
+ templateForProvider.register(function($type, $family) {
10
+ return customResolver($type, $family);
11
+ });
12
+ });
13
+ });
14
+
15
+ beforeEach(inject(function($rootScope, $injector) {
16
+ $scope = $rootScope.$new();
17
+ $http = $injector.get('$http');
18
+ templateFor = $injector.get('templateFor');
19
+ }));
20
+
21
+ describe('default templates', function() {
22
+ beforeEach(inject(function($templateCache) {
23
+ $templateCache.put('views/types/standalone/struct.html', '<div>standalone -> Struct</div>');
24
+ $templateCache.put('views/types/standalone/default.html', '<div>standalone -> Default</div>');
25
+ $templateCache.put('views/types/embedded/links.html', '<div>embedded -> Links</div>');
26
+ $templateCache.put('views/types/embedded/struct.html', '<div>embedded -> Struct</div>');
27
+ $templateCache.put('views/types/embedded/default.html', '<div>embedded -> Default</div>');
28
+ }));
29
+ _.each(['standalone', 'embedded'], function(templateType) {
30
+ _.each([
31
+ {name: 'Struct', family: 'hash'},
32
+ {name: 'Links', family: 'hash'},
33
+ {name: 'Default', family: 'Numeric'}
34
+ ], function(type) {
35
+ it('resolve ' + templateType + ' ' + type.name, function() {
36
+ var result;
37
+ templateFor(type, templateType).then(function(template) {
38
+ result = template($scope);
39
+ });
40
+ $scope.$apply();
41
+ var name = templateType === 'standalone' && type.name === 'Links' ? 'Struct' : type.name;
42
+ expect(result.text().split(' -> ')).toEqual([templateType, name]);
43
+ });
44
+ });
45
+ });
46
+ });
47
+
48
+ describe('custom templates', function() {
49
+ var result;
50
+ beforeEach(inject(function($templateCache) {
51
+ $templateCache.put('views/mytype.html', '<div>custom</div>');
52
+ customResolver = jasmine.createSpy().and.returnValue('views/mytype.html');
53
+ templateFor({name: 'Custom', family: 'CustomFamily'}, true).then(function(template) {
54
+ result = template($scope);
55
+ });
56
+ $scope.$apply();
57
+ }));
58
+
59
+ it('calls the custom resolver', function() {
60
+ expect(customResolver).toHaveBeenCalledWith('Custom', 'CustomFamily');
61
+ });
62
+
63
+ it('returns the custom template', function() {
64
+ expect(result.text()).toEqual('custom');
65
+ });
66
+ });
67
+ });
@@ -12,12 +12,70 @@ describe 'Functional specs' do
12
12
 
13
13
  context 'with a valid request' do
14
14
  it 'is successful' do
15
- get '/clouds/1/instances?api_version=1.0', nil, 'global_session' => session
15
+ get '/api/clouds/1/instances?api_version=1.0', nil, 'global_session' => session
16
16
  expect(last_response.headers['Content-Type']).to(
17
17
  eq("application/vnd.acme.instance;type=collection"))
18
18
  end
19
19
  end
20
20
 
21
+ context 'with a path param that can not load' do
22
+ it 'returns a useful error' do
23
+ get '/api/clouds/invalid/instances?api_version=1.0', nil, 'global_session' => session
24
+
25
+ expect(last_response.status).to eq 400
26
+
27
+ response = JSON.parse(last_response.body)
28
+ expect(response['name']).to eq 'ValidationError'
29
+ expect(response['summary']).to eq 'Error loading params.'
30
+ expect(response['errors']).to match_array([/Error loading attribute \$\.params\.cloud_id/])
31
+ expect(response['cause']['name']).to eq 'ArgumentError'
32
+ end
33
+ end
34
+
35
+ context 'with a header that can not load' do
36
+ it 'returns a useful error' do
37
+ get '/api/clouds/1/instances?api_version=1.0', nil, 'global_session' => session, 'HTTP_ACCOUNT_ID' => 'invalid'
38
+
39
+ expect(last_response.status).to eq 400
40
+
41
+ response = JSON.parse(last_response.body)
42
+
43
+ expect(response['name']).to eq 'ValidationError'
44
+ expect(response['summary']).to eq 'Error loading headers.'
45
+ expect(response['errors']).to match_array([/Error loading attribute .*Account-Id"/])
46
+ expect(response['cause']['name']).to eq 'ArgumentError'
47
+ end
48
+ end
49
+
50
+ context 'with a param that is invalid' do
51
+ it 'returns a useful error' do
52
+ get '/api/clouds/-1/instances?api_version=1.0', nil, 'global_session' => session
53
+
54
+ expect(last_response.status).to eq 400
55
+
56
+ response = JSON.parse(last_response.body)
57
+
58
+ expect(response['name']).to eq 'ValidationError'
59
+ expect(response['summary']).to eq 'Error validating request data.'
60
+ expect(response['errors']).to match_array([/.*cloud_id.*is smaller than the allowed min/])
61
+ end
62
+
63
+ end
64
+
65
+ context 'with a header that is invalid' do
66
+ it 'returns a useful error' do
67
+ get '/api/clouds/1/instances?api_version=1.0', nil, 'global_session' => session, 'HTTP_ACCOUNT_ID' => '-1'
68
+
69
+ expect(last_response.status).to eq 400
70
+
71
+ response = JSON.parse(last_response.body)
72
+
73
+ expect(response['name']).to eq 'ValidationError'
74
+ expect(response['summary']).to eq 'Error validating request data.'
75
+ expect(response['errors']).to match_array([/.*headers.*Account-Id.*is smaller than the allowed min/])
76
+ end
77
+ end
78
+
21
79
  context 'with an incorrect response_content_type param' do
22
80
  around do |example|
23
81
  logger = app.logger
@@ -29,13 +87,13 @@ describe 'Functional specs' do
29
87
  end
30
88
 
31
89
  it 'fails to validate the response' do
32
- get '/clouds/1/instances?response_content_type=somejunk&api_version=1.0', nil, 'HTTP_FOO' => "bar", 'global_session' => session
90
+ get '/api/clouds/1/instances?response_content_type=somejunk&api_version=1.0', nil, 'HTTP_FOO' => "bar", 'global_session' => session
33
91
  expect(last_response.status).to eq(400)
34
92
  response = JSON.parse(last_response.body)
35
93
 
36
94
  expect(response['name']).to eq('ValidationError')
37
-
38
- expect(response["message"]).to match(/Bad Content-Type/)
95
+ expect(response['summary']).to eq("Error validating response")
96
+ expect(response['errors'].first).to match(/Bad Content-Type/)
39
97
  end
40
98
 
41
99
  context 'with response validation disabled' do
@@ -48,7 +106,7 @@ describe 'Functional specs' do
48
106
 
49
107
  it 'fails to validate the response' do
50
108
  expect {
51
- get '/clouds/1/instances?response_content_type=somejunk&api_version=1.0',nil, 'global_session' => session
109
+ get '/api/clouds/1/instances?response_content_type=somejunk&api_version=1.0',nil, 'global_session' => session
52
110
  }.to_not raise_error
53
111
  end
54
112
 
@@ -59,7 +117,7 @@ describe 'Functional specs' do
59
117
 
60
118
  it 'works' do
61
119
  the_body = StringIO.new("{}") # This is a funny, GET request expecting a body
62
- get '/clouds/1/instances/2?junk=foo&api_version=1.0', nil,'rack.input' => the_body,'CONTENT_TYPE' => "application/json", 'global_session' => session
120
+ get '/api/clouds/1/instances/2?junk=foo&api_version=1.0', nil,'rack.input' => the_body,'CONTENT_TYPE' => "application/json", 'global_session' => session
63
121
  expect(last_response.status).to eq(200)
64
122
  expected = {
65
123
  "cloud_id" => 1,
@@ -76,20 +134,20 @@ describe 'Functional specs' do
76
134
  expect(JSON.parse(last_response.body)).to eq(expected)
77
135
 
78
136
  headers = last_response.headers
79
- expect(headers['Content-Type']).to eq('application/vnd.acme.instance')
137
+ expect(headers['Content-Type']).to eq('application/json')
80
138
  expect(headers['Spec-Middleware']).to eq('used')
81
139
  expect(headers['Content-Length']).to eq(last_response.body.size.to_s)
82
140
  end
83
141
 
84
142
  it 'returns early when making the before filter break' do
85
- get '/clouds/1/instances/2?junk=foo&api_version=1.0&fail_filter=true', nil, 'global_session' => session
143
+ get '/api/clouds/1/instances/2?junk=foo&api_version=1.0&fail_filter=true', nil, 'global_session' => session
86
144
  expect(last_response.status).to eq(401)
87
145
  end
88
146
 
89
147
  context 'bulk_create multipart' do
90
148
 
91
149
  let(:instance) { Instance.example }
92
- let(:instance_json) { JSON.pretty_generate(instance.render(:create)) }
150
+ let(:instance_json) { JSON.pretty_generate(instance.render(view: :create)) }
93
151
 
94
152
  let(:form) do
95
153
  form_data = MIME::Multipart::FormData.new
@@ -102,13 +160,13 @@ describe 'Functional specs' do
102
160
  let(:body) { form.body.to_s }
103
161
 
104
162
  it 'works' do
105
-
106
- post '/clouds/1/instances?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
163
+ post '/api/clouds/1/instances?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
107
164
 
108
165
  _reponse_preamble, response = Praxis::MultipartParser.parse(last_response.headers, last_response.body)
109
166
  expect(response).to have(1).item
110
167
 
111
- response_id, instance_part = response.first
168
+ instance_part = response.first
169
+ response_id = instance_part.name
112
170
  expect(response_id).to eq(instance.id.to_s)
113
171
 
114
172
  instance_headers = instance_part.headers
@@ -117,7 +175,7 @@ describe 'Functional specs' do
117
175
 
118
176
  response_instance = JSON.parse(instance_part.body)
119
177
  expect(response_instance["key"]).to eq(instance.id)
120
- expect(response_instance["value"].values).to eq(instance.render(:create).values)
178
+ expect(response_instance["value"].values).to eq(instance.render(view: :create).values)
121
179
  end
122
180
  end
123
181
 
@@ -140,7 +198,7 @@ describe 'Functional specs' do
140
198
 
141
199
  context 'with a valid payload' do
142
200
  before do
143
- post '/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
201
+ post '/api/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
144
202
  end
145
203
 
146
204
  subject(:response) { JSON.parse(last_response.body) }
@@ -153,7 +211,7 @@ describe 'Functional specs' do
153
211
  its(['filename']) { should eq('docker') }
154
212
  its(['type']) { should eq('text/plain') }
155
213
  its(['name']) { should eq('file') }
156
- its(['tempfile']) { should match(/^\//) }
214
+ its(['tempfile']) { should eq('DOCKER_HOST=tcp://127.0.0.1:2375') }
157
215
  end
158
216
  end
159
217
 
@@ -170,7 +228,7 @@ describe 'Functional specs' do
170
228
  let(:body) { form.body.to_s }
171
229
 
172
230
  it 'returns an error' do
173
- post '/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
231
+ post '/api/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
174
232
  response = JSON.parse(last_response.body)
175
233
 
176
234
  expect(response['name']).to eq('ValidationError')
@@ -200,22 +258,19 @@ describe 'Functional specs' do
200
258
  subject(:response) { JSON.parse(last_response.body) }
201
259
 
202
260
  before do
203
- post '/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
261
+ post '/api/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
204
262
  end
205
263
  its(:keys){ should eq(['destination_path','file','options'])}
206
264
  its(['options']){ should eq({"extra_thing"=>"I am extra"})}
207
265
  end
208
266
 
209
-
210
-
211
-
212
267
  end
213
268
 
214
269
 
215
270
  context 'not found and API versions' do
216
271
  context 'when no version is speficied' do
217
272
  it 'it tells you which available api versions would match' do
218
- get '/clouds/1/instances/2?junk=foo',nil, 'global_session' => session
273
+ get '/api/clouds/1/instances/2?junk=foo',nil, 'global_session' => session
219
274
 
220
275
  expect(last_response.status).to eq(404)
221
276
  expect(last_response.headers["Content-Type"]).to eq("text/plain")
@@ -232,7 +287,7 @@ describe 'Functional specs' do
232
287
 
233
288
  context 'when some version is speficied, but wrong' do
234
289
  it 'it tells you which possible correcte api versions exist' do
235
- get '/clouds/1/instances/2?junk=foo&api_version=50.0', nil, 'global_session' => session
290
+ get '/api/clouds/1/instances/2?junk=foo&api_version=50.0', nil, 'global_session' => session
236
291
 
237
292
  expect(last_response.status).to eq(404)
238
293
  expect(last_response.headers["Content-Type"]).to eq("text/plain")
@@ -243,26 +298,26 @@ describe 'Functional specs' do
243
298
  end
244
299
 
245
300
  context 'volumes' do
301
+ before do
302
+ header 'X-Api-Version', '1.0'
303
+ end
304
+
246
305
  context 'when no authorization header is passed' do
247
306
  it 'works as expected' do
248
- get '/v1.0/volumes/123?junk=stuff', nil, 'global_session' => session
307
+ get '/api/clouds/1/volumes/123?junk=stuff', nil, 'global_session' => session
249
308
  expect(last_response.status).to eq(200)
250
- expect(JSON.parse(last_response.body)).to eq({"id"=>123,
251
- "other_params"=>{
252
- "junk"=>"stuff",
253
- "some_date"=>"2012-12-21T00:00:00+00:00"}
254
- })
309
+ expect(Volume.load(last_response.body).validate).to be_empty
255
310
  expect(last_response.headers["Content-Type"]).to eq("application/vnd.acme.volume")
256
311
  end
257
312
  end
258
313
  context 'when an authorization header is passed' do
259
314
  it 'returns 401 when it does not match "secret" ' do
260
- get '/v1.0/volumes/123?junk=stuff', nil, 'HTTP_AUTHORIZATION' => 'foobar', 'global_session' => session
315
+ get '/api/clouds/1/volumes/123?junk=stuff', nil, 'HTTP_AUTHORIZATION' => 'foobar', 'global_session' => session
261
316
  expect(last_response.status).to eq(401)
262
317
  expect(last_response.body).to match(/Authentication info is invalid/)
263
318
  end
264
319
  it 'succeeds as expected when it matches "secret" ' do
265
- get '/v1.0/volumes/123?junk=stuff', nil, 'HTTP_AUTHORIZATION' => 'the secret', 'global_session' => session
320
+ get '/api/clouds/1/volumes/123?junk=stuff', nil, 'HTTP_AUTHORIZATION' => 'the secret', 'global_session' => session
266
321
  expect(last_response.status).to eq(200)
267
322
  end
268
323
 
@@ -270,7 +325,7 @@ describe 'Functional specs' do
270
325
 
271
326
  context 'index action with no args defined' do
272
327
  it 'dispatches successfully' do
273
- get '/v1.0/volumes', nil, 'HTTP_AUTHORIZATION' => 'the secret', 'global_session' => session
328
+ get '/api/clouds/1/volumes', nil, 'HTTP_AUTHORIZATION' => 'the secret', 'global_session' => session
274
329
  expect(last_response.status).to eq(200)
275
330
  end
276
331
  end
@@ -278,11 +333,11 @@ describe 'Functional specs' do
278
333
 
279
334
  context 'wildcard verb routing' do
280
335
  it 'can terminate instances with POST' do
281
- post '/clouds/23/instances/1/terminate?api_version=1.0', nil, 'global_session' => session
336
+ post '/api/clouds/23/instances/1/terminate?api_version=1.0', nil, 'global_session' => session
282
337
  expect(last_response.status).to eq(200)
283
338
  end
284
339
  it 'can terminate instances with DELETE' do
285
- post '/clouds/23/instances/1/terminate?api_version=1.0', nil, 'global_session' => session
340
+ post '/api/clouds/23/instances/1/terminate?api_version=1.0', nil, 'global_session' => session
286
341
  expect(last_response.status).to eq(200)
287
342
  end
288
343
 
@@ -290,11 +345,11 @@ describe 'Functional specs' do
290
345
 
291
346
  context 'route options' do
292
347
  it 'reach the endpoint that does not match the except clause' do
293
- get '/clouds/23/otherinstances/_action/test?api_version=1.0', nil, 'global_session' => session
348
+ get '/api/clouds/23/otherinstances/_action/test?api_version=1.0', nil, 'global_session' => session
294
349
  expect(last_response.status).to eq(200)
295
350
  end
296
351
  it 'does NOT reach the endpoint that matches the except clause' do
297
- get '/clouds/23/otherinstances/_action/exceptional?api_version=1.0', nil, 'global_session' => session
352
+ get '/api/clouds/23/otherinstances/_action/exceptional?api_version=1.0', nil, 'global_session' => session
298
353
  expect(last_response.status).to eq(404)
299
354
  end
300
355
 
@@ -303,12 +358,12 @@ describe 'Functional specs' do
303
358
 
304
359
  context 'auth_plugin' do
305
360
  it 'can terminate' do
306
- post '/clouds/23/instances/1/terminate?api_version=1.0', nil, 'global_session' => session
361
+ post '/api/clouds/23/instances/1/terminate?api_version=1.0', nil, 'global_session' => session
307
362
  expect(last_response.status).to eq(200)
308
363
  end
309
364
 
310
365
  it 'can not stop' do
311
- post '/clouds/23/instances/1/stop?api_version=1.0', nil, 'global_session' => session
366
+ post '/api/clouds/23/instances/1/stop?api_version=1.0', nil, 'global_session' => session
312
367
  expect(last_response.status).to eq(403)
313
368
  end
314
369
  end
@@ -318,24 +373,24 @@ describe 'Functional specs' do
318
373
  let(:content_type) { 'application/x-www-form-urlencoded' }
319
374
 
320
375
  before do
321
- post '/clouds/1/instances/2/terminate?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
376
+ post '/api/clouds/1/instances/2/terminate?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
322
377
  end
323
378
 
324
379
  it 'returns a useful error message' do
325
380
  body = JSON.parse(last_response.body)
326
381
  expect(body['name']).to eq('ValidationError')
327
- expect(body['message']).to match("For request Content-Type: 'application/x-www-form-urlencoded'")
382
+ expect(body['summary']).to match("Error loading payload. Used Content-Type: 'application/x-www-form-urlencoded'")
383
+ expect(body['errors']).to_not be_empty
328
384
  end
329
385
  end
330
386
 
331
387
  context 'update' do
332
388
 
333
-
334
389
  let(:body) { JSON.pretty_generate(request_payload) }
335
390
  let(:content_type) { 'application/json' }
336
391
 
337
392
  before do
338
- patch '/clouds/1/instances/3?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
393
+ patch '/api/clouds/1/instances/3?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
339
394
  end
340
395
 
341
396
  subject(:response_body) { JSON.parse(last_response.body) }
@@ -348,17 +403,28 @@ describe 'Functional specs' do
348
403
  end
349
404
 
350
405
  context 'with a provided name' do
351
- let(:request_payload) { {name: 'My Instance'} }
352
- its(['name']) { should eq('My Instance') }
406
+ let(:request_payload) { {name: 'MyInstance'} }
407
+ its(['name']) { should eq('MyInstance') }
353
408
  it { should_not have_key('root_volume') }
354
409
  end
355
410
 
356
411
  context 'with an explicitly-nil root_volme' do
357
- let(:request_payload) { {name: 'My Instance', root_volume: nil} }
358
- its(['name']) { should eq('My Instance') }
412
+ let(:request_payload) { {name: 'MyInstance', root_volume: nil} }
413
+ its(['name']) { should eq('MyInstance') }
359
414
  its(['root_volume']) { should be(nil) }
360
415
  end
361
416
 
417
+ context 'with an invalid name' do
418
+ let(:request_payload) { {name: 'Invalid Name'} }
419
+
420
+ its(['name']) { should eq 'ValidationError' }
421
+ its(['summary']) { should eq 'Error validating response' }
422
+ its(['errors']) { should match_array [/\$\.name value \(Invalid Name\) does not match regexp/] }
423
+
424
+ it 'returns a validation error' do
425
+ expect(last_response.status).to eq(400)
426
+ end
427
+ end
362
428
 
363
429
  end
364
430