oas_hanami 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a54ec2dcc566a43373e6345ad0dc9d5f6ce21decbb6ac136fadf3327241bf59e
4
+ data.tar.gz: ecec0f8eb9cc753bb89d6f9e47c05e90960a1273c983a2cec114057530f4cd0d
5
+ SHA512:
6
+ metadata.gz: e16468c06d74fba996631455a353d9ada8da46b61b17aa0892ad6d58ce7a8b32f635020fd11dde6090c05cc726cec2269c2e4d4f41cf130746fe16dcf67a4f48
7
+ data.tar.gz: f7846391ca5a5cb186083ee9cc62eb57556fd00c36287047aff424160aff588a5e963b5a2c62b5d8549b9494bdb0ab1b102d6ae257d689e03cbb32080b936996
@@ -0,0 +1,64 @@
1
+ {
2
+ "release-type": "ruby",
3
+ "changelog-sections": [
4
+ {
5
+ "type": "feat",
6
+ "section": "Features"
7
+ },
8
+ {
9
+ "type": "feature",
10
+ "section": "Features"
11
+ },
12
+ {
13
+ "type": "fix",
14
+ "section": "Bug Fixes"
15
+ },
16
+ {
17
+ "type": "perf",
18
+ "section": "Performance Improvements"
19
+ },
20
+ {
21
+ "type": "revert",
22
+ "section": "Reverts"
23
+ },
24
+ {
25
+ "type": "docs",
26
+ "section": "Documentation"
27
+ },
28
+ {
29
+ "type": "style",
30
+ "section": "Styles",
31
+ "hidden": true
32
+ },
33
+ {
34
+ "type": "chore",
35
+ "section": "Miscellaneous Chores",
36
+ "hidden": true
37
+ },
38
+ {
39
+ "type": "refactor",
40
+ "section": "Code Refactoring"
41
+ },
42
+ {
43
+ "type": "test",
44
+ "section": "Tests"
45
+ },
46
+ {
47
+ "type": "build",
48
+ "section": "Build System",
49
+ "hidden": true
50
+ },
51
+ {
52
+ "type": "ci",
53
+ "section": "Continuous Integration",
54
+ "hidden": true
55
+ }
56
+ ],
57
+ "packages": {
58
+ ".": {
59
+ "release-type": "ruby",
60
+ "package-name": "oas_hanami",
61
+ "version-file": "lib/oas_hanami/version.rb"
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.0"
3
+ }
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
4
+
data/.rspec_status ADDED
@@ -0,0 +1,11 @@
1
+ example_id | status | run_time |
2
+ -------------------------------------------------------------------- | ------ | --------------- |
3
+ ./spec/bookshelf/spec/requests/books/create_spec.rb[1:1:1] | failed | 0.00294 seconds |
4
+ ./spec/bookshelf/spec/requests/books/create_spec.rb[1:2:1] | failed | 0.00016 seconds |
5
+ ./spec/bookshelf/spec/requests/books/index/pagination_spec.rb[1:1:1] | failed | 0.00012 seconds |
6
+ ./spec/bookshelf/spec/requests/books/index/pagination_spec.rb[1:2:1] | failed | 0.00008 seconds |
7
+ ./spec/bookshelf/spec/requests/books/index_spec.rb[1:1] | failed | 0.00008 seconds |
8
+ ./spec/bookshelf/spec/requests/books/show_spec.rb[1:1:1] | failed | 0.00008 seconds |
9
+ ./spec/bookshelf/spec/requests/books/show_spec.rb[1:2:1] | failed | 0.00007 seconds |
10
+ ./spec/bookshelf/spec/requests/root_spec.rb[1:1] | failed | 0.00008 seconds |
11
+ ./spec/oas_hanami_spec.rb[1:1] | passed | 0.00408 seconds |
data/.rubocop.yml ADDED
@@ -0,0 +1,15 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 3.1
5
+ NewCops: disable
6
+ SuggestExtensions: false
7
+
8
+ Style/StringLiterals:
9
+ EnforcedStyle: double_quotes
10
+
11
+ Style/StringLiteralsInInterpolation:
12
+ EnforcedStyle: double_quotes
13
+
14
+ Style/Documentation:
15
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,20 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2025-06-15 19:33:58 UTC using RuboCop version 1.76.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
11
+ # AllowedMethods: refine
12
+ Metrics/BlockLength:
13
+ Max: 31
14
+
15
+ # Offense count: 2
16
+ # This cop supports safe autocorrection (--autocorrect).
17
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
18
+ # URISchemes: http, https
19
+ Layout/LineLength:
20
+ Max: 235
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.4
data/.ruby.version ADDED
@@ -0,0 +1 @@
1
+ 3.4.4
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0](https://github.com/a-chacon/oas_hanami/compare/oas_hanami-v0.0.1...oas_hanami/v0.1.0) (2025-06-15)
4
+
5
+
6
+ ### Features
7
+
8
+ * initial release ([a622d09](https://github.com/a-chacon/oas_hanami/commit/a622d09d96243406eac3887e38c145fb0e962ac2))
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ ![Gem Version](https://img.shields.io/gem/v/oas_hanami?color=E9573F)
2
+ ![GitHub License](https://img.shields.io/github/license/a-chacon/oas_hanami?color=blue)
3
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/a-chacon/oas_hanami/.github%2Fworkflows%2Fruby.yml)
4
+ ![Gem Total Downloads](https://img.shields.io/gem/dt/oas_hanami)
5
+ ![Static Badge](https://img.shields.io/badge/Hanami-%3E%3D2.0.0-%23E9573F)
6
+ ![Static Badge](https://img.shields.io/badge/Ruby-%3E%3D3.1.0-%23E9573F)
7
+
8
+ # 📃Open API Specification For Hanami
9
+
10
+ OasHanami is a tool for generating **automatic interactive documentation for your Hanami APIs**. It generates an **OAS 3.1** document and displays it using **[RapiDoc](https://rapidocweb.com)**.
11
+
12
+ Built for the modern [Hanami](https://hanamirb.org) framework, OasHanami leverages Hanami's lightweight and modular design, making it ideal for building scalable Ruby applications. It relies on the [OasCore](https://github.com/a-chacon/oas_core) gem for seamless OpenAPI integration.
13
+
14
+ ![Screenshot](https://a-chacon.com/assets/images/oas_hanami_ui.png)
15
+
16
+ ## Documentation
17
+
18
+ For details on how to install, configure, and use OasHanami, please refer to the [OasCore MDBook](http://a-chacon.com/oas_core).
19
+
20
+ ## Contributing
21
+
22
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star⭐! Thanks again!
23
+
24
+ If you plan a big feature, first open an issue to discuss it before any development.
25
+
26
+ 1. Fork the Project
27
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
28
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
29
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
30
+ 5. Open a Pull Request
31
+
32
+ ## License
33
+
34
+ The gem is available as open source under the terms of the [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.en.html#license-text).
35
+
36
+ ## Star History
37
+
38
+ [![Star History Chart](https://api.star-history.com/svg?repos=[USERNAME]/oas_hanami&type=Date)](https://www.star-history.com/#[USERNAME]/oas_hanami&Date)
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ RuboCop::RakeTask.new
10
+
11
+ task default: %i[spec rubocop]
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OasHanami
4
+ class Configuration < OasCore::Configuration
5
+ attr_accessor :rapidoc_theme
6
+ attr_reader :include_mode
7
+
8
+ def initialize
9
+ super(info: generate_info_object)
10
+
11
+ @include_mode = :all
12
+ @rapidoc_theme = :hanami
13
+ end
14
+
15
+ def include_mode=(value)
16
+ valid_modes = %i[all with_tags explicit]
17
+ raise ArgumentError, "include_mode must be one of #{valid_modes}" unless valid_modes.include?(value)
18
+
19
+ @include_mode = value
20
+ end
21
+
22
+ def generate_info_object
23
+ OasCore::Spec::Info.new(
24
+ title: title,
25
+ summary: summary,
26
+ description: description
27
+ )
28
+ end
29
+
30
+ def title
31
+ "OasHanami"
32
+ end
33
+
34
+ def summary
35
+ "OasHanami: Automatic Interactive API Documentation for Hanami"
36
+ end
37
+
38
+ def description
39
+ <<~DESC
40
+ # Welcome to OasHanami
41
+
42
+ OasHanami automatically generates interactive documentation for your Hanami APIs using the OpenAPI Specification 3.1 (OAS 3.1) and displays it with a sleek UI.
43
+
44
+ ## Getting Started
45
+
46
+ You've successfully mounted the OasHanami engine. This default documentation is based on your routes and automatically gathered information.
47
+
48
+ For more details, visit the official documentation: [OasCore Documentation](https://a-chacon.com/oas_core).
49
+
50
+ ## Features
51
+
52
+ - **Automatic OAS 3.1 Document Generation**: No manual specification required.
53
+ - **[RapiDoc](https://github.com/rapi-doc/RapiDoc) Integration**: Interactive API exploration.
54
+ - **Minimal Setup**: Basic documentation works out of the box.
55
+ - **Extensible**: Customize through configuration and YARD tags.
56
+
57
+ Explore your API documentation and enjoy the power of OasHanami!
58
+
59
+ Any questions visit the [OasHanami GitHub Repository](https://github.com/a-chacon/oas_hanami).
60
+ DESC
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OasHanami
4
+ class HanamiRouteFormatter
5
+ def call(routes, **_csv_opts)
6
+ routes
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/router/inspector"
4
+
5
+ module OasHanami
6
+ class Inspector < Hanami::Router::Inspector
7
+ def initialize(routes: [], formatter: HanamiRouteFormatter.new)
8
+ super(routes:, formatter:)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OasHanami
4
+ class OasRouteBuilder
5
+ def self.build_from_hanami_route(hanami_route)
6
+ new(hanami_route).build
7
+ end
8
+
9
+ def initialize(hanami_route)
10
+ @hanami_route = hanami_route
11
+ end
12
+
13
+ def build
14
+ OasCore::OasRoute.new(
15
+ controller: controller,
16
+ method_name: method,
17
+ verb: verb,
18
+ path: path,
19
+ docstring: docstring,
20
+ source_string: source_string,
21
+ tags: tags
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def controller_class
28
+ if @hanami_route.to.is_a?(String)
29
+ namespace = Hanami.app.name.gsub("App", "Actions")
30
+ parts = @hanami_route.to.split(".")
31
+ full_class_name = "#{namespace}::#{parts.map(&:camelize).join("::")}"
32
+
33
+ full_class_name.split("::").reduce(Object) { |mod, name| mod.const_get(name) }
34
+ else
35
+ @hanami_route.to
36
+ end
37
+ end
38
+
39
+ def controller
40
+ controller_class.to_s
41
+ end
42
+
43
+ def method
44
+ "handle"
45
+ end
46
+
47
+ def verb
48
+ @hanami_route.http_method.downcase
49
+ end
50
+
51
+ def path
52
+ @hanami_route.path
53
+ end
54
+
55
+ def source_string
56
+ controller_class.instance_method(method).source
57
+ rescue NameError
58
+ "Source not available"
59
+ end
60
+
61
+ def docstring
62
+ comment_lines = controller_class.instance_method(method).comment.lines
63
+ processed_lines = comment_lines.map { |line| line.sub(/^# /, "") }
64
+
65
+ filtered_lines = processed_lines.reject do |line|
66
+ line.include?("rubocop") ||
67
+ line.include?("TODO")
68
+ end
69
+
70
+ ::YARD::Docstring.parser.parse(filtered_lines.join).to_docstring
71
+ rescue NameError
72
+ "Docstring not available"
73
+ end
74
+
75
+ def tags
76
+ method_comment = controller_class.instance_method(method).comment
77
+
78
+ parse_tags(method_comment)
79
+ rescue NameError
80
+ []
81
+ end
82
+
83
+ def parse_tags(comment)
84
+ return [] unless comment
85
+
86
+ lines = comment.lines.map { |line| line.sub(/^# /, "") }
87
+ ::YARD::Docstring.parser.parse(lines.join).tags
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OasHanami
4
+ class RouteExtractor
5
+ class << self
6
+ def host_routes
7
+ @host_routes ||= extract_host_routes
8
+ end
9
+
10
+ def clear_cache
11
+ @host_routes = nil
12
+ end
13
+
14
+ def clean_route(route)
15
+ route.gsub("(.:format)", "").gsub(/:\w+/) { |match| "{#{match[1..]}}" }
16
+ end
17
+
18
+ private
19
+
20
+ def extract_host_routes
21
+ routes = Hanami.app.router.inspector.call
22
+ routes = transform_routes(routes)
23
+ filter_routes(routes)
24
+ end
25
+
26
+ def transform_routes(routes)
27
+ routes.map do |r|
28
+ next unless r.to.is_a? String
29
+
30
+ OasRouteBuilder.build_from_hanami_route(r)
31
+ end.compact
32
+ end
33
+
34
+ def filter_routes(routes)
35
+ case OasHanami.config.include_mode
36
+ when :with_tags
37
+ routes.select { |route| route.tags.any? }
38
+ when :explicit
39
+ routes.select { |route| route.tags.any? { |t| t.tag_name == "oas_include" } }
40
+ else
41
+ routes
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OasHanami
4
+ VERSION = "0.1.0"
5
+ end