rails_api_explorer 0.0.1.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +23 -0
  4. data/app/assets/javascripts/api_explorer/application.js +15 -0
  5. data/app/assets/javascripts/api_explorer/explorer.js +146 -0
  6. data/app/assets/javascripts/api_explorer/scroll.js +38 -0
  7. data/app/assets/stylesheets/api_explorer/application.css +15 -0
  8. data/app/assets/stylesheets/api_explorer/explorer.css +70 -0
  9. data/app/controllers/api_explorer/application_controller.rb +5 -0
  10. data/app/controllers/api_explorer/explorer_controller.rb +9 -0
  11. data/app/helpers/api_explorer/application_helper.rb +4 -0
  12. data/app/helpers/api_explorer/explorer_helper.rb +4 -0
  13. data/app/views/api_explorer/explorer/_content_node.html.erb +12 -0
  14. data/app/views/api_explorer/explorer/_node.html.erb +17 -0
  15. data/app/views/api_explorer/explorer/_params.html.erb +14 -0
  16. data/app/views/api_explorer/explorer/_request.html.erb +39 -0
  17. data/app/views/api_explorer/explorer/_shared.html.erb +12 -0
  18. data/app/views/api_explorer/explorer/form/_headers.html.erb +25 -0
  19. data/app/views/api_explorer/explorer/form/_param.html.erb +28 -0
  20. data/app/views/api_explorer/explorer/form/_params.html.erb +7 -0
  21. data/app/views/api_explorer/explorer/form/_url_params.html.erb +13 -0
  22. data/app/views/api_explorer/explorer/index.html.erb +20 -0
  23. data/app/views/api_explorer/explorer/perform_request.html.erb +1 -0
  24. data/config/routes.rb +4 -0
  25. data/lib/api_explorer/description.rb +7 -0
  26. data/lib/api_explorer/dsl/base_proxy.rb +13 -0
  27. data/lib/api_explorer/dsl/description_proxy.rb +7 -0
  28. data/lib/api_explorer/dsl/group_proxy.rb +44 -0
  29. data/lib/api_explorer/dsl/request_proxy.rb +41 -0
  30. data/lib/api_explorer/dsl.rb +4 -0
  31. data/lib/api_explorer/engine.rb +5 -0
  32. data/lib/api_explorer/group.rb +18 -0
  33. data/lib/api_explorer/header.rb +10 -0
  34. data/lib/api_explorer/node.rb +30 -0
  35. data/lib/api_explorer/parameter.rb +16 -0
  36. data/lib/api_explorer/request.rb +37 -0
  37. data/lib/api_explorer/version.rb +3 -0
  38. data/lib/api_explorer.rb +19 -0
  39. data/lib/rails_api_explorer.rb +1 -0
  40. data/lib/tasks/api_explorer_tasks.rake +4 -0
  41. metadata +126 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 072d32c87b27d505bb62ce22a1d491668db4e48d
4
+ data.tar.gz: ae39b35ef35b5ddf691b3a3dfcd3fcfa8e5f1841
5
+ SHA512:
6
+ metadata.gz: f447e761837f2647ab0bd4dc022d6f044185ffed149547581c5e14973878cf56c2637943cf75fddda2375034fd97e2dd298995be235ea2b77235661d94bfc079
7
+ data.tar.gz: 976d4f7a37d9fe5d215a0ed0896cae9f6e58f038015dda0f7b22e7be61da777b36aeca76903b07aa6a9cc0058a9b4abe9716dab7ba0a8fc7acdd6271d07094a6
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ApiExplorer'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,146 @@
1
+ $(function() {
2
+ $(".hidden").hide().removeClass("hidden");
3
+
4
+ window.responses = {};
5
+
6
+ $(".shared-input.header").change(function() {
7
+ updateShareds();
8
+ });
9
+ $(".shared-link").click(function() {
10
+ $($(this).attr("href")).find("input").focus();
11
+ });
12
+
13
+ function updateShareds() {
14
+ $(".shared-input.header").each(function() {
15
+ name = $(this).attr("data-name");
16
+ $(".shared.header[data-name=" + name + "]").val($(this).val());
17
+ });
18
+ }
19
+
20
+ function setValuesFromRequest(request) {
21
+ $("[data-source-request='" + request + "']").each(function(input) {
22
+ v = eval("responses['" + request + "']" + $(this).attr("data-source-accessor"));
23
+ $(this).val(v);
24
+ });
25
+ updateShareds();
26
+ }
27
+
28
+ // Enable / disable params
29
+ $(".param input").prop("disabled", false); // Firefox autocomplete workaround
30
+ $(".send-toggle").click(function(event) {
31
+ event.preventDefault();
32
+
33
+ var setState = function(elements, state) {
34
+ elements.each(function(i, el) {
35
+ $(el).attr("data-send", state ? "true" : "false");
36
+ $(el).find("input").first().prop("disabled", !state);
37
+ $(el).find(".send-toggle").first().text(state ? "don't send" : "send");
38
+ $(el).find(".name").first().toggleClass("strikethrough", !state);
39
+ });
40
+ }
41
+
42
+ var param = $(this).closest(".param");
43
+ var send = param.attr("data-send") == "true" ? false : true;
44
+ setState(param.add(param.find(".param")), send); // enable or disable children
45
+ if (send)
46
+ setState(param.parents(".param"), true); // enable parents
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
+ });
61
+ }
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
+ });
89
+ });
90
+
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
+ });
@@ -0,0 +1,38 @@
1
+ $(function() {
2
+ /**
3
+ * Check a href for an anchor. If exists, and in document, scroll to it.
4
+ * If href argument ommited, assumes context (this) is HTML Element,
5
+ * which will be the case when invoked by jQuery after an event
6
+ */
7
+ function scroll_if_anchor(href) {
8
+ href = typeof(href) == "string" ? href : $(this).attr("href");
9
+
10
+ var fromTop = 0;
11
+
12
+ if ($(".navbar-fixed-top").length > 0) {
13
+ fromTop = $(".navbar-fixed-top").height();
14
+ }
15
+
16
+ // If our Href points to a valid, non-empty anchor, and is on the same page (e.g. #foo)
17
+ // Legacy jQuery and IE7 may have issues: http://stackoverflow.com/q/1593174
18
+ if(href.indexOf("#") == 0) {
19
+ var $target = $(href);
20
+
21
+ // Older browser without pushState might flicker here, as they momentarily
22
+ // jump to the wrong position (IE < 10)
23
+ if($target.length) {
24
+ $('html, body').animate({ scrollTop: $target.offset().top - fromTop });
25
+ if(history && "pushState" in history) {
26
+ history.pushState({}, document.title, window.location.pathname + href);
27
+ return false;
28
+ }
29
+ }
30
+ }
31
+ }
32
+
33
+ // When our page loads, check to see if it contains and anchor
34
+ scroll_if_anchor(window.location.hash);
35
+
36
+ // Intercept all anchor clicks
37
+ $("body").on("click", "a", scroll_if_anchor);
38
+ });
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,70 @@
1
+ .hidden {
2
+ display: none;
3
+ }
4
+
5
+ .params .params {
6
+ margin-left: 30px;
7
+ }
8
+
9
+ .param-inputs .param-inputs {
10
+ margin-left: 30px;
11
+ }
12
+
13
+ .param-inputs fieldset {
14
+ border: none;
15
+ padding: 0;
16
+ }
17
+ .param-inputs input {
18
+ border: none;
19
+ }
20
+ h3 input {
21
+ border: none;
22
+ width: 120px;
23
+ text-align: center;
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 {
40
+ border: solid 1px black;
41
+ background-color: #CCC;
42
+ padding: 20px;
43
+ max-height: 400px;
44
+ overflow: scroll;
45
+ }
46
+
47
+ .description {
48
+ font-size: 80%;
49
+ }
50
+
51
+ fieldset {
52
+ margin-bottom: 5px;
53
+ }
54
+
55
+ legend, label {
56
+ position: relative;
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
+ }
@@ -0,0 +1,5 @@
1
+ class ApiExplorer::ApplicationController < ApplicationController
2
+ before_filter do
3
+ instance_eval(&ApiExplorer.auth) if ApiExplorer.auth
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ require_dependency "api_explorer/application_controller"
2
+
3
+ module ApiExplorer
4
+ class ExplorerController < ApplicationController
5
+ def index
6
+ @description = ApiExplorer.description
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module ApiExplorer
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApiExplorer
2
+ module ExplorerHelper
3
+ end
4
+ end
@@ -0,0 +1,12 @@
1
+ <li>
2
+ <% if node.is_a?(ApiExplorer::Request) %>
3
+ <a href="#node-<%= id %>"><%= node.title %></a>
4
+ <% else %>
5
+ <a href="#node-<%= id %>"><%= node.title %></a>
6
+ <ul class="children">
7
+ <% node.children.each_with_index do |ch, i| %>
8
+ <%= render 'content_node', node: ch, id: "#{id}-#{i}" %>
9
+ <% end %>
10
+ </ul>
11
+ <% end %>
12
+ </li>
@@ -0,0 +1,17 @@
1
+ <% node.children.each_with_index do |ch, i| %>
2
+ <% if ch.is_a?(ApiExplorer::Request) %>
3
+ <%= render 'request', req: ch, id: "#{id}-#{i}", depth: depth + 1 %>
4
+ <% else %>
5
+ <div class="group row" id="node<%= id %>-<%= i %>">
6
+ <div class="col-sm-12">
7
+ <% header_n = [1 + depth, 2].min %>
8
+ <h<%= header_n %>><%= ch.title %></h<%= header_n %>>
9
+ <% if ch.children.any? %>
10
+ <div class="children">
11
+ <%= render 'node', id: "#{id}-#{i}", node: ch, depth: depth + 1 %>
12
+ </div>
13
+ <% end %>
14
+ </div>
15
+ </div>
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <div class="params">
2
+ <% params.each do |param| %>
3
+ <div class="param">
4
+ <%= param.name %>:
5
+ <% if param.type == :hash %>
6
+ {
7
+ <%= render 'params', params: param.children %>
8
+ }
9
+ <% else %>
10
+ <small><%= param.type %></small>
11
+ <% end %>
12
+ </div>
13
+ <% end %>
14
+ </div>
@@ -0,0 +1,39 @@
1
+ <div class="row request" id="node<%= id %>">
2
+ <%= form_for :request, url: request_path, html: { class: "col-sm-6" } do |f| %>
3
+ <%= f.hidden_field :method, value: req.method %>
4
+ <%= f.hidden_field :path, value: req.full_path %>
5
+
6
+ <%= f.fields_for :url_params do |pf| %>
7
+ <h3>
8
+ <%= req.method.to_s.upcase %>
9
+ <% req.url_segments.each do |type, s| %>
10
+ <% if type == :param %>
11
+ <%= pf.text_field s, placeholder: ":#{s}" %>
12
+ <!-- span contenteditable="true" data-ph="<%= ":#{s}" %>" data-name="<%= s %>"></span -->
13
+ <% else %>
14
+ <%= raw s %>
15
+ <% end %>
16
+ <% end %>
17
+ </h3>
18
+ <% end %>
19
+
20
+ <div>
21
+ <p><%= simple_format req.description %></p>
22
+
23
+ <!-- %= render 'api_explorer/explorer/form/url_params', params: req.url_params, f: f % -->
24
+ <%= render 'api_explorer/explorer/form/headers', request: req, f: f %>
25
+ <% if req.params.any? %>
26
+ <fieldset>
27
+ <legend>Parameters</legend>
28
+ <%= render 'api_explorer/explorer/form/params', name: 'params', params: req.params, f: f %>
29
+ </fieldset>
30
+ <% end %>
31
+ <%= f.submit "Send", class: "btn btn-primary" %>
32
+ </div>
33
+ <% end %>
34
+
35
+ <div class="col-sm-6 output">
36
+ <p class="status"></p>
37
+ <pre class="response hidden"></pre>
38
+ </div>
39
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="row">
2
+ <div class="col-sm-12">
3
+ <h3>Shared headers</h3>
4
+
5
+ <% @description.headers.each do |h| %>
6
+ <div id="shared-header-<%= h.name %>">
7
+ <%= label_tag h.name, h.name %>:
8
+ <%= text_field_tag h.name, "", class: "shared-input header", data: { name: h.name, source_request: h.source[:request], source_accessor: h.source[:accessor] } %>
9
+ </div>
10
+ <% end %>
11
+ </div>
12
+ </div>
@@ -0,0 +1,25 @@
1
+ <% if request.excluded_shared_headers.any? %>
2
+ <p>Note: Does <strong>not</strong> use these shared headers: <%= request.excluded_shared_headers.join(", ") %>.</p>
3
+ <% end %>
4
+
5
+ <%= f.fields_for :headers do |hf| %>
6
+ <% @description.headers.each do |h| %>
7
+ <% next if request.excluded_shared_headers.include?(h.name) %>
8
+
9
+ <!--%= hf.label h.name, h.name %-->
10
+ <!--%= raw " (<a class='shared-link' href='#shared-header-#{h.name}'>shared</a>)" %-->
11
+ <%= hf.hidden_field h.name, class: "shared header", data: { name: h.name } %>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <% if request.headers.any? %>
16
+ <fieldset>
17
+ <legend>Headers</legend>
18
+ <%= f.fields_for :headers do |hf| %>
19
+ <% request.headers.each do |h| %>
20
+ <%= hf.label h.name, h.name + ":" %>
21
+ <%= hf.text_field h.name %>
22
+ <% end %>
23
+ <% end %>
24
+ </fieldset>
25
+ <% end %>
@@ -0,0 +1,28 @@
1
+ <div class="param" data-param-name="<%= p.name %>" data-send="true">
2
+ <% if p.type == :hash %>
3
+ <fieldset>
4
+ <legend>
5
+ <span class="name"><%= p.name %></span>:
6
+ {
7
+ <a class="send-toggle">don't send</a>
8
+ </legend>
9
+ <div class="description"><%= simple_format p.description %></div>
10
+ <div class="param-inputs">
11
+ <%= render 'api_explorer/explorer/form/params', name: p.name, params: p.params, f: f %>
12
+ </div>
13
+ }
14
+ </fieldset>
15
+ <% else %>
16
+ <%= f.label p.name do %>
17
+ <span class="name"><%= p.name %></span>:
18
+ <% end %>
19
+
20
+ <% if p.name == 'password' %>
21
+ <%= f.password_field p.name, placeholder: p.type %>
22
+ <% else %>
23
+ <%= f.text_field p.name, placeholder: p.type %>
24
+ <% end %>
25
+ <a class="send-toggle">don't send</a>
26
+ <div class="description"><%= p.description %></div>
27
+ <% end %>
28
+ </div>
@@ -0,0 +1,7 @@
1
+ <%= f.fields_for name do |pf| %>
2
+ <div class="param-inputs">
3
+ <% params.each do |p| %>
4
+ <%= render 'api_explorer/explorer/form/param', f: pf, p: p %>
5
+ <% end %>
6
+ </div>
7
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <% return if params.none? %>
2
+
3
+ <fieldset>
4
+ <legend>URL Parameters</legend>
5
+ <%= f.fields_for :url_params do |pf| %>
6
+ <% params.each do |p| %>
7
+ <p>
8
+ <%= pf.label p, p + ":" %>
9
+ <%= pf.text_field p %>
10
+ </p>
11
+ <% end %>
12
+ <% end %>
13
+ </fieldset>
@@ -0,0 +1,20 @@
1
+ <script type="text/javascript">
2
+ window.api_explorer_base_url = "<%= @description.base_url %>";
3
+ </script>
4
+
5
+ <%= stylesheet_link_tag "api_explorer/application", media: "all" %>
6
+ <%= javascript_include_tag "api_explorer/application" %>
7
+
8
+ <div class="row">
9
+ <div class="col-sm-12">
10
+ <h1>Index</h1>
11
+ <ul class="contents">
12
+ <% @description.children.each_with_index do |ch, i| %>
13
+ <%= render 'content_node', node: ch, id: i %>
14
+ <% end %>
15
+ </ul>
16
+ </div>
17
+ </div>
18
+
19
+ <%= render 'shared' %>
20
+ <%= render 'node', node: @description, id: "", depth: 0 %>
@@ -0,0 +1 @@
1
+ <%= raw ap @response %>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ ApiExplorer::Engine.routes.draw do
2
+ root to: 'explorer#index'
3
+ post 'request' => 'explorer#perform_request'
4
+ end
@@ -0,0 +1,7 @@
1
+ module ApiExplorer
2
+ class Description < Group
3
+ def base_url
4
+ path
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module ApiExplorer
2
+ class BaseProxy
3
+ attr_accessor :obj
4
+
5
+ def initialize(obj = nil)
6
+ self.obj = obj
7
+ end
8
+
9
+ def collect(&block)
10
+ instance_eval(&block)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module ApiExplorer
2
+ class DescriptionProxy < GroupProxy
3
+ def base_url(url)
4
+ path url
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,44 @@
1
+ module ApiExplorer
2
+ class GroupProxy < BaseProxy
3
+ def path(path = nil)
4
+ obj.path = path if path
5
+ obj.path
6
+ end
7
+
8
+ def group(title, &block)
9
+ group = Group.new(title)
10
+ proxy = GroupProxy.new(group)
11
+ proxy.collect(&block) if block_given?
12
+ obj.add_child group
13
+ end
14
+
15
+ def request(method, path, &block)
16
+ method = method.to_s.downcase.to_sym
17
+ req = Request.new(method, path)
18
+ proxy = RequestProxy.new(req)
19
+ proxy.collect(&block) if block_given?
20
+ obj.add_child req
21
+ end
22
+
23
+ def shared(&block)
24
+ proxy = RequestProxy.new(obj)
25
+ proxy.collect(&block)
26
+ end
27
+
28
+ def get(path, &block)
29
+ request(:get, path, &block)
30
+ end
31
+ def post(path, &block)
32
+ request(:post, path, &block)
33
+ end
34
+ def put(path, &block)
35
+ request(:put, path, &block)
36
+ end
37
+ def patch(path, &block)
38
+ request(:patch, path, &block)
39
+ end
40
+ def delete(path, &block)
41
+ request(:delete, path, &block)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ module ApiExplorer
2
+ class RequestProxy < BaseProxy
3
+ def exclude_shared_header(name)
4
+ obj.excluded_shared_headers << name
5
+ end
6
+
7
+ def desc(description)
8
+ obj.description = description
9
+ end
10
+
11
+ def param(name, type = nil, options = {}, &block)
12
+ desc = options.fetch(:desc, "")
13
+ if type.nil? && block_given?
14
+ param = Parameter.new(name, [], desc)
15
+ param.type = :hash
16
+ proxy = RequestProxy.new(param)
17
+ proxy.collect(&block)
18
+ obj.params << param
19
+ else
20
+ obj.params << Parameter.new(name, type, desc)
21
+ end
22
+ end
23
+
24
+ def struct(name, options = {}, &block)
25
+ param(name, nil, options, &block)
26
+ end
27
+ def string(name, options = {}, &block)
28
+ param(name, :string, options)
29
+ end
30
+ def boolean(name, options = {}, &block)
31
+ param(name, :boolean, options)
32
+ end
33
+ def integer(name, options = {}, &block)
34
+ param(name, :integer, options)
35
+ end
36
+
37
+ def header(name, options = {})
38
+ obj.headers << Header.new(name, options)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,4 @@
1
+ require "api_explorer/dsl/base_proxy"
2
+ require "api_explorer/dsl/group_proxy"
3
+ require "api_explorer/dsl/description_proxy"
4
+ require "api_explorer/dsl/request_proxy"
@@ -0,0 +1,5 @@
1
+ module ApiExplorer
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace ApiExplorer
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ module ApiExplorer
2
+ class Group < Node
3
+ attr_accessor :headers, :params, :title
4
+
5
+ def initialize(title, path = "", children = [], shared_headers = [], shared_params = [])
6
+ super nil, children, path
7
+
8
+ self.title = title
9
+ self.headers = shared_headers
10
+ self.params = shared_params
11
+ end
12
+
13
+ def add_child(child)
14
+ children << child
15
+ child.parent = self
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ module ApiExplorer
2
+ class Header
3
+ def initialize(name, options = {})
4
+ self.name = name.to_s
5
+ self.source = options[:source] || {}
6
+ end
7
+
8
+ attr_accessor :name, :source
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ module ApiExplorer
2
+ class Node
3
+ attr_accessor :parent, :children, :path
4
+
5
+ def initialize(parent = nil, children = nil, path = nil)
6
+ self.parent = parent || NullNode.new
7
+ self.children = children || []
8
+ self.path = path.to_s
9
+
10
+ self.children.each { |c| c.parent = self }
11
+ end
12
+
13
+ def full_path
14
+ parent.full_path + path
15
+ end
16
+
17
+
18
+ private
19
+
20
+ class NullNode
21
+ def full_path
22
+ ""
23
+ end
24
+
25
+ def method_missing
26
+ nil
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ module ApiExplorer
2
+ class Parameter
3
+ def initialize(name, type_or_children, description)
4
+ self.name = name.to_s
5
+ self.description = description
6
+ if type_or_children.is_a?(Array)
7
+ self.type = :hash
8
+ self.params = type_or_children
9
+ else
10
+ self.type = type_or_children.to_s.to_sym
11
+ end
12
+ end
13
+
14
+ attr_accessor :name, :type, :params, :description
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ module ApiExplorer
2
+ class Request < Node
3
+ attr_accessor :method, :params, :headers, :description, :excluded_shared_headers
4
+
5
+ def initialize(method, path, params = [], headers = [], description = "", excluded_shared_headers = [])
6
+ super nil, nil, path
7
+
8
+ self.method = method.to_s
9
+ self.params = Array(params)
10
+ self.headers = Array(headers)
11
+ self.description = description
12
+ self.excluded_shared_headers = Array(excluded_shared_headers)
13
+ end
14
+
15
+ def url
16
+ full_path
17
+ end
18
+
19
+ def url_params
20
+ path.scan(/:[a-zA-Z_\-]+/).map { |s| s[1..s.size] }
21
+ end
22
+
23
+ def url_segments
24
+ path.scan(/(:[a-zA-Z_\-]+)|([^:]+)/).map do |param, normal|
25
+ if param
26
+ [:param, param[1..param.size]]
27
+ else
28
+ [:normal, normal]
29
+ end
30
+ end
31
+ end
32
+
33
+ def title
34
+ "#{method.upcase} #{path}"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module ApiExplorer
2
+ VERSION = "0.0.1.pre.1"
3
+ end
@@ -0,0 +1,19 @@
1
+ require "api_explorer/engine"
2
+ require "api_explorer/node"
3
+ require "api_explorer/group"
4
+ require "api_explorer/description"
5
+ require "api_explorer/header"
6
+ require "api_explorer/parameter"
7
+ require "api_explorer/request"
8
+ require "api_explorer/dsl"
9
+
10
+ module ApiExplorer
11
+ mattr_accessor :description, :shared_headers, :shared_params, :auth
12
+
13
+ def self.describe(&block)
14
+ self.description = Description.new("", "", [], [], [])
15
+ proxy = DescriptionProxy.new(description)
16
+ proxy.collect(&block)
17
+ #self.description = Description.new(proxy.path, proxy.children, proxy.shared_headers, proxy.shared_params)
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ require "api_explorer"
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :api_explorer do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_api_explorer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre.1
5
+ platform: ruby
6
+ authors:
7
+ - Max Hollmann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jquery-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: ''
56
+ email:
57
+ - maxhollmann@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - Rakefile
64
+ - app/assets/javascripts/api_explorer/application.js
65
+ - app/assets/javascripts/api_explorer/explorer.js
66
+ - app/assets/javascripts/api_explorer/scroll.js
67
+ - app/assets/stylesheets/api_explorer/application.css
68
+ - app/assets/stylesheets/api_explorer/explorer.css
69
+ - app/controllers/api_explorer/application_controller.rb
70
+ - app/controllers/api_explorer/explorer_controller.rb
71
+ - app/helpers/api_explorer/application_helper.rb
72
+ - app/helpers/api_explorer/explorer_helper.rb
73
+ - app/views/api_explorer/explorer/_content_node.html.erb
74
+ - app/views/api_explorer/explorer/_node.html.erb
75
+ - app/views/api_explorer/explorer/_params.html.erb
76
+ - app/views/api_explorer/explorer/_request.html.erb
77
+ - app/views/api_explorer/explorer/_shared.html.erb
78
+ - app/views/api_explorer/explorer/form/_headers.html.erb
79
+ - app/views/api_explorer/explorer/form/_param.html.erb
80
+ - app/views/api_explorer/explorer/form/_params.html.erb
81
+ - app/views/api_explorer/explorer/form/_url_params.html.erb
82
+ - app/views/api_explorer/explorer/index.html.erb
83
+ - app/views/api_explorer/explorer/perform_request.html.erb
84
+ - config/routes.rb
85
+ - lib/api_explorer.rb
86
+ - lib/api_explorer/description.rb
87
+ - lib/api_explorer/dsl.rb
88
+ - lib/api_explorer/dsl/base_proxy.rb
89
+ - lib/api_explorer/dsl/description_proxy.rb
90
+ - lib/api_explorer/dsl/group_proxy.rb
91
+ - lib/api_explorer/dsl/request_proxy.rb
92
+ - lib/api_explorer/engine.rb
93
+ - lib/api_explorer/group.rb
94
+ - lib/api_explorer/header.rb
95
+ - lib/api_explorer/node.rb
96
+ - lib/api_explorer/parameter.rb
97
+ - lib/api_explorer/request.rb
98
+ - lib/api_explorer/version.rb
99
+ - lib/rails_api_explorer.rb
100
+ - lib/tasks/api_explorer_tasks.rake
101
+ homepage: https://github.com/maxhollmann/rails_api_explorer
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">"
117
+ - !ruby/object:Gem::Version
118
+ version: 1.3.1
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.2.2
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: Provides a simple DSL to describe your API, and let's you mount an interactive
125
+ sandbox to explore and test it.
126
+ test_files: []