├── spec
├── dummy
│ ├── log
│ │ └── .gitkeep
│ ├── spec
│ ├── app
│ │ ├── mailers
│ │ │ └── .gitkeep
│ │ ├── models
│ │ │ ├── .gitkeep
│ │ │ └── recipe.rb
│ │ ├── helpers
│ │ │ └── application_helper.rb
│ │ ├── controllers
│ │ │ ├── application_controller.rb
│ │ │ └── recipes_controller.rb
│ │ ├── views
│ │ │ └── layouts
│ │ │ │ └── application.html.erb
│ │ └── assets
│ │ │ ├── stylesheets
│ │ │ └── application.css
│ │ │ └── javascripts
│ │ │ └── application.js
│ ├── lib
│ │ └── assets
│ │ │ └── .gitkeep
│ ├── public
│ │ ├── favicon.ico
│ │ ├── 500.html
│ │ ├── 422.html
│ │ └── 404.html
│ ├── config
│ │ ├── routes.rb
│ │ ├── environment.rb
│ │ ├── locales
│ │ │ └── en.yml
│ │ ├── initializers
│ │ │ ├── mime_types.rb
│ │ │ ├── backtrace_silencers.rb
│ │ │ ├── session_store.rb
│ │ │ ├── wrap_parameters.rb
│ │ │ ├── inflections.rb
│ │ │ └── secret_token.rb
│ │ ├── boot.rb
│ │ ├── database.yml
│ │ ├── environments
│ │ │ ├── development.rb
│ │ │ ├── test.rb
│ │ │ └── production.rb
│ │ └── application.rb
│ ├── doc
│ │ ├── toc.md
│ │ └── recipes.md
│ ├── config.ru
│ ├── db
│ │ ├── migrate
│ │ │ └── 20130607075126_create_recipes.rb
│ │ └── schema.rb
│ ├── Rakefile
│ └── script
│ │ └── rails
├── spec_helper.rb
└── requests
│ └── recipes_spec.rb
├── Rakefile
├── lib
├── autodoc
│ ├── version.rb
│ ├── rspec.rb
│ ├── templates
│ │ ├── document.md.erb
│ │ └── toc.md.erb
│ ├── configuration.rb
│ ├── documents.rb
│ └── document.rb
└── autodoc.rb
├── Gemfile
├── .gitignore
├── CHANGELOG.md
├── autodoc.gemspec
├── LICENSE.txt
└── README.md
/spec/dummy/log/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/spec:
--------------------------------------------------------------------------------
1 | ../../spec
--------------------------------------------------------------------------------
/spec/dummy/app/mailers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/lib/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/spec/dummy/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 |
--------------------------------------------------------------------------------
/lib/autodoc/version.rb:
--------------------------------------------------------------------------------
1 | module Autodoc
2 | VERSION = "0.2.6"
3 | end
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/spec/dummy/config/routes.rb:
--------------------------------------------------------------------------------
1 | Dummy::Application.routes.draw do
2 | resources :recipes, only: [:show, :create]
3 | end
4 |
--------------------------------------------------------------------------------
/spec/dummy/app/models/recipe.rb:
--------------------------------------------------------------------------------
1 | class Recipe < ActiveRecord::Base
2 | attr_accessible :name, :type
3 | self.inheritance_column = :_type
4 | end
5 |
--------------------------------------------------------------------------------
/spec/dummy/doc/toc.md:
--------------------------------------------------------------------------------
1 | ## Table of Contents
2 | * [recipes.md](recipes.md)
3 | * [GET /recipes/:id](recipes.md#get-recipesid)
4 | * [POST /recipes](recipes.md#post-recipes)
5 |
--------------------------------------------------------------------------------
/spec/dummy/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Dummy::Application
5 |
--------------------------------------------------------------------------------
/spec/dummy/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the rails application
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the rails application
5 | Dummy::Application.initialize!
6 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gemspec
4 |
5 | group :test do
6 | gem "pry-rails"
7 | gem "rspec-rails"
8 | gem "weak_parameters"
9 | gem "protected_attributes"
10 | gem "rack-test"
11 | end
12 |
--------------------------------------------------------------------------------
/lib/autodoc/rspec.rb:
--------------------------------------------------------------------------------
1 | require "rspec"
2 |
3 | RSpec.configuration.after(:each, autodoc: true) do
4 | Autodoc.documents.append(self)
5 | end
6 |
7 | RSpec.configuration.after(:suite) do
8 | Autodoc.documents.write
9 | end
10 |
--------------------------------------------------------------------------------
/spec/dummy/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery
3 |
4 | respond_to :json
5 |
6 | rescue_from WeakParameters::ValidationError do
7 | head 400
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/dummy/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Sample localization file for English. Add more files in this directory for other locales.
2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 |
4 | en:
5 | hello: "Hello world"
6 |
--------------------------------------------------------------------------------
/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 | # Mime::Type.register_alias "text/html", :iphone
6 |
--------------------------------------------------------------------------------
/spec/dummy/db/migrate/20130607075126_create_recipes.rb:
--------------------------------------------------------------------------------
1 | class CreateRecipes < ActiveRecord::Migration
2 | def change
3 | create_table :recipes do |t|
4 | t.string :name
5 | t.integer :type
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/spec/dummy/config/boot.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | gemfile = File.expand_path('../../../../Gemfile', __FILE__)
3 |
4 | if File.exist?(gemfile)
5 | ENV['BUNDLE_GEMFILE'] = gemfile
6 | require 'bundler'
7 | Bundler.setup
8 | end
9 |
10 | $:.unshift File.expand_path('../../../../lib', __FILE__)
--------------------------------------------------------------------------------
/spec/dummy/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 | # Add your own tasks in files placed in lib/tasks ending in .rake,
3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4 |
5 | require File.expand_path('../config/application', __FILE__)
6 |
7 | Dummy::Application.load_tasks
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle/
4 | .config
5 | .yardoc
6 | Gemfile.lock
7 | InstalledFiles
8 | _yardoc
9 | coverage
10 | lib/bundler/man
11 | log/*.log
12 | pkg
13 | pkg/
14 | rdoc
15 | spec/dummy/.sass-cache
16 | spec/dummy/db/*.sqlite3
17 | spec/dummy/log/*.log
18 | spec/dummy/tmp/
19 | spec/reports
20 | tmp
21 |
--------------------------------------------------------------------------------
/spec/dummy/script/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3 |
4 | APP_PATH = File.expand_path('../../config/application', __FILE__)
5 | require File.expand_path('../../config/boot', __FILE__)
6 | require 'rails/commands'
7 |
--------------------------------------------------------------------------------
/spec/dummy/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dummy
5 | <%= stylesheet_link_tag "application", :media => "all" %>
6 | <%= javascript_include_tag "application" %>
7 | <%= csrf_meta_tags %>
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/lib/autodoc/templates/document.md.erb:
--------------------------------------------------------------------------------
1 | <%# coding: UTF-8 -%>
2 | ## <%= title %>
3 | <%= description %>
4 | <%= parameters_section %>
5 | ### request
6 | ```
7 | <%= method %> <%= path %>
8 | ```
9 | <%= request_body_section %>
10 | ### response
11 | ```ruby
12 | Status: <%= response_status %><%= response_headers %>
13 | response: <%= response_body %>
14 | ```
15 |
--------------------------------------------------------------------------------
/spec/dummy/app/controllers/recipes_controller.rb:
--------------------------------------------------------------------------------
1 | class RecipesController < ApplicationController
2 | validates :create do
3 | string :name, required: true, except: %w[alice bob]
4 | integer :type, only: 1..3
5 | end
6 |
7 | def show
8 | respond_with Recipe.find(params[:id])
9 | end
10 |
11 | def create
12 | respond_with Recipe.create(params.slice(:name, :type))
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/autodoc.rb:
--------------------------------------------------------------------------------
1 | require "autodoc/configuration"
2 | require "autodoc/document"
3 | require "autodoc/documents"
4 | require "autodoc/version"
5 | require "autodoc/rspec" if ENV["AUTODOC"]
6 |
7 | module Autodoc
8 | class << self
9 | def documents
10 | @documents ||= Documents.new
11 | end
12 |
13 | def configuration
14 | @configuration ||= Configuration.new
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/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/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
4 |
5 | # Use the database for sessions instead of the cookie-based default,
6 | # which shouldn't be used to store highly confidential information
7 | # (create the session table with "rails generate session_migration")
8 | # Dummy::Application.config.session_store :active_record_store
9 |
--------------------------------------------------------------------------------
/lib/autodoc/templates/toc.md.erb:
--------------------------------------------------------------------------------
1 | <%# coding: UTF-8 -%>
2 | ## Table of Contents
3 | <% @table.sort.each do |pathname, documents| -%>
4 | * [<%= pathname.basename %>](<%= pathname.basename %>)
5 | <% documents.group_by(&:title).each do |title, documents| -%>
6 | <% documents.each_with_index do |document, index| -%>
7 | <% suffix = index == 0 ? "" : "-#{index}" -%>
8 | * [<%= title %>](<%= "#{pathname.basename}##{document.identifier}#{suffix}" %>)
9 | <% end -%>
10 | <% end -%>
11 | <% end -%>
12 |
--------------------------------------------------------------------------------
/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 | # Disable root element in JSON by default.
12 | ActiveSupport.on_load(:active_record) do
13 | self.include_root_in_json = false
14 | end
15 |
--------------------------------------------------------------------------------
/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
4 | # (all these examples are active by default):
5 | # ActiveSupport::Inflector.inflections do |inflect|
6 | # inflect.plural /^(ox)$/i, '\1en'
7 | # inflect.singular /^(ox)en/i, '\1'
8 | # inflect.irregular 'person', 'people'
9 | # inflect.uncountable %w( fish sheep )
10 | # end
11 | #
12 | # These inflection rules are supported but not enabled by default:
13 | # ActiveSupport::Inflector.inflections do |inflect|
14 | # inflect.acronym 'RESTful'
15 | # end
16 |
--------------------------------------------------------------------------------
/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 vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the top of the
9 | * compiled file, but it's generally better to create a new file per style scope.
10 | *
11 | *= require_self
12 | *= require_tree .
13 | */
14 |
--------------------------------------------------------------------------------
/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 | development:
7 | adapter: sqlite3
8 | database: db/development.sqlite3
9 | pool: 5
10 | timeout: 5000
11 |
12 | # Warning: The database defined as "test" will be erased and
13 | # re-generated from your development database when you run "rake".
14 | # Do not set this db to the same as development or production.
15 | test:
16 | adapter: sqlite3
17 | database: db/test.sqlite3
18 | pool: 5
19 | timeout: 5000
20 |
21 | production:
22 | adapter: sqlite3
23 | database: db/production.sqlite3
24 | pool: 5
25 | timeout: 5000
26 |
--------------------------------------------------------------------------------
/spec/dummy/config/initializers/secret_token.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 | # Make sure the secret is at least 30 characters and all random,
6 | # no regular words or you'll be exposed to dictionary attacks.
7 | Dummy::Application.config.secret_token = '2da8e59639e7c92b0da46798ed97a45be5834c72cdd9a4ad141dadc5b1175f991b05ef02dde00f9c27cadb3790311e642010b89ed1dad598539980a1ae88be61'
8 | Dummy::Application.config.secret_key_base = '7bea42a7812ad8da2fa753be701ed39a8b35f014c0cfcc876ad08180f2b25504e67ed24fc4470c51b229bbbc4731454c912e4609902e1c0bba65fb86037f7f1a'
9 |
--------------------------------------------------------------------------------
/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 vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // the compiled file.
9 | //
10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11 | // GO AFTER THE REQUIRES BELOW.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require_tree .
16 |
--------------------------------------------------------------------------------
/spec/dummy/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
We're sorry, but something went wrong.
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spec/dummy/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The change you wanted was rejected.
23 |
Maybe you tried to change something you didn't have access to.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/spec/dummy/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The page you were looking for doesn't exist.
23 |
You may have mistyped the address or the page may have moved.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] ||= "test"
2 | require File.expand_path("../../spec/dummy/config/environment", __FILE__)
3 | require "rspec/rails"
4 | require "rspec/autorun"
5 |
6 | Autodoc.configuration.toc = true
7 | Autodoc.configuration.path = "spec/dummy/doc"
8 |
9 | RSpec.configure do |config|
10 | # If you"re not using ActiveRecord, or you"d prefer not to run each of your
11 | # examples within a transaction, remove the following line or assign false
12 | # instead of true.
13 | config.use_transactional_fixtures = true
14 |
15 | # If true, the base class of anonymous controllers will be inferred
16 | # automatically. This will be the default behavior in future versions of
17 | # rspec-rails.
18 | config.infer_base_class_for_anonymous_controllers = false
19 |
20 | config.treat_symbols_as_metadata_keys_with_true_values = true
21 | end
22 |
--------------------------------------------------------------------------------
/spec/dummy/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Dummy::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 | # Show full error reports and disable caching
10 | config.consider_all_requests_local = true
11 | config.action_controller.perform_caching = false
12 |
13 | # Don't care if the mailer can't send
14 | config.action_mailer.raise_delivery_errors = false
15 |
16 | # Print deprecation notices to the Rails logger
17 | config.active_support.deprecation = :log
18 |
19 | # Expands the lines which load the assets
20 | config.assets.debug = true
21 | end
22 |
--------------------------------------------------------------------------------
/lib/autodoc/configuration.rb:
--------------------------------------------------------------------------------
1 | module Autodoc
2 | class Configuration
3 | class << self
4 | def property(name, &default)
5 | define_method(name) do
6 | if instance_variable_defined?("@#{name}")
7 | instance_variable_get("@#{name}")
8 | else
9 | instance_variable_set("@#{name}", instance_exec(&default))
10 | end
11 | end
12 |
13 | attr_writer name
14 | end
15 | end
16 |
17 | property :path do
18 | "doc"
19 | end
20 |
21 | property :headers do
22 | %w[Location]
23 | end
24 |
25 | property :template do
26 | File.read(File.expand_path("../templates/document.md.erb", __FILE__))
27 | end
28 |
29 | property :toc_template do
30 | File.read(File.expand_path("../templates/toc.md.erb", __FILE__))
31 | end
32 |
33 | property :toc do
34 | false
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/spec/dummy/doc/recipes.md:
--------------------------------------------------------------------------------
1 | ## GET /recipes/:id
2 | Returns the recipe.
3 |
4 | ### request
5 | ```
6 | GET /recipes/:id
7 | ```
8 |
9 | ### response
10 | ```ruby
11 | Status: 200
12 | response:
13 | {
14 | "id": 1,
15 | "name": "test",
16 | "type": 2,
17 | "created_at": "2013-11-30T19:04:12.608Z",
18 | "updated_at": "2013-11-30T19:04:12.608Z"
19 | }
20 | ```
21 |
22 | ## POST /recipes
23 | Creates a new recipe.
24 |
25 | ### parameters
26 | * `name` string (required, except: `["alice", "bob"]`)
27 | * `type` integer (only: `1..3`)
28 |
29 | ### request
30 | ```
31 | POST /recipes
32 | ```
33 |
34 | ```
35 | name=name&type=1
36 | ```
37 |
38 | ### response
39 | ```ruby
40 | Status: 201
41 | Location: http://www.example.com/recipes/1
42 | response:
43 | {
44 | "id": 1,
45 | "name": "name",
46 | "type": 1,
47 | "created_at": "2013-11-30T19:04:12.684Z",
48 | "updated_at": "2013-11-30T19:04:12.684Z"
49 | }
50 | ```
51 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.2.6
2 | * fix ToC generator
3 |
4 | ## 0.2.5
5 | * add ToC generator
6 | * use Autodoc.configuration.path to change documents path
7 |
8 | ## 0.2.4
9 | * add Documents class
10 |
11 | ## 0.2.3
12 | * clean up dependencies & implementation
13 |
14 | ## 0.2.2
15 | * fix default documented headers
16 |
17 | ## 0.2.1
18 | * fix load dependency on rspec
19 |
20 | ## 0.2.0
21 | * remove dependency on awesome_print
22 |
23 | ## 0.1.9
24 | * fix encoding error at ruby 1.9 or earlier versions
25 |
26 | ## 0.1.8
27 | * support rack-test
28 |
29 | ## 0.1.7
30 | * change response format from Ruby hash table to JSON object
31 |
32 | ## 0.1.6
33 | * support WeakParameter's :description option
34 |
35 | ## 0.1.1
36 | * custom template
37 |
38 | ## 0.1.0
39 | * AUTODOC environment variable
40 |
41 | ## 0.0.8
42 | * show request body
43 |
44 | ## 0.0.3
45 | * configurable response header
46 |
47 | ## 0.0.1
48 | * 1st release on 2013-06-07
49 |
--------------------------------------------------------------------------------
/lib/autodoc/documents.rb:
--------------------------------------------------------------------------------
1 | require "pathname"
2 |
3 | module Autodoc
4 | class Documents
5 | def initialize
6 | @table = Hash.new {|table, key| table[key] = [] }
7 | end
8 |
9 | def append(context)
10 | document = Autodoc::Document.new(context.clone)
11 | @table[document.pathname] << document
12 | end
13 |
14 | def write
15 | write_toc if Autodoc.configuration.toc
16 | write_documents
17 | end
18 |
19 | private
20 |
21 | def write_documents
22 | @table.each do |pathname, documents|
23 | pathname.parent.mkpath
24 | pathname.open("w") {|file| file << documents.map(&:render).join("\n").rstrip + "\n" }
25 | end
26 | end
27 |
28 | def write_toc
29 | toc_path.parent.mkpath
30 | toc_path.open("w") {|file| file << render_toc }
31 | end
32 |
33 | def render_toc
34 | ERB.new(Autodoc.configuration.toc_template, nil, "-").result(binding)
35 | end
36 |
37 | def toc_path
38 | Pathname.new(Autodoc.configuration.path) + "toc.md"
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/spec/dummy/db/schema.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended to check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(:version => 20130607075126) do
15 |
16 | create_table "recipes", :force => true do |t|
17 | t.string "name"
18 | t.integer "type"
19 | t.datetime "created_at", :null => false
20 | t.datetime "updated_at", :null => false
21 | end
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/autodoc.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path("../lib", __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require "autodoc/version"
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = "autodoc"
8 | spec.version = Autodoc::VERSION
9 | spec.authors = ["Ryo Nakamura"]
10 | spec.email = ["r7kamura@gmail.com"]
11 | spec.summary = "Auto-generate JSON API documents from your request-specs."
12 | spec.homepage = "https://github.com/r7kamura/autodoc"
13 | spec.license = "MIT"
14 |
15 | spec.files = `git ls-files`.split($/)
16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18 | spec.require_paths = ["lib"]
19 |
20 | spec.add_dependency "actionpack"
21 | spec.add_dependency "rspec"
22 | spec.add_development_dependency "bundler", "~> 1.3"
23 | spec.add_development_dependency "rails", ">= 3.2.11"
24 | spec.add_development_dependency "rake"
25 | spec.add_development_dependency "sqlite3"
26 | end
27 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Ryo Nakamura
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/spec/dummy/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Dummy::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 | # Configure static asset server for tests with Cache-Control for performance
11 | config.serve_static_assets = true
12 | config.static_cache_control = "public, max-age=3600"
13 |
14 | # Show full error reports and disable caching
15 | config.consider_all_requests_local = true
16 | config.action_controller.perform_caching = false
17 |
18 | # Raise exceptions instead of rendering exception templates
19 | config.action_dispatch.show_exceptions = false
20 |
21 | # Disable request forgery protection in test environment
22 | config.action_controller.allow_forgery_protection = false
23 |
24 | # Print deprecation notices to the stderr
25 | config.active_support.deprecation = :stderr
26 |
27 | config.eager_load = false
28 | end
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Autodoc
2 | Auto-generate JSON API documents from your request-specs.
3 |
4 | ## Installation
5 | ```ruby
6 | gem "autodoc", group: :test
7 | ```
8 |
9 | ## Usage
10 | Run rspec with AUTODOC=1 to generate documents for the specs tagged with `:autodoc`.
11 | example: [doc/recipes.md](https://github.com/r7kamura/autodoc/blob/master/spec/dummy/doc/recipes.md), [doc/toc.md](https://github.com/r7kamura/autodoc/blob/master/spec/dummy/doc/toc.md)
12 |
13 | ```sh
14 | # shell-command
15 | AUTODOC=1 rspec
16 | ```
17 |
18 | ```ruby
19 | # spec/requests/recipes_spec.rb
20 | describe "Recipes" do
21 | describe "POST /recipes", autodoc: true do
22 | it "creates a new recipe" do
23 | post "/recipes.json", name: "alice", type: 1
24 | response.status.should == 201
25 | end
26 | end
27 | end
28 | ```
29 |
30 | ### Configuration
31 | You can configure `Autodoc.configuration` to change its behavior:
32 |
33 | * path - [String] location to put files (default: ./doc)
34 | * headers - [Array] keys of documented response header (default: ["Location"])
35 | * template - [String] ERB template for each document (default: [document.md.erb](https://github.com/r7kamura/autodoc/blob/master/lib/autodoc/templates/document.md.erb))
36 | * toc_template - [String] ERB template for ToC (default: [toc.md.erb](https://github.com/r7kamura/autodoc/blob/master/lib/autodoc/templates/toc.md.erb))
37 | * toc - [Boolean] whether to generate toc.md (default: false)
38 |
39 | ```ruby
40 | # example
41 | Autodoc.configuration.path = "doc/api"
42 | Autodoc.configuration.toc = true
43 | ```
44 |
--------------------------------------------------------------------------------
/spec/requests/recipes_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 |
3 | describe "Recipes" do
4 | let(:env) do
5 | { "HTTP_ACCEPT" => "application/json" }
6 | end
7 |
8 | let(:params) do
9 | {}
10 | end
11 |
12 | describe "GET /recipes/:id" do
13 | let(:recipe) do
14 | Recipe.create(name: "test", type: 2)
15 | end
16 |
17 | context "with valid condition (using Rack::Test)", :autodoc do
18 | include Rack::Test::Methods
19 |
20 | it "returns the recipe" do
21 | get "/recipes/#{recipe.id}", params, env
22 | last_response.status.should == 200
23 | end
24 | end
25 | end
26 |
27 | describe "POST /recipes" do
28 | before do
29 | params[:name] = "name"
30 | params[:type] = 1
31 | end
32 |
33 | context "without required param" do
34 | before do
35 | params.delete(:name)
36 | end
37 |
38 | it "returns 400" do
39 | post "/recipes", params, env
40 | response.status.should == 400
41 | end
42 | end
43 |
44 | context "with other typed param" do
45 | before do
46 | params[:type] = "x"
47 | end
48 |
49 | it "returns 400" do
50 | post "/recipes", params, env
51 | response.status.should == 400
52 | end
53 | end
54 |
55 | context "without non-required param" do
56 | before do
57 | params.delete(:type)
58 | end
59 |
60 | it "creates a new recipe" do
61 | post "/recipes", params, env
62 | response.status.should == 201
63 | end
64 | end
65 |
66 | context "with valid condition", :autodoc do
67 | it "creates a new recipe" do
68 | post "/recipes", params, env
69 | response.status.should == 201
70 | end
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/spec/dummy/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require "active_record/railtie"
4 | require "action_controller/railtie"
5 |
6 | Bundler.require(*Rails.groups)
7 | require "autodoc"
8 |
9 | module Dummy
10 | class Application < Rails::Application
11 | # Settings in config/environments/* take precedence over those specified here.
12 | # Application configuration should go into files in config/initializers
13 | # -- all .rb files in that directory are automatically loaded.
14 |
15 | # Custom directories with classes and modules you want to be autoloadable.
16 | # config.autoload_paths += %W(#{config.root}/extras)
17 |
18 | # Only load the plugins named here, in the order given (default is alphabetical).
19 | # :all can be used as a placeholder for all plugins not explicitly named.
20 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
21 |
22 | # Activate observers that should always be running.
23 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
24 |
25 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
26 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
27 | # config.time_zone = 'Central Time (US & Canada)'
28 |
29 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
30 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
31 | # config.i18n.default_locale = :de
32 |
33 | # Configure the default encoding used in templates for Ruby 1.9.
34 | config.encoding = "utf-8"
35 |
36 | # Configure sensitive parameters which will be filtered from the log file.
37 | config.filter_parameters += [:password]
38 |
39 | # Enable escaping HTML in JSON.
40 | config.active_support.escape_html_entities_in_json = true
41 |
42 | # Use SQL instead of Active Record's schema dumper when creating the database.
43 | # This is necessary if your schema can't be completely dumped by the schema dumper,
44 | # like if you have constraints or database-specific column types
45 | # config.active_record.schema_format = :sql
46 |
47 | # Enforce whitelist mode for mass assignment.
48 | # This will create an empty whitelist of attributes available for mass-assignment for all models
49 | # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
50 | # parameters by using an attr_accessible or attr_protected declaration.
51 | config.active_record.whitelist_attributes = true
52 |
53 | # Version of your assets, change this if you want to expire all your assets
54 | config.assets.version = '1.0'
55 | end
56 | end
57 |
58 |
--------------------------------------------------------------------------------
/spec/dummy/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Dummy::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 | # Full error reports are disabled and caching is turned on
8 | config.consider_all_requests_local = false
9 | config.action_controller.perform_caching = true
10 |
11 | # Disable Rails's static asset server (Apache or nginx will already do this)
12 | config.serve_static_assets = false
13 |
14 | # Compress JavaScripts and CSS
15 | config.assets.compress = true
16 |
17 | # Don't fallback to assets pipeline if a precompiled asset is missed
18 | config.assets.compile = false
19 |
20 | # Generate digests for assets URLs
21 | config.assets.digest = true
22 |
23 | # Defaults to nil and saved in location specified by config.assets.prefix
24 | # config.assets.manifest = YOUR_PATH
25 |
26 | # Specifies the header that your server uses for sending files
27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
29 |
30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
31 | # config.force_ssl = true
32 |
33 | # See everything in the log (default is :info)
34 | # config.log_level = :debug
35 |
36 | # Prepend all log lines with the following tags
37 | # config.log_tags = [ :subdomain, :uuid ]
38 |
39 | # Use a different logger for distributed setups
40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
41 |
42 | # Use a different cache store in production
43 | # config.cache_store = :mem_cache_store
44 |
45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server
46 | # config.action_controller.asset_host = "http://assets.example.com"
47 |
48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
49 | # config.assets.precompile += %w( search.js )
50 |
51 | # Disable delivery errors, bad email addresses will be ignored
52 | # config.action_mailer.raise_delivery_errors = false
53 |
54 | # Enable threaded mode
55 | # config.threadsafe!
56 |
57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
58 | # the I18n.default_locale when a translation can not be found)
59 | config.i18n.fallbacks = true
60 |
61 | # Send deprecation notices to registered listeners
62 | config.active_support.deprecation = :notify
63 |
64 | # Log the query plan for queries taking more than this (works
65 | # with SQLite, MySQL, and PostgreSQL)
66 | # config.active_record.auto_explain_threshold_in_seconds = 0.5
67 |
68 | config.eager_load = true
69 |
70 | config.assets.js_compressor = :uglifier
71 | end
72 |
--------------------------------------------------------------------------------
/lib/autodoc/document.rb:
--------------------------------------------------------------------------------
1 | require "action_dispatch/http/request"
2 | require "erb"
3 | require "pathname"
4 |
5 | module Autodoc
6 | class Document
7 | def self.render(*args)
8 | new(*args).render
9 | end
10 |
11 | def initialize(context)
12 | @context = context
13 | end
14 |
15 | def pathname
16 | @path ||= begin
17 | payload = @context.example.file_path.gsub(%r<\./spec/requests/(.+)_spec\.rb>, '\1.md')
18 | Pathname.new(Autodoc.configuration.path) + payload
19 | end
20 | end
21 |
22 | def render
23 | ERB.new(Autodoc.configuration.template, nil, "-").result(binding)
24 | end
25 |
26 | def title
27 | "#{method} #{path}"
28 | end
29 |
30 | def identifier
31 | title.gsub(" ", "-").gsub(/[:\/]/, "").downcase
32 | end
33 |
34 | private
35 |
36 | def request
37 | @request ||= begin
38 | if using_rack_test?
39 | ActionDispatch::Request.new(@context.last_request.env)
40 | else
41 | @context.request
42 | end
43 | end
44 | end
45 |
46 | def response
47 | @response ||= begin
48 | if using_rack_test?
49 | @context.last_response
50 | else
51 | @context.response
52 | end
53 | end
54 | end
55 |
56 | def method
57 | request.method
58 | end
59 |
60 | def request_body
61 | request.body.string
62 | end
63 |
64 | def response_status
65 | response.status
66 | end
67 |
68 | def response_header(header)
69 | response.headers[header]
70 | end
71 |
72 | def response_body_raw
73 | response.body
74 | end
75 |
76 | def controller
77 | request.params[:controller]
78 | end
79 |
80 | def action
81 | request.params[:action]
82 | end
83 |
84 | def using_rack_test?
85 | !!defined?(Rack::Test::Methods) && @context.class.ancestors.include?(Rack::Test::Methods)
86 | end
87 |
88 | def transaction
89 | @transaction ||= Autodoc::Transaction.build(@context)
90 | end
91 |
92 | def description
93 | "#{@context.example.description.capitalize}."
94 | end
95 |
96 | def path
97 | @context.example.full_description[%r<(GET|POST|PUT|DELETE) ([^ ]+)>, 2]
98 | end
99 |
100 | def response_body
101 | "\n" + JSON.pretty_generate(JSON.parse(response_body_raw))
102 | rescue JSON::ParserError
103 | end
104 |
105 | def request_body_section
106 | if has_request_body?
107 | "\n```\n#{request_body}\n```\n"
108 | end
109 | end
110 |
111 | def parameters_section
112 | if has_validators? && parameters.present?
113 | "\n### parameters\n#{parameters}\n"
114 | end
115 | end
116 |
117 | def parameters
118 | validators.map {|validator| Parameter.new(validator) }.join("\n")
119 | end
120 |
121 | def has_request_body?
122 | request_body.present?
123 | end
124 |
125 | def has_validators?
126 | !!(defined?(WeakParameters) && validators)
127 | end
128 |
129 | def validators
130 | WeakParameters.stats[controller][action].try(:validators)
131 | end
132 |
133 | def response_headers
134 | Autodoc.configuration.headers.map do |header|
135 | "\n#{header}: #{response_header(header)}" if response_header(header)
136 | end.compact.join
137 | end
138 |
139 | class Parameter
140 | attr_reader :validator
141 |
142 | def initialize(validator)
143 | @validator = validator
144 | end
145 |
146 | def to_s
147 | "#{body}#{payload}"
148 | end
149 |
150 | private
151 |
152 | def body
153 | "* `#{validator.key}` #{validator.type}"
154 | end
155 |
156 | def payload
157 | string = ""
158 | string << " (#{assets.join(', ')})" if assets.any?
159 | string << " - #{validator.options[:description]}" if validator.options[:description]
160 | string
161 | end
162 |
163 | def assets
164 | @assets ||= [required, only, except].compact
165 | end
166 |
167 | def required
168 | "required" if validator.required?
169 | end
170 |
171 | def only
172 | "only: `#{validator.options[:only].inspect}`" if validator.options[:only]
173 | end
174 |
175 | def except
176 | "except: `#{validator.options[:except].inspect}`" if validator.options[:except]
177 | end
178 | end
179 | end
180 | end
181 |
--------------------------------------------------------------------------------