apipony 0.0.4 → 0.0.7

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.
@@ -0,0 +1,42 @@
1
+ <li class="attribute-container">
2
+ <div class="attribute">
3
+ <div class="attribute-name name">
4
+ <%= attribute.name %>
5
+ </div>
6
+
7
+ <div class="attribute-type type">
8
+ <% if attribute.is_subtype? %>
9
+ <%= link_to root_path(:anchor => "subtype-#{attribute.type}") do %>
10
+ <%= attribute.type %>
11
+ <% end %>
12
+ <% else %>
13
+ <%= attribute.type %>
14
+ <% end %>
15
+ </div>
16
+
17
+ <% if attribute.description %>
18
+ <div class="attribute-description"><%= attribute.description %></div>
19
+ <% end %>
20
+ </div>
21
+
22
+ <% if attribute.is_enum? %>
23
+ <ul class="attribute-enum-list">
24
+ <div class="title">Possible values</div>
25
+ <% attribute.choices.each do |choice| %>
26
+ <li class="attribute-enum-member">
27
+ <div class="attribute-enum-member-name"><%= choice.name %></div>
28
+ <div class="attribute-enum-member-description"><%= choice.description %></div>
29
+ </li>
30
+ <% end %>
31
+ </ul>
32
+ <% end %>
33
+
34
+ <% if attribute.is_object? %>
35
+ <ul class="attribute-object-list">
36
+ <div class="title">Child attributes</div>
37
+ <%= render partial: "attribute",
38
+ collection: attribute.attributes,
39
+ as: :attribute %>
40
+ </ul>
41
+ <% end %>
42
+ </li>
@@ -0,0 +1,8 @@
1
+ <footer>
2
+ <div class="container">
3
+ Powered by
4
+ <%= link_to 'https://github.com/droptheplot/apipony' do %>
5
+ <i class="fa fa-github"></i> Apipony
6
+ <% end %>
7
+ </div>
8
+ </footer>
@@ -0,0 +1,8 @@
1
+ <header>
2
+ <div class="container">
3
+ <%= link_to @documentation.title, root_path, class: 'title' %>
4
+ <% if main_app.root_path %>
5
+ <%= link_to 'Back to site', main_app.root_path, class: 'back' %>
6
+ <% end %>
7
+ </div>
8
+ </header>
@@ -0,0 +1 @@
1
+ <span class="method <%= endpoint.method %>"><%= endpoint.method %></span><%= endpoint.url %>
@@ -0,0 +1,37 @@
1
+ <div class="request">
2
+ <h4>Request&#58;</h4>
3
+ <% if endpoint.request.params %>
4
+ <div class="panel">
5
+ <div class="title">Parameters</div>
6
+ <table class="table">
7
+ <% endpoint.request.params.each do |param| %>
8
+ <tr class="parameters">
9
+ <td class="name">
10
+ <%= param.name %>
11
+ </td>
12
+ <td class="type">
13
+ <%= param.type %>
14
+ </td>
15
+ <td class="required">
16
+ <% if param.required %>
17
+ <i class="fa fa-check-square-o" title="Required"></i>
18
+ <% else %>
19
+ <i class="fa fa-square-o" title="Optional"></i>
20
+ <% end %>
21
+ </td>
22
+ <td class="example">
23
+ <%= param.example %>
24
+ </td>
25
+ </tr>
26
+ <% end %>
27
+ </table>
28
+ </div>
29
+ <% end %>
30
+
31
+ <% if endpoint.request.headers %>
32
+ <div class="panel">
33
+ <div class="title">Headers</div>
34
+ <pre class="code"><%= JSON.pretty_generate(endpoint.request.headers) %></pre>
35
+ </div>
36
+ <% end %>
37
+ </div>
@@ -0,0 +1,30 @@
1
+ <div class="response">
2
+ <h4>Response: <%= response.status %></h4>
3
+ <% if response.example %>
4
+ <div class="response-example">
5
+ <%# This is kind of fancy for no reason but whatever %>
6
+ <% if response.example.headers %>
7
+ <div class="title">Headers</div>
8
+ <pre class="code hljs json"><%= JSON.pretty_generate(response.example.headers) %></pre>
9
+ <% end %>
10
+
11
+ <% if response.example.body %>
12
+ <div class="panel">
13
+ <div class="title">Body</div>
14
+ <pre class="code hljs json"><%= JSON.pretty_generate(response.example.body) %></pre>
15
+ </div>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
19
+
20
+ <% if response.attributes.size > 0 %>
21
+ <div class="panel">
22
+ <div class="title">Attributes</div>
23
+ <div class="table">
24
+ <div class="attributes">
25
+ <%= render partial: 'attribute', collection: response.attributes, as: :attribute %>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <% end %>
30
+ </div>
@@ -0,0 +1,16 @@
1
+ <% @documentation.sections.each do |section| %>
2
+ <h4>
3
+ <%= link_to section.title, root_path(:anchor => section.title) %>
4
+ </h4>
5
+ <ul>
6
+ <% section.endpoints.each do |endpoint| %>
7
+ <li>
8
+ <h5>
9
+ <%= link_to root_path(:anchor => endpoint.id) do %>
10
+ <span class="method <%= endpoint.method %>"><%= endpoint.method %></span><%= endpoint.url %>
11
+ <% end %>
12
+ </h5>
13
+ </li>
14
+ <% end %>
15
+ </ul>
16
+ <% end %>
@@ -0,0 +1,60 @@
1
+ <%= render partial: "header" %>
2
+
3
+ <main>
4
+ <div class="container">
5
+ <div class="row">
6
+ <div class="sidebar">
7
+ <%= render partial: "sidebar" %>
8
+ </div>
9
+
10
+ <div class="main-col">
11
+ <% @documentation.sections.each do |section| %>
12
+ <div class="section">
13
+ <h2 id="<%= section.title %>"><%= section.title %></h2>
14
+ <% section.endpoints.each do |endpoint| %>
15
+ <div class="endpoint" id="<%= endpoint.id %>">
16
+ <h3><%= render "method", endpoint: endpoint %></h3>
17
+
18
+ <% if endpoint.description %>
19
+ <div class="description">
20
+ <%= endpoint.description %>
21
+ </div>
22
+ <% end %>
23
+
24
+ <% if endpoint.request || endpoint.response %>
25
+ <% if endpoint.request %>
26
+ <%= render "request", endpoint: endpoint %>
27
+ <% end %>
28
+
29
+ <% if endpoint.response %>
30
+ <%= render "response", response: endpoint.response %>
31
+ <% end %>
32
+ <% end %>
33
+ </div>
34
+ <% end %>
35
+ </div>
36
+ <% end %>
37
+
38
+ <div id="defined_subtypes">
39
+ <% @documentation.subtypes.each do |name, type| %>
40
+ <div class="subtype" id="subtype-<%= name %>">
41
+ <h4><%= name %></h4>
42
+ <div class="panel">
43
+ <div class="title">Attributes</div>
44
+ <div class="table">
45
+ <div class="attributes">
46
+ <%= render partial: "attribute",
47
+ collection: type.attributes,
48
+ as: :attribute %>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ <% end %>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </main>
59
+
60
+ <%= render partial: "footer" %>
@@ -0,0 +1,22 @@
1
+ <html>
2
+ <head>
3
+ <%# UTF-8 Character Set %>
4
+ <meta charset="utf-8">
5
+
6
+ <%# HTML Title %>
7
+ <title><%= @documentation.title %></title>
8
+
9
+ <%# Viewport meta tag %>
10
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
11
+
12
+ <link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/github.min.css'>
13
+ <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css'>
14
+ <%= stylesheet_link_tag 'apipony/application', media: 'all' %>
15
+ <script src='//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js'></script>
16
+ <%= javascript_include_tag 'apipony/application' %>
17
+ <%= csrf_meta_tags %>
18
+ </head>
19
+ <body>
20
+ <%= yield %>
21
+ </body>
22
+ </html>
data/lib/apipony.rb CHANGED
@@ -7,6 +7,25 @@ require 'apipony/endpoint'
7
7
  require 'apipony/response'
8
8
  require 'apipony/request'
9
9
  require 'apipony/parameter'
10
+ require 'apipony/response_attribute'
11
+ require 'apipony/example_response'
10
12
 
11
13
  module Apipony
14
+
15
+ ##
16
+ # This allows you to define a common sub-type of attributes.
17
+ # A typical example is something like a list of users. If you want to
18
+ # display all users who created an image, who subscribe to a channel, or who
19
+ # are in a group, it may be useful if the information on those users is in a
20
+ # common format. This lets you define one common format, which you can then
21
+ # merge in to other attributes.
22
+ # = Example
23
+ # Apipony.define_attribute_type :user_stub do
24
+ # attribute :name
25
+ # attribute :id
26
+ # end
27
+ def self.define_attribute_type(name, **params, &block)
28
+ a = Apipony::ResponseAttribute.new("", **params, &block)
29
+ Apipony::ResponseAttribute.define_type(name, a)
30
+ end
12
31
  end
@@ -1,3 +1,5 @@
1
+ ##
2
+ # Top-level class for the DSL
1
3
  class Apipony::Documentation
2
4
  class << self
3
5
  attr_accessor :title, :base_url, :sections
@@ -9,11 +11,33 @@ class Apipony::Documentation
9
11
 
10
12
  instance_eval(&block)
11
13
  end
14
+ ##
15
+ # @return [Hash<String, ApiPony::ResponseAttribute] a hash of each subype.
16
+ # keys are the names of the subtype, values are the attribute object that
17
+ # defines it
18
+ def subtypes
19
+ Apipony::ResponseAttribute.defined_subtypes
20
+ end
12
21
 
22
+ ##
23
+ # Start a new section.
24
+ # Sections are logically separated on the display page.
13
25
  def section(title, &block)
14
26
  @sections << Apipony::Section.new(title, &block)
15
27
  end
16
28
 
29
+ ##
30
+ # Define a new subtype.
31
+ # A subtype describes a common object used in various places in your Api.
32
+ # Once defined, setting the `type` of an attribute to this given name will
33
+ # cause it to reference this subtype in a common location.
34
+ # @param [String] name what to call this subtype
35
+ def subtype(name, **params, &block)
36
+ Apipony.define_attribute_type(name, **params, &block)
37
+ end
38
+
39
+ ##
40
+ # Configure API pony with the DSL
17
41
  def config(&block)
18
42
  instance_eval(&block)
19
43
  end
@@ -1,5 +1,20 @@
1
+ ##
2
+ # Model a response endpoint.
1
3
  class Apipony::Endpoint < Apipony::Base
2
- attr_accessor :method, :url, :description, :response, :request
4
+ ##
5
+ # What HTTP verb to use to access this endpoint
6
+ attr_accessor :method
7
+ ##
8
+ # The URl of this endpoint
9
+ attr_accessor :url
10
+
11
+ ##
12
+ # A short description of what this endpoint does and why it may be useful.
13
+ attr_accessor :description
14
+
15
+ ##
16
+ #:nodoc:
17
+ attr_accessor :response, :request
3
18
 
4
19
  def initialize(method, url, &block)
5
20
  @method = method
@@ -8,14 +23,20 @@ class Apipony::Endpoint < Apipony::Base
8
23
  instance_eval(&block) if block_given?
9
24
  end
10
25
 
11
- def response_with(status, &block)
12
- @response = Apipony::Response.new(status, &block)
26
+ ##
27
+ # DSL method to start describing a response
28
+ def response_with(status, **params, &block)
29
+ @response = Apipony::Response.new(status, **params, &block)
13
30
  end
14
31
 
32
+ ##
33
+ # DSL method to start describind a request
15
34
  def request_with(&block)
16
35
  @request = Apipony::Request.new(&block)
17
36
  end
18
37
 
38
+ ##
39
+ # Create a unique identifier for this endpoint
19
40
  def id
20
41
  File.join(@method, @url)
21
42
  end
@@ -1,4 +1,6 @@
1
1
  module Apipony
2
+ ##
3
+ # Rails engine so you can just drop Apipony right into your application
2
4
  class Engine < ::Rails::Engine
3
5
  isolate_namespace Apipony
4
6
  end
@@ -0,0 +1,9 @@
1
+ ##
2
+ # Display an example response to help with understanding of the API.
3
+ class Apipony::ExampleResponse < Apipony::Base
4
+ attr_accessor :headers, :body
5
+ def initialize(&block)
6
+ instance_eval(&block) if block_given?
7
+ end
8
+
9
+ end
@@ -1,10 +1,11 @@
1
1
  class Apipony::Parameter < Apipony::Base
2
- attr_accessor :name, :type, :example, :required
2
+ attr_accessor :name, :type, :example, :required, :description
3
3
 
4
- def initialize(name, example, type, required)
4
+ def initialize(name, example, type, required, description)
5
5
  @name = name
6
6
  @example = example
7
7
  @type = type
8
8
  @required = required
9
+ @description = description
9
10
  end
10
11
  end
@@ -1,13 +1,26 @@
1
+ ##
2
+ # Model a request that an API user can make.
3
+ # Includes information about required parameters and required headers
1
4
  class Apipony::Request < Apipony::Base
2
- attr_accessor :params, :headers
5
+ ##
6
+ # :nodoc:
7
+ attr_accessor :params
8
+ ##
9
+ #:nodoc:
10
+ attr_accessor :headers
3
11
 
4
12
  def initialize(&block)
5
13
  @params = []
6
14
 
7
15
  instance_eval(&block)
8
16
  end
9
-
10
- def param(name, example: '', type: :string, required: false)
11
- @params << Apipony::Parameter.new(name, example, type, required)
17
+ ##
18
+ # Construct a new parameter
19
+ def param(name,
20
+ example: '',
21
+ type: :string,
22
+ required: false,
23
+ description: '')
24
+ @params << Apipony::Parameter.new(name, example, type, required, description)
12
25
  end
13
26
  end
@@ -1,9 +1,51 @@
1
- class Apipony::Response < Apipony::Base
2
- attr_accessor :status, :headers, :body
3
-
4
- def initialize(status, &block)
1
+ class Apipony::Response
2
+ attr_accessor :example, :attributes, :status
3
+ def initialize(status, array: false, &block)
5
4
  @status = status
6
-
5
+ @attributes = []
6
+ @array = array
7
7
  instance_eval(&block) if block_given?
8
8
  end
9
+
10
+ def is_array?
11
+ !! @array
12
+ end
13
+
14
+ def example(&block)
15
+ if block_given?
16
+ @example = Apipony::ExampleResponse.new(&block)
17
+ else
18
+ find_example
19
+ end
20
+ end
21
+
22
+ def attribute(name, **params, &block)
23
+ if params[:example]
24
+ @use_attribute_examples = true
25
+ end
26
+ @attributes << Apipony::ResponseAttribute.new(name, **params, &block)
27
+ end
28
+ private
29
+ def find_example
30
+ if @use_attribute_examples
31
+ build_example_from_attributes
32
+ end
33
+ @example
34
+ end
35
+
36
+ def build_example_from_attributes
37
+ build = Hash.new
38
+ @attributes.each do |attr|
39
+ build[attr.name] = attr.example if attr.example
40
+ end
41
+ @example ||= Apipony::ExampleResponse.new
42
+ case @example.body
43
+ when Hash
44
+ @example.body.merge! build
45
+ @example.body = [@example.body] if is_array?
46
+ when NilClass
47
+ @example.body = (is_array? ? [build] : build)
48
+ end
49
+ @example
50
+ end
9
51
  end