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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 86b81077625eb78efec26c41c96c30e832ef5c02
4
- data.tar.gz: d05befea092568084df3b920dfbc5ed4ea64f17d
3
+ metadata.gz: 4c3166ea73b31da19b4bda3071ae02dcfa4d4ca9
4
+ data.tar.gz: 5a6d604772716180f128ef341ff9df54e0a03eac
5
5
  SHA512:
6
- metadata.gz: 5fe9cdb7e1cfea04e9d4bac98aee904753b87750048da48fc4c37c826b9232bf709c17d1ed58f9c5c146b50f22915abc3cb91e054d85bd2c0c220d4c354c522c
7
- data.tar.gz: 2b756e4a6ec30fe410c96d8fa6d609dac9d73284b8c7f7b3bb594427d178873c97c857ce60a6d022d5ed629d6bea18aba6527a03f37d7b379b1a5961e6fbc698
6
+ metadata.gz: e734f9f86495b7ee3d9f10b16bd3148f43264133ca7a388f3c4e6067ce2af65c9bbe1ebd480697bc88c97bba20fc760c1f883ee3770948b8f055a6fad120f3b8
7
+ data.tar.gz: 52c6232bf579dc49170f7c8699e8f183449af9e66a63488e721f6502cc16d9652341f29f01036ef98d1530f51c9f55047848df1c95ab570522e6c3afc32a79dc
data/README.md CHANGED
@@ -1,19 +1,20 @@
1
1
  # Apipony
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/apipony.svg)](https://badge.fury.io/rb/apipony)
4
+ [![Build Status](https://travis-ci.org/droptheplot/apipony.svg?branch=travis)](https://travis-ci.org/droptheplot/apipony)
4
5
  [![Code Climate](https://codeclimate.com/github/droptheplot/apipony/badges/gpa.svg)](https://codeclimate.com/github/droptheplot/apipony)
5
6
 
6
7
  Ruby DSL to create Rails API documentation from your application.
7
8
 
8
- ## Getting started
9
9
 
10
+ ## Getting started
10
11
  * Add `gem 'apipony'` to Gemfile
11
12
  * `bundle install`
12
13
  * `rails g apipony:install`
13
14
  * Now you can edit your documentation in `config/initializers/apipony.rb`
14
15
 
15
- ## How it works
16
16
 
17
+ ## How it works
17
18
  DSL example:
18
19
 
19
20
  ```ruby
@@ -28,7 +29,7 @@ Apipony::Documentation.define do
28
29
  e.description = 'Find ponies'
29
30
 
30
31
  request_with do
31
- param :name, example: 'applejack', required: true
32
+ param :name, example: 'applejack', required: true
32
33
  end
33
34
 
34
35
  response_with 200 do
@@ -44,6 +45,207 @@ Apipony::Documentation.define do
44
45
  end
45
46
  ```
46
47
 
48
+
49
+ ## Features
50
+
51
+ ### Response Attribute Documentation
52
+ Apipony lets you provide further documentation about the attributes in your
53
+ API's responses. Simply create a new `attribute` inside a `respond_with` block.
54
+ These attributes can even have nested sub-attributes, for documentation of
55
+ more complex object graphs.
56
+
57
+ ```ruby
58
+ Apipony::Documentation.define do
59
+ section "Species" do
60
+ endpoint 'get', '/species/:id' do |e|
61
+ e.description = "Get information about a species"
62
+ respond_with 200 do
63
+ example do
64
+ set :body, {
65
+ name: "Unicorn",
66
+ is_pony: true,
67
+ biology: {
68
+ has_horn: true,
69
+ has_wings: false
70
+ }
71
+ }
72
+ end
73
+ attribute :name, type: :string
74
+ attribute :is_pony, type: :bool,
75
+ description: "Is this species a type of pony?"
76
+ attribute :biology do
77
+ attribute :has_horn, type: :bool
78
+ attribute :has_wings, type: :bool
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ ```
85
+
86
+ ### Enum Attributes
87
+ Your API may have some fields that can be picked from a pre-defined set of
88
+ values. You can document those values by using an enum attribute.
89
+
90
+ ```ruby
91
+ Apipony::Documentation.define do
92
+ section "Ponies" do
93
+ endpoint "get", "/ponies/:id" do |e|
94
+ e.description = "Information about a pony"
95
+ example do
96
+ set :body, {
97
+ name: "Applejack",
98
+ sex: "female",
99
+ kind: :earth,
100
+ occupation: :farmer
101
+ }
102
+ end
103
+
104
+ attribute :kind, type: :enum do
105
+ choice :earth, description: "A pony with no wings or horn"
106
+ choice :unicorn, description: "A pony with a horn"
107
+ choice :pegasus, description: "A pony with wings"
108
+ choice :alicorn,
109
+ description: "A pony with wings and a horn. Indicates royalty."
110
+ end
111
+ end
112
+ end
113
+ end
114
+ ```
115
+
116
+ ### Example Generation
117
+ When describing attributes, you can provide an optional `example:` parameter.
118
+ If included, this will be used to generate the example response in the
119
+ documentation.
120
+
121
+ ```ruby
122
+ Apipony::Documentation.define do
123
+ section "Ponies" do
124
+ endpoint "get", "/ponies/:id" do |e|
125
+ respond_with 200 do
126
+ attribute :name, type: :string, example: "Applejack"
127
+ # Enum members automatically select the first choice
128
+ attribute :kind, type: :enum do
129
+ choice :earth
130
+ choice :pegasus
131
+ choice :unicorn
132
+ choice :alicorn
133
+ end
134
+ end
135
+ end
136
+
137
+ endpoint "get", "/ponies/" do |e|
138
+ # Automatic serialization of arrays is supported
139
+ respond_with 200, array: true do
140
+ attribute :name, type: :string, example: "Applejack"
141
+ attribute :id, type: :integer, example: 10
142
+ end
143
+ end
144
+ end
145
+ end
146
+ ```
147
+
148
+ `GET /ponies/:id` will now have the example of:
149
+
150
+ ```json
151
+ {
152
+ "name": "Applejack",
153
+ "kind": "Earth"
154
+ }
155
+ ```
156
+
157
+ `GET /ponies/` will have the example of:
158
+
159
+ ```json
160
+ [
161
+ {
162
+ "name": "Applejack",
163
+ "id": 10
164
+ }
165
+ ]
166
+ ```
167
+
168
+ ### Predefined Subtypes
169
+ Sometimes, when building an API, it can be useful to store data in a common
170
+ format. Apipony lets you define this common format once, then use it multiple
171
+ times. Check it out:
172
+
173
+ ```ruby
174
+ Apipony::Documentation.define do
175
+ subtype :pony_stub do
176
+ attribute :name, type: :string
177
+ attribute :id, type: :integer
178
+ end
179
+
180
+ section "Ponies" do
181
+ endpoint 'get', '/ponies/:id' do |e|
182
+ e.description = "Find a pony with a given name"
183
+ request_with do
184
+ params :id, example: 10, required: true
185
+ end
186
+
187
+ response_with 200 do
188
+ example do
189
+ set :body, {
190
+ :name => :applejack,
191
+ :type => :earth,
192
+ :sex => :female,
193
+ :occupation => :farmer,
194
+ :friends => [
195
+ {name: "Twilight Sparkle", id: 1},
196
+ {name: "Pinkie Pie", id: 2},
197
+ {name: "Rainbow Dash", id: 3},
198
+ {name: "Rarity", id: 4},
199
+ {name: "Fluttershy", id: 5}
200
+ ]
201
+ }
202
+ end
203
+ attribute :name, type: :string
204
+ attribute :kind, type: :enum do
205
+ choice :alicorn
206
+ choice :earth
207
+ choice :unicorn
208
+ choice :pegasus
209
+ end
210
+ attribute :friends, type: :pony_stub, array: true
211
+ attribute :occupation, type: :string
212
+ end
213
+ end
214
+
215
+ section "Locations" do
216
+ endpoint 'get', '/locations/:id' do |e|
217
+ e.description = "Information about a location"
218
+ response_with 200 do
219
+ example do
220
+ set :body, {
221
+ :name => "Crystal Empire",
222
+ :population => 107770,
223
+ :rulers => [
224
+ {
225
+ name: "Shining Armor",
226
+ id: 50
227
+ },
228
+ {
229
+ name: "Princess Cadence",
230
+ id: 90001
231
+ }
232
+ ]
233
+ }
234
+ end
235
+ attribute :name, type: :string
236
+ attribute :population, type: :integer
237
+ attribute :rulers, type: :pony_stub, array: true
238
+ end
239
+ end
240
+ end
241
+ end
242
+ ```
243
+
244
+ Now, the `friends` attribute of `GET /ponies/:id` and the `rulers` attribute of
245
+ `GET /locations/:id` will reference a common subtype on the generated
246
+ documentation.
247
+
248
+
47
249
  Generated documentation example:
48
250
 
49
251
  ![Example](https://raw.githubusercontent.com/droptheplot/apipony/master/preview.png)
data/Rakefile CHANGED
@@ -1,20 +1,16 @@
1
1
  begin
2
2
  require 'bundler/setup'
3
+ require 'yard'
3
4
  rescue LoadError
4
5
  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
6
  end
6
7
 
7
8
  require 'rdoc/task'
8
9
 
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'Apipony'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.rdoc')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
10
+ YARD::Rake::YardocTask.new(:doc) do |doc|
15
11
  end
16
12
 
17
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
13
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
14
  load 'rails/tasks/engine.rake'
19
15
 
20
16
 
@@ -1,13 +1,25 @@
1
+ // Color scheme
1
2
  $dark_color: #111;
2
3
  $medium_color: #888;
3
4
  $light_color: #eee;
4
- $brand_color: #5E147D;
5
+ $brand_color: #5e147d;
5
6
 
6
- @import url(https://fonts.googleapis.com/css?family=Cuprum&subset=latin,cyrillic);
7
+ // Method colors
8
+ $get-color: #1abc9c;
9
+ $post-color: #3498db;
10
+ $put-color: #2980d9;
11
+ $delete-color: #c0392b;
7
12
 
8
- * {
13
+ // Misc. values
14
+ $transition-time: 200ms;
15
+ $mobile-width: 900px;
16
+
17
+
18
+ *, *::before, *::after {
9
19
  margin: 0;
10
20
  padding: 0;
21
+ box-sizing: border-box;
22
+
11
23
  &:focus {
12
24
  outline: none;
13
25
  }
@@ -19,8 +31,8 @@ html, body {
19
31
  }
20
32
 
21
33
  body {
22
- font-family: 'Arial';
23
- font-size: 14px;
34
+ font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
35
+ font-size: 12px;
24
36
  color: $dark_color;
25
37
  -webkit-font-smoothing: antialiased;
26
38
  }
@@ -45,8 +57,9 @@ h2 {
45
57
  }
46
58
 
47
59
  h3 {
60
+ padding-top: 10px;
48
61
  font-size: 17px;
49
- line-height: 17px;
62
+ line-height: 16px;
50
63
  }
51
64
 
52
65
  h4 {
@@ -57,17 +70,22 @@ h4 {
57
70
 
58
71
  h5 {
59
72
  font-weight: normal;
73
+ font-size: 12px;
74
+ line-height: 17px;
60
75
  }
61
76
 
62
77
  ul {
63
78
  margin-bottom: 20px;
79
+
64
80
  li {
65
81
  margin-bottom: 10px;
66
82
  }
67
83
  }
68
84
 
69
85
  .container {
70
- width: 940px;
86
+ max-width: 900px;
87
+ width: 100%;
88
+ padding: 0 20px;
71
89
  margin: 0 auto;
72
90
  position: relative;
73
91
  }
@@ -75,20 +93,28 @@ ul {
75
93
  .row {
76
94
  overflow: hidden;
77
95
  margin: 0 -10px;
96
+ display: flex;
97
+ flex-flow: row nowrap;
98
+
99
+ @media all and (max-width: $mobile-width) {
100
+ flex-flow: row wrap;
101
+ }
78
102
  }
79
103
 
80
- @for $i from 1 through 12 {
81
- .col-#{$i} {
82
- box-sizing: border-box;
83
- margin: 0 10px;
84
- width: 60px * $i + 20px * ($i - 1);
85
- float: left;
104
+ .sidebar {
105
+ flex: 1 120px;
106
+
107
+ @media all and (max-width: $mobile-width) {
108
+ flex: 1 100%;
109
+ margin-bottom: 30px;
86
110
  }
87
111
  }
88
112
 
89
- @for $i from 1 through 12 {
90
- .col-offset-#{$i} {
91
- margin-left: 60px * $i + 20px * ($i - 1) + 30px;
113
+ .main-col {
114
+ flex: 8;
115
+
116
+ @media all and (max-width: $mobile-width) {
117
+ flex: 1 100%;
92
118
  }
93
119
  }
94
120
 
@@ -96,17 +122,23 @@ header {
96
122
  background: $brand_color;
97
123
  height: 60px;
98
124
  line-height: 60px;
125
+
99
126
  .title {
100
- font-family: 'Cuprum';
101
127
  font-weight: bold;
102
128
  font-size: 20px;
103
129
  color: #fff;
104
130
  }
131
+
105
132
  .back {
106
133
  float: right;
107
134
  color: #fff;
108
- opacity: .7;
135
+ opacity: 0.7;
109
136
  font-size: 12px;
137
+ transition: $transition-time opacity;
138
+
139
+ &:hover {
140
+ opacity: 1;
141
+ }
110
142
  }
111
143
  }
112
144
 
@@ -120,8 +152,15 @@ footer {
120
152
  border-top: 1px solid $light_color;
121
153
  text-align: right;
122
154
  font-size: 12px;
155
+ color: $medium_color;
156
+
123
157
  a {
124
158
  color: $medium_color;
159
+ transition: $transition-time color;
160
+
161
+ &:hover {
162
+ color: $dark-color;
163
+ }
125
164
  }
126
165
  }
127
166
 
@@ -131,22 +170,27 @@ footer {
131
170
  margin-bottom: 40px;
132
171
  border-bottom: 1px solid $light_color;
133
172
  }
173
+
134
174
  .endpoint {
135
175
  position: relative;
176
+
136
177
  &:not(:last-child) {
137
178
  margin-bottom: 40px;
138
179
  }
180
+
139
181
  .description {
140
182
  font-size: 12px;
141
183
  color: $medium_color;
142
184
  padding-top: 20px;
143
185
  font-weight: normal;
144
186
  }
187
+
145
188
  .response, .request {
146
189
  padding-top: 20px;
190
+
147
191
  .code {
148
192
  padding: 8px 10px 10px;
149
- font-size: 12px;
193
+ font-size: 14px;
150
194
  border-radius: 0 0 3px 3px;
151
195
  }
152
196
  }
@@ -157,48 +201,60 @@ footer {
157
201
  border: 1px solid darken($light_color, 5%);
158
202
  border-radius: 3px;
159
203
  margin-top: 20px;
204
+ overflow-x: auto;
205
+
160
206
  .title {
161
207
  border-bottom: 1px solid darken($light_color, 5%);
162
208
  padding: 10px;
163
- font-size: 11px;
209
+ font-size: 12px;
164
210
  font-weight: bold;
165
211
  }
166
212
  }
167
213
 
168
214
  .method {
169
215
  text-transform: uppercase;
216
+ vertical-align: bottom;
170
217
  color: #fff;
171
218
  font-size: 9px;
172
219
  padding: 4px 5px;
173
220
  border-radius: 3px;
174
221
  margin-right: 5px;
175
222
  font-weight: bold;
176
- background: $medium_color;
223
+ background-color: $medium_color;
224
+
177
225
  &.get {
178
- background: #1ABC9C;
226
+ background-color: $get-color;
179
227
  }
228
+
180
229
  &.post {
181
- background: #3498DB;
230
+ background-color: $post-color;
182
231
  }
232
+
183
233
  &.put {
184
- background: #2980B9;
234
+ background-color: $put-color;
185
235
  }
236
+
186
237
  &.delete {
187
- background: #C0392B;
238
+ background-color: $delete-color;
188
239
  }
189
240
  }
190
241
 
191
- .param {
242
+ .parameters, .attributes {
243
+ font-size: 12px;
244
+
192
245
  .name {
193
246
  color: $brand_color;
194
247
  font-weight: bold;
195
248
  }
249
+
196
250
  .type {
197
251
  color: $medium_color;
198
252
  font-style: italic;
199
253
  }
254
+
200
255
  .required {
201
256
  text-align: center;
257
+
202
258
  .fa {
203
259
  color: $medium_color;
204
260
  }
@@ -207,9 +263,79 @@ footer {
207
263
 
208
264
  .table {
209
265
  padding: 8px 0;
266
+
210
267
  tr {
211
268
  td {
212
- padding: 2px 10px;
269
+ padding: 4px 10px;
270
+ }
271
+ }
272
+ }
273
+
274
+ .attribute-container {
275
+ display: flex;
276
+ flex-flow: column nowrap;
277
+
278
+ .attribute {
279
+ display: flex;
280
+ flex-flow: row nowrap;
281
+ align-items: inherit;
282
+ justify-content: flex-start;
283
+
284
+ > div {
285
+ padding: 4px 10px;
286
+ }
287
+
288
+ .attribute-type {
289
+ flex: 1 1 60px;
290
+ }
291
+
292
+ .attribute-name {
293
+ flex: 2 1 0;
294
+ min-width: 90px;
295
+ }
296
+
297
+ .attribute-description {
298
+ flex: 8 1 0;
299
+ }
300
+ }
301
+
302
+ ul {
303
+ margin: 8px 10px;
304
+ border: 1px solid #e1e1e1;
305
+ border-radius: 3px;
306
+
307
+ li {
308
+ list-style: none;
309
+ margin: 10px 0;
310
+ padding: 0 12px;
213
311
  }
214
312
  }
215
313
  }
314
+
315
+ .attribute-enum-member {
316
+ display: flex;
317
+ flex-flow: row nowrap;
318
+
319
+ .title {
320
+ border-bottom: 1px solid darken($light_color, 5%);
321
+ padding: 10px;
322
+ font-size: 11px;
323
+ font-weight: bold;
324
+ }
325
+
326
+ .attribute-enum-member-name {
327
+ font-weight: 400;
328
+ margin-right: 10px;
329
+ min-width: 60px;
330
+ flex: 1 1 0;
331
+ color: $brand_color;
332
+ }
333
+
334
+ .attribute-enum-member-description {
335
+ flex: 7 1 0;
336
+ }
337
+ }
338
+
339
+ .subtype {
340
+ margin-bottom: 25px;
341
+ }