grape-doc 0.0.1.alpha → 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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/VERSION +1 -1
- data/grape-doc.gemspec +3 -1
- data/lib/grape/doc/doc_class/header.rb +30 -0
- data/lib/grape/doc/doc_class/link.rb +22 -0
- data/lib/grape/doc/doc_class/list.rb +34 -0
- data/lib/grape/doc/doc_class/parser.rb +56 -0
- data/lib/grape/doc/doc_class/raw.rb +20 -0
- data/lib/grape/doc/doc_class/sidebar.rb +15 -0
- data/lib/grape/doc/doc_class/table.rb +17 -0
- data/lib/grape/doc/doc_class.rb +26 -0
- data/lib/grape/doc/generator.rb +127 -0
- data/lib/grape/doc/helper.rb +110 -0
- data/lib/grape/doc/prototype.rb +91 -0
- data/lib/grape-doc.rb +2 -1
- data/test/sample.html +16 -0
- data/test/test_doc_gen.rb +13 -0
- data/test/test_helper.rb +33 -0
- data/test/test_object_space_collector.rb +23 -0
- data/test/test_sample_api.rb +20 -0
- metadata +56 -9
- data/lib/grape/doc/logic.rb +0 -495
- data/lib/grape/doc/mpatch.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78159d4d2d7852fadb62e8caf6b7aad1dbd0f772
|
4
|
+
data.tar.gz: 4fcba1b40c4a766cfb9d2d06e48e2563c75bd6b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7780a35011633490200162fda618beb50ff8e82052c631690b99927fd82c4380d21d05a2fca12080373e32fc39b0041aaba4f2c067c8cc0142371c183991f22
|
7
|
+
data.tar.gz: 193c15ecde4b52289c5148b1b84aa4859f5561319b84c55ffcc7e40f1d2189962fb6e8632f0b62feab0c65e86ed54b2911be75fa3c2d64c6997f45ec4bfa1cf6
|
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
source :rubygems
|
2
|
-
gemspec
|
2
|
+
gemspec
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.0
|
data/grape-doc.gemspec
CHANGED
@@ -20,7 +20,9 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.add_development_dependency "rake"
|
21
21
|
|
22
22
|
spec.add_dependency "grape"
|
23
|
+
spec.add_dependency "loader"
|
24
|
+
spec.add_dependency "RedCloth"
|
23
25
|
spec.add_dependency "rack-test"
|
24
|
-
spec.add_dependency "rack-test-poc"
|
26
|
+
spec.add_dependency "rack-test-poc",">= 1.0.2"
|
25
27
|
|
26
28
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
class ApiDocParts
|
3
|
+
|
4
|
+
class H1 < StringObject
|
5
|
+
end
|
6
|
+
|
7
|
+
class H2 < H1
|
8
|
+
end
|
9
|
+
|
10
|
+
class H3 < H1
|
11
|
+
end
|
12
|
+
|
13
|
+
class H4 < H1
|
14
|
+
end
|
15
|
+
|
16
|
+
class H5 < H1
|
17
|
+
end
|
18
|
+
|
19
|
+
class H6 < H1
|
20
|
+
end
|
21
|
+
|
22
|
+
class Block < StringObject
|
23
|
+
self.markdown = "bq"
|
24
|
+
end
|
25
|
+
|
26
|
+
class Br < StringBasic
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
class ApiDocParts
|
3
|
+
|
4
|
+
class Link < StringObject
|
5
|
+
|
6
|
+
def initialize(text,url)
|
7
|
+
super(text)
|
8
|
+
@url = url
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_textile
|
12
|
+
"\"#{self}\":#{@url}"
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class PictureLink < StringObjectEnded
|
18
|
+
self.markdown = '!'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
class ApiDocParts
|
3
|
+
|
4
|
+
class List < ArrayObject
|
5
|
+
|
6
|
+
self.markdown = '*'
|
7
|
+
|
8
|
+
def initialize(obj)
|
9
|
+
obj = case obj
|
10
|
+
when Array
|
11
|
+
obj
|
12
|
+
|
13
|
+
when String,Symbol
|
14
|
+
obj.to_s.split("\n")
|
15
|
+
|
16
|
+
else
|
17
|
+
raise(ArgumentError,'unknown format given for list object')
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
super(obj)
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class NumericalList < List
|
28
|
+
self.markdown = '#'
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
class ApiDocParts
|
3
|
+
|
4
|
+
module Parser
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def parse(object)
|
8
|
+
case object
|
9
|
+
|
10
|
+
when Array
|
11
|
+
object.map{|e|
|
12
|
+
case e
|
13
|
+
when Array
|
14
|
+
e.dup
|
15
|
+
|
16
|
+
else
|
17
|
+
self.format_parse(*e)
|
18
|
+
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
else
|
23
|
+
# self.format_parse(object)
|
24
|
+
object
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def format_parse(text,*args)
|
30
|
+
text = text.dup.to_s
|
31
|
+
args.each do |command|
|
32
|
+
case command.to_s.downcase
|
33
|
+
|
34
|
+
when /^bold/
|
35
|
+
text.replace("*#{text}*")
|
36
|
+
|
37
|
+
when /^italic/
|
38
|
+
text.replace("__#{text}__")
|
39
|
+
|
40
|
+
when /^underlined/
|
41
|
+
text.replace("+#{text}+")
|
42
|
+
|
43
|
+
when /^superscript/
|
44
|
+
text.replace("^#{text}^")
|
45
|
+
|
46
|
+
end
|
47
|
+
end;return text
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
class ApiDocParts
|
3
|
+
|
4
|
+
class Table < ArrayObject
|
5
|
+
|
6
|
+
def pust(*args)
|
7
|
+
raise(ArgumentError,'invalid input for table!') if args.any?{|e| !(e.class <= Array) }
|
8
|
+
super(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_textile
|
12
|
+
self.map{|row| row.join(' | ') }.join("\n")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
|
3
|
+
class ApiDocumentation < Array
|
4
|
+
|
5
|
+
def create(type,*args)
|
6
|
+
raise(ArgumentError,'invalid type') unless [String,Symbol].any?{ |klass| type.class <= klass }
|
7
|
+
return Helpers.constantize("GrapeDoc::ApiDocParts::#{Helpers.camelize(type)}").new(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(type,*args)
|
11
|
+
self.push(create(type,*args))
|
12
|
+
end
|
13
|
+
|
14
|
+
def br(int=1)
|
15
|
+
raise unless int.class <= Integer
|
16
|
+
int.times{self.push(ApiDocParts::Br.new("\n"))}
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_textile
|
20
|
+
require 'RedCloth'
|
21
|
+
RedCloth.new(self.map{|e| e.to_textile }.join("\n"))
|
22
|
+
end;alias to_s to_textile
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
class Generator
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
|
6
|
+
raise(ArgumentError,'invalid options given') unless opts.class <= Hash
|
7
|
+
opts.merge!(
|
8
|
+
{
|
9
|
+
format: 'html'
|
10
|
+
}.merge(opts)
|
11
|
+
)
|
12
|
+
|
13
|
+
process_head
|
14
|
+
process_table_of_content
|
15
|
+
process_endpoints
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def document
|
20
|
+
@api_doc ||= ApiDocumentation.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def save
|
24
|
+
File.write File.join(Helpers.doc_folder_path,'api_doc.html'),
|
25
|
+
RedCloth.new(document.to_textile).to_html
|
26
|
+
|
27
|
+
end;alias save! save
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def process_head
|
32
|
+
document.add :h1, "Rest Api Documentation (#{RackTestPoc.root.split(File::Separator)[-1]})"
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_table_of_content
|
36
|
+
#TODO: Table of content here!
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_endpoints
|
40
|
+
|
41
|
+
# Iterates over all subclasses (direct and indirect)
|
42
|
+
Helpers.each_grape_class do |rest_api_model|
|
43
|
+
rest_api_model.routes.each do |route|
|
44
|
+
|
45
|
+
document.add :h2, "#{route.route_method.to_s.upcase}: #{route.route_path}"
|
46
|
+
document.add :h3, 'Request'
|
47
|
+
document.add :h4, 'description'
|
48
|
+
var = case route.route_description
|
49
|
+
|
50
|
+
when Hash
|
51
|
+
(route.route_description.find{|k,v| k == 'desc' || k == :desc } || [])[1] || ''
|
52
|
+
|
53
|
+
when Array
|
54
|
+
route.route_description
|
55
|
+
|
56
|
+
else
|
57
|
+
route.route_description.to_s
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
document.add :list,[*var]
|
62
|
+
|
63
|
+
if route.route_params.length > 0
|
64
|
+
document.add :h4, 'params'
|
65
|
+
|
66
|
+
route.route_params.each do |key,value|
|
67
|
+
document.add :list,[
|
68
|
+
document.create(:text,key.to_s,:bold),
|
69
|
+
document.create(:list,value.map{ |k,v| "#{k}: #{v}" })
|
70
|
+
]
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
route_path_var = route.route_path.to_s.sub(/\(\.:format\)$/,'')
|
77
|
+
@poc_data ||= Helpers.poc_data
|
78
|
+
if @poc_data && @poc_data.find{|k,v| k =~ /^#{route_path_var}/ }
|
79
|
+
if -> { @poc_data[route_path_var][route.route_method.to_s.upcase] rescue nil }.call
|
80
|
+
poc_opts = @poc_data[route_path_var][route.route_method.to_s.upcase]
|
81
|
+
|
82
|
+
document.add :h3,'Response'
|
83
|
+
# document.add :raw,poc_opts['response'].to_yaml
|
84
|
+
document.add :h4,'body'
|
85
|
+
document.add :raw,poc_opts['response']['raw_body']
|
86
|
+
|
87
|
+
document.add :h5,'options:'
|
88
|
+
|
89
|
+
document.add :list,[
|
90
|
+
"'status code: #{poc_opts['response']['status']}",
|
91
|
+
"format: #{poc_opts['response']['format']}"
|
92
|
+
]
|
93
|
+
|
94
|
+
|
95
|
+
document.add :h4,'example'
|
96
|
+
|
97
|
+
document.add :h5,'curl sample'
|
98
|
+
|
99
|
+
document.add :raw,[
|
100
|
+
"curl ",
|
101
|
+
"-X #{route.route_method.to_s.upcase} ",
|
102
|
+
"\"http://api_url#{route_path_var}?",
|
103
|
+
"#{poc_opts['request']['query']['raw']}\""
|
104
|
+
].join
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
class << self
|
120
|
+
|
121
|
+
def new(*args)
|
122
|
+
Generator.new(*args)
|
123
|
+
end;alias generate new
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
module Helpers
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def each_grape_class
|
6
|
+
::ObjectSpace.each_object(::Class) do |api_class|
|
7
|
+
next unless -> { api_class < Grape::API rescue false }.call
|
8
|
+
yield(api_class)
|
9
|
+
end if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def doc_folder_path
|
13
|
+
@doc_folder_path ||= -> {
|
14
|
+
doc_folder_path = File.join(RackTestPoc.root,'doc')
|
15
|
+
File.mkdir doc_folder_path unless File.exist?(doc_folder_path)
|
16
|
+
return doc_folder_path
|
17
|
+
|
18
|
+
}.call
|
19
|
+
end
|
20
|
+
|
21
|
+
def poc_file_path
|
22
|
+
return Dir.glob(
|
23
|
+
File.join(RackTestPoc.root,'test','poc','*.{yml,yaml}')
|
24
|
+
).max_by(&File.method(:ctime))
|
25
|
+
end
|
26
|
+
|
27
|
+
def poc_data
|
28
|
+
require 'yaml'
|
29
|
+
YAML.load(File.read(poc_file_path))
|
30
|
+
rescue;{}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Tries to find a constant with the name specified in the argument string.
|
34
|
+
#
|
35
|
+
# 'Module'.constantize # => Module
|
36
|
+
# 'Test::Unit'.constantize # => Test::Unit
|
37
|
+
#
|
38
|
+
# The name is assumed to be the one of a top-level constant, no matter
|
39
|
+
# whether it starts with "::" or not. No lexical context is taken into
|
40
|
+
# account:
|
41
|
+
#
|
42
|
+
# C = 'outside'
|
43
|
+
# module M
|
44
|
+
# C = 'inside'
|
45
|
+
# C # => 'inside'
|
46
|
+
# 'C'.constantize # => 'outside', same as ::C
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# NameError is raised when the name is not in CamelCase or the constant is
|
50
|
+
# unknown.
|
51
|
+
def constantize(camel_cased_word)
|
52
|
+
names = camel_cased_word.split('::')
|
53
|
+
|
54
|
+
# Trigger a builtin NameError exception including the ill-formed constant in the message.
|
55
|
+
Object.const_get(camel_cased_word) if names.empty?
|
56
|
+
|
57
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
58
|
+
names.shift if names.size > 1 && names.first.empty?
|
59
|
+
|
60
|
+
names.inject(Object) do |constant, name|
|
61
|
+
if constant == Object
|
62
|
+
constant.const_get(name)
|
63
|
+
else
|
64
|
+
candidate = constant.const_get(name)
|
65
|
+
next candidate if constant.const_defined?(name, false)
|
66
|
+
next candidate unless Object.const_defined?(name)
|
67
|
+
|
68
|
+
# Go down the ancestors to check it it's owned
|
69
|
+
# directly before we reach Object or the end of ancestors.
|
70
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
71
|
+
break const if ancestor == Object
|
72
|
+
break ancestor if ancestor.const_defined?(name, false)
|
73
|
+
const
|
74
|
+
end
|
75
|
+
|
76
|
+
# owner is in Object, so raise
|
77
|
+
constant.const_get(name, false)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# By default, +camelize+ converts strings to UpperCamelCase. If the argument
|
84
|
+
# to +camelize+ is set to <tt>:lower</tt> then +camelize+ produces
|
85
|
+
# lowerCamelCase.
|
86
|
+
#
|
87
|
+
# +camelize+ will also convert '/' to '::' which is useful for converting
|
88
|
+
# paths to namespaces.
|
89
|
+
#
|
90
|
+
# 'active_model'.camelize # => "ActiveModel"
|
91
|
+
# 'active_model'.camelize(:lower) # => "activeModel"
|
92
|
+
# 'active_model/errors'.camelize # => "ActiveModel::Errors"
|
93
|
+
# 'active_model/errors'.camelize(:lower) # => "activeModel::Errors"
|
94
|
+
#
|
95
|
+
# As a rule of thumb you can think of +camelize+ as the inverse of
|
96
|
+
# +underscore+, though there are cases where that does not hold:
|
97
|
+
#
|
98
|
+
# 'SSLError'.underscore.camelize # => "SslError"
|
99
|
+
def camelize(term)
|
100
|
+
string = term.to_s
|
101
|
+
string.capitalize!
|
102
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
103
|
+
string.gsub!('/', '::')
|
104
|
+
string
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module GrapeDoc
|
2
|
+
class ApiDocParts
|
3
|
+
|
4
|
+
class StringBasic < String
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def markdown=(obj)
|
8
|
+
@markdown=obj
|
9
|
+
end
|
10
|
+
def markdown
|
11
|
+
@markdown || self.to_s.split('::')[-1].downcase
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
args[0] = Parser.parse(args[0])
|
17
|
+
self.replace(args[0])
|
18
|
+
end
|
19
|
+
|
20
|
+
def markdown
|
21
|
+
self.class.markdown
|
22
|
+
end
|
23
|
+
|
24
|
+
alias to_textile to_s
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class StringObject < StringBasic
|
29
|
+
|
30
|
+
def to_textile
|
31
|
+
"#{markdown}. #{self.to_s}\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class StringObjectEnded < StringObject
|
37
|
+
|
38
|
+
def to_textile
|
39
|
+
"#{markdown}#{self}#{markdown}\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class ArrayObject < Array
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def markdown=(obj)
|
48
|
+
@markdown=obj
|
49
|
+
end
|
50
|
+
def markdown
|
51
|
+
@markdown || self.to_s.downcase
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(object)
|
56
|
+
object = Parser.parse(object)
|
57
|
+
self.replace(object)
|
58
|
+
end
|
59
|
+
|
60
|
+
def markdown
|
61
|
+
self.class.markdown
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_textile
|
65
|
+
self.map{|e|
|
66
|
+
case e
|
67
|
+
|
68
|
+
when ArrayObject
|
69
|
+
e.map{|e|
|
70
|
+
|
71
|
+
text = if e.respond_to?(:to_textile)
|
72
|
+
e.to_textile
|
73
|
+
else
|
74
|
+
e.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
"#{markdown}#{markdown} #{text}"
|
78
|
+
|
79
|
+
}.join("\n")
|
80
|
+
|
81
|
+
else
|
82
|
+
"#{markdown} #{e}"
|
83
|
+
|
84
|
+
end
|
85
|
+
}.push('').join("\n")
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
data/lib/grape-doc.rb
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
require '
|
1
|
+
require 'loader'
|
2
|
+
require_relative_directory_r 'grape/doc'
|
data/test/sample.html
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
<h1>Rest Api Documentation (grape-doc)</h1>
|
2
|
+
<h2><span class="caps">GET</span>: /hello(.:format)</h2>
|
3
|
+
<h3>Request</h3>
|
4
|
+
<h4>description</h4>
|
5
|
+
<ul>
|
6
|
+
<li>Hello world!</li>
|
7
|
+
</ul>
|
8
|
+
<h4>params</h4>
|
9
|
+
<ul>
|
10
|
+
<li>test
|
11
|
+
<ul>
|
12
|
+
<li>required: false</li>
|
13
|
+
<li>type: String</li>
|
14
|
+
<li>desc: it’s a test string</li>
|
15
|
+
</ul></li>
|
16
|
+
</ul>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
describe 'Doc generating' do
|
3
|
+
|
4
|
+
specify 'test documentation generator' do
|
5
|
+
|
6
|
+
var = GrapeDoc.new
|
7
|
+
puts var.document.to_textile
|
8
|
+
File.write File.join(RackTestPoc.root,'test','sample.html'),
|
9
|
+
var.document.to_textile.to_html
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'grape'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rack/test/poc'
|
4
|
+
|
5
|
+
require 'grape-doc'
|
6
|
+
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
class TestAPI1 < Grape::API
|
10
|
+
|
11
|
+
version 'v1', using: :accept_version_header
|
12
|
+
|
13
|
+
default_format :txt
|
14
|
+
format :json
|
15
|
+
|
16
|
+
content_type :txt, 'application/text'
|
17
|
+
content_type :json, 'application/json'
|
18
|
+
|
19
|
+
desc 'Hello world!'
|
20
|
+
params do
|
21
|
+
optional :test,
|
22
|
+
type: String,
|
23
|
+
desc: 'it\'s a test string'
|
24
|
+
|
25
|
+
end
|
26
|
+
get 'hello' do
|
27
|
+
{hello: "world!"}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class TestAPI2 < TestAPI1
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
describe 'Object Space Collector' do
|
3
|
+
|
4
|
+
specify 'test that there will be api classes on calling each_grape_class' do
|
5
|
+
GrapeDoc::Helpers.each_grape_class do |api_class|
|
6
|
+
api_class.must_be_instance_of Class
|
7
|
+
(api_class < Grape::API).must_be :==, true
|
8
|
+
|
9
|
+
api_class.respond_to?(:routes).must_be :==, true
|
10
|
+
api_class.routes.respond_to?(:each).must_be :==, true
|
11
|
+
|
12
|
+
api_class.routes.each do |r|
|
13
|
+
r.route_method.must_be_instance_of String
|
14
|
+
r.route_path.must_be_instance_of String
|
15
|
+
r.route_params.must_be_instance_of Hash
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|