loading
Generated 2025-10-11T17:20:39+00:00

All Files ( 100.0% covered at 6.03 hits/line )

45 files in total.
705 relevant lines, 705 lines covered and 0 lines missed. ( 100.0% )
39 total branches, 39 branches covered and 0 branches missed. ( 100.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
Gemfile 100.00 % 30 18 18 0 1.00 100.00 % 0 0 0
lib/hanamismith.rb 100.00 % 25 10 10 0 1.40 100.00 % 0 0 0
lib/hanamismith/../../hanamismith.gemspec 100.00 % 44 29 29 0 1.00 100.00 % 0 0 0
lib/hanamismith/builders/asset.rb 100.00 % 18 9 9 0 2.67 100.00 % 0 0 0
lib/hanamismith/builders/binstub.rb 100.00 % 20 8 8 0 2.50 100.00 % 0 0 0
lib/hanamismith/builders/bundler.rb 100.00 % 111 32 32 0 6.78 100.00 % 2 2 0
lib/hanamismith/builders/caliber.rb 100.00 % 23 11 11 0 2.73 100.00 % 2 2 0
lib/hanamismith/builders/circle_ci.rb 100.00 % 35 16 16 0 3.63 100.00 % 2 2 0
lib/hanamismith/builders/console.rb 100.00 % 40 16 16 0 2.56 100.00 % 2 2 0
lib/hanamismith/builders/core.rb 100.00 % 78 40 40 0 22.80 100.00 % 2 2 0
lib/hanamismith/builders/docker/compose.rb 100.00 % 21 10 10 0 2.30 100.00 % 2 2 0
lib/hanamismith/builders/docker/file.rb 100.00 % 21 10 10 0 4.40 100.00 % 2 2 0
lib/hanamismith/builders/documentation/readme.rb 100.00 % 25 11 11 0 3.18 100.00 % 2 2 0
lib/hanamismith/builders/environments/all.rb 100.00 % 34 15 15 0 2.33 100.00 % 0 0 0
lib/hanamismith/builders/environments/development.rb 100.00 % 22 9 9 0 2.11 100.00 % 0 0 0
lib/hanamismith/builders/environments/test.rb 100.00 % 22 9 9 0 2.11 100.00 % 0 0 0
lib/hanamismith/builders/git/commit.rb 100.00 % 12 5 5 0 1.00 100.00 % 0 0 0
lib/hanamismith/builders/git/ignore.rb 100.00 % 28 11 11 0 2.45 100.00 % 2 2 0
lib/hanamismith/builders/git_hub/ci.rb 100.00 % 22 11 11 0 3.18 100.00 % 2 2 0
lib/hanamismith/builders/icon.rb 100.00 % 18 9 9 0 2.67 100.00 % 0 0 0
lib/hanamismith/builders/javascript.rb 100.00 % 18 9 9 0 2.67 100.00 % 0 0 0
lib/hanamismith/builders/layout.rb 100.00 % 79 25 25 0 3.92 100.00 % 0 0 0
lib/hanamismith/builders/node.rb 100.00 % 54 30 30 0 3.67 100.00 % 5 5 0
lib/hanamismith/builders/providers/htmx.rb 100.00 % 20 10 10 0 2.50 100.00 % 0 0 0
lib/hanamismith/builders/puma/configuration.rb 100.00 % 20 9 9 0 2.11 100.00 % 0 0 0
lib/hanamismith/builders/puma/procfile.rb 100.00 % 20 10 10 0 3.10 100.00 % 0 0 0
lib/hanamismith/builders/pwa.rb 100.00 % 18 9 9 0 2.67 100.00 % 0 0 0
lib/hanamismith/builders/rack/attack.rb 100.00 % 33 16 16 0 4.38 100.00 % 0 0 0
lib/hanamismith/builders/rack/configuration.rb 100.00 % 19 9 9 0 2.11 100.00 % 0 0 0
lib/hanamismith/builders/rack/deflater.rb 100.00 % 21 9 9 0 2.11 100.00 % 0 0 0
lib/hanamismith/builders/rake/configuration.rb 100.00 % 25 11 11 0 2.45 100.00 % 2 2 0
lib/hanamismith/builders/refinement.rb 100.00 % 23 9 9 0 3.78 100.00 % 0 0 0
lib/hanamismith/builders/rspec/application_shared_context.rb 100.00 % 23 11 11 0 2.45 100.00 % 2 2 0
lib/hanamismith/builders/rspec/hanami.rb 100.00 % 23 11 11 0 2.45 100.00 % 2 2 0
lib/hanamismith/builders/rspec/helper.rb 100.00 % 42 21 21 0 3.71 100.00 % 2 2 0
lib/hanamismith/builders/setup.rb 100.00 % 37 13 13 0 3.23 100.00 % 2 2 0
lib/hanamismith/builders/slices/health.rb 100.00 % 68 34 34 0 10.41 100.00 % 0 0 0
lib/hanamismith/builders/slices/home.rb 100.00 % 74 37 37 0 12.22 100.00 % 0 0 0
lib/hanamismith/builders/stylesheet.rb 100.00 % 26 9 9 0 8.44 100.00 % 0 0 0
lib/hanamismith/cli/commands/build.rb 100.00 % 137 54 54 0 6.43 100.00 % 0 0 0
lib/hanamismith/cli/shell.rb 100.00 % 39 21 21 0 3.86 100.00 % 0 0 0
lib/hanamismith/container.rb 100.00 % 56 19 19 0 28.53 100.00 % 0 0 0
lib/hanamismith/dependencies.rb 100.00 % 7 3 3 0 1.00 100.00 % 0 0 0
lib/hanamismith/extensions/asset.rb 100.00 % 22 10 10 0 2.90 100.00 % 2 2 0
lib/hanamismith/extensions/npm.rb 100.00 % 33 17 17 0 3.59 100.00 % 2 2 0

Gemfile

100.0% lines covered

100.0% branches covered

18 relevant lines. 18 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 ruby file: ".ruby-version"
  3. 1 source "https://rubygems.org"
  4. 1 gemspec
  5. 1 group :quality do
  6. 1 gem "caliber", "~> 0.82"
  7. 1 gem "git-lint", "~> 9.0"
  8. 1 gem "reek", "~> 6.5", require: false
  9. 1 gem "simplecov", "~> 0.22", require: false
  10. end
  11. 1 group :development do
  12. 1 gem "rake", "~> 13.3"
  13. end
  14. 1 group :test do
  15. 1 gem "rspec", "~> 3.13"
  16. 1 gem "rubocop-sequel", "~> 0.4"
  17. end
  18. 1 group :tools do
  19. 1 gem "amazing_print", "~> 2.0"
  20. 1 gem "debug", "~> 1.11"
  21. 1 gem "irb-kit", "~> 1.1"
  22. 1 gem "repl_type_completor", "~> 0.1"
  23. end

lib/hanamismith.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "rubysmith"
  3. 1 require "zeitwerk"
  4. 1 Zeitwerk::Loader.new.then do |loader|
  5. 1 loader.inflector.inflect "cli" => "CLI",
  6. "ci" => "CI",
  7. "circle_ci" => "CircleCI",
  8. "htmx" => "HTMX",
  9. "npm" => "NPM",
  10. "pwa" => "PWA",
  11. "rspec" => "RSpec",
  12. "yjit" => "YJIT"
  13. 1 loader.tag = File.basename __FILE__, ".rb"
  14. 1 loader.push_dir __dir__
  15. 1 loader.setup
  16. end
  17. # Main namespace.
  18. 1 module Hanamismith
  19. 1 def self.loader registry = Zeitwerk::Registry
  20. 5 @loader ||= registry.loaders.each.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
  21. end
  22. end

lib/hanamismith/../../hanamismith.gemspec

100.0% lines covered

100.0% branches covered

29 relevant lines. 29 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 Gem::Specification.new do |spec|
  3. 1 spec.name = "hanamismith"
  4. 1 spec.version = "1.11.0"
  5. 1 spec.authors = ["Brooke Kuhlmann"]
  6. 1 spec.email = ["brooke@alchemists.io"]
  7. 1 spec.homepage = "https://alchemists.io/projects/hanamismith"
  8. 1 spec.summary = "A command line interface for smithing Hanami projects."
  9. 1 spec.license = "Hippocratic-2.1"
  10. 1 spec.metadata = {
  11. "bug_tracker_uri" => "https://github.com/bkuhlmann/hanamismith/issues",
  12. "changelog_uri" => "https://alchemists.io/projects/hanamismith/versions",
  13. "homepage_uri" => "https://alchemists.io/projects/hanamismith",
  14. "funding_uri" => "https://github.com/sponsors/bkuhlmann",
  15. "label" => "Hanamismith",
  16. "rubygems_mfa_required" => "true",
  17. "source_code_uri" => "https://github.com/bkuhlmann/hanamismith"
  18. }
  19. 1 spec.signing_key = Gem.default_key_path
  20. 1 spec.cert_chain = [Gem.default_cert_path]
  21. 1 spec.required_ruby_version = "~> 3.4"
  22. 1 spec.add_dependency "cogger", "~> 1.0"
  23. 1 spec.add_dependency "containable", "~> 1.1"
  24. 1 spec.add_dependency "dry-monads", "~> 1.9"
  25. 1 spec.add_dependency "dry-schema", "~> 1.13"
  26. 1 spec.add_dependency "etcher", "~> 3.0"
  27. 1 spec.add_dependency "htmx", "~> 2.0"
  28. 1 spec.add_dependency "infusible", "~> 4.0"
  29. 1 spec.add_dependency "refinements", "~> 13.5"
  30. 1 spec.add_dependency "rubysmith", "~> 8.7"
  31. 1 spec.add_dependency "runcom", "~> 12.0"
  32. 1 spec.add_dependency "sod", "~> 1.0"
  33. 1 spec.add_dependency "spek", "~> 4.0"
  34. 1 spec.add_dependency "zeitwerk", "~> 2.7"
  35. 1 spec.bindir = "exe"
  36. 1 spec.executables << "hanamismith"
  37. 1 spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
  38. 1 spec.files = Dir.glob ["*.gemspec", "lib/**/*"], File::FNM_DOTMATCH
  39. end

lib/hanamismith/builders/asset.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton for assets.
  6. 1 class Asset < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 6 path = "%project_name%/config/assets.js.erb"
  10. 6 builder.call(settings.with(template_path: path)).render
  11. 6 true
  12. end
  13. end
  14. end
  15. end

lib/hanamismith/builders/binstub.rb

100.0% lines covered

100.0% branches covered

8 relevant lines. 8 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton binstub.
  6. 1 class Binstub < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 7 builder.call(settings.with(template_path: "%project_name%/bin/hanami.erb"))
  10. .render
  11. .permit 0o755
  12. 7 true
  13. end
  14. end
  15. end
  16. end

lib/hanamismith/builders/bundler.rb

100.0% lines covered

100.0% branches covered

32 relevant lines. 32 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton with Gemfile configuration.
  6. 1 class Bundler < Rubysmith::Builders::Bundler
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 7 super
  10. 7 %i[groups hanami main persistence quality devtest development test].each do |name|
  11. 56 __send__ :"insert_#{name}"
  12. end
  13. 7 remove_zeitwerk
  14. 7 true
  15. end
  16. 1 private
  17. 1 def insert_groups
  18. 7 else: 2 then: 5 return unless settings.build_minimum
  19. 2 with_template.append <<~CONTENT
  20. group :development do
  21. end
  22. group :test do
  23. end
  24. CONTENT
  25. end
  26. 1 def insert_hanami
  27. 7 with_template.insert_after "source", <<~CONTENT.strip
  28. gem "hanami", "~> 2.2.0"
  29. gem "hanami-assets", "~> 2.2.0"
  30. gem "hanami-controller", "~> 2.2.0"
  31. gem "hanami-db", "~> 2.2.0"
  32. gem "hanami-router", "~> 2.2.0"
  33. gem "hanami-validations", "~> 2.2.0"
  34. gem "hanami-view", "~> 2.2.0"
  35. CONTENT
  36. end
  37. 1 def insert_main
  38. 7 with_template.insert_after "source", <<~CONTENT
  39. gem "dry-schema", "~> 1.13"
  40. gem "dry-types", "~> 1.7"
  41. gem "dry-validation", "~> 1.10"
  42. gem "htmx", "~> 2.1"
  43. gem "overmind", "~> 2.5"
  44. gem "puma", "~> 7.0"
  45. gem "rack-attack", "~> 6.7"
  46. CONTENT
  47. end
  48. 1 def insert_persistence
  49. 7 with_template.insert_after "source", <<~CONTENT
  50. gem "pg", "~> 1.5"
  51. gem "rom", "~> 5.4"
  52. gem "rom-sql", "~> 3.7"
  53. gem "sequel", "~> 5.89"
  54. CONTENT
  55. end
  56. 1 def insert_quality
  57. 7 with_template.insert_after(/group :quality/, %( gem "rubocop-sequel", "~> 0.4"\n))
  58. end
  59. 1 def insert_devtest
  60. 7 with_template.insert_before(/group :development/, <<~CONTENT)
  61. group :development, :test do
  62. gem "dotenv", "~> 3.1"
  63. end
  64. CONTENT
  65. end
  66. 1 def insert_development
  67. 7 with_template.insert_after(/group :development do/, <<~CONTENT.gsub("gem", " gem"))
  68. gem "hanami-webconsole", "~> 2.2.0"
  69. gem "localhost", "~> 1.3"
  70. gem "rerun", "~> 0.14"
  71. CONTENT
  72. end
  73. 1 def insert_test
  74. 7 with_template.insert_after(/group :test/, <<~CONTENT.gsub("gem", " gem"))
  75. gem "capybara", "~> 3.40"
  76. gem "capybara-validate_html5", "~> 2.1"
  77. gem "cuprite", "~> 0.15"
  78. gem "database_cleaner-sequel", "~> 2.0"
  79. gem "launchy", "~> 3.1"
  80. gem "rack-test", "~> 2.2"
  81. gem "rom-factory", "~> 0.13"
  82. CONTENT
  83. end
  84. 1 def remove_zeitwerk = with_template.replace(/.+zeitwerk.+\n\n/, "\n")
  85. 1 def with_template
  86. 58 builder.call settings.with(template_path: "%project_name%/Gemfile.erb")
  87. end
  88. end
  89. end
  90. end

lib/hanamismith/builders/caliber.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton with Caliber style support.
  6. 1 class Caliber < Rubysmith::Builders::Caliber
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 8 else: 4 then: 4 return false unless settings.build_caliber
  10. 4 super
  11. 4 path = "%project_name%/.config/rubocop/config.yml.erb"
  12. 4 builder.call(settings.with(template_path: path))
  13. .append("\nplugins: rubocop-sequel\n")
  14. 4 true
  15. end
  16. end
  17. end
  18. end

lib/hanamismith/builders/circle_ci.rb

100.0% lines covered

100.0% branches covered

16 relevant lines. 16 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 require "securerandom"
  4. 1 module Hanamismith
  5. 1 module Builders
  6. # Builds project skeleton Circle CI configuration.
  7. 1 class CircleCI < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def initialize(generator: SecureRandom, **)
  10. 10 @generator = generator
  11. 10 super(**)
  12. end
  13. 1 def call
  14. 10 else: 6 then: 4 return false unless settings.build_circle_ci
  15. 6 path = "%project_name%/.circleci/config.yml.erb"
  16. 6 builder.call(settings.with(template_path: path))
  17. .render
  18. .replace("<app_secret>", generator.hex(30))
  19. .replace(/\n\n\Z/, "\n")
  20. 6 true
  21. end
  22. 1 private
  23. 1 attr_reader :generator
  24. end
  25. end
  26. end

lib/hanamismith/builders/console.rb

100.0% lines covered

100.0% branches covered

16 relevant lines. 16 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton console for object inspection and exploration.
  6. 1 class Console < Rubysmith::Builders::Console
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 8 else: 4 then: 4 return false unless settings.build_console
  10. 4 super
  11. 4 builder.call(settings.with(template_path: "%project_name%/bin/console.erb"))
  12. .replace(/require Bundler.root.+/, %(require "hanami/prepare"))
  13. 4 add_irb_autocomplete
  14. 4 true
  15. end
  16. 1 private
  17. 1 def add_irb_autocomplete
  18. 4 with_template.insert_before "IRB.start", <<~CODE
  19. unless Hanami.env? :development, :test
  20. ENV["IRB_USE_AUTOCOMPLETE"] ||= "false"
  21. puts "IRB autocomplete disabled."
  22. end
  23. CODE
  24. end
  25. 1 def with_template
  26. 4 builder.call settings.with(template_path: "%project_name%/bin/console.erb")
  27. end
  28. end
  29. end
  30. end

lib/hanamismith/builders/core.rb

100.0% lines covered

100.0% branches covered

40 relevant lines. 40 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton foundation.
  6. 1 class Core < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 364 private_methods.grep(/\Aadd_/).sort.each { |method| __send__ method }
  10. 26 true
  11. end
  12. 1 private
  13. 1 def add_db_relation
  14. 26 builder.call(settings.with(template_path: "%project_name%/app/db/relation.rb.erb")).render
  15. end
  16. 1 def add_db_repository
  17. 26 builder.call(settings.with(template_path: "%project_name%/app/db/repository.rb.erb")).render
  18. end
  19. 1 def add_db_struct
  20. 26 builder.call(settings.with(template_path: "%project_name%/app/db/struct.rb.erb")).render
  21. end
  22. 1 def add_action
  23. 26 builder.call(settings.with(template_path: "%project_name%/app/action.rb.erb")).render
  24. end
  25. 1 def add_view
  26. 26 builder.call(settings.with(template_path: "%project_name%/app/view.rb.erb")).render
  27. end
  28. 1 def add_application_configuration
  29. 26 builder.call(settings.with(template_path: "%project_name%/config/app.rb.erb")).render
  30. end
  31. 1 def add_routes_configuration
  32. 26 builder.call(settings.with(template_path: "%project_name%/config/routes.rb.erb")).render
  33. end
  34. 1 def add_settings_configuration
  35. 26 builder.call(settings.with(template_path: "%project_name%/config/settings.rb.erb")).render
  36. end
  37. 1 def add_types
  38. 26 path = "%project_name%/lib/%project_path%/types.rb.erb"
  39. 26 builder.call(settings.with(template_path: path)).render
  40. end
  41. 1 def add_migrate_directory
  42. 26 builder.call(settings.with(template_path: "%project_name%/db/migrate")).make_path
  43. end
  44. 1 def add_well_known_security_text
  45. 26 else: 17 then: 9 return unless settings.build_security
  46. 17 path = "%project_name%/public/.well-known/security.txt.erb"
  47. 17 builder.call(settings.with(template_path: path)).render
  48. end
  49. 1 def add_public_http_errors
  50. 26 %w[404 500].each do |code|
  51. 52 path = "%project_name%/public/#{code}.html.erb"
  52. 52 builder.call(settings.with(template_path: path)).render
  53. end
  54. end
  55. 1 def add_temp_directory
  56. 26 builder.call(settings.with(template_path: "%project_name%/tmp")).make_path
  57. end
  58. end
  59. end
  60. end

lib/hanamismith/builders/docker/compose.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Docker
  6. # Builds Docker compose configuration.
  7. 1 class Compose < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 8 else: 4 then: 4 return false unless settings.build_docker
  11. 4 builder.call(settings.with(template_path: "%project_name%/compose.yml.erb")).render
  12. 4 true
  13. end
  14. end
  15. end
  16. end
  17. end

lib/hanamismith/builders/docker/file.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Docker
  6. # Builds Dockerfile configuration.
  7. 1 class File < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 15 else: 11 then: 4 return false unless settings.build_docker
  11. 11 builder.call(settings.with(template_path: "%project_name%/Dockerfile.erb")).render
  12. 11 true
  13. end
  14. end
  15. end
  16. end
  17. end

lib/hanamismith/builders/documentation/readme.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Documentation
  6. # Builds project skeleton README documentation.
  7. 1 class Readme < Rubysmith::Builders::Documentation::Readme
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 10 else: 6 then: 4 return false unless settings.build_readme
  11. 6 super
  12. 6 builder.call(settings.with(template_path: "%project_name%/README.#{kind}.erb"))
  13. .replace("Rubysmith", "Hanamismith")
  14. .replace("rubysmith", "hanamismith")
  15. 6 true
  16. end
  17. end
  18. end
  19. end
  20. end

lib/hanamismith/builders/environments/all.rb

100.0% lines covered

100.0% branches covered

15 relevant lines. 15 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 require "securerandom"
  4. 1 module Hanamismith
  5. 1 module Builders
  6. 1 module Environments
  7. # Builds test environment skeleton.
  8. 1 class All < Rubysmith::Builders::Abstract
  9. 1 using Refinements::Struct
  10. 1 def initialize(generator: SecureRandom, **)
  11. 6 @generator = generator
  12. 6 super(**)
  13. end
  14. 1 def call
  15. 6 builder.call(settings.with(template_path: "%project_name%/env.erb"))
  16. .render
  17. .replace("<app_secret>", generator.hex(40))
  18. .replace("<pg_password>", generator.hex(15))
  19. .rename(".env")
  20. 6 true
  21. end
  22. 1 private
  23. 1 attr_reader :generator
  24. end
  25. end
  26. end
  27. end

lib/hanamismith/builders/environments/development.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Environments
  6. # Builds development environment skeleton.
  7. 1 class Development < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 6 builder.call(settings.with(template_path: "%project_name%/env.development.erb"))
  11. .render
  12. .rename(".env.development")
  13. 6 true
  14. end
  15. end
  16. end
  17. end
  18. end

lib/hanamismith/builders/environments/test.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Environments
  6. # Builds test environment skeleton.
  7. 1 class Test < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 6 builder.call(settings.with(template_path: "%project_name%/env.test.erb"))
  11. .render
  12. .rename(".env.test")
  13. 6 true
  14. end
  15. end
  16. end
  17. end
  18. end

lib/hanamismith/builders/git/commit.rb

100.0% lines covered

100.0% branches covered

5 relevant lines. 5 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Hanamismith
  3. 1 module Builders
  4. 1 module Git
  5. # Builds project skeleton initial Git commit message.
  6. 1 class Commit < Rubysmith::Builders::Git::Commit
  7. 1 include Dependencies[:specification]
  8. end
  9. end
  10. end
  11. end

lib/hanamismith/builders/git/ignore.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Git
  6. # Builds project skeleton Git ignore.
  7. 1 class Ignore < Rubysmith::Builders::Git::Ignore
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 8 else: 4 then: 4 return false unless settings.build_git
  11. 4 super
  12. 4 builder.call(settings.with(template_path: "%project_name%/.gitignore.erb"))
  13. .insert_before "tmp\n", <<~CONTENT
  14. node_modules
  15. public/assets
  16. public/assets.json
  17. CONTENT
  18. 4 true
  19. end
  20. end
  21. end
  22. end
  23. end

lib/hanamismith/builders/git_hub/ci.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module GitHub
  6. # Builds project skeleton GitHub CI configuration.
  7. 1 class CI < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 10 else: 6 then: 4 return false unless settings.build_git_hub_ci
  11. 6 path = "%project_name%/.github/workflows/ci.yml.erb"
  12. 6 builder.call(settings.with(template_path: path)).render.replace(/\n\n\Z/, "\n")
  13. 6 true
  14. end
  15. end
  16. end
  17. end
  18. end

lib/hanamismith/builders/icon.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton SVG icon.
  6. 1 class Icon < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 6 path = "%project_name%/app/assets/images/icon.svg.erb"
  10. 6 builder.call(settings.with(template_path: path)).render
  11. 6 true
  12. end
  13. end
  14. end
  15. end

lib/hanamismith/builders/javascript.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton javascript.
  6. 1 class Javascript < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 6 path = "%project_name%/app/assets/js/app.js.erb"
  10. 6 builder.call(settings.with(template_path: path)).render
  11. 6 true
  12. end
  13. end
  14. end
  15. end

lib/hanamismith/builders/layout.rb

100.0% lines covered

100.0% branches covered

25 relevant lines. 25 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds app layout.
  6. 1 class Layout < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 7 path = "%project_name%/app/templates/layouts/app.html.erb.erb"
  10. 7 builder.call(settings.with(template_path: path))
  11. .render
  12. .replace("<!-- title -->", "<%= content_for :title %>")
  13. .replace("<!-- favicon -->", favicon)
  14. .replace("<!-- icon -->", icon)
  15. .replace("<!-- apple_icon -->", apple_icon)
  16. .replace("<!-- manifest -->", manifest)
  17. .replace("<!-- stylesheet -->", stylesheet)
  18. .replace("<!-- javascript -->", javascript)
  19. .replace("<!-- yield -->", "<%= yield %>")
  20. .replace("<!-- flash:alert -->", flash(:alert))
  21. .replace("<!-- flash:notice -->", flash(:notice))
  22. 7 true
  23. end
  24. 1 private
  25. 1 def favicon
  26. 7 uri = "https://alchemists.io/images/projects/hanamismith/icons/favicon.ico"
  27. 7 %(<%= tag.link title: "#{settings.project_label}: Favicon",\n) +
  28. %( rel: :icon,\n) +
  29. %( href: "#{uri}",\n) +
  30. %( sizes: "32x32" %>)
  31. end
  32. 1 def icon
  33. 7 %(<%= tag.link title: "#{settings.project_label}: Icon",\n) +
  34. %( rel: :icon,\n) +
  35. %( href: app_assets["icon.svg"],\n) +
  36. %( type: "image/svg+xml" %>)
  37. end
  38. 1 def apple_icon
  39. 7 uri = "https://alchemists.io/images/projects/hanamismith/icons/apple.png"
  40. 7 %(<%= tag.link title: "#{settings.project_label}: Apple Icon",\n) +
  41. %( rel: "apple-touch-icon",\n) +
  42. %( href: "#{uri}",\n) +
  43. %( type: "image/png" %>)
  44. end
  45. # :reek:UtilityFunction
  46. 1 def flash kind
  47. 14 %(<% if flash[:#{kind}] %>\n) +
  48. %( <div class="site-#{kind}">\n) +
  49. %( <p><%= flash[:#{kind}] %></p>\n) +
  50. %( </div>\n) +
  51. %( <% end %>\n)
  52. end
  53. 1 def manifest
  54. 7 %(<%= tag.link title: "#{settings.project_label}: Manifest",\n) +
  55. %( rel: :manifest,\n) +
  56. %( href: app_assets["manifest.webmanifest"] %>)
  57. end
  58. 1 def stylesheet
  59. 7 %(<%= tag.link title: "#{settings.project_label}: Stylesheet", rel: :stylesheet, ) +
  60. %(href: app_assets["app.css"] %>)
  61. end
  62. 1 def javascript = %(<%= tag.script src: app_assets["app.js"], type: "text/javascript" %>)
  63. end
  64. end
  65. end

lib/hanamismith/builders/node.rb

100.0% lines covered

100.0% branches covered

30 relevant lines. 30 lines covered and 0 lines missed.
5 total branches, 5 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "dry/monads"
  3. 1 require "refinements/pathname"
  4. 1 require "refinements/struct"
  5. 1 module Hanamismith
  6. 1 module Builders
  7. # Builds project skeleton for Node.
  8. 1 class Node < Rubysmith::Builders::Abstract
  9. 1 include Dry::Monads[:result]
  10. 1 using Refinements::Struct
  11. 1 using Refinements::Pathname
  12. 1 def initialize(executor: Open3, **)
  13. 10 @executor = executor
  14. 10 super(**)
  15. end
  16. 1 def call
  17. 10 build_version
  18. 10 builder.call(settings.with(template_path: "%project_name%/package.json.erb")).render
  19. 10 true
  20. end
  21. 1 private
  22. 1 attr_reader :executor
  23. 1 def build_version
  24. 10 in: 7 case load_version
  25. 7 in: 2 in Success(text) then version_path.make_ancestors.write text.delete_prefix("v")
  26. 2 else: 1 in Failure(message) then log_error message
  27. 1 else log_error "Shell failure. Is your environment configured properly?"
  28. end
  29. end
  30. 1 def load_version
  31. 10 executor.capture3("node", "--version").then do |stdout, _stderr, status|
  32. 8 then: 7 else: 1 return Success stdout if status.success?
  33. 1 Failure "Unable to obtain version for #{version_path.inspect}."
  34. end
  35. rescue Errno::ENOENT
  36. 1 Failure "Unable to find Node. Is Node installed?"
  37. end
  38. 1 def version_path = settings.project_root.join ".node-version"
  39. 4 def log_error(message) = logger.error { message }
  40. end
  41. end
  42. end

lib/hanamismith/builders/providers/htmx.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Providers
  6. # Builds project skeleton for HTMX provider.
  7. 1 class HTMX < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 6 path = "%project_name%/config/providers/htmx.rb.erb"
  11. 6 builder.call(settings.with(template_path: path)).render
  12. 6 true
  13. end
  14. end
  15. end
  16. end
  17. end

lib/hanamismith/builders/puma/configuration.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Puma
  6. # Builds project skeleton Puma configuration.
  7. 1 class Configuration < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 6 builder.call(settings.with(template_path: "%project_name%/config/puma.rb.erb")).render
  11. 6 true
  12. end
  13. end
  14. end
  15. end
  16. end

lib/hanamismith/builders/puma/procfile.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Puma
  6. # Builds project skeleton Puma Procfile for production and development environments.
  7. 1 class Procfile < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 8 builder.call(settings.with(template_path: "%project_name%/Procfile.erb")).render
  11. 8 builder.call(settings.with(template_path: "%project_name%/Procfile.dev.erb")).render
  12. 8 true
  13. end
  14. end
  15. end
  16. end
  17. end

lib/hanamismith/builders/pwa.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton Progressive Web Application (PWA) manifest.
  6. 1 class PWA < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 6 path = "%project_name%/app/assets/pwa/manifest.webmanifest.erb"
  10. 6 builder.call(settings.with(template_path: path)).render
  11. 6 true
  12. end
  13. end
  14. end
  15. end

lib/hanamismith/builders/rack/attack.rb

100.0% lines covered

100.0% branches covered

16 relevant lines. 16 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Rack
  6. # Builds project skeleton.
  7. 1 class Attack < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 10 add_configuration
  11. 10 add_middleware
  12. 10 true
  13. end
  14. 1 private
  15. 1 def add_configuration
  16. 10 template_path = "%project_name%/config/initializers/rack_attack.rb.erb"
  17. 10 builder.call(settings.with(template_path:)).render
  18. end
  19. 1 def add_middleware
  20. 10 builder.call(settings.with(template_path: "%project_name%/config/app.rb.erb"))
  21. .insert_after(/require/, %(\nrequire_relative "initializers/rack_attack"\n))
  22. .insert_before(/environment/, " config.middleware.use Rack::Attack\n\n")
  23. end
  24. end
  25. end
  26. end
  27. end

lib/hanamismith/builders/rack/configuration.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Rack
  6. # Builds project skeleton.
  7. 1 class Configuration < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 6 builder.call(settings.with(template_path: "%project_name%/config.ru.erb")).render
  11. 6 true
  12. end
  13. end
  14. end
  15. end
  16. end

lib/hanamismith/builders/rack/deflater.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Rack
  6. # Builds project skeleton.
  7. 1 class Deflater < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 6 builder.call(settings.with(template_path: "%project_name%/config/app.rb.erb"))
  11. .insert_after(/Rack::Attack/, " config.middleware.use Rack::Deflater\n")
  12. 6 true
  13. end
  14. end
  15. end
  16. end
  17. end

lib/hanamismith/builders/rake/configuration.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Rake
  6. # Builds project skeleton Rake configuration file.
  7. 1 class Configuration < Rubysmith::Builders::Rake::Configuration
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 8 else: 4 then: 4 return false unless settings.build_rake
  11. 4 super
  12. 4 builder.call(settings.with(template_path: "%project_name%/Rakefile.erb"))
  13. .render
  14. .insert_after(%r(bundler/setup), %(require "hanami/rake_tasks"))
  15. 4 true
  16. end
  17. end
  18. end
  19. end
  20. end

lib/hanamismith/builders/refinement.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton foundation.
  6. 1 class Refinement < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 7 %w[
  10. %project_name%/lib/%project_path%/refines/actions/response.rb.erb
  11. %project_name%/spec/lib/%project_path%/refines/actions/response_spec.rb.erb
  12. ].each do |path|
  13. 14 builder.call(settings.with(template_path: path)).render
  14. end
  15. 7 true
  16. end
  17. end
  18. end
  19. end

lib/hanamismith/builders/rspec/application_shared_context.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module RSpec
  6. # Builds project skeleton RSpec application shared context.
  7. 1 class ApplicationSharedContext < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 8 else: 4 then: 4 return false unless settings.build_rspec
  11. 4 path = "%project_name%/spec/support/shared_contexts/application.rb.erb"
  12. 4 builder.call(settings.with(template_path: path)).render
  13. 4 true
  14. end
  15. end
  16. end
  17. end
  18. end

lib/hanamismith/builders/rspec/hanami.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module RSpec
  6. # Builds project skeleton RSpec helper.
  7. 1 class Hanami < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 8 else: 4 then: 4 return false unless settings.build_rspec
  11. 4 path = "%project_name%/spec/hanami_helper.rb.erb"
  12. 4 builder.call(settings.with(template_path: path)).render
  13. 4 true
  14. end
  15. end
  16. end
  17. end
  18. end

lib/hanamismith/builders/rspec/helper.rb

100.0% lines covered

100.0% branches covered

21 relevant lines. 21 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module RSpec
  6. # Builds project skeleton RSpec helper.
  7. 1 class Helper < Rubysmith::Builders::RSpec::Helper
  8. 1 using Refinements::Struct
  9. 1 def initialize(...)
  10. 10 super
  11. 10 @template = builder.call settings.with(
  12. template_path: "%project_name%/spec/spec_helper.rb.erb"
  13. )
  14. end
  15. 1 def call
  16. 10 else: 6 then: 4 return false unless settings.build_rspec
  17. 6 super
  18. 6 remove_project_requirement
  19. 6 disable_simple_cov_eval
  20. 6 true
  21. end
  22. 1 private
  23. 1 attr_reader :template
  24. 1 def remove_project_requirement
  25. 6 template.replace(/require.+#{settings.project_name}.+\n/, "")
  26. end
  27. 1 def disable_simple_cov_eval
  28. 6 template.replace(/\s{4}enable_coverage_for_eval\n/, "")
  29. end
  30. end
  31. end
  32. end
  33. end

lib/hanamismith/builders/setup.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton setup script.
  6. 1 class Setup < Rubysmith::Builders::Setup
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 10 else: 6 then: 4 return false unless settings.build_setup
  10. 6 super
  11. 6 append
  12. 6 true
  13. end
  14. 1 private
  15. 1 def append
  16. 6 builder.call(settings.with(template_path: "%project_name%/bin/setup.erb"))
  17. .insert_after(%(Runner.call "bundle install"\n), <<~CONTENT.gsub(/^(?=\w)/, " "))
  18. puts "Installing packages..."
  19. Runner.call "npm install"
  20. puts "Configuring databases..."
  21. Runner.call "hanami db prepare"
  22. puts "Compiling assets..."
  23. Runner.call "hanami assets compile"
  24. CONTENT
  25. end
  26. end
  27. end
  28. end

lib/hanamismith/builders/slices/health.rb

100.0% lines covered

100.0% branches covered

34 relevant lines. 34 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Slices
  6. # Builds health slice skeleton.
  7. 1 class Health < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 117 private_methods.grep(/\Aadd_/).sort.each { |method| __send__ method }
  11. 13 true
  12. end
  13. 1 private
  14. 1 def add_configuration
  15. 13 path = "%project_name%/config/slices/health.rb.erb"
  16. 13 builder.call(settings.with(template_path: path)).render
  17. end
  18. 1 def add_action
  19. 13 path = "%project_name%/slices/health/action.rb.erb"
  20. 13 builder.call(settings.with(template_path: path)).render
  21. end
  22. 1 def add_view
  23. 13 path = "%project_name%/slices/health/view.rb.erb"
  24. 13 builder.call(settings.with(template_path: path)).render
  25. end
  26. 1 def add_show_template
  27. 13 path = "%project_name%/slices/health/templates/show.html.erb.erb"
  28. 13 builder.call(settings.with(template_path: path))
  29. .render
  30. .replace(
  31. "<!-- title -->",
  32. %(<% content_for :title, "Health | #{settings.project_label}" %>)
  33. )
  34. .replace("<!-- color -->", %(<%= color %>))
  35. end
  36. 1 def add_context
  37. 13 path = "%project_name%/slices/health/views/context.rb.erb"
  38. 13 builder.call(settings.with(template_path: path)).render
  39. end
  40. 1 def add_show_view
  41. 13 path = "%project_name%/slices/health/views/show.rb.erb"
  42. 13 builder.call(settings.with(template_path: path)).render
  43. end
  44. 1 def add_show_action
  45. 13 path = "%project_name%/slices/health/actions/show.rb.erb"
  46. 13 builder.call(settings.with(template_path: path)).render
  47. end
  48. 1 def add_show_action_spec
  49. 13 path = "%project_name%/spec/slices/health/actions/show_spec.rb.erb"
  50. 13 builder.call(settings.with(template_path: path)).render
  51. end
  52. end
  53. end
  54. end
  55. end

lib/hanamismith/builders/slices/home.rb

100.0% lines covered

100.0% branches covered

37 relevant lines. 37 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. 1 module Slices
  6. # Builds home slice skeleton.
  7. 1 class Home < Rubysmith::Builders::Abstract
  8. 1 using Refinements::Struct
  9. 1 def call
  10. 150 private_methods.grep(/\Aadd_/).sort.each { |method| __send__ method }
  11. 15 true
  12. end
  13. 1 private
  14. 1 def add_configuration
  15. 15 path = "%project_name%/config/slices/home.rb.erb"
  16. 15 builder.call(settings.with(template_path: path)).render
  17. end
  18. 1 def add_action
  19. 15 path = "%project_name%/slices/home/action.rb.erb"
  20. 15 builder.call(settings.with(template_path: path)).render
  21. end
  22. 1 def add_repository
  23. 15 path = "%project_name%/slices/home/repository.rb.erb"
  24. 15 builder.call(settings.with(template_path: path)).render
  25. end
  26. 1 def add_view
  27. 15 path = "%project_name%/slices/home/view.rb.erb"
  28. 15 builder.call(settings.with(template_path: path)).render
  29. end
  30. 1 def add_context
  31. 15 path = "%project_name%/slices/home/views/context.rb.erb"
  32. 15 builder.call(settings.with(template_path: path)).render
  33. end
  34. 1 def add_show_template
  35. 15 path = "%project_name%/slices/home/templates/show.html.erb.erb"
  36. 15 builder.call(settings.with(template_path: path))
  37. .render
  38. .replace(
  39. "<!-- title -->",
  40. %(<% content_for :title, "#{settings.project_label}" %>)
  41. )
  42. .replace("<!-- ruby_version -->", "<%= ruby_version %>")
  43. .replace("<!-- hanami_version -->", "<%= hanami_version %>")
  44. end
  45. 1 def add_show_view
  46. 15 path = "%project_name%/slices/home/views/show.rb.erb"
  47. 15 builder.call(settings.with(template_path: path)).render
  48. end
  49. 1 def add_show_action
  50. 15 path = "%project_name%/slices/home/actions/show.rb.erb"
  51. 15 builder.call(settings.with(template_path: path)).render
  52. end
  53. 1 def add_request_spec
  54. 15 path = "%project_name%/spec/features/home_spec.rb.erb"
  55. 15 builder.call(settings.with(template_path: path)).render
  56. end
  57. end
  58. end
  59. end
  60. end

lib/hanamismith/builders/stylesheet.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/struct"
  3. 1 module Hanamismith
  4. 1 module Builders
  5. # Builds project skeleton stylesheet.
  6. 1 class Stylesheet < Rubysmith::Builders::Abstract
  7. 1 using Refinements::Struct
  8. 1 def call
  9. 10 %w[
  10. %project_name%/app/assets/css/settings.css.erb
  11. %project_name%/app/assets/css/colors.css.erb
  12. %project_name%/app/assets/css/view_transitions.css.erb
  13. %project_name%/app/assets/css/defaults.css.erb
  14. %project_name%/app/assets/css/layout.css.erb
  15. ].each do |path|
  16. 50 builder.call(settings.with(template_path: path)).render
  17. end
  18. 10 true
  19. end
  20. end
  21. end
  22. end

lib/hanamismith/cli/commands/build.rb

100.0% lines covered

100.0% branches covered

54 relevant lines. 54 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "sod"
  3. 1 module Hanamismith
  4. 1 module CLI
  5. 1 module Commands
  6. # Handles the build command.
  7. 1 class Build < Sod::Command
  8. 1 include Dependencies[:settings, :logger]
  9. # Order matters.
  10. BUILDERS = [
  11. 1 Rubysmith::Builders::Init,
  12. Builders::Core,
  13. Builders::Providers::HTMX,
  14. Builders::Refinement,
  15. Builders::Icon,
  16. Builders::Stylesheet,
  17. Builders::Javascript,
  18. Builders::PWA,
  19. Builders::Layout,
  20. Builders::Slices::Home,
  21. Builders::Slices::Health,
  22. Rubysmith::Builders::Version,
  23. Builders::Documentation::Readme,
  24. Rubysmith::Builders::Documentation::Citation,
  25. Rubysmith::Builders::Documentation::License,
  26. Rubysmith::Builders::Documentation::Version,
  27. Rubysmith::Builders::Git::Setup,
  28. Builders::Git::Ignore,
  29. Rubysmith::Builders::Git::Safe,
  30. Builders::Bundler,
  31. Builders::Node,
  32. Builders::Asset,
  33. Rubysmith::Builders::Rake::Binstub,
  34. Builders::Rake::Configuration,
  35. Builders::Binstub,
  36. Builders::Console,
  37. Builders::CircleCI,
  38. Rubysmith::Builders::GitHub::Template,
  39. Rubysmith::Builders::GitHub::Funding,
  40. Builders::GitHub::CI,
  41. Builders::Setup,
  42. Rubysmith::Builders::Reek,
  43. Rubysmith::Builders::RSpec::Binstub,
  44. Rubysmith::Builders::RSpec::Context,
  45. Builders::RSpec::ApplicationSharedContext,
  46. Builders::RSpec::Helper,
  47. Builders::RSpec::Hanami,
  48. Builders::Rack::Configuration,
  49. Builders::Rack::Attack,
  50. Builders::Rack::Deflater,
  51. Builders::Puma::Configuration,
  52. Builders::Puma::Procfile,
  53. Builders::Caliber,
  54. Rubysmith::Builders::DevContainer::Dockerfile,
  55. Rubysmith::Builders::DevContainer::Compose,
  56. Rubysmith::Builders::DevContainer::Configuration,
  57. Rubysmith::Builders::Docker::Build,
  58. Rubysmith::Builders::Docker::Console,
  59. Rubysmith::Builders::Docker::Entrypoint,
  60. Builders::Docker::Compose,
  61. Builders::Docker::File,
  62. Rubysmith::Builders::Docker::Ignore,
  63. Rubysmith::Extensions::Bundler,
  64. Rubysmith::Extensions::Pragmater,
  65. Rubysmith::Extensions::Tocer,
  66. Rubysmith::Extensions::Rubocop,
  67. Extensions::NPM,
  68. Extensions::Asset,
  69. Builders::Environments::All,
  70. Builders::Environments::Development,
  71. Builders::Environments::Test,
  72. Builders::Git::Commit
  73. ].freeze
  74. 1 handle "build"
  75. 1 description "Build new project."
  76. 1 on Rubysmith::CLI::Actions::Name, settings: Container[:settings]
  77. 1 on Rubysmith::CLI::Actions::AmazingPrint, settings: Container[:settings]
  78. 1 on Rubysmith::CLI::Actions::Bootsnap, settings: Container[:settings]
  79. 1 on Rubysmith::CLI::Actions::Caliber, settings: Container[:settings]
  80. 1 on Rubysmith::CLI::Actions::CircleCI, settings: Container[:settings]
  81. 1 on Rubysmith::CLI::Actions::Citation, settings: Container[:settings]
  82. 1 on Rubysmith::CLI::Actions::Community, settings: Container[:settings]
  83. 1 on Rubysmith::CLI::Actions::Conduct, settings: Container[:settings]
  84. 1 on Rubysmith::CLI::Actions::Console, settings: Container[:settings]
  85. 1 on Rubysmith::CLI::Actions::Contributions, settings: Container[:settings]
  86. 1 on Rubysmith::CLI::Actions::DCOO, settings: Container[:settings]
  87. 1 on Rubysmith::CLI::Actions::Debug, settings: Container[:settings]
  88. 1 on Rubysmith::CLI::Actions::DevContainer, settings: Container[:settings]
  89. 1 on Rubysmith::CLI::Actions::Docker, settings: Container[:settings]
  90. 1 on Rubysmith::CLI::Actions::Funding, settings: Container[:settings]
  91. 1 on Rubysmith::CLI::Actions::Git, settings: Container[:settings]
  92. 1 on Rubysmith::CLI::Actions::GitHub, settings: Container[:settings]
  93. 1 on Rubysmith::CLI::Actions::GitHubCI, settings: Container[:settings]
  94. 1 on Rubysmith::CLI::Actions::GitLint, settings: Container[:settings]
  95. 1 on Rubysmith::CLI::Actions::IRBKit, settings: Container[:settings]
  96. 1 on Rubysmith::CLI::Actions::License, settings: Container[:settings]
  97. 1 on Rubysmith::CLI::Actions::Maximum, settings: Container[:settings]
  98. 1 on Rubysmith::CLI::Actions::Minimum, settings: Container[:settings]
  99. 1 on Rubysmith::CLI::Actions::Monads, settings: Container[:settings]
  100. 1 on Rubysmith::CLI::Actions::Rake, settings: Container[:settings]
  101. 1 on Rubysmith::CLI::Actions::Readme, settings: Container[:settings]
  102. 1 on Rubysmith::CLI::Actions::Reek, settings: Container[:settings]
  103. 1 on Rubysmith::CLI::Actions::Refinements, settings: Container[:settings]
  104. 1 on Rubysmith::CLI::Actions::RSpec, settings: Container[:settings]
  105. 1 on Rubysmith::CLI::Actions::RTC, settings: Container[:settings]
  106. 1 on Rubysmith::CLI::Actions::Security, settings: Container[:settings]
  107. 1 on Rubysmith::CLI::Actions::Setup, settings: Container[:settings]
  108. 1 on Rubysmith::CLI::Actions::SimpleCov, settings: Container[:settings]
  109. 1 on Rubysmith::CLI::Actions::Versions, settings: Container[:settings]
  110. 1 on Rubysmith::CLI::Actions::Zeitwerk, settings: Container[:settings]
  111. 1 def initialize(builders: BUILDERS, **)
  112. 9 super(**)
  113. 9 @builders = builders
  114. end
  115. 1 def call
  116. 6 log_info "Building project skeleton: #{settings.project_name}..."
  117. 256 builders.each { |constant| constant.new(settings:, logger:).call }
  118. 6 log_info "Project skeleton complete!"
  119. end
  120. 1 private
  121. 1 attr_reader :builders
  122. 13 def log_info(message) = logger.info { message }
  123. end
  124. end
  125. end
  126. end

lib/hanamismith/cli/shell.rb

100.0% lines covered

100.0% branches covered

21 relevant lines. 21 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "sod"
  3. 1 module Hanamismith
  4. 1 module CLI
  5. # The main Command Line Interface (CLI) object.
  6. 1 class Shell
  7. 1 include Dependencies[:defaults_path, :xdg_config, :specification]
  8. 1 def initialize(context: Sod::Context, dsl: Sod, **)
  9. 7 super(**)
  10. 7 @context = context
  11. 7 @dsl = dsl
  12. end
  13. 1 def call(...) = cli.call(...)
  14. 1 private
  15. 1 attr_reader :context, :dsl
  16. 1 def cli
  17. 7 context = build_context
  18. 7 dsl.new :hanamismith, banner: specification.banner do
  19. 7 on(Sod::Prefabs::Commands::Config, context:)
  20. 7 on Commands::Build
  21. 7 on(Sod::Prefabs::Actions::Version, context:)
  22. 7 on Sod::Prefabs::Actions::Help, self
  23. end
  24. end
  25. 1 def build_context
  26. 7 context[defaults_path:, xdg_config:, version_label: specification.labeled_version]
  27. end
  28. end
  29. end
  30. end

lib/hanamismith/container.rb

100.0% lines covered

100.0% branches covered

19 relevant lines. 19 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "cogger"
  3. 1 require "containable"
  4. 1 require "etcher"
  5. 1 require "runcom"
  6. 1 require "spek"
  7. 1 module Hanamismith
  8. # Provides a global gem container for injection into other objects.
  9. 1 module Container
  10. 1 extend Containable
  11. 1 register :registry, as: :fresh do
  12. 172 contract = Rubysmith::Configuration::Contract
  13. 172 model = Rubysmith::Configuration::Model
  14. 172 Etcher::Registry.new(contract:, model:)
  15. .add_loader(:yaml, self[:defaults_path])
  16. .add_loader(:yaml, self[:xdg_config].active)
  17. .add_transformer(Rubysmith::Configuration::Transformers::GitHubUser.new)
  18. .add_transformer(Rubysmith::Configuration::Transformers::GitEmail.new)
  19. .add_transformer(Rubysmith::Configuration::Transformers::GitUser.new)
  20. .add_transformer(Rubysmith::Configuration::Transformers::TemplateRoot.new)
  21. .add_transformer(
  22. Rubysmith::Configuration::Transformers::TemplateRoot.new(
  23. default: Pathname(__dir__).join("templates")
  24. )
  25. )
  26. .add_transformer(:root, :target_root)
  27. .add_transformer(:format, :author_uri)
  28. .add_transformer(:format, :citation_affiliation)
  29. .add_transformer(:format, :project_uri_community)
  30. .add_transformer(:format, :project_uri_conduct)
  31. .add_transformer(:format, :project_uri_contributions)
  32. .add_transformer(:format, :project_uri_dcoo)
  33. .add_transformer(:format, :project_uri_download, :project_name)
  34. .add_transformer(:format, :project_uri_funding)
  35. .add_transformer(:format, :project_uri_home, :project_name)
  36. .add_transformer(:format, :project_uri_issues, :project_name)
  37. .add_transformer(:format, :project_uri_license)
  38. .add_transformer(:format, :project_uri_security)
  39. .add_transformer(:format, :project_uri_source, :project_name)
  40. .add_transformer(:format, :project_uri_versions, :project_name)
  41. .add_transformer(:time, :loaded_at)
  42. end
  43. 2 register(:settings) { Etcher.call(self[:registry]).dup }
  44. 8 register(:specification) { Spek::Loader.call "#{__dir__}/../../hanamismith.gemspec" }
  45. 2 register(:defaults_path) { Rubysmith::Container[:defaults_path] }
  46. 2 register(:xdg_config) { Runcom::Config.new "hanamismith/configuration.yml" }
  47. 1 register(:logger) { Cogger.new id: :hanamismith }
  48. 1 register :kernel, Kernel
  49. 1 register :io, STDOUT
  50. end
  51. end

lib/hanamismith/dependencies.rb

100.0% lines covered

100.0% branches covered

3 relevant lines. 3 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "infusible"
  3. 1 module Hanamismith
  4. 1 Dependencies = Infusible[Container]
  5. end

lib/hanamismith/extensions/asset.rb

100.0% lines covered

100.0% branches covered

10 relevant lines. 10 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Hanamismith
  3. 1 module Extensions
  4. # Ensures assets are compiled.
  5. 1 class Asset
  6. 1 include Dependencies[:settings, :kernel, :logger]
  7. 1 def call
  8. 8 else: 6 then: 1 logger.error { "Unable to compile assets. Try: `hanami assets compile`." } unless compile
  9. 7 true
  10. end
  11. 1 private
  12. 1 def compile
  13. 7 kernel.system "node config/assets.js -- --path=app --dest=public/assets > /dev/null 2>&1",
  14. chdir: settings.project_root
  15. end
  16. end
  17. end
  18. end

lib/hanamismith/extensions/npm.rb

100.0% lines covered

100.0% branches covered

17 relevant lines. 17 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "refinements/io"
  3. 1 require "refinements/pathname"
  4. 1 module Hanamismith
  5. 1 module Extensions
  6. # Ensures NPM packages are installed if NPM is available.
  7. 1 class NPM
  8. 1 include Dependencies[:settings, :kernel, :logger]
  9. 1 using Refinements::IO
  10. 1 using Refinements::Pathname
  11. 1 def call
  12. 8 else: 6 then: 1 logger.error { "Unable to detect NPM. Install NPM and run: `npm install`." } unless run
  13. 7 true
  14. end
  15. 1 private
  16. 1 def run
  17. 7 success = false
  18. 7 settings.project_root.change_dir do
  19. 14 STDOUT.squelch { success = kernel.system "command -v npm && npm install" }
  20. end
  21. 7 success
  22. end
  23. end
  24. end
  25. end