Skip to content

Commit 5dd5e0c

Browse files
committed
fix: fix Rubocop Metrics/PerceivedComplexity offense
1 parent 1da8c28 commit 5dd5e0c

File tree

4 files changed

+499
-299
lines changed

4 files changed

+499
-299
lines changed

.rubocop_todo.yml

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2025-07-05 15:13:23 UTC using RuboCop version 1.77.0.
3+
# on 2025-07-06 05:52:16 UTC using RuboCop version 1.77.0.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
77
# versions of RuboCop, may require this file to be generated again.
88

9-
# Offense count: 56
9+
# Offense count: 50
1010
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
1111
Metrics/AbcSize:
1212
Max: 109
1313

1414
# Offense count: 21
1515
# Configuration parameters: CountComments, CountAsOne.
1616
Metrics/ClassLength:
17-
Max: 976
17+
Max: 1032
1818

19-
# Offense count: 9
19+
# Offense count: 2
2020
# Configuration parameters: AllowedMethods, AllowedPatterns.
2121
Metrics/CyclomaticComplexity:
22-
Max: 14
23-
24-
# Offense count: 7
25-
# Configuration parameters: AllowedMethods, AllowedPatterns.
26-
Metrics/PerceivedComplexity:
27-
Max: 14
22+
Max: 8

lib/git/args_builder.rb

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# frozen_string_literal: true
2+
3+
module Git
4+
# Takes a hash of user options and a declarative map and produces
5+
# an array of command-line arguments. Also validates that only
6+
# supported options are provided based on the map.
7+
#
8+
# @api private
9+
class ArgsBuilder
10+
# This hash maps an option type to a lambda that knows how to build the
11+
# corresponding command-line argument. This is a scalable dispatch table.
12+
ARG_BUILDERS = {
13+
boolean: ->(config, value) { value ? config[:flag] : [] },
14+
15+
valued_equals: ->(config, value) { "#{config[:flag]}=#{value}" if value },
16+
17+
valued_space: ->(config, value) { [config[:flag], value.to_s] if value },
18+
19+
repeatable_valued_space: lambda do |config, value|
20+
Array(value).flat_map { |v| [config[:flag], v.to_s] }
21+
end,
22+
23+
custom: ->(config, value) { config[:builder].call(value) },
24+
25+
validate_only: ->(_config, _value) { [] } # Does not build any args
26+
}.freeze
27+
28+
# Main entrypoint to validate options and build arguments
29+
def self.build(opts, option_map)
30+
validate!(opts, option_map)
31+
new(opts, option_map).build
32+
end
33+
34+
# Public validation method that can be called independently
35+
def self.validate!(opts, option_map)
36+
validate_unsupported_keys!(opts, option_map)
37+
validate_configured_options!(opts, option_map)
38+
end
39+
40+
def initialize(opts, option_map)
41+
@opts = opts
42+
@option_map = option_map
43+
end
44+
45+
def build
46+
@option_map.flat_map do |config|
47+
type = config[:type]
48+
next config[:flag] if type == :static
49+
50+
key = config[:keys].find { |k| @opts.key?(k) }
51+
next [] unless key
52+
53+
build_arg_for_option(config, @opts[key])
54+
end.compact
55+
end
56+
57+
private
58+
59+
def build_arg_for_option(config, value)
60+
builder = ARG_BUILDERS[config[:type]]
61+
builder&.call(config, value) || []
62+
end
63+
64+
private_class_method def self.validate_unsupported_keys!(opts, option_map)
65+
all_valid_keys = option_map.flat_map { |config| config[:keys] }.compact
66+
unsupported_keys = opts.keys - all_valid_keys
67+
68+
return if unsupported_keys.empty?
69+
70+
raise ArgumentError, "Unsupported options: #{unsupported_keys.map(&:inspect).join(', ')}"
71+
end
72+
73+
private_class_method def self.validate_configured_options!(opts, option_map)
74+
option_map.each do |config|
75+
next unless config[:keys] # Skip static flags
76+
77+
check_for_missing_required_option!(opts, config)
78+
validate_option_value!(opts, config)
79+
end
80+
end
81+
82+
private_class_method def self.check_for_missing_required_option!(opts, config)
83+
return unless config[:required]
84+
85+
key_provided = config[:keys].any? { |k| opts.key?(k) }
86+
return if key_provided
87+
88+
raise ArgumentError, "Missing required option: #{config[:keys].first}"
89+
end
90+
91+
private_class_method def self.validate_option_value!(opts, config)
92+
validator = config[:validator]
93+
return unless validator
94+
95+
user_key = config[:keys].find { |k| opts.key?(k) }
96+
return unless user_key # Don't validate if the user didn't provide the option
97+
98+
return if validator.call(opts[user_key])
99+
100+
raise ArgumentError, "Invalid value for option: #{user_key}"
101+
end
102+
end
103+
end

0 commit comments

Comments
 (0)