diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 5f9d4dc..75eaa76 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -58,6 +58,7 @@ Metrics/BlockLength: # Configuration parameters: CountComments, Max, CountAsOne. Metrics/ClassLength: Exclude: + - 'lib/grape-swagger/entity/attribute_parser.rb' - 'lib/grape-swagger/entity/parser.rb' # Offense count: 2 diff --git a/CHANGELOG.md b/CHANGELOG.md index a510f76..6d5a181 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ #### Features +* [#69](https://github.com/ruby-grape/grape-swagger-entity/pull/67): Add support for minimum and maximum - [@storey](https://github.com/storey). * Your contribution here. #### Fixes diff --git a/lib/grape-swagger/entity/attribute_parser.rb b/lib/grape-swagger/entity/attribute_parser.rb index 0d6c15f..4323f2a 100644 --- a/lib/grape-swagger/entity/attribute_parser.rb +++ b/lib/grape-swagger/entity/attribute_parser.rb @@ -115,6 +115,15 @@ def add_attribute_sample(attribute, hash, key) end def add_attribute_documentation(param, documentation) + param[:minimum] = documentation[:minimum] if documentation.key?(:minimum) + param[:maximum] = documentation[:maximum] if documentation.key?(:maximum) + + values = documentation[:values] + if values&.is_a?(Range) + param[:minimum] = values.begin if values.begin.is_a?(Numeric) + param[:maximum] = values.end if values.end.is_a?(Numeric) + end + param[:minLength] = documentation[:min_length] if documentation.key?(:min_length) param[:maxLength] = documentation[:max_length] if documentation.key?(:max_length) end diff --git a/spec/grape-swagger/entity/attribute_parser_spec.rb b/spec/grape-swagger/entity/attribute_parser_spec.rb index 1ab2c80..d67fe82 100644 --- a/spec/grape-swagger/entity/attribute_parser_spec.rb +++ b/spec/grape-swagger/entity/attribute_parser_spec.rb @@ -85,6 +85,20 @@ it { is_expected.to include(maxLength: 1) } end + context 'when it contains values array' do + let(:entity_options) { { documentation: { type: 'string', desc: 'Colors', values: %w[red blue] } } } + + it { is_expected.to_not include('minimum') } + it { is_expected.to_not include('maximum') } + end + + context 'when it contains values range' do + let(:entity_options) { { documentation: { type: 'string', desc: 'Colors', values: 'a'...'c' } } } + + it { is_expected.to_not include('minimum') } + it { is_expected.to_not include('maximum') } + end + context 'when it contains extensions' do let(:entity_options) { { documentation: { type: 'string', desc: 'Colors', x: { some: 'stuff' } } } } @@ -92,6 +106,94 @@ end end + context 'when it is exposed as a number' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH' } } } + + it { is_expected.to include(type: 'number') } + + context 'when it contains minimum' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH', minimum: 2.5 } } } + + it { is_expected.to include(minimum: 2.5) } + end + + context 'when it contains maximum' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH', maximum: 9.1 } } } + + it { is_expected.to include(maximum: 9.1) } + end + + context 'when it contains values array' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH', values: [6.0, 7.0, 8.0] } } } + + it { is_expected.to_not include('minimum') } + it { is_expected.to_not include('maximum') } + end + + context 'when it contains values range' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH', values: 0.0..14.0 } } } + + it { is_expected.to include(minimum: 0.0, maximum: 14.0) } + end + + context 'when it contains values range with no minimum' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH', values: ..14.0 } } } + + it { is_expected.to_not include('minimum') } + it { is_expected.to include(maximum: 14.0) } + end + + context 'when it contains values range with no maximum' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH', values: 0.0.. } } } + + it { is_expected.to_not include('maximum') } + it { is_expected.to include(minimum: 0.0) } + end + + context 'when it contains extensions' do + let(:entity_options) { { documentation: { type: 'number', desc: 'Solution pH', x: { some: 'stuff' } } } } + + it { is_expected.to include('x-some' => 'stuff') } + end + end + + context 'when it is exposed as an integer' do + let(:entity_options) { { documentation: { type: 'integer', desc: 'Count' } } } + + it { is_expected.to include(type: 'integer') } + + context 'when it contains minimum' do + let(:entity_options) { { documentation: { type: 'integer', desc: 'Count', minimum: 2 } } } + + it { is_expected.to include(minimum: 2) } + end + + context 'when it contains maximum' do + let(:entity_options) { { documentation: { type: 'integer', desc: 'Count', maximum: 100 } } } + + it { is_expected.to include(maximum: 100) } + end + + context 'when it contains values array' do + let(:entity_options) { { documentation: { type: 'integer', desc: 'Count', values: 1..10 } } } + + it { is_expected.to_not include('minimum') } + it { is_expected.to_not include('maximum') } + end + + context 'when it contains values range' do + let(:entity_options) { { documentation: { type: 'integer', desc: 'Count', values: 1..10 } } } + + it { is_expected.to include(minimum: 1, maximum: 10) } + end + + context 'when it contains extensions' do + let(:entity_options) { { documentation: { type: 'integer', desc: 'Count', x: { some: 'stuff' } } } } + + it { is_expected.to include('x-some' => 'stuff') } + end + end + context 'when it is exposed as an array' do let(:entity_options) { { documentation: { type: 'string', desc: 'Colors', is_array: true } } }