From 1744460c56e6f0fa1ee7631960fdacdd7a5935b9 Mon Sep 17 00:00:00 2001 From: Andrea Carratta Date: Sat, 5 Sep 2026 10:01:43 +0200 Subject: [PATCH] Initial gem scaffold Scaffold generated with 'bundle gem' (RSpec, MIT license, RuboCop): - password_forge.gemspec (Ruby >= 3.0.0, MFA required, metadata URIs) - lib entry point and version (0.0.0) - Rakefile default task (spec + rubocop), bin/setup, bin/console - CI workflow (RSpec matrix + RuboCop) - private-notes/, Gemfile.lock and built gems git-ignored --- .github/workflows/main.yml | 53 +++++++++++++++++++++++++++++++++++ .gitignore | 22 +++++++++++++++ .rspec | 3 ++ .rubocop.yml | 20 +++++++++++++ Gemfile | 13 +++++++++ LICENSE.txt | 21 ++++++++++++++ Rakefile | 12 ++++++++ bin/console | 11 ++++++++ bin/setup | 8 ++++++ lib/password_forge.rb | 10 +++++++ lib/password_forge/version.rb | 5 ++++ password_forge.gemspec | 43 ++++++++++++++++++++++++++++ sig/password_forge.rbs | 4 +++ spec/password_forge_spec.rb | 7 +++++ spec/spec_helper.rb | 15 ++++++++++ 15 files changed, 247 insertions(+) create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 .rspec create mode 100644 .rubocop.yml create mode 100644 Gemfile create mode 100644 LICENSE.txt create mode 100644 Rakefile create mode 100755 bin/console create mode 100755 bin/setup create mode 100644 lib/password_forge.rb create mode 100644 lib/password_forge/version.rb create mode 100644 password_forge.gemspec create mode 100644 sig/password_forge.rbs create mode 100644 spec/password_forge_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..b76ff19 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,53 @@ +name: Ruby + +on: + push: + branches: + - main + + pull_request: + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + name: Test - Ruby ${{ matrix.ruby }} + strategy: + fail-fast: false + matrix: + ruby: + - '3.0' + - '3.1' + - '3.2' + - '3.3' + - '3.4' + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run the test suite + run: bundle exec rspec + + lint: + runs-on: ubuntu-latest + name: Lint (RuboCop) + + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4' + bundler-cache: true + - name: Run RuboCop + run: bundle exec rubocop diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b72b37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ + +# rspec failure tracking +.rspec_status + +# Personal, private notes kept locally and excluded from the repo +# (e.g. the development diary "how-i-created-my-first-ruby-gem-with-kiro.md"). +/private-notes/ + +# Built gem artifacts +/*.gem + +# Gems should not commit their lockfile (Bundler resolves it per environment). +# Committing it here pinned Bundler 4.x, which breaks CI on Ruby < 3.2. +/Gemfile.lock diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..34c5164 --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--format documentation +--color +--require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..2b912b9 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,20 @@ +AllCops: + TargetRubyVersion: 3.0 + NewCops: enable + SuggestExtensions: false + +Style/StringLiterals: + EnforcedStyle: double_quotes + +Style/StringLiteralsInInterpolation: + EnforcedStyle: double_quotes + +# Spec files legitimately contain long describe/context blocks. +Metrics/BlockLength: + Exclude: + - "spec/**/*" + +# The PasswordForge module is documented in lib/password_forge.rb; other files +# reopen it to add classes and do not need to repeat the documentation. +Style/Documentation: + Enabled: false diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..0bc1e04 --- /dev/null +++ b/Gemfile @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# Specify your gem's dependencies in password_forge.gemspec +gemspec + +gem "irb" +gem "rake", "~> 13.0" + +gem "rspec", "~> 3.0" + +gem "rubocop", "~> 1.21" diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f60de96 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2026 Andrea Carratta + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +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 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. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..cca7175 --- /dev/null +++ b/Rakefile @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +require "rubocop/rake_task" + +RuboCop::RakeTask.new + +task default: %i[spec rubocop] diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..4fec77d --- /dev/null +++ b/bin/console @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "password_forge" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +require "irb" +IRB.start(__FILE__) diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/lib/password_forge.rb b/lib/password_forge.rb new file mode 100644 index 0000000..3f1afcf --- /dev/null +++ b/lib/password_forge.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require_relative "password_forge/version" + +# PasswordForge generates random passwords from selectable character sets. +module PasswordForge + # Base error class for all PasswordForge-specific errors. + class Error < StandardError; end + # Implementation is added in the next version. +end diff --git a/lib/password_forge/version.rb b/lib/password_forge/version.rb new file mode 100644 index 0000000..6ab2aea --- /dev/null +++ b/lib/password_forge/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module PasswordForge + VERSION = "0.0.0" +end diff --git a/password_forge.gemspec b/password_forge.gemspec new file mode 100644 index 0000000..bd4d6e5 --- /dev/null +++ b/password_forge.gemspec @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require_relative "lib/password_forge/version" + +Gem::Specification.new do |spec| + spec.name = "password_forge" + spec.version = PasswordForge::VERSION + spec.authors = ["Andrea Carratta"] + + spec.summary = "A configurable password generator with selectable character sets." + spec.description = "PasswordForge generates random passwords from selectable character sets " \ + "(uppercase, lowercase, numeric, special). Built as a learning-friendly, " \ + "well-tested Ruby gem with a clean, idiomatic API." + spec.homepage = "https://github.com/devandreacarratta/password-forge-ruby-gem" + spec.license = "MIT" + spec.required_ruby_version = ">= 3.0.0" + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = "https://github.com/devandreacarratta/password-forge-ruby-gem/tree/main" + spec.metadata["changelog_uri"] = "https://github.com/devandreacarratta/password-forge-ruby-gem/blob/main/CHANGELOG.md" + + # Require MFA for gem pushes to protect against supply chain attacks. + # See: https://guides.rubygems.org/mfa-requirement-opt-in/ + spec.metadata["rubygems_mfa_required"] = "true" + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + gemspec = File.basename(__FILE__) + spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls| + ls.readlines("\x0", chomp: true).reject do |f| + (f == gemspec) || + f.start_with?(*%w[bin/ Gemfile .gitignore .rspec spec/ .github/ .rubocop.yml]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + # Uncomment to register a new dependency of your gem + # spec.add_dependency "example-gem", "~> 1.0" + + # For more information and examples about making a new gem, check out our + # guide at: https://guides.rubygems.org/make-your-own-gem/ +end diff --git a/sig/password_forge.rbs b/sig/password_forge.rbs new file mode 100644 index 0000000..e26ffa0 --- /dev/null +++ b/sig/password_forge.rbs @@ -0,0 +1,4 @@ +module PasswordForge + VERSION: String + # See the writing guide of rbs: https://github.com/ruby/rbs#guides +end diff --git a/spec/password_forge_spec.rb b/spec/password_forge_spec.rb new file mode 100644 index 0000000..d887ae2 --- /dev/null +++ b/spec/password_forge_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +RSpec.describe PasswordForge do + it "has a version number" do + expect(PasswordForge::VERSION).not_to be_nil + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..991c09a --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require "password_forge" + +RSpec.configure do |config| + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! + + config.expect_with :rspec do |c| + c.syntax = :expect + end +end