betterdocs 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +5 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +9 -0
  6. data/COPYING +202 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE +202 -0
  9. data/README.md +124 -0
  10. data/Rakefile +25 -0
  11. data/VERSION +1 -0
  12. data/betterdocs.gemspec +48 -0
  13. data/lib/betterdocs.rb +27 -0
  14. data/lib/betterdocs/controller_collector.rb +50 -0
  15. data/lib/betterdocs/dsl.rb +9 -0
  16. data/lib/betterdocs/dsl/common.rb +26 -0
  17. data/lib/betterdocs/dsl/controller.rb +9 -0
  18. data/lib/betterdocs/dsl/controller/action.rb +126 -0
  19. data/lib/betterdocs/dsl/controller/action/param.rb +25 -0
  20. data/lib/betterdocs/dsl/controller/action/response.rb +47 -0
  21. data/lib/betterdocs/dsl/controller/controller.rb +31 -0
  22. data/lib/betterdocs/dsl/controller/controller_base.rb +21 -0
  23. data/lib/betterdocs/dsl/json_params.rb +8 -0
  24. data/lib/betterdocs/dsl/json_params/param.rb +31 -0
  25. data/lib/betterdocs/dsl/json_type_mapper.rb +27 -0
  26. data/lib/betterdocs/dsl/naming.rb +32 -0
  27. data/lib/betterdocs/dsl/representer.rb +29 -0
  28. data/lib/betterdocs/dsl/result.rb +10 -0
  29. data/lib/betterdocs/dsl/result/collection_property.rb +9 -0
  30. data/lib/betterdocs/dsl/result/link.rb +37 -0
  31. data/lib/betterdocs/dsl/result/property.rb +53 -0
  32. data/lib/betterdocs/generator/config_shortcuts.rb +28 -0
  33. data/lib/betterdocs/generator/markdown.rb +151 -0
  34. data/lib/betterdocs/generator/markdown/templates/README.md.erb +9 -0
  35. data/lib/betterdocs/generator/markdown/templates/section.md.erb +132 -0
  36. data/lib/betterdocs/global.rb +143 -0
  37. data/lib/betterdocs/json_params_representer.rb +37 -0
  38. data/lib/betterdocs/json_params_representer_collector.rb +48 -0
  39. data/lib/betterdocs/mix_into_controller.rb +19 -0
  40. data/lib/betterdocs/rake_tasks.rb +5 -0
  41. data/lib/betterdocs/representer.rb +42 -0
  42. data/lib/betterdocs/result_representer.rb +68 -0
  43. data/lib/betterdocs/result_representer_collector.rb +82 -0
  44. data/lib/betterdocs/section.rb +6 -0
  45. data/lib/betterdocs/tasks/doc.rake +55 -0
  46. data/lib/betterdocs/version.rb +8 -0
  47. data/spec/controller_dsl_spec.rb +143 -0
  48. data/spec/generator/markdown_spec.rb +5 -0
  49. data/spec/json_params_representer_spec.rb +79 -0
  50. data/spec/json_type_mapper_spec.rb +33 -0
  51. data/spec/result_representer_dsl_spec.rb +183 -0
  52. data/spec/result_representer_spec.rb +182 -0
  53. data/spec/spec_helper.rb +19 -0
  54. metadata +234 -0
@@ -0,0 +1,124 @@
1
+ Betterdocs API Documentation
2
+ ============================
3
+
4
+ [![Code Climate](https://codeclimate.com/repos/51128561f3ea0022cc027f31/badges/2a9719de54628d821871/gpa.png)](https://codeclimate.com/repos/51128561f3ea0022cc027f31/feed)
5
+
6
+ DESCRIPTION
7
+ -----------
8
+
9
+ This library can be used to document a rails based API.
10
+
11
+ LICENSE
12
+ -------
13
+
14
+ Apache License Version 2.0, see also the COPYING file.
15
+
16
+ USAGE EXAMPLES
17
+ --------------
18
+
19
+ These are some examples. Note that they are neither complete, nor work out of the box.
20
+
21
+ This api generator requires that you follow the [representer pattern](http://nicksda.apotomo.de/2011/12/ruby-on-rest-introducing-the-representer-pattern/) to decorate the objects you want to render. Betterdocs comes with it's own representer support baked in.
22
+
23
+ ## Controller
24
+
25
+ class ThingsController < ApplicationController
26
+ # :nocov: Documentation
27
+ doc :action do
28
+ section :things_list
29
+ title 'A List of things ⇄ [Details](things_details.md)'
30
+ description to <<-end
31
+ This action shows a list of things. **Markdown** can be used.
32
+ end
33
+
34
+ param :order do
35
+ description to <<-end
36
+ Optional parameter to order the list.
37
+ end
38
+ required no
39
+ value 'created_at:ASC'
40
+ end
41
+
42
+ response do
43
+ generate_fake_result_with_representer
44
+ end
45
+ end
46
+ # :nocov:
47
+ def index
48
+ render json: real_result_with_representer
49
+ end
50
+
51
+ # :nocov: Documentation
52
+ doc :action do
53
+ section :things_details
54
+ title 'Things Details ⇄ [List](things_list.md)'
55
+ description to <<-end
56
+ The details of a thing. You must give an id for the thing
57
+ end
58
+
59
+ param :thing_id do
60
+ description 'The id of the thing you want to see. Required.'
61
+ required yes # this is the default
62
+ value 38
63
+ end
64
+
65
+ response do
66
+ generate_fake_details_response_with_representer
67
+ end
68
+ end
69
+ # :nocov:
70
+ def show
71
+ render json: real_result_with_representer
72
+ end
73
+ end
74
+
75
+ ## Representer
76
+
77
+ Betterdocs comes with its own representer class. It is not documented
78
+ yet but works kind of like [ROAR](https://github.com/apotonick/roar).
79
+
80
+ module ThingsRepresenter
81
+
82
+ extend ActiveSupport::Concern
83
+ include Betterdocs::Representer
84
+
85
+ property :microfleem_count, if: -> { has_microfleems? }, as: :number_of_fleems do
86
+ description 'If we have microfleems, return the count'
87
+ types Integer
88
+ example '5000'
89
+ end
90
+
91
+ property :title, as: :name do
92
+ description to <<-end
93
+ Represent the internal field "title" as the name of the thing
94
+ end
95
+ types String
96
+ example 'my_name'
97
+ end
98
+
99
+ link :self do
100
+ description to <<-end
101
+ Link to this resource itself
102
+ (<a href="opinion_details.md">things details</a>)
103
+ end
104
+ url { thing_url(id) }
105
+ end
106
+ end
107
+
108
+ AUTHORS
109
+ -------
110
+ Florian Frank <flori@ping.de>
111
+
112
+ TODO
113
+ ----
114
+ - Implement some kind of scheme for versioning or at least better commit messages;
115
+ we also may want to keep other peoples commits if possible (how?).
116
+ - Refactor configuration to avoid singleton antipattern
117
+ - Create method in generator that considers a given string to be markdown
118
+ formatted and compiles it to html (as a work around to put multiline
119
+ descriptions inside of html tables in a markdown)
120
+ - Display enums as possible values in representers
121
+ - Automatically document error result documents
122
+ - Use private flag action/controller to skip docu creation by default. Make it
123
+ configurable to create private API as well.
124
+
@@ -0,0 +1,25 @@
1
+ # vim: set filetype=ruby et sw=2 ts=2:
2
+
3
+ require 'gem_hadar'
4
+
5
+ GemHadar do
6
+ name 'betterdocs'
7
+ author 'betterplace Developers'
8
+ email 'developers@betterplace.org'
9
+ homepage "http://github.com/betterplace/#{name}"
10
+ summary 'Betterplace API documentation library'
11
+ description "This library provides tools to generate API documention for a web site's REST-ful JSON API."
12
+ test_dir 'spec'
13
+ ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', 'coverage', '.rvmrc',
14
+ '.ruby-version', '.AppleDouble', 'tags', '.DS_Store', '.utilsrc', '.bundle'
15
+ readme 'README.md'
16
+ title "#{name.camelize} -- "
17
+
18
+ dependency 'tins', '~>1.3', '>=1.3.5'
19
+ dependency 'rails', '>=3', '<5'
20
+ dependency 'term-ansicolor', '~>1.3'
21
+ development_dependency 'simplecov'
22
+ development_dependency 'rspec'
23
+ end
24
+
25
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,48 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # stub: betterdocs 0.2.0 ruby lib
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "betterdocs"
6
+ s.version = "0.2.0"
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.require_paths = ["lib"]
10
+ s.authors = ["betterplace Developers"]
11
+ s.date = "2016-03-30"
12
+ s.description = "This library provides tools to generate API documention for a web site's REST-ful JSON API."
13
+ s.email = "developers@betterplace.org"
14
+ s.extra_rdoc_files = ["README.md", "lib/betterdocs.rb", "lib/betterdocs/controller_collector.rb", "lib/betterdocs/dsl.rb", "lib/betterdocs/dsl/common.rb", "lib/betterdocs/dsl/controller.rb", "lib/betterdocs/dsl/controller/action.rb", "lib/betterdocs/dsl/controller/action/param.rb", "lib/betterdocs/dsl/controller/action/response.rb", "lib/betterdocs/dsl/controller/controller.rb", "lib/betterdocs/dsl/controller/controller_base.rb", "lib/betterdocs/dsl/json_params.rb", "lib/betterdocs/dsl/json_params/param.rb", "lib/betterdocs/dsl/json_type_mapper.rb", "lib/betterdocs/dsl/naming.rb", "lib/betterdocs/dsl/representer.rb", "lib/betterdocs/dsl/result.rb", "lib/betterdocs/dsl/result/collection_property.rb", "lib/betterdocs/dsl/result/link.rb", "lib/betterdocs/dsl/result/property.rb", "lib/betterdocs/generator/config_shortcuts.rb", "lib/betterdocs/generator/markdown.rb", "lib/betterdocs/global.rb", "lib/betterdocs/json_params_representer.rb", "lib/betterdocs/json_params_representer_collector.rb", "lib/betterdocs/mix_into_controller.rb", "lib/betterdocs/rake_tasks.rb", "lib/betterdocs/representer.rb", "lib/betterdocs/result_representer.rb", "lib/betterdocs/result_representer_collector.rb", "lib/betterdocs/section.rb", "lib/betterdocs/version.rb"]
15
+ s.files = [".codeclimate.yml", ".gitignore", ".rspec", ".travis.yml", "COPYING", "Gemfile", "LICENSE", "README.md", "Rakefile", "VERSION", "betterdocs.gemspec", "lib/betterdocs.rb", "lib/betterdocs/controller_collector.rb", "lib/betterdocs/dsl.rb", "lib/betterdocs/dsl/common.rb", "lib/betterdocs/dsl/controller.rb", "lib/betterdocs/dsl/controller/action.rb", "lib/betterdocs/dsl/controller/action/param.rb", "lib/betterdocs/dsl/controller/action/response.rb", "lib/betterdocs/dsl/controller/controller.rb", "lib/betterdocs/dsl/controller/controller_base.rb", "lib/betterdocs/dsl/json_params.rb", "lib/betterdocs/dsl/json_params/param.rb", "lib/betterdocs/dsl/json_type_mapper.rb", "lib/betterdocs/dsl/naming.rb", "lib/betterdocs/dsl/representer.rb", "lib/betterdocs/dsl/result.rb", "lib/betterdocs/dsl/result/collection_property.rb", "lib/betterdocs/dsl/result/link.rb", "lib/betterdocs/dsl/result/property.rb", "lib/betterdocs/generator/config_shortcuts.rb", "lib/betterdocs/generator/markdown.rb", "lib/betterdocs/generator/markdown/templates/README.md.erb", "lib/betterdocs/generator/markdown/templates/section.md.erb", "lib/betterdocs/global.rb", "lib/betterdocs/json_params_representer.rb", "lib/betterdocs/json_params_representer_collector.rb", "lib/betterdocs/mix_into_controller.rb", "lib/betterdocs/rake_tasks.rb", "lib/betterdocs/representer.rb", "lib/betterdocs/result_representer.rb", "lib/betterdocs/result_representer_collector.rb", "lib/betterdocs/section.rb", "lib/betterdocs/tasks/doc.rake", "lib/betterdocs/version.rb", "spec/controller_dsl_spec.rb", "spec/generator/markdown_spec.rb", "spec/json_params_representer_spec.rb", "spec/json_type_mapper_spec.rb", "spec/result_representer_dsl_spec.rb", "spec/result_representer_spec.rb", "spec/spec_helper.rb"]
16
+ s.homepage = "http://github.com/betterplace/betterdocs"
17
+ s.rdoc_options = ["--title", "Betterdocs -- ", "--main", "README.md"]
18
+ s.rubygems_version = "2.5.1"
19
+ s.summary = "Betterplace API documentation library"
20
+ s.test_files = ["spec/controller_dsl_spec.rb", "spec/generator/markdown_spec.rb", "spec/json_params_representer_spec.rb", "spec/json_type_mapper_spec.rb", "spec/result_representer_dsl_spec.rb", "spec/result_representer_spec.rb", "spec/spec_helper.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ s.specification_version = 4
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ s.add_development_dependency(%q<gem_hadar>, ["~> 1.6.1"])
27
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
28
+ s.add_development_dependency(%q<rspec>, [">= 0"])
29
+ s.add_runtime_dependency(%q<tins>, [">= 1.3.5", "~> 1.3"])
30
+ s.add_runtime_dependency(%q<rails>, ["< 5", ">= 3"])
31
+ s.add_runtime_dependency(%q<term-ansicolor>, ["~> 1.3"])
32
+ else
33
+ s.add_dependency(%q<gem_hadar>, ["~> 1.6.1"])
34
+ s.add_dependency(%q<simplecov>, [">= 0"])
35
+ s.add_dependency(%q<rspec>, [">= 0"])
36
+ s.add_dependency(%q<tins>, [">= 1.3.5", "~> 1.3"])
37
+ s.add_dependency(%q<rails>, ["< 5", ">= 3"])
38
+ s.add_dependency(%q<term-ansicolor>, ["~> 1.3"])
39
+ end
40
+ else
41
+ s.add_dependency(%q<gem_hadar>, ["~> 1.6.1"])
42
+ s.add_dependency(%q<simplecov>, [">= 0"])
43
+ s.add_dependency(%q<rspec>, [">= 0"])
44
+ s.add_dependency(%q<tins>, [">= 1.3.5", "~> 1.3"])
45
+ s.add_dependency(%q<rails>, ["< 5", ">= 3"])
46
+ s.add_dependency(%q<term-ansicolor>, ["~> 1.3"])
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ require 'tins/xt'
2
+ require 'rails'
3
+
4
+ module Betterdocs
5
+ class << self
6
+ def rails
7
+ ::Rails
8
+ end
9
+
10
+ alias trait proc
11
+ public :trait
12
+ end
13
+ end
14
+
15
+ require 'betterdocs/version'
16
+ require 'betterdocs/dsl'
17
+ require 'betterdocs/result_representer'
18
+ require 'betterdocs/result_representer_collector'
19
+ require 'betterdocs/controller_collector'
20
+ require 'betterdocs/json_params_representer_collector'
21
+ require 'betterdocs/json_params_representer'
22
+ require 'betterdocs/global'
23
+ require 'betterdocs/section'
24
+ require 'betterdocs/mix_into_controller'
25
+ require 'betterdocs/generator/config_shortcuts'
26
+ require 'betterdocs/generator/markdown'
27
+ require 'betterdocs/rake_tasks'
@@ -0,0 +1,50 @@
1
+ module Betterdocs
2
+ class ControllerCollector
3
+ def initialize
4
+ @actions = {}
5
+ @element = nil
6
+ @controller = nil
7
+ end
8
+
9
+ attr_accessor :controller
10
+
11
+ attr_writer :element
12
+
13
+ def actions
14
+ @actions.values.reject(&:private)
15
+ end
16
+
17
+ def action(action_name)
18
+ action_name = action_name.to_sym
19
+ @actions[action_name]
20
+ end
21
+
22
+ def section
23
+ @controller.ask_and_send(:section)
24
+ end
25
+
26
+ def add_element(klass, type, &block)
27
+ element = build_element(klass, type, &block)
28
+ element.add_to_collector(self)
29
+ end
30
+
31
+ def configure_current_element(action_name)
32
+ if @element
33
+ @element.configure_for_action(action_name)
34
+ @actions[action_name] = @element
35
+ end
36
+ @element = nil
37
+ self
38
+ end
39
+
40
+ def to_s
41
+ ([ @controller, '=' * 79, actions * ("-" * 79 + "\n"), '' ]) * "\n"
42
+ end
43
+
44
+ private
45
+
46
+ def build_element(klass, type, &block)
47
+ Dsl::Controller.const_get(type.to_s.camelcase).new(klass, &block)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ module Betterdocs
2
+ module Dsl
3
+ end
4
+ end
5
+
6
+ require 'betterdocs/dsl/naming'
7
+ require 'betterdocs/dsl/controller'
8
+ require 'betterdocs/dsl/result'
9
+ require 'betterdocs/dsl/json_params'
@@ -0,0 +1,26 @@
1
+ module Betterdocs
2
+ module Dsl
3
+ module Common
4
+ extend Tins::Constant
5
+
6
+ constant :yes, true
7
+
8
+ constant :no, false
9
+
10
+ def set_context(context)
11
+ @__context__ = context
12
+ self
13
+ end
14
+
15
+ private
16
+
17
+ def method_missing(name, *a, &b)
18
+ if @__context__
19
+ @__context__.__send__(name, *a, &b)
20
+ else
21
+ super
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module Betterdocs
2
+ module Dsl
3
+ module Controller
4
+ end
5
+ end
6
+ end
7
+
8
+ require 'betterdocs/dsl/controller/action'
9
+ require 'betterdocs/dsl/controller/controller'
@@ -0,0 +1,126 @@
1
+ require 'betterdocs/dsl/controller/controller_base'
2
+ require 'betterdocs/dsl/common.rb'
3
+
4
+ class Betterdocs::Dsl::Controller::Action < Betterdocs::Dsl::Controller::ControllerBase
5
+ require 'betterdocs/dsl/controller/action/param'
6
+ require 'betterdocs/dsl/controller/action/response'
7
+
8
+ dsl_accessor :action
9
+
10
+ alias name action
11
+
12
+ dsl_accessor :title do "All about: #{action}" end
13
+
14
+ dsl_accessor :section do
15
+ controller.docs.controller.full?(:section) || :misc
16
+ end
17
+
18
+ dsl_accessor :action_method
19
+
20
+ dsl_accessor :http_method do
21
+ case action
22
+ when :show, :index
23
+ :GET
24
+ when :update
25
+ :PUT
26
+ when :destroy
27
+ :DELETE
28
+ when :create
29
+ :POST
30
+ else
31
+ raise ArgumentError, "Cannot automatically derive http_method for"\
32
+ " #{name.inspect}, specify manually"
33
+ end
34
+ end
35
+
36
+ dsl_accessor :params do {} end
37
+
38
+ dsl_accessor :json_params_representer
39
+
40
+ def json_params_like(klass)
41
+ json_params_representer klass.docs
42
+ self
43
+ end
44
+
45
+ def json_params
46
+ json_params_representer.full?(:params)
47
+ end
48
+
49
+ def json_params_example_json
50
+ if params = json_params_representer.full?(:params)
51
+ data = {}
52
+ params.each_with_object(data) do |(name, param), d|
53
+ d[name] = param.value
54
+ end
55
+ JSON.pretty_generate(JSON.load(JSON.dump(data)), quirks_mode: true) # sigh, don't ask…
56
+ end
57
+ end
58
+
59
+ dsl_accessor :private, false
60
+
61
+ def param(name, &block)
62
+ name = name.to_sym
63
+ if block
64
+ param = Betterdocs::Dsl::Controller::Action::Param.new(name, &block)
65
+ param.value or param.value params.size + 1
66
+ params[name] = param
67
+ else
68
+ params[name]
69
+ end
70
+ end
71
+
72
+ dsl_accessor :responses do {} end
73
+
74
+ def response(name = :default, &block)
75
+ if block
76
+ responses[name] = Betterdocs::Dsl::Controller::Action::Response.new(
77
+ name, &block
78
+ ).set_context(self)
79
+ else
80
+ responses[name]
81
+ end
82
+ end
83
+
84
+ dsl_accessor :description, 'TODO'
85
+
86
+ def configure_for_action(action_name)
87
+ action action_name
88
+ action_method controller.instance_method(action_name)
89
+ end
90
+
91
+ def include_params(callee)
92
+ instance_eval(&callee)
93
+ end
94
+
95
+ def url
96
+ url_params = params.select { |_, param| param.use_in_url? }
97
+ Betterdocs.rails.application.routes.url_for(
98
+ {
99
+ controller: controller.name.underscore.sub(/_controller\z/, ''),
100
+ action: action,
101
+ } | url_params | Betterdocs::Global.config.api_url_options
102
+ )
103
+ end
104
+
105
+ def request
106
+ "#{http_method.to_s.upcase} #{url}"
107
+ end
108
+
109
+ def to_s
110
+ (
111
+ [ request, '' ] +
112
+ [ inspect, '' ] +
113
+ params.map { |name, param|
114
+ "#{name}(=#{param.value}): #{param.description}"
115
+ } + [ '', description, '', action_method.source_location * ':', '' ]
116
+ ) * "\n"
117
+ end
118
+
119
+ def inspect
120
+ "#{controller}##{action}(#{params.keys * ', '})"
121
+ end
122
+
123
+ def add_to_collector(collector)
124
+ collector.element = self
125
+ end
126
+ end