rails_api_documentation 0.1.9 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4c67c2cdc12a310b1972630df13fa2a7dbab76e5
4
- data.tar.gz: cd2a6c178374ad1a8e9e9870fca0efe7f00c0796
3
+ metadata.gz: 2eafaedd7e6a3665cb3f17763d5204a80ec35e84
4
+ data.tar.gz: 3b09eb7ddd55e8300a60a0a4514084c8b03a2496
5
5
  SHA512:
6
- metadata.gz: 00397485504bad53e5ea83f3414165d59a9328375461cfb78355d650ced0e2615be6f7aaf4a4691686a059885f8eacb3e16642f36e00f2473139364675a391b8
7
- data.tar.gz: e533be586b8eb26d39ce266ecccb45d37e911e20afda1f8d6eaf058d6108bc50ae48398d238611bf2fa8440879c71aaea7ebacd4b5225b2b489ebd1c707232c1
6
+ metadata.gz: 8aff4ed365764127675f1150047a0ef21f05da820834a77a5459607bb0c7319b60123643f24398cd9003bda449a304ce8de2b094420a51409d321c347970ef17
7
+ data.tar.gz: 4d095bb8a1ea783f09820189c7c96544d21e1adf57b6d8a8065b24701fdef752e7cc9461cc755aec682c6fe7849cf29621157580fde4a39c86e149208c5590e6
data/Gemfile CHANGED
@@ -21,6 +21,7 @@ gem 'therubyrhino', '2.0.4', platforms: :jruby
21
21
 
22
22
  gem 'pry'
23
23
  gem 'pry-stack_explorer'
24
+ gem 'pry-rescue'
24
25
 
25
26
  group :development, :test do
26
27
  gem 'rspec-rails', '~> 3.5'
data/README.md CHANGED
@@ -17,6 +17,13 @@ Or install it yourself as:
17
17
 
18
18
  $ gem install rails_api_doc
19
19
 
20
+ ## Features
21
+
22
+ + displaying application api if used in one of correct ways
23
+ ![alt tag](https://raw.githubusercontent.com/vshaveyko/rails_api_doc/master/preview.png)
24
+ + Integration with Rabl if it is bundled
25
+ + ```resource_params``` method that will filter incoming params for you
26
+
20
27
  ## Usage
21
28
 
22
29
  To display api documentation on route '/api_doc' you need to:
@@ -49,12 +56,89 @@ To display api documentation on route '/api_doc' you need to:
49
56
  end
50
57
  ```
51
58
 
52
- Parameter type may be one of these:
59
+ ## Strong params
60
+
61
+ You may want to use your defined request api to filter incoming parameters.
62
+ Usually we use something like `params.permit(:name, :age)`, but no more!
63
+ With this gem bundled you can do this:
53
64
 
54
65
  ```ruby
55
- ACCEPTED_TYPES = [Bool, String, Integer, Object, Array, DateTime, :enum, :model].freeze
66
+
67
+ parameter :body, type: :string
68
+ parameter :title, type: :string
69
+
70
+ # controller action
71
+ def create
72
+ Comment.create!(resource_params)
73
+ end
74
+
75
+ ```
76
+
77
+ and if request is `POST '/comments', params: { body: 'Comment body', title: 'Comment title', age: 34 }`
78
+
79
+ Comment will be created with: `Comment(body='Comment body', title='Comment title', age=nil)`
80
+
81
+ ## Types
82
+
83
+ Parameter type may be one of these:
84
+
85
+ ```ruby
86
+
87
+ # Non nested
88
+ :bool - Boolean type, accepts true, false, 'true', 'false'
89
+ :string - will accept anything beside nested type
90
+ :integer - accepts numbers as string value, and usual numbers
91
+ :array - array of atomic values (integer, strings, etc)
92
+ :datetime - string with some datetime representation accepted by DateTime.parse
93
+ :enum - one of predefined values of enum: option (only atomic types)
94
+
95
+ # nested
96
+ :object - usual nested type. comes very handy with rails nested_attributes feature
97
+ :ary_object - array of :object type, rails nested_attributes on has_many
98
+
56
99
  ```
57
100
 
101
+ ## TODO's
102
+ + type for id reference with model field to display associated model and CONTROLLER in params for linking
103
+
104
+ + native DSL for defining response
105
+ ```ruby
106
+ action :show do
107
+ response :age, type: Integer
108
+ response :name, type String
109
+ response :data, type: :model, model: Datum do
110
+ response :creation_date, type: DateTime
111
+ response :comment, type: String
112
+ end
113
+ end
114
+ ```
115
+ + native DSL for defining scopes
116
+ ```ruby
117
+ scope :age, desc: 'Filters authors by given age'
118
+ ```
119
+ + dsl for extending response parameters
120
+ ```ruby
121
+ response :data, type: :model, model: Datum do
122
+ extends DataController, action: :show
123
+ end
124
+ ```
125
+ + dsl for extending request parameters
126
+ ```ruby
127
+ parameter :data, type: :model, model: Datum do
128
+ extends DataController, action: :show
129
+ end
130
+ ```
131
+ + ability to split request params to actions(low prior)
132
+ + CRUD for all parameters
133
+ + merging parameters from all sources before display
134
+ + pull everything that's possible to config
135
+
136
+ ## Development
137
+
138
+ + add specs for everything done
139
+ + inline documentation
140
+ + README FAQ on added functionality with examples
141
+
58
142
  ## License
59
143
 
60
144
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # author: Vadim Shaveiko <@vshaveyko>
3
+ class RailsApiDoc::Config::ValidateAryObject
4
+
5
+ #
6
+ # @api_param_data - RailsApiDoc::Controller::Parameter::Repository::Param
7
+ # @controller_param - ActionController::Parameter
8
+ #
9
+ # check validation of current type by given data
10
+ #
11
+ # ary_object: check that parameter is array of parameters
12
+ #
13
+ def valid?(controller_param, api_param_data)
14
+ return true unless api_param_data.ary_object?
15
+
16
+ controller_param.is_a?(Array) && begin
17
+ controller_param.all? { |param| param.is_a?(::ActionController::Parameters) }
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # author: Vadim Shaveiko <@vshaveyko>
3
+ # :nodoc:
4
+ class RailsApiDoc::Config::ValidateEnum
5
+
6
+ #
7
+ # @api_param_data - RailsApiDoc::Controller::Parameter::Repository::Param
8
+ # @controller_param - ActionController::Parameter
9
+ #
10
+ # check validation of current type by given data
11
+ #
12
+ # enum: check that enum array includes given value
13
+ #
14
+ def valid?(controller_param, api_param_data)
15
+ return true unless api_param_data.enum?
16
+
17
+ api_param_data[:enum].include?(controller_param)
18
+ end
19
+
20
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ # author: Vadim Shaveiko <@vshaveyko>
3
+ # :nodoc:
4
+ class RailsApiDoc::Config::ValidateType
5
+
6
+ #
7
+ # @api_param_data - RailsApiDoc::Controller::Parameter::Repository::Param
8
+ # @controller_param - ActionController::Parameter
9
+ #
10
+ # check validation of current type by given data
11
+ #
12
+ # type: check that param value is of requested type
13
+ # Examples:
14
+ #
15
+ # 1. controller_param == '1' , api_param_data[:type] == :integer > ok
16
+ # 2. controller_param == 'string' , api_param_data[:type] == :integer > not_ok
17
+ # 3. controller_param == {a: 'b'} , api_param_data[:type] == :object > ok
18
+ # 4. controller_param == [{a:'b'}, {c: 'd'}] , api_param_data[:type] == :ary_object > ok
19
+ # 5. controller_param == "2016-11-26 13:55:30 +0200"(or any other singature , use DateTime.parse to check) , api_param_data[:type] == :datetime > ok
20
+ # 6. controller_param == 'true' , api_param_data[:type] == :bool > ok
21
+ # 7. controller_param == true , api_param_data[:type] == :bool > ok
22
+ # 8. controller_param == 'ok' , api_param_data[:type] == :bool > not_ok
23
+ # 9. controller_param == ['1', '2', 3] , api_param_data[:type] == :array > ok
24
+ # 10. controller_param == [{a:'b'}] , api_param_data[:type] == :array > not_ok
25
+ #
26
+ # TODO: write rspec for this cases and implement
27
+ def valid?(_controller_param, _api_param_data)
28
+ true
29
+ end
30
+
31
+ end
@@ -1,14 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
  # author: Vadim Shaveiko <@vshaveyko>
3
+ require_relative 'validate_ary_object'
4
+ require_relative 'validate_enum'
5
+ require_relative 'validate_type'
6
+
3
7
  class RailsApiDoc::Config::Validator
4
8
 
5
- cattr_accessor :checkers
6
- self.checkers = []
9
+ class << self
10
+
11
+ attr_accessor :checkers
12
+
13
+ def add_checker(klass)
14
+ return if checkers.detect { |c| c.is_a?(klass) }
15
+
16
+ checkers << klass.new
17
+ end
7
18
 
8
- def self.valid_param?(controller_param, api_param_data)
9
- checkers.all? do |checker|
10
- checker.valid?(controller_param, api_param_data)
19
+ def remove_checker(klass)
20
+ checkers.delete_if { |c| c.is_a?(klass) }
11
21
  end
22
+
23
+ def valid_param?(controller_param, api_param_data)
24
+ checkers.all? do |checker|
25
+ checker.valid?(controller_param, api_param_data)
26
+ end
27
+ end
28
+
12
29
  end
13
30
 
31
+ self.checkers = [RailsApiDoc::Config::ValidateEnum.new, RailsApiDoc::Config::ValidateAryObject.new]
32
+
14
33
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # author: Vadim Shaveiko <@vshaveyko>
3
+ # :nodoc:
4
+ class RailsApiDoc::Config
5
+
6
+ attr_accessor :check_params_type
7
+
8
+ def check_params_type=(value)
9
+ if value
10
+ Validator.add_checker(ValidateType)
11
+ else
12
+ Validator.remove_checker(ValidateType)
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ require_relative 'config/validator'
@@ -2,21 +2,26 @@
2
2
  # author: Vadim Shaveiko <@vshaveyko>
3
3
  class RailsApiDoc::Controller::Parameter::Repository::Param
4
4
 
5
- ACCEPTED_TYPES = [::Bool, String, Integer, Object, Array, DateTime, :enum, :model].freeze
5
+ NESTED_TYPES = [:ary_object, :object, :model, Object].freeze
6
+
7
+ STRAIGHT_TYPES = [:bool, :string, :integer, :array, :datetime, :enum, String, Object, Integer, Array, DateTime].freeze
8
+
9
+ ACCEPTED_TYPES = (NESTED_TYPES + STRAIGHT_TYPES).freeze
6
10
 
7
11
  # @type - type to check
8
12
  def self.accepted_nested_type?(type)
9
- type == Object || type == :model
13
+ type.in?(NESTED_TYPES)
10
14
  end
11
15
 
12
16
  def self.valid_type?(type)
13
- return if type.in?(ACCEPTED_TYPES)
17
+ return if type.nil? || type.in?(ACCEPTED_TYPES)
14
18
  raise ArgumentError, "Wrong type: #{type}. " \
15
19
  "Correct types are: #{ACCEPTED_TYPES}."
16
20
  end
17
21
 
18
- def self.valid_enum?(enum)
19
- return if enum.nil? || enum.is_a?(Array)
22
+ def self.valid_enum?(type, enum)
23
+ return false unless type == :enum
24
+ return if enum.is_a?(Array)
20
25
  raise ArgumentError, 'Enum must be an array.'
21
26
  end
22
27
 
@@ -31,16 +36,28 @@ class RailsApiDoc::Controller::Parameter::Repository::Param
31
36
  @store = store
32
37
  end
33
38
 
39
+ def enum?
40
+ @store[:type] == :enum && @store[:enum].present?
41
+ end
42
+
43
+ def ary_object?
44
+ @store[:type] == :ary_object
45
+ end
46
+
34
47
  def nested?
35
48
  self.class.accepted_nested_type?(@store[:type])
36
49
  end
37
50
 
51
+ def nesting
52
+ @store[:nested]
53
+ end
54
+
38
55
  def required?
39
56
  @store[:required]
40
57
  end
41
58
 
42
59
  def method_missing(name, *args)
43
- return @store.send(name, *args) if respond_to_missing?(name)
60
+ return @store.public_send(name, *args) if respond_to_missing?(name)
44
61
  super
45
62
  end
46
63
 
@@ -6,7 +6,7 @@ module RailsApiDoc::Controller::Parameter
6
6
 
7
7
  # Use parameter in controller to defined REQUEST parameter.
8
8
  # Adds it to repository: RailsApiDoc::Controller::Parameter::Repository
9
- def parameter(name, options, &block)
9
+ def parameter(name, options = {}, &block)
10
10
  raise ArgumentError, 'Parameter already defined.' if repo.key?(name)
11
11
 
12
12
  validate_options(options, block_given?)
@@ -17,17 +17,9 @@ module RailsApiDoc::Controller::Parameter
17
17
  private
18
18
 
19
19
  def validate_options(options, block_given)
20
- if options.nil? || options.empty?
21
- raise ArgumentError, 'Empty options passed.'
22
- end
23
-
24
20
  options.assert_valid_keys(VALID_KEYS)
25
21
 
26
22
  Repository::Param.valid_type?(options[:type])
27
-
28
- Repository::Param.valid_enum?(options[:enum])
29
-
30
- Repository::Param.valid_nested?(options[:type], block_given)
31
23
  end
32
24
 
33
25
  # default repo can be reassigned to deal with nested parameters
@@ -36,13 +28,18 @@ module RailsApiDoc::Controller::Parameter
36
28
  @repo || Repository[self]
37
29
  end
38
30
 
31
+ # adjust parameter values depending on parameter type
32
+ # 1. if nested - add nested values to parameter_data on :nested key
33
+ # 2. if enum - transform all values to_s
34
+ # bcs all incoming controller parameters will be strings and there can be errors
39
35
  def define_parameter(name, parameter_data, &block)
40
- repo[name] = \
41
- if Repository::Param.valid_nested?(parameter_data[:type], block_given?)
42
- Repository::Param.new(name, nested_parameter(parameter_data, &block))
43
- else
44
- Repository::Param.new(name, parameter_data)
45
- end
36
+ if Repository::Param.valid_nested?(parameter_data[:type], block_given?)
37
+ parameter_data = nested_parameter(parameter_data, &block)
38
+ elsif Repository::Param.valid_enum?(parameter_data[:type], parameter_data[:enum])
39
+ parameter_data[:enum].map!(:to_s)
40
+ end
41
+
42
+ repo[name] = Repository::Param.new(name, parameter_data)
46
43
  end
47
44
 
48
45
  def nested_parameter(parameter_data)
@@ -2,45 +2,70 @@
2
2
  # frozen_string_literal: true
3
3
  module RailsApiDoc::Controller::StrongParams
4
4
 
5
+ ParamIsRequired = Class.new(StandardError)
6
+
5
7
  def resource_params
6
8
  # accepted_params for permit
7
- accepted_params = [{}]
8
- loop_params(params, permitted_params, accepted_params)
9
- params.permit(accepted_params)
9
+ params.permit(params_to_permit)
10
10
  end
11
11
 
12
12
  private
13
13
 
14
- # loop through current level of params and add to permit level if
15
- # all requirements met
16
- # requirements are: 1) if required is set - param must be present and not empty
17
- # 2) if enum is set - param must equal predefined value
14
+ def params_to_permit
15
+ accepted_params = [{}]
16
+
17
+ loop_params(params, permitted_params, accepted_params)
18
+
19
+ accepted_params
20
+ end
21
+
22
+ # loop through current level of params and add to permit level if all requirements are met
23
+ #
24
+ # requirements are: 1) if required is set - param must be present and not empty => or error is raised
25
+ # 2) if enum is set - param must equal predefined value => see Config::ValidateEnum
26
+ # 3) if ary_object => see Config::ValidateAryObject
18
27
  # 3) if config.check_params_type is set - param must be of required type
28
+ #
19
29
  # @accepted_params = [{}] - array with last member hash for nesting
20
30
  # @level_params - current nesting level params
21
31
  # @level_permitted_params - data for params permission
22
- def loop_params(nested_controller_params, level_permitted_params, accepted_params)
32
+ def loop_params(params, level_permitted_params, accepted_params)
23
33
  level_permitted_params.each do |param_name, api_param_data|
24
- controller_param = nested_controller_params[param_name]
34
+ controller_param = params[param_name]
35
+
36
+ check_required(param_name, controller_param, api_param_data)
37
+ #
38
+ # no value present && not required => go next
39
+ next unless controller_param
25
40
 
26
41
  next unless RailsApiDoc::Config::Validator.valid_param?(controller_param, api_param_data)
27
42
 
28
- if api_param_data.nested?
29
- level_accepted_params = accepted_params.last[param_name] = [{}]
30
- next loop_params(controller_param, api_param_data, level_accepted_params)
43
+ # if settings is array
44
+ if api_param_data.ary_object?
45
+ controller_param.each do |single_controller_param|
46
+ _next_nesting_level(single_controller_param, param_data: api_param_data, current_accepted_params: accepted_params, param_name: param_name)
47
+ end
48
+ elsif api_param_data.nested?
49
+ _next_nesting_level(controller_param, param_data: api_param_data, current_accepted_params: accepted_params, param_name: param_name)
31
50
  else
32
51
  accepted_params.unshift(param_name)
33
52
  end
34
53
  end
35
54
  end
36
55
 
56
+ def _next_nesting_level(controller_param, param_data:, current_accepted_params:, param_name:)
57
+ level_accepted_params = current_accepted_params.last[param_name] = [{}]
58
+
59
+ loop_params(controller_param, param_data.nesting, level_accepted_params)
60
+ end
61
+
37
62
  def permitted_params
38
- Parameter::Repository[self]
63
+ ::RailsApiDoc::Controller::Parameter::Repository[self.class]
39
64
  end
40
65
 
41
- def check_required_ok?(param_data, param_config)
42
- return true unless param_config.required?
43
- !param_data.blank?
66
+ def check_required(param_name, param_data, param_config)
67
+ return unless param_config.required? && param_data.blank?
68
+ raise RailsApiDoc::Exception::ParamRequired, param_name
44
69
  end
45
70
 
46
71
  end
@@ -5,9 +5,12 @@ require 'action_view'
5
5
  require 'jquery-rails'
6
6
  require 'slim'
7
7
 
8
+ require_relative 'exception/param_required'
9
+
8
10
  require_relative 'controller'
9
11
  require_relative 'controller/strong_params'
10
12
  require_relative 'controller/attribute_parser'
13
+
11
14
  require_relative 'controller/parameter'
12
15
  require_relative 'controller/parameter/repository'
13
16
  require_relative 'controller/parameter/repository/param'
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ # author: Vadim Shaveiko <@vshaveyko>
3
+ # :nodoc:
4
+ module RailsApiDoc
5
+ module Exception
6
+ class ParamRequired < StandardError
7
+
8
+ def initialize(param_name)
9
+ @message = "#{param_name} is marked as required, but has no value."
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  # author: Vadim Shaveiko <@vshaveyko>
3
3
  module RailsApiDoc
4
- VERSION = '0.1.9'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/rails_api_doc.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # author: Vadim Shaveiko <@vshaveyko>
2
2
  # frozen_string_literal: true
3
- module RailsApiDoc
3
+ require 'rails_api_doc/config'
4
4
 
5
- extend ActiveSupport::Autoload
5
+ module RailsApiDoc
6
6
 
7
7
  class << self
8
8
 
@@ -11,7 +11,7 @@ module RailsApiDoc
11
11
  end
12
12
 
13
13
  def configuration
14
- @_configuration ||= Configuration.new
14
+ @_configuration ||= Config.new
15
15
  end
16
16
 
17
17
  def reset_configuration
@@ -20,19 +20,6 @@ module RailsApiDoc
20
20
 
21
21
  end
22
22
 
23
- autoload :Controller
24
-
25
- end
26
-
27
- # constants for defining in controllers
28
- # TODO: move to namespace ?
29
- class Bool
30
- end
31
-
32
- class Enum
33
- end
34
-
35
- class Nested
36
23
  end
37
24
 
38
25
  require 'rails_api_doc/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_api_documentation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - vs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-23 00:00:00.000000000 Z
11
+ date: 2016-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -158,8 +158,11 @@ files:
158
158
  - app/views/shared/_table.slim
159
159
  - config/routes.rb
160
160
  - lib/rails_api_doc.rb
161
+ - lib/rails_api_doc/config.rb
162
+ - lib/rails_api_doc/config/validate_ary_object.rb
163
+ - lib/rails_api_doc/config/validate_enum.rb
164
+ - lib/rails_api_doc/config/validate_type.rb
161
165
  - lib/rails_api_doc/config/validator.rb
162
- - lib/rails_api_doc/configuration.rb
163
166
  - lib/rails_api_doc/controller.rb
164
167
  - lib/rails_api_doc/controller/attribute_parser.rb
165
168
  - lib/rails_api_doc/controller/parameter.rb
@@ -170,6 +173,7 @@ files:
170
173
  - lib/rails_api_doc/controller/response_factory.rb
171
174
  - lib/rails_api_doc/controller/strong_params.rb
172
175
  - lib/rails_api_doc/engine.rb
176
+ - lib/rails_api_doc/exception/param_required.rb
173
177
  - lib/rails_api_doc/version.rb
174
178
  homepage: https://github.com/vshaveyko/rails_api_doc
175
179
  licenses:
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
- # author: Vadim Shaveiko <@vshaveyko>
3
- # :nodoc:
4
- class RailsApiDoc::Configuration
5
-
6
- def initialize
7
- end
8
-
9
- end