From 41def4c4e120ec94ab937d9f665e5d42bbbae5f4 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 18:42:10 -0400 Subject: [PATCH 01/11] ci: uplift the repo process - Introduced a new setup script to automate the installation of dependencies. - Added a generator for creating serializers for models, enhancing the ease of serialization in Rails applications. - Implemented a base serializer class with methods for JSON serialization, including support for attributes and relationships. - Created helper classes for caching and inflection operations to optimize performance. - Developed comprehensive tests for the new serialization features, ensuring reliability and correctness. - Updated the gemspec to include necessary dependencies and metadata for better package management. --- .codeclimate.yml | 4 - .github/ISSUE_TEMPLATE/bug_report.md | 14 +- .github/ISSUE_TEMPLATE/documentation_issue.md | 8 +- .github/ISSUE_TEMPLATE/feature_request.md | 12 +- .github/ISSUE_TEMPLATE/question_or_help.md | 6 +- .../report_a_security_vulnerability.md | 22 +- .github/ISSUE_TEMPLATE/translations.md | 18 +- .github/PULL_REQUEST_TEMPLATE.md | 14 +- .github/dependabot.yml | 16 +- .github/release-drafter.yml | 102 +++--- .github/workflows/ci.yml | 56 +-- .github/workflows/codeql.yml | 73 ++-- .github/workflows/danger.yml | 38 ++ .github/workflows/jekyll-gh-pages.yml | 50 +++ .github/workflows/release-drafter.yml | 29 +- .github/workflows/release.yml | 45 ++- .github/workflows/shared-ci.yml | 141 ++++++++ .jrubyrc | 1 - .qlty/.gitignore | 7 + .qlty/configs/.markdownlint.json | 8 + .qlty/configs/.yamllint.yaml | 22 ++ .qlty/qlty.toml | 98 ++++++ .releaserc | 64 ---- .rspec | 2 - .rubocop.yml | 17 - CHANGELOG.md | 112 +++--- CODE_OF_CONDUCT.md | 24 +- Gemfile | 18 - Gemfile.lock | 140 -------- README.md | 126 ++++--- SECURITY.md | 2 +- Version | 1 - danger/Dangerfile | 65 ++++ danger/Gemfile | 11 + danger/Gemfile.lock | 107 ++++++ docs/.gitignore | 5 + docs/.ruby-version | 1 + docs/404.html | 8 + docs/CNAME | 1 + docs/Gemfile | 32 ++ docs/Gemfile.lock | 332 ++++++++++++++++++ docs/_config.yml | 33 ++ docs/_includes/footer_custom.html | 98 ++++++ docs/_includes/head_custom.html | 32 ++ docs/assets/css/just-the-docs-dark.scss | 3 + docs/assets/css/just-the-docs-light.scss | 3 + docs/assets/images/favicon.svg | 28 ++ docs/assets/images/logo.svg | 30 ++ docs/index.md | 67 ++++ docs/pages/101-faq.md | 84 +++++ docs/pages/2-overview.md | 95 +++++ docs/pages/3-install.md | 61 ++++ docs/pages/5-usage.md | 252 +++++++++++++ lib/mutils/serialization/methods/relations.rb | 42 --- mutils.gemspec | 32 -- mutils/.gitignore | 15 + mutils/.reek.yml | 46 +++ mutils/.rspec | 4 + mutils/.rubocop.yml | 46 +++ .ruby-version => mutils/.ruby-version | 0 mutils/Gemfile | 28 ++ mutils/Gemfile.lock | 168 +++++++++ LICENSE.txt => mutils/LICENSE | 12 +- mutils/README.md | 301 ++++++++++++++++ Rakefile => mutils/Rakefile | 0 {bin => mutils/bin}/console | 0 mutils/bin/reek | 26 ++ {bin => mutils/bin}/rspec | 4 + {bin => mutils/bin}/rubocop | 4 + {bin => mutils/bin}/setup | 0 {lib => mutils/lib}/generators/mutils/USAGE | 0 .../generators/mutils/serializer_generator.rb | 0 .../mutils/templates/serializer.rb.tt | 0 {lib => mutils/lib}/mutils.rb | 0 {lib => mutils/lib}/mutils/lib/helper.rb | 0 {lib => mutils/lib}/mutils/lib/result_hash.rb | 0 .../mutils/serialization/base_serializer.rb | 0 .../serialization/methods/attributes.rb | 4 +- .../lib}/mutils/serialization/methods/main.rb | 0 .../mutils/serialization/methods/relations.rb | 57 +++ .../serialization/results/attributes.rb | 0 .../lib}/mutils/serialization/results/main.rb | 0 .../mutils/serialization/results/relations.rb | 0 .../serialization/serialization_includes.rb | 0 .../serialization/serialization_methods.rb | 0 .../serialization/serialization_results.rb | 0 {lib => mutils/lib}/mutils/version.rb | 0 mutils/mutils.gemspec | 32 ++ {spec => mutils/spec}/mock_classes.rb | 0 mutils/spec/mutils/lib/helper_spec.rb | 21 ++ {spec => mutils/spec}/mutils_spec.rb | 0 .../spec}/serialization/expect_output.rb | 0 .../serialization/serialization_json_spec.rb | 39 +- mutils/spec/spec_helper.rb | 28 ++ spec/spec_helper.rb | 36 -- 95 files changed, 2887 insertions(+), 696 deletions(-) delete mode 100755 .codeclimate.yml create mode 100644 .github/workflows/danger.yml create mode 100644 .github/workflows/jekyll-gh-pages.yml create mode 100644 .github/workflows/shared-ci.yml delete mode 100755 .jrubyrc create mode 100644 .qlty/.gitignore create mode 100644 .qlty/configs/.markdownlint.json create mode 100644 .qlty/configs/.yamllint.yaml create mode 100644 .qlty/qlty.toml delete mode 100755 .releaserc delete mode 100755 .rspec delete mode 100755 .rubocop.yml delete mode 100644 Gemfile delete mode 100644 Gemfile.lock delete mode 100755 Version create mode 100644 danger/Dangerfile create mode 100644 danger/Gemfile create mode 100644 danger/Gemfile.lock create mode 100644 docs/.gitignore create mode 100644 docs/.ruby-version create mode 100644 docs/404.html create mode 100644 docs/CNAME create mode 100644 docs/Gemfile create mode 100644 docs/Gemfile.lock create mode 100644 docs/_config.yml create mode 100644 docs/_includes/footer_custom.html create mode 100644 docs/_includes/head_custom.html create mode 100644 docs/assets/css/just-the-docs-dark.scss create mode 100644 docs/assets/css/just-the-docs-light.scss create mode 100644 docs/assets/images/favicon.svg create mode 100644 docs/assets/images/logo.svg create mode 100644 docs/index.md create mode 100644 docs/pages/101-faq.md create mode 100644 docs/pages/2-overview.md create mode 100644 docs/pages/3-install.md create mode 100644 docs/pages/5-usage.md delete mode 100755 lib/mutils/serialization/methods/relations.rb delete mode 100755 mutils.gemspec create mode 100755 mutils/.gitignore create mode 100644 mutils/.reek.yml create mode 100755 mutils/.rspec create mode 100644 mutils/.rubocop.yml rename .ruby-version => mutils/.ruby-version (100%) create mode 100644 mutils/Gemfile create mode 100644 mutils/Gemfile.lock rename LICENSE.txt => mutils/LICENSE (85%) create mode 100755 mutils/README.md rename Rakefile => mutils/Rakefile (100%) rename {bin => mutils/bin}/console (100%) create mode 100755 mutils/bin/reek rename {bin => mutils/bin}/rspec (81%) rename {bin => mutils/bin}/rubocop (81%) rename {bin => mutils/bin}/setup (100%) rename {lib => mutils/lib}/generators/mutils/USAGE (100%) rename {lib => mutils/lib}/generators/mutils/serializer_generator.rb (100%) rename {lib => mutils/lib}/generators/mutils/templates/serializer.rb.tt (100%) rename {lib => mutils/lib}/mutils.rb (100%) rename {lib => mutils/lib}/mutils/lib/helper.rb (100%) rename {lib => mutils/lib}/mutils/lib/result_hash.rb (100%) rename {lib => mutils/lib}/mutils/serialization/base_serializer.rb (100%) rename {lib => mutils/lib}/mutils/serialization/methods/attributes.rb (91%) rename {lib => mutils/lib}/mutils/serialization/methods/main.rb (100%) create mode 100755 mutils/lib/mutils/serialization/methods/relations.rb rename {lib => mutils/lib}/mutils/serialization/results/attributes.rb (100%) rename {lib => mutils/lib}/mutils/serialization/results/main.rb (100%) rename {lib => mutils/lib}/mutils/serialization/results/relations.rb (100%) rename {lib => mutils/lib}/mutils/serialization/serialization_includes.rb (100%) rename {lib => mutils/lib}/mutils/serialization/serialization_methods.rb (100%) rename {lib => mutils/lib}/mutils/serialization/serialization_results.rb (100%) rename {lib => mutils/lib}/mutils/version.rb (100%) create mode 100755 mutils/mutils.gemspec rename {spec => mutils/spec}/mock_classes.rb (100%) create mode 100644 mutils/spec/mutils/lib/helper_spec.rb rename {spec => mutils/spec}/mutils_spec.rb (100%) rename {spec => mutils/spec}/serialization/expect_output.rb (100%) rename {spec => mutils/spec}/serialization/serialization_json_spec.rb (87%) create mode 100755 mutils/spec/spec_helper.rb delete mode 100755 spec/spec_helper.rb diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100755 index dd488a1..0000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,4 +0,0 @@ -plugins: - rubocop: - enabled: true - channel: rubocop-0-80 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dcb1099..7f9c75f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,36 +8,36 @@ assignees: "" ## Bug Report -### Description: +### Description [Provide a clear and concise description of the bug.] -### Steps to Reproduce: +### Steps to Reproduce 1. [First step] 2. [Second step] 3. [Third step] - [If applicable] -### Expected Behavior: +### Expected Behavior [Describe what you expected to happen.] -### Actual Behavior: +### Actual Behavior [Describe what actually happened.] -### Screenshots or Additional Information: +### Screenshots or Additional Information [If applicable, add screenshots or other information to help illustrate the issue.] -### Environment: +### Environment - Operating System: [e.g., Windows, macOS, Linux] - Browser (if applicable): [e.g., Chrome, Firefox, Safari] - Version: [e.g., 1.0.0] -### Checklist: +### Checklist - [ ] I have searched for a similar issue and didn't find any duplicates. - [ ] I have included all the required information. diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.md b/.github/ISSUE_TEMPLATE/documentation_issue.md index 702b752..a7beab2 100644 --- a/.github/ISSUE_TEMPLATE/documentation_issue.md +++ b/.github/ISSUE_TEMPLATE/documentation_issue.md @@ -8,19 +8,19 @@ assignees: "" ## Documentation Issue -### Description: +### Description [Provide a clear and concise description of the documentation issue.] -### Affected Documentation: +### Affected Documentation [Specify the affected section(s) or page(s) of the documentation.] -### Suggested Improvement: +### Suggested Improvement [If you have a suggestion for improving the documentation, please describe it here.] -### Checklist: +### Checklist - [ ] I have searched for similar documentation issues and found none. - [ ] I have included all the required information. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index c7380af..c10bd0d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,27 +8,27 @@ assignees: "" ## Feature Request -### Description: +### Description [Provide a clear and concise description of the feature you're requesting.] -### Use Case: +### Use Case [Explain the use case or scenario where this feature would be beneficial.] -### Proposed Solution: +### Proposed Solution [If you have a specific solution in mind, describe it here.] -### Alternatives Considered: +### Alternatives Considered [Have you considered any alternative solutions or workarounds?] -### Additional Context: +### Additional Context [Add any additional context or information that might be relevant to the feature request.] -### Checklist: +### Checklist - [ ] I have searched for a similar feature request and didn't find any duplicates. - [ ] I have included all the required information. diff --git a/.github/ISSUE_TEMPLATE/question_or_help.md b/.github/ISSUE_TEMPLATE/question_or_help.md index f71abae..d88d939 100644 --- a/.github/ISSUE_TEMPLATE/question_or_help.md +++ b/.github/ISSUE_TEMPLATE/question_or_help.md @@ -8,15 +8,15 @@ assignees: "" ## Question/Help -### Description: +### Description [Briefly describe the question or issue you need help with.] -### Context: +### Context [Provide any relevant context or details that might help others understand your question or issue better.] -### Checklist: +### Checklist - [ ] I have searched for similar questions or issues and found none. - [ ] I have included all the required information. diff --git a/.github/ISSUE_TEMPLATE/report_a_security_vulnerability.md b/.github/ISSUE_TEMPLATE/report_a_security_vulnerability.md index 823213d..c84da9f 100644 --- a/.github/ISSUE_TEMPLATE/report_a_security_vulnerability.md +++ b/.github/ISSUE_TEMPLATE/report_a_security_vulnerability.md @@ -10,48 +10,48 @@ assignees: "" # Security Vulnerability Report -## Title: +## Title [Concise title describing the vulnerability] -## Contact Information: +## Contact Information [Your contact information - email or other preferred means of contact] [Remember that this information may be publicly visible depending on the project's settings] -## Description: +## Description [Detailed description of the vulnerability, including steps to reproduce if possible] -## Supporting Documentation: +## Supporting Documentation [Attach any supporting documentation, code, or relevant information] -## Impact: +## Impact [Describe the impact of the vulnerability] -## Suggestions to Fix: +## Suggestions to Fix [If you have suggestions on how to fix the vulnerability, please include them here] -## Steps to uncover: +## Steps to uncover [If you have suggestions on how to uncover the vulnerability, please include them here] -## Steps to reproduce: +## Steps to reproduce [If you have suggestions on how to reproduce the vulnerability, please include them here] -## Severity: +## Severity [Low/Medium/High] -## Affected Versions: +## Affected Versions [List affected versions here] -## Checklist: +## Checklist - [ ] I have filled out all the fields above - [ ] I have searched for a similar issue in the project and found none diff --git a/.github/ISSUE_TEMPLATE/translations.md b/.github/ISSUE_TEMPLATE/translations.md index 2cf4ebf..8015d81 100644 --- a/.github/ISSUE_TEMPLATE/translations.md +++ b/.github/ISSUE_TEMPLATE/translations.md @@ -8,41 +8,41 @@ assignees: "" # Translation Issue Report -## Description: +## Description [Provide a clear and concise description of the translation issue.] -## Context: +## Context [Explain the context in which the translation issue occurred.] -## Source Language: +## Source Language [Specify the language of the original content.] -## Target Language: +## Target Language [Specify the language the content was translated into.] -## Incorrect Translation: +## Incorrect Translation [Provide the section or phrase that is incorrectly translated.] -## Suggested Translation: +## Suggested Translation [Offer your suggested correction or improvement.] -## Screenshots or Additional Information: +## Screenshots or Additional Information [If applicable, add screenshots or other information to help illustrate the translation issue.] -## Environment: +## Environment - Operating System: [e.g., Windows, macOS, Linux] - Browser (if applicable): [e.g., Chrome, Firefox, Safari] - Version: [e.g., 1.0.0] -## Checklist: +## Checklist - [ ] I have searched for similar translation issues and didn't find any duplicates. - [ ] I have included all the relevant information. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cee181c..404f5fd 100755 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,21 +15,21 @@ For example: A CLA is required for this pull request. Please read and sign the CLA at https://cla.developers.codevedas.com --> -## Pull Request +# Pull Request -### Description: +## Description [Provide a clear and concise description of the changes introduced by this pull request.] -### Related Issue: +## Related Issue [If your pull request addresses a specific issue, reference it here by linking to the issue using the pound sign (#). For example, #123] -### Proposed Changes: +## Proposed Changes [Outline the changes made in this pull request. Include any new features, bug fixes, or enhancements.] -### Checklist: +## Checklist - [ ] I have tested these changes locally. - [ ] I have ensured that my code follows the project's coding standards. @@ -39,11 +39,11 @@ A CLA is required for this pull request. Please read and sign the CLA at https:/ - [ ] I have confirmed that the changes work with the latest version of dependencies. - [ ] I have added appropriate labels to the pull request. -### Screenshots or Additional Information: +## Screenshots or Additional Information [If applicable, provide screenshots or any additional information that helps reviewers understand the changes.] -### Environment: +## Environment - Operating System: [e.g., Windows, macOS, Linux] - Browser (if applicable): [e.g., Chrome, Firefox, Safari] diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 638a1d3..4b896e7 100755 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,19 @@ version: 2 updates: - - package-ecosystem: "bundler" - directory: "/" + - package-ecosystem: bundler + directory: /docs schedule: - interval: "daily" + interval: daily + - package-ecosystem: bundler + directory: /danger + schedule: + interval: daily + - package-ecosystem: bundler + directory: /mutils + schedule: + interval: daily - package-ecosystem: github-actions - directory: "/" + directory: / schedule: interval: daily open-pull-requests-limit: 10 diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 772f0cb..4908c1e 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,146 +1,148 @@ -name-template: "v$RESOLVED_VERSION" -tag-template: "v$RESOLVED_VERSION" +name-template: v$RESOLVED_VERSION +tag-template: v$RESOLVED_VERSION autolabeler: - - label: "dependencies" + - label: dependencies branch: - /^dependabot\// title: - /^chore\(deps\):/ - /^chore\(dependencies\):/ - - label: "feature" + - label: feature branch: - /^feat\// title: - /^feat:/ - - label: "bug" + - label: bug branch: - /^bugfix\// title: - /^bugfix:/ - - label: "docs" + - label: docs branch: - /^docs\// title: - /^docs:/ - - label: "release" + - label: release branch: - /^release\// title: - /^release:/ - - label: "chore" + - label: chore branch: - /^chore\// title: - /^chore:/ - - label: "refactor" + - label: refactor branch: - /^refactor\// title: - /^refactor:/ - - label: "test" + - label: test branch: - /^test\// title: - /^test:/ - - label: "style" + - label: style branch: - /^style\// title: - /^style:/ - - label: "ci" + - label: ci branch: - /^ci\// title: - /^ci:/ - - label: "perf" + - label: perf branch: - /^perf\// title: - /^perf:/ - - label: "build" + - label: build branch: - /^build\// title: - /^build:/ categories: - - title: "πŸš€ Features" + - title: πŸš€ Features labels: - - "feature" + - feature - - title: "πŸ› Bug Fixes" + - title: πŸ› Bug Fixes labels: - - "bug" + - bug - - title: "πŸ“ Documentation" + - title: πŸ“ Documentation labels: - - "docs" + - docs - - title: "πŸ”– Releases" + - title: πŸ”– Releases labels: - - "release" + - release - - title: "🧰 Maintenance" + - title: 🧰 Maintenance labels: - - "chore" - - "refactor" - - "dependencies" + - chore + - refactor + - dependencies - - title: "πŸ§ͺ Tests" + - title: πŸ§ͺ Tests labels: - - "test" + - test - - title: "πŸ’… Styling" + - title: πŸ’… Styling labels: - - "style" + - style - - title: "βš™οΈ CI" + - title: βš™οΈ CI labels: - - "ci" + - ci - - title: "πŸš€ Performance" + - title: πŸš€ Performance labels: - - "perf" + - perf - - title: "πŸ“¦ Build" + - title: πŸ“¦ Build labels: - - "build" + - build -change-template: "- $TITLE @$AUTHOR (#$NUMBER)" -no-changes-template: "- No user-facing changes." +change-template: >- + - $TITLE @$AUTHOR (#$NUMBER) +no-changes-template: >- + - No user-facing changes. version-resolver: major: labels: - - "breaking" + - breaking minor: labels: - - "feature" + - feature patch: labels: - - "bug" - - "chore" - - "refactor" - - "test" - - "style" - - "ci" - - "perf" - - "build" - - "dependencies" + - bug + - chore + - refactor + - test + - style + - ci + - perf + - build + - dependencies exclude-labels: - - "skip-changelog" + - skip-changelog template: | ## Changes diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a84f65..15b46a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,45 +1,21 @@ -name: Pull Requests +name: CI + +permissions: + contents: read + on: - push: - branches: [main] pull_request: + push: branches: [main] -jobs: - lint: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.4.3 - bundler-cache: true +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('ref-{0}', github.ref) }} + cancel-in-progress: true - - name: Lint code for consistent style - run: bin/rubocop -f github - test: - runs-on: ubuntu-latest - steps: - - name: Install packages - run: sudo apt-get update && sudo apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config - - - name: Checkout code - uses: actions/checkout@v6 - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.4.3 - bundler-cache: true - - - name: Run tests - run: bin/rspec --format documentation --color --profile - - - name: Upload simplecov report - uses: actions/upload-artifact@v7 - with: - name: simplecov-report - path: ${{ github.workspace }}/coverage - if-no-files-found: ignore +jobs: + ci: + permissions: + contents: read + uses: ./.github/workflows/shared-ci.yml + with: + upload_coverage: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a10c484..f30412d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,62 +1,53 @@ -name: "CodeQL" - +name: CodeQL +permissions: + security-events: write + packages: read + actions: read + contents: read on: push: - branches: ["*"] + branches: [main] pull_request: - # The branches below must be a subset of the branches above - branches: ["*"] + branches: [main] schedule: - - cron: "26 6 * * 5" - + - cron: 22 14 * * 3 jobs: analyze: - name: Analyze - runs-on: ubuntu-latest + name: Analyze (${{ matrix.language }}) + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} permissions: + security-events: write + packages: read actions: read contents: read - security-events: write - strategy: fail-fast: false matrix: - language: ["ruby"] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Use only 'java' to analyze code written in Java, Kotlin or both - # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - + include: + - language: actions + build-mode: none + - language: javascript-typescript + build-mode: none + - language: ruby + build-mode: none steps: - name: Checkout repository - uses: actions/checkout@v6 - - # Initializes the CodeQL tools for scanning. + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - # ℹ️ Command-line programs to run using the OS shell. - # πŸ“š See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh + build-mode: ${{ matrix.build-mode }} + - name: Run manual build steps + if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml new file mode 100644 index 0000000..2b7d2c1 --- /dev/null +++ b/.github/workflows/danger.yml @@ -0,0 +1,38 @@ +permissions: + contents: read + pull-requests: write +name: Danger +on: + pull_request: + types: [opened, synchronize, reopened] + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('ref-{0}', github.ref) }} + cancel-in-progress: true +env: + RUBY_VERSION: 3.4 + APP_DIR: ${{ github.workspace }}/danger +jobs: + danger: + permissions: + contents: read + pull-requests: write + if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' && !startsWith(github.head_ref, 'dependabot/') }} + runs-on: ubuntu-latest + defaults: + run: + working-directory: ${{ env.APP_DIR }} + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ env.RUBY_VERSION }} + bundler-cache: true + working-directory: ${{ env.APP_DIR }} + - name: Run Danger + run: bundle exec danger + env: + DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml new file mode 100644 index 0000000..96d84c3 --- /dev/null +++ b/.github/workflows/jekyll-gh-pages.yml @@ -0,0 +1,50 @@ +name: Deploy Docs +on: + push: + tags: + - v* + workflow_dispatch: +permissions: + contents: read + pages: write + id-token: write +concurrency: + group: pages + cancel-in-progress: false +env: + RUBY_VERSION: 3.4 + DOCS_DIR: ${{ github.workspace }}/docs +jobs: + build: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ${{ env.DOCS_DIR }} + steps: + - uses: actions/checkout@v6 + - uses: actions/configure-pages@v5 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ env.RUBY_VERSION }} + bundler-cache: true + working-directory: ${{ env.DOCS_DIR }} + - name: Build site + run: bundle exec jekyll build + env: + JEKYLL_ENV: production + PAGES_REPO_NWO: ${{ github.repository }} + JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload artifact + uses: actions/upload-pages-artifact@v4 + with: + path: ${{ env.DOCS_DIR }}/_site + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 13055ab..546f7bc 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -1,27 +1,38 @@ +permissions: + contents: read name: Release Drafter - on: push: branches: - main pull_request: - types: [opened, reopened, synchronize] + types: [opened, synchronize, reopened] -permissions: - contents: write - pull-requests: read +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('ref-{0}', github.ref) }} + cancel-in-progress: true jobs: - release_drafter: + update_release_draft: permissions: contents: write - pull-requests: write + pull-requests: read + if: github.event_name == 'push' runs-on: ubuntu-latest steps: - uses: release-drafter/release-drafter@v7 with: config-name: release-drafter.yml - disable-releaser: ${{ github.event_name != 'push' }} - disable-autolabeler: ${{ github.event_name != 'pull_request' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + auto_label_pull_request: + permissions: + pull-requests: write + contents: read + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter/autolabeler@v7 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 13b61a1..44d3f91 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,27 +1,34 @@ name: Release +permissions: + contents: read on: + workflow_dispatch: push: tags: - - "v*" + - v* + +concurrency: + group: release + cancel-in-progress: true + +env: + APP_DIR: ${{ github.workspace }}/mutils + RUBY_VERSION: 3.4 jobs: - test: - name: Run RSpec - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - - name: RSpec - run: bin/rspec + verify_release: + name: Verify release + permissions: + contents: read + uses: ./.github/workflows/shared-ci.yml + with: + upload_coverage: false - push: + publish_mutils: + name: Publish mutils runs-on: ubuntu-latest - needs: test + needs: [verify_release] permissions: contents: write id-token: write @@ -33,11 +40,13 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: + ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true - ruby-version: ruby + working-directory: ${{ env.APP_DIR }} - name: Configure RubyGems Credentials - uses: rubygems/configure-rubygems-credentials@main - - name: Release + uses: rubygems/configure-rubygems-credentials@c631c084989f8f5953cd1cdbfb04e4cf3dba10aa + - name: Build and push gem + working-directory: ${{ env.APP_DIR }} run: | gem build mutils.gemspec gem push mutils-*.gem diff --git a/.github/workflows/shared-ci.yml b/.github/workflows/shared-ci.yml new file mode 100644 index 0000000..c846e51 --- /dev/null +++ b/.github/workflows/shared-ci.yml @@ -0,0 +1,141 @@ +name: Shared CI +permissions: + contents: read + +env: + APP_DIR: ${{ github.workspace }}/mutils + BUNDLE_PATH: ${{ github.workspace }}/vendor/bundle + BUNDLE_JOBS: "4" + BUNDLE_RETRY: "3" + +on: + workflow_call: + inputs: + upload_coverage: + required: false + type: boolean + default: false + +jobs: + rubocop: + name: RuboCop Β· Ruby ${{ matrix.ruby_version }} + permissions: + contents: read + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby_version: + - "3.2" + - "3.4" + - "4.0" + steps: + - uses: actions/checkout@v6 + - name: Install apt packages + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y \ + build-essential git libyaml-dev pkg-config + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: false + - name: Restore bundle cache + uses: actions/cache@v4 + with: + path: ${{ env.BUNDLE_PATH }} + key: ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle-${{ hashFiles('mutils/Gemfile.lock', 'mutils/mutils.gemspec') }} + restore-keys: | + ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle- + - name: Install bundle + working-directory: ${{ env.APP_DIR }} + run: bundle install --jobs "${BUNDLE_JOBS}" --retry "${BUNDLE_RETRY}" + - name: Run RuboCop + working-directory: ${{ env.APP_DIR }} + run: bin/rubocop -f github + + reek: + name: Reek Β· Ruby ${{ matrix.ruby_version }} + permissions: + contents: read + runs-on: ubuntu-latest + needs: rubocop + strategy: + fail-fast: false + matrix: + ruby_version: + - "3.2" + - "3.4" + - "4.0" + steps: + - uses: actions/checkout@v6 + - name: Install apt packages + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y \ + build-essential git libyaml-dev pkg-config + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: false + - name: Restore bundle cache + uses: actions/cache@v4 + with: + path: ${{ env.BUNDLE_PATH }} + key: ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle-${{ hashFiles('mutils/Gemfile.lock', 'mutils/mutils.gemspec') }} + restore-keys: | + ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle- + - name: Install bundle + working-directory: ${{ env.APP_DIR }} + run: bundle install --jobs "${BUNDLE_JOBS}" --retry "${BUNDLE_RETRY}" + - name: Run Reek + working-directory: ${{ env.APP_DIR }} + run: bin/reek + + test: + name: Unit Tests Β· Ruby ${{ matrix.ruby_version }} + permissions: + contents: read + runs-on: ubuntu-latest + needs: reek + strategy: + fail-fast: false + matrix: + ruby_version: + - "3.2" + - "3.4" + - "4.0" + steps: + - uses: actions/checkout@v6 + - name: Install apt packages + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y \ + build-essential git libyaml-dev pkg-config + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: false + - name: Restore bundle cache + uses: actions/cache@v4 + with: + path: ${{ env.BUNDLE_PATH }} + key: ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle-${{ hashFiles('mutils/Gemfile.lock', 'mutils/mutils.gemspec') }} + restore-keys: | + ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle- + - name: Install bundle + working-directory: ${{ env.APP_DIR }} + run: bundle install --jobs "${BUNDLE_JOBS}" --retry "${BUNDLE_RETRY}" + - name: Run unit tests + working-directory: ${{ env.APP_DIR }} + run: bin/rspec --format documentation --color --profile + - name: Upload simplecov report + if: inputs.upload_coverage && matrix.ruby_version == '3.4' + uses: actions/upload-artifact@v4 + with: + name: simplecov-report-ruby-${{ matrix.ruby_version }} + path: ${{ env.APP_DIR }}/coverage + if-no-files-found: ignore diff --git a/.jrubyrc b/.jrubyrc deleted file mode 100755 index ec033ee..0000000 --- a/.jrubyrc +++ /dev/null @@ -1 +0,0 @@ -debug.fullTrace=true diff --git a/.qlty/.gitignore b/.qlty/.gitignore new file mode 100644 index 0000000..3036618 --- /dev/null +++ b/.qlty/.gitignore @@ -0,0 +1,7 @@ +* +!configs +!configs/** +!hooks +!hooks/** +!qlty.toml +!.gitignore diff --git a/.qlty/configs/.markdownlint.json b/.qlty/configs/.markdownlint.json new file mode 100644 index 0000000..964f60a --- /dev/null +++ b/.qlty/configs/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "MD013": { + "line_length": 1000 + }, + "MD033": false, + "MD025": false, + "MD024": false +} diff --git a/.qlty/configs/.yamllint.yaml b/.qlty/configs/.yamllint.yaml new file mode 100644 index 0000000..2270907 --- /dev/null +++ b/.qlty/configs/.yamllint.yaml @@ -0,0 +1,22 @@ +extends: default + +rules: + document-start: disable + quoted-strings: + required: only-when-needed + extra-allowed: ["{|}"] + key-duplicates: {} + octal-values: + forbid-implicit-octal: true + line-length: disable + indentation: disable + new-line-at-end-of-file: disable + trailing-spaces: disable + brackets: disable + colons: disable + empty-lines: disable + comments: disable + braces: disable + comments-indentation: disable + commas: disable + truthy: disable diff --git a/.qlty/qlty.toml b/.qlty/qlty.toml new file mode 100644 index 0000000..31af57d --- /dev/null +++ b/.qlty/qlty.toml @@ -0,0 +1,98 @@ +# This file was automatically generated by `qlty init`. +# You can modify it to suit your needs. +# We recommend you to commit this file to your repository. +# +# This configuration is used by both Qlty CLI and Qlty Cloud. +# +# Qlty CLI -- Code quality toolkit for developers +# Qlty Cloud -- Fully automated Code Health Platform +# +# Try Qlty Cloud: https://qlty.sh +# +# For a guide to configuration, visit https://qlty.sh/d/config +# Or for a full reference, visit https://qlty.sh/d/qlty-toml +config_version = "0" + +exclude_patterns = [ + "*_min.*", + "*-min.*", + "*.min.*", + "**/.yarn/**", + "**/*.d.ts", + "**/assets/**", + "**/bower_components/**", + "**/build/**", + "**/cache/**", + "**/config/**", + "**/db/**", + "**/deps/**", + "**/dist/**", + "**/extern/**", + "**/external/**", + "**/generated/**", + "**/Godeps/**", + "**/gradlew/**", + "**/mvnw/**", + "**/node_modules/**", + "**/protos/**", + "**/seed/**", + "**/target/**", + "**/templates/**", + "**/testdata/**", + "**/vendor/**", +] + +test_patterns = [ + "**/test/**", + "**/spec/**", + "**/*.test.*", + "**/*.spec.*", + "**/*_test.*", + "**/*_spec.*", + "**/test_*.*", + "**/spec_*.*", +] + +[smells] +mode = "comment" + +[[source]] +name = "default" +default = true + + +[[plugin]] +name = "actionlint" + +[[plugin]] +name = "checkov" + +[[plugin]] +name = "markdownlint" +mode = "comment" + +[[plugin]] +name = "osv-scanner" + +[[plugin]] +name = "prettier" + +[[plugin]] +name = "radarlint-js" + +[[plugin]] +name = "ripgrep" +mode = "comment" + +[[plugin]] +name = "trivy" +drivers = [ + "config", + "fs-vuln", +] + +[[plugin]] +name = "trufflehog" + +[[plugin]] +name = "yamllint" diff --git a/.releaserc b/.releaserc deleted file mode 100755 index 5e7f145..0000000 --- a/.releaserc +++ /dev/null @@ -1,64 +0,0 @@ -branch: master -ci: false -verifyConditions: -- "@semantic-release/changelog" -- "@semantic-release/git" -- "@semantic-release/github" -analyzeCommits: -- "@semantic-release/commit-analyzer" -generateNotes: - path: "@semantic-release/release-notes-generator" - preset: angular - parserOpts: - noteKeywords: - - BREAKING CHANGE - - BREAKING CHANGES - - BREAKING - writerOpts: - commitsSort: - - scope - - subject - presetConfig: - types: - - type: chore - section: Chores - - type: build - section: Build Changes - - type: docs - section: Documentation Changes - - type: feat - section: Features - - type: fix - section: Bug Fixes - - type: perf - section: Performance Improvements - - type: refactor - section: Refactors - - type: revert - section: Reverted - - type: style - section: Styles Changes - - type: test - section: Test Suite Changes -prepare: -- path: "@semantic-release/changelog" - changelogFile: CHANGELOG.md -- path: "@semantic-release/exec" - cmd: echo "v${nextRelease.version}" > Version -- path: "@semantic-release/exec" - cmd: 'bundle config unset deployment' -- path: "@semantic-release/exec" - cmd: 'bundle install' -- path: "@semantic-release/exec" - cmd: 'echo "Creating Version: $(cat Version)"' -- path: "@semantic-release/git" - assets: - - CHANGELOG.md - - Version - - Gemfile.lock - message: |- - build(release): v${nextRelease.version} [skip ci] - - ${nextRelease.notes} -publish: -- "@semantic-release/github" \ No newline at end of file diff --git a/.rspec b/.rspec deleted file mode 100755 index 83e16f8..0000000 --- a/.rspec +++ /dev/null @@ -1,2 +0,0 @@ ---color ---require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml deleted file mode 100755 index c54d276..0000000 --- a/.rubocop.yml +++ /dev/null @@ -1,17 +0,0 @@ -plugins: - - rubocop-rake - - rubocop-rspec -AllCops: - NewCops: enable - TargetRubyVersion: 3.2 - SuggestExtensions: true - Exclude: - - 'vendor/**/*' - - 'vendor/bundle/**/*' - - spec/mock_classes.rb -Metrics/MethodLength: - Max: 20 -RSpec/MultipleExpectations: - Max: 10 -RSpec/ExampleLength: - Max: 15 diff --git a/CHANGELOG.md b/CHANGELOG.md index 503e63f..4a2fc36 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +# Changelog + ## [1.3.5](https://github.com/Code-Vedas/mutils/compare/v1.3.4...v1.3.5) (2026-02-14) ## 🧰 Maintenance @@ -51,165 +53,147 @@ ## [1.3.3](https://github.com/Code-Vedas/mutils/compare/v1.3.2...v1.3.3) (2024-09-05) - ### Bug Fixes -* outdated deps ([dd551fc](https://github.com/Code-Vedas/mutils/commit/dd551fca6ac14e4131ab07eb1261eea6ac3d90f2)) -* outdated deps ([8918619](https://github.com/Code-Vedas/mutils/commit/89186194908af12c167b030ef2c6f8139127748a)) +- outdated deps ([dd551fc](https://github.com/Code-Vedas/mutils/commit/dd551fca6ac14e4131ab07eb1261eea6ac3d90f2)) +- outdated deps ([8918619](https://github.com/Code-Vedas/mutils/commit/89186194908af12c167b030ef2c6f8139127748a)) ## [1.3.2](https://github.com/Code-Vedas/mutils/compare/v1.3.1...v1.3.2) (2024-06-28) - ### Bug Fixes -* bundle updated ([b5770d6](https://github.com/Code-Vedas/mutils/commit/b5770d62edd2566f1d0e581843c4e528c43a8fd4)) -* rubocop >= 1.63.3 ([9d8f944](https://github.com/Code-Vedas/mutils/commit/9d8f944e1277b068a65b068f5b2d7601bbf18704)) +- bundle updated ([b5770d6](https://github.com/Code-Vedas/mutils/commit/b5770d62edd2566f1d0e581843c4e528c43a8fd4)) +- rubocop >= 1.63.3 ([9d8f944](https://github.com/Code-Vedas/mutils/commit/9d8f944e1277b068a65b068f5b2d7601bbf18704)) ## [1.3.1](https://github.com/Code-Vedas/mutils/compare/v1.3.0...v1.3.1) (2024-04-02) - ### Bug Fixes -* **maintenance:** maintenance release ([19ef41d](https://github.com/Code-Vedas/mutils/commit/19ef41d754f6b398e4955e8ba40359bf91c3bddd)) - -# [1.3.0](https://github.com/Code-Vedas/mutils/compare/v1.2.6...v1.3.0) (2023-03-01) +- **maintenance:** maintenance release ([19ef41d](https://github.com/Code-Vedas/mutils/commit/19ef41d754f6b398e4955e8ba40359bf91c3bddd)) +## [1.3.0](https://github.com/Code-Vedas/mutils/compare/v1.2.6...v1.3.0) (2023-03-01) ### Features -* remove ruby 2.6 support ([0a3cb1f](https://github.com/Code-Vedas/mutils/commit/0a3cb1f657ce4f3a8a153a012933dcb826a74cef)) +- remove ruby 2.6 support ([0a3cb1f](https://github.com/Code-Vedas/mutils/commit/0a3cb1f657ce4f3a8a153a012933dcb826a74cef)) ## [1.2.6](https://github.com/Code-Vedas/mutils/compare/v1.2.5...v1.2.6) (2023-02-23) - ### Bug Fixes -* add upto ruby 3.2 test matrix ([cbeedc3](https://github.com/Code-Vedas/mutils/commit/cbeedc36ca96bb691fa8b6fdc8c19788c7184b4a)) +- add upto ruby 3.2 test matrix ([cbeedc3](https://github.com/Code-Vedas/mutils/commit/cbeedc36ca96bb691fa8b6fdc8c19788c7184b4a)) ## [1.2.5](https://github.com/Code-Vedas/mutils/compare/v1.2.4...v1.2.5) (2022-03-10) - ### Bug Fixes -* include Gemfile.lock when creating release ([7c9b88a](https://github.com/Code-Vedas/mutils/commit/7c9b88a2ef63bda6ab44a36eafbbaf31dab9cd7f)) +- include Gemfile.lock when creating release ([7c9b88a](https://github.com/Code-Vedas/mutils/commit/7c9b88a2ef63bda6ab44a36eafbbaf31dab9cd7f)) ## [1.2.4](https://github.com/Code-Vedas/mutils/compare/v1.2.3...v1.2.4) (2022-03-10) - ### Bug Fixes -* bundle ([4f70247](https://github.com/Code-Vedas/mutils/commit/4f70247451df4df88397ff51b0dbe382eed02838)) +- bundle ([4f70247](https://github.com/Code-Vedas/mutils/commit/4f70247451df4df88397ff51b0dbe382eed02838)) ## [1.2.3](https://github.com/Code-Vedas/mutils/compare/v1.2.2...v1.2.3) (2022-03-10) - ### Bug Fixes -* release with test ruby 3.0 ([c3a6034](https://github.com/Code-Vedas/mutils/commit/c3a60344f7722552215559f46377dc83d7e33e05)) +- release with test ruby 3.0 ([c3a6034](https://github.com/Code-Vedas/mutils/commit/c3a60344f7722552215559f46377dc83d7e33e05)) ## [1.2.2](https://github.com/Code-Vedas/mutils/compare/v1.2.1...v1.2.2) (2021-11-26) - ### Bug Fixes -* deps ([a778c53](https://github.com/Code-Vedas/mutils/commit/a778c533db613936e26cbd92caea75c8e87347d6)) +- deps ([a778c53](https://github.com/Code-Vedas/mutils/commit/a778c533db613936e26cbd92caea75c8e87347d6)) ## [1.2.1](https://github.com/Code-Vedas/mutils/compare/v1.2.0...v1.2.1) (2021-08-20) - ### Bug Fixes -* dropping ruby 2.5 support ([#172](https://github.com/Code-Vedas/mutils/issues/172)) ([a74d02c](https://github.com/Code-Vedas/mutils/commit/a74d02c4f6b126092e18a94aaa4ebd62e48c22e9)) - -# [1.2.0](https://github.com/Code-Vedas/mutils/compare/v1.1.8...v1.2.0) (2021-08-20) +- dropping ruby 2.5 support ([#172](https://github.com/Code-Vedas/mutils/issues/172)) ([a74d02c](https://github.com/Code-Vedas/mutils/commit/a74d02c4f6b126092e18a94aaa4ebd62e48c22e9)) +## [1.2.0](https://github.com/Code-Vedas/mutils/compare/v1.1.8...v1.2.0) (2021-08-20) ### Features -* attribute can accept Proc without params ([c014fef](https://github.com/Code-Vedas/mutils/commit/c014fef841426673d1f409b56a1c2548222fd2f5)) +- attribute can accept Proc without params ([c014fef](https://github.com/Code-Vedas/mutils/commit/c014fef841426673d1f409b56a1c2548222fd2f5)) ## [1.1.8](https://github.com/Code-Vedas/mutils/compare/v1.1.7...v1.1.8) (2021-08-20) - ### Bug Fixes -* deps ([4bec0e0](https://github.com/Code-Vedas/mutils/commit/4bec0e0e3a33ec5aa3f3ca28936bb09e3fde1203)) +- deps ([4bec0e0](https://github.com/Code-Vedas/mutils/commit/4bec0e0e3a33ec5aa3f3ca28936bb09e3fde1203)) ## [1.1.7](https://github.com/Code-Vedas/mutils/compare/v1.1.6...v1.1.7) (2021-01-28) - ### Bug Fixes -* version file missing ([aed03ed](https://github.com/Code-Vedas/mutils/commit/aed03edeb10efca4307e2ba1f8faca72d98a1f1d)) +- version file missing ([aed03ed](https://github.com/Code-Vedas/mutils/commit/aed03edeb10efca4307e2ba1f8faca72d98a1f1d)) ## [1.1.6](https://github.com/Code-Vedas/mutils/compare/v1.1.5...v1.1.6) (2020-11-21) - ### Bug Fixes -* **github-token:** use github action token ([9b69a06](https://github.com/Code-Vedas/mutils/commit/9b69a0683a06b6e1659eb2984de273191441cbfd)) +- **github-token:** use github action token ([9b69a06](https://github.com/Code-Vedas/mutils/commit/9b69a0683a06b6e1659eb2984de273191441cbfd)) ## [1.1.4](https://github.com/Code-Vedas/mutils/compare/v1.1.3...v1.1.4) (2020-10-19) - ### Bug Fixes -* gemfile to reduce vulnerabilities ([#65](https://github.com/Code-Vedas/mutils/issues/65)) ([b2e2ef6](https://github.com/Code-Vedas/mutils/commit/b2e2ef66360279bd0995470b6cb80111cc7091c2)) -* gemfile to reduce vulnerabilities ([#65](https://github.com/Code-Vedas/mutils/issues/65)) ([b19cbea](https://github.com/Code-Vedas/mutils/commit/b19cbea4dfa74bde23b0ddacfbbc5972d0b383c4)) +- gemfile to reduce vulnerabilities ([#65](https://github.com/Code-Vedas/mutils/issues/65)) ([b2e2ef6](https://github.com/Code-Vedas/mutils/commit/b2e2ef66360279bd0995470b6cb80111cc7091c2)) +- gemfile to reduce vulnerabilities ([#65](https://github.com/Code-Vedas/mutils/issues/65)) ([b19cbea](https://github.com/Code-Vedas/mutils/commit/b19cbea4dfa74bde23b0ddacfbbc5972d0b383c4)) ## [1.1.3](https://github.com/Code-Vedas/mutils/compare/v1.1.2...v1.1.3) (2020-10-18) - ### Bug Fixes -* Gemfile to reduce vulnerabilities ([#65](https://github.com/Code-Vedas/mutils/issues/65)) ([49b5ae2](https://github.com/Code-Vedas/mutils/commit/49b5ae2ba795d16976425ddbaf1e1c372a940c1f)) +- Gemfile to reduce vulnerabilities ([#65](https://github.com/Code-Vedas/mutils/issues/65)) ([49b5ae2](https://github.com/Code-Vedas/mutils/commit/49b5ae2ba795d16976425ddbaf1e1c372a940c1f)) ## [1.1.2](https://github.com/Code-Vedas/mutils/compare/v1.1.1...v1.1.2) (2020-10-15) - ### Bug Fixes -* **coveralls:** gemfile to reduce vulnerabilities ([#64](https://github.com/Code-Vedas/mutils/issues/64)) ([7d4e592](https://github.com/Code-Vedas/mutils/commit/7d4e59214d5c9aced1c4beb1a6b9f929367d84da)) +- **coveralls:** gemfile to reduce vulnerabilities ([#64](https://github.com/Code-Vedas/mutils/issues/64)) ([7d4e592](https://github.com/Code-Vedas/mutils/commit/7d4e59214d5c9aced1c4beb1a6b9f929367d84da)) ## [1.1.1](https://github.com/Code-Vedas/mutils/compare/v1.1.0...v1.1.1) (2020-10-05) - ### Bug Fixes -* **params:** always send hash in params ([7d71b6d](https://github.com/Code-Vedas/mutils/commit/7d71b6d2c89f39883745a40e5472c444b5673e8b)) - -# [1.1.0](https://github.com/Code-Vedas/mutils/compare/v1.0.1...v1.1.0) (2020-08-15) +- **params:** always send hash in params ([7d71b6d](https://github.com/Code-Vedas/mutils/commit/7d71b6d2c89f39883745a40e5472c444b5673e8b)) +## [1.1.0](https://github.com/Code-Vedas/mutils/compare/v1.0.1...v1.1.0) (2020-08-15) ### Features -* **params:** conditional if:Proc get params as second attribute ([55a3b08](https://github.com/Code-Vedas/mutils/commit/55a3b08fee52c0dbef2b22c6e4f468389f8c53a4)) +- **params:** conditional if:Proc get params as second attribute ([55a3b08](https://github.com/Code-Vedas/mutils/commit/55a3b08fee52c0dbef2b22c6e4f468389f8c53a4)) ## [1.0.1](https://github.com/Code-Vedas/mutils/compare/v1.0.0...v1.0.1) (2020-07-24) - ### Bug Fixes -* **semantic-release:** enable semantic-release ([aa9c28f](https://github.com/Code-Vedas/mutils/commit/aa9c28fb8da7fcd1915a189bda22f8421a566eee)) +- **semantic-release:** enable semantic-release ([aa9c28f](https://github.com/Code-Vedas/mutils/commit/aa9c28fb8da7fcd1915a189bda22f8421a566eee)) ## [1.0.0](https://github.com/code-vedas/mutils/tree/v0.2.36) (2020-04-17) [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.36...v1.0.0) -**First Stable release: Features** +### First Stable release: Features + - Performance upto 35i/s under load - Observed 35-40 MB of memory usage - Fully featured JSON serializer similar to Active Serializer but with more power and speed. - -**Changes:** -- Code refactored + +### Changes + +- Code refactored - Using cache for expensive operations ## [0.2.36](https://github.com/code-vedas/mutils/tree/v0.2.36) (2020-04-14) [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.35...v0.2.36) -**Merged pull requests:** +### Merged pull requests - Remove active support dep [\#34](https://github.com/code-vedas/mutils/pull/34) ([niteshpurohit](https://github.com/niteshpurohit)) - Conditional attributes and relations [\#32](https://github.com/code-vedas/mutils/pull/32) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -219,17 +203,17 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.34...v0.2.35) -**Merged pull requests:** +### Merged pull requests - new option 'label' for relations [\#30](https://github.com/code-vedas/mutils/pull/30) ([niteshpurohit](https://github.com/niteshpurohit)) -- added custom\_method and attribute example [\#29](https://github.com/code-vedas/mutils/pull/29) ([niteshpurohit](https://github.com/niteshpurohit)) +- added custom_method and attribute example [\#29](https://github.com/code-vedas/mutils/pull/29) ([niteshpurohit](https://github.com/niteshpurohit)) - chore: update changelog [\#28](https://github.com/code-vedas/mutils/pull/28) ([niteshpurohit](https://github.com/niteshpurohit)) ## [0.2.34](https://github.com/code-vedas/mutils/tree/v0.2.34) (2020-03-29) [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.33...v0.2.34) -**Merged pull requests:** +### Merged pull requests - Feature/attribute can be optional [\#27](https://github.com/code-vedas/mutils/pull/27) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -237,9 +221,9 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.32...v0.2.33) -**Merged pull requests:** +### Merged pull requests -- Added new custom\_method in serializer to control if include method [\#26](https://github.com/code-vedas/mutils/pull/26) ([niteshpurohit](https://github.com/niteshpurohit)) +- Added new custom_method in serializer to control if include method [\#26](https://github.com/code-vedas/mutils/pull/26) ([niteshpurohit](https://github.com/niteshpurohit)) - Update CHANGELOG.md [\#25](https://github.com/code-vedas/mutils/pull/25) ([niteshpurohit](https://github.com/niteshpurohit)) - Create .codeclimate.yml [\#24](https://github.com/code-vedas/mutils/pull/24) ([niteshpurohit](https://github.com/niteshpurohit)) - changelog: v0.2.32 [\#22](https://github.com/code-vedas/mutils/pull/22) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -248,7 +232,7 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.31...v0.2.32) -**Merged pull requests:** +### Merged pull requests - Feature/improve performance [\#21](https://github.com/code-vedas/mutils/pull/21) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -256,7 +240,7 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.30...v0.2.31) -**Merged pull requests:** +### Merged pull requests - Update version.rb [\#20](https://github.com/code-vedas/mutils/pull/20) ([niteshpurohit](https://github.com/niteshpurohit)) - Rake 13.0 [\#19](https://github.com/code-vedas/mutils/pull/19) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -265,7 +249,7 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.29...v0.2.30) -**Merged pull requests:** +### Merged pull requests - Deps [\#18](https://github.com/code-vedas/mutils/pull/18) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -273,7 +257,7 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.28...v0.2.29) -**Merged pull requests:** +### Merged pull requests - Scope Variable bug [\#14](https://github.com/code-vedas/mutils/pull/14) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -281,7 +265,7 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.27...v0.2.28) -**Implemented enhancements:** +### Implemented enhancements - Feature/scoped generator [\#13](https://github.com/code-vedas/mutils/pull/13) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -289,11 +273,11 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/v0.2.26...v0.2.27) -**Implemented enhancements:** +### Implemented enhancements - feat: coveralls added [\#5](https://github.com/code-vedas/mutils/pull/5) ([niteshpurohit](https://github.com/niteshpurohit)) -**Merged pull requests:** +### Merged pull requests - Update CHANGELOG.md [\#12](https://github.com/code-vedas/mutils/pull/12) ([niteshpurohit](https://github.com/niteshpurohit)) - Update version.rb [\#11](https://github.com/code-vedas/mutils/pull/11) ([niteshpurohit](https://github.com/niteshpurohit)) @@ -310,7 +294,7 @@ [Full Changelog](https://github.com/code-vedas/mutils/compare/885f96959dd3701ac20ed0981b920be753c00db0...v0.2.25) -**Merged pull requests:** +### Merged pull requests - Feature/improve concurrency [\#4](https://github.com/code-vedas/mutils/pull/4) ([niteshpurohit](https://github.com/niteshpurohit)) - Testing Deploy [\#3](https://github.com/code-vedas/mutils/pull/3) ([niteshpurohit](https://github.com/niteshpurohit)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1365650..093156f 100755 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,21 +14,21 @@ orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at nitesh.purohit.it@gmail.com. All +reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 1ecefa5..0000000 --- a/Gemfile +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -source 'https://rubygems.org' - -# Specify your gem's dependencies in mutils.gemspec -gem 'benchmark' -gem 'bundler' -gem 'coveralls', '>= 0.8.23' -gem 'json' -gem 'rake' -gem 'rspec' -gem 'rspec-benchmark' -gem 'rspec-json_expectations' -gem 'rubocop' -gem 'rubocop-rake' -gem 'rubocop-rspec' -gem 'simplecov-lcov', git: 'https://github.com/niteshpurohit/simplecov-lcov' -gemspec diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index cf71c8b..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,140 +0,0 @@ -GIT - remote: https://github.com/niteshpurohit/simplecov-lcov - revision: f1f759f078b19a2c0c13c1cb16cfff96d915e807 - specs: - simplecov-lcov (0.8.0) - -PATH - remote: . - specs: - mutils (1.3.5) - dry-inflector - -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.9) - public_suffix (>= 2.0.2, < 8.0) - ast (2.4.3) - benchmark (0.5.0) - benchmark-malloc (0.2.0) - benchmark-perf (0.6.0) - benchmark-trend (0.4.0) - bigdecimal (4.0.1) - bigdecimal (4.0.1-java) - coveralls (0.8.23) - json (>= 1.8, < 3) - simplecov (~> 0.16.1) - term-ansicolor (~> 1.3) - thor (>= 0.19.4, < 2.0) - tins (~> 1.6) - diff-lcs (1.6.2) - docile (1.4.1) - dry-inflector (1.3.1) - io-console (0.8.2) - io-console (0.8.2-java) - json (2.19.2) - json (2.19.2-java) - json-schema (6.2.0) - addressable (~> 2.8) - bigdecimal (>= 3.1, < 5) - language_server-protocol (3.17.0.5) - lint_roller (1.1.0) - mcp (0.8.0) - json-schema (>= 4.1) - mize (0.6.1) - parallel (1.27.0) - parser (3.3.10.2) - ast (~> 2.4.1) - racc - prism (1.9.0) - public_suffix (7.0.5) - racc (1.8.1) - racc (1.8.1-java) - rainbow (3.1.1) - rake (13.3.1) - readline (0.0.4) - reline - regexp_parser (2.11.3) - reline (0.6.3) - io-console (~> 0.5) - rspec (3.13.2) - rspec-core (~> 3.13.0) - rspec-expectations (~> 3.13.0) - rspec-mocks (~> 3.13.0) - rspec-benchmark (0.6.0) - benchmark-malloc (~> 0.2) - benchmark-perf (~> 0.6) - benchmark-trend (~> 0.4) - rspec (>= 3.0) - rspec-core (3.13.6) - rspec-support (~> 3.13.0) - rspec-expectations (3.13.5) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.13.0) - rspec-json_expectations (2.2.0) - rspec-mocks (3.13.8) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.13.0) - rspec-support (3.13.7) - rubocop (1.85.1) - json (~> 2.3) - language_server-protocol (~> 3.17.0.2) - lint_roller (~> 1.1.0) - mcp (~> 0.6) - parallel (~> 1.10) - parser (>= 3.3.0.2) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.9.3, < 3.0) - rubocop-ast (>= 1.49.0, < 2.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.49.1) - parser (>= 3.3.7.2) - prism (~> 1.7) - rubocop-rake (0.7.1) - lint_roller (~> 1.1) - rubocop (>= 1.72.1) - rubocop-rspec (3.9.0) - lint_roller (~> 1.1) - rubocop (~> 1.81) - ruby-progressbar (1.13.0) - simplecov (0.16.1) - docile (~> 1.1) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - sync (0.5.0) - term-ansicolor (1.11.3) - tins (~> 1) - thor (1.5.0) - tins (1.52.0) - bigdecimal - mize (~> 0.6) - readline - sync - unicode-display_width (3.2.0) - unicode-emoji (~> 4.1) - unicode-emoji (4.2.0) - -PLATFORMS - java - ruby - -DEPENDENCIES - benchmark - bundler - coveralls (>= 0.8.23) - json - mutils! - rake - rspec - rspec-benchmark - rspec-json_expectations - rubocop - rubocop-rake - rubocop-rspec - simplecov-lcov! - -BUNDLED WITH - 2.5.6 diff --git a/README.md b/README.md index ffed237..a67af13 100755 --- a/README.md +++ b/README.md @@ -1,51 +1,62 @@ +# Mutils + [![Maintainability](https://api.codeclimate.com/v1/badges/42e8a34f839ca0c5ec45/maintainability)](https://codeclimate.com/github/code-vedas/mutils/maintainability) -![](https://ruby-gem-downloads-badge.herokuapp.com/mutils?type=total&color=brightgreen) +![Ruby gem downloads](https://ruby-gem-downloads-badge.herokuapp.com/mutils?type=total&color=brightgreen) [![Gem Version](https://badge.fury.io/rb/mutils.svg)](https://badge.fury.io/rb/mutils) [![Coverage Status](https://badge.coveralls.io/repos/github/Code-Vedas/mutils/badge.svg?branch=master)](https://badge.coveralls.io/github/Code-Vedas/mutils?branch=master) -# Mutils ## Introduction + `mutils` is collection of useful modules for `ruby on rails` which is tested and benchmarked against high load. These collection of modules are built by developer for developers :-) -# Table of Contents - -* [Features](#features) -* [Installation](#installation) -* [Usage](#usage) - * [Rails Generator](#rails-generator) - * [Attributes](#attributes) - * [Relations](#relations) - * [Conditional Attributes](#conditional-attributes) - * [Conditional Relations](#conditional-relations) - * [Attributes Block](#attributes-blocks) - * [Attributes Block with Params](#attributes-blocks-with-params) - * [Custom Methods](#custom-methods) - * [Name Tag](#name-tag) - * [Sample Usage](#sample-usage) + +## Table of Contents + +- [Features](#features) +- [Installation](#installation) +- [Usage](#usage) + - [Rails Generator](#rails-generator) + - [Attributes](#attributes) + - [Relations](#relations) + - [Conditional Attributes](#conditional-attributes) + - [Conditional Relations](#conditional-relations) + - [Attributes Block](#attributes-blocks) + - [Attributes Block with Params](#attributes-blocks-with-params) + - [Custom Methods](#custom-methods) + - [Name Tag](#name-tag) + - [Sample Usage](#sample-usage) ## Features -* Simple declaration syntax similar to Active Model Serializer -* Realtionships support `belongs_to`, `has_many`, `has_one` -* Block style attributes with params + +- Simple declaration syntax similar to Active Model Serializer +- Realtionships support `belongs_to`, `has_many`, `has_one` +- Block style attributes with params ## Installation Add this line to your application's Gemfile: + ```ruby gem 'mutils' ``` + And then execute: - $ bundle install +```bash +bundle install +``` Or install it yourself as: - $ gem install mutils +```bash +gem install mutils +``` -## Usage +## Usage ### Rails Generator + ```shell script rails g mutils:serializer User id first_name last_name email @@ -53,7 +64,9 @@ OUTPUT Running via Spring preloader in process xxxxx create app/serializers/user_serializer.rb ``` + You will get serializer in app/serializers/user_serializer.rb + ```ruby # frozen_string_literal: true @@ -64,7 +77,9 @@ end ``` ### Attributes + Attributes are fields in the model itself. You can reference them by below example + ```ruby # frozen_string_literal: true @@ -77,37 +92,44 @@ class UserSerializer < Mutils::Serialization::BaseSerializer attribute :email, &:email ## this will call email attribute from User end ``` + ### Relations + Relations such as `has_many`, `belongs_to`, `has_one` can be used as follows + 1. Every relation must be provided with their own serializer 2. `always_include` option can be used to instruct `Serializer` to always include this relation 3. `always_include` by default is disabled, relations which are not `always_include` can be included while using the serializer. Refer to next section for this usage 4. `label` option can be used to override model class name while serializing + ```ruby # frozen_string_literal: true # User Serializer class UserSerializer < Mutils::Serialization::BaseSerializer attributes :id, :first_name, :last_name, :email - + belongs_to :company, serializer: CompanySerializer, always_include: true ## OR belongs_to :company, serializer: CompanySerializer, always_include: true, label: 'organization' ##<== important to give singular name - + has_many :comments, serializer: CommentSerializer has_one :account, serializer: AccountSerializer - + def full_name "#{scope.first_name} #{scope.last_name}" end end ``` + ### Conditional Attributes -Serializer can have conditional attributes with `if: Proc` + +Serializer can have conditional attributes with `if: Proc` `if: Proc` block can receive `scope` and `params` as arguments -- __in proc {|scope|}__, scope is object which is being serialized -- __in proc {|scope,params|}__, scope is object which is being serialized and params is hash given to Serializer as second arguments in {params:anything} +- **in proc {|scope|}**, scope is object which is being serialized +- **in proc {|scope,params|}**, scope is object which is being serialized and params is hash given to Serializer as second arguments in {params:anything} + ```ruby # frozen_string_literal: true @@ -124,11 +146,13 @@ UserSerializer.new(user,{params:{show_email:true}}) # With params ``` ### Conditional Relations -Serializer can have conditional relations with `if: Proc` + +Serializer can have conditional relations with `if: Proc` `if: Proc` block can receive `scope` and `params` as arguments -- __in proc {|scope|}__, scope is object which is being serialized -- __in proc {|scope,params|}__, scope is object which is being serialized and params is hash given to Serializer as second arguments in {params:anything} +- **in proc {|scope|}**, scope is object which is being serialized +- **in proc {|scope,params|}**, scope is object which is being serialized and params is hash given to Serializer as second arguments in {params:anything} + ```ruby # frozen_string_literal: true @@ -145,9 +169,11 @@ UserSerializer.new(user) # Without params UserSerializer.new(user,{params:{show_account:true}}) # With params ``` - + ### Attributes Blocks + While writting attribute a block can be provided for useful transformations like `full_name` as shown below + ```ruby # frozen_string_literal: true @@ -159,8 +185,11 @@ class UserSerializer < Mutils::Serialization::BaseSerializer end end ``` + ### Attributes Blocks with Params + While writting attribute a block can be provided for useful transformations like `full_name` as shown below + ```ruby # frozen_string_literal: true @@ -172,6 +201,7 @@ class UserSerializer < Mutils::Serialization::BaseSerializer end end ``` + ```ruby # in controller @@ -179,7 +209,9 @@ user = current_user owner = owner_user render json: UserSerializer.new(user,{params:{owner:owner}}) ``` + ### Custom Methods + Custom methods used in Serializer can be useful for cases as below. `scope` will be available to reference object in Serializer in below case its `user` @@ -193,21 +225,25 @@ class UserSerializer < Mutils::Serialization::BaseSerializer custom_methods :full_name ## OR custom_method :full_name, {always_include: true} ## this will allow to selectively include full_name - ### - + ### + def full_name "#{scope.first_name} #{scope.last_name}" end end ``` + ### Name Tag + name_tag is used to provide custom name to serializer output keys for json -**Options** - - ``name_tag 'Person', true`` # Include Person or People in JSON serialization as root, true|false this only implies to root serializer - - ``name_tag 'Person', false`` # not Include Person or People in JSON serialization as root, true|false this only implies to root serializer - - ``name_tag 'Person'`` # same as ``name_tag 'Person', false`` - - without name_tag, actual class name of scope object inside serializer will be used +#### Options + +- `name_tag 'Person', true` # Include Person or People in JSON serialization as root, true|false this only implies to root serializer +- `name_tag 'Person', false` # not Include Person or People in JSON serialization as root, true|false this only implies to root serializer +- `name_tag 'Person'` # same as `name_tag 'Person', false` +- without name_tag, actual class name of scope object inside serializer will be used + ```ruby # frozen_string_literal: true @@ -216,7 +252,7 @@ class UserSerializer < Mutils::Serialization::BaseSerializer name_tag 'Person', true attributes :id, :first_name, :last_name, :email custom_methods :full_name - + def full_name "#{scope.first_name} #{scope.last_name}" end @@ -230,13 +266,17 @@ user = User.first options = {includes: [:comments,:account]} UserSerializer.new(user,options).to_h ``` -### or + +#### Or + ```ruby users = User.all options = {includes: [:account]} UserSerializer.new(users,options).to_json ``` -### or in controllers + +#### Or In Controllers + ```ruby users = User.all options = {includes: [:account]} diff --git a/SECURITY.md b/SECURITY.md index 10832be..442411b 100755 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,4 +10,4 @@ Versions currently being supported with security updates. ## Reporting a Vulnerability -Create an issue or email at security@codevedas.com +Create an issue or email at diff --git a/Version b/Version deleted file mode 100755 index 3252f64..0000000 --- a/Version +++ /dev/null @@ -1 +0,0 @@ -v1.3.5 diff --git a/danger/Dangerfile b/danger/Dangerfile new file mode 100644 index 0000000..761f9ba --- /dev/null +++ b/danger/Dangerfile @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +# Copyright Codevedas Inc. 2025-present +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# rubocop:disable Style/SignalException +valid_prefixes = %w[feat/ bugfix/ docs/ release/ chore/ refactor/ test/ style/ ci/ perf/ build/ lang/] + +def all_modified_files(git) + all_added = git.added_files + git.modified_files + git.renamed_files.map { |file| file[:after] } + all_removed = git.deleted_files + git.renamed_files.map { |file| file[:before] } + (all_added - all_removed).uniq +end + +modified_files = all_modified_files(git) + +fail('πŸ“ Please include a more detailed description of your change.') if github.pr_body.strip.length < 10 + +if github.branch_for_head && valid_prefixes.none? { |prefix| github.branch_for_head.start_with?(prefix) } + fail("⚠️ PR branch name should start with one of: #{valid_prefixes.join(', ')}") +end + +# pr title should match with prefix minus / and colon +if github.pr_title && valid_prefixes.none? { |prefix| github.pr_title.start_with?("#{prefix.delete_suffix('/')}:") } + fail("⚠️ PR title should start with one of: #{valid_prefixes.map { |p| "#{p.delete_suffix('/')}:" }.join(', ')}") +end + +if modified_files.include?('Gemfile') && !modified_files.include?('Gemfile.lock') + fail('πŸ“¦ Gemfile changed but Gemfile.lock did not. Did you forget to run bundle install?') +end + +modified_files.each do |f| + diff = git.diff_for_file(f) + debug_statements = ['binding.pry', 'binding.b', 'byebug', 'debugger'] + if f.end_with?('.rb') && diff && debug_statements.any? { |stmt| diff.patch.include?(stmt) } + fail("🚫 Do not commit debugging statements like binding.pry, binding.b, byebug, or debugger!. Found in #{f}") + end + + fail("🧹 Remove temporary or system files like #{f}.") if f.end_with?('.swp', '.DS_Store') +end + +if github.branch_for_head&.start_with?('release/') + changelog_modified = modified_files.include?('CHANGELOG.md') + fail('🚨 CHANGELOG.md must be updated in a release branch.') unless changelog_modified +end + +unless modified_files.grep(/\.rb$/).empty? + test_files = modified_files.grep(%r{spec/|test/}) + warn('⚠️ No tests/specs modified. Please ensure tests are updated for any Ruby code changes.') if test_files.empty? +end + +if violation_report[:errors].any? || violation_report[:warnings].any? + message = <<~MSG + --- + ⚠️ You got #{violation_report[:errors].count} error(s) and #{violation_report[:warnings].count} warning(s) in your PR. + πŸ”§ **How to fix and re-trigger:** + Please address the above issues and push your changes. The checks will automatically re-run on each push. + If you want to manually re-run the checks on GitHub, you can do so from the "Actions" tab or the "Checks" section of this PR. + MSG + + markdown(message) +end +# rubocop:enable Style/SignalException diff --git a/danger/Gemfile b/danger/Gemfile new file mode 100644 index 0000000..f959b16 --- /dev/null +++ b/danger/Gemfile @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# Copyright Codevedas Inc. 2025-present +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +source "https://rubygems.org" + +gem "danger", "~> 9.5" +gem "faraday-retry", "~> 2.4" \ No newline at end of file diff --git a/danger/Gemfile.lock b/danger/Gemfile.lock new file mode 100644 index 0000000..36d3013 --- /dev/null +++ b/danger/Gemfile.lock @@ -0,0 +1,107 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (8.1.2.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.9) + public_suffix (>= 2.0.2, < 8.0) + base64 (0.3.0) + bigdecimal (4.0.1) + claide (1.1.0) + claide-plugins (0.9.2) + cork + nap + open4 (~> 1.3) + colored2 (3.1.2) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) + cork (0.3.0) + colored2 (~> 3.1) + danger (9.5.3) + base64 (~> 0.2) + claide (~> 1.0) + claide-plugins (>= 0.9.2) + colored2 (>= 3.1, < 5) + cork (~> 0.1) + faraday (>= 0.9.0, < 3.0) + faraday-http-cache (~> 2.0) + git (>= 1.13, < 3.0) + kramdown (>= 2.5.1, < 3.0) + kramdown-parser-gfm (~> 1.0) + octokit (>= 4.0) + pstore (~> 0.1) + terminal-table (>= 1, < 5) + drb (2.2.3) + faraday (2.14.1) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-http-cache (2.6.1) + faraday (>= 0.8) + faraday-net_http (3.4.2) + net-http (~> 0.5) + faraday-retry (2.4.0) + faraday (~> 2.0) + git (2.3.3) + activesupport (>= 5.0) + addressable (~> 2.8) + process_executer (~> 1.1) + rchardet (~> 1.8) + i18n (1.14.8) + concurrent-ruby (~> 1.0) + json (2.19.2) + kramdown (2.5.2) + rexml (>= 3.4.4) + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + logger (1.7.0) + minitest (6.0.2) + drb (~> 2.0) + prism (~> 1.5) + nap (1.1.0) + net-http (0.9.1) + uri (>= 0.11.1) + octokit (10.0.0) + faraday (>= 1, < 3) + sawyer (~> 0.9) + open4 (1.3.4) + prism (1.9.0) + process_executer (1.3.0) + pstore (0.2.1) + public_suffix (7.0.5) + rchardet (1.10.0) + rexml (3.4.4) + sawyer (0.9.3) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) + securerandom (0.4.1) + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + uri (1.1.1) + +PLATFORMS + arm64-darwin-24 + ruby + +DEPENDENCIES + danger (~> 9.5) + faraday-retry (~> 2.4) + +BUNDLED WITH + 2.7.2 diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..6726c73 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,5 @@ +_site +.sass-cache +.jekyll-cache +.jekyll-metadata +.ruby-lsp diff --git a/docs/.ruby-version b/docs/.ruby-version new file mode 100644 index 0000000..8a0feb9 --- /dev/null +++ b/docs/.ruby-version @@ -0,0 +1 @@ +3.4.3 \ No newline at end of file diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 0000000..e95f215 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,8 @@ +--- +layout: default +title: 404 +permalink: /404.html +nav_exclude: true +--- + +# Page not found The requested page does not exist. diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..c29fe32 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +mutils.codevedas.com diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 0000000..f2322e6 --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# Copyright Codevedas Inc. 2019-present +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +source 'https://rubygems.org' +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve +# +# This will help ensure the proper Jekyll version is running. +# Happy Jekylling! +gem 'jekyll', '~> 3.10.0' +gem 'minima', '~> 2.5' +# If you have any plugins, put them here! +group :jekyll_plugins do + gem 'github-pages', '~> 232' + gem 'just-the-docs', git: 'https://github.com/niteshpurohit/just-the-docs.git' + gem 'kramdown' +end + +platforms :mingw, :x64_mingw, :mswin, :jruby do + gem 'tzinfo', '>= 1', '< 3' + gem 'tzinfo-data' +end + +# Performance-booster for watching directories on Windows +gem 'http_parser.rb', '~> 0.6.0', platforms: [:jruby] +gem 'wdm', '~> 0.1', platforms: %i[mingw x64_mingw mswin] diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock new file mode 100644 index 0000000..2d130a3 --- /dev/null +++ b/docs/Gemfile.lock @@ -0,0 +1,332 @@ +GIT + remote: https://github.com/niteshpurohit/just-the-docs.git + revision: 933dc227584741c30a343cec25a1f315a3153988 + specs: + just-the-docs (0.12.0) + jekyll (>= 3.8.5) + jekyll-include-cache + jekyll-seo-tag (>= 2.0) + rake (>= 12.3.1) + +GEM + remote: https://rubygems.org/ + specs: + activesupport (8.1.2.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + json + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.9) + public_suffix (>= 2.0.2, < 8.0) + base64 (0.3.0) + bigdecimal (4.0.1) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + colorator (1.1.0) + commonmarker (0.23.12) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) + csv (3.3.5) + dnsruby (1.73.1) + base64 (>= 0.2) + logger (~> 1.6) + simpleidn (~> 0.2.1) + drb (2.2.3) + em-websocket (0.5.3) + eventmachine (>= 0.12.9) + http_parser.rb (~> 0) + ethon (0.18.0) + ffi (>= 1.15.0) + logger + eventmachine (1.2.7) + execjs (2.10.0) + faraday (2.14.1) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-net_http (3.4.2) + net-http (~> 0.5) + ffi (1.17.3-aarch64-linux-gnu) + ffi (1.17.3-aarch64-linux-musl) + ffi (1.17.3-arm-linux-gnu) + ffi (1.17.3-arm-linux-musl) + ffi (1.17.3-arm64-darwin) + ffi (1.17.3-x86_64-darwin) + ffi (1.17.3-x86_64-linux-gnu) + ffi (1.17.3-x86_64-linux-musl) + forwardable-extended (2.6.0) + gemoji (4.1.0) + github-pages (232) + github-pages-health-check (= 1.18.2) + jekyll (= 3.10.0) + jekyll-avatar (= 0.8.0) + jekyll-coffeescript (= 1.2.2) + jekyll-commonmark-ghpages (= 0.5.1) + jekyll-default-layout (= 0.1.5) + jekyll-feed (= 0.17.0) + jekyll-gist (= 1.5.0) + jekyll-github-metadata (= 2.16.1) + jekyll-include-cache (= 0.2.1) + jekyll-mentions (= 1.6.0) + jekyll-optional-front-matter (= 0.3.2) + jekyll-paginate (= 1.1.0) + jekyll-readme-index (= 0.3.0) + jekyll-redirect-from (= 0.16.0) + jekyll-relative-links (= 0.6.1) + jekyll-remote-theme (= 0.4.3) + jekyll-sass-converter (= 1.5.2) + jekyll-seo-tag (= 2.8.0) + jekyll-sitemap (= 1.4.0) + jekyll-swiss (= 1.0.0) + jekyll-theme-architect (= 0.2.0) + jekyll-theme-cayman (= 0.2.0) + jekyll-theme-dinky (= 0.2.0) + jekyll-theme-hacker (= 0.2.0) + jekyll-theme-leap-day (= 0.2.0) + jekyll-theme-merlot (= 0.2.0) + jekyll-theme-midnight (= 0.2.0) + jekyll-theme-minimal (= 0.2.0) + jekyll-theme-modernist (= 0.2.0) + jekyll-theme-primer (= 0.6.0) + jekyll-theme-slate (= 0.2.0) + jekyll-theme-tactile (= 0.2.0) + jekyll-theme-time-machine (= 0.2.0) + jekyll-titles-from-headings (= 0.5.3) + jemoji (= 0.13.0) + kramdown (= 2.4.0) + kramdown-parser-gfm (= 1.1.0) + liquid (= 4.0.4) + mercenary (~> 0.3) + minima (= 2.5.1) + nokogiri (>= 1.16.2, < 2.0) + rouge (= 3.30.0) + terminal-table (~> 1.4) + webrick (~> 1.8) + github-pages-health-check (1.18.2) + addressable (~> 2.3) + dnsruby (~> 1.60) + octokit (>= 4, < 8) + public_suffix (>= 3.0, < 6.0) + typhoeus (~> 1.3) + html-pipeline (2.14.3) + activesupport (>= 2) + nokogiri (>= 1.4) + http_parser.rb (0.8.1) + i18n (1.14.8) + concurrent-ruby (~> 1.0) + jekyll (3.10.0) + addressable (~> 2.4) + colorator (~> 1.0) + csv (~> 3.0) + em-websocket (~> 0.5) + i18n (>= 0.7, < 2) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 2.0) + kramdown (>= 1.17, < 3) + liquid (~> 4.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (>= 1.7, < 4) + safe_yaml (~> 1.0) + webrick (>= 1.0) + jekyll-avatar (0.8.0) + jekyll (>= 3.0, < 5.0) + jekyll-coffeescript (1.2.2) + coffee-script (~> 2.2) + coffee-script-source (~> 1.12) + jekyll-commonmark (1.4.0) + commonmarker (~> 0.22) + jekyll-commonmark-ghpages (0.5.1) + commonmarker (>= 0.23.7, < 1.1.0) + jekyll (>= 3.9, < 4.0) + jekyll-commonmark (~> 1.4.0) + rouge (>= 2.0, < 5.0) + jekyll-default-layout (0.1.5) + jekyll (>= 3.0, < 5.0) + jekyll-feed (0.17.0) + jekyll (>= 3.7, < 5.0) + jekyll-gist (1.5.0) + octokit (~> 4.2) + jekyll-github-metadata (2.16.1) + jekyll (>= 3.4, < 5.0) + octokit (>= 4, < 7, != 4.4.0) + jekyll-include-cache (0.2.1) + jekyll (>= 3.7, < 5.0) + jekyll-mentions (1.6.0) + html-pipeline (~> 2.3) + jekyll (>= 3.7, < 5.0) + jekyll-optional-front-matter (0.3.2) + jekyll (>= 3.0, < 5.0) + jekyll-paginate (1.1.0) + jekyll-readme-index (0.3.0) + jekyll (>= 3.0, < 5.0) + jekyll-redirect-from (0.16.0) + jekyll (>= 3.3, < 5.0) + jekyll-relative-links (0.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-remote-theme (0.4.3) + addressable (~> 2.0) + jekyll (>= 3.5, < 5.0) + jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) + rubyzip (>= 1.3.0, < 3.0) + jekyll-sass-converter (1.5.2) + sass (~> 3.4) + jekyll-seo-tag (2.8.0) + jekyll (>= 3.8, < 5.0) + jekyll-sitemap (1.4.0) + jekyll (>= 3.7, < 5.0) + jekyll-swiss (1.0.0) + jekyll-theme-architect (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-cayman (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-dinky (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-hacker (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-leap-day (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-merlot (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-midnight (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-minimal (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-modernist (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-primer (0.6.0) + jekyll (> 3.5, < 5.0) + jekyll-github-metadata (~> 2.9) + jekyll-seo-tag (~> 2.0) + jekyll-theme-slate (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-tactile (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-theme-time-machine (0.2.0) + jekyll (> 3.5, < 5.0) + jekyll-seo-tag (~> 2.0) + jekyll-titles-from-headings (0.5.3) + jekyll (>= 3.3, < 5.0) + jekyll-watch (2.2.1) + listen (~> 3.0) + jemoji (0.13.0) + gemoji (>= 3, < 5) + html-pipeline (~> 2.2) + jekyll (>= 3.0, < 5.0) + json (2.19.2) + kramdown (2.4.0) + rexml + kramdown-parser-gfm (1.1.0) + kramdown (~> 2.0) + liquid (4.0.4) + listen (3.10.0) + logger + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.7.0) + mercenary (0.3.6) + minima (2.5.1) + jekyll (>= 3.5, < 5.0) + jekyll-feed (~> 0.9) + jekyll-seo-tag (~> 2.1) + minitest (6.0.2) + drb (~> 2.0) + prism (~> 1.5) + net-http (0.9.1) + uri (>= 0.11.1) + nokogiri (1.19.2-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.2-aarch64-linux-musl) + racc (~> 1.4) + nokogiri (1.19.2-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.2-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.19.2-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.2-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.19.2-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.2-x86_64-linux-musl) + racc (~> 1.4) + octokit (4.25.1) + faraday (>= 1, < 3) + sawyer (~> 0.9) + pathutil (0.16.2) + forwardable-extended (~> 2.6) + prism (1.9.0) + public_suffix (5.1.1) + racc (1.8.1) + rake (13.3.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rexml (3.4.4) + rouge (3.30.0) + rubyzip (2.4.1) + safe_yaml (1.0.5) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sawyer (0.9.3) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) + securerandom (0.4.1) + simpleidn (0.2.3) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + typhoeus (1.6.0) + ethon (>= 0.18.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (1.8.0) + uri (1.1.1) + webrick (1.9.2) + +PLATFORMS + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl + +DEPENDENCIES + github-pages (~> 232) + http_parser.rb (~> 0.6.0) + jekyll (~> 3.10.0) + just-the-docs! + kramdown + minima (~> 2.5) + tzinfo (>= 1, < 3) + tzinfo-data + wdm (~> 0.1) + +BUNDLED WITH + 2.7.2 diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..b414138 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,33 @@ +title: Mutils +description: >- + Mutils is a small Ruby serializer DSL for building explicit JSON output in Ruby and Rails apps. +baseurl: "" +domain: mutils.codevedas.com +repository: Code-Vedas/mutils +# Build settings +theme: just-the-docs +plugins: + - jekyll-feed + - kramdown +mermaid: + version: 10.1.0 +logo: /assets/images/logo.svg +callouts: + note: + title: Note + color: blue +toc: + depth: 2 + min_heading_level: 2 + max_heading_level: 3 +aux_links: + - title: " πŸŒ™ / β˜€οΈ " + url: javascript:toggleTheme(); + new_tab: false + - title: Repository + url: https://github.com/Code-Vedas/mutils + new_tab: true +aux_links_new_tab: true +nav_enabled: true +heading_anchors: true +enable_copy_code_button: true diff --git a/docs/_includes/footer_custom.html b/docs/_includes/footer_custom.html new file mode 100644 index 0000000..a2bfcff --- /dev/null +++ b/docs/_includes/footer_custom.html @@ -0,0 +1,98 @@ +

+ + + CI + + + License + + + GitHub Repository + + + Open Issues + + + Code Coverage + + + Maintainability + + +

+

+ + Copyright © 2019-present Codevedas Inc. Distributed under the + MIT license. + +
+ + GitHub + | + Issues + | + Changelog + | + License + +

diff --git a/docs/_includes/head_custom.html b/docs/_includes/head_custom.html new file mode 100644 index 0000000..f185c3a --- /dev/null +++ b/docs/_includes/head_custom.html @@ -0,0 +1,32 @@ + + diff --git a/docs/assets/css/just-the-docs-dark.scss b/docs/assets/css/just-the-docs-dark.scss new file mode 100644 index 0000000..ac92fb1 --- /dev/null +++ b/docs/assets/css/just-the-docs-dark.scss @@ -0,0 +1,3 @@ +--- +--- +{% include css/just-the-docs.scss.liquid color_scheme="dark" %} diff --git a/docs/assets/css/just-the-docs-light.scss b/docs/assets/css/just-the-docs-light.scss new file mode 100644 index 0000000..ac69688 --- /dev/null +++ b/docs/assets/css/just-the-docs-light.scss @@ -0,0 +1,3 @@ +--- +--- +{% include css/just-the-docs.scss.liquid color_scheme="light" %} diff --git a/docs/assets/images/favicon.svg b/docs/assets/images/favicon.svg new file mode 100644 index 0000000..e6e7a08 --- /dev/null +++ b/docs/assets/images/favicon.svg @@ -0,0 +1,28 @@ + + + + + + + + M> + \ No newline at end of file diff --git a/docs/assets/images/logo.svg b/docs/assets/images/logo.svg new file mode 100644 index 0000000..bc936db --- /dev/null +++ b/docs/assets/images/logo.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..a4db6d9 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,67 @@ +--- +layout: default +title: Home +nav_order: 1 +--- + +# Mutils + +{: .note } + +> Mutils is a focused serializer DSL for Ruby and Rails apps. It gives you explicit control over attributes, computed fields, relationships, and JSON root naming without depending on Active Model Serializers. + +Mutils centers on one job: turn Ruby objects into predictable hashes or JSON with a small class-based API. + +## What it provides + +- attribute declarations for model fields +- computed serializer methods +- block-based fields with access to `params` +- `has_many`, `has_one`, and `belongs_to` relationships +- conditional inclusion with `if: proc` +- selective field loading with `includes:` +- optional JSON root keys with `name_tag` +- a Rails generator for serializer scaffolding + +## Quick start + +```ruby +gem "mutils" +``` + +```bash +bundle install +``` + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name + custom_methods :full_name + + def full_name + "#{scope.first_name} #{scope.last_name}" + end +end +``` + +```ruby +UserSerializer.new(user).to_h +# => { id: 1, first_name: "Ada", last_name: "Lovelace", full_name: "Ada Lovelace" } +``` + +## Core ideas + +- `attributes` are always included by default +- `attribute` is opt-in by default unless `always_include: true` +- `custom_methods` are always included by default +- `custom_method` is opt-in by default unless `always_include: true` +- relationships are opt-in by default unless `always_include: true` + +That split is intentional: bulk declarations default to "include now", while single declarations are useful for optional fields. + +## Links + +- [Overview & Motivation](./overview) +- [Installation](./install) +- [Usage](./usage) +- [FAQ / Troubleshooting](./faq) diff --git a/docs/pages/101-faq.md b/docs/pages/101-faq.md new file mode 100644 index 0000000..c98ce3f --- /dev/null +++ b/docs/pages/101-faq.md @@ -0,0 +1,84 @@ +--- +title: FAQ / Troubleshooting +nav_order: 101 +permalink: /faq +--- + +# FAQ / Troubleshooting + +## Can I use Mutils without Rails? + +Yes. Runtime serialization only requires `require "mutils"`. + +## Do I need a serializer for relationships? + +Yes. `belongs_to`, `has_one`, and `has_many` require `serializer:`. + +If you omit it, Mutils raises an error when the serializer class is defined. + +## Why is a field missing from the output? + +Check which declaration you used: + +- `attributes` are included by default +- `custom_methods` are included by default +- `attribute` is optional by default +- `custom_method` is optional by default +- relationships are optional by default + +For optional entries, pass `includes:` or set `always_include: true`. + +## Why is my conditional field missing? + +Check: + +- your `if:` value is a `Proc` +- the proc logic matches the object being serialized +- any expected `params:` were passed to the serializer + +Example: + +```ruby +UserSerializer.new(user, params: { show_email: true }).to_h +``` + +## Why did Mutils raise `if: should be a Proc object`? + +Because `if:` only accepts a proc: + +```ruby +attribute :email, if: proc { |scope| scope.admin? } +``` + +## What does `scope` refer to? + +`scope` is the object currently being serialized. Inside serializer instance methods, use `scope` to read values from that object. + +## What happens when I pass a collection? + +`to_h` returns an array of serialized entries. `as_json` can wrap the collection in a pluralized root key if root wrapping is enabled. + +## Why is the root key singular or plural? + +Mutils uses: + +- the configured `name_tag`, if present +- otherwise the serialized object's class name + +For collections, it pluralizes the chosen name. + +## Why is my renamed relationship not included with `includes:`? + +Use the original relationship name in `includes:`, not the `label:` value. + +Example: + +```ruby +belongs_to :company, serializer: CompanySerializer, label: "organization" +``` + +Request it with: + +```ruby +UserSerializer.new(user, includes: [:company]).to_h +``` diff --git a/docs/pages/2-overview.md b/docs/pages/2-overview.md new file mode 100644 index 0000000..c01af81 --- /dev/null +++ b/docs/pages/2-overview.md @@ -0,0 +1,95 @@ +--- +title: Overview & Motivation +nav_order: 2 +permalink: /overview +--- + +# Overview & Motivation + +Mutils is a serializer library for Ruby objects. You define a serializer class, list the fields you want, and call `to_h`, `as_json`, or `to_json`. + +It is designed for cases where you want: + +- explicit serialized output +- serializer-local computed fields +- lightweight conditional inclusion +- straightforward relationship nesting +- a smaller surface area than larger serializer frameworks + +## What it owns + +Mutils handles: + +- collecting scalar fields from the serialized object +- running serializer instance methods as computed fields +- evaluating block-based fields +- nesting related serializers +- producing hash and JSON output +- optional wrapping of the root object under a root key + +## What it does not try to do + +Mutils does not own: + +- controller integration +- caching strategy +- pagination metadata +- JSON:API formatting +- automatic preload or query optimization + +Those concerns stay in your application code. + +## Main serializer shape + +Every serializer inherits from `Mutils::Serialization::BaseSerializer`: + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :email +end +``` + +The serializer receives: + +- the object or collection to serialize +- an optional options hash such as `includes:` or `params:` + +Example: + +```ruby +UserSerializer.new(user).to_h +UserSerializer.new(user, includes: [:account]).to_json +UserSerializer.new(user, params: { current_user: current_user }).as_json +``` + +## Collections + +Passing a collection returns an array from `to_h` and `as_json` unless you explicitly enable a root wrapper through `name_tag`. + +```ruby +UserSerializer.new(users).to_h +# => [{...}, {...}] +``` + +## Root keys + +By default, `as_json` returns the serialized hash directly. + +It wraps the top-level output only when `include_root` is enabled through `name_tag`. + +```ruby +UserSerializer.new(user).as_json +# => { id: 1, email: "ada@example.com" } +``` + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + name_tag "user", true + attributes :id, :email +end + +UserSerializer.new(user).as_json +# => { "user" => { id: 1, email: "ada@example.com" } } +``` + +If you want to control that behavior, use `name_tag`. See [Usage](/usage). diff --git a/docs/pages/3-install.md b/docs/pages/3-install.md new file mode 100644 index 0000000..25ba399 --- /dev/null +++ b/docs/pages/3-install.md @@ -0,0 +1,61 @@ +--- +title: Installation +nav_order: 3 +permalink: /install +--- + +# Installation + +## Gemfile + +Add Mutils to your application: + +```ruby +gem "mutils" +``` + +Install dependencies: + +```bash +bundle install +``` + +## Rails generator + +If you are using Rails, Mutils ships with a serializer generator: + +```bash +bundle exec rails generate mutils:serializer User id first_name last_name email +``` + +This creates: + +```text +app/serializers/user_serializer.rb +``` + +Generated example: + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email +end +``` + +## Plain Ruby setup + +You can also use Mutils directly in plain Ruby: + +```ruby +require "mutils" + +class User + attr_accessor :id, :first_name, :last_name +end + +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name +end +``` + +No Rails dependency is required for runtime serialization. diff --git a/docs/pages/5-usage.md b/docs/pages/5-usage.md new file mode 100644 index 0000000..2c62ce0 --- /dev/null +++ b/docs/pages/5-usage.md @@ -0,0 +1,252 @@ +--- +title: Usage +nav_order: 5 +permalink: /usage +--- + +# Usage + +## Basic attributes + +Use `attributes` when fields should always be included. + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email +end +``` + +```ruby +UserSerializer.new(user).to_h +``` + +## Optional single attributes + +Use `attribute` for a single field that should be opt-in unless you set `always_include: true`. + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name + attribute :email +end +``` + +```ruby +UserSerializer.new(user).to_h +# => { id: 1, first_name: "Ada" } + +UserSerializer.new(user, includes: [:email]).to_h +# => { id: 1, first_name: "Ada", email: "ada@example.com" } +``` + +This also works with a proc shorthand: + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attribute :object_id, &:id +end +``` + +## Computed methods + +Use `custom_methods` for computed fields that should always be included. + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :first_name, :last_name + custom_methods :full_name + + def full_name + "#{scope.first_name} #{scope.last_name}" + end +end +``` + +Use `custom_method` for an opt-in computed field: + +```ruby +class HouseSerializer < Mutils::Serialization::BaseSerializer + custom_method :house_tag + + def house_tag + "#{scope.name}--#{scope.number}" + end +end +``` + +```ruby +HouseSerializer.new(house, includes: [:house_tag]).to_h +``` + +## Block attributes + +Use a block when the serialized value is easiest to express inline. + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :first_name, :last_name + + attribute :full_name do |user| + "#{user.first_name} #{user.last_name}" + end +end +``` + +If you pass `params:`, the block can receive them as the second argument: + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attribute :is_owner do |user, params| + params[:owner].id == user.id + end +end + +UserSerializer.new(user, params: { owner: current_user }).to_h +``` + +## Conditional inclusion + +Both attributes and relationships accept `if: proc`. + +The proc can take: + +- `|scope|` +- `|scope, params|` + +Example: + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name + attribute :email, if: proc { |scope, params| params[:show_email] == true } +end + +UserSerializer.new(user).to_h +UserSerializer.new(user, params: { show_email: true }).to_h +``` + +## Relationships + +Mutils supports `belongs_to`, `has_one`, and `has_many`. + +Every relationship must declare a serializer: + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name + + belongs_to :company, serializer: CompanySerializer, always_include: true + has_one :account, serializer: AccountSerializer + has_many :comments, serializer: CommentSerializer +end +``` + +Relationship inclusion rules: + +- relationships are opt-in by default +- set `always_include: true` to include them every time +- use `includes:` to request optional relationships + +```ruby +UserSerializer.new(user, includes: [:account, :comments]).to_h +``` + +## Relationship labels + +Use `label:` to rename the serialized key: + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + belongs_to :company, serializer: CompanySerializer, label: "organization" +end +``` + +The output key becomes `:organization`. + +For collections, Mutils pluralizes the label automatically. + +## Root naming + +Use `name_tag` to control the root key used by `as_json` and `to_json`. + +```ruby +class UserSerializer < Mutils::Serialization::BaseSerializer + name_tag "person", true + attributes :id, :first_name +end +``` + +```ruby +UserSerializer.new(user).as_json +# => { "person" => { ... } } +``` + +Common forms: + +- `name_tag "person", true` + include a root key on the top-level serializer +- `name_tag "person", false` + set the serializer name but do not wrap the top-level output +- `name_tag "person"` + same as `false` +- no `name_tag` + use the serialized object's class name + +For collections with a root key, Mutils pluralizes the configured name. + +## Output methods + +Use the output method that matches your call site: + +- `to_h` + returns a Ruby hash or array +- `as_json` + returns a hash, optionally wrapped with a root key at the top level +- `to_json` + returns a JSON string + +Examples: + +```ruby +UserSerializer.new(user).to_h +UserSerializer.new(user).as_json +UserSerializer.new(user).to_json +UserSerializer.new(users).to_h +``` + +## Complete example + +```ruby +class CountrySerializer < Mutils::Serialization::BaseSerializer + attributes :name +end + +class HouseSerializer < Mutils::Serialization::BaseSerializer + custom_methods :house_tag + + def house_tag + "#{scope.name}--#{scope.number}" + end +end + +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :first_name, :last_name + custom_methods :full_name + has_many :houses, serializer: HouseSerializer, always_include: true + belongs_to :country, serializer: CountrySerializer, always_include: true + attribute :object_id, &:id + + def full_name + "#{scope.first_name} #{scope.last_name}" + end +end + +UserSerializer.new(user).to_h +UserSerializer.new(user, includes: [:object_id]).to_json +``` + +## Notes + +- `includes:` matches the declared field name, not the renamed `label:` +- nested relationship serializers run independently with their own serializer declarations +- passing a collection to the serializer returns an array from `to_h` diff --git a/lib/mutils/serialization/methods/relations.rb b/lib/mutils/serialization/methods/relations.rb deleted file mode 100755 index 93c0374..0000000 --- a/lib/mutils/serialization/methods/relations.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -# Module Mutils -module Mutils - # Module SerializationCore - module Serialization - # Module Methods - module Methods - # Module Relations - module Relations - def relationship(relationship_name, options = {}) - if options[:if] && !options[:if].instance_of?(Proc) - raise "if: should be a Proc object for attribute #{relationship_name}" - end - - options = prepare_options(relationship_name, options, __callee__) - self.relationships = {} if relationships.nil? - relationships[relationship_name] = options - end - - alias belongs_to relationship - alias has_many relationship - alias has_one relationship - - def prepare_options(relationship_name, options, option_name) - class_name = options[:serializer] - if class_name.nil? - raise "Serializer is Required for belongs_to :#{relationship_name}." \ - "\nDefine it like:\n#{option_name} :#{relationship_name}, " \ - 'serializer: SERIALIZER_CLASS' - end - raise "Serializer class not defined for relationship: #{relationship_name}" unless class_exists? class_name - - options[:serializer] = class_name.to_s - options[:always_include] = options[:always_include].nil? ? false : options[:always_include] - options[:label] = Lib::Helper.instance.underscore options[:label] || relationship_name - options - end - end - end - end -end diff --git a/mutils.gemspec b/mutils.gemspec deleted file mode 100755 index 8d80a31..0000000 --- a/mutils.gemspec +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -lib = File.expand_path('lib', __dir__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'mutils/version' - -Gem::Specification.new do |spec| - spec.name = 'mutils' - spec.version = Mutils::VERSION - spec.authors = ['Nitesh Purohit'] - spec.email = ['nitesh.purohit.it@gmail.com'] - - spec.summary = 'mutils Utilities for rails app' - spec.description = 'mutils Utilities for rails app' - spec.homepage = 'https://github.com/code-vedas/mutils' - spec.license = 'MIT' - spec.files = Dir.chdir(File.expand_path(__dir__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - end - spec.bindir = 'exe' - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } - spec.require_paths = ['lib'] - spec.required_ruby_version = '>= 3.2' - spec.add_dependency('dry-inflector') - - spec.metadata = { - 'bug_tracker_uri' => 'https://github.com/code-vedas/mutils/issues', - 'source_code_uri' => 'https://github.com/Code-Vedas/mutils.git', - 'homepage_uri' => 'https://github.com/code-vedas/mutils', - 'rubygems_mfa_required' => 'true' - } -end diff --git a/mutils/.gitignore b/mutils/.gitignore new file mode 100755 index 0000000..65d4858 --- /dev/null +++ b/mutils/.gitignore @@ -0,0 +1,15 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ + +# rspec failure tracking +.rspec_status +.idea/* +*.gem +/node_modules +.DS_Store diff --git a/mutils/.reek.yml b/mutils/.reek.yml new file mode 100644 index 0000000..dc6d5c8 --- /dev/null +++ b/mutils/.reek.yml @@ -0,0 +1,46 @@ +--- +detectors: + UncommunicativeVariableName: + accept: + - e + - t + - _ + TooManyStatements: + enabled: true + max_statements: 20 + TooManyMethods: + enabled: true + max_methods: 40 + BooleanParameter: + enabled: false + ControlParameter: + enabled: false + TooManyConstants: + enabled: true + max_constants: 40 + LongParameterList: + enabled: false + TooManyInstanceVariables: + enabled: true + max_instance_variables: 10 + DataClump: + enabled: false + DuplicateMethodCall: + enabled: false + ManualDispatch: + enabled: false + NilCheck: + enabled: false + UtilityFunction: + enabled: false + IrresponsibleModule: + enabled: false + Attribute: + exclude: + - Mutils::Serialization::SerializationIncludes#self.included +exclude_paths: + - spec/**/* + - db/**/* + - bin/* + - config/**/* + - vendor/**/* diff --git a/mutils/.rspec b/mutils/.rspec new file mode 100755 index 0000000..ef66ca3 --- /dev/null +++ b/mutils/.rspec @@ -0,0 +1,4 @@ +--require spec_helper +--color +--format progress +--order random diff --git a/mutils/.rubocop.yml b/mutils/.rubocop.yml new file mode 100644 index 0000000..8ec208d --- /dev/null +++ b/mutils/.rubocop.yml @@ -0,0 +1,46 @@ +plugins: + - rubocop-rspec + - rubocop-performance + - rubocop-rake +AllCops: + NewCops: enable + TargetRubyVersion: 3.2 + SuggestExtensions: true + Exclude: + - .vscode/**/* + - vendor/**/* + - vendor/bundle/**/* +Metrics/MethodLength: + Max: 40 +Metrics/ModuleLength: + Max: 350 +Metrics/BlockLength: + Max: 250 +Metrics/ParameterLists: + Max: 10 +RSpec/MultipleExpectations: + Max: 40 +RSpec/ExampleLength: + Max: 80 +Layout/LineLength: + Max: 160 +Metrics/ClassLength: + Max: 220 +Metrics/AbcSize: + Max: 35 +RSpec/MultipleMemoizedHelpers: + Max: 15 +Metrics/CyclomaticComplexity: + Max: 12 +RSpec/NestedGroups: + Max: 5 +Metrics/PerceivedComplexity: + Max: 16 +Style/MutableConstant: + Enabled: false +Style/RedundantReturn: + Enabled: false +Style/TrivialAccessors: + Enabled: false +Style/OneClassPerFile: + Enabled: false diff --git a/.ruby-version b/mutils/.ruby-version similarity index 100% rename from .ruby-version rename to mutils/.ruby-version diff --git a/mutils/Gemfile b/mutils/Gemfile new file mode 100644 index 0000000..e3852a5 --- /dev/null +++ b/mutils/Gemfile @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gemspec + +group :development, :test do + gem 'benchmark' + gem 'json' + gem 'reek' + gem 'rspec' + gem 'rspec-benchmark' + gem 'rspec-json_expectations' + gem 'rubocop-factory_bot' + gem 'rubocop-performance' + gem 'rubocop-rake' + gem 'rubocop-rspec' +end + +group :test do + gem 'simplecov', require: false + gem 'simplecov-console', require: false +end + +group :development do + gem 'ruby-lsp', require: false + gem 'ruby-lsp-rspec', require: false +end diff --git a/mutils/Gemfile.lock b/mutils/Gemfile.lock new file mode 100644 index 0000000..f809915 --- /dev/null +++ b/mutils/Gemfile.lock @@ -0,0 +1,168 @@ +PATH + remote: . + specs: + mutils (1.3.5) + dry-inflector + +GEM + remote: https://rubygems.org/ + specs: + ansi (1.5.0) + ast (2.4.3) + benchmark (0.5.0) + benchmark-malloc (0.2.0) + benchmark-perf (0.6.0) + benchmark-trend (0.4.0) + bigdecimal (4.1.0) + bigdecimal (4.1.0-java) + concurrent-ruby (1.3.6) + diff-lcs (1.6.2) + docile (1.4.1) + dry-configurable (1.3.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-core (1.2.0) + concurrent-ruby (~> 1.0) + logger + zeitwerk (~> 2.6) + dry-inflector (1.3.1) + dry-initializer (3.2.0) + dry-logic (1.6.0) + bigdecimal + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-schema (1.16.0) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.1) + dry-initializer (~> 3.2) + dry-logic (~> 1.6) + dry-types (~> 1.9, >= 1.9.1) + zeitwerk (~> 2.6) + dry-types (1.9.1) + bigdecimal (>= 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) + json (2.19.3) + json (2.19.3-java) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) + logger (1.7.0) + parallel (1.27.0) + parser (3.3.11.1) + ast (~> 2.4.1) + racc + prism (1.9.0) + racc (1.8.1) + racc (1.8.1-java) + rainbow (3.1.1) + rbs (4.0.2) + logger + prism (>= 1.6.0) + tsort + reek (6.5.0) + dry-schema (~> 1.13) + logger (~> 1.6) + parser (~> 3.3.0) + rainbow (>= 2.0, < 4.0) + rexml (~> 3.1) + regexp_parser (2.11.3) + rexml (3.4.4) + rspec (3.13.2) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-benchmark (0.6.0) + benchmark-malloc (~> 0.2) + benchmark-perf (~> 0.6) + benchmark-trend (~> 0.4) + rspec (>= 3.0) + rspec-core (3.13.6) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-json_expectations (2.2.0) + rspec-mocks (3.13.8) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.7) + rubocop (1.86.0) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.49.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.49.1) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-factory_bot (2.28.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-performance (1.26.1) + lint_roller (~> 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.47.1, < 2.0) + rubocop-rake (0.7.1) + lint_roller (~> 1.1) + rubocop (>= 1.72.1) + rubocop-rspec (3.9.0) + lint_roller (~> 1.1) + rubocop (~> 1.81) + ruby-lsp (0.26.9) + language_server-protocol (~> 3.17.0) + prism (>= 1.2, < 2.0) + rbs (>= 3, < 5) + ruby-lsp-rspec (0.1.29) + ruby-lsp (~> 0.26.0) + ruby-progressbar (1.13.0) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-console (0.9.5) + ansi + simplecov + terminal-table + simplecov-html (0.13.2) + simplecov_json_formatter (0.1.4) + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) + tsort (0.2.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + zeitwerk (2.7.5) + +PLATFORMS + java + ruby + +DEPENDENCIES + benchmark + json + mutils! + reek + rspec + rspec-benchmark + rspec-json_expectations + rubocop-factory_bot + rubocop-performance + rubocop-rake + rubocop-rspec + ruby-lsp + ruby-lsp-rspec + simplecov + simplecov-console + +BUNDLED WITH + 2.5.6 diff --git a/LICENSE.txt b/mutils/LICENSE similarity index 85% rename from LICENSE.txt rename to mutils/LICENSE index 32ab165..ddb1ac5 100755 --- a/LICENSE.txt +++ b/mutils/LICENSE @@ -1,6 +1,6 @@ -The MIT License (MIT) +MIT License -Copyright (c) 2019 Nitesh Purohit +Copyright (c) 2019-present Codevedas Inc. and the Mutils Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mutils/README.md b/mutils/README.md new file mode 100755 index 0000000..a9c8e17 --- /dev/null +++ b/mutils/README.md @@ -0,0 +1,301 @@ +# Mutils + +[![Maintainability](https://api.codeclimate.com/v1/badges/42e8a34f839ca0c5ec45/maintainability)](https://codeclimate.com/github/code-vedas/mutils/maintainability) +![Ruby gem downloads](https://ruby-gem-downloads-badge.herokuapp.com/mutils?type=total&color=brightgreen) +[![Gem Version](https://badge.fury.io/rb/mutils.svg)](https://badge.fury.io/rb/mutils) +[![Coverage Status](https://badge.coveralls.io/repos/github/Code-Vedas/mutils/badge.svg?branch=master)](https://badge.coveralls.io/github/Code-Vedas/mutils?branch=master) + +## Introduction + +`mutils` is collection of useful modules for `ruby on rails` which is tested and benchmarked against high load. + +These collection of modules are built by developer for developers :-) + +## Table of Contents + +- [Features](#features) +- [Installation](#installation) +- [Usage](#usage) + - [Rails Generator](#rails-generator) + - [Attributes](#attributes) + - [Relations](#relations) + - [Conditional Attributes](#conditional-attributes) + - [Conditional Relations](#conditional-relations) + - [Attributes Block](#attributes-blocks) + - [Attributes Block with Params](#attributes-blocks-with-params) + - [Custom Methods](#custom-methods) + - [Name Tag](#name-tag) + - [Sample Usage](#sample-usage) + +## Features + +- Simple declaration syntax similar to Active Model Serializer +- Relationships support `belongs_to`, `has_many`, `has_one` +- Block style attributes with params + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'mutils' +``` + +And then execute: + +```bash +bundle install +``` + +Or install it yourself as: + +```bash +gem install mutils +``` + +## Usage + +### Rails Generator + +```shell script +rails g mutils:serializer User id first_name last_name email + +OUTPUT +Running via Spring preloader in process xxxxx + create app/serializers/user_serializer.rb +``` + +You will get serializer in app/serializers/user_serializer.rb + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email +end +``` + +### Attributes + +Attributes are fields in the model itself. You can reference them by below example + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email + ## OR + attribute :email, {always_include: true} ## this will allow to selectively include email + ## OR + attribute :email, &:email ## this will call email attribute from User +end +``` + +### Relations + +Relations such as `has_many`, `belongs_to`, `has_one` can be used as follows + +1. Every relation must be provided with their own serializer +2. `always_include` option can be used to instruct `Serializer` to always include this relation +3. `always_include` by default is disabled, relations which are not `always_include` can be included while using the serializer. Refer to next section for this usage +4. `label` option can be used to override model class name while serializing + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email + + belongs_to :company, serializer: CompanySerializer, always_include: true + ## OR + belongs_to :company, serializer: CompanySerializer, always_include: true, label: 'organization' ##<== important to give singular name + + has_many :comments, serializer: CommentSerializer + has_one :account, serializer: AccountSerializer + + def full_name + "#{scope.first_name} #{scope.last_name}" + end +end +``` + +### Conditional Attributes + +Serializer can have conditional attributes with `if: Proc` +`if: Proc` block can receive `scope` and `params` as arguments + +- **in proc {|scope|}**, scope is object which is being serialized +- **in proc {|scope,params|}**, scope is object which is being serialized and params is hash given to Serializer as second arguments in {params:anything} + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name + attribute :email, if: proc { |scope| scope.name == 'mutils' } ## Email will only serialize if user's name is 'mutils' + # OR with Params + attribute :email, if: proc { |scope,params| params && params[:show_email] == true } ## Email will only serialize if params[:show_email] is true +end + +UserSerializer.new(user) # Without params +UserSerializer.new(user,{params:{show_email:true}}) # With params +``` + +### Conditional Relations + +Serializer can have conditional relations with `if: Proc` +`if: Proc` block can receive `scope` and `params` as arguments + +- **in proc {|scope|}**, scope is object which is being serialized +- **in proc {|scope,params|}**, scope is object which is being serialized and params is hash given to Serializer as second arguments in {params:anything} + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name + has_many :comments, serializer: CommentSerializer, if: proc { |scope| scope.name == 'mutils' } ## comments will only serialize if user's name is 'mutils' + belongs_to :account, serializer: AccountSerializer, if: proc { |scope| scope.name != 'mutils' } ## account will only serialize if user's name is not 'mutils' + # OR with Params + belongs_to :account, serializer: AccountSerializer, if: proc { |scope,params| params && params[:show_account] == true } ## account will only serialize if params[:show_account] is true +end + +UserSerializer.new(user) # Without params +UserSerializer.new(user,{params:{show_account:true}}) # With params + +``` + +### Attributes Blocks + +While writing attribute a block can be provided for useful transformations like `full_name` as shown below + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email + attribute :full_name do |object| + "#{object.first_name} #{object.last_name}" + end +end +``` + +### Attributes Blocks with Params + +While writing attribute a block can be provided for useful transformations like `full_name` as shown below + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email + attribute :is_owner do |object,params| + params[:owner].id == object.id ? true:false + end +end +``` + +```ruby +# in controller + +user = current_user +owner = owner_user +render json: UserSerializer.new(user,{params:{owner:owner}}) +``` + +### Custom Methods + +Custom methods used in Serializer can be useful for cases as below. +`scope` will be available to reference object in Serializer in below case its `user` + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + attributes :id, :first_name, :last_name, :email + ### + custom_methods :full_name + ## OR + custom_method :full_name, {always_include: true} ## this will allow to selectively include full_name + ### + + def full_name + "#{scope.first_name} #{scope.last_name}" + end +end +``` + +### Name Tag + +name_tag is used to provide custom name to serializer output keys for json + +#### Options + +- `name_tag 'Person', true` # Include Person or People in JSON serialization as root, true|false this only implies to root serializer +- `name_tag 'Person', false` # not Include Person or People in JSON serialization as root, true|false this only implies to root serializer +- `name_tag 'Person'` # same as `name_tag 'Person', false` +- without name_tag, actual class name of scope object inside serializer will be used + +```ruby +# frozen_string_literal: true + +# User Serializer +class UserSerializer < Mutils::Serialization::BaseSerializer + name_tag 'Person', true + attributes :id, :first_name, :last_name, :email + custom_methods :full_name + + def full_name + "#{scope.first_name} #{scope.last_name}" + end +end +``` + +### Sample Usage + +```ruby +user = User.first +options = {includes: [:comments,:account]} +UserSerializer.new(user,options).to_h +``` + +#### Or + +```ruby +users = User.all +options = {includes: [:account]} +UserSerializer.new(users,options).to_json +``` + +#### Or In Controllers + +```ruby +users = User.all +options = {includes: [:account]} +users_serializer =UserSerializer.new(users,options) +render json: users_serializer +``` + +## Contributing + +Bug Reports and PR's are welcomed in this repository kindly follow guidelines from `.github` directory. + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). + +## Code of Conduct + +Everyone interacting in the Mutils project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/code-vedas/mutils/blob/master/CODE_OF_CONDUCT.md). + +## Security + +For security refer to [security](https://github.com/Code-Vedas/mutils/blob/master/SECURITY.md) document. diff --git a/Rakefile b/mutils/Rakefile similarity index 100% rename from Rakefile rename to mutils/Rakefile diff --git a/bin/console b/mutils/bin/console similarity index 100% rename from bin/console rename to mutils/bin/console diff --git a/mutils/bin/reek b/mutils/bin/reek new file mode 100755 index 0000000..acdb187 --- /dev/null +++ b/mutils/bin/reek @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Copyright Codevedas Inc. 2019-present +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +require 'pty' + +root_dir = File.expand_path('..', __dir__) +Dir.chdir(root_dir) + +command = ['bundle', 'exec', 'reek', *ARGV] +output = +'' +status = nil + +PTY.spawn(*command) do |reader, _writer, pid| + reader.each { |line| output << line } +rescue Errno::EIO + nil +ensure + _, status = Process.wait2(pid) +end + +print(output.gsub("\r\n", "\n")) +exit(status.exitstatus || 1) diff --git a/bin/rspec b/mutils/bin/rspec similarity index 81% rename from bin/rspec rename to mutils/bin/rspec index b79c4d1..98f9262 100755 --- a/bin/rspec +++ b/mutils/bin/rspec @@ -1,6 +1,10 @@ #!/usr/bin/env ruby # frozen_string_literal: true +# Copyright Codevedas Inc. 2019-present +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. # # This file was generated by Bundler. # diff --git a/bin/rubocop b/mutils/bin/rubocop similarity index 81% rename from bin/rubocop rename to mutils/bin/rubocop index 786dcf0..15f9ab7 100755 --- a/bin/rubocop +++ b/mutils/bin/rubocop @@ -1,6 +1,10 @@ #!/usr/bin/env ruby # frozen_string_literal: true +# Copyright Codevedas Inc. 2019-present +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. # # This file was generated by Bundler. # diff --git a/bin/setup b/mutils/bin/setup similarity index 100% rename from bin/setup rename to mutils/bin/setup diff --git a/lib/generators/mutils/USAGE b/mutils/lib/generators/mutils/USAGE similarity index 100% rename from lib/generators/mutils/USAGE rename to mutils/lib/generators/mutils/USAGE diff --git a/lib/generators/mutils/serializer_generator.rb b/mutils/lib/generators/mutils/serializer_generator.rb similarity index 100% rename from lib/generators/mutils/serializer_generator.rb rename to mutils/lib/generators/mutils/serializer_generator.rb diff --git a/lib/generators/mutils/templates/serializer.rb.tt b/mutils/lib/generators/mutils/templates/serializer.rb.tt similarity index 100% rename from lib/generators/mutils/templates/serializer.rb.tt rename to mutils/lib/generators/mutils/templates/serializer.rb.tt diff --git a/lib/mutils.rb b/mutils/lib/mutils.rb similarity index 100% rename from lib/mutils.rb rename to mutils/lib/mutils.rb diff --git a/lib/mutils/lib/helper.rb b/mutils/lib/mutils/lib/helper.rb similarity index 100% rename from lib/mutils/lib/helper.rb rename to mutils/lib/mutils/lib/helper.rb diff --git a/lib/mutils/lib/result_hash.rb b/mutils/lib/mutils/lib/result_hash.rb similarity index 100% rename from lib/mutils/lib/result_hash.rb rename to mutils/lib/mutils/lib/result_hash.rb diff --git a/lib/mutils/serialization/base_serializer.rb b/mutils/lib/mutils/serialization/base_serializer.rb similarity index 100% rename from lib/mutils/serialization/base_serializer.rb rename to mutils/lib/mutils/serialization/base_serializer.rb diff --git a/lib/mutils/serialization/methods/attributes.rb b/mutils/lib/mutils/serialization/methods/attributes.rb similarity index 91% rename from lib/mutils/serialization/methods/attributes.rb rename to mutils/lib/mutils/serialization/methods/attributes.rb index af34eff..9ca95ce 100755 --- a/lib/mutils/serialization/methods/attributes.rb +++ b/mutils/lib/mutils/serialization/methods/attributes.rb @@ -25,9 +25,7 @@ def parse_attributes_methods(list, is_method) end def attribute(method_name, options = {}, &proc) - if options[:if] && !options[:if].instance_of?(Proc) - raise "if: should be a Proc object for attribute #{method_name}" - end + raise "if: should be a Proc object for attribute #{method_name}" if options[:if] && !options[:if].instance_of?(Proc) if proc.instance_of? Proc self.attributes_to_serialize_blocks = {} if attributes_to_serialize_blocks.nil? diff --git a/lib/mutils/serialization/methods/main.rb b/mutils/lib/mutils/serialization/methods/main.rb similarity index 100% rename from lib/mutils/serialization/methods/main.rb rename to mutils/lib/mutils/serialization/methods/main.rb diff --git a/mutils/lib/mutils/serialization/methods/relations.rb b/mutils/lib/mutils/serialization/methods/relations.rb new file mode 100755 index 0000000..2e5a8d4 --- /dev/null +++ b/mutils/lib/mutils/serialization/methods/relations.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +# Module Mutils +module Mutils + # Module SerializationCore + module Serialization + # Module Methods + module Methods + # Module Relations + module Relations + def relationship(relationship_name, options = {}) + raise "if: should be a Proc object for relationship #{relationship_name}" if options[:if] && !options[:if].instance_of?(Proc) + + options = prepare_options(relationship_name, options, __callee__) + self.relationships = {} if relationships.nil? + relationships[relationship_name] = options + end + + alias belongs_to relationship + alias has_many relationship + alias has_one relationship + + def prepare_options(relationship_name, options, option_name) + serializer, always_include, label = options.values_at(:serializer, :always_include, :label) + serializer = fetch_serializer!(relationship_name, serializer, option_name) + + options.merge( + serializer: serializer.to_s, + always_include: default_always_include(always_include), + label: relation_label(label, relationship_name) + ) + end + + private + + def fetch_serializer!(relationship_name, serializer, option_name) + if serializer.nil? + raise "Serializer is Required for belongs_to :#{relationship_name}." \ + "\nDefine it like:\n#{option_name} :#{relationship_name}, " \ + 'serializer: SERIALIZER_CLASS' + end + raise "Serializer class not defined for relationship: #{relationship_name}" unless class_exists? serializer + + serializer + end + + def default_always_include(always_include) + always_include.nil? ? false : always_include + end + + def relation_label(label, relationship_name) + Lib::Helper.instance.underscore(label || relationship_name) + end + end + end + end +end diff --git a/lib/mutils/serialization/results/attributes.rb b/mutils/lib/mutils/serialization/results/attributes.rb similarity index 100% rename from lib/mutils/serialization/results/attributes.rb rename to mutils/lib/mutils/serialization/results/attributes.rb diff --git a/lib/mutils/serialization/results/main.rb b/mutils/lib/mutils/serialization/results/main.rb similarity index 100% rename from lib/mutils/serialization/results/main.rb rename to mutils/lib/mutils/serialization/results/main.rb diff --git a/lib/mutils/serialization/results/relations.rb b/mutils/lib/mutils/serialization/results/relations.rb similarity index 100% rename from lib/mutils/serialization/results/relations.rb rename to mutils/lib/mutils/serialization/results/relations.rb diff --git a/lib/mutils/serialization/serialization_includes.rb b/mutils/lib/mutils/serialization/serialization_includes.rb similarity index 100% rename from lib/mutils/serialization/serialization_includes.rb rename to mutils/lib/mutils/serialization/serialization_includes.rb diff --git a/lib/mutils/serialization/serialization_methods.rb b/mutils/lib/mutils/serialization/serialization_methods.rb similarity index 100% rename from lib/mutils/serialization/serialization_methods.rb rename to mutils/lib/mutils/serialization/serialization_methods.rb diff --git a/lib/mutils/serialization/serialization_results.rb b/mutils/lib/mutils/serialization/serialization_results.rb similarity index 100% rename from lib/mutils/serialization/serialization_results.rb rename to mutils/lib/mutils/serialization/serialization_results.rb diff --git a/lib/mutils/version.rb b/mutils/lib/mutils/version.rb similarity index 100% rename from lib/mutils/version.rb rename to mutils/lib/mutils/version.rb diff --git a/mutils/mutils.gemspec b/mutils/mutils.gemspec new file mode 100755 index 0000000..597774c --- /dev/null +++ b/mutils/mutils.gemspec @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +version = File.read(File.expand_path('lib/mutils/version.rb', __dir__)) + .match(/VERSION\s*=\s*['"]([^'"]+)['"]/)[1] + +Gem::Specification.new do |spec| + spec.name = 'mutils' + spec.version = version + spec.authors = ['Nitesh Purohit', 'Codevedas Inc.'] + spec.email = ['nitesh.purohit.it@gmail.com', 'team@codevedas.com'] + + spec.summary = 'mutils Utilities for rails app' + spec.description = 'mutils Utilities for rails app' + spec.license = 'MIT' + spec.metadata['bug_tracker_uri'] = 'https://github.com/Code-Vedas/mutils/issues' + spec.metadata['changelog_uri'] = 'https://github.com/Code-Vedas/mutils/blob/main/CHANGELOG.md' + spec.metadata['documentation_uri'] = 'https://mutils.codevedas.com' + spec.metadata['homepage_uri'] = 'https://github.com/Code-Vedas/mutils' + spec.metadata['source_code_uri'] = 'https://github.com/Code-Vedas/mutils.git' + spec.metadata['funding_uri'] = 'https://github.com/sponsors/Code-Vedas' + spec.metadata['support_uri'] = 'https://mutils.codevedas.com' + spec.metadata['rubygems_uri'] = 'https://rubygems.org/gems/mutils' + spec.metadata['rubygems_mfa_required'] = 'true' + spec.files = Dir.chdir(File.expand_path(__dir__)) do + `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + end + spec.bindir = 'exe' + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 3.2' + spec.add_dependency('dry-inflector') +end diff --git a/spec/mock_classes.rb b/mutils/spec/mock_classes.rb similarity index 100% rename from spec/mock_classes.rb rename to mutils/spec/mock_classes.rb diff --git a/mutils/spec/mutils/lib/helper_spec.rb b/mutils/spec/mutils/lib/helper_spec.rb new file mode 100644 index 0000000..b888128 --- /dev/null +++ b/mutils/spec/mutils/lib/helper_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +RSpec.describe Mutils::Lib::Helper do + describe '#underscore' do + it 'reuses cached inflections when the same key is requested twice' do + helper = described_class.instance + + expect(helper.underscore('HouseName')).to eq('house_name') + expect(helper.underscore('HouseName')).to eq('house_name') + end + end + + describe '#pluralize' do + it 'reuses cached inflections when the same key is requested twice' do + helper = described_class.instance + + expect(helper.pluralize('house')).to eq('houses') + expect(helper.pluralize('house')).to eq('houses') + end + end +end diff --git a/spec/mutils_spec.rb b/mutils/spec/mutils_spec.rb similarity index 100% rename from spec/mutils_spec.rb rename to mutils/spec/mutils_spec.rb diff --git a/spec/serialization/expect_output.rb b/mutils/spec/serialization/expect_output.rb similarity index 100% rename from spec/serialization/expect_output.rb rename to mutils/spec/serialization/expect_output.rb diff --git a/spec/serialization/serialization_json_spec.rb b/mutils/spec/serialization/serialization_json_spec.rb similarity index 87% rename from spec/serialization/serialization_json_spec.rb rename to mutils/spec/serialization/serialization_json_spec.rb index 1e9862a..91ffa35 100755 --- a/spec/serialization/serialization_json_spec.rb +++ b/mutils/spec/serialization/serialization_json_spec.rb @@ -3,6 +3,7 @@ require_relative '../mock_classes' require_relative 'expect_output' require 'rspec/json_expectations' +require 'securerandom' RSpec.describe 'Mutils::Serialization::JSON' do it 'serializes user to JSON' do @@ -207,7 +208,7 @@ Class.new(Mutils::Serialization::BaseSerializer) do has_many :bikes, if: 'not_a_proc', always_include: false end - end.to raise_error(RuntimeError, 'if: should be a Proc object for attribute bikes') + end.to raise_error(RuntimeError, 'if: should be a Proc object for relationship bikes') end it 'raises an exception when attribute\'s proc is not a proc' do @@ -217,4 +218,40 @@ end end.to raise_error(RuntimeError, 'if: should be a Proc object for attribute name') end + + it 'allows parse_attributes_methods to receive nil' do + serializer_class = Class.new(Mutils::Serialization::BaseSerializer) + + expect { serializer_class.parse_attributes_methods(nil, false) }.not_to raise_error + end + + it 'supports multiple block attributes on the same serializer class' do + serializer_class = Class.new(Mutils::Serialization::BaseSerializer) do + attribute :full_name do |user| + "#{user.first_name} #{user.last_name}" + end + + attribute :initials do |user| + "#{user.first_name[0]}#{user.last_name[0]}" + end + end + + user = User.new('FirstName', 'LastName', nil) + result = serializer_class.new(user).to_h + + expect(result[:full_name]).to eq('FirstName LastName') + expect(result[:initials]).to eq('FL') + end + + it 'handles serializers that only define block attributes' do + serializer_class = Class.new(Mutils::Serialization::BaseSerializer) do + attribute :full_name do |user| + "#{user.first_name} #{user.last_name}" + end + end + + user = User.new('FirstName', 'LastName', nil) + + expect(serializer_class.new(user).to_h).to eq(full_name: 'FirstName LastName') + end end diff --git a/mutils/spec/spec_helper.rb b/mutils/spec/spec_helper.rb new file mode 100755 index 0000000..ebd222e --- /dev/null +++ b/mutils/spec/spec_helper.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +unless ENV['NO_COVERAGE'] == '1' + require 'simplecov' + + SimpleCov.start do + enable_coverage :branch + track_files 'lib/**/*.rb' + add_filter '/spec/' + add_filter '/lib/generators/' + minimum_coverage line: 100, branch: 100 + end +end + +require 'bundler/setup' +require_relative '../lib/mutils' + +require 'benchmark' +require 'rspec-benchmark' + +RSpec.configure do |config| + config.include RSpec::Benchmark::Matchers + config.example_status_persistence_file_path = '.rspec_status' + config.disable_monkey_patching! + config.expect_with :rspec do |c| + c.syntax = :expect + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100755 index d7ac0cf..0000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'coveralls' -require 'simplecov' -require 'simplecov-lcov' - -SimpleCov::Formatter::LcovFormatter.config do |c| - c.report_with_single_file = true - c.output_directory = 'coverage' - c.lcov_file_name = 'lcov.info' - c.single_report_path = 'coverage/lcov.info' -end - -SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::LcovFormatter] -SimpleCov.start do - add_filter '/generators/' - add_filter '/spec/' - add_group 'Lib', '/lib/' - add_group 'Lib:Method', '/methods/' - add_group 'Lib:Results', '/results/' -end - -require 'bundler/setup' -require_relative '../lib/mutils' - -require 'benchmark' -require 'rspec-benchmark' - -RSpec.configure do |config| - config.include RSpec::Benchmark::Matchers - config.example_status_persistence_file_path = '.rspec_status' - config.disable_monkey_patching! - config.expect_with :rspec do |c| - c.syntax = :expect - end -end From 13ed19b4e1bb495d34fc6b2084759a149d7e68d2 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:02:43 -0400 Subject: [PATCH 02/11] docs: update README for improved structure and clarity - Reorganized the Table of Contents for better navigation. - Added missing sections such as Contributing, License, Code of Conduct, and Security. - Corrected typos in the documentation for clarity. --- README.md | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a67af13..f1ac8c5 100755 --- a/README.md +++ b/README.md @@ -13,19 +13,29 @@ These collection of modules are built by developer for developers :-) ## Table of Contents -- [Features](#features) -- [Installation](#installation) -- [Usage](#usage) - - [Rails Generator](#rails-generator) - - [Attributes](#attributes) - - [Relations](#relations) - - [Conditional Attributes](#conditional-attributes) - - [Conditional Relations](#conditional-relations) - - [Attributes Block](#attributes-blocks) - - [Attributes Block with Params](#attributes-blocks-with-params) - - [Custom Methods](#custom-methods) - - [Name Tag](#name-tag) - - [Sample Usage](#sample-usage) +- [Mutils](#mutils) + - [Introduction](#introduction) + - [Table of Contents](#table-of-contents) + - [Features](#features) + - [Installation](#installation) + - [Usage](#usage) + - [Rails Generator](#rails-generator) + - [Attributes](#attributes) + - [Relations](#relations) + - [Conditional Attributes](#conditional-attributes) + - [Conditional Relations](#conditional-relations) + - [Attributes Blocks](#attributes-blocks) + - [Attributes Blocks with Params](#attributes-blocks-with-params) + - [Custom Methods](#custom-methods) + - [Name Tag](#name-tag) + - [Options](#options) + - [Sample Usage](#sample-usage) + - [Or](#or) + - [Or In Controllers](#or-in-controllers) + - [Contributing](#contributing) + - [License](#license) + - [Code of Conduct](#code-of-conduct) + - [Security](#security) ## Features @@ -172,7 +182,7 @@ UserSerializer.new(user,{params:{show_account:true}}) # With params ### Attributes Blocks -While writting attribute a block can be provided for useful transformations like `full_name` as shown below +While writing attribute a block can be provided for useful transformations like `full_name` as shown below ```ruby # frozen_string_literal: true @@ -188,7 +198,7 @@ end ### Attributes Blocks with Params -While writting attribute a block can be provided for useful transformations like `full_name` as shown below +While writing attribute a block can be provided for useful transformations like `full_name` as shown below ```ruby # frozen_string_literal: true From f6ea1e6984c7efef7b19b15a1e34fd9ff54d9517 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:08:09 -0400 Subject: [PATCH 03/11] ci: update coverage upload step - Changed the step name from "Upload simplecov report" to "Publish coverage to Qlty" for clarity. - Updated the action used for uploading coverage from `actions/upload-artifact@v4` to `qltysh/qlty-action/coverage@v2`. - Modified the parameters to use a token for authentication and specified the path to the coverage result file. --- .github/workflows/shared-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/shared-ci.yml b/.github/workflows/shared-ci.yml index c846e51..844a3dc 100644 --- a/.github/workflows/shared-ci.yml +++ b/.github/workflows/shared-ci.yml @@ -132,10 +132,10 @@ jobs: - name: Run unit tests working-directory: ${{ env.APP_DIR }} run: bin/rspec --format documentation --color --profile - - name: Upload simplecov report + - name: Publish coverage to Qlty if: inputs.upload_coverage && matrix.ruby_version == '3.4' - uses: actions/upload-artifact@v4 + uses: qltysh/qlty-action/coverage@v2 with: - name: simplecov-report-ruby-${{ matrix.ruby_version }} - path: ${{ env.APP_DIR }}/coverage - if-no-files-found: ignore + token: ${{ secrets.QLTY_COVERAGE_TOKEN }} + files: | + ${{ github.workspace }}/mutils/coverage/.resultset.json From aa2a63cb67be70620642200a5046bd3c046951e5 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:11:15 -0400 Subject: [PATCH 04/11] docs: correct typos in README and error messages - Fixed typo in README regarding relationships support. - Updated error message to specify the option name for clarity. --- README.md | 2 +- mutils/lib/mutils/serialization/methods/relations.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f1ac8c5..077feb6 100755 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ These collection of modules are built by developer for developers :-) ## Features - Simple declaration syntax similar to Active Model Serializer -- Realtionships support `belongs_to`, `has_many`, `has_one` +- Relationships support `belongs_to`, `has_many`, `has_one` - Block style attributes with params ## Installation diff --git a/mutils/lib/mutils/serialization/methods/relations.rb b/mutils/lib/mutils/serialization/methods/relations.rb index 2e5a8d4..89f3208 100755 --- a/mutils/lib/mutils/serialization/methods/relations.rb +++ b/mutils/lib/mutils/serialization/methods/relations.rb @@ -35,7 +35,7 @@ def prepare_options(relationship_name, options, option_name) def fetch_serializer!(relationship_name, serializer, option_name) if serializer.nil? - raise "Serializer is Required for belongs_to :#{relationship_name}." \ + raise "Serializer is Required for #{option_name} :#{relationship_name}." \ "\nDefine it like:\n#{option_name} :#{relationship_name}, " \ 'serializer: SERIALIZER_CLASS' end From 502701cc79788bb055b2636bbf511301dc4206d6 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:18:44 -0400 Subject: [PATCH 05/11] ci: update cache action version and add secret - Updated the cache action from v4 to v5 for improved performance and compatibility. - Added QLTY_COVERAGE_TOKEN as an optional secret input for better coverage management. --- .github/workflows/shared-ci.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/shared-ci.yml b/.github/workflows/shared-ci.yml index 844a3dc..c63ab55 100644 --- a/.github/workflows/shared-ci.yml +++ b/.github/workflows/shared-ci.yml @@ -15,6 +15,9 @@ on: required: false type: boolean default: false + secrets: + QLTY_COVERAGE_TOKEN: + required: false jobs: rubocop: @@ -42,7 +45,7 @@ jobs: ruby-version: ${{ matrix.ruby_version }} bundler-cache: false - name: Restore bundle cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.BUNDLE_PATH }} key: ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle-${{ hashFiles('mutils/Gemfile.lock', 'mutils/mutils.gemspec') }} @@ -81,7 +84,7 @@ jobs: ruby-version: ${{ matrix.ruby_version }} bundler-cache: false - name: Restore bundle cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.BUNDLE_PATH }} key: ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle-${{ hashFiles('mutils/Gemfile.lock', 'mutils/mutils.gemspec') }} @@ -120,7 +123,7 @@ jobs: ruby-version: ${{ matrix.ruby_version }} bundler-cache: false - name: Restore bundle cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.BUNDLE_PATH }} key: ${{ runner.os }}-ruby-${{ matrix.ruby_version }}-bundle-${{ hashFiles('mutils/Gemfile.lock', 'mutils/mutils.gemspec') }} From 9da26a0cbdced849cb21243edeedfdba2a1c3169 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:23:30 -0400 Subject: [PATCH 06/11] ci: inherit secrets in CI and release workflows - Added `secrets: inherit` to the CI job in `ci.yml` to ensure secrets are available during the CI process. - Added `secrets: inherit` to the verify_release job in `release.yml` for consistent access to secrets. - Updated the condition for publishing coverage in `shared-ci.yml` to check if the coverage token is not empty, enhancing security. --- .github/workflows/ci.yml | 1 + .github/workflows/release.yml | 1 + .github/workflows/shared-ci.yml | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15b46a6..a48032a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,5 +17,6 @@ jobs: permissions: contents: read uses: ./.github/workflows/shared-ci.yml + secrets: inherit with: upload_coverage: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 44d3f91..cc5ef21 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,6 +22,7 @@ jobs: permissions: contents: read uses: ./.github/workflows/shared-ci.yml + secrets: inherit with: upload_coverage: false diff --git a/.github/workflows/shared-ci.yml b/.github/workflows/shared-ci.yml index c63ab55..103daa6 100644 --- a/.github/workflows/shared-ci.yml +++ b/.github/workflows/shared-ci.yml @@ -136,7 +136,7 @@ jobs: working-directory: ${{ env.APP_DIR }} run: bin/rspec --format documentation --color --profile - name: Publish coverage to Qlty - if: inputs.upload_coverage && matrix.ruby_version == '3.4' + if: inputs.upload_coverage && matrix.ruby_version == '3.4' && secrets.QLTY_COVERAGE_TOKEN != '' uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} From 1b696d5b34dc07b8ecef765ccf3725f7c8aee597 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:24:40 -0400 Subject: [PATCH 07/11] ci: update coverage publishing condition - Removed the check for QLTY_COVERAGE_TOKEN in the coverage publishing step. - This change simplifies the condition for uploading coverage when using Ruby version 3.4. --- .github/workflows/shared-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shared-ci.yml b/.github/workflows/shared-ci.yml index 103daa6..c63ab55 100644 --- a/.github/workflows/shared-ci.yml +++ b/.github/workflows/shared-ci.yml @@ -136,7 +136,7 @@ jobs: working-directory: ${{ env.APP_DIR }} run: bin/rspec --format documentation --color --profile - name: Publish coverage to Qlty - if: inputs.upload_coverage && matrix.ruby_version == '3.4' && secrets.QLTY_COVERAGE_TOKEN != '' + if: inputs.upload_coverage && matrix.ruby_version == '3.4' uses: qltysh/qlty-action/coverage@v2 with: token: ${{ secrets.QLTY_COVERAGE_TOKEN }} From c10c2ee593b789d0129164d00cb47cb382cea116 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:32:09 -0400 Subject: [PATCH 08/11] docs: update README and gemspec for clarity - Revised the introduction in README to better describe `mutils` as a collection of Ruby helpers. - Enhanced the description in the gemspec to clarify the purpose and features of `mutils`. - Updated the summary and description in the gemspec for improved accuracy. - Adjusted the dependency specification for `dry-inflector` to ensure compatibility. --- README.md | 4 ++-- docs/index.md | 4 ++-- mutils/Gemfile.lock | 2 +- mutils/README.md | 4 ++-- mutils/mutils.gemspec | 13 +++++++------ 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 077feb6..29aef63 100755 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ ## Introduction -`mutils` is collection of useful modules for `ruby on rails` which is tested and benchmarked against high load. +`mutils` is a collection of useful helpers for Ruby and Rails applications. -These collection of modules are built by developer for developers :-) +Serialization is one of the features available today, and the gem is intended to grow into a broader utility toolkit over time. ## Table of Contents diff --git a/docs/index.md b/docs/index.md index a4db6d9..9d52132 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,9 +8,9 @@ nav_order: 1 {: .note } -> Mutils is a focused serializer DSL for Ruby and Rails apps. It gives you explicit control over attributes, computed fields, relationships, and JSON root naming without depending on Active Model Serializers. +> Mutils is a general-purpose helper gem for Ruby and Rails apps. Serialization is one supported feature today, with room for more reusable utilities over time. -Mutils centers on one job: turn Ruby objects into predictable hashes or JSON with a small class-based API. +Today, Mutils primarily provides a class-based serialization API for turning Ruby objects into predictable hashes or JSON. ## What it provides diff --git a/mutils/Gemfile.lock b/mutils/Gemfile.lock index f809915..bf0557b 100644 --- a/mutils/Gemfile.lock +++ b/mutils/Gemfile.lock @@ -2,7 +2,7 @@ PATH remote: . specs: mutils (1.3.5) - dry-inflector + dry-inflector (~> 1.3) GEM remote: https://rubygems.org/ diff --git a/mutils/README.md b/mutils/README.md index a9c8e17..2d80ae2 100755 --- a/mutils/README.md +++ b/mutils/README.md @@ -7,9 +7,9 @@ ## Introduction -`mutils` is collection of useful modules for `ruby on rails` which is tested and benchmarked against high load. +`mutils` is a collection of useful helpers for Ruby and Rails applications. -These collection of modules are built by developer for developers :-) +Serialization is one of the features available today, and the gem is intended to grow into a broader utility toolkit over time. ## Table of Contents diff --git a/mutils/mutils.gemspec b/mutils/mutils.gemspec index 597774c..1f9d6cf 100755 --- a/mutils/mutils.gemspec +++ b/mutils/mutils.gemspec @@ -9,8 +9,9 @@ Gem::Specification.new do |spec| spec.authors = ['Nitesh Purohit', 'Codevedas Inc.'] spec.email = ['nitesh.purohit.it@gmail.com', 'team@codevedas.com'] - spec.summary = 'mutils Utilities for rails app' - spec.description = 'mutils Utilities for rails app' + spec.summary = 'General-purpose Ruby helpers for application development' + spec.description = 'Mutils is a general-purpose Ruby helper gem for application development. It currently includes a lightweight serialization toolkit and is designed to grow with additional reusable helpers over time.' + spec.homepage = 'https://github.com/Code-Vedas/mutils' spec.license = 'MIT' spec.metadata['bug_tracker_uri'] = 'https://github.com/Code-Vedas/mutils/issues' spec.metadata['changelog_uri'] = 'https://github.com/Code-Vedas/mutils/blob/main/CHANGELOG.md' @@ -22,11 +23,11 @@ Gem::Specification.new do |spec| spec.metadata['rubygems_uri'] = 'https://rubygems.org/gems/mutils' spec.metadata['rubygems_mfa_required'] = 'true' spec.files = Dir.chdir(File.expand_path(__dir__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + Dir['bin/**/*', 'lib/**/*', 'LICENSE', 'Rakefile', 'README.md'].reject { |f| File.directory?(f) || f.end_with?('.DS_Store') } end - spec.bindir = 'exe' - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.bindir = 'bin' + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.2' - spec.add_dependency('dry-inflector') + spec.add_dependency 'dry-inflector', '~> 1.3' end From fbbc2bae542f570bc3eccee0b0d381e226ae4155 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:38:55 -0400 Subject: [PATCH 09/11] chore: clean up gemspec file structure - Removed unnecessary filtering of files in the gemspec. - Simplified the file inclusion pattern for better clarity. - Removed bindir and executables settings as they are no longer needed. --- mutils/mutils.gemspec | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mutils/mutils.gemspec b/mutils/mutils.gemspec index 1f9d6cf..0b7b2a9 100755 --- a/mutils/mutils.gemspec +++ b/mutils/mutils.gemspec @@ -23,10 +23,8 @@ Gem::Specification.new do |spec| spec.metadata['rubygems_uri'] = 'https://rubygems.org/gems/mutils' spec.metadata['rubygems_mfa_required'] = 'true' spec.files = Dir.chdir(File.expand_path(__dir__)) do - Dir['bin/**/*', 'lib/**/*', 'LICENSE', 'Rakefile', 'README.md'].reject { |f| File.directory?(f) || f.end_with?('.DS_Store') } + Dir['{bin,exe,lib}/**/*', 'LICENSE', 'Rakefile', 'README.md'] end - spec.bindir = 'bin' - spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.2' spec.add_dependency 'dry-inflector', '~> 1.3' From f24edd0b23d7d77883d20ac206f11c8d60b88f1c Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:40:25 -0400 Subject: [PATCH 10/11] ci: update checkout action version - Changed the checkout action version from v4 to v6. - This update ensures compatibility with the latest features and improvements in the checkout action. --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f30412d..385d4a8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,7 +32,7 @@ jobs: build-mode: none steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: From d888c4141bc221fe2ebe5d46e5bf1c5610220daf Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Mon, 30 Mar 2026 19:43:08 -0400 Subject: [PATCH 11/11] docs: update gemspec description formatting - Changed the description format in the gemspec file to a heredoc for improved readability. - This enhances clarity and maintains consistency in the documentation style. --- mutils/mutils.gemspec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mutils/mutils.gemspec b/mutils/mutils.gemspec index 0b7b2a9..099e91f 100755 --- a/mutils/mutils.gemspec +++ b/mutils/mutils.gemspec @@ -10,7 +10,10 @@ Gem::Specification.new do |spec| spec.email = ['nitesh.purohit.it@gmail.com', 'team@codevedas.com'] spec.summary = 'General-purpose Ruby helpers for application development' - spec.description = 'Mutils is a general-purpose Ruby helper gem for application development. It currently includes a lightweight serialization toolkit and is designed to grow with additional reusable helpers over time.' + spec.description = <<~DESC + Mutils is a general-purpose Ruby helper gem for application development. + It currently includes a lightweight serialization toolkit and is designed to grow with additional reusable helpers over time. + DESC spec.homepage = 'https://github.com/Code-Vedas/mutils' spec.license = 'MIT' spec.metadata['bug_tracker_uri'] = 'https://github.com/Code-Vedas/mutils/issues'