grape-swagger-entity 0.7.0 → 0.7.1

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
  SHA256:
3
- metadata.gz: 3d55e877c4ed7f40cbc6331e38fdb62522c85e92dfcb5bbf239be8181cbcd456
4
- data.tar.gz: c22441830ec45ee2ef82dff6066106bfecfd5a820050665090e4c4f9c110b16e
3
+ metadata.gz: 30e014da1f2cee91b947f2028660fcad2f9d71102bbe30d4eff6369a48974949
4
+ data.tar.gz: 4e6d460b2a210c5356a99444b89ca8dec5ded34b1601a4200e01ac4e7d84d68e
5
5
  SHA512:
6
- metadata.gz: bbf329848abcdcef57edd7cde491cef96160f29e266958f9ad5763f987210d506811858937c4e9cee59d85e2ff3ad200e85834a2cece230a172d22a6b0aaa2c9
7
- data.tar.gz: efe0f9739a54925a044661d02ecd9ba232a5909a9c08556bd5a51c39aa6ea82ab413db5e77a350659ccba75462ceba704efb95f02ce2f774ea762f3491d8460c
6
+ metadata.gz: 4830b3a7de51a5391ff090594e70bdb492c722bbcdc6e88745f169b22dc417a64291facee0fb465b3488804a81c113beb6b0f8f5b84f4204b69c9c108b5e3b89
7
+ data.tar.gz: 0b029af3078ad8c0769177445a2ed698292ba7f77fd910134dd8274f8d4d5d0f0354d2130916a78cc687aa44b36af797a503055052c9ea30808eaf0a0fbec63e
@@ -0,0 +1,10 @@
1
+ name: Danger Comment
2
+ on:
3
+ workflow_run:
4
+ workflows: [Danger]
5
+ types: [completed]
6
+
7
+ jobs:
8
+ comment:
9
+ uses: numbata/danger-pr-comment/.github/workflows/danger-comment.yml@main
10
+ secrets: inherit
@@ -1,21 +1,11 @@
1
- name: danger
2
- on: pull_request
1
+ name: Danger
2
+ on:
3
+ pull_request:
4
+ types: [opened, reopened, edited, synchronize]
3
5
 
4
6
  jobs:
5
7
  danger:
6
- runs-on: ubuntu-latest
7
- steps:
8
- - uses: actions/checkout@v4
9
- with:
10
- fetch-depth: 100
11
- - name: Set up Ruby
12
- uses: ruby/setup-ruby@v1
13
- with:
14
- ruby-version: 3.2
15
- bundler-cache: true
16
- rubygems: latest
17
- - name: Run Danger
18
- run: |
19
- # the token is public, has public_repo scope and belongs to the grape-bot user owned by @dblock, this is ok
20
- TOKEN=$(echo -n Z2hwX2lYb0dPNXNyejYzOFJyaTV3QUxUdkNiS1dtblFwZTFuRXpmMwo= | base64 --decode)
21
- DANGER_GITHUB_API_TOKEN=$TOKEN bundle exec danger --verbose
8
+ uses: numbata/danger-pr-comment/.github/workflows/danger-run.yml@main
9
+ secrets: inherit
10
+ with:
11
+ ruby-version: "3.2"
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --format documentation
2
2
  --color
3
+ --require "spec_helper"
data/.rubocop_todo.yml CHANGED
@@ -6,12 +6,14 @@
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 3
9
+ # Offense count: 8
10
10
  # Configuration parameters: AllowedMethods.
11
11
  # AllowedMethods: enums
12
12
  Lint/ConstantDefinitionInBlock:
13
13
  Exclude:
14
14
  - 'spec/grape-swagger/entities/response_model_spec.rb'
15
+ - 'spec/issues/44_desc_in_entity_type_spec.rb'
16
+ - 'spec/issues/962_polymorphic_entity_with_custom_documentation_spec.rb'
15
17
  - 'spec/support/shared_contexts/inheritance_api.rb'
16
18
  - 'spec/support/shared_contexts/this_api.rb'
17
19
 
@@ -21,6 +23,11 @@ Lint/EmptyBlock:
21
23
  Exclude:
22
24
  - 'spec/grape-swagger/entity/attribute_parser_spec.rb'
23
25
 
26
+ # Offense count: 1
27
+ Lint/EmptyClass:
28
+ Exclude:
29
+ - 'spec/support/shared_contexts/custom_type_parser.rb'
30
+
24
31
  # Offense count: 2
25
32
  # This cop supports unsafe autocorrection (--autocorrect-all).
26
33
  # Configuration parameters: AllowedMethods.
@@ -37,7 +44,7 @@ Metrics/AbcSize:
37
44
  # Offense count: 2
38
45
  # Configuration parameters: CountComments, CountAsOne.
39
46
  Metrics/ClassLength:
40
- Max: 117
47
+ Max: 145
41
48
 
42
49
  # Offense count: 2
43
50
  # Configuration parameters: AllowedMethods, AllowedPatterns.
@@ -79,11 +86,12 @@ RSpec/ContextWording:
79
86
  - 'spec/support/shared_contexts/inheritance_api.rb'
80
87
  - 'spec/support/shared_contexts/this_api.rb'
81
88
 
82
- # Offense count: 2
89
+ # Offense count: 3
83
90
  # Configuration parameters: IgnoredMetadata.
84
91
  RSpec/DescribeClass:
85
92
  Exclude:
86
93
  - '**/spec/features/**/*'
94
+ - '**/spec/issues/**/*'
87
95
  - '**/spec/requests/**/*'
88
96
  - '**/spec/routing/**/*'
89
97
  - '**/spec/system/**/*'
@@ -93,12 +101,13 @@ RSpec/DescribeClass:
93
101
  # Offense count: 4
94
102
  # Configuration parameters: CountAsOne.
95
103
  RSpec/ExampleLength:
96
- Max: 213
104
+ Max: 225
97
105
 
98
- # Offense count: 26
106
+ # Offense count: 30
99
107
  RSpec/LeakyConstantDeclaration:
100
108
  Exclude:
101
109
  - 'spec/grape-swagger/entities/response_model_spec.rb'
110
+ - '**/spec/issues/**/*'
102
111
  - 'spec/support/shared_contexts/inheritance_api.rb'
103
112
  - 'spec/support/shared_contexts/this_api.rb'
104
113
 
data/AGENTS.md ADDED
@@ -0,0 +1,24 @@
1
+ # grape-swagger-entity
2
+
3
+ Adapter for grape-swagger that parses Grape::Entity classes into OpenAPI schema definitions.
4
+
5
+ ## Quick Reference
6
+
7
+ ```bash
8
+ bundle install # Install dependencies
9
+ bundle exec rspec # Run tests
10
+ bundle exec rubocop # Run linter
11
+ bundle exec rubocop -a # Auto-fix linter issues
12
+ ```
13
+
14
+ ## Key Constraints
15
+
16
+ - Ruby >= 3.0
17
+ - All files must start with `# frozen_string_literal: true`
18
+ - CHANGELOG.md entry required for every PR (danger enforces this)
19
+
20
+ ## Documentation
21
+
22
+ - [Testing Patterns](docs/testing.md)
23
+ - [Contributing Guidelines](docs/contributing.md)
24
+ - [Architecture Overview](docs/architecture.md)
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### 0.7.1 (2026/01/28)
2
+
3
+ #### Features
4
+
5
+ * [#91](https://github.com/ruby-grape/grape-swagger-entity/pull/91): Improve README and add documentation structure - [@numbata](https://github.com/numbata).
6
+
7
+ #### Fixes
8
+
9
+ * [#90](https://github.com/ruby-grape/grape-swagger-entity/pull/90): Fix description not rendered for non-array entity references - [@numbata](https://github.com/numbata).
10
+ * [#86](https://github.com/ruby-grape/grape-swagger-entity/pull/86): Fix Array[Object] documentation type parsing - [@numbata](https://github.com/numbata).
11
+ * [#87](https://github.com/ruby-grape/grape-swagger-entity/pull/87): Remove hidden attributes from required - [@bogdan](https://github.com/bogdan).
12
+ * [#88](https://github.com/ruby-grape/grape-swagger-entity/pull/88): Update danger workflows - [@numbata](https://github.com/numbata).
13
+ * [#89](https://github.com/ruby-grape/grape-swagger-entity/pull/89): Remove ruby-grape-danger - [@dblock](https://github.com/dblock).
14
+
1
15
  ### 0.7.0 (2025/08/02)
2
16
 
3
17
  #### Features
data/Dangerfile CHANGED
@@ -1,3 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- danger.import_dangerfile(gem: 'ruby-grape-danger')
3
+ danger.import_dangerfile(gem: 'danger-pr-comment')
4
+
5
+ changelog.check!
6
+ toc.check!
data/Gemfile CHANGED
@@ -43,7 +43,10 @@ group :development do
43
43
  end
44
44
 
45
45
  group :test do
46
+ gem 'danger', require: false
47
+ gem 'danger-changelog', require: false
48
+ gem 'danger-pr-comment', require: false
49
+ gem 'danger-toc', require: false
46
50
  gem 'grape-entity', grape_entity_spec
47
- gem 'ruby-grape-danger', '~> 0.2.1', require: false
48
51
  gem 'simplecov', require: false
49
52
  end
data/README.md CHANGED
@@ -6,15 +6,64 @@
6
6
  ## Table of Contents
7
7
 
8
8
  - [What is grape-swagger-entity?](#what-is-grape-swagger-entity)
9
+ - [What it does](#what-it-does)
10
+ - [Example Output](#example-output)
11
+ - [Related Projects](#related-projects)
12
+ - [Compatibility](#compatibility)
9
13
  - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ - [Basic Entity](#basic-entity)
16
+ - [Custom Model Description](#custom-model-description)
17
+ - [Entity References](#entity-references)
18
+ - [Documentation Options](#documentation-options)
10
19
  - [Development](#development)
11
20
  - [Contributing](#contributing)
12
21
  - [License](#license)
13
22
 
14
-
15
23
  ## What is grape-swagger-entity?
16
24
 
17
- A simple grape-swagger adapter to allow parse representers as response model
25
+ This gem provides an adapter for [grape-swagger](https://github.com/ruby-grape/grape-swagger) that allows parsing [grape-entity](https://github.com/ruby-grape/grape-entity) classes to generate OpenAPI/Swagger model definitions automatically.
26
+
27
+ ### What it does
28
+
29
+ - Generates `definitions` in your Swagger JSON from Grape::Entity exposures
30
+ - Maps entity properties to OpenAPI schema properties with types and descriptions
31
+ - Handles nested entities and entity references via `$ref`
32
+ - Supports arrays, required fields, and documentation options
33
+
34
+ ### Example Output
35
+
36
+ ```json
37
+ {
38
+ "definitions": {
39
+ "User": {
40
+ "type": "object",
41
+ "description": "User model",
42
+ "properties": {
43
+ "id": { "type": "integer", "description": "User ID" },
44
+ "name": { "type": "string", "description": "Full name" }
45
+ },
46
+ "required": ["id", "name"]
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## Related Projects
53
+
54
+ - [Grape](https://github.com/ruby-grape/grape)
55
+ - [Grape Entity](https://github.com/ruby-grape/grape-entity)
56
+ - [Grape Swagger](https://github.com/ruby-grape/grape-swagger)
57
+ - [Grape Swagger Representable](https://github.com/ruby-grape/grape-swagger-representable)
58
+
59
+ ## Compatibility
60
+
61
+ This gem is tested with the following versions:
62
+
63
+ | grape-swagger-entity | grape-swagger | grape-entity | grape |
64
+ |---------------------|---------------|--------------|---------|
65
+ | 0.7.x | >= 2.0.0 | >= 1.0.0 | >= 1.3 |
66
+ | 0.6.x | >= 1.2.0 | >= 0.6.0 | >= 1.3 |
18
67
 
19
68
  ## Installation
20
69
 
@@ -32,17 +81,63 @@ Or install it yourself as:
32
81
 
33
82
  $ gem install grape-swagger-entity
34
83
 
35
- ## Development
84
+ ## Usage
85
+
86
+ ### Basic Entity
87
+
88
+ Define your entities with `documentation` options to generate OpenAPI schema properties:
89
+
90
+ ```ruby
91
+ class UserEntity < Grape::Entity
92
+ expose :id, documentation: { type: Integer, desc: 'User ID' }
93
+ expose :name, documentation: { type: String, desc: 'Full name' }
94
+ expose :email, documentation: { type: String, desc: 'Email address' }
95
+ end
96
+ ```
97
+
98
+ ### Custom Model Description
36
99
 
37
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec` to run the tests. You can also run `bin/pry` for an interactive prompt that will allow you to experiment.
100
+ Override the default "{ModelName} model" description by defining a `self.documentation` method. This feature is handled by [grape-swagger](https://github.com/ruby-grape/grape-swagger) (requires grape-swagger >= 2.2.0):
38
101
 
39
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
102
+ ```ruby
103
+ class UserEntity < Grape::Entity
104
+ def self.documentation
105
+ { desc: 'Represents a user account with profile information' }
106
+ end
107
+
108
+ expose :id, documentation: { type: Integer, desc: 'User ID' }
109
+ expose :name, documentation: { type: String, desc: 'Full name' }
110
+ end
111
+ ```
112
+
113
+ ### Entity References
114
+
115
+ Use `using:` to reference other entities and `is_array:` for collections:
116
+
117
+ ```ruby
118
+ class OrderEntity < Grape::Entity
119
+ expose :id, documentation: { type: Integer, desc: 'Order ID' }
120
+ expose :user, using: UserEntity,
121
+ documentation: { desc: 'The customer who placed this order' }
122
+ expose :items, using: ItemEntity,
123
+ documentation: { desc: 'Line items', is_array: true }
124
+ end
125
+ ```
126
+
127
+ ### Documentation Options
128
+
129
+ Common options: `type`, `desc`, `required`, `is_array`, `values`, `example`.
130
+
131
+ See [full documentation options](docs/documentation-options.md) for all available options including validation constraints.
132
+
133
+ ## Development
134
+
135
+ See [testing documentation](docs/testing.md) for development setup and running tests.
40
136
 
41
137
  ## Contributing
42
138
 
43
- Bug reports and pull requests are welcome on GitHub at https://github.com/ruby-grape/grape-swagger-entity.
139
+ See [contributing guidelines](docs/contributing.md).
44
140
 
45
141
  ## License
46
142
 
47
143
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
48
-
@@ -0,0 +1,71 @@
1
+ # Architecture Overview
2
+
3
+ ## Purpose
4
+
5
+ This gem registers a model parser with grape-swagger that converts `Grape::Entity` classes into OpenAPI schema definitions.
6
+
7
+ ## Core Components
8
+
9
+ ```
10
+ lib/grape-swagger/entity/
11
+ ├── parser.rb # Main parser - converts Entity to OpenAPI schema
12
+ ├── attribute_parser.rb # Parses individual exposure attributes
13
+ ├── helper.rb # Utility methods for model naming, discriminators
14
+ └── version.rb # Gem version
15
+ ```
16
+
17
+ ### Parser (`parser.rb`)
18
+
19
+ Entry point for entity parsing. Responsibilities:
20
+ - Extract exposures from Grape::Entity
21
+ - Handle nested entities and `using:` references
22
+ - Process `merge: true` exposures
23
+ - Handle inheritance with `allOf` and discriminators
24
+ - Determine required fields
25
+
26
+ ### AttributeParser (`attribute_parser.rb`)
27
+
28
+ Converts individual exposure options to OpenAPI property schema:
29
+ - Maps Ruby types to OpenAPI types
30
+ - Handles arrays (`is_array: true`)
31
+ - Processes enums (`values:`)
32
+ - Adds constraints (min/max, minLength/maxLength)
33
+
34
+ ### Helper (`helper.rb`)
35
+
36
+ Utilities for:
37
+ - Model name resolution (strips Entity/Entities suffix)
38
+ - Discriminator detection for inheritance
39
+ - Root exposure extraction
40
+
41
+ ## Data Flow
42
+
43
+ ```
44
+ Grape::Entity class
45
+
46
+
47
+ Parser.call
48
+
49
+ ├── extract_params (get exposures)
50
+
51
+ ├── parse_grape_entity_params
52
+ │ │
53
+ │ ├── AttributeParser (per exposure)
54
+ │ │
55
+ │ └── parse_nested (for nested blocks)
56
+
57
+ └── handle_discriminator (inheritance)
58
+
59
+
60
+ [properties_hash, required_array]
61
+ ```
62
+
63
+ ## Integration Point
64
+
65
+ Registered with grape-swagger in `lib/grape-swagger/entity.rb`:
66
+
67
+ ```ruby
68
+ GrapeSwagger.model_parsers.register(GrapeSwagger::Entity::Parser, Grape::Entity)
69
+ ```
70
+
71
+ grape-swagger calls `Parser.new(model, endpoint).call` when it encounters a `Grape::Entity` subclass.
@@ -0,0 +1,57 @@
1
+ # Contributing Guidelines
2
+
3
+ ## PR Requirements
4
+
5
+ Every PR must include:
6
+
7
+ 1. **CHANGELOG.md entry** - Add under `### X.X.X (Next)` in the appropriate section:
8
+ ```markdown
9
+ #### Fixes
10
+ * [#123](https://github.com/ruby-grape/grape-swagger-entity/pull/123): Brief description - [@username](https://github.com/username).
11
+ ```
12
+
13
+ 2. **Passing CI** - RuboCop + RSpec must pass
14
+
15
+ 3. **Tests** - New functionality needs specs; bug fixes need regression tests
16
+
17
+ ## CHANGELOG Format
18
+
19
+ ```markdown
20
+ ### 0.7.1 (Next)
21
+
22
+ #### Features
23
+
24
+ * Your contribution here.
25
+
26
+ #### Fixes
27
+
28
+ * [#PR](URL): Description - [@author](URL).
29
+ ```
30
+
31
+ - Use `Features` for new functionality
32
+ - Use `Fixes` for bug fixes and maintenance
33
+
34
+ ## Commit Messages
35
+
36
+ Follow conventional style:
37
+ - `Fix #123: description` for bug fixes
38
+ - `Add feature description` for features
39
+ - `Update dependency/docs` for maintenance
40
+
41
+ ## Code Style
42
+
43
+ RuboCop enforces style. Key rules:
44
+ - `frozen_string_literal: true` pragma required
45
+ - Consistent hash indentation
46
+ - No trailing whitespace
47
+
48
+ ```bash
49
+ bundle exec rubocop -a # Auto-fix most issues
50
+ ```
51
+
52
+ ## Danger Checks
53
+
54
+ CI runs danger which enforces:
55
+ - CHANGELOG entry present
56
+ - Table of Contents in README is current
57
+ - PR has description
@@ -0,0 +1,89 @@
1
+ # Documentation Options
2
+
3
+ The `documentation` hash in entity exposures supports the following options:
4
+
5
+ ## Type Options
6
+
7
+ | Option | Description | Example |
8
+ |--------|-------------|---------|
9
+ | `type` | OpenAPI data type | `String`, `Integer`, `Boolean`, `Float`, `Date`, `DateTime` |
10
+ | `is_array` | Marks field as array type | `true` / `false` |
11
+
12
+ ## Description Options
13
+
14
+ | Option | Description | Example |
15
+ |--------|-------------|---------|
16
+ | `desc` | Property description | `'User email address'` |
17
+ | `example` | Example value for documentation | `'user@example.com'` |
18
+ | `default` | Default value | `'pending'` |
19
+
20
+ ## Validation Options
21
+
22
+ | Option | Description | Example |
23
+ |--------|-------------|---------|
24
+ | `required` | Whether field is required | `true` / `false` |
25
+ | `values` | Enum values (array or proc) | `%w[pending active]` or `-> { Status.all }` |
26
+ | `minimum` | Minimum value for numeric types | `0` |
27
+ | `maximum` | Maximum value for numeric types | `100` |
28
+ | `min_length` | Minimum length for strings | `1` |
29
+ | `max_length` | Maximum length for strings | `255` |
30
+ | `min_items` | Minimum items for arrays | `1` |
31
+ | `max_items` | Maximum items for arrays | `10` |
32
+ | `unique_items` | Array items must be unique | `true` |
33
+
34
+ ## Display Options
35
+
36
+ | Option | Description | Example |
37
+ |--------|-------------|---------|
38
+ | `read_only` | Marks field as read-only | `true` |
39
+ | `hidden` | Hide field from documentation | `true` |
40
+
41
+ ## Examples
42
+
43
+ ### Basic types
44
+
45
+ ```ruby
46
+ expose :id, documentation: { type: Integer, desc: 'Unique identifier' }
47
+ expose :name, documentation: { type: String, desc: 'Full name', required: true }
48
+ expose :active, documentation: { type: Boolean, default: true }
49
+ ```
50
+
51
+ ### Enums
52
+
53
+ ```ruby
54
+ expose :status, documentation: {
55
+ type: String,
56
+ desc: 'Current status',
57
+ values: %w[pending active suspended]
58
+ }
59
+ ```
60
+
61
+ ### Numeric constraints
62
+
63
+ ```ruby
64
+ expose :age, documentation: {
65
+ type: Integer,
66
+ minimum: 0,
67
+ maximum: 150
68
+ }
69
+ ```
70
+
71
+ ### String constraints
72
+
73
+ ```ruby
74
+ expose :username, documentation: {
75
+ type: String,
76
+ min_length: 3,
77
+ max_length: 20
78
+ }
79
+ ```
80
+
81
+ ### Arrays
82
+
83
+ ```ruby
84
+ expose :tags, documentation: {
85
+ type: String,
86
+ is_array: true,
87
+ desc: 'Associated tags'
88
+ }
89
+ ```
data/docs/testing.md ADDED
@@ -0,0 +1,63 @@
1
+ # Testing Patterns
2
+
3
+ ## Running Tests
4
+
5
+ ```bash
6
+ bundle exec rspec # Run all tests
7
+ bundle exec rspec spec/path/file.rb # Run specific file
8
+ bundle exec rspec -e "description" # Run matching examples
9
+ ```
10
+
11
+ ## Test Structure
12
+
13
+ ```
14
+ spec/
15
+ ├── grape-swagger/
16
+ │ ├── entity_spec.rb # Main module specs
17
+ │ ├── entity/
18
+ │ │ ├── parser_spec.rb # Parser unit tests
19
+ │ │ └── attribute_parser_spec.rb
20
+ │ └── entities/
21
+ │ └── response_model_spec.rb # Integration tests
22
+ ├── issues/ # Regression tests for GitHub issues
23
+ │ └── 962_polymorphic_entity_... # Named by issue number
24
+ └── support/
25
+ └── shared_contexts/ # Reusable test setup
26
+ ```
27
+
28
+ ## Shared Contexts
29
+
30
+ Use shared contexts for common API setups:
31
+
32
+ ```ruby
33
+ require 'spec_helper'
34
+ require_relative '../../support/shared_contexts/this_api'
35
+
36
+ describe SomeClass do
37
+ include_context 'this api'
38
+ # ...
39
+ end
40
+ ```
41
+
42
+ ## Issue Regression Tests
43
+
44
+ When fixing a bug, create a spec in `spec/issues/` named `{issue_number}_{brief_description}_spec.rb`:
45
+
46
+ ```ruby
47
+ # spec/issues/123_some_bug_spec.rb
48
+ require 'spec_helper'
49
+
50
+ describe '#123 brief description of the issue' do
51
+ # Test that reproduces and verifies the fix
52
+ end
53
+ ```
54
+
55
+ ## Testing with Different Gem Versions
56
+
57
+ Environment variables control dependency versions:
58
+
59
+ ```bash
60
+ GRAPE_VERSION=2.0.0 bundle update grape
61
+ GRAPE_SWAGGER_VERSION=HEAD bundle update grape-swagger
62
+ GRAPE_ENTITY_VERSION=1.0.1 bundle update grape-entity
63
+ ```
@@ -20,7 +20,7 @@ module GrapeSwagger
20
20
  documentation = entity_options[:documentation]
21
21
  return param if documentation.nil?
22
22
 
23
- add_array_documentation(param, documentation) if documentation[:is_array]
23
+ add_array_documentation(param, documentation) if array_type?(documentation)
24
24
 
25
25
  add_attribute_sample(param, documentation, :default)
26
26
  add_attribute_sample(param, documentation, :example)
@@ -37,11 +37,26 @@ module GrapeSwagger
37
37
  def model_from(entity_options)
38
38
  model = entity_options[:using] if entity_options[:using].present?
39
39
 
40
- model ||= entity_options[:documentation][:type] if could_it_be_a_model?(entity_options[:documentation])
40
+ documentation = entity_options[:documentation]
41
+ model ||= documentation[:type] if could_it_be_a_model?(documentation)
41
42
 
42
43
  model
43
44
  end
44
45
 
46
+ # Checks if documentation indicates an array type that needs items wrapping.
47
+ # Returns true for:
48
+ # - is_array: true (explicit flag)
49
+ # - type: 'Array[Something]' (array with element type)
50
+ # Returns false for:
51
+ # - type: 'Array' (bare array - already an array type, no wrapping needed)
52
+ def array_type?(documentation)
53
+ return false if documentation.nil?
54
+ return documentation[:is_array] if documentation.key?(:is_array)
55
+
56
+ # Only match Array[ElementType] syntax, not bare 'Array'
57
+ documentation[:type].to_s.match?(/\Aarray\[.+\]\z/i)
58
+ end
59
+
45
60
  def could_it_be_a_model?(value)
46
61
  return false if value.nil?
47
62
 
@@ -57,6 +72,8 @@ module GrapeSwagger
57
72
  end
58
73
 
59
74
  def primitive_type?(type)
75
+ return false if type.nil?
76
+
60
77
  data_type = GrapeSwagger::DocMethods::DataType.call(type)
61
78
  GrapeSwagger::DocMethods::DataType.request_primitive?(data_type)
62
79
  end
@@ -69,7 +86,7 @@ module GrapeSwagger
69
86
 
70
87
  documented_data_type = document_data_type(documentation, data_type)
71
88
 
72
- if documentation[:is_array]
89
+ if array_type?(documentation)
73
90
  {
74
91
  type: :array,
75
92
  items: documented_data_type
@@ -97,7 +114,9 @@ module GrapeSwagger
97
114
  end
98
115
 
99
116
  def entity_model_type(name, entity_options)
100
- if entity_options[:documentation] && entity_options[:documentation][:is_array]
117
+ documentation = entity_options[:documentation]
118
+
119
+ if array_type?(documentation)
101
120
  {
102
121
  'type' => 'array',
103
122
  'items' => {
@@ -43,37 +43,72 @@ module GrapeSwagger
43
43
  def parse_grape_entity_params(params, parent_model = nil)
44
44
  return unless params
45
45
 
46
- parsed = params.each_with_object({}) do |(entity_name, entity_options), memo|
47
- documentation_options = entity_options.fetch(:documentation, {})
48
- in_option = documentation_options.fetch(:in, nil).to_s
49
- hidden_option = documentation_options.fetch(:hidden, nil)
50
- next if in_option == 'header' || hidden_option == true
51
-
52
- entity_name = entity_name.original if entity_name.is_a?(Alias)
53
- final_entity_name = entity_options.fetch(:as, entity_name)
54
- documentation = entity_options[:documentation]
55
-
56
- memo[final_entity_name] = if entity_options[:nesting]
57
- parse_nested(entity_name, entity_options, parent_model)
58
- else
59
- attribute_parser.call(entity_options)
60
- end
61
-
62
- next unless documentation
63
-
64
- memo[final_entity_name][:readOnly] = documentation[:read_only].to_s == 'true' if documentation[:read_only]
65
- memo[final_entity_name][:description] = documentation[:desc] if documentation[:desc]
46
+ required = required_params(params)
47
+ parsed_params = parse_params(params, parent_model)
48
+
49
+ handle_discriminator(parsed_params, required)
50
+ end
51
+
52
+ def parse_params(params, parent_model)
53
+ params.each_with_object({}) do |(entity_name, entity_options), memo|
54
+ next if skip_param?(entity_options)
55
+
56
+ original_entity_name = entity_name.is_a?(Alias) ? entity_name.original : entity_name
57
+ final_entity_name = entity_options.fetch(:as, original_entity_name)
58
+
59
+ memo[final_entity_name] = parse_entity_options(entity_options, original_entity_name, parent_model)
60
+ add_documentation_to_memo(memo[final_entity_name], entity_options[:documentation])
61
+ end
62
+ end
63
+
64
+ def skip_param?(entity_options)
65
+ documentation_options = entity_options.fetch(:documentation, {})
66
+ in_option = documentation_options.fetch(:in, nil).to_s
67
+ hidden_option = documentation_options.fetch(:hidden, nil)
68
+
69
+ in_option == 'header' || hidden_option == true
70
+ end
71
+
72
+ def parse_entity_options(entity_options, entity_name, parent_model)
73
+ if entity_options[:nesting]
74
+ parse_nested(entity_name, entity_options, parent_model)
75
+ else
76
+ attribute_parser.call(entity_options)
66
77
  end
78
+ end
79
+
80
+ def add_documentation_to_memo(memo_entry, documentation)
81
+ return unless documentation
82
+
83
+ has_read_only = documentation[:read_only]
84
+ has_description = documentation[:desc]
85
+
86
+ return unless has_read_only || has_description
87
+
88
+ # In OpenAPI/Swagger 2.0 and 3.0.x, $ref cannot have sibling properties - they are ignored.
89
+ # To add description or readOnly to a $ref, wrap it in allOf.
90
+ # See: https://swagger.io/docs/specification/using-ref/
91
+ wrap_ref_in_all_of(memo_entry) if memo_entry.key?('$ref')
67
92
 
93
+ memo_entry[:readOnly] = documentation[:read_only].to_s == 'true' if has_read_only
94
+ memo_entry[:description] = documentation[:desc] if has_description
95
+ end
96
+
97
+ def wrap_ref_in_all_of(memo_entry)
98
+ ref = memo_entry.delete('$ref')
99
+ memo_entry['allOf'] = [{ '$ref' => ref }]
100
+ end
101
+
102
+ def handle_discriminator(parsed, required)
68
103
  discriminator = GrapeSwagger::Entity::Helper.discriminator(model)
69
104
  if discriminator
70
- respond_with_all_of(parsed, params, discriminator)
105
+ respond_with_all_of(parsed, required, discriminator)
71
106
  else
72
- [parsed, required_params(params)]
107
+ [parsed, required]
73
108
  end
74
109
  end
75
110
 
76
- def respond_with_all_of(parsed, params, discriminator)
111
+ def respond_with_all_of(parsed, required, discriminator)
77
112
  parent_name = GrapeSwagger::Entity::Helper.model_name(model.superclass, endpoint)
78
113
 
79
114
  {
@@ -83,7 +118,7 @@ module GrapeSwagger
83
118
  },
84
119
  [
85
120
  add_discriminator(parsed, discriminator),
86
- required_params(params).push(discriminator.attribute)
121
+ required.push(discriminator.attribute)
87
122
  ]
88
123
  ]
89
124
  }
@@ -136,8 +171,11 @@ module GrapeSwagger
136
171
 
137
172
  def required_params(params)
138
173
  params.each_with_object(Set.new) do |(key, options), accum|
139
- required = if options.fetch(:documentation, {}).key?(:required)
140
- options.dig(:documentation, :required)
174
+ documentation = options.fetch(:documentation, {})
175
+ next if documentation[:hidden]
176
+
177
+ required = if documentation.key?(:required)
178
+ documentation[:required]
141
179
  else
142
180
  !options.key?(:if) && !options.key?(:unless) && options[:expose_nil] != false
143
181
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GrapeSwagger
4
4
  module Entity
5
- VERSION = '0.7.0'
5
+ VERSION = '0.7.1'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-swagger-entity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kirill Zaitsev
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-01-28 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: grape-entity
@@ -37,18 +38,21 @@ dependencies:
37
38
  - - "~>"
38
39
  - !ruby/object:Gem::Version
39
40
  version: '2'
41
+ description:
40
42
  email:
41
43
  - kirik910@gmail.com
42
44
  executables: []
43
45
  extensions: []
44
46
  extra_rdoc_files: []
45
47
  files:
48
+ - ".github/workflows/danger-comment.yml"
46
49
  - ".github/workflows/danger.yml"
47
50
  - ".github/workflows/test.yml"
48
51
  - ".gitignore"
49
52
  - ".rspec"
50
53
  - ".rubocop.yml"
51
54
  - ".rubocop_todo.yml"
55
+ - AGENTS.md
52
56
  - CHANGELOG.md
53
57
  - Dangerfile
54
58
  - Gemfile
@@ -59,6 +63,10 @@ files:
59
63
  - UPGRADING.md
60
64
  - bin/pry
61
65
  - bin/setup
66
+ - docs/architecture.md
67
+ - docs/contributing.md
68
+ - docs/documentation-options.md
69
+ - docs/testing.md
62
70
  - grape-swagger-entity.gemspec
63
71
  - lib/grape-swagger-entity.rb
64
72
  - lib/grape-swagger/entity.rb
@@ -71,6 +79,7 @@ licenses:
71
79
  - MIT
72
80
  metadata:
73
81
  rubygems_mfa_required: 'true'
82
+ post_install_message:
74
83
  rdoc_options: []
75
84
  require_paths:
76
85
  - lib
@@ -85,7 +94,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
94
  - !ruby/object:Gem::Version
86
95
  version: '0'
87
96
  requirements: []
88
- rubygems_version: 3.6.8
97
+ rubygems_version: 3.5.22
98
+ signing_key:
89
99
  specification_version: 4
90
100
  summary: Grape swagger adapter to support grape-entity object parsing
91
101
  test_files: []