├── .github └── workflows │ └── test-coverage.yml ├── .gitignore ├── .hound.yml ├── .rspec ├── .rubocop.yml ├── .ruby-version ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE ├── README.md ├── Rakefile ├── _config.yml ├── apidoco.gemspec ├── app ├── assets │ ├── config │ │ └── apidoco_manifest.js │ ├── javascripts │ │ └── apidoco │ │ │ ├── apidoco_app.js │ │ │ ├── application.js │ │ │ ├── bootstrap │ │ │ ├── bootrstap.js.map │ │ │ └── bootstrap.js │ │ │ ├── clipboard.min.js │ │ │ ├── components │ │ │ └── tabbed │ │ │ │ ├── ad-tabbed.html │ │ │ │ ├── ad-tabbed.js.erb │ │ │ │ ├── body-properties │ │ │ │ ├── ad-body-properties.html │ │ │ │ └── ad-body-properties.js.erb │ │ │ │ ├── example-body │ │ │ │ ├── ad-example-body.html │ │ │ │ └── ad-example-body.js.erb │ │ │ │ ├── example-headers │ │ │ │ ├── ad-example-headers.html │ │ │ │ └── ad-example-headers.js.erb │ │ │ │ └── headers │ │ │ │ ├── ad-headers.html │ │ │ │ └── ad-headers.js.erb │ │ │ ├── controllers │ │ │ └── documentations_controller.js │ │ │ ├── directives │ │ │ ├── jq_json_viewer.js │ │ │ └── ngclipboard.js │ │ │ ├── icons │ │ │ ├── copyIcon.js │ │ │ ├── linkIcon.js │ │ │ └── redirectIcon.js │ │ │ ├── jquery.json-viewer.js │ │ │ └── jquery.min.js │ └── stylesheets │ │ └── apidoco │ │ ├── application.css │ │ ├── bootstrap │ │ ├── bootstrap.css │ │ └── bootstrap.css.map │ │ ├── custom.css │ │ ├── helpers.css │ │ ├── jquery.json-viewer.css │ │ ├── ng-prettyjson.min.css │ │ └── simple-sidebar.css ├── controllers │ └── apidoco │ │ ├── apis_controller.rb │ │ └── application_controller.rb ├── helpers │ └── apidoco │ │ └── application_helper.rb └── views │ ├── apidoco │ └── apis │ │ ├── _side_bar.html.erb │ │ └── show.html.erb │ └── layouts │ └── apidoco │ └── application.html.erb ├── bin └── rails ├── config ├── initializers │ └── assets.rb └── routes.rb ├── images └── 1.png ├── lib ├── apidoco.rb ├── apidoco │ ├── engine.rb │ ├── file_parse_error.rb │ ├── file_parser.rb │ ├── folder_parser.rb │ ├── version.rb │ ├── version_documentation.rb │ └── version_parser.rb ├── generators │ └── apidoco_generator.rb └── tasks │ └── apidoco_tasks.rake ├── spec ├── apidoco │ ├── file_parse_error_spec.rb │ ├── file_parser_spec.rb │ ├── folder_parser_spec.rb │ ├── version_documentation_spec.rb │ └── version_parser_spec.rb ├── dummy │ ├── Rakefile │ ├── app │ │ ├── assets │ │ │ ├── config │ │ │ │ └── manifest.js │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ ├── application.js │ │ │ │ ├── cable.js │ │ │ │ └── channels │ │ │ │ │ └── .keep │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── channels │ │ │ └── application_cable │ │ │ │ ├── channel.rb │ │ │ │ └── connection.rb │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ └── concerns │ │ │ │ └── .keep │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── jobs │ │ │ └── application_job.rb │ │ ├── mailers │ │ │ └── application_mailer.rb │ │ ├── models │ │ │ ├── application_record.rb │ │ │ └── concerns │ │ │ │ └── .keep │ │ └── views │ │ │ └── layouts │ │ │ ├── application.html.erb │ │ │ ├── mailer.html.erb │ │ │ └── mailer.text.erb │ ├── bin │ │ ├── bundle │ │ ├── rails │ │ ├── rake │ │ ├── setup │ │ └── update │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── cable.yml │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── application_controller_renderer.rb │ │ │ ├── assets.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── new_framework_defaults.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ ├── puma.rb │ │ ├── routes.rb │ │ ├── secrets.yml │ │ └── spring.rb │ ├── db │ │ └── schema.rb │ ├── lib │ │ └── assets │ │ │ └── .keep │ ├── log │ │ └── .keep │ └── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ └── favicon.ico ├── features │ └── apidoco │ │ ├── documentation_attributes │ │ ├── end_point_spec.rb │ │ ├── examples_spec.rb │ │ ├── http_method_spec.rb │ │ ├── name_spec.rb │ │ ├── params_spec.rb │ │ ├── published_spec.rb │ │ └── response_properties_spec.rb │ │ └── show_spec.rb ├── generators │ └── apidoco │ │ └── apidoco_generator_spec.rb ├── rails_helper.rb ├── spec_helper.rb └── support │ ├── capybara.rb │ └── documentation_builder.rb └── vendor └── assets └── apidoco └── angular └── 1.8.0 └── angular.js /.github/workflows/test-coverage.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake 6 | # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby 7 | 8 | name: Ruby 9 | 10 | on: 11 | push: 12 | 13 | jobs: 14 | test: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Set up Ruby 21 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, 22 | # change this to (see https://github.com/ruby/setup-ruby#versioning): 23 | # uses: ruby/setup-ruby@v1 24 | uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0 25 | with: 26 | ruby-version: 2.6 27 | env: 28 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 29 | - name: Install dependencies 30 | run: bundle install 31 | - name: Run tests 32 | run: bundle exec rake 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | 5 | spec/dummy/db/test.sqlite3 6 | spec/dummy/db/*.sqlite3-journal 7 | spec/dummy/log/*.log 8 | spec/dummy/tmp/ 9 | spec/dummy/docs 10 | 11 | *.gem 12 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | ruby: 2 | config_file: .rubocop.yml 3 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - 'spec/dummy/db/schema.rb' 4 | 5 | Metrics/LineLength: 6 | Max: 120 7 | Style/FrozenStringLiteralComment: 8 | Enabled: false 9 | Documentation: 10 | Enabled: false 11 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.6.6 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] - yyyy-mm-dd 8 | 9 | ### Added 10 | 11 | ### Changed 12 | 13 | ### Deprecated 14 | 15 | ### Removed 16 | 17 | ### Fixed 18 | 19 | ### Security 20 | 21 | ## [1.6.4] - 2021-06-18 22 | 23 | ## Added 24 | - [Response Body Properties](https://github.com/72pulses/apidoco/pull/118) 25 | 26 | ## [1.6.3] - 2021-06-02 27 | 28 | ### Changed 29 | 30 | - [Bump mimemagic to 0.3.10](https://github.com/72pulses/apidoco/pull/109) 31 | 32 | ## [1.6.2] - 2020-11-18 33 | 34 | ### Added 35 | - [UI V2](https://github.com/72pulses/apidoco/pull/99) 36 | 37 | ### Changed 38 | - [upgrading bootsrap to 4.5](https://github.com/72pulses/apidoco/pull/97) 39 | - [Angularjs upgrade - 1.8.x](https://github.com/72pulses/apidoco/pull/100) 40 | 41 | ## [1.6.1] - 2020-08-19 42 | 43 | ### Added 44 | - [Test coverage for sorting fix](https://github.com/72pulses/apidoco/commit/ad291ceadcb5bc1f2cf481bcf0277a915ee9cebf) 45 | 46 | ### Removed 47 | - [Removed circle ci config in favor of github action](https://github.com/72pulses/apidoco/commit/e433056658605ebf9c2325c3d483beaa4b9f5a7b) 48 | 49 | ### Fixed 50 | - Better error handling when parsing files [#91](https://github.com/72pulses/apidoco/pull/91) 51 | - Update genrator to use the `base_path` config [#92](https://github.com/72pulses/apidoco/pull/92) 52 | 53 | ### Security 54 | - Bump rack from 2.2.2 to 2.2.3 [#83](https://github.com/72pulses/apidoco/pull/83) 55 | 56 | ## [1.6.0] - 2020-07-10 57 | 58 | ### Added 59 | - Using app name as the sidebar title https://github.com/72pulses/apidoco/pull/80 60 | - Adding built-with https://github.com/72pulses/apidoco/pull/81 61 | - Added more test coverage https://github.com/72pulses/apidoco/pull/85 62 | - Added Github Action: Test Coverage https://github.com/72pulses/apidoco/pull/89 63 | 64 | ### Changed 65 | - (Breaking Change) Setting rails 5 as min requirement. Make sure your rails app version is >= 5.0.0 https://github.com/72pulses/apidoco/pull/78 66 | - Improved gitignore - fixed untracked files https://github.com/72pulses/apidoco/pull/79 67 | 68 | ## [1.5.6] - 2020-06-10 69 | 70 | ### Changed 71 | - Bump websocket-extensions https://github.com/72pulses/apidoco/pull/75 72 | - Bump puma https://github.com/72pulses/apidoco/pull/71 73 | 74 | ### Fixed 75 | - AssetNotPrecompiled bug for rails 6 https://github.com/72pulses/apidoco/pull/76 76 | 77 | ## [1.5.5] - 2020-06-04 78 | 79 | ### Added 80 | - Added auto-generated CircleCI 2.0 config file https://github.com/72pulses/apidoco/pull/56 81 | 82 | ### Changed 83 | - Bumped dependent gems - Capybara, Nokogiri, Puma, Rack and Loofah 84 | - Using apparition instead of webkit https://github.com/72pulses/apidoco/pull/55 85 | 86 | ### Fixed 87 | - Fix forced reference to api path https://github.com/72pulses/apidoco/pull/69 88 | - updating gemspec to fix build warnings, update ruby https://github.com/72pulses/apidoco/pull/70 89 | 90 | ## [1.5.4] - 2019-07-23 91 | 92 | ### Added 93 | - CHANGELOG.md https://github.com/72pulses/apidoco/pull/53 94 | 95 | ### Changed 96 | - Sort sub-directories alphabetically https://github.com/72pulses/apidoco/pull/47 97 | 98 | ### Fixed 99 | - Show in a line 'request' and 'response' https://github.com/72pulses/apidoco/pull/52 100 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Declare your gem's dependencies in apidoco.gemspec. 4 | # Bundler will treat runtime dependencies like base dependencies, and 5 | # development dependencies will be added by default to the :development group. 6 | gemspec 7 | 8 | # Declare any dependencies that are still in development here instead of in 9 | # your gemspec. These might include edge Rails or gems from your path or 10 | # Git. Remember to move these dependencies to your gemspec before releasing 11 | # your gem to rubygems.org. 12 | 13 | # To use a debugger 14 | # gem 'byebug', group: [:development, :test] 15 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | apidoco (1.6.4) 5 | rails (>= 5.0.0) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actioncable (5.2.4.3) 11 | actionpack (= 5.2.4.3) 12 | nio4r (~> 2.0) 13 | websocket-driver (>= 0.6.1) 14 | actionmailer (5.2.4.3) 15 | actionpack (= 5.2.4.3) 16 | actionview (= 5.2.4.3) 17 | activejob (= 5.2.4.3) 18 | mail (~> 2.5, >= 2.5.4) 19 | rails-dom-testing (~> 2.0) 20 | actionpack (5.2.4.3) 21 | actionview (= 5.2.4.3) 22 | activesupport (= 5.2.4.3) 23 | rack (~> 2.0, >= 2.0.8) 24 | rack-test (>= 0.6.3) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 27 | actionview (5.2.4.3) 28 | activesupport (= 5.2.4.3) 29 | builder (~> 3.1) 30 | erubi (~> 1.4) 31 | rails-dom-testing (~> 2.0) 32 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 33 | activejob (5.2.4.3) 34 | activesupport (= 5.2.4.3) 35 | globalid (>= 0.3.6) 36 | activemodel (5.2.4.3) 37 | activesupport (= 5.2.4.3) 38 | activerecord (5.2.4.3) 39 | activemodel (= 5.2.4.3) 40 | activesupport (= 5.2.4.3) 41 | arel (>= 9.0) 42 | activestorage (5.2.4.3) 43 | actionpack (= 5.2.4.3) 44 | activerecord (= 5.2.4.3) 45 | marcel (~> 0.3.1) 46 | activesupport (5.2.4.3) 47 | concurrent-ruby (~> 1.0, >= 1.0.2) 48 | i18n (>= 0.7, < 2) 49 | minitest (~> 5.1) 50 | tzinfo (~> 1.1) 51 | addressable (2.7.0) 52 | public_suffix (>= 2.0.2, < 5.0) 53 | apparition (0.5.0) 54 | capybara (~> 3.13, < 4) 55 | websocket-driver (>= 0.6.5) 56 | arel (9.0.0) 57 | builder (3.2.4) 58 | byebug (11.1.3) 59 | capybara (3.32.2) 60 | addressable 61 | mini_mime (>= 0.1.3) 62 | nokogiri (~> 1.8) 63 | rack (>= 1.6.0) 64 | rack-test (>= 0.6.3) 65 | regexp_parser (~> 1.5) 66 | xpath (~> 3.2) 67 | coderay (1.1.3) 68 | concurrent-ruby (1.1.6) 69 | crass (1.0.6) 70 | diff-lcs (1.3) 71 | erubi (1.9.0) 72 | ffi (1.13.1) 73 | generator_spec (0.9.4) 74 | activesupport (>= 3.0.0) 75 | railties (>= 3.0.0) 76 | globalid (0.4.2) 77 | activesupport (>= 4.2.0) 78 | i18n (1.8.3) 79 | concurrent-ruby (~> 1.0) 80 | loofah (2.5.0) 81 | crass (~> 1.0.2) 82 | nokogiri (>= 1.5.9) 83 | mail (2.7.1) 84 | mini_mime (>= 0.1.1) 85 | marcel (0.3.3) 86 | mimemagic (~> 0.3.2) 87 | method_source (1.0.0) 88 | mimemagic (0.3.10) 89 | nokogiri (~> 1) 90 | rake 91 | mini_mime (1.0.2) 92 | mini_portile2 (2.4.0) 93 | minitest (5.14.1) 94 | nio4r (2.5.2) 95 | nokogiri (1.10.9) 96 | mini_portile2 (~> 2.4.0) 97 | pry (0.13.1) 98 | coderay (~> 1.1) 99 | method_source (~> 1.0) 100 | pry-byebug (3.9.0) 101 | byebug (~> 11.0) 102 | pry (~> 0.13.0) 103 | public_suffix (4.0.5) 104 | puma (4.3.5) 105 | nio4r (~> 2.0) 106 | rack (2.2.3) 107 | rack-test (1.1.0) 108 | rack (>= 1.0, < 3) 109 | rails (5.2.4.3) 110 | actioncable (= 5.2.4.3) 111 | actionmailer (= 5.2.4.3) 112 | actionpack (= 5.2.4.3) 113 | actionview (= 5.2.4.3) 114 | activejob (= 5.2.4.3) 115 | activemodel (= 5.2.4.3) 116 | activerecord (= 5.2.4.3) 117 | activestorage (= 5.2.4.3) 118 | activesupport (= 5.2.4.3) 119 | bundler (>= 1.3.0) 120 | railties (= 5.2.4.3) 121 | sprockets-rails (>= 2.0.0) 122 | rails-dom-testing (2.0.3) 123 | activesupport (>= 4.2.0) 124 | nokogiri (>= 1.6) 125 | rails-html-sanitizer (1.3.0) 126 | loofah (~> 2.3) 127 | railties (5.2.4.3) 128 | actionpack (= 5.2.4.3) 129 | activesupport (= 5.2.4.3) 130 | method_source 131 | rake (>= 0.8.7) 132 | thor (>= 0.19.0, < 2.0) 133 | rake (13.0.1) 134 | regexp_parser (1.7.1) 135 | rspec-core (3.9.2) 136 | rspec-support (~> 3.9.3) 137 | rspec-expectations (3.9.2) 138 | diff-lcs (>= 1.2.0, < 2.0) 139 | rspec-support (~> 3.9.0) 140 | rspec-mocks (3.9.1) 141 | diff-lcs (>= 1.2.0, < 2.0) 142 | rspec-support (~> 3.9.0) 143 | rspec-rails (4.0.1) 144 | actionpack (>= 4.2) 145 | activesupport (>= 4.2) 146 | railties (>= 4.2) 147 | rspec-core (~> 3.9) 148 | rspec-expectations (~> 3.9) 149 | rspec-mocks (~> 3.9) 150 | rspec-support (~> 3.9) 151 | rspec-support (3.9.3) 152 | sass-rails (6.0.0) 153 | sassc-rails (~> 2.1, >= 2.1.1) 154 | sassc (2.4.0) 155 | ffi (~> 1.9) 156 | sassc-rails (2.1.2) 157 | railties (>= 4.0.0) 158 | sassc (>= 2.0) 159 | sprockets (> 3.0) 160 | sprockets-rails 161 | tilt 162 | sprockets (4.0.2) 163 | concurrent-ruby (~> 1.0) 164 | rack (> 1, < 3) 165 | sprockets-rails (3.2.1) 166 | actionpack (>= 4.0) 167 | activesupport (>= 4.0) 168 | sprockets (>= 3.0.0) 169 | sqlite3 (1.4.2) 170 | thor (1.0.1) 171 | thread_safe (0.3.6) 172 | tilt (2.0.10) 173 | tzinfo (1.2.7) 174 | thread_safe (~> 0.1) 175 | websocket-driver (0.7.2) 176 | websocket-extensions (>= 0.1.0) 177 | websocket-extensions (0.1.5) 178 | xpath (3.2.0) 179 | nokogiri (~> 1.8) 180 | 181 | PLATFORMS 182 | ruby 183 | 184 | DEPENDENCIES 185 | apidoco! 186 | apparition (~> 0.1, >= 0.1.0) 187 | capybara (~> 3.31, >= 3.31.0) 188 | generator_spec (~> 0.9, >= 0.9.4) 189 | pry-byebug (~> 3.9.0, >= 3.9.0) 190 | puma (~> 4.3, >= 4.3.3) 191 | rspec-rails (~> 4.0, >= 4.0.0) 192 | sass-rails (>= 5.0.0) 193 | sqlite3 (~> 1.3, >= 1.3.13) 194 | 195 | BUNDLED WITH 196 | 1.17.3 197 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Al Ameen 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. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gem Version](https://badge.fury.io/rb/apidoco.svg)](https://badge.fury.io/rb/apidoco) 2 | 3 | # Apidoco - Ruby on Rails API documentation tool 4 | Easy documentation of REST APIs - [Demo](http://demo.apidoco.com/docs/). 5 | 6 | ## Screenshots 7 | 8 | ![screeshot 1](https://github.com/72pulses/apidoco/blob/master/images/1.png?raw=true) 9 | 10 | 11 | ## Installation 12 | Add this line to your application's Gemfile: 13 | 14 | ```ruby 15 | gem 'apidoco' 16 | ``` 17 | 18 | And then execute: 19 | ```bash 20 | $ bundle 21 | ``` 22 | 23 | Add this line to your routes: 24 | 25 | ```ruby 26 | mount Apidoco::Engine, at: "/docs" 27 | ``` 28 | 29 | ## Configuring 30 | 31 | Create a configuration file in initializers e.g. /config/initializers/apidoco.rb and add the following. 32 | 33 | ```ruby 34 | Apidoco.auth_name = 'authentication_name' 35 | Apidoco.auth_password = 'authentication_password' 36 | Apidoco.app_name = 'your app name' 37 | Apidoco.base_path = 38 | ``` 39 | ### # Basic Http Authentication 40 | - To add basic http authentication add the `auth_name` and `auth_password` to the config file. 41 | ``` 42 | Apidoco.auth_name = 'authentication_name' 43 | Apidoco.auth_password = 'authentication_password' 44 | ``` 45 | 46 | ### # `app_name` 47 | - The `app_name` will be added to the sidebar 48 | ``` 49 | Apidoco.app_name = 'Apidoco Demo' 50 | ``` 51 | 52 | ### # `base_path` 53 | - Sets the root folder for the documentation 54 | - Default: `docs/api` 55 | ``` 56 | Apidoco.base_path = 'documentations' 57 | ``` 58 | 59 | ## Generators 60 | 61 | To create a Api documentation file for an action: 62 | 63 | ```ruby 64 | rails g apidoco resource 65 | ``` 66 | For Example: 67 | ``` 68 | rails g apidoco v1/posts 69 | ``` 70 | will create the following files by default with sample content 71 | - docs/api/v1/posts/show.json 72 | - docs/api/v1/posts/create.json 73 | - docs/api/v1/posts/update.json 74 | - docs/api/v1/posts/destroy.json 75 | - docs/api/v1/posts/index.json 76 | 77 | The root path will be based on the `base_path` config. 78 | 79 | If you need to create Api documention file for actions other than default 80 | crud actions, you need to specify the actions for which the files need to be generated 81 | 82 | ```ruby 83 | rails g apidoco v1/posts download upload 84 | ``` 85 | will create the following files with sample content 86 | - docs/api/v1/posts/download.json 87 | - docs/api/v1/posts/upload.json 88 | 89 | ### Sample API documentation format 90 | 91 | ``` 92 | // docs/api/v1/posts/create.json 93 | { 94 | "published": true, 95 | 96 | "name": "Create", 97 | 98 | "sort_order": 1, 99 | 100 | "end_point": "api/v1/posts/:id.json", 101 | 102 | "http_method": "POST", 103 | 104 | "params": [ 105 | { 106 | "key": "post[title]", 107 | "required": true, 108 | "type": "String", 109 | "description": "Title of the post", 110 | "validations": ["Should be less than or equal to 40 characters"] 111 | }, 112 | { 113 | "key": "post[content]", 114 | "required": true, 115 | "type": "String", 116 | "description": "Content/Body of the post", 117 | "validations": ["Should be less than or equal to 300 characters"] 118 | }, 119 | { 120 | "key": "post[publsihed]", 121 | "required": true, 122 | "type": "Boolean", 123 | "description": "Published status of the post" 124 | } 125 | ], 126 | 127 | "header": { 128 | "Authentication": "Token token=", 129 | "Content-Type": "application/json" 130 | }, 131 | 132 | "response_properties": [ 133 | { 134 | "key": "success", 135 | "type": "Boolean" 136 | }, { 137 | "key": "message", 138 | "type": "String", 139 | "description": "It can be any generic message. Examples:- Successfully created, Missing properties - title, content" 140 | } 141 | ], 142 | 143 | "examples": [ 144 | { 145 | "request_headers": { 146 | "Authentication": "Token token=", 147 | "Content-Type": "application/json" 148 | }, 149 | 150 | "request": { 151 | "post": { 152 | "title": "Ruby is awesome", 153 | "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec interdum a tellus sed finibus.", 154 | "published": false 155 | } 156 | }, 157 | 158 | "response_headers": { 159 | "Authentication": "Token token=" 160 | }, 161 | 162 | "response": { 163 | "suceess": true, 164 | "message": "Successfully created" 165 | } 166 | } 167 | ] 168 | } 169 | ``` 170 | 171 | ``` 172 | //docs/api/v1/posts/delete.json 173 | { 174 | "published": true, 175 | 176 | "name": "Destroy Post", 177 | 178 | "sort_order": 6, 179 | 180 | "end_point": "api/v1/posts/:id.json", 181 | 182 | "http_method": "DELETE", 183 | 184 | "header": { 185 | "Authentication": "Token token=", 186 | "Content-Type": "application/json" 187 | }, 188 | 189 | "response_properties": [ 190 | { 191 | "key": "success", 192 | "type": "Boolean" 193 | }, { 194 | "key": "message", 195 | "type": "String", 196 | "description": "It can be any generic message. Examples:- Successfully created, Missing properties - title, content" 197 | } 198 | ], 199 | 200 | "examples": [ 201 | { 202 | "request_headers": { 203 | "Authentication": "Token token=", 204 | "Content-Type": "application/json" 205 | }, 206 | 207 | "response": { 208 | "suceess": true, 209 | "message": "Successfully destroyed" 210 | } 211 | } 212 | ] 213 | } 214 | ``` 215 | 216 | ## Documentation format reference 217 | 218 | ### # published 219 | - Set this to false if you do not want to list this api 220 | - Optional 221 | - Default: true 222 | 223 | ### # name 224 | - Name of the api 225 | - Required 226 | 227 | ### # sort_order 228 | - Order of the api to be listed 229 | - Optional 230 | 231 | ### # end_point 232 | - Required 233 | - Usage: 234 | ``` 235 | "end_point": "/posts" 236 | ``` 237 | 238 | ### # http_method 239 | - The HTTP method of the API 240 | - Required 241 | - Usage: 242 | ``` 243 | "http_method": "GET" 244 | ``` 245 | 246 | ### # params 247 | - Parameters to be used 248 | - Optional 249 | - Usage: 250 | ``` 251 | "params": [ 252 | { 253 | "key": "post['name']", 254 | 255 | "required": true, 256 | 257 | "type": "String", 258 | 259 | "notes": ["Name or title of the post"], 260 | 261 | "validations": ["should be less than or equal to 150 characters"] 262 | } 263 | ] 264 | ``` 265 | 266 | ### # header 267 | - headers to be used 268 | - Optional 269 | - Usage: 270 | ``` 271 | "header": { 272 | "Authorization": "Token token=", 273 | "Content-type": 'application/json' 274 | } 275 | ``` 276 | 277 | ### # response_properties 278 | - Describing the properties in the response body 279 | - Optional 280 | - Usage: 281 | ``` 282 | "response_properties": [ 283 | { 284 | "key": "success", 285 | "type": "Boolean" 286 | }, { 287 | "key": "message", 288 | "type": "String", 289 | "description": "It can be any generic message. Examples:- Successfully created." 290 | } 291 | ], 292 | ``` 293 | 294 | ### # examples 295 | - Array of sample requests, responses and their headers 296 | - Optional 297 | - Usage: 298 | ``` 299 | "examples": [ 300 | { 301 | "request_headers": { 302 | "Authorization": "Token token=", 303 | "Content-type": 'application/json' 304 | }, 305 | 306 | "request": { 307 | "post": { 308 | "name": "I was scared" 309 | } 310 | }, 311 | 312 | "response_headers": { 313 | "Content-type": 'application/json' 314 | }, 315 | 316 | "response": { 317 | "message": "Post was successfully created", 318 | "id": 101 319 | } 320 | } 321 | ] 322 | ``` 323 | 324 | ## License 325 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 326 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 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 = 'Apidoco' 12 | rdoc.options << '--line-numbers' 13 | rdoc.rdoc_files.include('README.md') 14 | rdoc.rdoc_files.include('lib/**/*.rb') 15 | end 16 | 17 | APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__) 18 | 19 | load 'rails/tasks/engine.rake' 20 | 21 | load 'rails/tasks/statistics.rake' 22 | 23 | require 'bundler/gem_tasks' 24 | 25 | require 'rake/testtask' 26 | 27 | require 'rspec/core' 28 | 29 | require 'rspec/core/rake_task' 30 | 31 | desc 'Run all specs in spec directory (excluding plugin specs)' 32 | RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare') 33 | 34 | task default: :spec 35 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /apidoco.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path('../lib', __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require 'apidoco/version' 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |s| 8 | s.name = 'apidoco' 9 | s.version = Apidoco::VERSION 10 | s.authors = ['Al Ameen', 'Sufinsha Musthafa', 'Nidhin S G', 'Aby George'] 11 | s.email = ['alameenkhader@gmail.com', 'nidhinsg@gmail.com'] 12 | s.homepage = 'https://github.com/72pulses/apidoco' 13 | s.summary = 'Document Rest APIs' 14 | s.description = 'Document Rest APIs.' 15 | s.license = 'MIT' 16 | 17 | s.files = Dir['{app,config,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.md'] 18 | s.test_files = Dir['spec/**/*'] 19 | 20 | s.add_runtime_dependency 'rails', '>= 5.0.0' # Do not specify the rails version 21 | 22 | s.add_development_dependency 'apparition', '~> 0.1', '>= 0.1.0' 23 | s.add_development_dependency 'capybara', '~> 3.31', '>= 3.31.0' 24 | s.add_development_dependency 'generator_spec', '~> 0.9', '>= 0.9.4' 25 | s.add_development_dependency 'pry-byebug', '~> 3.9.0', '>= 3.9.0' 26 | s.add_development_dependency 'puma', '~> 4.3', '>= 4.3.3' 27 | s.add_development_dependency 'rspec-rails', '~> 4.0', '>= 4.0.0' 28 | s.add_development_dependency 'sass-rails', '>= 5.0.0' 29 | s.add_development_dependency 'sqlite3', '~> 1.3', '>= 1.3.13' 30 | end 31 | -------------------------------------------------------------------------------- /app/assets/config/apidoco_manifest.js: -------------------------------------------------------------------------------- 1 | //= link_directory ../javascripts/apidoco .js 2 | //= link_directory ../stylesheets/apidoco .css 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/apidoco_app.js: -------------------------------------------------------------------------------- 1 | angular.module('apiDocoApp', ['ngclipboard']); 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/application.js: -------------------------------------------------------------------------------- 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 any plugin's vendor/assets/javascripts directory 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. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require angular/1.8.0/angular 14 | // 15 | //= require apidoco/jquery.min 16 | //= require apidoco/jquery.json-viewer 17 | //= require apidoco/bootstrap/bootstrap 18 | //= require apidoco/clipboard.min 19 | //= require apidoco/directives/ngclipboard 20 | //= require apidoco/apidoco_app 21 | // 22 | // Icons 23 | //= require apidoco/icons/linkIcon 24 | //= require apidoco/icons/copyIcon 25 | //= require apidoco/icons/redirectIcon 26 | // 27 | //= Components 28 | //= require apidoco/components/tabbed/ad-tabbed 29 | //= require apidoco/components/tabbed/headers/ad-headers 30 | //= require apidoco/components/tabbed/body-properties/ad-body-properties 31 | //= require apidoco/components/tabbed/example-headers/ad-example-headers 32 | //= require apidoco/components/tabbed/example-body/ad-example-body 33 | // 34 | //= require apidoco/directives/jq_json_viewer 35 | //= require apidoco/controllers/documentations_controller 36 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v1.6.0 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Clipboard=e()}}(function(){var e,t,n;return function e(t,n,o){function i(a,c){if(!n[a]){if(!t[a]){var l="function"==typeof require&&require;if(!c&&l)return l(a,!0);if(r)return r(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var s=n[a]={exports:{}};t[a][0].call(s.exports,function(e){var n=t[a][1][e];return i(n?n:e)},s,s.exports,e,t,n,o)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;a0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function e(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function e(){var t=this,n="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=document.body.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[n?"right":"left"]="-9999px";var o=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=o+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,document.body.appendChild(this.fakeElem),this.selectedText=(0,i.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function e(){this.fakeHandler&&(document.body.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(document.body.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function e(){this.selectedText=(0,i.default)(this.target),this.copyText()}},{key:"copyText",value:function e(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function e(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function e(){this.target&&this.target.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function e(){this.removeFake()}},{key:"action",set:function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function e(){return this._action}},{key:"target",set:function e(t){if(void 0!==t){if(!t||"object"!==("undefined"==typeof t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function e(){return this._target}}]),e}();e.exports=c})},{select:5}],8:[function(t,n,o){!function(i,r){if("function"==typeof e&&e.amd)e(["module","./clipboard-action","tiny-emitter","good-listener"],r);else if("undefined"!=typeof o)r(n,t("./clipboard-action"),t("tiny-emitter"),t("good-listener"));else{var a={exports:{}};r(a,i.clipboardAction,i.tinyEmitter,i.goodListener),i.clipboard=a.exports}}(this,function(e,t,n,o){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function c(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}var u=i(t),s=i(n),f=i(o),d=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText}},{key:"listenClick",value:function e(t){var n=this;this.listener=(0,f.default)(t,"click",function(e){return n.onClick(e)})}},{key:"onClick",value:function e(t){var n=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new u.default({action:this.action(n),target:this.target(n),text:this.text(n),trigger:n,emitter:this})}},{key:"defaultAction",value:function e(t){return l("action",t)}},{key:"defaultTarget",value:function e(t){var n=l("target",t);if(n)return document.querySelector(n)}},{key:"defaultText",value:function e(t){return l("text",t)}},{key:"destroy",value:function e(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["copy","cut"],n="string"==typeof t?[t]:t,o=!!document.queryCommandSupported;return n.forEach(function(e){o=o&&!!document.queryCommandSupported(e)}),o}}]),t}(s.default);e.exports=h})},{"./clipboard-action":7,"good-listener":4,"tiny-emitter":6}]},{},[8])(8)}); -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/ad-tabbed.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | 25 |
28 | 29 | 32 | 33 | 34 | 35 | 38 | 39 |
40 |
41 | 42 | 43 |
44 | 45 | 48 | 49 | 50 | 51 |
54 | 55 | 58 | 59 | 60 | 61 | 64 | 65 |
66 |
67 |
-------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/ad-tabbed.js.erb: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").component("adTabbed", { 4 | templateUrl: "<%= asset_path('apidoco/components/tabbed/ad-tabbed.html') %>", 5 | bindings: { 6 | doc: "<", 7 | index: "<", 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/body-properties/ad-body-properties.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
Body Properties
6 |
7 |
8 |
{{property.key}}
9 |
10 | REQUIRED 11 | OPTIONAL 12 |
13 |
14 |
{{property.type}}
15 |
{{property.description}}
16 |
17 | {{property.notes}} 18 |

19 | {{validation}}
20 |

21 |
22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/body-properties/ad-body-properties.js.erb: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").component("adBodyProperties", { 4 | templateUrl: 5 | "<%= asset_path('apidoco/components/tabbed/body-properties/ad-body-properties.html') %>", 6 | bindings: { 7 | properties: "<", 8 | showRequired: "@", 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/example-body/ad-example-body.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |
Body example
7 | 8 | 9 | 16 | 24 |
25 | 26 | 27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/example-body/ad-example-body.js.erb: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").component("adExampleBody", { 4 | templateUrl: "<%= asset_path('apidoco/components/tabbed/example-body/ad-example-body.html') %>", 5 | bindings: { 6 | body: "<", 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/example-headers/ad-example-headers.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Headers example
4 |
5 | 6 | 7 |
8 |
9 |
10 |
-------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/example-headers/ad-example-headers.js.erb: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").component("adExampleHeaders", { 4 | templateUrl: "<%= asset_path('apidoco/components/tabbed/example-headers/ad-example-headers.html') %>", 5 | bindings: { 6 | headers: "<", 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/headers/ad-headers.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Headers
4 |
5 |
6 | {{key}} 7 | 8 |
9 |
string
10 |
11 | {{value}} 12 |
13 |
14 |
15 |
-------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/components/tabbed/headers/ad-headers.js.erb: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").component("adHeaders", { 4 | templateUrl: "<%= asset_path('apidoco/components/tabbed/headers/ad-headers.html') %>", 5 | bindings: { 6 | headers: "<", 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/controllers/documentations_controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('apiDocoApp') 4 | .controller('DocumentationController', ['$scope', '$window', function ($scope, $window) { 5 | $scope.navigateToCurrentVersion = function (versionName) { 6 | var version = $scope.documentationVersions.filter(function(v) { 7 | return v.name === versionName; 8 | })[0]; 9 | $window.location.href = version.path; 10 | }; 11 | 12 | $scope.versionAddress = function () { 13 | return $window.location.href.split('#')[0]; 14 | }; 15 | 16 | $scope.viewRaw = function(data) { 17 | var dataStingified = JSON.stringify(data, null, 2); 18 | var x = window.open(); 19 | 20 | x.document.open(); 21 | x.document.write('
' + dataStingified + '
'); 22 | x.document.close(); 23 | }; 24 | 25 | $scope.initMenuToggle = function() { 26 | $(document).ready(function () { 27 | $("#menu-toggle").click(function(e) { 28 | e.preventDefault(); 29 | $("#wrapper").toggleClass("toggled"); 30 | }); 31 | }); 32 | }; 33 | 34 | $scope.init = function () { 35 | $scope.initMenuToggle(); 36 | }; 37 | 38 | $scope.init(); 39 | }]); 40 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/directives/jq_json_viewer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('apiDocoApp').directive('jqJsonViewer', [function() { 4 | return { 5 | restrict: 'A', 6 | scope: { 7 | data: "=" 8 | }, 9 | link: function(scope, elem, attrs) { 10 | $(elem).jsonViewer(scope.data, { withQuotes: true }); 11 | 12 | // Collapse the second level 13 | $(elem).find('ul.json-dict > li > ol > li > a.json-toggle').click(); 14 | } 15 | }; 16 | }]); 17 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/directives/ngclipboard.js: -------------------------------------------------------------------------------- 1 | /*! ngclipboard - v1.1.1 - 2016-02-26 2 | * https://github.com/sachinchoolur/ngclipboard 3 | * Copyright (c) 2016 Sachin; Licensed MIT */ 4 | (function() { 5 | 'use strict'; 6 | var MODULE_NAME = 'ngclipboard'; 7 | var angular, Clipboard; 8 | 9 | // Check for CommonJS support 10 | if (typeof module === 'object' && module.exports) { 11 | angular = require('angular'); 12 | Clipboard = require('clipboard'); 13 | module.exports = MODULE_NAME; 14 | } else { 15 | angular = window.angular; 16 | Clipboard = window.Clipboard; 17 | } 18 | 19 | angular.module(MODULE_NAME, []).directive('ngclipboard', function() { 20 | return { 21 | restrict: 'A', 22 | scope: { 23 | ngclipboardSuccess: '&', 24 | ngclipboardError: '&' 25 | }, 26 | link: function(scope, element) { 27 | var clipboard = new Clipboard(element[0]); 28 | 29 | clipboard.on('success', function(e) { 30 | scope.$apply(function () { 31 | scope.ngclipboardSuccess({ 32 | e: e 33 | }); 34 | }); 35 | }); 36 | 37 | clipboard.on('error', function(e) { 38 | scope.$apply(function () { 39 | scope.ngclipboardError({ 40 | e: e 41 | }); 42 | }); 43 | }); 44 | 45 | } 46 | }; 47 | }); 48 | }()); 49 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/icons/copyIcon.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").directive("copyIcon", [ 4 | function () { 5 | return { 6 | restrict: "E", 7 | template: 8 | '", 11 | }; 12 | }, 13 | ]); 14 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/icons/linkIcon.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").directive("linkIcon", [ 4 | function () { 5 | return { 6 | restrict: "E", 7 | template: 8 | '', 10 | }; 11 | }, 12 | ]); 13 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/icons/redirectIcon.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | angular.module("apiDocoApp").directive("redirectIcon", [ 4 | function () { 5 | return { 6 | restrict: "E", 7 | template: 8 | '' + 9 | '' + 10 | '', 11 | }; 12 | }, 13 | ]); 14 | -------------------------------------------------------------------------------- /app/assets/javascripts/apidoco/jquery.json-viewer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery json-viewer 3 | * @author: Alexandre Bodelot 4 | */ 5 | (function($){ 6 | /** 7 | * Check if arg is either an array with at least 1 element, or a dict with at least 1 key 8 | * @return boolean 9 | */ 10 | function isCollapsable(arg) { 11 | return arg instanceof Object && Object.keys(arg).length > 0; 12 | } 13 | 14 | /** 15 | * Check if a string represents a valid url 16 | * @return boolean 17 | */ 18 | function isUrl(string) { 19 | var regexp = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; 20 | return regexp.test(string); 21 | } 22 | 23 | /** 24 | * Transform a json object into html representation 25 | * @return string 26 | */ 27 | function json2html(json, options) { 28 | var html = ''; 29 | if (typeof json === 'string') { 30 | /* Escape tags */ 31 | json = json.replace(/&/g, '&').replace(//g, '>'); 32 | if (isUrl(json)) 33 | html += '' + json + ''; 34 | else 35 | html += '"' + json + '"'; 36 | } 37 | else if (typeof json === 'number') { 38 | html += '' + json + ''; 39 | } 40 | else if (typeof json === 'boolean') { 41 | html += '' + json + ''; 42 | } 43 | else if (json === null) { 44 | html += 'null'; 45 | } 46 | else if (json instanceof Array) { 47 | if (json.length > 0) { 48 | html += '[
    '; 49 | for (var i = 0; i < json.length; ++i) { 50 | html += '
  1. '; 51 | /* Add toggle button if item is collapsable */ 52 | if (isCollapsable(json[i])) { 53 | html += ''; 54 | } 55 | html += json2html(json[i], options); 56 | /* Add comma if item is not last */ 57 | if (i < json.length - 1) { 58 | html += ','; 59 | } 60 | html += '
  2. '; 61 | } 62 | html += '
]'; 63 | } 64 | else { 65 | html += '[]'; 66 | } 67 | } 68 | else if (typeof json === 'object') { 69 | var key_count = Object.keys(json).length; 70 | if (key_count > 0) { 71 | html += '{
    '; 72 | for (var key in json) { 73 | if (json.hasOwnProperty(key)) { 74 | html += '
  • '; 75 | var keyRepr = options.withQuotes ? 76 | '"' + key + '"' : key; 77 | /* Add toggle button if item is collapsable */ 78 | if (isCollapsable(json[key])) { 79 | html += '' + keyRepr + ''; 80 | } 81 | else { 82 | html += keyRepr; 83 | } 84 | html += ': ' + json2html(json[key], options); 85 | /* Add comma if item is not last */ 86 | if (--key_count > 0) 87 | html += ','; 88 | html += '
  • '; 89 | } 90 | } 91 | html += '
}'; 92 | } 93 | else { 94 | html += '{}'; 95 | } 96 | } 97 | return html; 98 | } 99 | 100 | /** 101 | * jQuery plugin method 102 | * @param json: a javascript object 103 | * @param options: an optional options hash 104 | */ 105 | $.fn.jsonViewer = function(json, options) { 106 | options = options || {}; 107 | 108 | /* jQuery chaining */ 109 | return this.each(function() { 110 | 111 | /* Transform to HTML */ 112 | var html = json2html(json, options); 113 | if (isCollapsable(json)) 114 | html = '' + html; 115 | 116 | /* Insert HTML in target DOM element */ 117 | $(this).html(html); 118 | 119 | /* Bind click on toggle buttons */ 120 | $(this).off('click'); 121 | $(this).on('click', 'a.json-toggle', function() { 122 | var target = $(this).toggleClass('collapsed').siblings('ul.json-dict, ol.json-array'); 123 | target.toggle(); 124 | if (target.is(':visible')) { 125 | target.siblings('.json-placeholder').remove(); 126 | } 127 | else { 128 | var count = target.children('li').length; 129 | var placeholder = count + (count > 1 ? ' items' : ' item'); 130 | target.after('' + placeholder + ''); 131 | } 132 | return false; 133 | }); 134 | 135 | /* Simulate click on toggle button when placeholder is clicked */ 136 | $(this).on('click', 'a.json-placeholder', function() { 137 | $(this).siblings('a.json-toggle').click(); 138 | return false; 139 | }); 140 | 141 | if (options.collapsed == true) { 142 | /* Trigger click to collapse all nodes */ 143 | $(this).find('a.json-toggle').click(); 144 | } 145 | }); 146 | }; 147 | })(jQuery); 148 | -------------------------------------------------------------------------------- /app/assets/stylesheets/apidoco/application.css: -------------------------------------------------------------------------------- 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 any plugin's vendor/assets/stylesheets directory 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 other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/apidoco/custom.css: -------------------------------------------------------------------------------- 1 | .api_details { 2 | border: 1px solid rgba(0, 0, 0, 0.125); 3 | padding: 20px; 4 | background-color: #fff; 5 | margin-bottom: -1px; 6 | } 7 | 8 | #page-content-wrapper { 9 | background-color: #ffffff; 10 | padding: 0px; 11 | } 12 | 13 | .text_wheat { 14 | color: wheat; 15 | } 16 | 17 | pre { 18 | background-color: #f6f8fa; 19 | border-radius: 3px; 20 | border: none; 21 | } 22 | 23 | h2.section-title { 24 | font-size: 20px; 25 | font-weight: bold; 26 | border-bottom: 1px solid #ededed; 27 | padding-bottom: 10px; 28 | } 29 | 30 | .section-block { 31 | margin-bottom: 15px; 32 | margin-top: 15px; 33 | } 34 | 35 | h3 { 36 | font-size: 14px; 37 | font-weight: bold; 38 | } 39 | 40 | .section-block .block-title { 41 | margin-top: 0; 42 | } 43 | 44 | .container-flex { 45 | display: flex; 46 | width: 100%; 47 | position: relative; 48 | } 49 | 50 | .container-flex .description { 51 | flex: 0 0 65%; 52 | } 53 | 54 | .container-flex .examples { 55 | position: absolute; 56 | left: 70%; 57 | top: 0; 58 | bottom: 0; 59 | right: 0; 60 | overflow: auto; 61 | } 62 | 63 | .built-with { 64 | position: absolute; 65 | bottom: 0; 66 | left: 20%; 67 | padding: 10px; 68 | font-size: 12px; 69 | } 70 | 71 | .built-with a, .built-with a:hover { 72 | color: white; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /app/assets/stylesheets/apidoco/helpers.css: -------------------------------------------------------------------------------- 1 | /* All the helper/reusable classes should be in here */ 2 | .pointer { 3 | cursor: pointer; 4 | } 5 | 6 | .mt-2 { 7 | margin-top: 2px !important; 8 | } 9 | 10 | .mt-10 { 11 | margin-top: 10px !important; 12 | } 13 | 14 | .mb-50 { 15 | margin-bottom: 50px !important; 16 | } 17 | 18 | .padding-10 { 19 | padding: 10px !important; 20 | } 21 | 22 | .padding-15 { 23 | padding: 15px !important; 24 | } 25 | -------------------------------------------------------------------------------- /app/assets/stylesheets/apidoco/jquery.json-viewer.css: -------------------------------------------------------------------------------- 1 | /* Syntax highlighting for JSON objects */ 2 | ul.json-dict, ol.json-array { 3 | list-style-type: none; 4 | margin: 0 0 0 1px; 5 | border-left: 1px dotted #ccc; 6 | padding-left: 2em; 7 | } 8 | .json-string { 9 | color: #0B7500; 10 | } 11 | .json-literal { 12 | color: #1A01CC; 13 | font-weight: bold; 14 | } 15 | 16 | /* Toggle button */ 17 | a.json-toggle { 18 | position: relative; 19 | color: inherit; 20 | text-decoration: none; 21 | } 22 | a.json-toggle:focus { 23 | outline: none; 24 | } 25 | a.json-toggle:before { 26 | color: #aaa; 27 | content: "\25BC"; /* down arrow */ 28 | position: absolute; 29 | display: inline-block; 30 | width: 1em; 31 | left: -1em; 32 | } 33 | a.json-toggle.collapsed:before { 34 | transform: rotate(-90deg); /* Use rotated down arrow, prevents right arrow appearing smaller than down arrow in some browsers */ 35 | -ms-transform: rotate(-90deg); 36 | -webkit-transform: rotate(-90deg); 37 | } 38 | 39 | /* Collapsable placeholder links */ 40 | a.json-placeholder { 41 | color: #aaa; 42 | padding: 0 1em; 43 | text-decoration: none; 44 | } 45 | a.json-placeholder:hover { 46 | text-decoration: underline; 47 | } 48 | -------------------------------------------------------------------------------- /app/assets/stylesheets/apidoco/ng-prettyjson.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @license ng-prettyjson - v0.2.0 3 | * (c) 2013 Julien VALERY https://github.com/darul75/ng-prettyjson 4 | * License: MIT 5 | **/ 6 | 7 | pre.pretty-json{padding:16px;margin:5px}pre.pretty-json span.string{color:green}pre.pretty-json span.number{color:#ff8c00}pre.pretty-json span.boolean{color:#00f}pre.pretty-json span.null{color:#ff00ff}pre.pretty-json span.key{color:red}pre.pretty-json span.sep{color:#000} -------------------------------------------------------------------------------- /app/assets/stylesheets/apidoco/simple-sidebar.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - Simple Sidebar (http://startbootstrap.com/) 3 | * Copyright 2013-2016 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE) 5 | */ 6 | 7 | body { 8 | overflow-x: hidden; 9 | } 10 | 11 | /* Toggle Styles */ 12 | 13 | #wrapper { 14 | padding-left: 0; 15 | -webkit-transition: all 0.5s ease; 16 | -moz-transition: all 0.5s ease; 17 | -o-transition: all 0.5s ease; 18 | transition: all 0.5s ease; 19 | } 20 | 21 | #wrapper.toggled { 22 | padding-left: 225px; 23 | } 24 | 25 | #sidebar-wrapper { 26 | z-index: 1000; 27 | position: fixed; 28 | left: 225px; 29 | width: 0; 30 | height: 100%; 31 | margin-left: -225px; 32 | overflow-y: auto; 33 | background: #364150; 34 | -webkit-transition: all 0.5s ease; 35 | -moz-transition: all 0.5s ease; 36 | -o-transition: all 0.5s ease; 37 | transition: all 0.5s ease; 38 | color: #b4bcc8; 39 | } 40 | 41 | #wrapper.toggled #sidebar-wrapper { 42 | width: 225px; 43 | } 44 | 45 | #page-content-wrapper { 46 | width: 100%; 47 | position: absolute; 48 | padding: 15px; 49 | } 50 | 51 | #wrapper.toggled #page-content-wrapper { 52 | position: absolute; 53 | margin-right: -225px; 54 | } 55 | 56 | /* Sidebar Styles */ 57 | 58 | .sidebar-nav { 59 | position: absolute; 60 | top: 0; 61 | width: 95%; 62 | margin: 0; 63 | padding: 0; 64 | margin-left: 10px; 65 | list-style: none; 66 | } 67 | 68 | .sidebar-nav li { 69 | margin-bottom: 3px; 70 | } 71 | 72 | .sidebar-nav li a { 73 | display: block; 74 | text-decoration: none; 75 | color: #b4bcc8; 76 | } 77 | 78 | .sidebar-nav li a:hover, 79 | .sidebar-nav li a:active, 80 | .sidebar-nav li a.active, 81 | .sidebar-nav li a:focus { 82 | text-decoration: none; 83 | color: #fff; 84 | background: rgba(255,255,255,0.2); 85 | } 86 | 87 | .sidebar-nav > .sidebar-brand { 88 | height: 65px; 89 | font-size: 18px; 90 | line-height: 60px; 91 | } 92 | 93 | .sidebar-nav > .sidebar-brand a { 94 | color: #999999; 95 | } 96 | 97 | .sidebar-nav > .sidebar-brand a:hover { 98 | color: #fff; 99 | background: none; 100 | } 101 | .sidebar-nav ul { 102 | margin-bottom: 20px !important; 103 | padding-left: 30px !important; 104 | } 105 | 106 | @media(min-width:768px) { 107 | #wrapper { 108 | padding-left: 225px; 109 | } 110 | 111 | #wrapper.toggled { 112 | padding-left: 0; 113 | } 114 | 115 | #sidebar-wrapper { 116 | width: 20%; 117 | min-width: 300px; 118 | max-width: 400px; 119 | } 120 | 121 | #wrapper.toggled #sidebar-wrapper { 122 | width: 0; 123 | } 124 | 125 | #page-content-wrapper { 126 | padding: 20px; 127 | position: relative; 128 | } 129 | 130 | #wrapper.toggled #page-content-wrapper { 131 | position: relative; 132 | margin-right: 0; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /app/controllers/apidoco/apis_controller.rb: -------------------------------------------------------------------------------- 1 | require_dependency 'apidoco/application_controller' 2 | 3 | module Apidoco 4 | class ApisController < ApplicationController 5 | before_action :set_version_parser 6 | 7 | http_basic_authenticate_with name: Apidoco.auth_name, password: Apidoco.auth_password, 8 | if: proc { Apidoco.auth_name && Apidoco.auth_password } 9 | 10 | def index 11 | redirect_to api_path(id: @vp.documentations.first.name) 12 | end 13 | 14 | def show 15 | @documentation = @vp.documentation(params[:id]) 16 | @data = @documentation.as_json 17 | rescue Apidoco::FileParseError => e 18 | render plain: e.info 19 | end 20 | 21 | private 22 | 23 | def set_version_parser 24 | @vp = VersionParser.new 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/controllers/apidoco/application_controller.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | class ApplicationController < ActionController::Base 3 | protect_from_forgery with: :exception 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/helpers/apidoco/application_helper.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | module ApplicationHelper 3 | def documentation_versions(version_parser) 4 | version_parser.documentations.map do |documentation| 5 | { name: documentation.name, path: api_path(id: documentation.name) } 6 | end 7 | end 8 | 9 | def build_documentation_array(documentations) 10 | documentation_array = documentations.map do |documentation| 11 | if documentation[:is_folder] 12 | build_documentation_array(documentation[:children]) 13 | else 14 | documentation 15 | end 16 | end 17 | 18 | documentation_array.flatten 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/views/apidoco/apis/_side_bar.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 33 | 34 | -------------------------------------------------------------------------------- /app/views/apidoco/apis/show.html.erb: -------------------------------------------------------------------------------- 1 |
6 | 7 | <%= render partial: "side_bar" %> 8 | 9 |
10 |
11 |
12 |
13 |
14 |
15 | BASE URL 16 | {{ data.base_url }} 17 |
18 |

19 | 20 |
21 |
22 | 23 | 24 | 27 | 28 | 29 | 30 |
31 | 32 |
{{x.name}}
33 | 36 |
37 | 38 | 39 |
40 |
41 |
42 | 43 | 46 |
47 |
48 |
49 | 50 | 51 |

{{x.description}}

52 | 53 | 54 | 55 |
56 |

Notes

57 |

58 | {{ note }} 59 |

60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | -------------------------------------------------------------------------------- /app/views/layouts/apidoco/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= Apidoco.app_name %> 5 | <%= stylesheet_link_tag "apidoco/application", media: "all" %> 6 | <%= javascript_include_tag "apidoco/application" %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 |
11 | <%= yield %> 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails gems 3 | # installed from the root of your application. 4 | 5 | ENGINE_ROOT = File.expand_path('../..', __FILE__) 6 | ENGINE_PATH = File.expand_path('../../lib/apidoco/engine', __FILE__) 7 | 8 | # Set up gems listed in the Gemfile. 9 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 10 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 11 | 12 | require 'rails/all' 13 | require 'rails/engine/commands' 14 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.assets.precompile += %w[apidoco_manifest.js] 2 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Apidoco::Engine.routes.draw do 2 | root 'apis#index' 3 | resources :apis, only: [:show] 4 | end 5 | -------------------------------------------------------------------------------- /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/images/1.png -------------------------------------------------------------------------------- /lib/apidoco.rb: -------------------------------------------------------------------------------- 1 | require 'apidoco/engine' 2 | require 'apidoco/version_parser' 3 | require 'apidoco/version_documentation' 4 | require 'apidoco/folder_parser' 5 | require 'apidoco/file_parser' 6 | require 'apidoco/file_parse_error' 7 | 8 | APIDOCO_TITLE = 'ApiDoco' 9 | 10 | module Apidoco 11 | mattr_accessor :app_name, :auth_name, :auth_password, :base_path 12 | 13 | self.app_name = APIDOCO_TITLE 14 | self.base_path = 'docs/api' 15 | end 16 | -------------------------------------------------------------------------------- /lib/apidoco/engine.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | class Engine < ::Rails::Engine 3 | isolate_namespace Apidoco 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/apidoco/file_parse_error.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | class FileParseError < StandardError 3 | attr_accessor :file, :message 4 | 5 | def initialize(file, message) 6 | self.file = file 7 | self.message = message 8 | end 9 | 10 | def info 11 | "Failed to parse #{file}, #{message}" 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/apidoco/file_parser.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | # Parse a folder and find all the sub folders and files 3 | class FileParser 4 | attr_accessor :file, :parents 5 | 6 | def initialize(file, parents:) 7 | self.file = file 8 | self.parents = parents 9 | end 10 | 11 | def as_json 12 | content.merge(parents: parents, id: id) 13 | end 14 | 15 | def content 16 | @content ||= JSON.parse(File.read(file)) 17 | rescue JSON::ParserError => e 18 | raise Apidoco::FileParseError.new file, e.message 19 | end 20 | 21 | def id 22 | parents.push(content['name']).join('-').downcase.delete(' ') 23 | end 24 | 25 | def published? 26 | content['published'].nil? || content['published'] 27 | end 28 | 29 | def sort_order 30 | content['sort_order'] || 999 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/apidoco/folder_parser.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | # Parse a folder and find all the sub folders and files 3 | class FolderParser 4 | attr_accessor :directory, :parents 5 | 6 | def initialize(directory, parents: []) 7 | self.directory = directory 8 | self.parents = parents 9 | end 10 | 11 | def as_json 12 | { 13 | is_folder: true, 14 | name: basename, 15 | children: children.select(&:published?).yield_self(&method(:sorter)).map(&:as_json) 16 | } 17 | end 18 | 19 | def basename 20 | directory.basename.to_s.titleize 21 | end 22 | 23 | def children 24 | directory.children.map do |child| 25 | hierrarchy = parents + [basename] 26 | if child.directory? 27 | Apidoco::FolderParser.new(child, parents: hierrarchy) 28 | else 29 | Apidoco::FileParser.new(child, parents: hierrarchy) 30 | end 31 | end 32 | end 33 | 34 | def published? 35 | true 36 | end 37 | 38 | def sort_order 39 | basename 40 | end 41 | 42 | private 43 | 44 | def sorter(files) 45 | files.sort do |a, b| 46 | if a.sort_order.class == b.sort_order.class 47 | a.sort_order <=> b.sort_order 48 | elsif a.sort_order.is_a?(String) 49 | -1 50 | else 51 | 1 52 | end 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/apidoco/version.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | VERSION = '1.6.4'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/apidoco/version_documentation.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | class VersionDocumentation 3 | attr_accessor :directory 4 | 5 | def initialize(directory) 6 | self.directory = directory 7 | end 8 | 9 | def name 10 | directory.basename.to_s 11 | end 12 | alias_method :version, :name 13 | 14 | def as_json 15 | { 16 | name: name, 17 | base_url: '', 18 | apis: documentations.flat_map(&:as_json) 19 | } 20 | end 21 | 22 | def documentations 23 | documentation_directories.map { |dir| FolderParser.new(dir) } 24 | end 25 | 26 | def documentation_directories 27 | directory.children.select(&:directory?) 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/apidoco/version_parser.rb: -------------------------------------------------------------------------------- 1 | module Apidoco 2 | # Parses the documentation versions, keeps track of all the documented api versions 3 | class VersionParser 4 | attr_accessor :base_path 5 | 6 | def initialize 7 | self.base_path = Rails.root.join(Apidoco.base_path) 8 | end 9 | 10 | def documentations 11 | documentation_directories.map { |dir| VersionDocumentation.new(dir) } 12 | end 13 | 14 | def documentation(version) 15 | documentations.find { |doc| doc.version.eql?(version) } 16 | end 17 | 18 | private 19 | 20 | def documentation_directories 21 | base_path.children.select(&:directory?) 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/generators/apidoco_generator.rb: -------------------------------------------------------------------------------- 1 | require 'apidoco' 2 | 3 | # 4 | # ApidocoGenerator 5 | # 6 | # @author sufinsha 7 | # 8 | class ApidocoGenerator < Rails::Generators::Base 9 | desc 'This generator creates empty folder for api versions' 10 | def create_apidoco_folder 11 | resource = args[0] 12 | 13 | resource_actions = actions(args[1..-1]) 14 | 15 | resource_actions.each do |action| 16 | create_file "#{Rails.root}/#{Apidoco.base_path}/#{file_name(resource, action)}", 17 | file_content(resource, action) 18 | end 19 | end 20 | 21 | private 22 | 23 | def actions(args) 24 | return args if args.present? 25 | 26 | %i[show index create update destroy] 27 | end 28 | 29 | def default_end_points_with_method(action) 30 | end_points_with_method = { 31 | index: { 32 | endpoint: '.json', method: 'GET', collection: true 33 | }, 34 | show: { 35 | endpoint: '/:id.json', method: 'GET', collection: false 36 | }, 37 | create: { 38 | endpoint: '.json', method: 'POST', collection: true 39 | }, 40 | update: { 41 | endpoint: '/:id.json', method: 'PUT|PATCH', collection: false 42 | }, 43 | destroy: { 44 | endpoint: '/:id.json', method: 'DELETE', collection: false 45 | } 46 | } 47 | end_points_with_method[action] || {} 48 | end 49 | 50 | def api_name(resource, action) 51 | endpoint_with_method = default_end_points_with_method(action.intern) 52 | resource_title = if endpoint_with_method[:collection] 53 | resource.pluralize.titleize 54 | else 55 | resource.singularize.titleize 56 | end 57 | "#{action.to_s.titleize} #{resource_title}" 58 | end 59 | 60 | def file_name(resource, action) 61 | "#{resource}/#{action}.json" 62 | end 63 | 64 | def resource_name(resource) 65 | resource.split('/').last 66 | end 67 | 68 | def file_content(resource, action) 69 | endpoint_with_method = default_end_points_with_method(action.intern) 70 | name = api_name(resource_name(resource), action) 71 | <<-FILE 72 | { 73 | "published": true, 74 | "name": "#{name}", 75 | "end_point": "#{resource}#{endpoint_with_method[:endpoint]}", 76 | "http_method": "#{endpoint_with_method[:method]}", 77 | "params": [], 78 | "header": {}, 79 | "examples": [{ 80 | "request": {}, 81 | "response": {} 82 | }] 83 | } 84 | FILE 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /lib/tasks/apidoco_tasks.rake: -------------------------------------------------------------------------------- 1 | # desc "Explaining what the task does" 2 | # task :apidoco do 3 | # # Task goes here 4 | # end 5 | -------------------------------------------------------------------------------- /spec/apidoco/file_parse_error_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Apidoco::FileParseError do 4 | let(:error) { described_class.new(Pathname.new('tmp/test.json'), 'Test') } 5 | 6 | describe '#info' do 7 | subject(:info) { error.info } 8 | 9 | it { is_expected.to eq('Failed to parse tmp/test.json, Test') } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/apidoco/file_parser_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Apidoco::FileParser do 4 | let(:doc) { { name: 'Create Resource' } } 5 | let(:file) do 6 | Tempfile.new.tap do |f| 7 | f.write(doc.to_json) 8 | f.rewind 9 | end 10 | end 11 | let(:file_parser) { described_class.new(file, parents: []) } 12 | 13 | after do 14 | file.close 15 | file.unlink 16 | end 17 | 18 | describe '#content' do 19 | subject(:content) { file_parser.content } 20 | 21 | context 'when parsing an invalid json file' do 22 | let(:file) do 23 | Tempfile.new.tap do |f| 24 | f.write('sdsd') 25 | f.rewind 26 | end 27 | end 28 | 29 | it { expect { content }.to raise_error(Apidoco::FileParseError) } 30 | end 31 | end 32 | 33 | describe '#id' do 34 | subject(:id) { file_parser.id } 35 | 36 | it { is_expected.to eq('createresource') } 37 | end 38 | 39 | describe '#published?' do 40 | subject(:published?) { file_parser.published? } 41 | 42 | context 'when published key is not available in the doc' do 43 | it { is_expected.to eq true } 44 | end 45 | 46 | context 'when published key is true in the doc' do 47 | let(:doc) { { published: true } } 48 | 49 | it { is_expected.to eq true } 50 | end 51 | 52 | context 'when published key is false in the doc' do 53 | let(:doc) { { published: false } } 54 | 55 | it { is_expected.to eq false } 56 | end 57 | end 58 | 59 | describe '#sort_order' do 60 | subject(:sort_order) { file_parser.sort_order } 61 | 62 | context 'when sort_order key is not available in the doc' do 63 | it { is_expected.to eq 999 } 64 | end 65 | 66 | context 'when sort_order key is available in the doc' do 67 | let(:doc) { { sort_order: 25 } } 68 | 69 | it { is_expected.to eq 25 } 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /spec/apidoco/folder_parser_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Apidoco::FolderParser do 4 | let(:doc) { { name: 'Create User' } } 5 | let(:file) do 6 | Tempfile.new.tap do |f| 7 | f.write(doc.to_json) 8 | f.rewind 9 | end 10 | end 11 | let(:directory) { double(basename: 'users', children: [file]) } 12 | let(:folder_parser) { described_class.new(directory, parents: []) } 13 | 14 | after do 15 | file.close 16 | file.unlink 17 | end 18 | 19 | describe '#as_json' do 20 | before { allow(file).to receive(:directory?).and_return(false) } 21 | 22 | subject(:as_json) { folder_parser.as_json } 23 | 24 | describe 'is_folder' do 25 | it { is_expected.to include(is_folder: true) } 26 | end 27 | 28 | describe 'name' do 29 | it { is_expected.to include(name: 'Users') } 30 | end 31 | 32 | describe 'children' do 33 | let(:sub_directory1) { double(basename: 'roles', children: [], directory?: true) } 34 | let(:sub_directory2) { double(basename: 'departments', children: [], directory?: true) } 35 | let(:file1) { file } 36 | let(:file2) do 37 | Tempfile.new.tap do |f| 38 | f.write({ name: 'Delete User' }.to_json) 39 | f.rewind 40 | end 41 | end 42 | 43 | before { allow(file2).to receive(:directory?).and_return(false) } 44 | 45 | after do 46 | file2.close 47 | file2.unlink 48 | end 49 | 50 | let(:directory) do 51 | double(basename: 'users', children: [file1, file2, sub_directory1, sub_directory2]) 52 | end 53 | 54 | it 'sorts the files and folders based on the sort order' do 55 | expect(as_json).to include(name: 'Users') 56 | expect(as_json[:children][0][:name]).to eq('Departments') 57 | expect(as_json[:children][1][:name]).to eq('Roles') 58 | expect(as_json[:children][2]['name']).to eq('Create User') 59 | expect(as_json[:children][3]['name']).to eq('Delete User') 60 | end 61 | end 62 | end 63 | 64 | describe '#base_name' do 65 | subject(:basename) { folder_parser.basename } 66 | 67 | it { is_expected.to eq('Users') } 68 | end 69 | 70 | describe '#children' do 71 | subject(:children) { folder_parser.children } 72 | 73 | context 'when the child is a directory' do 74 | before { allow(file).to receive(:directory?).and_return(true) } 75 | 76 | it { expect(children.first).to be_instance_of(Apidoco::FolderParser) } 77 | end 78 | 79 | context 'when the child is a file' do 80 | before { allow(file).to receive(:directory?).and_return(false) } 81 | 82 | it { expect(children.first).to be_instance_of(Apidoco::FileParser) } 83 | end 84 | end 85 | 86 | describe '#published?' do 87 | subject(:published?) { folder_parser.published? } 88 | 89 | it { is_expected.to eq(true) } 90 | end 91 | 92 | describe '#sort_order' do 93 | subject(:sort_order) { folder_parser.sort_order } 94 | 95 | it { is_expected.to eq('Users') } 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /spec/apidoco/version_documentation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Apidoco::VersionDocumentation do 4 | let(:sub_directory) do 5 | double(basename: 'users', directory?: true, children: []) 6 | end 7 | let(:directory) do 8 | double(basename: 'v1', children: [sub_directory]) 9 | end 10 | let(:version_documentation) { described_class.new(directory) } 11 | 12 | describe '#name' do 13 | subject(:name) { version_documentation.name } 14 | 15 | it { is_expected.to eq('v1') } 16 | end 17 | 18 | describe '#as_json' do 19 | subject(:as_json) { version_documentation.as_json } 20 | 21 | describe 'name' do 22 | it { is_expected.to include(name: 'v1') } 23 | end 24 | 25 | describe 'base_url' do 26 | it { is_expected.to include(base_url: '') } 27 | end 28 | 29 | describe 'apis' do 30 | before { expect(Apidoco::FolderParser).to receive(:new).with(sub_directory).and_call_original } 31 | 32 | it { is_expected.to include(apis: an_instance_of(Array)) } 33 | end 34 | end 35 | 36 | describe '#documentations' do 37 | subject(:documentations) { version_documentation.documentations } 38 | 39 | it { is_expected.to include(an_instance_of(Apidoco::FolderParser)) } 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/apidoco/version_parser_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Apidoco::VersionParser do 4 | let(:v1_directory) { double(basename: 'v1', directory?: true, children: []) } 5 | let(:v2_directory) { double(basename: 'v2', directory?: true, children: []) } 6 | let(:base_directory) { double(children: [v1_directory, v2_directory]) } 7 | let(:version_parser) { described_class.new } 8 | 9 | before { allow(version_parser).to receive(:base_path).and_return(base_directory) } 10 | 11 | describe '#documentations' do 12 | subject(:documentations) { version_parser.documentations } 13 | 14 | before do 15 | expect(Apidoco::VersionDocumentation).to receive(:new).with(v1_directory).and_call_original 16 | expect(Apidoco::VersionDocumentation).to receive(:new).with(v2_directory).and_call_original 17 | end 18 | 19 | it { is_expected.to include(an_instance_of(Apidoco::VersionDocumentation)) } 20 | end 21 | 22 | describe '#documentation' do 23 | subject(:documentation) { version_parser.documentation('v1') } 24 | 25 | it { expect(documentation.name).to eq('v1') } 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | 2 | //= link_tree ../images 3 | //= link_directory ../javascripts .js 4 | //= link_directory ../stylesheets .css 5 | //= link apidoco_manifest.js 6 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 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 any plugin's vendor/assets/javascripts directory 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. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require_tree . 14 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/cable.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the rails generate channel command. 3 | // 4 | //= require action_cable 5 | //= require_self 6 | //= require_tree ./channels 7 | 8 | (function() { 9 | this.App || (this.App = {}); 10 | 11 | App.cable = ActionCable.createConsumer(); 12 | 13 | }).call(this); 14 | -------------------------------------------------------------------------------- /spec/dummy/app/assets/javascripts/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/app/assets/javascripts/channels/.keep -------------------------------------------------------------------------------- /spec/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 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 any plugin's vendor/assets/stylesheets directory 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 other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /spec/dummy/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :exception 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /spec/dummy/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /spec/dummy/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= csrf_meta_tags %> 6 | 7 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 8 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /spec/dummy/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /spec/dummy/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /spec/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /spec/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /spec/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a starting point to setup your application. 15 | # Add necessary setup steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | # puts "\n== Copying sample files ==" 22 | # unless File.exist?('config/database.yml') 23 | # cp 'config/database.yml.sample', 'config/database.yml' 24 | # end 25 | 26 | puts "\n== Preparing database ==" 27 | system! 'bin/rails db:setup' 28 | 29 | puts "\n== Removing old logs and tempfiles ==" 30 | system! 'bin/rails log:clear tmp:clear' 31 | 32 | puts "\n== Restarting application server ==" 33 | system! 'bin/rails restart' 34 | end 35 | -------------------------------------------------------------------------------- /spec/dummy/bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /spec/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /spec/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | require 'apidoco' 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | # Settings in config/environments/* take precedence over those specified here. 11 | # Application configuration should go into files in config/initializers 12 | # -- all .rb files in that directory are automatically loaded. 13 | 14 | Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) 6 | -------------------------------------------------------------------------------- /spec/dummy/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /spec/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /spec/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | if Rails.root.join('tmp/caching-dev.txt').exist? 17 | config.action_controller.perform_caching = true 18 | 19 | config.cache_store = :memory_store 20 | config.public_file_server.headers = { 21 | 'Cache-Control' => 'public, max-age=172800' 22 | } 23 | else 24 | config.action_controller.perform_caching = false 25 | 26 | config.cache_store = :null_store 27 | end 28 | 29 | # Don't care if the mailer can't send. 30 | config.action_mailer.raise_delivery_errors = false 31 | 32 | config.action_mailer.perform_caching = false 33 | 34 | # Print deprecation notices to the Rails logger. 35 | config.active_support.deprecation = :log 36 | 37 | # Raise an error on page load if there are pending migrations. 38 | config.active_record.migration_error = :page_load 39 | 40 | # Debug mode disables concatenation and preprocessing of assets. 41 | # This option may cause significant delays in view rendering with a large 42 | # number of complex assets. 43 | config.assets.debug = true 44 | 45 | # Suppress logger output for asset requests. 46 | config.assets.quiet = true 47 | 48 | # Raises error for missing translations 49 | # config.action_view.raise_on_missing_translations = true 50 | 51 | # Use an evented file watcher to asynchronously detect changes in source code, 52 | # routes, locales, etc. This feature depends on the listen gem. 53 | # config.file_watcher = ActiveSupport::EventedFileUpdateChecker 54 | end 55 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Disable serving static files from the `/public` folder by default since 18 | # Apache or NGINX already handles this. 19 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 20 | 21 | # Compress JavaScripts and CSS. 22 | config.assets.js_compressor = :uglifier 23 | # config.assets.css_compressor = :sass 24 | 25 | # Do not fallback to assets pipeline if a precompiled asset is missed. 26 | config.assets.compile = false 27 | 28 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 29 | 30 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 31 | # config.action_controller.asset_host = 'http://assets.example.com' 32 | 33 | # Specifies the header that your server uses for sending files. 34 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 35 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 36 | 37 | # Mount Action Cable outside main process or domain 38 | # config.action_cable.mount_path = nil 39 | # config.action_cable.url = 'wss://example.com/cable' 40 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Use the lowest log level to ensure availability of diagnostic information 46 | # when problems arise. 47 | config.log_level = :debug 48 | 49 | # Prepend all log lines with the following tags. 50 | config.log_tags = [:request_id] 51 | 52 | # Use a different cache store in production. 53 | # config.cache_store = :mem_cache_store 54 | 55 | # Use a real queuing backend for Active Job (and separate queues per environment) 56 | # config.active_job.queue_adapter = :resque 57 | # config.active_job.queue_name_prefix = "dummy_#{Rails.env}" 58 | config.action_mailer.perform_caching = false 59 | 60 | # Ignore bad email addresses and do not raise email delivery errors. 61 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 62 | # config.action_mailer.raise_delivery_errors = false 63 | 64 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 65 | # the I18n.default_locale when a translation cannot be found). 66 | config.i18n.fallbacks = true 67 | 68 | # Send deprecation notices to registered listeners. 69 | config.active_support.deprecation = :notify 70 | 71 | # Use default logging formatter so that PID and timestamp are not suppressed. 72 | config.log_formatter = ::Logger::Formatter.new 73 | 74 | # Use a different logger for distributed setups. 75 | # require 'syslog/logger' 76 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 77 | 78 | if ENV['RAILS_LOG_TO_STDOUT'].present? 79 | logger = ActiveSupport::Logger.new(STDOUT) 80 | logger.formatter = config.log_formatter 81 | config.logger = ActiveSupport::TaggedLogging.new(logger) 82 | end 83 | 84 | # Do not dump schema after migrations. 85 | config.active_record.dump_schema_after_migration = false 86 | end 87 | -------------------------------------------------------------------------------- /spec/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => 'public, max-age=3600' 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | 25 | # Raise exceptions instead of rendering exception templates. 26 | config.action_dispatch.show_exceptions = false 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | config.action_mailer.perform_caching = false 31 | 32 | # Tell Action Mailer not to deliver emails to the real world. 33 | # The :test delivery method accumulates sent emails in the 34 | # ActionMailer::Base.deliveries array. 35 | config.action_mailer.delivery_method = :test 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/new_framework_defaults.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.0 upgrade. 4 | # 5 | # Read the Rails 5.0 release notes for more info on each option. 6 | 7 | # Enable per-form CSRF tokens. Previous versions had false. 8 | Rails.application.config.action_controller.per_form_csrf_tokens = true 9 | 10 | # Enable origin-checking CSRF mitigation. Previous versions had false. 11 | Rails.application.config.action_controller.forgery_protection_origin_check = true 12 | 13 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. 14 | # Previous versions had false. 15 | ActiveSupport.to_time_preserves_timezone = true 16 | 17 | # Require `belongs_to` associations by default. Previous versions had false. 18 | Rails.application.config.active_record.belongs_to_required_by_default = true 19 | 20 | # Configure SSL options to enable HSTS with subdomains. Previous versions had false. 21 | Rails.application.config.ssl_options = { hsts: { subdomains: true } } 22 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /spec/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /spec/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /spec/dummy/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum, this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 }.to_i 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests, default is 3000. 11 | # 12 | port ENV.fetch('PORT') { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch('RAILS_ENV') { 'development' } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. If you use this option 30 | # you need to make sure to reconnect any threads in the `on_worker_boot` 31 | # block. 32 | # 33 | # preload_app! 34 | 35 | # The code in the `on_worker_boot` will be called if you are using 36 | # clustered mode by specifying a number of `workers`. After each worker 37 | # process is booted this block will be run, if you are using `preload_app!` 38 | # option you will want to use this block to reconnect to any threads 39 | # or connections that may have been created at application boot, Ruby 40 | # cannot share connections between processes. 41 | # 42 | # on_worker_boot do 43 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 44 | # end 45 | 46 | # Allow puma to be restarted by `rails restart` command. 47 | plugin :tmp_restart 48 | -------------------------------------------------------------------------------- /spec/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | mount Apidoco::Engine => '/apidoco' 3 | end 4 | -------------------------------------------------------------------------------- /spec/dummy/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: e41dd2c639bb221ad88fe7a1971275bac906ff4ec202288252650ee59d7d0e8033c3af4cc77e4436866389adcd13dab2391c15a6916b07e2fa6ae91d4717667a 15 | 16 | test: 17 | secret_key_base: 2149dda8125616807b000273fd42a7d29f8a7a4b4716ee820a49b27c57c523be19d6413a8901e2c0d638a2c15d19a94de326e1dbf5340f45c4d6e49853454840 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /spec/dummy/config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /spec/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 0) do 14 | 15 | end 16 | -------------------------------------------------------------------------------- /spec/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /spec/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/log/.keep -------------------------------------------------------------------------------- /spec/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /spec/dummy/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /spec/dummy/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/public/apple-touch-icon.png -------------------------------------------------------------------------------- /spec/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/72pulses/apidoco/d0cd74fc0a61f5dddc83c1a51dd9506c38171eb2/spec/dummy/public/favicon.ico -------------------------------------------------------------------------------- /spec/features/apidoco/documentation_attributes/end_point_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Document Attributes', type: :feature do 4 | describe 'end_point', js: true do 5 | it 'will list the documentation' do 6 | create_json = { 7 | published: true, 8 | name: 'Create Currency', 9 | end_point: '/currencies' 10 | } 11 | DocumentationBuilder.create(create_json) 12 | 13 | visit '/apidoco' 14 | expect(page).to have_css("input[value=\"#{create_json[:end_point]}\"]") 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/features/apidoco/documentation_attributes/examples_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Document Attributes', type: :feature do 4 | describe 'examples', js: true do 5 | it 'will list the documentation' do 6 | create_json = { 7 | published: true, 8 | examples: [{ 9 | request: { 10 | currency: { 11 | name: "US dollar", 12 | symbol: "$", 13 | exchange_rate: "1.3" 14 | } 15 | }, 16 | response: { 17 | currency: { 18 | id: "8", 19 | name: "us dollar", 20 | symbol: "$", 21 | exchange_rate: "1.3" 22 | } 23 | } 24 | }] 25 | } 26 | DocumentationBuilder.create(create_json) 27 | 28 | visit '/apidoco' 29 | request = create_json[:examples][0][:request][:currency] 30 | response = create_json[:examples][0][:response][:currency] 31 | 32 | request.each do |key, value| 33 | expect(page).to have_text(format('"%s": "%s"', key, value)) 34 | end 35 | 36 | page.click_on('Response') 37 | 38 | response.each do |key, value| 39 | expect(page).to have_text(format('"%s": "%s"', key, value)) 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /spec/features/apidoco/documentation_attributes/http_method_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Document Attributes', type: :feature do 4 | describe 'http_method', js: true do 5 | it 'will list the documentation' do 6 | create_json = { 7 | published: true, 8 | name: 'Create Currency', 9 | http_method: '/currencies' 10 | } 11 | DocumentationBuilder.create(create_json) 12 | 13 | visit '/apidoco' 14 | expect(page).to have_text(create_json[:http_method]) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/features/apidoco/documentation_attributes/name_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Document Attributes', type: :feature do 4 | describe 'name', js: true do 5 | it 'will list the documentation' do 6 | create_json = { 7 | published: true, 8 | name: 'Create Currency' 9 | } 10 | DocumentationBuilder.create(create_json) 11 | 12 | visit '/apidoco' 13 | expect(page).to have_text(create_json[:name]) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/features/apidoco/documentation_attributes/params_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Document Attributes', type: :feature do 4 | describe 'params', js: true do 5 | context 'when required is true' do 6 | it 'will list the documentation' do 7 | create_json = { 8 | name: 'Create Currency', 9 | end_point: '/currencies', 10 | published: true, 11 | params: [{ 12 | key: "currency['name']", 13 | required: true, 14 | type: "String" 15 | }] 16 | } 17 | DocumentationBuilder.create(create_json) 18 | 19 | visit '/apidoco' 20 | param = create_json[:params][0] 21 | expect(page).to have_text(param[:key]) 22 | expect(page).to have_text("REQUIRED") 23 | expect(page).to have_text(param[:type].downcase) 24 | end 25 | end 26 | 27 | context 'when required is false' do 28 | it 'will list the documentation' do 29 | create_json = { 30 | published: true, 31 | params: [{ 32 | key: "currency['name']", 33 | required: false, 34 | type: "String" 35 | }] 36 | } 37 | DocumentationBuilder.create(create_json) 38 | 39 | visit '/apidoco' 40 | param = create_json[:params][0] 41 | expect(page).to have_text(param[:key]) 42 | expect(page).to have_text("OPTIONAL") 43 | expect(page).to have_text(param[:type].downcase) 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /spec/features/apidoco/documentation_attributes/published_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Document Attributes', type: :feature do 4 | describe 'published', js: true do 5 | context 'when published is true' do 6 | it 'will list the documentation' do 7 | create_json = { 8 | published: true, 9 | name: 'Create Currency' 10 | } 11 | DocumentationBuilder.create(create_json) 12 | 13 | visit '/apidoco' 14 | expect(page).to have_text(create_json[:name]) 15 | end 16 | end 17 | 18 | context 'when published is false' do 19 | it 'will list the documentation' do 20 | create_json = { 21 | published: false, 22 | name: 'Create Currency' 23 | } 24 | DocumentationBuilder.create(create_json) 25 | 26 | visit '/apidoco' 27 | expect(page).to have_no_text(create_json[:name]) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/features/apidoco/documentation_attributes/response_properties_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Document Attributes', type: :feature do 4 | describe 'respose_properties', js: true do 5 | it 'will list the documentation' do 6 | properties = [ 7 | { 8 | key: 'success', 9 | type: 'Boolean' 10 | }, 11 | { 12 | key: 'message', 13 | type: 'String', 14 | description: 'It can be any generic message.' 15 | } 16 | ] 17 | create_json = { 18 | name: 'Create Currency', 19 | end_point: '/currencies', 20 | published: true, 21 | response_properties: properties 22 | } 23 | DocumentationBuilder.create(create_json) 24 | 25 | visit '/apidoco' 26 | page.click_on('Response') 27 | 28 | expect(page).to have_text(properties[0][:key]) 29 | expect(page).to have_text(properties[0][:type].downcase) 30 | 31 | expect(page).to have_text(properties[0][:key]) 32 | expect(page).to have_text(properties[0][:type].downcase) 33 | expect(page).to have_text(properties[0][:description]) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/features/apidoco/show_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.feature 'Show Page', type: :feature do 4 | describe 'title', js: true do 5 | it 'shows the app name as its title' do 6 | Apidoco.app_name = 'MyApp API Documentation' 7 | DocumentationBuilder.create({}) # setting the minimum to load the page 8 | visit '/apidoco' 9 | expect(page).to have_title(Apidoco.app_name) 10 | expect(page).to have_text(Apidoco.app_name) # shows the title in the sidebar 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/generators/apidoco/apidoco_generator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | require 'generators/apidoco_generator' 3 | require 'generator_spec' 4 | 5 | describe ApidocoGenerator, type: :generator do 6 | def remove_docs_directory 7 | FileUtils.rm_rf("#{Rails.root}/docs") 8 | end 9 | 10 | after(:all) do 11 | remove_docs_directory 12 | end 13 | 14 | context 'default actions' do 15 | it 'creates a crud documentation files' do 16 | run_generator %w[v1/posts] 17 | assert_file "#{Rails.root}/docs/api/v1/posts/create.json", %r{v1/posts.json} 18 | assert_file "#{Rails.root}/docs/api/v1/posts/destroy.json", %r{v1/posts/:id.json} 19 | assert_file "#{Rails.root}/docs/api/v1/posts/index.json", %r{v1/posts.json} 20 | assert_file "#{Rails.root}/docs/api/v1/posts/show.json", %r{v1/posts/:id.json} 21 | assert_file "#{Rails.root}/docs/api/v1/posts/update.json", %r{v1/posts/:id.json} 22 | end 23 | end 24 | 25 | context 'custom actions' do 26 | let(:upload_acton) { 'upload' } 27 | 28 | it 'creates the documentation files for the actions supplied in arguments' do 29 | run_generator ['v1/posts', upload_acton] 30 | 31 | assert_file "#{Rails.root}/docs/api/v1/posts/#{upload_acton}.json" 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV['RAILS_ENV'] ||= 'test' 3 | require File.expand_path('../dummy/config/environment', __FILE__) 4 | # Prevent database truncation if the environment is production 5 | abort('The Rails environment is running in production mode!') if Rails.env.production? 6 | require 'spec_helper' 7 | require 'rspec/rails' 8 | require 'pry-byebug' 9 | # Add additional requires below this line. Rails is not loaded until this point! 10 | 11 | # Requires supporting ruby files with custom matchers and macros, etc, in 12 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 13 | # run as spec files by default. This means that files in spec/support that end 14 | # in _spec.rb will both be required and run as specs, causing the specs to be 15 | # run twice. It is recommended that you do not name files matching this glob to 16 | # end with _spec.rb. You can configure this pattern with the --pattern 17 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 18 | # 19 | # The following line is provided for convenience purposes. It has the downside 20 | # of increasing the boot-up time by auto-requiring all files in the support 21 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 22 | # require only the support files necessary. 23 | # 24 | # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 25 | 26 | # Checks for pending migration and applies them before tests are run. 27 | # If you are not using ActiveRecord, you can remove this line. 28 | ActiveRecord::Migration.maintain_test_schema! 29 | 30 | RSpec.configure do |config| 31 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 32 | # config.fixture_path = "#{::Rails.root}/spec/fixtures" 33 | 34 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 35 | # examples within a transaction, remove the following line or assign false 36 | # instead of true. 37 | # config.use_transactional_fixtures = true 38 | 39 | # RSpec Rails can automatically mix in different behaviours to your tests 40 | # based on their file location, for example enabling you to call `get` and 41 | # `post` in specs under `spec/controllers`. 42 | # 43 | # You can disable this behaviour by removing the line below, and instead 44 | # explicitly tag your specs with their type, e.g.: 45 | # 46 | # RSpec.describe UsersController, :type => :controller do 47 | # # ... 48 | # end 49 | # 50 | # The different available types are documented in the features, such as in 51 | # https://relishapp.com/rspec/rspec-rails/docs 52 | config.infer_spec_type_from_file_location! 53 | 54 | # Filter lines from Rails gems in backtraces. 55 | config.filter_rails_from_backtrace! 56 | # arbitrary gems may also be filtered via: 57 | # config.filter_gems_from_backtrace("gem name") 58 | end 59 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | 3 | require File.expand_path('../dummy/config/environment.rb', __FILE__) 4 | require 'rspec/rails' 5 | 6 | Rails.backtrace_cleaner.remove_silencers! 7 | 8 | # Load support files 9 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } 10 | 11 | RSpec.configure do |config| 12 | config.mock_with :rspec 13 | config.use_transactional_fixtures = true 14 | config.infer_base_class_for_anonymous_controllers = false 15 | config.order = "random" 16 | end 17 | -------------------------------------------------------------------------------- /spec/support/capybara.rb: -------------------------------------------------------------------------------- 1 | require 'capybara/rspec' 2 | require 'capybara/apparition' 3 | 4 | Capybara.register_driver :apparition_debug do |app| 5 | Capybara::Apparition::Driver.new( 6 | app, 7 | headless: true, # Set this to false if you want to launch in a browser 8 | window_size: [2000, 1500] 9 | ) 10 | end 11 | 12 | Capybara.javascript_driver = :apparition_debug 13 | -------------------------------------------------------------------------------- /spec/support/documentation_builder.rb: -------------------------------------------------------------------------------- 1 | class DocumentationBuilder 2 | def self.create(doc_hash) 3 | FileUtils.rm_rf("#{Rails.root}/docs") 4 | FileUtils.mkdir_p(Rails.root.join('docs', 'api', 'v1', 'currencies')) 5 | File.open(Rails.root.join('docs', 'api', 'v1', 'currencies', '1.json'), 'w') do |line| 6 | line.puts(doc_hash.to_json) 7 | end 8 | end 9 | end 10 | --------------------------------------------------------------------------------