Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']

steps:
- uses: actions/checkout@v4

- name: Set up Ruby ${{ matrix.ruby-version }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true

- name: Run tests
run: bundle exec rake spec

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true

- name: Run RuboCop
run: bundle exec rubocop
124 changes: 124 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
AllCops:
TargetRubyVersion: 3.0
NewCops: enable
SuggestExtensions: false
Exclude:
- 'spec/fixtures/**/*'
- 'vendor/**/*'
- 'tmp/**/*'

Style/Documentation:
Enabled: false

Style/FrozenStringLiteralComment:
Enabled: true
EnforcedStyle: always
Exclude:
- 'spec/**/*'
- 'Rakefile'
- 'Gemfile'
- 'bin/*'

Metrics/MethodLength:
Max: 400
Exclude:
- 'spec/**/*'
- 'lib/open_api_import/open_api_import.rb'

Metrics/AbcSize:
Max: 500
Exclude:
- 'spec/**/*'
- 'lib/open_api_import/open_api_import.rb'

Metrics/CyclomaticComplexity:
Max: 80
Exclude:
- 'lib/open_api_import/open_api_import.rb'

Metrics/PerceivedComplexity:
Max: 80
Exclude:
- 'lib/open_api_import/open_api_import.rb'

Metrics/BlockLength:
Exclude:
- 'spec/**/*'
- 'Rakefile'
- 'bin/open_api_import'
- 'lib/open_api_import/open_api_import.rb'
- 'lib/open_api_import/get_examples.rb'

Metrics/ClassLength:
Max: 800

Layout/LineLength:
Max: 200

Style/StringLiterals:
EnforcedStyle: double_quotes

Style/StringLiteralsInInterpolation:
EnforcedStyle: double_quotes

Naming/MethodName:
Enabled: false

Naming/MethodParameterName:
Enabled: false

Style/GuardClause:
Enabled: false

Style/Next:
Enabled: false

Style/IfUnlessModifier:
Enabled: false

Style/ConditionalAssignment:
Enabled: false

Style/NegatedIf:
Enabled: false

Style/CaseLikeIf:
Enabled: false

Style/SymbolArray:
Enabled: false

Lint/SuppressedException:
Enabled: false

Style/RescueStandardError:
Enabled: false

Style/OptionalBooleanParameter:
Enabled: false

Metrics/BlockNesting:
Enabled: false

Metrics/ParameterLists:
Enabled: false

Lint/DuplicateBranch:
Enabled: false

Lint/UnreachableLoop:
Enabled: false

Lint/EmptyFile:
Exclude:
- 'spec/open_api_import/utils/open_api_import_utils_spec.rb'

Gemspec/DevelopmentDependencies:
Enabled: false

Gemspec/RequiredRubyVersion:
Enabled: false

Security/Eval:
Exclude:
- 'spec/**/*'
48 changes: 48 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.12.0] - 2026-03-17

### Added
- OpenAPI 3.1 support: handles nullable type arrays (`type: ["string", "null"]`) and `examples` keyword (plural)
- `OpenApiImport::ParseError` exception class for parse failures (instead of `exit!`)
- `OpenApiImport::VERSION` constant
- `return_data` option to get generated code as a Hash without writing files
- `--version` / `-v` CLI flag
- `--dry_run` / `-d` CLI flag to preview output without writing files
- GitHub Actions CI workflow (`.github/workflows/ci.yml`) testing Ruby 3.0-3.4
- RuboCop configuration (`.rubocop.yml`)
- Unit tests for all helper modules (`get_examples`, `get_patterns`, `filter`, `get_required_data`, `pretty_hash_symbolized`, `get_data_all_of_bodies`)
- Feature tests for `mock_response`, `silent`, error handling, `return_data`, and OAS 3.1
- `after(:suite)` cleanup in spec_helper to remove generated test artifacts
- `CHANGELOG.md`

### Changed
- **BREAKING**: `exit!` on parse failure replaced with `raise OpenApiImport::ParseError` -- callers should rescue this
- **BREAKING**: Minimum Ruby version raised from 2.7 to 3.0
- `rescue Exception` replaced with `rescue StandardError` throughout (no longer swallows Ctrl-C/OOM)
- `eval()` calls removed -- replaced with safe hash construction and `load` for file validation
- `String` monkey-patching (`snake_case`/`camel_case`) replaced with Ruby refinements (`OpenApiImportStringExt`)
- `include LibOpenApiImport` moved from top-level (global namespace) into `OpenApiImport` class via `extend`
- Shell commands (`rufo`, `ruby -c`) now use `Shellwords.shellescape` for path safety
- `activesupport` constraint relaxed from `~> 6.1` to `>= 6.1, < 8.0` (supports Rails 7)
- `rufo` constraint relaxed from `~> 0.16.1` to `~> 0.16`
- Input data mutations reduced (non-destructive `gsub` instead of `gsub!`, local variables instead of modifying input hashes)
- Repeated `rufo` formatting + syntax check code extracted into `format_and_check_file` helper method
- `kind_of?` standardized to `is_a?`, `.keys.include?` to `.key?`
- Ruby version comparison uses `Gem::Version` instead of string comparison
- Output messages now display relative paths (as provided by the user) instead of expanded absolute paths

### Fixed
- Bug in `get_examples.rb`: `val.include?("'")` was checking hash keys instead of string content
- Array modification during iteration in `get_required_data.rb` (now collects and concatenates after)
- `filter.rb`: nil guard added for nested key access (`result[key] ||= {}`)
- `get_patterns`: simple-type array items (e.g., `{type: "string"}`) now correctly produce `[:'string']` patterns without relying on mutation side-effects from `get_examples`
- `build_example_value`: array types now recurse into items schema instead of returning empty `[]`, restoring type-hinted examples like `["string"]` and `[{...}]`

### Deprecated
- Travis CI configuration (`.travis.yml`) -- superseded by GitHub Actions
10 changes: 5 additions & 5 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
source 'https://rubygems.org'
source "https://rubygems.org"

group :test do
gem 'rake'
gem 'rspec'
gem 'coveralls_reborn', '~> 0.27.0', require: false
gem "coveralls_reborn", "~> 0.27.0", require: false
gem "rake"
gem "rspec"
end

# Specify your gem's dependencies in mygem.gemspec
gemspec
gemspec
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# OpenApiImport

[![Gem Version](https://badge.fury.io/rb/open_api_import.svg)](https://rubygems.org/gems/open_api_import)
[![Build Status](https://travis-ci.com/MarioRuiz/open_api_import.svg?branch=master)](https://github.com/MarioRuiz/open_api_import)
[![CI](https://github.com/MarioRuiz/open_api_import/actions/workflows/ci.yml/badge.svg)](https://github.com/MarioRuiz/open_api_import/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/MarioRuiz/open_api_import/badge.svg?branch=master)](https://coveralls.io/github/MarioRuiz/open_api_import?branch=master)

Import a Swagger or Open API file and create a Ruby Request Hash file including all requests and responses with all the examples. The file can be in JSON or YAML.
Import a Swagger or Open API file (including Open API 3.1) and create a Ruby Request Hash file including all requests and responses with all the examples. The file can be in JSON or YAML.

The Request Hash will include also the pattern (regular expressions) of the fields, parameters, default values...

Expand Down Expand Up @@ -68,6 +68,10 @@ This is the output of the previous run:
- Helper: ./spec/helper.rb
```

## Requirements

- Ruby >= 3.0

## Installation

Install it yourself as:
Expand Down Expand Up @@ -102,6 +106,7 @@ More info: https://github.com/MarioRuiz/open_api_import
In case no options supplied:
* It will be used the value of operation_id on snake_case for the name of the methods
* It will be used the first folder of the path to create the module name
-v, --version Display the version
-n, --no_responses if you don't want to add the examples of responses in the resultant file.
-m, --mock Add the first response on the request as mock_response
-p, --path_method it will be used the path and http method to create the method names
Expand All @@ -111,6 +116,7 @@ In case no options supplied:
-F, --fixed_module all the requests will be under the module Requests
-s, --silent It will display only errors
-c, --create_constants For required arguments, it will create keyword arguments assigning by default a constant.
-d, --dry_run Preview the generated output without writing files
```


Expand Down Expand Up @@ -490,6 +496,23 @@ It will include this on the output file:
...
```

### return_data

Instead of writing files to disk, return a Hash of `{filename => content}`. This is useful for previewing the output or programmatically processing the generated code.

Accepts true or false, by default is false.

```ruby
require 'open_api_import'

result = OpenApiImport.from "./spec/fixtures/v2.0/yaml/petstore-simple.yaml", return_data: true

result.each do |filepath, content|
puts "--- #{filepath} ---"
puts content
end
```

### create_constants

The methods will be generated using keyword arguments and for required arguments, it will create keyword arguments assigning by default a constant.
Expand Down
13 changes: 12 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@ RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = Dir.glob("spec/**/*_spec.rb")
t.rspec_opts = "--format documentation"
end
task default: :spec

begin
require "rubocop/rake_task"
RuboCop::RakeTask.new(:rubocop)
rescue LoadError
desc "RuboCop not available"
task :rubocop do
puts "RuboCop is not installed. Run: gem install rubocop"
end
end

task default: [:spec]
36 changes: 25 additions & 11 deletions bin/open_api_import
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
#!/usr/bin/env ruby
require 'optparse'
require 'open_api_import'
require "optparse"
require "open_api_import"

options = {
name_for_module: :path
}

optparse = OptionParser.new do |opts|
opts.banner = "Usage: open_api_import [open_api_file] [options]\n"
opts.banner+= "Import a Swagger or Open API file and create a Ruby Request Hash file including all requests and responses.\n"
opts.banner+= "More info: https://github.com/MarioRuiz/open_api_import\n\n"
opts.banner+= "In case no options supplied: \n"
opts.banner+= " * It will be used the value of operation_id on snake_case for the name of the methods\n"
opts.banner+= " * It will be used the first folder of the path to create the module name\n"

opts.banner += "Import a Swagger or Open API file and create a Ruby Request Hash file including all requests and responses.\n"
opts.banner += "More info: https://github.com/MarioRuiz/open_api_import\n\n"
opts.banner += "In case no options supplied: \n"
opts.banner += " * It will be used the value of operation_id on snake_case for the name of the methods\n"
opts.banner += " * It will be used the first folder of the path to create the module name\n"

opts.on("-v", "--version", "Display the version") do
puts "open_api_import #{OpenApiImport::VERSION}"
exit
end

opts.on("-n", "--no_responses", "if you don't want to add the examples of responses in the resultant file.") do
options[:include_responses] = false
end
Expand Down Expand Up @@ -50,7 +55,9 @@ optparse = OptionParser.new do |opts|
options[:create_constants] = true
end


opts.on("-d", "--dry_run", "Preview the generated output without writing files") do
options[:return_data] = true
end
end

optparse.parse!
Expand All @@ -65,9 +72,16 @@ if options.key?(:create_files)
end

filename = ARGV.pop
if filename.to_s==''
if filename.to_s == ""
puts optparse
puts "** Need to specify at least a file to import."
else
OpenApiImport.from filename, **options
result = OpenApiImport.from filename, **options
if options[:return_data] && result.is_a?(Hash)
result.each do |filepath, content|
puts "--- #{filepath} ---"
puts content
puts
end
end
end
6 changes: 3 additions & 3 deletions lib/open_api_import.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require_relative "open_api_import/utils"
require_relative "open_api_import/filter"
require_relative "open_api_import/pretty_hash_symbolized"
Expand All @@ -8,10 +10,8 @@
require_relative "open_api_import/get_examples"
require_relative "open_api_import/open_api_import"

include LibOpenApiImport

require "oas_parser_reborn"
require "rufo"
require "nice_hash"
require "logger"

require "shellwords"
Loading
Loading