From 87a807eb23aeafaa77b0d91c9d3149f32692e522 Mon Sep 17 00:00:00 2001 From: Andrey Subbota Date: Wed, 28 Jan 2026 19:14:03 +0100 Subject: [PATCH 1/5] Improve README with comprehensive documentation - Explain what the gem does and add example output - Add Related Projects section linking to grape ecosystem - Add Compatibility section with version table - Add usage examples for basic entities, custom descriptions, and references - Document all available documentation options - Expand table of contents with subsections - Add reference to CONTRIBUTING.md Fixes #58 --- README.md | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 115 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3d8db85..53c8956 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,62 @@ ## Table of Contents - [What is grape-swagger-entity?](#what-is-grape-swagger-entity) +- [Related Projects](#related-projects) +- [Compatibility](#compatibility) - [Installation](#installation) +- [Usage](#usage) + - [Basic Entity](#basic-entity) + - [Custom Model Description](#custom-model-description) + - [Entity References](#entity-references) + - [Documentation Options](#documentation-options) - [Development](#development) - [Contributing](#contributing) - [License](#license) - ## What is grape-swagger-entity? -A simple grape-swagger adapter to allow parse representers as response model +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. + +### What it does + +- Generates `definitions` in your Swagger JSON from Grape::Entity exposures +- Maps entity properties to OpenAPI schema properties with types and descriptions +- Handles nested entities and entity references via `$ref` +- Supports arrays, required fields, and documentation options + +### Example Output + +```json +{ + "definitions": { + "User": { + "type": "object", + "description": "User model", + "properties": { + "id": { "type": "integer", "description": "User ID" }, + "name": { "type": "string", "description": "Full name" } + }, + "required": ["id", "name"] + } + } +} +``` + +## Related Projects + +- [Grape](https://github.com/ruby-grape/grape) +- [Grape Entity](https://github.com/ruby-grape/grape-entity) +- [Grape Swagger](https://github.com/ruby-grape/grape-swagger) +- [Grape Swagger Representable](https://github.com/ruby-grape/grape-swagger-representable) + +## Compatibility + +This gem is tested with the following versions: + +| grape-swagger-entity | grape-swagger | grape-entity | grape | +|---------------------|---------------|--------------|---------| +| 0.7.x | >= 1.2.0 | >= 0.6.0 | >= 1.3 | +| 0.6.x | >= 1.2.0 | >= 0.6.0 | >= 1.3 | ## Installation @@ -32,17 +79,81 @@ Or install it yourself as: $ gem install grape-swagger-entity +## Usage + +### Basic Entity + +Define your entities with `documentation` options to generate OpenAPI schema properties: + +```ruby +class UserEntity < Grape::Entity + expose :id, documentation: { type: Integer, desc: 'User ID' } + expose :name, documentation: { type: String, desc: 'Full name' } + expose :email, documentation: { type: String, desc: 'Email address' } +end +``` + +### Custom Model Description + +Override the default "{ModelName} model" description by defining a `self.documentation` method (requires grape-swagger >= 2.2.0): + +```ruby +class UserEntity < Grape::Entity + def self.documentation + { desc: 'Represents a user account with profile information' } + end + + expose :id, documentation: { type: Integer, desc: 'User ID' } + expose :name, documentation: { type: String, desc: 'Full name' } +end +``` + +### Entity References + +Use `using:` to reference other entities and `is_array:` for collections: + +```ruby +class OrderEntity < Grape::Entity + expose :id, documentation: { type: Integer, desc: 'Order ID' } + expose :user, using: UserEntity, + documentation: { desc: 'The customer who placed this order' } + expose :items, using: ItemEntity, + documentation: { desc: 'Line items', is_array: true } +end +``` + +### Documentation Options + +The following options are available in the `documentation` hash: + +| Option | Description | +|--------|-------------| +| `type` | OpenAPI data type (`String`, `Integer`, `Boolean`, etc.) | +| `desc` | Property description | +| `required` | Whether field is required (default: based on expose options) | +| `is_array` | Marks field as array type | +| `read_only` | Marks field as read-only | +| `values` | Enum values for the field | +| `example` | Example value | +| `default` | Default value | +| `minimum` | Minimum value for numeric types | +| `maximum` | Maximum value for numeric types | +| `min_length` | Minimum length for string types | +| `max_length` | Maximum length for string types | +| `hidden` | Hide field from documentation | + ## Development 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. -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). +To install this gem onto your local machine, run `bundle exec rake install`. ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/ruby-grape/grape-swagger-entity. +See [CONTRIBUTING](CONTRIBUTING.md) for more information. + ## License The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). - From 28eb8cebf3777c549121ef29ffcf1694812e24d1 Mon Sep 17 00:00:00 2001 From: Andrey Subbota Date: Wed, 28 Jan 2026 19:28:33 +0100 Subject: [PATCH 2/5] Add AGENTS.md with progressive disclosure documentation - Minimal root AGENTS.md with essential commands and constraints - docs/testing.md: Test patterns, shared contexts, issue regression specs - docs/contributing.md: PR requirements, CHANGELOG format, danger checks - docs/architecture.md: Component overview and data flow --- AGENTS.md | 24 +++++++++++++++ docs/architecture.md | 71 ++++++++++++++++++++++++++++++++++++++++++++ docs/contributing.md | 57 +++++++++++++++++++++++++++++++++++ docs/testing.md | 63 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 AGENTS.md create mode 100644 docs/architecture.md create mode 100644 docs/contributing.md create mode 100644 docs/testing.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..dc4a011 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,24 @@ +# grape-swagger-entity + +Adapter for grape-swagger that parses Grape::Entity classes into OpenAPI schema definitions. + +## Quick Reference + +```bash +bundle install # Install dependencies +bundle exec rspec # Run tests +bundle exec rubocop # Run linter +bundle exec rubocop -a # Auto-fix linter issues +``` + +## Key Constraints + +- Ruby >= 3.0 +- All files must start with `# frozen_string_literal: true` +- CHANGELOG.md entry required for every PR (danger enforces this) + +## Documentation + +- [Testing Patterns](docs/testing.md) +- [Contributing Guidelines](docs/contributing.md) +- [Architecture Overview](docs/architecture.md) diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..23f3e99 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,71 @@ +# Architecture Overview + +## Purpose + +This gem registers a model parser with grape-swagger that converts `Grape::Entity` classes into OpenAPI schema definitions. + +## Core Components + +``` +lib/grape-swagger/entity/ +├── parser.rb # Main parser - converts Entity to OpenAPI schema +├── attribute_parser.rb # Parses individual exposure attributes +├── helper.rb # Utility methods for model naming, discriminators +└── version.rb # Gem version +``` + +### Parser (`parser.rb`) + +Entry point for entity parsing. Responsibilities: +- Extract exposures from Grape::Entity +- Handle nested entities and `using:` references +- Process `merge: true` exposures +- Handle inheritance with `allOf` and discriminators +- Determine required fields + +### AttributeParser (`attribute_parser.rb`) + +Converts individual exposure options to OpenAPI property schema: +- Maps Ruby types to OpenAPI types +- Handles arrays (`is_array: true`) +- Processes enums (`values:`) +- Adds constraints (min/max, minLength/maxLength) + +### Helper (`helper.rb`) + +Utilities for: +- Model name resolution (strips Entity/Entities suffix) +- Discriminator detection for inheritance +- Root exposure extraction + +## Data Flow + +``` +Grape::Entity class + │ + ▼ + Parser.call + │ + ├── extract_params (get exposures) + │ + ├── parse_grape_entity_params + │ │ + │ ├── AttributeParser (per exposure) + │ │ + │ └── parse_nested (for nested blocks) + │ + └── handle_discriminator (inheritance) + │ + ▼ +[properties_hash, required_array] +``` + +## Integration Point + +Registered with grape-swagger in `lib/grape-swagger-entity.rb`: + +```ruby +GrapeSwagger.model_parsers.register(GrapeSwagger::Entity::Parser, Grape::Entity) +``` + +grape-swagger calls `Parser.new(model, endpoint).call` when it encounters a `Grape::Entity` subclass. diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..e9f337f --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,57 @@ +# Contributing Guidelines + +## PR Requirements + +Every PR must include: + +1. **CHANGELOG.md entry** - Add under `### X.X.X (Next)` in the appropriate section: + ```markdown + #### Fixes + * [#123](https://github.com/ruby-grape/grape-swagger-entity/pull/123): Brief description - [@username](https://github.com/username). + ``` + +2. **Passing CI** - RuboCop + RSpec must pass + +3. **Tests** - New functionality needs specs; bug fixes need regression tests + +## CHANGELOG Format + +```markdown +### 0.7.1 (Next) + +#### Features + +* Your contribution here. + +#### Fixes + +* [#PR](URL): Description - [@author](URL). +``` + +- Use `Features` for new functionality +- Use `Fixes` for bug fixes and maintenance + +## Commit Messages + +Follow conventional style: +- `Fix #123: description` for bug fixes +- `Add feature description` for features +- `Update dependency/docs` for maintenance + +## Code Style + +RuboCop enforces style. Key rules: +- `frozen_string_literal: true` pragma required +- Consistent hash indentation +- No trailing whitespace + +```bash +bundle exec rubocop -a # Auto-fix most issues +``` + +## Danger Checks + +CI runs danger which enforces: +- CHANGELOG entry present +- Table of Contents in README is current +- PR has description diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..6ceba20 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,63 @@ +# Testing Patterns + +## Running Tests + +```bash +bundle exec rspec # Run all tests +bundle exec rspec spec/path/file.rb # Run specific file +bundle exec rspec -e "description" # Run matching examples +``` + +## Test Structure + +``` +spec/ +├── grape-swagger/ +│ ├── entity_spec.rb # Main module specs +│ ├── entity/ +│ │ ├── parser_spec.rb # Parser unit tests +│ │ └── attribute_parser_spec.rb +│ └── entities/ +│ └── response_model_spec.rb # Integration tests +├── issues/ # Regression tests for GitHub issues +│ └── 962_polymorphic_entity_... # Named by issue number +└── support/ + └── shared_contexts/ # Reusable test setup +``` + +## Shared Contexts + +Use shared contexts for common API setups: + +```ruby +require 'spec_helper' +require_relative '../../support/shared_contexts/this_api' + +describe SomeClass do + include_context 'this api' + # ... +end +``` + +## Issue Regression Tests + +When fixing a bug, create a spec in `spec/issues/` named `{issue_number}_{brief_description}_spec.rb`: + +```ruby +# spec/issues/123_some_bug_spec.rb +require 'spec_helper' + +describe '#123 brief description of the issue' do + # Test that reproduces and verifies the fix +end +``` + +## Testing with Different Gem Versions + +Environment variables control dependency versions: + +```bash +GRAPE_VERSION=2.0.0 bundle update grape +GRAPE_SWAGGER_VERSION=HEAD bundle update grape-swagger +GRAPE_ENTITY_VERSION=1.0.1 bundle update grape-entity +``` From 6101b796bb5bd242b2075284a3673fdee9152545 Mon Sep 17 00:00:00 2001 From: Andrey Subbota Date: Wed, 28 Jan 2026 19:31:05 +0100 Subject: [PATCH 3/5] Move detailed documentation from README to docs/ - Move Documentation Options table to docs/documentation-options.md - Simplify Development and Contributing sections to reference docs/ - Keep README focused on quick start examples --- README.md | 32 ++----------- docs/documentation-options.md | 86 +++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 docs/documentation-options.md diff --git a/README.md b/README.md index 53c8956..7c40df3 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,6 @@ - [Compatibility](#compatibility) - [Installation](#installation) - [Usage](#usage) - - [Basic Entity](#basic-entity) - - [Custom Model Description](#custom-model-description) - - [Entity References](#entity-references) - - [Documentation Options](#documentation-options) - [Development](#development) - [Contributing](#contributing) - [License](#license) @@ -124,35 +120,17 @@ end ### Documentation Options -The following options are available in the `documentation` hash: - -| Option | Description | -|--------|-------------| -| `type` | OpenAPI data type (`String`, `Integer`, `Boolean`, etc.) | -| `desc` | Property description | -| `required` | Whether field is required (default: based on expose options) | -| `is_array` | Marks field as array type | -| `read_only` | Marks field as read-only | -| `values` | Enum values for the field | -| `example` | Example value | -| `default` | Default value | -| `minimum` | Minimum value for numeric types | -| `maximum` | Maximum value for numeric types | -| `min_length` | Minimum length for string types | -| `max_length` | Maximum length for string types | -| `hidden` | Hide field from documentation | +Common options: `type`, `desc`, `required`, `is_array`, `values`, `example`. -## Development +See [full documentation options](docs/documentation-options.md) for all available options including validation constraints. -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. +## Development -To install this gem onto your local machine, run `bundle exec rake install`. +See [testing documentation](docs/testing.md) for development setup and running tests. ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/ruby-grape/grape-swagger-entity. - -See [CONTRIBUTING](CONTRIBUTING.md) for more information. +See [contributing guidelines](docs/contributing.md). ## License diff --git a/docs/documentation-options.md b/docs/documentation-options.md new file mode 100644 index 0000000..e59d16e --- /dev/null +++ b/docs/documentation-options.md @@ -0,0 +1,86 @@ +# Documentation Options + +The `documentation` hash in entity exposures supports the following options: + +## Type Options + +| Option | Description | Example | +|--------|-------------|---------| +| `type` | OpenAPI data type | `String`, `Integer`, `Boolean`, `Float`, `Date`, `DateTime` | +| `is_array` | Marks field as array type | `true` / `false` | + +## Description Options + +| Option | Description | Example | +|--------|-------------|---------| +| `desc` | Property description | `'User email address'` | +| `example` | Example value for documentation | `'user@example.com'` | +| `default` | Default value | `'pending'` | + +## Validation Options + +| Option | Description | Example | +|--------|-------------|---------| +| `required` | Whether field is required | `true` / `false` | +| `values` | Enum values (array or proc) | `%w[pending active]` or `-> { Status.all }` | +| `minimum` | Minimum value for numeric types | `0` | +| `maximum` | Maximum value for numeric types | `100` | +| `min_length` | Minimum length for strings | `1` | +| `max_length` | Maximum length for strings | `255` | + +## Display Options + +| Option | Description | Example | +|--------|-------------|---------| +| `read_only` | Marks field as read-only | `true` | +| `hidden` | Hide field from documentation | `true` | + +## Examples + +### Basic types + +```ruby +expose :id, documentation: { type: Integer, desc: 'Unique identifier' } +expose :name, documentation: { type: String, desc: 'Full name', required: true } +expose :active, documentation: { type: Boolean, default: true } +``` + +### Enums + +```ruby +expose :status, documentation: { + type: String, + desc: 'Current status', + values: %w[pending active suspended] +} +``` + +### Numeric constraints + +```ruby +expose :age, documentation: { + type: Integer, + minimum: 0, + maximum: 150 +} +``` + +### String constraints + +```ruby +expose :username, documentation: { + type: String, + min_length: 3, + max_length: 20 +} +``` + +### Arrays + +```ruby +expose :tags, documentation: { + type: String, + is_array: true, + desc: 'Associated tags' +} +``` From 777460e830e3734eec875839a202ad2f22092dc2 Mon Sep 17 00:00:00 2001 From: Andrey Subbota Date: Wed, 28 Jan 2026 19:35:46 +0100 Subject: [PATCH 4/5] Fix TOC and add CHANGELOG entry for #91 --- CHANGELOG.md | 1 + README.md | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f93dfe2..002bfc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ #### Features * Your contribution here. +* [#91](https://github.com/ruby-grape/grape-swagger-entity/pull/91): Improve README and add documentation structure - [@numbata](https://github.com/numbata). #### Fixes diff --git a/README.md b/README.md index 7c40df3..905b82b 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,16 @@ ## Table of Contents - [What is grape-swagger-entity?](#what-is-grape-swagger-entity) + - [What it does](#what-it-does) + - [Example Output](#example-output) - [Related Projects](#related-projects) - [Compatibility](#compatibility) - [Installation](#installation) - [Usage](#usage) + - [Basic Entity](#basic-entity) + - [Custom Model Description](#custom-model-description) + - [Entity References](#entity-references) + - [Documentation Options](#documentation-options) - [Development](#development) - [Contributing](#contributing) - [License](#license) From abdd29468fa468a2a8a7494f619a78ce2bc15f82 Mon Sep 17 00:00:00 2001 From: Andrey Subbota Date: Wed, 28 Jan 2026 19:56:09 +0100 Subject: [PATCH 5/5] Address review comments - Fix compatibility table versions (grape-swagger >= 2.0.0, grape-entity >= 1.0.0 for 0.7.x) - Fix file path in architecture.md (lib/grape-swagger/entity.rb) - Add missing array options (min_items, max_items, unique_items) - Clarify Custom Model Description is a grape-swagger feature --- README.md | 4 ++-- docs/architecture.md | 2 +- docs/documentation-options.md | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 905b82b..74790bc 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ This gem is tested with the following versions: | grape-swagger-entity | grape-swagger | grape-entity | grape | |---------------------|---------------|--------------|---------| -| 0.7.x | >= 1.2.0 | >= 0.6.0 | >= 1.3 | +| 0.7.x | >= 2.0.0 | >= 1.0.0 | >= 1.3 | | 0.6.x | >= 1.2.0 | >= 0.6.0 | >= 1.3 | ## Installation @@ -97,7 +97,7 @@ end ### Custom Model Description -Override the default "{ModelName} model" description by defining a `self.documentation` method (requires grape-swagger >= 2.2.0): +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): ```ruby class UserEntity < Grape::Entity diff --git a/docs/architecture.md b/docs/architecture.md index 23f3e99..0ba014c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -62,7 +62,7 @@ Grape::Entity class ## Integration Point -Registered with grape-swagger in `lib/grape-swagger-entity.rb`: +Registered with grape-swagger in `lib/grape-swagger/entity.rb`: ```ruby GrapeSwagger.model_parsers.register(GrapeSwagger::Entity::Parser, Grape::Entity) diff --git a/docs/documentation-options.md b/docs/documentation-options.md index e59d16e..85e2a87 100644 --- a/docs/documentation-options.md +++ b/docs/documentation-options.md @@ -27,6 +27,9 @@ The `documentation` hash in entity exposures supports the following options: | `maximum` | Maximum value for numeric types | `100` | | `min_length` | Minimum length for strings | `1` | | `max_length` | Maximum length for strings | `255` | +| `min_items` | Minimum items for arrays | `1` | +| `max_items` | Maximum items for arrays | `10` | +| `unique_items` | Array items must be unique | `true` | ## Display Options