loading
Generated 2025-10-09T00:00:21+00:00

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

62 files in total.
793 relevant lines, 793 lines covered and 0 lines missed. ( 100.0% )
14 total branches, 14 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/pennyworth.rb 100.00 % 20 9 9 0 1.33 100.00 % 0 0 0
lib/pennyworth/../../pennyworth.gemspec 100.00 % 45 30 30 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/encoding.rb 100.00 % 20 9 9 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/gem.rb 100.00 % 22 10 10 0 3.30 100.00 % 0 0 0
lib/pennyworth/cli/actions/git_hub/organization.rb 100.00 % 24 11 11 0 3.09 100.00 % 0 0 0
lib/pennyworth/cli/actions/git_hub/user.rb 100.00 % 24 11 11 0 3.09 100.00 % 0 0 0
lib/pennyworth/cli/actions/htmx/example.rb 100.00 % 22 10 10 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/htmx/extension.rb 100.00 % 22 10 10 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/htmx/reference.rb 100.00 % 22 10 10 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/http_status.rb 100.00 % 20 9 9 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/rodauth.rb 100.00 % 20 9 9 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/standard_error.rb 100.00 % 20 9 9 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/standard_gem.rb 100.00 % 35 15 15 0 4.33 100.00 % 0 0 0
lib/pennyworth/cli/actions/system/error.rb 100.00 % 22 10 10 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/system/signal.rb 100.00 % 22 10 10 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/actions/text.rb 100.00 % 20 9 9 0 1.00 100.00 % 0 0 0
lib/pennyworth/cli/shell.rb 100.00 % 59 36 36 0 14.19 100.00 % 0 0 0
lib/pennyworth/configuration/contract.rb 100.00 % 27 20 20 0 1.00 100.00 % 0 0 0
lib/pennyworth/configuration/model.rb 100.00 % 22 3 3 0 1.00 100.00 % 0 0 0
lib/pennyworth/container.rb 100.00 % 106 44 44 0 9.70 100.00 % 0 0 0
lib/pennyworth/dependencies.rb 100.00 % 7 3 3 0 1.00 100.00 % 0 0 0
lib/pennyworth/inflector.rb 100.00 % 18 8 8 0 91.25 100.00 % 0 0 0
lib/pennyworth/loaders/encoding.rb 100.00 % 31 14 14 0 32.29 100.00 % 0 0 0
lib/pennyworth/loaders/gem.rb 100.00 % 21 9 9 0 1.78 100.00 % 2 2 0
lib/pennyworth/loaders/git_hub.rb 100.00 % 21 10 10 0 3.10 100.00 % 0 0 0
lib/pennyworth/loaders/htmx.rb 100.00 % 62 31 31 0 288.42 100.00 % 6 6 0
lib/pennyworth/loaders/http_status.rb 100.00 % 28 14 14 0 18.50 100.00 % 0 0 0
lib/pennyworth/loaders/rodauth.rb 100.00 % 54 26 26 0 26.77 100.00 % 2 2 0
lib/pennyworth/loaders/standard_error.rb 100.00 % 27 13 13 0 1022.38 100.00 % 0 0 0
lib/pennyworth/loaders/standard_gem.rb 100.00 % 23 10 10 0 2.00 100.00 % 2 2 0
lib/pennyworth/loaders/system/error.rb 100.00 % 29 14 14 0 94.36 100.00 % 0 0 0
lib/pennyworth/loaders/system/signal.rb 100.00 % 21 10 10 0 15.40 100.00 % 0 0 0
lib/pennyworth/loaders/text.rb 100.00 % 27 13 13 0 3.54 100.00 % 0 0 0
lib/pennyworth/models/encoding.rb 100.00 % 8 3 3 0 1.00 100.00 % 0 0 0
lib/pennyworth/models/htmx.rb 100.00 % 8 3 3 0 1.00 100.00 % 0 0 0
lib/pennyworth/models/http_status.rb 100.00 % 12 5 5 0 40.00 100.00 % 0 0 0
lib/pennyworth/models/rodauth.rb 100.00 % 8 3 3 0 1.00 100.00 % 0 0 0
lib/pennyworth/models/standard_error.rb 100.00 % 12 5 5 0 296.20 100.00 % 0 0 0
lib/pennyworth/models/system/error.rb 100.00 % 10 4 4 0 1.00 100.00 % 0 0 0
lib/pennyworth/models/system/signal.rb 100.00 % 10 4 4 0 1.00 100.00 % 0 0 0
lib/pennyworth/models/text.rb 100.00 % 8 3 3 0 1.00 100.00 % 0 0 0
lib/pennyworth/presenters/encoding.rb 100.00 % 22 10 10 0 13.60 100.00 % 0 0 0
lib/pennyworth/presenters/gem.rb 100.00 % 44 22 22 0 6.09 100.00 % 0 0 0
lib/pennyworth/presenters/htmx.rb 100.00 % 24 11 11 0 42.64 100.00 % 0 0 0
lib/pennyworth/presenters/http_status.rb 100.00 % 41 18 18 0 22.56 100.00 % 0 0 0
lib/pennyworth/presenters/repository.rb 100.00 % 35 17 17 0 8.76 100.00 % 0 0 0
lib/pennyworth/presenters/rodauth.rb 100.00 % 24 11 11 0 10.64 100.00 % 0 0 0
lib/pennyworth/presenters/standard_error.rb 100.00 % 28 13 13 0 152.31 100.00 % 2 2 0
lib/pennyworth/presenters/standard_gem.rb 100.00 % 44 23 23 0 13.48 100.00 % 0 0 0
lib/pennyworth/presenters/system/error.rb 100.00 % 28 13 13 0 21.62 100.00 % 0 0 0
lib/pennyworth/presenters/system/signal.rb 100.00 % 22 10 10 0 8.00 100.00 % 0 0 0
lib/pennyworth/presenters/text.rb 100.00 % 25 12 12 0 5.17 100.00 % 0 0 0
lib/pennyworth/processor.rb 100.00 % 29 15 15 0 335.27 100.00 % 0 0 0
lib/pennyworth/serializers/encoding.rb 100.00 % 35 12 12 0 21.50 100.00 % 0 0 0
lib/pennyworth/serializers/htmx.rb 100.00 % 51 16 16 0 171.31 100.00 % 0 0 0
lib/pennyworth/serializers/http_status.rb 100.00 % 41 14 14 0 26.71 100.00 % 0 0 0
lib/pennyworth/serializers/project.rb 100.00 % 52 16 16 0 60.19 100.00 % 0 0 0
lib/pennyworth/serializers/rodauth.rb 100.00 % 52 16 16 0 45.75 100.00 % 0 0 0
lib/pennyworth/serializers/standard_error.rb 100.00 % 41 15 15 0 196.60 100.00 % 0 0 0
lib/pennyworth/serializers/system/error.rb 100.00 % 46 15 15 0 53.80 100.00 % 0 0 0
lib/pennyworth/serializers/system/signal.rb 100.00 % 40 14 14 0 15.57 100.00 % 0 0 0
lib/pennyworth/serializers/text.rb 100.00 % 31 11 11 0 4.82 100.00 % 0 0 0

lib/pennyworth.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 "zeitwerk"
  3. 1 Zeitwerk::Loader.new.then do |loader|
  4. 1 loader.inflector.inflect "cli" => "CLI",
  5. "http_status" => "HTTPStatus",
  6. "http_statuses" => "HTTPStatuses",
  7. "htmx" => "HTMX"
  8. 1 loader.tag = File.basename __FILE__, ".rb"
  9. 1 loader.push_dir __dir__
  10. 1 loader.setup
  11. end
  12. # Main namespace.
  13. 1 module Pennyworth
  14. 1 def self.loader registry = Zeitwerk::Registry
  15. 4 @loader ||= registry.loaders.each.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
  16. end
  17. end

lib/pennyworth/../../pennyworth.gemspec

100.0% lines covered

100.0% branches covered

30 relevant lines. 30 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 = "pennyworth"
  4. 1 spec.version = "18.7.0"
  5. 1 spec.authors = ["Brooke Kuhlmann"]
  6. 1 spec.email = ["brooke@alchemists.io"]
  7. 1 spec.homepage = "https://alchemists.io/projects/pennyworth"
  8. 1 spec.summary = "A command line interface for augmented Alfred workflows."
  9. 1 spec.license = "Hippocratic-2.1"
  10. 1 spec.metadata = {
  11. "bug_tracker_uri" => "https://github.com/bkuhlmann/pennyworth/issues",
  12. "changelog_uri" => "https://alchemists.io/projects/pennyworth/versions",
  13. "homepage_uri" => "https://alchemists.io/projects/pennyworth",
  14. "funding_uri" => "https://github.com/sponsors/bkuhlmann",
  15. "label" => "Pennyworth",
  16. "rubygems_mfa_required" => "true",
  17. "source_code_uri" => "https://github.com/bkuhlmann/pennyworth"
  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 "core", "~> 2.0"
  25. 1 spec.add_dependency "etcher", "~> 3.0"
  26. 1 spec.add_dependency "ghub", "~> 0.22"
  27. 1 spec.add_dependency "http", "~> 5.2"
  28. 1 spec.add_dependency "infusible", "~> 4.0"
  29. 1 spec.add_dependency "ox", "~> 2.14"
  30. 1 spec.add_dependency "rack", "~> 3.1"
  31. 1 spec.add_dependency "refinements", "~> 13.5"
  32. 1 spec.add_dependency "runcom", "~> 12.0"
  33. 1 spec.add_dependency "sod", "~> 1.0"
  34. 1 spec.add_dependency "spek", "~> 4.0"
  35. 1 spec.add_dependency "zeitwerk", "~> 2.7"
  36. 1 spec.bindir = "exe"
  37. 1 spec.executables << "pennyworth"
  38. 1 spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
  39. 1 spec.files = Dir["*.gemspec", "lib/**/*"]
  40. end

lib/pennyworth/cli/actions/encoding.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. # Handles the encoding action.
  7. 1 class Encoding < Sod::Action
  8. 1 include Dependencies[:io, processor: "processors.encoding"]
  9. 1 description "Render Alfred encodings script filter."
  10. 1 on "--encodings"
  11. 1 def call(*) = io.puts processor.call.to_json
  12. end
  13. end
  14. end
  15. end

lib/pennyworth/cli/actions/gem.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. # Handles the RubyGem action.
  7. 1 class Gem < Sod::Action
  8. 1 include Dependencies[:io, processor: "processors.gem"]
  9. 1 description "Render Alfred RubyGems script filter."
  10. 1 on "--gems", argument: "[HANDLE]"
  11. 24 default { Container[:settings].ruby_gems_owner }
  12. 1 def call(handle = default) = io.puts processor.call("owners/#{handle}/gems.json").to_json
  13. end
  14. end
  15. end
  16. end

lib/pennyworth/cli/actions/git_hub/organization.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 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 Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. 1 module GitHub
  7. # Handles the GitHub user action.
  8. 1 class Organization < Sod::Action
  9. 1 include Dependencies[:io, processor: "processors.project"]
  10. 1 description "Specify organization."
  11. 1 on %w[-o --organization], argument: "[HANDLE]"
  12. 24 default { Container[:settings].git_hub_organization }
  13. 1 def call(handle = default) = io.puts processor.call("orgs/#{handle}").to_json
  14. end
  15. end
  16. end
  17. end
  18. end

lib/pennyworth/cli/actions/git_hub/user.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 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 Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. 1 module GitHub
  7. # Handles the GitHub user action.
  8. 1 class User < Sod::Action
  9. 1 include Dependencies[:io, processor: "processors.project"]
  10. 1 description "Specify user."
  11. 1 on %w[-u --user], argument: "[HANDLE]"
  12. 24 default { Container[:settings].git_hub_user }
  13. 1 def call(handle = default) = io.puts processor.call("users/#{handle}").to_json
  14. end
  15. end
  16. end
  17. end
  18. end

lib/pennyworth/cli/actions/htmx/example.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. 1 module HTMX
  7. # Handles examples documentation action.
  8. 1 class Example < Sod::Action
  9. 1 include Dependencies[:settings, :io, processor: "processors.htmx"]
  10. 1 description "Render Alfred examples script filter."
  11. 1 on "--examples"
  12. 1 def call(*) = io.puts processor.call(settings.htmx_examples_uri).to_json
  13. end
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/cli/actions/htmx/extension.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. 1 module HTMX
  7. # Handles extension documentation action.
  8. 1 class Extension < Sod::Action
  9. 1 include Dependencies[:settings, :io, processor: "processors.htmx"]
  10. 1 description "Render Alfred extensions script filter."
  11. 1 on "--extensions"
  12. 1 def call(*) = io.puts processor.call(settings.htmx_extensions_uri).to_json
  13. end
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/cli/actions/htmx/reference.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. 1 module HTMX
  7. # Handles references documentation action.
  8. 1 class Reference < Sod::Action
  9. 1 include Dependencies[:settings, :io, processor: "processors.htmx"]
  10. 1 description "Render Alfred references script filter."
  11. 1 on "--references"
  12. 1 def call(*) = io.puts processor.call(settings.htmx_references_uri).to_json
  13. end
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/cli/actions/http_status.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. # Handles the HTTP status action.
  7. 1 class HTTPStatus < Sod::Action
  8. 1 include Dependencies[:io, processor: "processors.http_status"]
  9. 1 description "Render Alfred HTTP statuses script filter."
  10. 1 on "--http_statuses"
  11. 1 def call(*) = io.puts processor.call.to_json
  12. end
  13. end
  14. end
  15. end

lib/pennyworth/cli/actions/rodauth.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. # Handles Rodauth feature action.
  7. 1 class Rodauth < Sod::Action
  8. 1 include Dependencies[:settings, :io, processor: "processors.rodauth"]
  9. 1 description "Render Alfred Rodauth script filter."
  10. 1 on "--rodauth"
  11. 1 def call(*) = io.puts processor.call(settings.rodauth_documentation_uri).to_json
  12. end
  13. end
  14. end
  15. end

lib/pennyworth/cli/actions/standard_error.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. # Handles the system error action.
  7. 1 class StandardError < Sod::Action
  8. 1 include Dependencies[:io, processor: "processors.standard_error"]
  9. 1 description "Render Alfred standard errors script filter."
  10. 1 on "--standard_errors"
  11. 1 def call(*) = io.puts processor.call.to_json
  12. end
  13. end
  14. end
  15. end

lib/pennyworth/cli/actions/standard_gem.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. # Handles the Standard Gem action.
  7. 1 class StandardGem < Sod::Action
  8. 1 include Dependencies[:io, processor: "processors.standard_gem"]
  9. 1 ENDPOINTS = {
  10. "all" => "stdgems.json",
  11. "default" => "default_gems.json",
  12. "bundled" => "bundled_gems.json"
  13. }.freeze
  14. 1 description "Render Alfred Standard Gems script filter."
  15. 1 on "--standard_gems", argument: "[KIND]", allow: %w[all default bundled], default: "all"
  16. 1 def initialize(endpoints: ENDPOINTS, **)
  17. 26 super(**)
  18. 26 @endpoints = endpoints
  19. end
  20. 1 def call(kind = default) = io.puts processor.call(endpoints.fetch(kind)).to_json
  21. 1 private
  22. 1 attr_reader :endpoints
  23. end
  24. end
  25. end
  26. end

lib/pennyworth/cli/actions/system/error.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. 1 module System
  7. # Handles the system error action.
  8. 1 class Error < Sod::Action
  9. 1 include Dependencies[:io, processor: "processors.system_error"]
  10. 1 description "Render Alfred system errors script filter."
  11. 1 on "--system_errors"
  12. 1 def call(*) = io.puts processor.call.to_json
  13. end
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/cli/actions/system/signal.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. 1 module System
  7. # Handles the system signal action.
  8. 1 class Signal < Sod::Action
  9. 1 include Dependencies[:io, processor: "processors.system_signal"]
  10. 1 description "Render Alfred system signals script filter."
  11. 1 on "--system_signals"
  12. 1 def call(*) = io.puts processor.call.to_json
  13. end
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/cli/actions/text.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 "sod"
  3. 1 module Pennyworth
  4. 1 module CLI
  5. 1 module Actions
  6. # Handles the text action.
  7. 1 class Text < Sod::Action
  8. 1 include Dependencies[:io, processor: "processors.text"]
  9. 1 description "Render Alfred text script filter."
  10. 1 on "--text", argument: "CONTENT"
  11. 1 def call(content) = io.puts processor.call(content).to_json
  12. end
  13. end
  14. end
  15. end

lib/pennyworth/cli/shell.rb

100.0% lines covered

100.0% branches covered

36 relevant lines. 36 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 Pennyworth
  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. 20 super(**)
  10. 20 @context = context
  11. 20 @dsl = dsl
  12. end
  13. 1 def call(...) = cli.call(...)
  14. 1 private
  15. 1 attr_reader :context, :dsl
  16. 1 def cli
  17. 20 context = build_context
  18. 20 dsl.new :pennyworth, banner: specification.banner do
  19. 20 on(Sod::Prefabs::Commands::Config, context:)
  20. 20 on "git_hub", "Render Alfred GitHub repositories script filter." do
  21. 20 on Actions::GitHub::Organization
  22. 20 on Actions::GitHub::User
  23. end
  24. 20 on "htmx", "Render htmx script filters" do
  25. 20 on Actions::HTMX::Example
  26. 20 on Actions::HTMX::Extension
  27. 20 on Actions::HTMX::Reference
  28. end
  29. 20 on Actions::Encoding
  30. 20 on Actions::HTTPStatus
  31. 20 on Actions::Gem
  32. 20 on Actions::Rodauth
  33. 20 on Actions::StandardGem
  34. 20 on Actions::StandardError
  35. 20 on Actions::System::Error
  36. 20 on Actions::System::Signal
  37. 20 on Actions::Text
  38. 20 on(Sod::Prefabs::Actions::Version, context:)
  39. 20 on Sod::Prefabs::Actions::Help, self
  40. end
  41. end
  42. 1 def build_context
  43. 20 context[defaults_path:, xdg_config:, version_label: specification.labeled_version]
  44. end
  45. end
  46. end
  47. end

lib/pennyworth/configuration/contract.rb

100.0% lines covered

100.0% branches covered

20 relevant lines. 20 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "dry/schema"
  3. 1 Dry::Schema.load_extensions :monads
  4. 1 module Pennyworth
  5. 1 module Configuration
  6. 1 Contract = Dry::Schema.Params do
  7. 1 optional(:alfred_preferences).filled :string
  8. 1 required(:inflections).array :hash
  9. 1 required(:git_hub_api_uri).filled :string
  10. 1 optional(:git_hub_organization).filled :string
  11. 1 optional(:git_hub_user).filled :string
  12. 1 required(:http_statuses_uri).filled :string
  13. 1 required(:htmx_examples_uri).filled :string
  14. 1 required(:htmx_extensions_uri).filled :string
  15. 1 required(:htmx_references_uri).filled :string
  16. 1 required(:htmx_site_uri).filled :string
  17. 1 required(:rodauth_site_uri).filled :string
  18. 1 required(:rodauth_documentation_uri).filled :string
  19. 1 required(:ruby_gems_api_uri).filled :string
  20. 1 optional(:ruby_gems_owner).filled :string
  21. 1 required(:standard_gems_api_uri).filled :string
  22. end
  23. end
  24. end

lib/pennyworth/configuration/model.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 module Pennyworth
  3. 1 module Configuration
  4. # Defines configuration content as the primary source of truth for use throughout the gem.
  5. 1 Model = Struct.new :alfred_preferences,
  6. :inflections,
  7. :git_hub_api_uri,
  8. :git_hub_organization,
  9. :git_hub_user,
  10. :http_statuses_uri,
  11. :htmx_examples_uri,
  12. :htmx_extensions_uri,
  13. :htmx_references_uri,
  14. :htmx_site_uri,
  15. :rodauth_site_uri,
  16. :rodauth_documentation_uri,
  17. :ruby_gems_api_uri,
  18. :ruby_gems_owner,
  19. :standard_gems_api_uri
  20. end
  21. end

lib/pennyworth/container.rb

100.0% lines covered

100.0% branches covered

44 relevant lines. 44 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 "http"
  6. 1 require "ox"
  7. 1 require "runcom"
  8. 1 require "spek"
  9. 1 module Pennyworth
  10. # Provides a global gem container for injection into other objects.
  11. 1 module Container
  12. 1 extend Containable
  13. 1 register :registry, as: :fresh do
  14. 58 Etcher::Registry.new(contract: Configuration::Contract, model: Configuration::Model)
  15. .add_loader(:yaml, self[:defaults_path])
  16. .add_loader(:yaml, self[:xdg_config].active)
  17. .add_transformer(:format, :htmx_examples_uri)
  18. .add_transformer(:format, :htmx_extensions_uri)
  19. .add_transformer(:format, :htmx_references_uri)
  20. .add_transformer(:format, :rodauth_documentation_uri)
  21. end
  22. 1 namespace :processors do
  23. 1 register :encoding do
  24. 21 Processor.new loader: Loaders::Encoding.new,
  25. presenter: Presenters::Encoding,
  26. serializer: Serializers::Encoding
  27. end
  28. 1 register :gem do
  29. 20 Processor.new loader: Loaders::Gem.new,
  30. presenter: Presenters::Gem,
  31. serializer: Serializers::Project
  32. end
  33. 1 register :htmx do
  34. 26 Processor.new loader: Loaders::HTMX.new,
  35. presenter: Presenters::HTMX,
  36. serializer: Serializers::HTMX
  37. end
  38. 1 register :http_status do
  39. 21 Processor.new loader: Loaders::HTTPStatus.new,
  40. presenter: Presenters::HTTPStatus,
  41. serializer: Serializers::HTTPStatus
  42. end
  43. 1 register :project do
  44. 20 Processor.new loader: Loaders::GitHub.new,
  45. presenter: Presenters::Repository,
  46. serializer: Serializers::Project
  47. end
  48. 1 register :rodauth do
  49. 22 Processor.new loader: Loaders::Rodauth.new,
  50. presenter: Presenters::Rodauth,
  51. serializer: Serializers::Rodauth
  52. end
  53. 1 register :standard_gem do
  54. 20 Processor.new loader: Loaders::StandardGem.new,
  55. presenter: Presenters::StandardGem,
  56. serializer: Serializers::Project
  57. end
  58. 1 register :standard_error do
  59. 21 Processor.new loader: Loaders::StandardError.new,
  60. presenter: Presenters::StandardError,
  61. serializer: Serializers::StandardError
  62. end
  63. 1 register :system_error do
  64. 21 Processor.new loader: Loaders::System::Error.new,
  65. presenter: Presenters::System::Error,
  66. serializer: Serializers::System::Error
  67. end
  68. 1 register :system_signal do
  69. 21 Processor.new loader: Loaders::System::Signal.new,
  70. presenter: Presenters::System::Signal,
  71. serializer: Serializers::System::Signal
  72. end
  73. 1 register :text do
  74. 1 Processor.new loader: Loaders::Text.new,
  75. presenter: Presenters::Text,
  76. serializer: Serializers::Text
  77. end
  78. end
  79. 1 register :ox do
  80. 68 Ox.tap { |ox| ox.default_options = {mode: :generic, effort: :tolerant, smart: true} }
  81. end
  82. 2 register(:settings) { Etcher.call(self[:registry]).dup }
  83. 21 register(:specification) { Spek::Loader.call "#{__dir__}/../../pennyworth.gemspec" }
  84. 2 register(:defaults_path) { Pathname(__dir__).join("configuration/defaults.yml") }
  85. 2 register(:xdg_config) { Runcom::Config.new "pennyworth/configuration.yml" }
  86. 34 register(:http) { HTTP.timeout 3 }
  87. 1 register(:logger) { Cogger.new id: :pennyworth }
  88. 1 register :io, STDOUT
  89. end
  90. end

lib/pennyworth/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 Pennyworth
  4. 1 Dependencies = Infusible[Container]
  5. end

lib/pennyworth/inflector.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 module Pennyworth
  3. # Overrides any string to desired form if matched, otherwise answers the original string.
  4. 1 class Inflector
  5. 1 DEFAULTS = Array(Container[:settings].inflections).reduce({}, :merge)
  6. 1 def initialize overrides = DEFAULTS
  7. 328 @overrides = overrides
  8. end
  9. 396 def call(key) = overrides.fetch(key) { |fallback| fallback }
  10. 1 private
  11. 1 attr_reader :overrides
  12. end
  13. end

lib/pennyworth/loaders/encoding.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 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/array"
  3. 1 module Pennyworth
  4. 1 module Loaders
  5. # Loads an array of encoding records.
  6. 1 class Encoding
  7. 1 using Refinements::Array
  8. 1 def initialize encoding: ::Encoding, model: Models::Encoding
  9. 22 @encoding = encoding
  10. 22 @model = model
  11. end
  12. 1 def call(*)
  13. 3 encoding.aliases
  14. 213 .map { |_second, first| first }
  15. .uniq
  16. .sort
  17. .map do |first|
  18. 183 model[name: first, aliases: encoding.find(first).names.sort.excluding(first)]
  19. end
  20. end
  21. 1 private
  22. 1 attr_reader :encoding, :model
  23. end
  24. end
  25. end

lib/pennyworth/loaders/gem.rb

100.0% lines covered

100.0% branches covered

9 relevant lines. 9 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 module Pennyworth
  4. 1 module Loaders
  5. # Loads an array gems from the RubyGems API.
  6. 1 class Gem
  7. 1 include Dependencies[:settings, :http]
  8. 1 def call endpoint
  9. 4 http.get("#{settings.ruby_gems_api_uri}/#{endpoint}")
  10. .then do |response|
  11. 4 then: 2 else: 2 return JSON response.body.to_s, symbolize_names: true if response.status.success?
  12. 2 Core::EMPTY_HASH
  13. end
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/loaders/git_hub.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 "core"
  3. 1 require "ghub"
  4. 1 module Pennyworth
  5. 1 module Loaders
  6. # Loads an array projects from the GitHub API.
  7. 1 class GitHub
  8. 1 def initialize endpoint: Ghub::Endpoints::Repositories::Root.new
  9. 22 @endpoint = endpoint
  10. end
  11. 1 def call(path) = endpoint.index(*path.split("/")).value_or(Core::EMPTY_ARRAY).map(&:to_h)
  12. 1 private
  13. 1 attr_reader :endpoint
  14. end
  15. end
  16. end

lib/pennyworth/loaders/htmx.rb

100.0% lines covered

100.0% branches covered

31 relevant lines. 31 lines covered and 0 lines missed.
6 total branches, 6 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "core"
  3. 1 require "refinements/string"
  4. 1 module Pennyworth
  5. 1 module Loaders
  6. # Loads htmx documentation by scraping web page.
  7. 1 class HTMX
  8. 1 include Dependencies[:http, :settings, parser: :ox]
  9. 1 using Refinements::String
  10. 1 def self.text_for element
  11. 683 parts = element.each.with_object [] do |item, content|
  12. 1338 then: 349 text = if item.is_a? Ox::Element
  13. 349 "`#{item.text}`"
  14. else: 989 else
  15. 989 item.encode ::Encoding::UTF_8, replace: Core::EMPTY_STRING
  16. end
  17. 1338 content.append text
  18. end
  19. 683 parts.join.up.delete_suffix "."
  20. end
  21. 1 def initialize(model: Models::HTMX, **)
  22. 30 @model = model
  23. 30 super(**)
  24. end
  25. 1 def call uri
  26. 13 read(uri).each.with_object [] do |row, entries|
  27. 723 else: 681 then: 42 next unless row.locate("td") in Ox::Element => item, Ox::Element => description
  28. 681 entries.append record_for(item, description, uri)
  29. end
  30. end
  31. 1 private
  32. 1 attr_reader :model
  33. 1 def read uri
  34. 13 http.follow.get(uri).then do |response|
  35. 13 then: 12 else: 1 [200, 301].include?(response.status) ? parse_rows(response.body.to_s) : Core::EMPTY_ARRAY
  36. end
  37. end
  38. 1 def parse_rows(document) = parser.parse(document).locate "*/tr"
  39. 1 def record_for item, description, uri
  40. 681 model[
  41. 681 label: (item.locate("*/code").first || item.locate("a").first).text,
  42. description: "#{self.class.text_for description}.",
  43. 681 uri: (item.locate("*/@href").first || uri).sub(%r(\A(?=/)), settings.htmx_site_uri)
  44. ]
  45. end
  46. end
  47. end
  48. end

lib/pennyworth/loaders/http_status.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "rack"
  3. 1 module Pennyworth
  4. 1 module Loaders
  5. # Loads an array of HTTP status records.
  6. 1 class HTTPStatus
  7. 1 include Dependencies[:settings]
  8. 1 def initialize(codes: Rack::Utils::HTTP_STATUS_CODES, model: Models::HTTPStatus, **)
  9. 22 super(**)
  10. 22 @codes = codes
  11. 22 @model = model
  12. end
  13. 1 def call(*)
  14. 183 codes.map { |(code, label)| model[code:, label:, url: "#{url}/#{code}"] }
  15. end
  16. 1 private
  17. 1 attr_reader :codes, :model
  18. 1 def url = settings.http_statuses_uri
  19. end
  20. end
  21. end

lib/pennyworth/loaders/rodauth.rb

100.0% lines covered

100.0% branches covered

26 relevant lines. 26 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 "refinements/pathname"
  4. 1 require "refinements/string"
  5. 1 module Pennyworth
  6. 1 module Loaders
  7. # Loads Rodauth documentation by scraping the web page.
  8. 1 class Rodauth
  9. 1 include Dependencies[:http, :settings, parser: :ox]
  10. 1 using Refinements::String
  11. 1 using Refinements::Pathname
  12. 1 def initialize(model: Models::Rodauth, **)
  13. 24 @model = model
  14. 24 super(**)
  15. end
  16. 1 def call uri
  17. 158 read(uri).each.with_object([]) { |item, entries| entries.append record_for(item) }
  18. end
  19. 1 private
  20. 1 attr_reader :model
  21. 1 def read uri
  22. 5 http.get(uri).then do |response|
  23. 5 then: 4 else: 1 [200, 301].include?(response.status) ? parse_items(response.body.to_s) : Core::EMPTY_ARRAY
  24. end
  25. end
  26. 1 def parse_items document
  27. 4 parser.parse(document).root.body.div.ul.nodes
  28. rescue NoMethodError
  29. 1 Core::EMPTY_ARRAY
  30. end
  31. 1 def record_for item
  32. 153 link = item.a
  33. 153 uri = "#{settings.rodauth_site_uri}/#{link.href}"
  34. 153 model[
  35. name: Pathname(uri).name.to_s.delete_suffix("_rdoc"),
  36. label: link.text,
  37. description: item.text.delete_prefix(": "),
  38. uri:
  39. ]
  40. end
  41. end
  42. end
  43. end

lib/pennyworth/loaders/standard_error.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pennyworth
  3. 1 module Loaders
  4. # Loads an array of standard error records.
  5. 1 class StandardError
  6. 1 def initialize root: ::StandardError, model: Models::StandardError
  7. 22 @root = root
  8. 22 @model = model
  9. end
  10. 1 def call(*)
  11. 3 ObjectSpace.each_object(Class)
  12. 10303 .select { |klass| klass < root }
  13. .sort_by(&:name)
  14. .map do |error|
  15. 1467 file_path, line_number = Object.const_source_location error.name
  16. 1467 model[name: error, file_path:, line_number:]
  17. end
  18. end
  19. 1 private
  20. 1 attr_reader :root, :model
  21. end
  22. end
  23. end

lib/pennyworth/loaders/standard_gem.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 "core"
  3. 1 module Pennyworth
  4. 1 module Loaders
  5. # Loads an array gems from the Standard Gems API.
  6. 1 class StandardGem
  7. 1 include Dependencies[:settings, :http]
  8. 1 def call endpoint
  9. 6 http.get("#{settings.standard_gems_api_uri}/#{endpoint}")
  10. .then do |response|
  11. 6 then: 4 else: 2 response.status.success? ? records(response.body.to_s) : Core::EMPTY_HASH
  12. end
  13. end
  14. 1 private
  15. 1 def records(body) = JSON(body, symbolize_names: true).fetch :gems, Core::EMPTY_ARRAY
  16. end
  17. end
  18. end

lib/pennyworth/loaders/system/error.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pennyworth
  3. 1 module Loaders
  4. 1 module System
  5. # Loads an array of system error records.
  6. 1 class Error
  7. 1 def initialize errno: Errno, model: Models::System::Error
  8. 22 @errno = errno
  9. 22 @model = model
  10. end
  11. 1 def call(*)
  12. 3 errno.constants
  13. 474 .map { |name| errno.const_get name }
  14. .uniq
  15. 396 .sort_by { |error| error::Errno }
  16. .map do |error|
  17. 396 model[id: error::Errno, name: error.name, description: error.exception.message]
  18. end
  19. end
  20. 1 private
  21. 1 attr_reader :errno, :model
  22. end
  23. end
  24. end
  25. end

lib/pennyworth/loaders/system/signal.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 module Pennyworth
  3. 1 module Loaders
  4. 1 module System
  5. # Loads an array of signal records.
  6. 1 class Signal
  7. 1 def initialize list: ::Signal.list, model: Models::System::Signal
  8. 22 @list = list
  9. 22 @model = model
  10. end
  11. 103 def call(*) = list.map { |name, number| model[number:, name:] }
  12. 1 private
  13. 1 attr_reader :list, :model
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/loaders/text.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 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/string"
  3. 1 module Pennyworth
  4. 1 module Loaders
  5. # Loads an array of text records.
  6. 1 class Text
  7. 1 using Refinements::String
  8. 1 TRANSFORMS = %w[camelcase capitalize downcase size snakecase titleize upcase].freeze
  9. 1 def initialize transforms: TRANSFORMS, model: Models::Text
  10. 2 @transforms = transforms
  11. 2 @model = model
  12. end
  13. 1 def call content
  14. 32 transforms.map { |kind| model[id: kind, content: content.public_send(kind)] }
  15. end
  16. 1 private
  17. 1 attr_reader :transforms, :model
  18. end
  19. end
  20. end

lib/pennyworth/models/encoding.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 module Pennyworth
  3. 1 module Models
  4. # Defines an encoding.
  5. 1 Encoding = Data.define :name, :aliases
  6. end
  7. end

lib/pennyworth/models/htmx.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 module Pennyworth
  3. 1 module Models
  4. # Represents a htmx link.
  5. 1 HTMX = Data.define :label, :description, :uri
  6. end
  7. end

lib/pennyworth/models/http_status.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 Pennyworth
  3. 1 module Models
  4. # Defines HTTP status details.
  5. 1 HTTPStatus = Data.define :code, :label, :url do
  6. 1 def initialize code: nil, label: nil, url: nil
  7. 196 super
  8. end
  9. end
  10. end
  11. end

lib/pennyworth/models/rodauth.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 module Pennyworth
  3. 1 module Models
  4. # Represents a Rodauth list item.
  5. 1 Rodauth = Data.define :name, :label, :description, :uri
  6. end
  7. end

lib/pennyworth/models/standard_error.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 Pennyworth
  3. 1 module Models
  4. # Defines a standard error.
  5. 1 StandardError = Data.define :name, :file_path, :line_number do
  6. 1 def initialize name: nil, file_path: nil, line_number: nil
  7. 1477 super
  8. end
  9. end
  10. end
  11. end

lib/pennyworth/models/system/error.rb

100.0% lines covered

100.0% branches covered

4 relevant lines. 4 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pennyworth
  3. 1 module Models
  4. 1 module System
  5. # Defines a system error.
  6. 1 Error = Data.define :id, :name, :description
  7. end
  8. end
  9. end

lib/pennyworth/models/system/signal.rb

100.0% lines covered

100.0% branches covered

4 relevant lines. 4 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pennyworth
  3. 1 module Models
  4. 1 module System
  5. # Defines a low-level operating system signal.
  6. 1 Signal = Data.define :number, :name
  7. end
  8. end
  9. end

lib/pennyworth/models/text.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 module Pennyworth
  3. 1 module Models
  4. # Defines basic text.
  5. 1 Text = Data.define :id, :content
  6. end
  7. end

lib/pennyworth/presenters/encoding.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 module Pennyworth
  3. 1 module Presenters
  4. # Shapes an encoding record for serialization.
  5. 1 class Encoding
  6. 1 def initialize record
  7. 127 @record = record
  8. end
  9. 1 def id = record.name
  10. 1 def label = record.name
  11. 1 def aliases = record.aliases
  12. 1 private
  13. 1 attr_reader :record
  14. end
  15. end
  16. end

lib/pennyworth/presenters/gem.rb

100.0% lines covered

100.0% branches covered

22 relevant lines. 22 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/string"
  3. 1 module Pennyworth
  4. 1 module Presenters
  5. # Shapes a RubyGems record for serialization.
  6. 1 class Gem
  7. 1 using Refinements::Array
  8. 1 using Refinements::String
  9. 1 def initialize record, inflector: Inflector.new
  10. 57 @record = record
  11. 57 @inflector = inflector
  12. end
  13. 1 def id = record.fetch(:name)
  14. 1 def label = "#{inflector.call id.titleize} #{version}"
  15. 1 def subtitle = "Downloads: #{downloads}. Licenses: #{licenses}. Updated: #{updated_at[..9]}."
  16. 1 def version = record.fetch(__method__)
  17. 1 def licenses = Array(record.fetch(__method__)).to_sentence
  18. 1 def downloads = record.fetch(__method__)
  19. 1 def site_uri = record.fetch(:homepage_uri)
  20. 1 def source_uri = record.fetch(:source_code_uri)
  21. 1 def issues_uri = record.fetch(:bug_tracker_uri)
  22. 1 def versions_uri = record.fetch(:changelog_uri)
  23. 1 def updated_at = record.fetch(:version_created_at)
  24. 1 private
  25. 1 attr_reader :record, :inflector
  26. end
  27. end
  28. end

lib/pennyworth/presenters/htmx.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "forwardable"
  3. 1 module Pennyworth
  4. 1 module Presenters
  5. # Shapes a htmx record for serialization.
  6. 1 class HTMX
  7. 1 extend Forwardable
  8. 1 delegate %i[label description uri] => :record
  9. 1 def initialize record
  10. 459 @record = record
  11. end
  12. 1 alias id label
  13. 1 private
  14. 1 attr_reader :record
  15. end
  16. end
  17. end

lib/pennyworth/presenters/http_status.rb

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 require "forwardable"
  3. 1 require "refinements/string"
  4. 1 module Pennyworth
  5. 1 module Presenters
  6. # Shapes a HTTP status record for serialization.
  7. 1 class HTTPStatus
  8. 1 extend Forwardable
  9. 1 using Refinements::String
  10. 1 delegate %i[code label url] => :record
  11. 1 def initialize record, inflector: Inflector.new
  12. 132 @record = record
  13. 132 @inflector = inflector
  14. end
  15. 1 def id = record.code
  16. 1 def subtitle = "#{id} #{label}"
  17. 1 def symbol = ":#{inflector.call name}"
  18. 1 private
  19. 1 attr_reader :record, :inflector
  20. 1 def name
  21. 127 label.snakecase
  22. .tr("/", "_")
  23. .gsub(/(\(|\))/, "")
  24. .sub("h_t_t_p_version_not_supported", "http_version_not_supported")
  25. .sub("i_m_used", "im_used")
  26. .sub("u_r_i_too_long", "uri_too_long")
  27. end
  28. end
  29. end
  30. end

lib/pennyworth/presenters/repository.rb

100.0% lines covered

100.0% branches covered

17 relevant lines. 17 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/string"
  3. 1 module Pennyworth
  4. 1 module Presenters
  5. # Shapes a repository record for serialization.
  6. 1 class Repository
  7. 1 using Refinements::String
  8. 1 def initialize record, inflector: Inflector.new
  9. 67 @record = record
  10. 67 @inflector = inflector
  11. end
  12. 1 def id = record.fetch(:name)
  13. 1 def label = inflector.call(id.titleize)
  14. 1 def subtitle = record.fetch(:description)
  15. 1 def site_uri = record.fetch(:homepage)
  16. 1 def source_uri = record.fetch(:html_url)
  17. 1 def issues_uri = "#{source_uri}/issues"
  18. 1 def versions_uri = "#{site_uri}/versions"
  19. 1 private
  20. 1 attr_reader :record, :inflector
  21. end
  22. end
  23. end

lib/pennyworth/presenters/rodauth.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "forwardable"
  3. 1 module Pennyworth
  4. 1 module Presenters
  5. # Shapes a Rodauth record for serialization.
  6. 1 class Rodauth
  7. 1 extend Forwardable
  8. 1 delegate %i[name label description uri] => :record
  9. 1 def initialize record
  10. 107 @record = record
  11. end
  12. 1 alias id name
  13. 1 private
  14. 1 attr_reader :record
  15. end
  16. end
  17. end

lib/pennyworth/presenters/standard_error.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/array"
  3. 1 module Pennyworth
  4. 1 module Presenters
  5. # Shapes a standard error record for serialization.
  6. 1 class StandardError
  7. 1 using Refinements::Array
  8. 1 def initialize record
  9. 985 @record = record
  10. end
  11. 1 def id = label
  12. 1 def label = record.name.to_s
  13. 984 then: 354 else: 629 def path = file_path.empty? ? "" : [file_path, record.line_number].compress.join(":")
  14. 1 private
  15. 1 attr_reader :record
  16. 1 def file_path = record.file_path.to_s
  17. end
  18. end
  19. end

lib/pennyworth/presenters/standard_gem.rb

100.0% lines covered

100.0% branches covered

23 relevant lines. 23 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "core"
  3. 1 require "refinements/string"
  4. 1 module Pennyworth
  5. 1 module Presenters
  6. # Shapes a standard gem record for serialization.
  7. 1 class StandardGem
  8. 1 using Refinements::Array
  9. 1 using Refinements::String
  10. 1 def initialize record, inflector: Inflector.new
  11. 44 @record = record
  12. 44 @inflector = inflector
  13. end
  14. 1 def id = record.fetch :gem
  15. 1 def label = "#{inflector.call id.titleize} #{version}"
  16. 1 def subtitle = record.fetch :description
  17. 1 def version
  18. 68 versions = record.fetch :versions, Core::EMPTY_HASH
  19. 68 bundled, defaults = versions.values_at :bundled, :default
  20. 68 (bundled || defaults || versions).values.first
  21. end
  22. 1 def site_uri = record.fetch(:sourceRepository, Core::EMPTY_STRING)
  23. 1 def source_uri = record.fetch(:sourceRepository, Core::EMPTY_STRING)
  24. 1 def issues_uri = "https://github.com/ruby/#{id}/issues"
  25. 1 def versions_uri = "https://github.com/ruby/#{id}/tags"
  26. 1 private
  27. 1 attr_reader :record, :inflector
  28. end
  29. end
  30. end

lib/pennyworth/presenters/system/error.rb

100.0% lines covered

100.0% branches covered

13 relevant lines. 13 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 require "forwardable"
  3. 1 module Pennyworth
  4. 1 module Presenters
  5. 1 module System
  6. # Shapes a system error record for serialization.
  7. 1 class Error
  8. 1 extend Forwardable
  9. 1 delegate %i[id description] => :record
  10. 1 def initialize record
  11. 269 @record = record
  12. end
  13. 1 def label = record.name
  14. 1 def subtitle = "#{label}: #{description}."
  15. 1 private
  16. 1 attr_reader :record
  17. end
  18. end
  19. end
  20. end

lib/pennyworth/presenters/system/signal.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 module Pennyworth
  3. 1 module Presenters
  4. 1 module System
  5. # Shapes a system signal record for serialization.
  6. 1 class Signal
  7. 1 def initialize record
  8. 71 @record = record
  9. end
  10. 1 def id = record.number
  11. 1 def label = record.name
  12. 1 private
  13. 1 attr_reader :record
  14. end
  15. end
  16. end
  17. end

lib/pennyworth/presenters/text.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 "forwardable"
  3. 1 module Pennyworth
  4. 1 module Presenters
  5. # Shapes a text record for serialization.
  6. 1 class Text
  7. 1 extend Forwardable
  8. 1 delegate %i[id content] => :record
  9. 1 def initialize record, inflector: Inflector.new
  10. 26 @record = record
  11. 26 @inflector = inflector
  12. end
  13. 1 def label = inflector.call(record.content.to_s)
  14. 1 private
  15. 1 attr_reader :record, :inflector
  16. end
  17. end
  18. end

lib/pennyworth/processor.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 module Pennyworth
  3. # Processes all steps required to render an Alfred Script Filter response.
  4. 1 class Processor
  5. 1 def initialize steps
  6. 214 @steps = steps
  7. 214 freeze
  8. end
  9. 1 def call content = nil
  10. 32 loader.call(content)
  11. 2264 .map { |record| presenter.new record }
  12. .sort_by(&:label)
  13. 2264 .map { |record| serializer.new record }
  14. 32 .then { |records| {items: records.map(&:to_h)} }
  15. end
  16. 1 private
  17. 1 attr_reader :steps
  18. 1 def loader = steps.fetch(__method__)
  19. 1 def presenter = steps.fetch(__method__)
  20. 1 def serializer = steps.fetch(__method__)
  21. end
  22. end

lib/pennyworth/serializers/encoding.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 module Pennyworth
  3. 1 module Serializers
  4. # Serializes an encoding presenter for parsing by Alfred script filters.
  5. 1 class Encoding
  6. 1 using Refinements::Array
  7. 1 def initialize presenter
  8. 124 @presenter = presenter
  9. end
  10. 1 def to_h
  11. {
  12. 124 uid: presenter.id,
  13. title: label,
  14. subtitle: %(Aliases: #{aliases.to_sentence}.),
  15. arg: label,
  16. mods: {
  17. alt: {subtitle: "Copy aliases.", arg: aliases.join(", ")}
  18. },
  19. text: {copy: label, largetype: label}
  20. }
  21. end
  22. 1 private
  23. 1 attr_reader :presenter
  24. 1 def label = presenter.label
  25. 1 def aliases = presenter.aliases
  26. end
  27. end
  28. end

lib/pennyworth/serializers/htmx.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 module Pennyworth
  3. 1 module Serializers
  4. # Serializes a htmx presenter for parsing by Alfred script filters.
  5. 1 class HTMX
  6. 1 def initialize presenter
  7. 455 @presenter = presenter
  8. end
  9. 1 def to_h
  10. {
  11. 455 uid: presenter.id,
  12. title: presenter.label,
  13. subtitle: presenter.description,
  14. arg: site_uri,
  15. quicklookurl: site_uri,
  16. mods: modifications,
  17. text:
  18. }
  19. end
  20. 1 private
  21. 1 attr_reader :presenter
  22. 1 def modifications
  23. {
  24. 455 alt: modification(presenter.label, "Copy label."),
  25. cmd: modification(presenter.description, "Copy description.")
  26. }
  27. end
  28. 1 def modification argument, subtitle
  29. {
  30. 910 subtitle:,
  31. arg: argument
  32. }
  33. end
  34. 1 def text
  35. {
  36. 455 copy: site_uri,
  37. largetype: site_uri
  38. }
  39. end
  40. 1 def site_uri = presenter.uri
  41. end
  42. end
  43. end

lib/pennyworth/serializers/http_status.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pennyworth
  3. 1 module Serializers
  4. # Serializes a HTTP status presenter for parsing by Alfred script filters.
  5. 1 class HTTPStatus
  6. 1 def initialize presenter
  7. 121 @presenter = presenter
  8. end
  9. 1 def to_h
  10. {
  11. 121 uid: id,
  12. title: code,
  13. subtitle: label,
  14. arg: presenter.symbol,
  15. mods: modifications,
  16. text: {copy: "#{code} #{label}", largetype: "#{code} #{label}"}
  17. }
  18. end
  19. 1 private
  20. 1 attr_reader :presenter
  21. 1 def id = presenter.id
  22. 1 def code = presenter.code
  23. 1 def label = presenter.label
  24. 1 def modifications
  25. {
  26. 121 control: {subtitle: "Copy code.", arg: id},
  27. alt: {subtitle: "Copy label.", arg: label},
  28. cmd: {subtitle: "View documentation.", arg: presenter.url}
  29. }
  30. end
  31. end
  32. end
  33. end

lib/pennyworth/serializers/project.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 module Pennyworth
  3. 1 module Serializers
  4. # Serializes a project presenter for parsing by Alfred script filters.
  5. 1 class Project
  6. 1 def initialize presenter
  7. 136 @presenter = presenter
  8. end
  9. 1 def to_h
  10. {
  11. 136 uid: presenter.id,
  12. title: presenter.label,
  13. subtitle: presenter.subtitle,
  14. arg: site_uri,
  15. quicklookurl: site_uri,
  16. mods: modifications,
  17. text:
  18. }
  19. end
  20. 1 private
  21. 1 attr_reader :presenter
  22. 1 def modifications
  23. {
  24. 136 alt: modification(presenter.source_uri, "View source."),
  25. cmd: modification(presenter.issues_uri, "View issues."),
  26. control: modification(presenter.versions_uri, "View versions.")
  27. }
  28. end
  29. 1 def modification argument, subtitle
  30. {
  31. 408 subtitle:,
  32. arg: argument
  33. }
  34. end
  35. 1 def text
  36. {
  37. 136 copy: site_uri,
  38. largetype: site_uri
  39. }
  40. end
  41. 1 def site_uri = presenter.site_uri
  42. end
  43. end
  44. end

lib/pennyworth/serializers/rodauth.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 module Pennyworth
  3. 1 module Serializers
  4. # Serializes a Rodauth presenter for parsing by Alfred script filters.
  5. 1 class Rodauth
  6. 1 def initialize presenter
  7. 103 @presenter = presenter
  8. end
  9. 1 def to_h
  10. {
  11. 103 uid: presenter.id,
  12. title: presenter.label,
  13. subtitle: presenter.description,
  14. arg: site_uri,
  15. quicklookurl: site_uri,
  16. mods: modifications,
  17. text:
  18. }
  19. end
  20. 1 private
  21. 1 attr_reader :presenter
  22. 1 def modifications
  23. {
  24. 103 alt: modification(presenter.label, "Copy label."),
  25. cmd: modification(presenter.description, "Copy description."),
  26. control: modification(presenter.name, "Copy name.")
  27. }
  28. end
  29. 1 def modification argument, subtitle
  30. {
  31. 309 subtitle:,
  32. arg: argument
  33. }
  34. end
  35. 1 def text
  36. {
  37. 103 copy: site_uri,
  38. largetype: site_uri
  39. }
  40. end
  41. 1 def site_uri = presenter.uri
  42. end
  43. end
  44. end

lib/pennyworth/serializers/standard_error.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 module Pennyworth
  3. 1 module Serializers
  4. # Serializes a standard error presenter for parsing by Alfred script filters.
  5. 1 class StandardError
  6. 1 def initialize presenter
  7. 979 @presenter = presenter
  8. end
  9. 1 def to_h
  10. {
  11. 979 uid: id,
  12. title: id,
  13. arg: label,
  14. mods: modifications,
  15. text: {copy: label, largetype: label}
  16. }
  17. end
  18. 1 private
  19. 1 attr_reader :presenter
  20. 1 def id = presenter.id
  21. 1 def label = presenter.label
  22. 1 def description = presenter.description
  23. 1 def modifications
  24. {
  25. 979 control: {subtitle: "Copy label.", arg: label},
  26. alt: {subtitle: "Copy path.", arg: path}
  27. }
  28. end
  29. 1 def path = presenter.path
  30. end
  31. end
  32. end

lib/pennyworth/serializers/system/error.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 module Pennyworth
  3. 1 module Serializers
  4. 1 module System
  5. # Serializes a system error presenter for parsing by Alfred script filters.
  6. 1 class Error
  7. 1 def initialize presenter
  8. 265 @presenter = presenter
  9. end
  10. 1 def to_h
  11. {
  12. 265 uid: id,
  13. title: id,
  14. subtitle: presenter.subtitle,
  15. arg: label,
  16. mods: modifications,
  17. text: {copy: label, largetype: label}
  18. }
  19. end
  20. 1 private
  21. 1 attr_reader :presenter
  22. 1 def id = presenter.id
  23. 1 def label = presenter.label
  24. 1 def description = presenter.description
  25. 1 def modifications
  26. {
  27. 265 control: {subtitle: "Copy ID.", arg: id},
  28. alt: {subtitle: "Copy description.", arg: description},
  29. cmd: {
  30. subtitle: "Copy ID, name, and description.",
  31. arg: "#{id}, #{label}, #{description}"
  32. }
  33. }
  34. end
  35. end
  36. end
  37. end
  38. end

lib/pennyworth/serializers/system/signal.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pennyworth
  3. 1 module Serializers
  4. 1 module System
  5. # Serializes a system signal presenter for parsing by Alfred script filters.
  6. 1 class Signal
  7. 1 def initialize presenter
  8. 69 @presenter = presenter
  9. end
  10. 1 def to_h
  11. {
  12. 69 uid: id,
  13. title: label,
  14. subtitle: id,
  15. arg: label,
  16. mods: modifications,
  17. text: {copy: label, largetype: label}
  18. }
  19. end
  20. 1 private
  21. 1 attr_reader :presenter
  22. 1 def id = presenter.id
  23. 1 def label = presenter.label
  24. 1 def modifications
  25. {
  26. 69 alt: {subtitle: "Copy ID.", arg: id},
  27. cmd: {subtitle: "Copy ID and name.", arg: "#{id}, #{label}"}
  28. }
  29. end
  30. end
  31. end
  32. end
  33. end

lib/pennyworth/serializers/text.rb

100.0% lines covered

100.0% branches covered

11 relevant lines. 11 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pennyworth
  3. 1 module Serializers
  4. # Serializes a text presenter for parsing by Alfred script filters.
  5. 1 class Text
  6. 1 def initialize presenter
  7. 22 @presenter = presenter
  8. end
  9. 1 def to_h
  10. {
  11. 22 uid: id,
  12. title: presenter.label,
  13. subtitle: id.capitalize,
  14. arg: content,
  15. icon: {path: "text/#{id}.png"},
  16. text: {copy: content, largetype: content}
  17. }
  18. end
  19. 1 private
  20. 1 attr_reader :presenter
  21. 1 def id = presenter.id
  22. 1 def content = presenter.content
  23. end
  24. end
  25. end