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

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

21 files in total.
264 relevant lines, 264 lines covered and 0 lines missed. ( 100.0% )
12 total branches, 12 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/pragmater.rb 100.00 % 17 9 9 0 1.33 100.00 % 0 0 0
lib/pragmater/../../pragmater.gemspec 100.00 % 41 26 26 0 1.00 100.00 % 0 0 0
lib/pragmater/cli/actions/comment.rb 100.00 % 22 10 10 0 2.70 100.00 % 0 0 0
lib/pragmater/cli/actions/pattern.rb 100.00 % 22 10 10 0 2.70 100.00 % 0 0 0
lib/pragmater/cli/actions/root.rb 100.00 % 22 10 10 0 2.60 100.00 % 0 0 0
lib/pragmater/cli/commands/insert.rb 100.00 % 33 17 17 0 1.82 100.00 % 0 0 0
lib/pragmater/cli/commands/remove.rb 100.00 % 33 17 17 0 1.82 100.00 % 0 0 0
lib/pragmater/cli/shell.rb 100.00 % 40 22 22 0 3.00 100.00 % 0 0 0
lib/pragmater/configuration/contract.rb 100.00 % 16 9 9 0 1.00 100.00 % 0 0 0
lib/pragmater/configuration/model.rb 100.00 % 14 7 7 0 13.43 100.00 % 0 0 0
lib/pragmater/dependencies.rb 100.00 % 7 3 3 0 1.00 100.00 % 0 0 0
lib/pragmater/formatters/general.rb 100.00 % 34 12 12 0 23.17 100.00 % 2 2 0
lib/pragmater/formatters/main.rb 100.00 % 25 12 12 0 18.67 100.00 % 0 0 0
lib/pragmater/formatters/shebang.rb 100.00 % 25 12 12 0 17.17 100.00 % 2 2 0
lib/pragmater/inserter.rb 100.00 % 28 14 14 0 4.71 100.00 % 2 2 0
lib/pragmater/parsers/comments.rb 100.00 % 24 12 12 0 13.17 100.00 % 0 0 0
lib/pragmater/parsers/file.rb 100.00 % 32 15 15 0 12.73 100.00 % 0 0 0
lib/pragmater/processors/handler.rb 100.00 % 20 9 9 0 4.78 100.00 % 0 0 0
lib/pragmater/processors/inserter.rb 100.00 % 24 12 12 0 7.25 100.00 % 2 2 0
lib/pragmater/processors/remover.rb 100.00 % 24 12 12 0 5.58 100.00 % 2 2 0
lib/pragmater/remover.rb 100.00 % 28 14 14 0 3.21 100.00 % 2 2 0

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

lib/pragmater/../../pragmater.gemspec

100.0% lines covered

100.0% branches covered

26 relevant lines. 26 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 = "pragmater"
  4. 1 spec.version = "16.4.0"
  5. 1 spec.authors = ["Brooke Kuhlmann"]
  6. 1 spec.email = ["brooke@alchemists.io"]
  7. 1 spec.homepage = "https://alchemists.io/projects/pragmater"
  8. 1 spec.summary = "A command line interface for managing pragma comments."
  9. 1 spec.license = "Hippocratic-2.1"
  10. 1 spec.metadata = {
  11. "bug_tracker_uri" => "https://github.com/bkuhlmann/pragmater/issues",
  12. "changelog_uri" => "https://alchemists.io/projects/pragmater/versions",
  13. "homepage_uri" => "https://alchemists.io/projects/pragmater",
  14. "funding_uri" => "https://github.com/sponsors/bkuhlmann",
  15. "label" => "Pragmater",
  16. "rubygems_mfa_required" => "true",
  17. "source_code_uri" => "https://github.com/bkuhlmann/pragmater"
  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-schema", "~> 1.13"
  25. 1 spec.add_dependency "etcher", "~> 3.0"
  26. 1 spec.add_dependency "infusible", "~> 4.0"
  27. 1 spec.add_dependency "refinements", "~> 13.5"
  28. 1 spec.add_dependency "runcom", "~> 12.0"
  29. 1 spec.add_dependency "sod", "~> 1.0"
  30. 1 spec.add_dependency "spek", "~> 4.0"
  31. 1 spec.add_dependency "zeitwerk", "~> 2.7"
  32. 1 spec.bindir = "exe"
  33. 1 spec.executables << "pragmater"
  34. 1 spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
  35. 1 spec.files = Dir["*.gemspec", "lib/**/*"]
  36. end

lib/pragmater/cli/actions/comment.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 Pragmater
  4. 1 module CLI
  5. 1 module Actions
  6. # Stores pragma comments.
  7. 1 class Comment < Sod::Action
  8. 1 include Dependencies[:settings]
  9. 1 description "Set pragma comments."
  10. 1 on %w[-c --comments], argument: "[a,b,c]"
  11. 18 default { Container[:settings].comments }
  12. 1 def call(comments = default) = settings.comments = Array(comments)
  13. end
  14. end
  15. end
  16. end

lib/pragmater/cli/actions/pattern.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 Pragmater
  4. 1 module CLI
  5. 1 module Actions
  6. # Stores file patterns.
  7. 1 class Pattern < Sod::Action
  8. 1 include Dependencies[:settings]
  9. 1 description "Set file patterns."
  10. 1 on %w[-p --patterns], argument: "[a,b,c]"
  11. 18 default { Container[:settings].patterns }
  12. 1 def call(patterns = default) = settings.patterns = Array(patterns)
  13. end
  14. end
  15. end
  16. end

lib/pragmater/cli/actions/root.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 Pragmater
  4. 1 module CLI
  5. 1 module Actions
  6. # Stores root path.
  7. 1 class Root < Sod::Action
  8. 1 include Dependencies[:settings]
  9. 1 description "Set root directory."
  10. 1 on %w[-r --root], argument: "[PATH]"
  11. 17 default { Container[:settings].root_dir }
  12. 1 def call(path = default) = settings.root_dir = Pathname(path)
  13. end
  14. end
  15. end
  16. end

lib/pragmater/cli/commands/insert.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 "sod"
  3. 1 module Pragmater
  4. 1 module CLI
  5. 1 module Commands
  6. # Inserts pragmas.
  7. 1 class Insert < Sod::Command
  8. 1 include Dependencies[:settings, :io]
  9. 1 handle "insert"
  10. 1 description "Insert pragma comments."
  11. 1 on Actions::Root
  12. 1 on Actions::Comment
  13. 1 on Actions::Pattern
  14. 1 def initialize(handler: Inserter.new, **)
  15. 7 super(**)
  16. 7 @handler = handler
  17. end
  18. 3 def call = handler.call { |path| io.puts path }
  19. 1 private
  20. 1 attr_reader :handler
  21. end
  22. end
  23. end
  24. end

lib/pragmater/cli/commands/remove.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 "sod"
  3. 1 module Pragmater
  4. 1 module CLI
  5. 1 module Commands
  6. # Removes pragmas.
  7. 1 class Remove < Sod::Command
  8. 1 include Dependencies[:settings, :io]
  9. 1 handle "remove"
  10. 1 description "Remove pragma comments."
  11. 1 on Actions::Root
  12. 1 on Actions::Comment
  13. 1 on Actions::Pattern
  14. 1 def initialize(handler: Remover.new, **)
  15. 7 super(**)
  16. 7 @handler = handler
  17. end
  18. 3 def call = handler.call { |path| io.puts path }
  19. 1 private
  20. 1 attr_reader :handler
  21. end
  22. end
  23. end
  24. end

lib/pragmater/cli/shell.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 "sod"
  3. 1 module Pragmater
  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. 5 super(**)
  10. 5 @context = context
  11. 5 @dsl = dsl
  12. end
  13. 1 def call(...) = cli.call(...)
  14. 1 private
  15. 1 attr_reader :context, :dsl
  16. 1 def cli
  17. 5 context = build_context
  18. 5 dsl.new :pragmater, banner: specification.banner do
  19. 5 on(Sod::Prefabs::Commands::Config, context:)
  20. 5 on Commands::Insert
  21. 5 on Commands::Remove
  22. 5 on(Sod::Prefabs::Actions::Version, context:)
  23. 5 on Sod::Prefabs::Actions::Help, self
  24. end
  25. end
  26. 1 def build_context
  27. 5 context[defaults_path:, xdg_config:, version_label: specification.labeled_version]
  28. end
  29. end
  30. end
  31. end

lib/pragmater/configuration/contract.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 "dry/schema"
  3. 1 require "etcher"
  4. 1 Dry::Schema.load_extensions :monads
  5. 1 module Pragmater
  6. 1 module Configuration
  7. 1 Contract = Dry::Schema.Params do
  8. 1 required(:comments).array :string
  9. 1 required(:patterns).array :string
  10. 1 required(:root_dir).filled Etcher::Types::Pathname
  11. end
  12. end
  13. end

lib/pragmater/configuration/model.rb

100.0% lines covered

100.0% branches covered

7 relevant lines. 7 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pragmater
  3. 1 module Configuration
  4. # Defines the content of the configuration for use throughout the gem.
  5. 1 Model = Struct.new :comments, :patterns, :root_dir do
  6. 1 def initialize(**)
  7. 30 super
  8. 30 self[:comments] = Array comments
  9. 30 self[:patterns] = Array patterns
  10. end
  11. end
  12. end
  13. end

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

lib/pragmater/formatters/general.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pragmater
  3. 1 module Formatters
  4. # Formats general pragmas in a consistent manner.
  5. 1 class General
  6. 1 PATTERN = /
  7. \A # Start of line.
  8. \# # Start of comment.
  9. \s? # Space - optional.
  10. \w+ # Key - One or more word characters only.
  11. : # Delimiter.
  12. \s? # Space - optional.
  13. [\w-]+ # Value - One or more word or dash characters.
  14. \Z # End of line.
  15. /x
  16. 1 def initialize string, pattern: PATTERN
  17. 60 @string = string
  18. 60 @pattern = pattern
  19. end
  20. 1 def call
  21. 60 else: 45 then: 15 return string unless string.match? pattern
  22. 90 string.split(":").then { |key, value| "# #{key.gsub(/\#\s?/, "")}: #{value.strip}" }
  23. end
  24. 1 private
  25. 1 attr_reader :string, :pattern
  26. end
  27. end
  28. end

lib/pragmater/formatters/main.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 Pragmater
  3. 1 module Formatters
  4. # Formats all pragmas in a consistent manner.
  5. 1 class Main
  6. 1 FORMATTERS = [General, Shebang].freeze
  7. 3 PATTERN = FORMATTERS.map { |formatter| formatter::PATTERN }
  8. 1 .then { |patterns| Regexp.union(*patterns) }
  9. .freeze
  10. 1 def initialize string, formatters: FORMATTERS
  11. 53 @string = string
  12. 53 @formatters = formatters
  13. end
  14. 107 def call = formatters.reduce(string) { |pragma, formatter| formatter.new(pragma).call }
  15. 1 private
  16. 1 attr_reader :string, :formatters
  17. end
  18. end
  19. end

lib/pragmater/formatters/shebang.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pragmater
  3. 1 module Formatters
  4. # Formats shebang pragmas in a consistent manner.
  5. 1 class Shebang
  6. 1 PATTERN = %r(\A\#!\s?/.*ruby\Z)
  7. 1 def initialize string, pattern: PATTERN
  8. 58 @string = string
  9. 58 @pattern = pattern
  10. end
  11. 1 def call
  12. 58 else: 12 then: 46 return string unless string.match? pattern
  13. 24 string.split("!").then { |octothorpe, path| "#{octothorpe}! #{path.strip}" }
  14. end
  15. 1 private
  16. 1 attr_reader :string, :pattern
  17. end
  18. end
  19. end

lib/pragmater/inserter.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 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/pathname"
  3. 1 module Pragmater
  4. # Inserts pragma comments.
  5. 1 class Inserter
  6. 1 include Dependencies[:settings]
  7. 1 using Refinements::Pathname
  8. 1 def initialize(parser: Parsers::File.new, **)
  9. 15 @parser = parser
  10. 15 super(**)
  11. end
  12. 1 def call
  13. 11 Pathname(settings.root_dir).files("{#{settings.patterns.join ","}}").map do |path|
  14. 8 then: 3 else: 5 yield path if block_given?
  15. 8 path.write parser.call(path, settings.comments, action: :insert).join
  16. end
  17. end
  18. 1 private
  19. 1 attr_reader :parser
  20. end
  21. end

lib/pragmater/parsers/comments.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 Pragmater
  3. 1 module Parsers
  4. # Manages pragma comments.
  5. 1 class Comments
  6. 1 def initialize older, newer, formatter: Formatters::Main
  7. 33 @formatter = formatter
  8. 33 @older = format older
  9. 33 @newer = format newer
  10. end
  11. 1 def insert = older.union(newer)
  12. 1 def remove = older - older.intersection(newer)
  13. 1 private
  14. 1 attr_reader :formatter, :older, :newer
  15. 51 def format(pragmas) = Array(pragmas).map { |pragma| formatter.new(pragma).call }
  16. end
  17. end
  18. end

lib/pragmater/parsers/file.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 Pragmater
  3. 1 module Parsers
  4. # Parses a file into pragma comment and body lines.
  5. 1 class File
  6. 1 def initialize pattern: Formatters::Main::PATTERN,
  7. comments: Comments,
  8. processor: Processors::Handler.new
  9. 32 @pattern = pattern
  10. 32 @comments = comments
  11. 32 @processor = processor
  12. end
  13. 1 def call path, new_comments, action:
  14. 20 path.each_line
  15. 14 .partition { |line| line.match? pattern }
  16. .then do |old_comments, body|
  17. 20 processor.call action, wrap_in_new_line(old_comments, new_comments, action), body
  18. end
  19. end
  20. 1 private
  21. 1 attr_reader :pattern, :comments, :processor
  22. 1 def wrap_in_new_line old_comments, new_comments, action
  23. 33 comments.new(old_comments, new_comments).public_send(action).map { |line| "#{line}\n" }
  24. end
  25. end
  26. end
  27. end

lib/pragmater/processors/handler.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 Pragmater
  3. 1 module Processors
  4. # Handles the insertion or removal of pragma comments.
  5. 1 class Handler
  6. 1 DEFAULTS = {insert: Inserter, remove: Remover}.freeze
  7. 1 def initialize processors: DEFAULTS
  8. 35 @processors = processors
  9. end
  10. 1 def call(action, comments, body) = processors.fetch(action).new(comments, body).call
  11. 1 private
  12. 1 attr_reader :processors
  13. end
  14. end
  15. end

lib/pragmater/processors/inserter.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pragmater
  3. 1 module Processors
  4. # Inserts new pragma comments.
  5. 1 class Inserter
  6. 1 def initialize comments, body
  7. 16 @comments = comments
  8. 16 @body = body
  9. end
  10. 1 def call
  11. 16 body.first.then do |first|
  12. 16 else: 12 then: 4 comments.append "\n" unless first == "\n" || body.empty?
  13. 16 comments + body
  14. end
  15. end
  16. 1 private
  17. 1 attr_reader :comments, :body
  18. end
  19. end
  20. end

lib/pragmater/processors/remover.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # frozen_string_literal: true
  2. 1 module Pragmater
  3. 1 module Processors
  4. # Removes existing pragma comments.
  5. 1 class Remover
  6. 1 def initialize comments, body
  7. 12 @comments = comments
  8. 12 @body = body
  9. end
  10. 1 def call
  11. 12 body.first.then do |first_line|
  12. 12 then: 3 else: 9 body.delete_at 0 if first_line == "\n" && comments.empty?
  13. 12 comments + body
  14. end
  15. end
  16. 1 private
  17. 1 attr_reader :comments, :body
  18. end
  19. end
  20. end

lib/pragmater/remover.rb

100.0% lines covered

100.0% branches covered

14 relevant lines. 14 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/pathname"
  3. 1 module Pragmater
  4. # Removes pragma comments.
  5. 1 class Remover
  6. 1 include Dependencies[:settings]
  7. 1 using Refinements::Pathname
  8. 1 def initialize(parser: Parsers::File.new, **)
  9. 10 @parser = parser
  10. 10 super(**)
  11. end
  12. 1 def call
  13. 6 Pathname(settings.root_dir).files("{#{settings.patterns.join ","}}").map do |path|
  14. 5 then: 3 else: 2 yield path if block_given?
  15. 5 path.write parser.call(path, settings.comments, action: :remove).join
  16. end
  17. end
  18. 1 private
  19. 1 attr_reader :parser
  20. end
  21. end