loading
Generated 2025-10-09T00:04:03+00:00

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

6 files in total.
102 relevant lines, 102 lines covered and 0 lines missed. ( 100.0% )
5 total branches, 5 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
lib/spek.rb 100.00 % 16 8 8 0 1.38 100.00 % 0 0 0
lib/spek/finder.rb 100.00 % 19 9 9 0 1.67 100.00 % 0 0 0
lib/spek/loader.rb 100.00 % 19 9 9 0 4.22 100.00 % 0 0 0
lib/spek/picker.rb 100.00 % 41 22 22 0 1.64 100.00 % 3 3 0
lib/spek/presenter.rb 100.00 % 91 42 42 0 3.43 100.00 % 2 2 0
lib/spek/versioner.rb 100.00 % 25 12 12 0 1.75 100.00 % 0 0 0

lib/spek.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 "zeitwerk"
  3. 1 Zeitwerk::Loader.new.then do |loader|
  4. 1 loader.tag = File.basename __FILE__, ".rb"
  5. 1 loader.push_dir __dir__
  6. 1 loader.setup
  7. end
  8. # Main namespace.
  9. 1 module Spek
  10. 1 def self.loader registry = Zeitwerk::Registry
  11. 4 @loader ||= registry.loaders.each.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
  12. end
  13. end

lib/spek/finder.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 module Spek
  3. # Finds multiple versions of an installed gem (if any) and answers found specifications.
  4. 1 class Finder
  5. 1 def self.call(path, ...) = new(...).call path
  6. 1 def initialize client: ::Gem::Specification, presenter: Presenter
  7. 3 @client = client
  8. 3 @presenter = presenter
  9. end
  10. 3 def call(name) = client.find_all_by_name(name).map { |record| presenter.with_default record }
  11. 1 private
  12. 1 attr_reader :client, :presenter
  13. end
  14. end

lib/spek/loader.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 module Spek
  3. # Loads a gem's specification.
  4. 1 class Loader
  5. 1 def self.call(path, ...) = new(...).call path
  6. 1 def initialize client: ::Gem::Specification, presenter: Presenter
  7. 10 @client = client
  8. 10 @presenter = presenter
  9. end
  10. 12 def call(path) = client.load(path.to_s).then { |record| presenter.with_default record }
  11. 1 private
  12. 1 attr_reader :client, :presenter
  13. end
  14. end

lib/spek/picker.rb

100.0% lines covered

100.0% branches covered

22 relevant lines. 22 lines covered and 0 lines missed.
3 total branches, 3 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "dry/monads"
  3. 1 module Spek
  4. # Picks a gem specification.
  5. 1 class Picker
  6. 1 include Dry::Monads[:result]
  7. 1 def self.call(name, ...) = new(...).call name
  8. 1 def initialize finder: Finder.new, kernel: Kernel
  9. 4 @finder = finder
  10. 4 @kernel = kernel
  11. end
  12. 1 def call name
  13. 4 specifications = finder.call name
  14. 4 when: 2 case specifications.size
  15. 2 when: 1 when 1 then Success specifications.first
  16. 1 else: 1 when 2.. then Success choose(specifications)
  17. 1 else Failure "Unknown or uninstalled gem: #{name}."
  18. end
  19. end
  20. 1 def choose specifications
  21. 1 specifications.each.with_index 1 do |specification, index|
  22. 2 kernel.puts "#{index}. #{specification.named_version}"
  23. end
  24. 1 kernel.puts "\nPlease enter gem selection:"
  25. 1 ARGV.clear
  26. 1 specifications[kernel.gets.chomp.to_i - 1]
  27. end
  28. 1 private
  29. 1 attr_reader :finder, :kernel
  30. end
  31. end

lib/spek/presenter.rb

100.0% lines covered

100.0% branches covered

42 relevant lines. 42 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "core"
  3. 1 require "forwardable"
  4. 1 require "refinements/array"
  5. 1 require "refinements/pathname"
  6. 1 require "refinements/string"
  7. 1 require "versionaire"
  8. 1 module Spek
  9. # Enhances the default Ruby Gems specification.
  10. 1 class Presenter
  11. 1 extend Forwardable
  12. 1 using Refinements::Array
  13. 1 using Refinements::String
  14. 1 using Refinements::Pathname
  15. 1 using Versionaire::Cast
  16. 1 delegate %i[
  17. bindir
  18. executables
  19. extra_rdoc_files
  20. files
  21. license
  22. metadata
  23. name
  24. platform
  25. require_paths
  26. required_ruby_version
  27. runtime_dependencies
  28. summary
  29. ] => :record
  30. 1 def self.with_default record = nil, model: Gem::Specification
  31. 16 then: 14 else: 2 record && record.is_a?(model) ? new(record) : new(model.new)
  32. end
  33. 1 def initialize record
  34. 87 @record = record
  35. end
  36. 1 def allowed_push_host = metadata.fetch "allowed_push_host", ::Gem::DEFAULT_HOST
  37. 1 def allowed_push_key = metadata.fetch "allowed_push_key", "rubygems_api_key"
  38. 1 def authors = Array record.author
  39. 1 def banner(delimiter: ": ") = [labeled_version, summary].tap(&:compress!).join delimiter
  40. 2 def certificate_chain = Array(record.cert_chain).map { |path| Pathname path.to_s }
  41. 1 def documentation_url = metadata.fetch "documentation_uri", Core::EMPTY_STRING
  42. 1 def emails = Array record.email
  43. 1 def funding_url = metadata.fetch "funding_uri", Core::EMPTY_STRING
  44. 1 def homepage_url = String record.homepage
  45. 1 def issues_url = metadata.fetch "bug_tracker_uri", Core::EMPTY_STRING
  46. 1 def label = metadata.fetch "label", Core::EMPTY_STRING
  47. 1 def labeled_summary(delimiter: ": ") = [label, summary].tap(&:compress!).join delimiter
  48. 1 def labeled_version = [label, version].tap(&:compress!).join " "
  49. 1 def named_version = [name, version].tap(&:compress!).join " "
  50. 1 def package_name = %(#{[name, version].tap(&:compress!).join "-"}.gem)
  51. 1 def package_path = Pathname("tmp").join package_name
  52. 1 def rubygems_mfa? = metadata.fetch("rubygems_mfa_required", "false").truthy?
  53. 1 def signing_key = Pathname record.signing_key.to_s
  54. 1 def source_path = Pathname record.full_gem_path
  55. 1 def source_url = metadata.fetch "source_code_uri", Core::EMPTY_STRING
  56. 1 def version = Version record.version.to_s
  57. 1 def versions_url = metadata.fetch "changelog_uri", Core::EMPTY_STRING
  58. 1 private
  59. 1 attr_reader :record
  60. end
  61. end

lib/spek/versioner.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 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/pathname"
  3. 1 module Spek
  4. # Updates a gem specification's version.
  5. 1 class Versioner
  6. 1 using Refinements::Pathname
  7. 1 def self.call(version, path, ...) = new(...).call version, path
  8. 1 def initialize loader: Loader.new
  9. 3 @loader = loader
  10. end
  11. 1 def call version, path
  12. 6 Pathname(path).rewrite { |content| content.sub(/version.+\n/, %(version = "#{version}"\n)) }
  13. 3 loader.call path
  14. end
  15. 1 private
  16. 1 attr_reader :loader
  17. end
  18. end