rails_api_explorer 0.0.1.pre.1 → 0.0.2.pre.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 +4 -4
- data/README.md +96 -0
- data/app/assets/javascripts/api_explorer/application.js +1 -0
- data/app/assets/javascripts/api_explorer/explorer.js +79 -136
- data/app/assets/javascripts/api_explorer/scroll.js +1 -0
- data/app/assets/javascripts/api_explorer/serialize_object.js +54 -0
- data/app/assets/stylesheets/api_explorer/explorer.css +40 -66
- data/app/views/api_explorer/explorer/index.html.erb +18 -16
- data/lib/api_explorer/version.rb +1 -1
- metadata +33 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92e109fe3ecbff439ba1527c91138e8aea97cae1
|
4
|
+
data.tar.gz: 6ae0e546fab6cb707335daaefe25c6b496658eaa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5941e240df85be5594187045bed33bda332cda60ca1d5115a118eaa09b1ff2724a74be737c22c544fa93b67ab3902abc7c0aee04783c4490cd5e0b2bc31bcde5
|
7
|
+
data.tar.gz: 6a201c1994bd8100f41e6f700e669003c2b2ceae847ccd4c1974f719292f56e8c08179571cb44d26b104900f2a5aea17a831bfc8040297d391c78f1edd11649b
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# rails_api_explorer
|
2
|
+
|
3
|
+
Provides a simple DSL to describe your API, and let's you mount an interactive sandbox to explore and test it.
|
4
|
+
|
5
|
+
[Here's a demo.](http://rails-api-explorer.herokuapp.com)
|
6
|
+
|
7
|
+
This project is in the early stages of development and missing some features. Pull requests are more than welcome!
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'rails_api_explorer'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Describe your API in `config/initializers/api_explorer.rb`:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
ApiExplorer.describe do
|
27
|
+
base_url 'http://localhost:3000/api/'
|
28
|
+
|
29
|
+
shared do
|
30
|
+
header 'X-AUTH-TOKEN', source: { request: "POST:users/sign_in", accessor: "['auth_token']"}
|
31
|
+
# The source option makes the value get set automatically when a request to the given url succeeds.
|
32
|
+
# The accessor is evaluated on the JSON object returned by the server.
|
33
|
+
end
|
34
|
+
|
35
|
+
post 'users/sign_in' do
|
36
|
+
desc "Authenticate a user, returns the auth token. Anything except blank values will work for this example."
|
37
|
+
|
38
|
+
exclude_shared_header 'X-AUTH-TOKEN'
|
39
|
+
|
40
|
+
struct 'user_login' do
|
41
|
+
string 'email'
|
42
|
+
string 'password'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
group "Posts" do
|
47
|
+
get 'posts'
|
48
|
+
|
49
|
+
get 'posts/:id' do
|
50
|
+
desc "Returns details for a single post."
|
51
|
+
end
|
52
|
+
|
53
|
+
post 'posts' do
|
54
|
+
desc "Create a post."
|
55
|
+
struct 'post' do
|
56
|
+
string 'title', desc: "Required."
|
57
|
+
string 'body'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
patch 'posts/:id' do
|
62
|
+
struct 'post' do
|
63
|
+
string 'title', desc: "Required."
|
64
|
+
string 'body'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
Then mount it in your `routes.rb`:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
mount ApiExplorer::Engine => '/api/explore', as: 'api_explorer'
|
75
|
+
```
|
76
|
+
|
77
|
+
|
78
|
+
If you don't want the public to access the explorer, you can provide a lambda that will be executed in the `before_filter` of the controller:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
ApiExplorer.auth = lambda do
|
82
|
+
authenticate_user!
|
83
|
+
current_user.admin? or redirect_to main_app.root_path
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
The explorer is rendered within your application layout and uses bootstrap 3 classes, so it's prettier if you have that included.
|
88
|
+
Bootstrap is optional, but it requires jQuery.
|
89
|
+
|
90
|
+
## Contributing
|
91
|
+
|
92
|
+
1. Fork it
|
93
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
94
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
95
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
96
|
+
5. Create a new Pull Request
|
@@ -1,146 +1,89 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
// Generated by CoffeeScript 1.4.0
|
2
|
+
(function() {
|
3
3
|
|
4
|
+
$(function() {
|
5
|
+
var setValuesFromRequest, updateShareds;
|
6
|
+
$(".hidden").hide().removeClass("hidden");
|
4
7
|
window.responses = {};
|
5
|
-
|
6
8
|
$(".shared-input.header").change(function() {
|
7
|
-
|
8
|
-
});
|
9
|
-
$(".shared-link").click(function() {
|
10
|
-
$($(this).attr("href")).find("input").focus();
|
9
|
+
return updateShareds();
|
11
10
|
});
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
updateShareds = function() {
|
12
|
+
return $(".shared-input.header").each(function() {
|
13
|
+
var name;
|
14
|
+
name = $(this).attr("data-name");
|
15
|
+
return $(".shared.header[data-name=" + name + "]").val($(this).val());
|
16
|
+
});
|
17
|
+
};
|
18
|
+
setValuesFromRequest = function(request) {
|
19
|
+
$("[data-source-request='" + request + "']").each(function(input) {
|
20
|
+
var v;
|
21
|
+
v = eval("responses['" + request + "']" + $(this).attr("data-source-accessor"));
|
22
|
+
return $(this).val(v);
|
23
|
+
});
|
24
|
+
return updateShareds();
|
25
|
+
};
|
26
|
+
$(".param input").prop("disabled", false);
|
27
|
+
$(".send-toggle").click(function(event) {
|
28
|
+
var param, send, setState;
|
29
|
+
event.preventDefault();
|
30
|
+
setState = function(elements, state) {
|
31
|
+
return elements.each(function(i, el) {
|
32
|
+
$(el).attr("data-send", state ? "true" : "false");
|
33
|
+
$(el).find("input").first().prop("disabled", !state);
|
34
|
+
$(el).find(".send-toggle").first().text(state ? "don't send" : "send");
|
35
|
+
return $(el).find(".name").first().toggleClass("strikethrough", !state);
|
17
36
|
});
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
37
|
+
};
|
38
|
+
param = $(this).closest(".param");
|
39
|
+
send = param.attr("data-send") !== "true";
|
40
|
+
setState(param.add(param.find(".param")), send);
|
41
|
+
if (send) {
|
42
|
+
return setState(param.parents(".param"), true);
|
43
|
+
}
|
44
|
+
});
|
45
|
+
return $("form").submit(function(event) {
|
46
|
+
var form, path, req;
|
47
|
+
event.preventDefault();
|
48
|
+
form = $(this);
|
49
|
+
req = form.serializeObject().request;
|
50
|
+
form.closest(".request").find(".status").html("Requesting...");
|
51
|
+
path = req.path;
|
52
|
+
if (req.url_params) {
|
53
|
+
$.each(req.url_params, function(p, v) {
|
54
|
+
return path = path.replace(":" + p, v);
|
24
55
|
});
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
var
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
56
|
+
}
|
57
|
+
return $.ajax({
|
58
|
+
url: path,
|
59
|
+
type: req.method,
|
60
|
+
headers: req.headers,
|
61
|
+
data: req.params,
|
62
|
+
dataType: 'json'
|
63
|
+
}).always(function(data, status, error) {
|
64
|
+
var code, key;
|
65
|
+
if (status === 'success') {
|
66
|
+
code = 200;
|
67
|
+
key = req.method.toUpperCase() + ":" + req.path.replace(api_explorer_base_url, "");
|
68
|
+
window.responses[key] = data;
|
69
|
+
setValuesFromRequest(key);
|
70
|
+
} else {
|
71
|
+
code = data.status;
|
72
|
+
try {
|
73
|
+
data = $.parseJSON(data.responseText);
|
74
|
+
} catch (SyntaxError) {
|
75
|
+
|
76
|
+
}
|
40
77
|
}
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
});
|
48
|
-
|
49
|
-
$("form").submit(function(event) {
|
50
|
-
event.preventDefault();
|
51
|
-
|
52
|
-
var form = $(this);
|
53
|
-
var req = form.serializeObject().request;
|
54
|
-
form.closest(".request").find(".status").html("Requesting...");
|
55
|
-
|
56
|
-
path = req.path;
|
57
|
-
if (req.url_params) {
|
58
|
-
$.each(req.url_params, function(p, v) {
|
59
|
-
path = path.replace(":" + p, v);
|
60
|
-
});
|
78
|
+
if (code === 0) {
|
79
|
+
form.closest(".request").find(".status").text("Can't reach server");
|
80
|
+
return form.closest(".request").find(".response").hide();
|
81
|
+
} else {
|
82
|
+
form.closest(".request").find(".status").text(code);
|
83
|
+
return form.closest(".request").find(".response").text(JSON.stringify(data, null, 4)).show();
|
61
84
|
}
|
62
|
-
|
63
|
-
$.ajax({
|
64
|
-
url: path,
|
65
|
-
type: req.method,
|
66
|
-
headers: req.headers,
|
67
|
-
data: req.params,
|
68
|
-
dataType: 'json'
|
69
|
-
}).always(function(data, status, error) {
|
70
|
-
if(status == 'success') {
|
71
|
-
code = 200;
|
72
|
-
var key = req.method.toUpperCase() + ":" + req.path.replace(api_explorer_base_url, "");
|
73
|
-
window.responses[key] = data;
|
74
|
-
setValuesFromRequest(key);
|
75
|
-
} else {
|
76
|
-
code = data.status;
|
77
|
-
try {
|
78
|
-
data = $.parseJSON(data.responseText);
|
79
|
-
} catch(SyntaxError) {}
|
80
|
-
}
|
81
|
-
if (code == 0) {
|
82
|
-
form.closest(".request").find(".status").text("Can't reach server");
|
83
|
-
form.closest(".request").find(".response").hide();
|
84
|
-
} else {
|
85
|
-
form.closest(".request").find(".status").text(code);
|
86
|
-
form.closest(".request").find(".response").text(JSON.stringify(data, null, 4)).show();
|
87
|
-
}
|
88
|
-
});
|
85
|
+
});
|
89
86
|
});
|
87
|
+
});
|
90
88
|
|
91
|
-
|
92
|
-
$.fn.serializeObject = function() {
|
93
|
-
var self = this,
|
94
|
-
json = {},
|
95
|
-
push_counters = {},
|
96
|
-
patterns = {
|
97
|
-
"validate": /^[a-zA-Z][a-zA-Z0-9_\-]*(?:\[(?:\d*|[a-zA-Z0-9_\-]+)\])*$/,
|
98
|
-
"key": /[a-zA-Z0-9_\-]+|(?=\[\])/g,
|
99
|
-
"push": /^$/,
|
100
|
-
"fixed": /^\d+$/,
|
101
|
-
"named": /^[a-zA-Z0-9_\-]+$/
|
102
|
-
};
|
103
|
-
|
104
|
-
this.build = function(base, key, value){
|
105
|
-
base[key] = value;
|
106
|
-
return base;
|
107
|
-
};
|
108
|
-
this.push_counter = function(key){
|
109
|
-
if(push_counters[key] === undefined){
|
110
|
-
push_counters[key] = 0;
|
111
|
-
}
|
112
|
-
return push_counters[key]++;
|
113
|
-
};
|
114
|
-
$.each($(this).serializeArray(), function(){
|
115
|
-
// skip invalid keys
|
116
|
-
if(!patterns.validate.test(this.name)) {
|
117
|
-
return;
|
118
|
-
}
|
119
|
-
var k,
|
120
|
-
keys = this.name.match(patterns.key),
|
121
|
-
merge = this.value,
|
122
|
-
reverse_key = this.name;
|
123
|
-
|
124
|
-
while((k = keys.pop()) !== undefined){
|
125
|
-
|
126
|
-
// adjust reverse_key
|
127
|
-
reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');
|
128
|
-
|
129
|
-
// push
|
130
|
-
if(k.match(patterns.push)){
|
131
|
-
merge = self.build([], self.push_counter(reverse_key), merge);
|
132
|
-
}
|
133
|
-
// fixed
|
134
|
-
else if(k.match(patterns.fixed)){
|
135
|
-
merge = self.build([], k, merge);
|
136
|
-
}
|
137
|
-
// named
|
138
|
-
else if(k.match(patterns.named)){
|
139
|
-
merge = self.build({}, k, merge);
|
140
|
-
}
|
141
|
-
}
|
142
|
-
json = $.extend(true, json, merge);
|
143
|
-
});
|
144
|
-
return json;
|
145
|
-
};
|
146
|
-
});
|
89
|
+
}).call(this);
|
@@ -0,0 +1,54 @@
|
|
1
|
+
$.fn.serializeObject = function() {
|
2
|
+
var self = this,
|
3
|
+
json = {},
|
4
|
+
push_counters = {},
|
5
|
+
patterns = {
|
6
|
+
"validate": /^[a-zA-Z][a-zA-Z0-9_\-]*(?:\[(?:\d*|[a-zA-Z0-9_\-]+)\])*$/,
|
7
|
+
"key": /[a-zA-Z0-9_\-]+|(?=\[\])/g,
|
8
|
+
"push": /^$/,
|
9
|
+
"fixed": /^\d+$/,
|
10
|
+
"named": /^[a-zA-Z0-9_\-]+$/
|
11
|
+
};
|
12
|
+
|
13
|
+
this.build = function(base, key, value){
|
14
|
+
base[key] = value;
|
15
|
+
return base;
|
16
|
+
};
|
17
|
+
this.push_counter = function(key){
|
18
|
+
if(push_counters[key] === undefined){
|
19
|
+
push_counters[key] = 0;
|
20
|
+
}
|
21
|
+
return push_counters[key]++;
|
22
|
+
};
|
23
|
+
$.each($(this).serializeArray(), function(){
|
24
|
+
// skip invalid keys
|
25
|
+
if(!patterns.validate.test(this.name)) {
|
26
|
+
return;
|
27
|
+
}
|
28
|
+
var k,
|
29
|
+
keys = this.name.match(patterns.key),
|
30
|
+
merge = this.value,
|
31
|
+
reverse_key = this.name;
|
32
|
+
|
33
|
+
while((k = keys.pop()) !== undefined){
|
34
|
+
|
35
|
+
// adjust reverse_key
|
36
|
+
reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');
|
37
|
+
|
38
|
+
// push
|
39
|
+
if(k.match(patterns.push)){
|
40
|
+
merge = self.build([], self.push_counter(reverse_key), merge);
|
41
|
+
}
|
42
|
+
// fixed
|
43
|
+
else if(k.match(patterns.fixed)){
|
44
|
+
merge = self.build([], k, merge);
|
45
|
+
}
|
46
|
+
// named
|
47
|
+
else if(k.match(patterns.named)){
|
48
|
+
merge = self.build({}, k, merge);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
json = $.extend(true, json, merge);
|
52
|
+
});
|
53
|
+
return json;
|
54
|
+
};
|
@@ -1,70 +1,44 @@
|
|
1
|
-
.hidden {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
}
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
25
|
-
|
26
|
-
legend {
|
27
|
-
margin-bottom: 5px;
|
28
|
-
}
|
29
|
-
.param-inputs legend {
|
30
|
-
font-size: 100%;
|
31
|
-
border: none;
|
32
|
-
margin-bottom: 0;
|
33
|
-
}
|
34
|
-
label {
|
35
|
-
font-weight: normal;
|
36
|
-
margin-bottom: 0;
|
37
|
-
}
|
38
|
-
|
39
|
-
.response {
|
1
|
+
.api-explorer .hidden {
|
2
|
+
display: none; }
|
3
|
+
.api-explorer .params .params {
|
4
|
+
margin-left: 30px; }
|
5
|
+
.api-explorer .param-inputs .param-inputs {
|
6
|
+
margin-left: 30px; }
|
7
|
+
.api-explorer .param-inputs fieldset {
|
8
|
+
border: none;
|
9
|
+
padding: 0; }
|
10
|
+
.api-explorer .param-inputs input {
|
11
|
+
border: none; }
|
12
|
+
.api-explorer h3 input {
|
13
|
+
border: none;
|
14
|
+
width: 120px;
|
15
|
+
text-align: center; }
|
16
|
+
.api-explorer legend {
|
17
|
+
margin-bottom: 5px; }
|
18
|
+
.api-explorer .param-inputs legend {
|
19
|
+
font-size: 100%;
|
20
|
+
border: none;
|
21
|
+
margin-bottom: 0; }
|
22
|
+
.api-explorer label {
|
23
|
+
font-weight: normal;
|
24
|
+
margin-bottom: 0; }
|
25
|
+
.api-explorer .response {
|
40
26
|
border: solid 1px black;
|
41
27
|
background-color: #CCC;
|
42
28
|
padding: 20px;
|
43
29
|
max-height: 400px;
|
44
|
-
overflow: scroll;
|
45
|
-
|
46
|
-
|
47
|
-
.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
.send-toggle {
|
60
|
-
font-size: 80%;
|
61
|
-
cursor: pointer;
|
62
|
-
display: none;
|
63
|
-
}
|
64
|
-
:hover > .send-toggle {
|
65
|
-
display: inline;
|
66
|
-
}
|
67
|
-
|
68
|
-
.strikethrough {
|
69
|
-
text-decoration: line-through;
|
70
|
-
}
|
30
|
+
overflow: scroll; }
|
31
|
+
.api-explorer .description {
|
32
|
+
font-size: 80%; }
|
33
|
+
.api-explorer fieldset {
|
34
|
+
margin-bottom: 5px; }
|
35
|
+
.api-explorer legend, .api-explorer label {
|
36
|
+
position: relative; }
|
37
|
+
.api-explorer .send-toggle {
|
38
|
+
font-size: 80%;
|
39
|
+
cursor: pointer;
|
40
|
+
display: none; }
|
41
|
+
.api-explorer :hover > .send-toggle {
|
42
|
+
display: inline; }
|
43
|
+
.api-explorer .strikethrough {
|
44
|
+
text-decoration: line-through; }
|
@@ -1,20 +1,22 @@
|
|
1
|
-
<
|
2
|
-
|
3
|
-
|
1
|
+
<div class="api-explorer">
|
2
|
+
<script type="text/javascript">
|
3
|
+
window.api_explorer_base_url = "<%= @description.base_url %>";
|
4
|
+
</script>
|
4
5
|
|
5
|
-
<%= stylesheet_link_tag "api_explorer/application", media: "all" %>
|
6
|
-
<%= javascript_include_tag "api_explorer/application" %>
|
6
|
+
<%= stylesheet_link_tag "api_explorer/application", media: "all" %>
|
7
|
+
<%= javascript_include_tag "api_explorer/application" %>
|
7
8
|
|
8
|
-
<div class="row">
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
<div class="row">
|
10
|
+
<div class="col-sm-12">
|
11
|
+
<h1>Index</h1>
|
12
|
+
<ul class="contents">
|
13
|
+
<% @description.children.each_with_index do |ch, i| %>
|
14
|
+
<%= render 'content_node', node: ch, id: i %>
|
15
|
+
<% end %>
|
16
|
+
</ul>
|
17
|
+
</div>
|
16
18
|
</div>
|
17
|
-
</div>
|
18
19
|
|
19
|
-
<%= render 'shared' %>
|
20
|
-
<%= render 'node', node: @description, id: "", depth: 0 %>
|
20
|
+
<%= render 'shared' %>
|
21
|
+
<%= render 'node', node: @description, id: "", depth: 0 %>
|
22
|
+
</div>
|
data/lib/api_explorer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_api_explorer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Hollmann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coffee-script
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sass
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
description: ''
|
56
84
|
email:
|
57
85
|
- maxhollmann@gmail.com
|
@@ -60,10 +88,12 @@ extensions: []
|
|
60
88
|
extra_rdoc_files: []
|
61
89
|
files:
|
62
90
|
- MIT-LICENSE
|
91
|
+
- README.md
|
63
92
|
- Rakefile
|
64
93
|
- app/assets/javascripts/api_explorer/application.js
|
65
94
|
- app/assets/javascripts/api_explorer/explorer.js
|
66
95
|
- app/assets/javascripts/api_explorer/scroll.js
|
96
|
+
- app/assets/javascripts/api_explorer/serialize_object.js
|
67
97
|
- app/assets/stylesheets/api_explorer/application.css
|
68
98
|
- app/assets/stylesheets/api_explorer/explorer.css
|
69
99
|
- app/controllers/api_explorer/application_controller.rb
|
@@ -121,6 +151,6 @@ rubyforge_project:
|
|
121
151
|
rubygems_version: 2.2.2
|
122
152
|
signing_key:
|
123
153
|
specification_version: 4
|
124
|
-
summary: Provides a simple DSL to describe your API, and let's you mount an interactive
|
154
|
+
summary: Provides a simple DSL to describe your JSON API, and let's you mount an interactive
|
125
155
|
sandbox to explore and test it.
|
126
156
|
test_files: []
|