utils 0.68.0 → 0.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +251 -18
  3. data/bin/ascii7 +28 -0
  4. data/bin/blameline +17 -0
  5. data/bin/changes +69 -5
  6. data/bin/classify +128 -7
  7. data/bin/code_comment +102 -104
  8. data/bin/commit_message +26 -2
  9. data/bin/create_cstags +18 -0
  10. data/bin/create_tags +10 -0
  11. data/bin/discover +38 -1
  12. data/bin/edit +14 -1
  13. data/bin/edit_wait +14 -0
  14. data/bin/enum +139 -15
  15. data/bin/git-empty +50 -0
  16. data/bin/git-versions +20 -0
  17. data/bin/json_check +15 -1
  18. data/bin/long_lines +11 -2
  19. data/bin/myex +38 -0
  20. data/bin/on_change +22 -0
  21. data/bin/path +21 -0
  22. data/bin/print_method +29 -1
  23. data/bin/probe +52 -4
  24. data/bin/rainbow +52 -0
  25. data/bin/rd2md +15 -0
  26. data/bin/search +83 -1
  27. data/bin/sedit +6 -0
  28. data/bin/serve +18 -3
  29. data/bin/ssh-tunnel +14 -2
  30. data/bin/strip_spaces +17 -9
  31. data/bin/sync_dir +48 -1
  32. data/bin/untest +19 -1
  33. data/bin/utils-utilsrc +42 -6
  34. data/bin/vcf2alias +33 -0
  35. data/bin/yaml_check +24 -2
  36. data/lib/utils/config_dir.rb +127 -0
  37. data/lib/utils/config_file.rb +445 -1
  38. data/lib/utils/editor.rb +215 -3
  39. data/lib/utils/finder.rb +127 -16
  40. data/lib/utils/grepper.rb +90 -1
  41. data/lib/utils/irb.rb +387 -39
  42. data/lib/utils/line_blamer.rb +28 -0
  43. data/lib/utils/line_formatter.rb +198 -0
  44. data/lib/utils/md5.rb +14 -0
  45. data/lib/utils/patterns.rb +77 -3
  46. data/lib/utils/probe_server.rb +302 -23
  47. data/lib/utils/ssh_tunnel_specification.rb +58 -0
  48. data/lib/utils/version.rb +1 -1
  49. data/lib/utils/xt/source_location_extension.rb +18 -6
  50. data/lib/utils.rb +3 -1
  51. data/tests/utils_test.rb +7 -1
  52. data/utils.gemspec +5 -5
  53. metadata +4 -6
  54. data/bin/number_files +0 -26
  55. data/lib/utils/xdg_config.rb +0 -10
  56. /data/{COPYING → LICENSE} +0 -0
data/bin/rd2md CHANGED
@@ -1,4 +1,19 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # RDoc to Markdown Converter
4
+ #
5
+ # This script converts RDoc formatted documentation into Markdown format.
6
+ # It reads from standard input (or files passed via ARGF) and outputs
7
+ # the converted Markdown to stdout.
8
+ #
9
+ # Usage: rd2md [input.rdoc] > output.md
10
+ # or: cat input.rdoc | rd2md > output.md
11
+ #
12
+ # Features:
13
+ # - Converts RDoc markup syntax to equivalent Markdown
14
+ # - Preserves code blocks, lists, and formatting
15
+ # - Handles standard RDoc elements like headings, emphasis, and links
16
+ # - Streaming conversion for efficient processing of large files
2
17
 
3
18
  require 'rdoc'
4
19
 
data/bin/search CHANGED
@@ -1,13 +1,39 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Code Search and Edit Tool
4
+ #
5
+ # Interactive code search and editing utility that combines grep-like functionality
6
+ # with Vim integration for efficient code navigation and modification.
7
+ #
8
+ # Features:
9
+ # - Search code patterns across files with extensive filtering options
10
+ # - Edit matching files directly in Vim with automatic positioning
11
+ # - Interactive replacement with confirmation prompts
12
+ # - Support for fuzzy matching, regular expressions, and case-insensitive searches
13
+ # - Git integration to show author information
14
+ # - Configurable context display (lines before/after matches)
15
+ #
16
+ # The tool integrates seamlessly with your terminal workflow, allowing you to
17
+ # search code and edit files without touching the mouse.
2
18
 
3
19
  require 'utils'
4
20
  include Utils
5
- require 'tins/xt'
6
21
  include Tins::GO
7
22
  require 'term/ansicolor'
8
23
  include Term::ANSIColor
9
24
  require 'tempfile'
10
25
 
26
+ # The convert_ruby_to_vim_regexp method converts a Ruby regular expression
27
+ # pattern to a Vim-compatible regular expression string.
28
+ #
29
+ # This method takes a Ruby regular expression object and transforms it into a
30
+ # format suitable for Vim's regular expression engine.
31
+ # It duplicates the source pattern, escapes standalone question marks, and
32
+ # appends a case folding flag when appropriate.
33
+ #
34
+ # @param pattern [ Regexp ] the Ruby regular expression pattern to convert
35
+ #
36
+ # @return [ String ] the converted Vim-compatible regular expression string
11
37
  def convert_ruby_to_vim_regexp(pattern)
12
38
  regexp = pattern.source.dup
13
39
  regexp.gsub!(/([^\\])\?/, '\1\\?')
@@ -15,6 +41,16 @@ def convert_ruby_to_vim_regexp(pattern)
15
41
  regexp
16
42
  end
17
43
 
44
+ # The read_line method retrieves a specific line from a file based on the
45
+ # source location.
46
+ #
47
+ # This method extracts the filename and line number from the provided path
48
+ # object, then opens the file to lazily iterate through its contents until it
49
+ # finds and returns the line at the specified line number.
50
+ #
51
+ # @param path [ Object] the path object containing source location information
52
+ #
53
+ # @return [ String, nil ] the content of the specified line if found, otherwise nil
18
54
  def read_line(path)
19
55
  filename, lineno = path.source_location
20
56
  File.open(filename) do |file|
@@ -22,6 +58,17 @@ def read_line(path)
22
58
  end
23
59
  end
24
60
 
61
+ # The replace_line method replaces a specific line in a file with a new line
62
+ # content.
63
+ #
64
+ # This method takes a path object that contains source location information,
65
+ # extracts the filename and line number, then opens the file to replace the
66
+ # specified line with the provided new line content. It uses a temporary file
67
+ # to perform the replacement safely without corrupting the original file.
68
+ #
69
+ # @param path [ Object] an object that responds to source_location and provides
70
+ # filename and line number information
71
+ # @param new_line [ String ] the new line content that will replace the existing line
25
72
  def replace_line(path, new_line)
26
73
  filename, lineno = path.source_location
27
74
  Tempfile.open do |output|
@@ -43,6 +90,23 @@ def replace_line(path, new_line)
43
90
  end
44
91
  end
45
92
 
93
+ # The replace_ask method guides the user through replacing patterns in a file
94
+ # line by line.
95
+ #
96
+ # It reads a line from the specified path, displays it with highlighted
97
+ # matches, and prompts the user for replacement decisions based on the provided
98
+ # pattern and replacement string.
99
+ # The method supports various user responses to control the replacement
100
+ # process, including replacing individual matches, all matches, editing the
101
+ # file, or quitting.
102
+ #
103
+ # @param editor [ Utils::Editor ] the editor instance used for file editing
104
+ # @param path [ String ] the file path from which to read and replace content
105
+ # @param pattern [ Utils::Patterns::Pattern ] the pattern matcher used to identify content for replacement
106
+ # @param replace [ String ] the string to replace matched content with
107
+ # @param all [ TrueClass, FalseClass ] flag indicating whether to replace all matches immediately
108
+ #
109
+ # @return [ TrueClass, FalseClass ] true if all matches were replaced, false otherwise
46
110
  def replace_ask(editor, path, pattern, replace, all)
47
111
  line = read_line path
48
112
  display_new_line = line.gsub(
@@ -77,6 +141,18 @@ def replace_ask(editor, path, pattern, replace, all)
77
141
  end
78
142
  end
79
143
 
144
+ # The edit_files method opens editor sessions for specified files and applies
145
+ # pattern-based editing operations.
146
+ #
147
+ # This method utilizes an editor instance to open files for editing, applying
148
+ # either replacement operations or interactive selection based on provided
149
+ # parameters. It supports processing multiple paths with optional pattern
150
+ # matching and replacement functionality.
151
+ #
152
+ # @param pattern [ String ] the pattern used for filtering or matching files
153
+ # @param paths [ Array<String> ] the list of file paths to be processed
154
+ # @param pick [ TrueClass, FalseClass ] determines whether to interactively select a file from the paths
155
+ # @param replace [ String, nil ] the replacement string to be applied when performing replacements
80
156
  def edit_files(pattern, paths, pick: false, replace: nil)
81
157
  editor = Utils::Editor.new
82
158
  editor.edit_remote_send("<ESC>/#{convert_ruby_to_vim_regexp(pattern)}<CR>")
@@ -107,6 +183,12 @@ def edit_files(pattern, paths, pick: false, replace: nil)
107
183
  end
108
184
  end
109
185
 
186
+ # The usage method displays the command-line interface help text and version
187
+ # information.
188
+ #
189
+ # This method outputs a formatted help message that describes the available
190
+ # options and usage patterns for the command-line tool, including pattern
191
+ # matching, file filtering, context display, and search behavior.
110
192
  def usage
111
193
  puts <<~EOT
112
194
  Usage: #{File.basename($0)} [OPTS] PATTERN [PATHS]
data/bin/sedit CHANGED
@@ -1,3 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Super-user editor launcher - executes 'edit' command with sudo privileges
4
+ # Usage: sedit [FILE...]
5
+ #
6
+ # This script is a simple wrapper that elevates permissions when editing files,
7
+ # useful for modifying system configuration files or protected resources.
2
8
 
3
9
  exec 'sudo', 'edit', *$*
data/bin/serve CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Launch simple HTTP server for a local directory
2
4
 
3
5
  require 'tins/go'
4
6
  include Tins::GO
@@ -7,9 +9,22 @@ require 'webrick'
7
9
  $opts = go 'p:h'
8
10
 
9
11
  if $opts[?h]
10
- puts <<USAGE
11
- #{File.basename($0)} [OPTIONS] [DIR]
12
- USAGE
12
+ puts <<~USAGE
13
+ #{File.basename($0)} - Launch simple HTTP server for a local directory
14
+
15
+ Usage: #{File.basename($0)} [OPTIONS] [DIR]
16
+
17
+ Options:
18
+ -p PORT Specify port number (default: 8888)
19
+ -h Show this help message
20
+
21
+ Examples:
22
+ #{File.basename($0)} # Serve current directory on port 8888
23
+ #{File.basename($0)} -p 3000 # Serve on port 3000
24
+ #{File.basename($0)} /path/to/dir # Serve specific directory
25
+
26
+ Note: If no directory is specified, serves the current working directory.
27
+ USAGE
13
28
  exit
14
29
  end
15
30
 
data/bin/ssh-tunnel CHANGED
@@ -1,10 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # SSH tunnel manager with session and multiplexer support
4
+ #
5
+ # This script manages SSH connections with tunneling capabilities, session
6
+ # management, and terminal multiplexer integration (screen/tmux).
2
7
 
3
8
  require 'fileutils'
4
9
  include FileUtils::Verbose
5
- require 'tins/xt'
6
- include Tins::GO
7
10
  require 'utils'
11
+ include Tins::GO
8
12
  require 'pstree'
9
13
  require 'term/ansicolor'
10
14
  include Term::ANSIColor
@@ -19,6 +23,8 @@ Host *
19
23
  ControlPath ~/.ssh/%r@%h:%p.sock
20
24
  SSH_CONFIG_END
21
25
 
26
+ # The usage method displays the command-line interface help text and version
27
+ # information.
22
28
  def usage
23
29
  puts <<~EOT
24
30
  Usage: #{File.basename($0)} [OPTS] [user@]remote[:port]"
@@ -39,6 +45,12 @@ def usage
39
45
  exit 1
40
46
  end
41
47
 
48
+ # The cmd method executes a shell command string.
49
+ #
50
+ # This method takes a command string and executes it using the system exec
51
+ # function, replacing the current process with the specified command.
52
+ #
53
+ # @param string [ String ] the shell command to be executed
42
54
  def cmd(string)
43
55
  $DEBUG and warn "Executing: #{string.inspect}"
44
56
  exec string
data/bin/strip_spaces CHANGED
@@ -1,4 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Strip trailing whitespace from files or stdin
4
+ #
5
+ # This script removes trailing spaces and tabs from files, with optional tab
6
+ # conversion to spaces. It can process directories recursively or read from
7
+ # stdin and write to stdout.
2
8
 
3
9
  require 'tins/go'
4
10
  include Tins::GO
@@ -8,20 +14,22 @@ require 'tins/find'
8
14
  include Tins::Find
9
15
  require 'utils'
10
16
 
17
+ # The usage method displays the help message and version information for the
18
+ # command-line tool.
11
19
  def usage
12
- puts <<-EOT
13
- Usage: #{File.basename($0)} [OPTS] [PATHS]
20
+ puts <<~EOT
21
+ Usage: #{File.basename($0)} [OPTS] [PATHS]
14
22
 
15
- PATHS are the directory and file paths that are search for files to be
16
- stripped.
23
+ PATHS are the directory and file paths that are search for files to be
24
+ stripped.
17
25
 
18
- Options are
26
+ Options are
19
27
 
20
- -t COLUMNS turn tabs into COLUMNS spaces
21
- -I SUFFIXES list of suffixes
22
- -h display this help
28
+ -t COLUMNS turn tabs into COLUMNS spaces
29
+ -I SUFFIX list of suffixes (can be used multiple times)
30
+ -h display this help
23
31
 
24
- Version is #{File.basename($0)} #{Utils::VERSION}.
32
+ Version is #{File.basename($0)} #{Utils::VERSION}.
25
33
  EOT
26
34
  exit 1
27
35
  end
data/bin/sync_dir CHANGED
@@ -1,7 +1,31 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Directory Synchronization Tool
4
+ #
5
+ # This script synchronizes directories with interactive conflict resolution. It
6
+ # compares source and destination directories recursively, showing differences
7
+ # and prompting for actions when conflicts arise.
8
+ #
9
+ # Usage:
10
+ # sync_dir <source_directory> [<destination_directory>]
11
+ #
12
+ # If destination is not specified, current directory is used.
13
+ #
14
+ # Features:
15
+ # - Interactive file comparison with colored diffs
16
+ # - Support for copying, editing, deleting, or skipping files
17
+ # - Configuration-based skipping of files/directories
18
+ # - Vim integration for editing files
19
+ # - Colorized output using ANSI escape codes
20
+ #
21
+ # Actions available when conflicts are detected:
22
+ # - c: Copy file to destination
23
+ # - e: Edit file with vim
24
+ # - d: Delete file from source
25
+ # - s: Skip (continue with next file)
26
+ # - q: Quit (exit script)
2
27
 
3
28
  require 'pathname'
4
- require 'tins/xt'
5
29
  require 'fileutils'
6
30
  include FileUtils::Verbose
7
31
  require 'utils'
@@ -11,16 +35,39 @@ include Term::ANSIColor
11
35
  $config = Utils::ConfigFile.new
12
36
  $config.configure_from_paths
13
37
 
38
+ # The local_path method computes the relative path from the current directory
39
+ # to the specified path.
40
+ #
41
+ # This method takes an absolute or relative path and returns its relative
42
+ # representation with respect to the current working directory.
43
+ #
44
+ # @param path [ String ] the path to be converted to a relative path
45
+ #
46
+ # @return [ String ] the relative path from the current directory to the
47
+ # specified path
14
48
  def local_path(path)
15
49
  Pathname.new(path).expand_path.relative_path_from(
16
50
  Pathname.new(?.).expand_path
17
51
  ).to_s
18
52
  end
19
53
 
54
+ # The diff_dir method compares the contents of two directories recursively.
55
+ #
56
+ # This method executes a shell command to perform a recursive directory
57
+ # comparison between the source and destination paths, reporting differences in
58
+ # files and subdirectories.
59
+ #
60
+ # @return [ String ] the output from the diff command showing directory
61
+ # differences
20
62
  def diff_dir
21
63
  `diff -rq #{$src.inspect} #{$dst.inspect}`
22
64
  end
23
65
 
66
+ # The ask? method prompts the user for input and returns the trimmed response.
67
+ #
68
+ # @param prompt [ String ] the message to display to the user
69
+ #
70
+ # @return [ String ] the user's input with leading and trailing whitespace removed
24
71
  def ask?(prompt:)
25
72
  print prompt
26
73
  gets.chomp
data/bin/untest CHANGED
@@ -1,8 +1,26 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Untest - Convert Minitest test blocks to standard Ruby methods
4
+ #
5
+ # This script transforms Minitest test definitions from:
6
+ # test "method name" do
7
+ # # test code
8
+ # end
9
+ #
10
+ # To standard Ruby method definitions:
11
+ # def test_method_name
12
+ # # test code
13
+ # end
14
+ #
15
+ # Usage:
16
+ # untest file1.rb file2.rb
17
+ #
18
+ # The script preserves whitespace and normalizes test names to snake_case
19
+ # format.
2
20
 
3
21
  require 'tins/xt/secure_write'
4
22
 
5
- for filename in ARGV
23
+ ARGV.each do |filename|
6
24
  File.open(filename) do |input|
7
25
  File.secure_write(filename) do |output|
8
26
  until input.eof?
data/bin/utils-utilsrc CHANGED
@@ -1,12 +1,27 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # Utils Configuration Manager
4
+ #
5
+ # Manages utility configuration files (~/.utilsrc) with commands to show,
6
+ # diff, edit, and display default configurations.
2
7
 
3
8
  require 'tempfile'
4
9
  require 'utils'
5
- include Utils
6
-
7
- $config = Utils::ConfigFile.new
8
- $utilsrc = File.expand_path('~/.utilsrc')
9
10
 
11
+ # Creates a default utilsrc file by generating configuration content and
12
+ # yielding temporary and source paths.
13
+ #
14
+ # This method checks if a utilsrc file exists at the configured path, and if so,
15
+ # creates a temporary file containing the Ruby representation of the current
16
+ # configuration. It then yields both the temporary file path and the original
17
+ # utilsrc path to the provided block for further processing.
18
+ #
19
+ # @return [ nil ] returns nil if no utilsrc file exists at the configured path
20
+ #
21
+ # @yield [ tmp_path, source_path ]
22
+ #
23
+ # @yieldparam tmp_path [ String ] the path to the temporary file containing configuration
24
+ # @yieldparam source_path [ String ] the path to the original utilsrc file
10
25
  def create_default_utilsrc
11
26
  if File.exist?($utilsrc)
12
27
  Tempfile.open('utilsrc') do |tmp|
@@ -17,6 +32,14 @@ def create_default_utilsrc
17
32
  end
18
33
  end
19
34
 
35
+ $config = Utils::ConfigFile.new
36
+ utilsrc_path = if ARGV.size == 2
37
+ ARGV.pop
38
+ else
39
+ '~/.utilsrc'
40
+ end
41
+ $utilsrc = File.expand_path(utilsrc_path)
42
+
20
43
  case cmd = ARGV.shift
21
44
  when 'show'
22
45
  if File.exist?($utilsrc)
@@ -28,7 +51,7 @@ when 'default'
28
51
  puts $config.to_ruby
29
52
  when 'diff'
30
53
  create_default_utilsrc do |default_utilsrc, utilsrc|
31
- system "diff -u #{default_utilsrc.inspect} #{utilsrc.inspect} | cdiff"
54
+ system "diff --color=always -u #{default_utilsrc.inspect} #{utilsrc.inspect}"
32
55
  end
33
56
  when 'edit'
34
57
  create_default_utilsrc do |default_utilsrc, utilsrc|
@@ -36,6 +59,19 @@ when 'edit'
36
59
  end
37
60
  else
38
61
  puts <<~EOT
39
- Usage: #{File.basename($0)} show|diff|edit
62
+ Usage: #{File.basename($0)} show|diff|edit|default [UTILSRC]
63
+
64
+ Commands:
65
+
66
+ show - Display current ~/.utilsrc file or default config if none exists
67
+ default - Show the default Ruby configuration representation
68
+ diff - Show differences between current config and default using 'diff'
69
+ edit - Open current config in vimdiff to compare with default for editing
70
+
71
+
72
+ Arguments:
73
+
74
+ UTILSRC - Optional path to configuration file (defaults to ~/.utilsrc)
75
+
40
76
  EOT
41
77
  end
data/bin/vcf2alias CHANGED
@@ -1,10 +1,43 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
+ # VCard to Mutt Aliases Converter
4
+ #
5
+ # This script reads a VCard (.vcf) file containing contact information and
6
+ # generates corresponding mutt alias entries in a specified output file.
7
+ #
8
+ # Features:
9
+ # - Generates unique shorthand identifiers for contact names
10
+ # - Handles multiple email types (HOME, WORK, general)
11
+ # - Supports Unicode characters including German umlauts
12
+ # - Avoids duplicate aliases through intelligent conflict resolution
13
+ # - Automatically resolves symbolic links in output path
14
+ #
15
+ # Usage: vcf2alias [input.vcf] [output.alias]
16
+ # input.vcf - VCard file path (defaults to ~/Desktop/Contacts.vcf)
17
+ # output.alias - Output file path (defaults to ~/.muttrc-aliases)
18
+ #
19
+ # Example output:
20
+ # alias jsm h-smith <john.smith@company.com>
21
+ # alias jsmh john.smith <john.smith.home@company.com>
22
+ # alias jsmw john.smith <john.smith.work@company.com>
23
+
3
24
  require 'tins/xt'
4
25
  require 'set'
5
26
 
6
27
  $shortcuts = Set.new
7
28
 
29
+ # The shortcut method generates a unique shorthand identifier for a given
30
+ # function name.
31
+ #
32
+ # This method creates a concise shortcut representation by extracting initial
33
+ # capital letters from the function name and appending an optional suffix.
34
+ # It ensures uniqueness by incrementing a numeric suffix or appending a digit
35
+ # when conflicts are detected in the global shortcuts collection.
36
+ #
37
+ # @param fn [ String ] the full name to generate a shortcut for
38
+ # @param suffix [ String, nil ] an optional suffix to append to the shortcut
39
+ #
40
+ # @return [ String ] the generated unique shortcut identifier
8
41
  def shortcut(fn, suffix = nil)
9
42
  shortcut = fn.scan(/([A-ZÄÖÜ])[a-zäöü]/).join.downcase
10
43
  shortcut.empty? and return fn.gsub(' ', ?_)
data/bin/yaml_check CHANGED
@@ -1,6 +1,28 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- require 'yaml'
2
+ #
3
+ # YAML Validator - Checks YAML syntax correctness
4
+ #
5
+ # This script validates YAML files or stdin input for proper syntax.
6
+ # It uses YAML.unsafe_load which can execute arbitrary Ruby code, so
7
+ # use with caution on untrusted input.
8
+ #
9
+ # Usage:
10
+ # yaml_check <filename> # Validate a file
11
+ # cat file.yaml | yaml_check # Validate from stdin
12
+ #
13
+ # Options:
14
+ # DEBUG=1 # Enable verbose output with parsed YAML
15
+ #
16
+ # Output:
17
+ # 'ok' - if YAML is valid
18
+ # 'nak' - if YAML is invalid
19
+ # Error messages to STDERR with line/column information
20
+ #
21
+ # Examples:
22
+ # ./yaml_check config.yaml
23
+ # echo "name: John" | ./yaml_check
24
+ # DEBUG=1 ./yaml_check data.yaml
25
+ #
4
26
 
5
27
  format = -> s {
6
28
  if /^\((?<f>[^)]+)\):\ (?<m>.*?) at line (?<l>\d+) column (?<c>\d+)/ =~ s
@@ -0,0 +1,127 @@
1
+ require 'pathname'
2
+ require 'stringio'
3
+
4
+ module Utils
5
+ class ConfigDir
6
+ # Initializes a new ConfigDir instance with the specified name and optional
7
+ # root path or environment variable.
8
+ #
9
+ # @param name [ String ] the name of the directory to be used
10
+ # @param root_path [ String, nil ] the root path to use; if nil, the
11
+ # default root path is used
12
+ # @param env_var [ String, nil ] the name of the environment variable to
13
+ # check for the root path
14
+ def initialize(name, root_path: nil, env_var: nil)
15
+ root_path ||= env_var_path(env_var)
16
+ @directory_path = derive_directory_path(name, root_path)
17
+ end
18
+
19
+ # Memoizes the foobar method's return value and returns the result of the computation.
20
+ # Initializes a new ConfigDir instance with the specified name and optional
21
+ # root path or environment variable.
22
+ #
23
+ # @param name [ String ] the name of the directory to be used
24
+ # @param root_path [ String, nil ] the root path to use; if nil, the
25
+ # default root path is used
26
+ # @param env_var [ String, nil ] the name of the environment variable to
27
+ # check for the root path
28
+ def initialize(name, root_path: nil, env_var: nil)
29
+ root_path ||= env_var_path(env_var)
30
+ @directory_path = derive_directory_path(name, root_path)
31
+ end
32
+
33
+ # Returns the string representation of the configuration directory path.
34
+ #
35
+ # @return [ String ] the path of the configuration directory as a string
36
+ def to_s
37
+ @directory_path.to_s
38
+ end
39
+
40
+ # Joins the directory path with the given path and returns the combined
41
+ # result.
42
+ #
43
+ # @param path [ String ] the path to be joined with the directory path
44
+ #
45
+ # @return [ Pathname ] the combined path as a Pathname object
46
+ def join(path)
47
+ @directory_path + path
48
+ end
49
+ alias + join
50
+
51
+ # Reads the content of a file at the given path within the configuration
52
+ # directory.
53
+ #
54
+ # If the file exists, it returns the file's content as a string encoded in
55
+ # UTF-8. If a block is given and the file exists, it opens the file and
56
+ # yields to the block.
57
+ # If the file does not exist and a default value is provided, it returns
58
+ # the default. If a block is given and the file does not exist, it yields a
59
+ # StringIO object containing
60
+ # the default value to the block.
61
+ #
62
+ # @param path [ String ] the path to the file relative to the configuration
63
+ # directory
64
+ # @param default [ String, nil ] the default value to return if the file
65
+ # does not exist
66
+ #
67
+ # @yield [ io ]
68
+ #
69
+ # @return [ String, nil ] the content of the file or the default value if
70
+ # the file does not exist
71
+ def read(path, default: nil, &block)
72
+ full_path = join(path)
73
+ if File.exist?(full_path)
74
+ if block
75
+ File.new(full_path, &block)
76
+ else
77
+ File.read(full_path, encoding: 'UTF-8')
78
+ end
79
+ else
80
+ if default && block
81
+ block.(StringIO.new(default))
82
+ else
83
+ default
84
+ end
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ # Derives the full directory path by combining the root path and the given
91
+ # name.
92
+ #
93
+ # @param name [ String ] the name of the directory to be appended to the root path
94
+ # @param root_path [ String, nil ] the root path to use; if nil, the default root path is used
95
+ #
96
+ # @return [ Pathname ] the combined directory path as a Pathname object
97
+ def derive_directory_path(name, root_path)
98
+ root = if path = root_path
99
+ Pathname.new(path)
100
+ else
101
+ Pathname.new(default_root_path)
102
+ end
103
+ root + name
104
+ end
105
+
106
+ # Returns the environment variable path if it is set and not empty.
107
+ #
108
+ # @param env_var [ String ] the name of the environment variable to check
109
+ # @return [ String, nil ] the value of the environment variable if it
110
+ # exists and is not empty, otherwise nil
111
+ def env_var_path(env_var)
112
+ env_var.full? { ENV[it].full? }
113
+ end
114
+
115
+ # Returns the default configuration directory path based on the HOME
116
+ # environment variable.
117
+ #
118
+ # This method constructs and returns a Pathname object pointing to the
119
+ # standard configuration directory location, which is typically
120
+ # $HOME/.config.
121
+ #
122
+ # @return [ Pathname ] the default configuration directory path
123
+ def default_root_path
124
+ Pathname.new(ENV.fetch('HOME') + '.config')
125
+ end
126
+ end
127
+ end