textualize 0.1.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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +3 -0
  6. data/CODE_OF_CONDUCT.md +28 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +1 -0
  9. data/README.md +76 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +7 -0
  12. data/bin/textualize +7 -0
  13. data/circle.yml +8 -0
  14. data/lib/textualize.rb +33 -0
  15. data/lib/textualize/tasks/helpers/route_hash_creator.rb +62 -0
  16. data/lib/textualize/tasks/helpers/route_hashes.rb +21 -0
  17. data/lib/textualize/tasks/helpers/transformers/two_hundred.rb +30 -0
  18. data/lib/textualize/tasks/helpers/transformers/two_hundred_four.rb +17 -0
  19. data/lib/textualize/tasks/http_backend.rb +59 -0
  20. data/lib/textualize/tasks/new.rb +44 -0
  21. data/lib/textualize/tasks/request_specs.rb +48 -0
  22. data/lib/textualize/tasks/server.rb +35 -0
  23. data/lib/textualize/templates/http_backend/delete.js.erb +10 -0
  24. data/lib/textualize/templates/http_backend/get.js.erb +10 -0
  25. data/lib/textualize/templates/http_backend/module.js +1 -0
  26. data/lib/textualize/templates/http_backend/patch.js.erb +10 -0
  27. data/lib/textualize/templates/http_backend/post.js.erb +10 -0
  28. data/lib/textualize/templates/new/.gitignore +3 -0
  29. data/lib/textualize/templates/new/.ruby-version +1 -0
  30. data/lib/textualize/templates/new/Gemfile +5 -0
  31. data/lib/textualize/templates/new/Gemfile.lock +28 -0
  32. data/lib/textualize/templates/new/Readme.md +10 -0
  33. data/lib/textualize/templates/new/apis/base.raml +26 -0
  34. data/lib/textualize/templates/new/apis/base/routes/items.yaml +8 -0
  35. data/lib/textualize/templates/new/apis/base/routes/orders.yaml +8 -0
  36. data/lib/textualize/templates/new/apis/base/samples/item.json +12 -0
  37. data/lib/textualize/templates/new/apis/base/samples/items.json +34 -0
  38. data/lib/textualize/templates/new/apis/base/samples/order.json +43 -0
  39. data/lib/textualize/templates/new/apis/base/samples/orders.json +70 -0
  40. data/lib/textualize/templates/new/apis/base/schemas/item.json +17 -0
  41. data/lib/textualize/templates/new/apis/base/schemas/order.json +25 -0
  42. data/lib/textualize/templates/new/apis/documentation/authentication.yaml +21 -0
  43. data/lib/textualize/templates/new/apis/documentation/http_statuses.md +26 -0
  44. data/lib/textualize/templates/new/apis/errors.yaml +6 -0
  45. data/lib/textualize/templates/new/apis/resourceTypes/collection-item-ro.yaml +20 -0
  46. data/lib/textualize/templates/new/apis/resourceTypes/collection-item.yaml +20 -0
  47. data/lib/textualize/templates/new/apis/resourceTypes/collection-ro.yaml +18 -0
  48. data/lib/textualize/templates/new/apis/resourceTypes/collection.yaml +18 -0
  49. data/lib/textualize/templates/new/apis/responses/200.yaml +3 -0
  50. data/lib/textualize/templates/new/apis/responses/204.yaml +1 -0
  51. data/lib/textualize/templates/new/apis/responses/400.yaml +8 -0
  52. data/lib/textualize/templates/new/apis/responses/401.yaml +4 -0
  53. data/lib/textualize/templates/new/apis/responses/403.yaml +4 -0
  54. data/lib/textualize/templates/new/apis/responses/404.yaml +4 -0
  55. data/lib/textualize/templates/new/apis/responses/422.yaml +8 -0
  56. data/lib/textualize/templates/new/apis/responses/500.yaml +4 -0
  57. data/lib/textualize/templates/new/gulpfile.js +93 -0
  58. data/lib/textualize/templates/new/package.json +38 -0
  59. data/lib/textualize/templates/new/server/api/v1/items/get.json +1 -0
  60. data/lib/textualize/templates/new/server/api/v1/items/{item_id}/get.json +1 -0
  61. data/lib/textualize/templates/new/server/api/v1/orders/get.json +1 -0
  62. data/lib/textualize/templates/new/server/api/v1/orders/{order_id}/get.json +1 -0
  63. data/lib/textualize/templates/request_specs/delete_collection-item.rb.erb +0 -0
  64. data/lib/textualize/templates/request_specs/get_collection-item.rb.erb +16 -0
  65. data/lib/textualize/templates/request_specs/get_collection.rb.erb +16 -0
  66. data/lib/textualize/templates/request_specs/patch_collection-item.rb.erb +0 -0
  67. data/lib/textualize/templates/request_specs/post_collection.rb.erb +13 -0
  68. data/lib/textualize/version.rb +3 -0
  69. data/sample_item.rb +43 -0
  70. data/textualize.gemspec +41 -0
  71. metadata +259 -0
@@ -0,0 +1,21 @@
1
+ description: |
2
+ OAuth2 is a protocol that lets external apps request authorization to private
3
+ details in a user's account without getting their password. This is preferred
4
+ over Basic Authentication because tokens can be limited to specific types of
5
+ data, and can be revoked by users at any time.
6
+ type: OAuth 2.0
7
+ describedBy:
8
+ headers:
9
+ Authorization:
10
+ description: Used to send a valid OAuth 2 access token.
11
+ type: string
12
+ responses:
13
+ 404:
14
+ description: Unauthorized
15
+ settings:
16
+ authorizationUri: https://app.my-awesome-restaurant.com/login/oauth/authorize
17
+ accessTokenUri: https://app.my-awesome-restaurant.com/login/oauth/access_token
18
+ authorizationGrants: [ code ]
19
+ scopes:
20
+ - "customer"
21
+ - "staff"
@@ -0,0 +1,26 @@
1
+ # HTTP Status Code Summary
2
+
3
+ We use conventional HTTP response codes to indicate success or failure of an
4
+ API request. In general, codes in the 2xx range indicate success, codes in the
5
+ 4xx range indicate an error that resulted from the provided information (e.g. a
6
+ required parameter was missing, a charge failed, etc.), and codes in the 5xx
7
+ range indicate an error with our servers.
8
+
9
+
10
+ | Code | Description |
11
+ |------------------------------------|-------------------------------------------|
12
+ | 200 - OK | Everything worked as expected. |
13
+ | 201 - Created | New resource being created |
14
+ | 400 - Bad Request | Often missing a required parameter. |
15
+ | 401 - Unauthorized | No valid API key provided. |
16
+ | 402 - Request Failed | Parameters were valid but request failed. |
17
+ | 404 - Not Found | The requested item doesn't exist. |
18
+ | 500, 502, 503, 504 - Server Errors | Something went wrong on our end. |
19
+
20
+ # Errors
21
+
22
+ | ATTRIBUTES | Description |
23
+ |--------------------|-----------------------------------------------------------------------------|
24
+ | code | The same as HTTP status code. This can help other clients are easy to read. |
25
+ | details (optional) | List of validation errors. ex: {name: [{error: :blank}]} |
26
+ | message (optional) | A human-readable message giving more details about the error. |
@@ -0,0 +1,6 @@
1
+ 400: !include ./responses/400.yaml
2
+ 401: !include ./responses/401.yaml
3
+ 403: !include ./responses/403.yaml
4
+ 404: !include ./responses/404.yaml
5
+ 422: !include ./responses/422.yaml
6
+ 500: !include ./responses/500.yaml
@@ -0,0 +1,20 @@
1
+ collection-item-ro:
2
+ description: Read only entity representing a <<resourcePathName|!singularize>>
3
+
4
+ get:
5
+ securedBy: [ oauth_2_0: { scopes: [ "customer", "staff" ] } ]
6
+ description: Get the <<resourcePathName|!singularize>> by ID
7
+ responses:
8
+ 200: !include ../responses/200.yaml
9
+
10
+ patch:
11
+ securedBy: [ oauth_2_0: { scopes: [ "staff" ] } ]
12
+ description: Update the <<resourcePathName|!singularize>> by ID
13
+ responses:
14
+ 204: !include ../responses/204.yaml
15
+
16
+ delete:
17
+ securedBy: [ oauth_2_0: { scopes: [ "staff" ] } ]
18
+ description: Remove the <<resourcePathName|!singularize>> by ID
19
+ responses:
20
+ 204: !include ../responses/204.yaml
@@ -0,0 +1,20 @@
1
+ collection-item:
2
+ description: Entity representing a <<resourcePathName|!singularize>>
3
+
4
+ get:
5
+ securedBy: [ oauth_2_0: { scopes: [ "customer", "staff" ] } ]
6
+ description: Get the <<resourcePathName|!singularize>> by ID
7
+ responses:
8
+ 200: !include ../responses/200.yaml
9
+
10
+ patch:
11
+ securedBy: [ oauth_2_0: { scopes: [ "customer", "staff" ] } ]
12
+ description: Update the <<resourcePathName|!singularize>> by ID
13
+ responses:
14
+ 204: !include ../responses/204.yaml
15
+
16
+ delete:
17
+ securedBy: [ oauth_2_0: { scopes: [ "customer", "staff" ] } ]
18
+ description: Remove the <<resourcePathName|!singularize>> by ID
19
+ responses:
20
+ 204: !include ../responses/204.yaml
@@ -0,0 +1,18 @@
1
+ collection-ro:
2
+ description: Read-only collection of available <<resourcePathName>>
3
+
4
+ get:
5
+ securedBy: [ oauth_2_0: { scopes: [ "staff" ] } ]
6
+ responses:
7
+ 200:
8
+ body:
9
+ application/json:
10
+ example: <<exampleCollection>>
11
+
12
+ post:
13
+ securedBy: [ oauth_2_0: { scopes: [ "staff" ] } ]
14
+ body:
15
+ application/json:
16
+ schema: <<resourcePathName|!singularize>>
17
+ responses:
18
+ 200: !include ../responses/200.yaml
@@ -0,0 +1,18 @@
1
+ collection:
2
+ description: Collection of available <<resourcePathName>>
3
+
4
+ get:
5
+ securedBy: [ oauth_2_0: { scopes: [ "customer", "staff" ] } ]
6
+ responses:
7
+ 200:
8
+ body:
9
+ application/json:
10
+ example: <<exampleCollection>>
11
+
12
+ post:
13
+ securedBy: [ oauth_2_0: { scopes: [ "customer", "staff" ] } ]
14
+ body:
15
+ application/json:
16
+ schema: <<resourcePathName|!singularize>>
17
+ responses:
18
+ 200: !include ../responses/200.yaml
@@ -0,0 +1,3 @@
1
+ body:
2
+ application/json:
3
+ example: <<exampleItem>>
@@ -0,0 +1 @@
1
+ description: Success (no body)
@@ -0,0 +1,8 @@
1
+ body:
2
+ application/json:
3
+ example: |
4
+ {
5
+ name: [
6
+ "has already been taken"
7
+ ]
8
+ }
@@ -0,0 +1,4 @@
1
+ body:
2
+ application/json:
3
+ example: |
4
+ { "message": "Unauthorized, please login" }
@@ -0,0 +1,4 @@
1
+ body:
2
+ application/json:
3
+ example: |
4
+ { "message": "Forbidden" }
@@ -0,0 +1,4 @@
1
+ body:
2
+ application/json:
3
+ example: |
4
+ { "message": "Not found" }
@@ -0,0 +1,8 @@
1
+ body:
2
+ application/json:
3
+ example: |
4
+ {
5
+ name: [
6
+ "parameter is required"
7
+ ]
8
+ }
@@ -0,0 +1,4 @@
1
+ body:
2
+ application/json:
3
+ example: |
4
+ { "message": "Server error" }
@@ -0,0 +1,93 @@
1
+ var gulp = require('gulp');
2
+
3
+ gulp.task('default', ['convert-raml-to-json'])
4
+
5
+ gulp.task('mkdir-src', function() {
6
+ var mkdirp = require('mkdirp')
7
+
8
+ mkdirp('./.tmp')
9
+
10
+ return gulp.src('./')
11
+ })
12
+
13
+ var raml = require('gulp-raml');
14
+ var debug = require('gulp-debug');
15
+
16
+ gulp.task('validate-raml', function() {
17
+ return gulp.src('apis/*.raml')
18
+
19
+ .pipe(debug({title: 'checking raml file: '}))
20
+ .pipe(raml())
21
+ .pipe(raml.reporter('default'))
22
+ .pipe(raml.reporter('fail'))
23
+ })
24
+
25
+ var notify = require('gulp-notify');
26
+ var concat = require('gulp-concat');
27
+ var yaml = require('gulp-yaml');
28
+
29
+ gulp.task('convert-raml-to-json', ['validate-raml'], function() {
30
+ return gulp.src('apis/*.raml', { base: './' })
31
+ .pipe(raml2json())
32
+ .pipe(gulp.dest('./.tmp'))
33
+ })
34
+
35
+ function raml2json(options) {
36
+ var path = require('path');
37
+ var gutil = require('gulp-util');
38
+ var through = require('through2');
39
+ var raml2html = require('raml2html');
40
+
41
+ var simplifyMark = function(mark) {
42
+ if (mark) {
43
+ mark.buffer = mark.buffer.split('\n', mark.line + 1)[mark.line].trim();
44
+ }
45
+ }
46
+
47
+ var options = {}
48
+ options.type = 'json'
49
+ options.config = {
50
+ template: function(obj) { return JSON.stringify(obj, null, 2); }
51
+ };
52
+ options.extension = '.json'
53
+
54
+ var stream = through.obj(function(file, enc, done) {
55
+ var fail = function(message) {
56
+ done(new gutil.PluginError('raml2html', message));
57
+ };
58
+ if (file.isBuffer()) {
59
+ var cwd = process.cwd();
60
+ process.chdir(path.resolve(path.dirname(file.path)));
61
+ raml2html.render(file.contents, options.config,
62
+ function(output) {
63
+ process.chdir(cwd);
64
+ stream.push(new gutil.File({
65
+ base: file.base,
66
+ cwd: file.cwd,
67
+ path: gutil.replaceExtension(file.path, options.extension),
68
+ contents: new Buffer(output)
69
+ }));
70
+ done();
71
+ },
72
+ function(error) {
73
+ process.chdir(cwd);
74
+ simplifyMark(error.context_mark);
75
+ simplifyMark(error.problem_mark);
76
+ process.nextTick(function() {
77
+ fail(JSON.stringify(error, null, 2));
78
+ });
79
+ });
80
+ }
81
+ else if (file.isStream()) fail(
82
+ 'Streams are not supported: ' + file.inspect()
83
+ );
84
+ else if (file.isNull()) fail('Input file is null: ' + file.inspect());
85
+ });
86
+
87
+ return stream;
88
+ }
89
+
90
+ function handleError(err) {
91
+ console.error(err.toString());
92
+ this.emit('end');
93
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "api-documentation",
3
+ "version": "0.0.1",
4
+ "description": "RAML documentation and gulp tasks for test/http stub files",
5
+ "main": "gulpfile.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": ""
12
+ },
13
+ "author": "",
14
+ "license": "Copyright by the contributors of the master branch of this repository",
15
+ "bugs": {
16
+ "url": ""
17
+ },
18
+ "homepage": "",
19
+ "dependencies": {
20
+ "gulp": "^3.8.11",
21
+ "gulp-concat": "^2.5.2",
22
+ "gulp-data": "^1.2.0",
23
+ "gulp-debug": "^2.0.1",
24
+ "gulp-load-plugins": "^0.9.0",
25
+ "gulp-notify": "^2.2.0",
26
+ "gulp-raml": "^0.1.3",
27
+ "gulp-template": "^3.0.0",
28
+ "gulp-util": "^3.0.4",
29
+ "gulp-yaml": "^0.2.4",
30
+ "js-yaml": "^3.2.7",
31
+ "raml2html": "^1.6.0",
32
+ "through2": "^0.6.3"
33
+ },
34
+ "devDependencies": {
35
+ "gulp-load-plugins": "^0.9.0",
36
+ "require-dir": "^0.3.0"
37
+ }
38
+ }
@@ -0,0 +1 @@
1
+ {"data":[{"id":"1","type":"item","created_at":"1430407103","updated_at":"1430407180","name":"Hamburger","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/1"}},{"id":"2","type":"item","created_at":"1430407103","updated_at":"1430407180","name":"Cheese burger","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/2"}},{"id":"3","type":"item","created_at":"1430407103","updated_at":"1430407180","name":"French Fries","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/3"}}]}
@@ -0,0 +1 @@
1
+ {"data":{"id":"1","type":"item","name":"Hamburger","created_at":"1430407103","updated_at":"1430407180","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/hamburger/1"}}}
@@ -0,0 +1 @@
1
+ {"data":[{"id":"1","type":"order","created_at":"1430407203","updated_at":"1430407280","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/orders/1","items":{"related":"https://app.my-awesome-restaurant.com/api/v1/orders/1/items","linkage":[{"type":"items","id":"1"},{"type":"items","id":"3"}]}}},{"id":"2","type":"order","created_at":"1430407203","updated_at":"1430407280","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/orders/1","items":{"related":"https://app.my-awesome-restaurant.com/api/v1/orders/2/items","linkage":[{"type":"items","id":"2"},{"type":"items","id":"3"}]}}}],"included":{"items":{"1":{"id":1,"type":"item","created_at":"1430407103","updated_at":"1430407180","name":"Hamburger","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/1"}},"2":{"id":2,"type":"item","created_at":"1430407103","updated_at":"1430407180","name":"Cheese burger","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/2"}},"3":{"id":3,"type":"item","created_at":"1430407103","updated_at":"1430407180","name":"French Fries","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/3"}}}}}
@@ -0,0 +1 @@
1
+ {"data":{"id":"1","type":"order","created_at":"1430407203","updated_at":"1430407280","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/orders/1","items":{"related":"https://app.my-awesome-restaurant.com/api/v1/orders/1/items","linkage":[{"type":"items","id":"1"},{"type":"items","id":"3"}]}}},"included":{"items":{"1":{"id":1,"type":"item","created_at":"1430407103","updated_at":"1430407180","name":"Hamburger","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/1"}},"3":{"id":3,"type":"item","created_at":"1430407103","updated_at":"1430407180","name":"French Fries","links":{"self":"https://app.my-awesome-restaurant.com/api/v1/items/3"}}}}}
@@ -0,0 +1,16 @@
1
+ require 'airborne'
2
+
3
+ describe 'GET <%= url %>' do
4
+ let!(:<%= name %>) { create(:<%= name %>) }
5
+
6
+ before do
7
+ add_header_tokens(<%= secured_by %>)
8
+ end
9
+
10
+ it 'returns expected json' do
11
+ get "<%= url %>"
12
+ expect_status <%= response_code %>
13
+ expect_json_keys <%= body.data.keys %>
14
+ end
15
+ end
16
+
@@ -0,0 +1,16 @@
1
+ require 'airborne'
2
+
3
+ describe 'GET <%= url %>' do
4
+ let!(:<%= name %>) { create_list(:<%= name %>, 3) }
5
+
6
+ before do
7
+ add_header_tokens(<%= secured_by %>)
8
+ end
9
+
10
+ it 'returns expected json' do
11
+ get "<%= url %>"
12
+ expect_status <%= response_code %>
13
+ expect_json_keys <%= body.data.sample.keys %>
14
+ end
15
+ end
16
+
@@ -0,0 +1,13 @@
1
+ require 'airborne'
2
+
3
+ describe 'POST <%= url %>' do
4
+ before do
5
+ add_header_tokens(<%= secured_by %>)
6
+ end
7
+
8
+ it 'returns the saved record' do
9
+ post "<%= url %>"
10
+ expect_status <%= response_code %>
11
+ end
12
+ end
13
+
@@ -0,0 +1,3 @@
1
+ module Textualize
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,43 @@
1
+ {
2
+ verb: 'get',
3
+ url: '/api/v1/items',
4
+ relative_path: '/items',
5
+ type: 'collection-ro',
6
+ secured_by: ['staff'],
7
+ name: 'items',
8
+ response_code: 200,
9
+ body: {
10
+ data: [
11
+ {
12
+ id: '1',
13
+ type: 'item',
14
+ created_at: '1430407103',
15
+ updated_at: '1430407180',
16
+ name: 'Hamburger',
17
+ links: {
18
+ self: 'https://app.my-awesome-restaurant.com/api/v1/items/1'
19
+ }
20
+ },
21
+ {
22
+ id: '2',
23
+ type: 'item',
24
+ created_at: '1430407103',
25
+ updated_at: '1430407180',
26
+ name: 'Cheese burger',
27
+ links: {
28
+ self: 'https://app.my-awesome-restaurant.com/api/v1/items/2'
29
+ }
30
+ },
31
+ {
32
+ id: '3',
33
+ type: 'item',
34
+ created_at: '1430407103',
35
+ updated_at: '1430407180',
36
+ name: 'French Fries',
37
+ links: {
38
+ self: 'https://app.my-awesome-restaurant.com/api/v1/items/3'
39
+ }
40
+ }
41
+ ]
42
+ }
43
+ }
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'textualize/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'textualize'
8
+ spec.version = Textualize::VERSION
9
+ spec.authors = ['Q-Centrix Dev Team']
10
+ spec.email = ['devjobs@q-centrix.com']
11
+
12
+ spec.summary = 'Turn Documentation into Tests and More'
13
+ spec.description = <<-DESCRIPTION
14
+ Textualize uses RAML for documentation and comes with scripts to generate
15
+ template files that can be used to fulfill an implementation of your
16
+ documentation.
17
+ DESCRIPTION
18
+
19
+ spec.homepage = 'https://github.com/q-centrix/textualize'
20
+ spec.license = 'MIT'
21
+
22
+ spec.files = `git ls-files`.split("\n").reject do |file|
23
+ file.match(%r{^(spec|features)/})
24
+ end
25
+ spec.executables = spec.files.grep(%r{^bin/}) do |file|
26
+ File.basename(file)
27
+ end
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_runtime_dependency 'thor', '~> 0'
31
+ spec.add_runtime_dependency 'attr_extras', '~> 4'
32
+ spec.add_runtime_dependency 'hashie', '~> 3'
33
+ spec.add_runtime_dependency 'uglifier', '~> 2'
34
+
35
+ spec.add_development_dependency 'aruba', '~> 0'
36
+ spec.add_development_dependency 'byebug', '~> 3'
37
+ spec.add_development_dependency 'pry', '~> 0'
38
+ spec.add_development_dependency 'bundler', '~> 1.8'
39
+ spec.add_development_dependency 'rake', '~> 10.0'
40
+ spec.add_development_dependency 'rspec', '~> 3'
41
+ end