grape-apiary 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +18 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +71 -0
- data/Rakefile +19 -0
- data/grape-apiary.gemspec +29 -0
- data/lib/grape-apiary.rb +17 -0
- data/lib/grape-apiary/blueprint.rb +18 -0
- data/lib/grape-apiary/config.rb +28 -0
- data/lib/grape-apiary/parameter.rb +41 -0
- data/lib/grape-apiary/resource.rb +46 -0
- data/lib/grape-apiary/route.rb +54 -0
- data/lib/grape-apiary/routes.rb +57 -0
- data/lib/grape-apiary/sample_generator.rb +20 -0
- data/lib/grape-apiary/templates/blueprint.md.erb +38 -0
- data/lib/grape-apiary/version.rb +3 -0
- data/lib/grape/apiary.rb +1 -0
- data/spec/grape-apiary/blueprint_spec.rb +50 -0
- data/spec/grape-apiary/config_spec.rb +51 -0
- data/spec/grape-apiary/route_spec.rb +21 -0
- data/spec/grape-apiary/routes_spec.rb +54 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/config_context.rb +28 -0
- data/spec/support/sample_api.rb +32 -0
- metadata +177 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7cd2c0def37017f4c088f97f4f447ba07ab3af0a
|
4
|
+
data.tar.gz: 318d3495eb891906a53283927c7a22ac8d52a0f8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1efa251c4b80aa5d7bb16284584bc367c1d7dac8ce3dc6948444d10c87e7200d351084e11d18c7660b89cc65a6951ec6d9dbce7b3e99665ec6767a5d963c559e
|
7
|
+
data.tar.gz: 39e7c7e6bb078cf7355394580db5a9ea524d63456ddb9f280f868108e44ddf681677baf7dae4da2d77dbff287b26b0feedcc4df8328006f7a88a3cdd7b7e9299
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
AllCops:
|
2
|
+
Excludes:
|
3
|
+
- Rakefile
|
4
|
+
- vendor/**
|
5
|
+
- bin/**
|
6
|
+
|
7
|
+
Documentation:
|
8
|
+
# don't require classes to be documented
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Encoding:
|
12
|
+
# no need to always specify encoding
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
LineLength:
|
16
|
+
# just one more character please
|
17
|
+
Max: 80
|
18
|
+
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 John Allen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# GrapeApiary
|
2
|
+
|
3
|
+
[](https://codeclimate.com/github/connexio-labs/grape-apiary)
|
4
|
+
[](https://travis-ci.org/connexio-labs/grape-apiary)
|
5
|
+
[](https://coveralls.io/r/connexio-labs/grape-apiary)
|
6
|
+
|
7
|
+
Auto generates an [Apiary Blueprint](http://apiary.io) from the docuementation that is created by your Grape API.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'grape-apiary'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install grape-apiary
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### Configuration
|
26
|
+
|
27
|
+
Configure details about your api in an initializers or similar
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
GrapeApiary.config do |config|
|
31
|
+
# your apiary.io host name
|
32
|
+
config.host = 'http://awesome-api.apiary.io'
|
33
|
+
# the name of your api
|
34
|
+
config.name = 'Awesome API'
|
35
|
+
# a description for your api
|
36
|
+
config.description = 'The awesome description'
|
37
|
+
# resources you do not want documented
|
38
|
+
config.resource_exclusion = [:admin, :swagger_doc]
|
39
|
+
end
|
40
|
+
|
41
|
+
# headers you want documented
|
42
|
+
GrapeApiary.config.request_headers = [
|
43
|
+
{ 'Accept-Charset' => 'utf-8' },
|
44
|
+
{ 'Connection' => 'keep-alive' },
|
45
|
+
{ 'Content-Type' => 'application/json' }
|
46
|
+
]
|
47
|
+
|
48
|
+
GrapeApiary.config.response_headers = [
|
49
|
+
{ 'Content-Length' => '21685' },
|
50
|
+
{ 'Connection' => 'keep-alive' },
|
51
|
+
{ 'Content-Type' => 'application/json' }
|
52
|
+
]
|
53
|
+
```
|
54
|
+
|
55
|
+
### Generation
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# supply the class you'd like to document and generate your blueprint
|
59
|
+
GrapeApiary::Blueprint.new(AwesomeAPI).generate
|
60
|
+
```
|
61
|
+
|
62
|
+
## TODO
|
63
|
+
|
64
|
+
|
65
|
+
## Contributing
|
66
|
+
|
67
|
+
1. Fork it ( http://github.com/<my-github-username>/grape-apiary/fork )
|
68
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
69
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
70
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
71
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
5
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'rainbow/ext/string' unless String.respond_to?(:color)
|
9
|
+
require 'rubocop/rake_task'
|
10
|
+
Rubocop::RakeTask.new(:rubocop)
|
11
|
+
|
12
|
+
task default: [:rubocop, :spec]
|
13
|
+
|
14
|
+
task :console do
|
15
|
+
require 'pry'
|
16
|
+
require 'grape-apiary'
|
17
|
+
ARGV.clear
|
18
|
+
Pry.start
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'grape-apiary/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'grape-apiary'
|
8
|
+
spec.version = GrapeApiary::VERSION
|
9
|
+
spec.authors = ['John Allen']
|
10
|
+
spec.email = ['john@threedogconsulting.com']
|
11
|
+
spec.summary = %q{Allows for generating an Apiary Blueprint for you Grape API}
|
12
|
+
spec.description = %q{Auto generates an Apiary (http://apiary.io) Blueprint from the docuementation that is created by your Grape API}
|
13
|
+
spec.homepage = 'https://github.com/connexio/grape-apiary'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'grape', '~> 0.6'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'coveralls', '~> 0.7'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 2.14'
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'rubocop', '~> 0.18'
|
28
|
+
spec.add_development_dependency 'pry', '~> 0.9'
|
29
|
+
end
|
data/lib/grape-apiary.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'grape'
|
2
|
+
require 'grape-apiary/version'
|
3
|
+
require 'grape-apiary/config'
|
4
|
+
require 'grape-apiary/parameter'
|
5
|
+
require 'grape-apiary/sample_generator'
|
6
|
+
require 'grape-apiary/route'
|
7
|
+
require 'grape-apiary/resource'
|
8
|
+
require 'grape-apiary/routes'
|
9
|
+
require 'grape-apiary/blueprint'
|
10
|
+
|
11
|
+
module GrapeApiary
|
12
|
+
module_function
|
13
|
+
|
14
|
+
def config
|
15
|
+
block_given? ? yield(Config) : Config
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module GrapeApiary
|
2
|
+
class Blueprint
|
3
|
+
attr_reader :api_class, :template, :binding
|
4
|
+
|
5
|
+
def initialize(api_class)
|
6
|
+
@api_class = api_class
|
7
|
+
@template = File.read('./lib/grape-apiary/templates/blueprint.md.erb')
|
8
|
+
@binding = Routes.new(api_class).routes_binding
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
ERB.new(template).result(binding)
|
13
|
+
end
|
14
|
+
|
15
|
+
def write
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GrapeApiary
|
2
|
+
class Config
|
3
|
+
SETTINGS = [
|
4
|
+
:host,
|
5
|
+
:name,
|
6
|
+
:description,
|
7
|
+
:request_headers,
|
8
|
+
:response_headers,
|
9
|
+
:resource_exclusion
|
10
|
+
]
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor(*SETTINGS)
|
14
|
+
|
15
|
+
def request_headers
|
16
|
+
@request_headers ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
def response_headers
|
20
|
+
@response_headers ||= []
|
21
|
+
end
|
22
|
+
|
23
|
+
def resource_exclusion
|
24
|
+
@resource_exclusion ||= []
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GrapeApiary
|
2
|
+
class Parameter
|
3
|
+
attr_reader :route, :name, :settings
|
4
|
+
|
5
|
+
delegate :route_model, :route_namespace, to: :route
|
6
|
+
delegate :requirement, :type, :example, :desc, to: :settings
|
7
|
+
|
8
|
+
def initialize(route, name, options)
|
9
|
+
@route = route
|
10
|
+
@name = name
|
11
|
+
@name = name.scan(/\[(.*)\]/).flatten.first if name.include?('[')
|
12
|
+
@settings = parse_options(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"#{name} (#{requirement}, #{type}, `#{example}`) ... #{desc}"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def parse_options(options)
|
22
|
+
options = default_options(options) if options.blank?
|
23
|
+
|
24
|
+
options[:requirement] = options[:required] ? 'required' : 'optional'
|
25
|
+
|
26
|
+
Hashie::Mash.new(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_options(options)
|
30
|
+
model = name.include?('_id') ? name.gsub('_id', '') : route.route_model
|
31
|
+
|
32
|
+
{
|
33
|
+
required: true,
|
34
|
+
requirement: 'required',
|
35
|
+
type: 'uuid',
|
36
|
+
desc: "the `id` of the `#{model}`",
|
37
|
+
example: SecureRandom.uuid
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module GrapeApiary
|
2
|
+
class Resource
|
3
|
+
attr_reader :key, :name, :routes
|
4
|
+
|
5
|
+
def initialize(key, routes)
|
6
|
+
@key = key
|
7
|
+
@name = key.humanize
|
8
|
+
@routes = routes
|
9
|
+
end
|
10
|
+
|
11
|
+
def title
|
12
|
+
@title ||= name.titleize
|
13
|
+
end
|
14
|
+
|
15
|
+
def namespaced
|
16
|
+
@namespaced ||= routes.group_by(&:route_namespace).map do |_, routes|
|
17
|
+
Resource.new(name, routes)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def paths
|
22
|
+
@paths ||= routes.group_by(&:route_path_without_format).map do |n, routes|
|
23
|
+
Resource.new(name, routes)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def header
|
28
|
+
# TODO: ???
|
29
|
+
route = routes.first
|
30
|
+
|
31
|
+
"#{title} #{route.route_type} [#{route.route_path_without_format}]"
|
32
|
+
end
|
33
|
+
|
34
|
+
def sample_request
|
35
|
+
SampleGenerator.new(self).request
|
36
|
+
end
|
37
|
+
|
38
|
+
def sample_response
|
39
|
+
SampleGenerator.new(self).response
|
40
|
+
end
|
41
|
+
|
42
|
+
def unique_params
|
43
|
+
# params = routes.map(&:route_params)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GrapeApiary
|
2
|
+
class Route < SimpleDelegator
|
3
|
+
# would like to rely on SimpleDelegator but Grape::Route uses
|
4
|
+
# method_missing for these methods :'(
|
5
|
+
delegate :route_namespace, :route_path, :route_method, to: '__getobj__'
|
6
|
+
|
7
|
+
def route_params
|
8
|
+
@route_params ||= __getobj__.route_params.map do |param|
|
9
|
+
Parameter.new(self, *param)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def route_name
|
14
|
+
route_namespace.split('/').last ||
|
15
|
+
route_path.match('\/(\w*?)[\.\/\(]').captures.first
|
16
|
+
end
|
17
|
+
|
18
|
+
def route_description
|
19
|
+
"#{__getobj__.route_description} [#{route_method.upcase}]"
|
20
|
+
end
|
21
|
+
|
22
|
+
def route_path_without_format
|
23
|
+
route_path.gsub(/\((.*?)\)/, '')
|
24
|
+
end
|
25
|
+
|
26
|
+
def route_model
|
27
|
+
route_namespace.split('/').last.singularize
|
28
|
+
end
|
29
|
+
|
30
|
+
def route_type
|
31
|
+
list? ? 'collection' : 'single'
|
32
|
+
end
|
33
|
+
|
34
|
+
def request_description
|
35
|
+
"+ Request #{'(application/json)' if request_body?}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def response_description
|
39
|
+
code = route_method == 'POST' ? 201 : 200
|
40
|
+
|
41
|
+
"+ Response #{code} (application/json)"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def list?
|
47
|
+
route_method == 'GET' && !route_path.include?(':id')
|
48
|
+
end
|
49
|
+
|
50
|
+
def request_body?
|
51
|
+
!%w(GET DELETE).include?(route_method)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module GrapeApiary
|
2
|
+
class Routes
|
3
|
+
attr_reader :api_class
|
4
|
+
|
5
|
+
delegate(*GrapeApiary::Config::SETTINGS, to: 'GrapeApiary::Config')
|
6
|
+
|
7
|
+
def initialize(api_class)
|
8
|
+
@api_class = api_class
|
9
|
+
end
|
10
|
+
|
11
|
+
def routes
|
12
|
+
@routes ||= api_class.routes.map do |route|
|
13
|
+
GrapeApiary::Route.new(route)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def resources
|
18
|
+
@resources ||= begin
|
19
|
+
grouped_routes = routes.group_by(&:route_name).reject do |name, routes|
|
20
|
+
resource_exclusion.include?(name.to_sym)
|
21
|
+
end
|
22
|
+
|
23
|
+
grouped_routes.map { |name, routes| Resource.new(name, routes) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def formatted_request_headers
|
28
|
+
formatted_headers(GrapeApiary::Config.request_headers)
|
29
|
+
end
|
30
|
+
|
31
|
+
def formatted_response_headers
|
32
|
+
formatted_headers(GrapeApiary::Config.response_headers)
|
33
|
+
end
|
34
|
+
|
35
|
+
def show_request_sample?(route)
|
36
|
+
%w(PUT POST).include?(route.route_method)
|
37
|
+
end
|
38
|
+
|
39
|
+
def routes_binding
|
40
|
+
binding
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def formatted_headers(headers)
|
46
|
+
spacer = "\n" + (' ' * 12)
|
47
|
+
|
48
|
+
strings = headers.map do |header|
|
49
|
+
key, value = *header.first
|
50
|
+
|
51
|
+
"#{key}: #{value}"
|
52
|
+
end
|
53
|
+
|
54
|
+
strings.join(spacer)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
FORMAT: 1A
|
2
|
+
HOST: <%= host %>
|
3
|
+
|
4
|
+
# <%= name %>
|
5
|
+
<%= description %>
|
6
|
+
|
7
|
+
<% resources.each do |resource| %>
|
8
|
+
# Group <%= resource.title %>
|
9
|
+
<% resource.namespaced.each do |grouped_resource| %>
|
10
|
+
<% grouped_resource.paths.each do |resource_by_path| %>
|
11
|
+
## <%= resource.header %>
|
12
|
+
Actions on the <%= resource.name %> resource
|
13
|
+
<% if resource_by_path.routes.first.route_params.present? %>
|
14
|
+
+ Parameters
|
15
|
+
<% resource_by_path.routes.first.route_params.each do |param| %>
|
16
|
+
+ <%= param.description %>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% resource_by_path.routes.each do |route| %>
|
20
|
+
### <%= route.route_description %>
|
21
|
+
<%= route.request_description %>
|
22
|
+
+ Headers
|
23
|
+
|
24
|
+
<%= formatted_request_headers %>
|
25
|
+
<% if show_request_sample?(route) %>
|
26
|
+
+ Body
|
27
|
+
|
28
|
+
<%= resource.sample_request %>
|
29
|
+
<% end %>
|
30
|
+
+ Headers
|
31
|
+
|
32
|
+
<%= formatted_response_headers %>
|
33
|
+
|
34
|
+
+ Body
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
37
|
+
<% end %>
|
38
|
+
<% end %>
|
data/lib/grape/apiary.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'grape-apiary'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrapeApiary::Blueprint do
|
4
|
+
include_context 'configuration'
|
5
|
+
|
6
|
+
context '#generate' do
|
7
|
+
before do
|
8
|
+
GrapeApiary.config do |config|
|
9
|
+
config.host = host
|
10
|
+
config.name = name
|
11
|
+
config.description = description
|
12
|
+
config.resource_exclusion = [:admin]
|
13
|
+
end
|
14
|
+
|
15
|
+
GrapeApiary.config.request_headers = [
|
16
|
+
{ 'Accept-Charset' => 'utf-8' },
|
17
|
+
{ 'Connection' => 'keep-alive' }
|
18
|
+
]
|
19
|
+
|
20
|
+
GrapeApiary.config.response_headers = [
|
21
|
+
{ 'Content-Length' => '21685' },
|
22
|
+
{ 'Connection' => 'keep-alive' }
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:klass) { SampleApi }
|
27
|
+
|
28
|
+
subject { GrapeApiary::Blueprint.new(klass).generate }
|
29
|
+
|
30
|
+
it 'sets the format to 1A' do
|
31
|
+
expect(subject).to include('1A')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'sets the host based on configuration' do
|
35
|
+
expect(subject).to include("HOST: #{host}")
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'creates a header from configuration' do
|
39
|
+
expect(subject).to include("# #{name}")
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'adds the description' do
|
43
|
+
expect(subject).to include(description)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'includes groups for each resource' do
|
47
|
+
expect(subject).to include('# Group Widgets')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrapeApiary::Config do
|
4
|
+
include_context 'configuration'
|
5
|
+
|
6
|
+
subject { GrapeApiary::Config }
|
7
|
+
|
8
|
+
it 'allows for host to be set' do
|
9
|
+
subject.host = host
|
10
|
+
|
11
|
+
expect(subject.host).to eq(host)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'allows for name to be set' do
|
15
|
+
subject.name = name
|
16
|
+
|
17
|
+
expect(subject.name).to eq(name)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'allows for description to be set' do
|
21
|
+
subject.description = description
|
22
|
+
|
23
|
+
expect(subject.description).to eq(description)
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'headers' do
|
27
|
+
[:request_headers, :response_headers].each do |type|
|
28
|
+
context type do
|
29
|
+
it 'is an array' do
|
30
|
+
expect(subject.send(type)).to be_a(Array)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'allows for request headers to be set in bulk' do
|
34
|
+
headers = send(type)
|
35
|
+
|
36
|
+
subject.send("#{type}=", headers)
|
37
|
+
|
38
|
+
expect(subject.send(type)).to eq(headers)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'allows for request headers to be set individually' do
|
42
|
+
header = { Host: 'api.connexiolabs-qa.com' }
|
43
|
+
|
44
|
+
expect do
|
45
|
+
subject.send(type) << header
|
46
|
+
end.to change { subject.send(type).length }.by(1)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrapeApiary::Route do
|
4
|
+
include_context 'configuration'
|
5
|
+
|
6
|
+
let(:routes) { GrapeApiary::Routes.new(SampleApi).routes }
|
7
|
+
|
8
|
+
subject { routes.first }
|
9
|
+
|
10
|
+
it 'adds a name helper to routes' do
|
11
|
+
expect(subject.route_name).to eq('widgets')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'adds a path helper without format' do
|
15
|
+
expect(subject.route_path_without_format).to eq('/widgets')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'adds a type helper' do
|
19
|
+
expect(subject.route_type).to eq('collection')
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrapeApiary::Routes do
|
4
|
+
include_context 'configuration'
|
5
|
+
|
6
|
+
before do
|
7
|
+
GrapeApiary.config do |config|
|
8
|
+
config.host = host
|
9
|
+
config.name = name
|
10
|
+
config.description = description
|
11
|
+
config.resource_exclusion = [:admin]
|
12
|
+
end
|
13
|
+
|
14
|
+
GrapeApiary.config.request_headers = [
|
15
|
+
{ 'Accept-Charset' => 'utf-8' },
|
16
|
+
{ 'Connection' => 'keep-alive' }
|
17
|
+
]
|
18
|
+
|
19
|
+
GrapeApiary.config.response_headers = [
|
20
|
+
{ 'Content-Length' => '21685' },
|
21
|
+
{ 'Connection' => 'keep-alive' }
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
subject { GrapeApiary::Routes.new(SampleApi) }
|
26
|
+
|
27
|
+
it 'exposes configuration settings' do
|
28
|
+
GrapeApiary::Config::SETTINGS.each do |setting|
|
29
|
+
expect(subject.send(setting)).to eq(GrapeApiary.config.send(setting))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'exposes the raw routes of the given api' do
|
34
|
+
expect(subject.routes).to eq(SampleApi.routes)
|
35
|
+
end
|
36
|
+
|
37
|
+
context '#resources' do
|
38
|
+
let(:unique_routes) { subject.routes.map(&:route_name).uniq }
|
39
|
+
|
40
|
+
let(:included_routes) do
|
41
|
+
unique_routes.reject do |name|
|
42
|
+
GrapeApiary.config.resource_exclusion.include?(name.to_sym)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'aggregates routes into resources' do
|
47
|
+
expect(subject.resources.first).to be_a(GrapeApiary::Resource)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'excluded resources based on configuration' do
|
51
|
+
expect(subject.resources.map(&:key)).to eq(included_routes)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.setup :default, :test
|
6
|
+
|
7
|
+
require 'coveralls'
|
8
|
+
Coveralls.wear!
|
9
|
+
|
10
|
+
require 'grape/apiary'
|
11
|
+
require 'rspec'
|
12
|
+
require 'pry'
|
13
|
+
|
14
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
@@ -0,0 +1,28 @@
|
|
1
|
+
shared_context 'configuration' do
|
2
|
+
let(:host) { 'http://grape-apiary.apiary.io' }
|
3
|
+
let(:name) { 'some api v1' }
|
4
|
+
let(:description) { 'some blueprint description' }
|
5
|
+
let(:resource_exclusion) { [:admin, :swagger_docs] }
|
6
|
+
|
7
|
+
let(:request_headers) do
|
8
|
+
[
|
9
|
+
{ 'Accept-Charset' => 'utf-8' },
|
10
|
+
{ 'Connection' => 'keep-alive' },
|
11
|
+
{ 'Content-Type' => 'application/json' }
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:response_headers) do
|
16
|
+
[
|
17
|
+
{ 'Content-Length' => '21685' },
|
18
|
+
{ 'Connection' => 'keep-alive' },
|
19
|
+
{ 'Content-Type' => 'application/json' }
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:app) do
|
24
|
+
def app
|
25
|
+
SampleApi
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class SampleApi < Grape::API
|
2
|
+
resource 'widgets' do
|
3
|
+
desc 'widgets list'
|
4
|
+
get '/' do
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'individual widget'
|
8
|
+
get ':id' do
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'create a widget'
|
12
|
+
params do
|
13
|
+
requires :name, type: 'string', desc: 'the widgets name'
|
14
|
+
optional :description, type: 'string', desc: 'the widgets name'
|
15
|
+
end
|
16
|
+
post '/' do
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'update a widget'
|
20
|
+
params do
|
21
|
+
optional :name, type: 'string', desc: 'the widgets name'
|
22
|
+
optional :description, type: 'string', desc: 'the widgets name'
|
23
|
+
end
|
24
|
+
put ':id' do
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
resource 'admin' do
|
29
|
+
get '/' do
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grape-apiary
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Allen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: grape
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: coveralls
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.14'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.14'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.18'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.18'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.9'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.9'
|
111
|
+
description: Auto generates an Apiary (http://apiary.io) Blueprint from the docuementation
|
112
|
+
that is created by your Grape API
|
113
|
+
email:
|
114
|
+
- john@threedogconsulting.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- ".gitignore"
|
120
|
+
- ".rubocop.yml"
|
121
|
+
- ".travis.yml"
|
122
|
+
- Gemfile
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- grape-apiary.gemspec
|
127
|
+
- lib/grape-apiary.rb
|
128
|
+
- lib/grape-apiary/blueprint.rb
|
129
|
+
- lib/grape-apiary/config.rb
|
130
|
+
- lib/grape-apiary/parameter.rb
|
131
|
+
- lib/grape-apiary/resource.rb
|
132
|
+
- lib/grape-apiary/route.rb
|
133
|
+
- lib/grape-apiary/routes.rb
|
134
|
+
- lib/grape-apiary/sample_generator.rb
|
135
|
+
- lib/grape-apiary/templates/blueprint.md.erb
|
136
|
+
- lib/grape-apiary/version.rb
|
137
|
+
- lib/grape/apiary.rb
|
138
|
+
- spec/grape-apiary/blueprint_spec.rb
|
139
|
+
- spec/grape-apiary/config_spec.rb
|
140
|
+
- spec/grape-apiary/route_spec.rb
|
141
|
+
- spec/grape-apiary/routes_spec.rb
|
142
|
+
- spec/spec_helper.rb
|
143
|
+
- spec/support/config_context.rb
|
144
|
+
- spec/support/sample_api.rb
|
145
|
+
homepage: https://github.com/connexio/grape-apiary
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubyforge_project:
|
165
|
+
rubygems_version: 2.2.2
|
166
|
+
signing_key:
|
167
|
+
specification_version: 4
|
168
|
+
summary: Allows for generating an Apiary Blueprint for you Grape API
|
169
|
+
test_files:
|
170
|
+
- spec/grape-apiary/blueprint_spec.rb
|
171
|
+
- spec/grape-apiary/config_spec.rb
|
172
|
+
- spec/grape-apiary/route_spec.rb
|
173
|
+
- spec/grape-apiary/routes_spec.rb
|
174
|
+
- spec/spec_helper.rb
|
175
|
+
- spec/support/config_context.rb
|
176
|
+
- spec/support/sample_api.rb
|
177
|
+
has_rdoc:
|