Created
January 25, 2026 19:10
-
-
Save Snarp/fb4c14e31d5324bade8a6af25370bfce to your computer and use it in GitHub Desktop.
Monkeypatch / core extension adding some functionality to Pathname
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SOURCES: | |
| # - https://docs.ruby-lang.org/en/master/Pathname.html | |
| # - https://github.com/ruby/pathname | |
| class Pathname | |
| # Returns the basename with the extension removed: if #basename is "foo.bar", returns "foo". | |
| # | |
| # @return [String] | |
| def stemname | |
| basename.chomp(extname) | |
| end | |
| def sub_parts(dir: nil, base: nil, stem: nil, ext: nil) | |
| dir ||= dirname | |
| if !base | |
| if stem || ext | |
| stem ||= stemname_full | |
| ext ||= extname_full | |
| base = stem + ext | |
| else | |
| base = basename_full | |
| end | |
| end | |
| self.class.new File.join(dir, base) | |
| end | |
| # Return a pathname with `repl` replacing the dirname. If self has no dirname part, `repl` is prepended. | |
| # | |
| # @param [String] repl new dirname | |
| # @return [Pathname] | |
| def sub_dir(repl) | |
| self.class.new File.join(repl, basename_full) | |
| end | |
| # Return a pathname with `repl` replacing the basename. If self has no basename part, `repl` is appended. | |
| # | |
| # @param [String] repl new basename | |
| # @return [Pathname] | |
| def sub_base(repl) | |
| self.class.new(@path.chomp(basename_full.to_s) + repl) | |
| end | |
| # Return a pathname with `repl` replacing the stemname portion of basename. If self has no basename part, `repl` is appended. | |
| # | |
| # @param [String] repl new stemname | |
| # @return [Pathname] | |
| def sub_stem(repl) | |
| self.class.new(@path.chomp(basename_full.to_s) + repl + extname_full) | |
| end | |
| # Based on source for #sub_ext; corrects for potential issues with File.extname's handling of constructions like `foo.bar:stream` on NTFS. | |
| # | |
| # @return [String] | |
| def extname_full | |
| ext = File.extname(@path) | |
| unless @path.end_with?(ext) | |
| ext = @path[@path.rindex(ext)..] | |
| end | |
| return ext | |
| end | |
| # Based on source for #sub_ext; corrects for potential issues with File.extname's handling of constructions like `foo.bar:stream` on NTFS. | |
| # | |
| # @return [String] | |
| def basename_full | |
| base = File.basename(@path) | |
| unless @path.end_with?(base) | |
| base = @path[@path.rindex(base)..] | |
| end | |
| return base | |
| end | |
| # Based on source for #sub_ext; corrects for potential issues with File.extname's handling of constructions like `foo.bar:stream` on NTFS. | |
| # | |
| # @return [String] | |
| def stemname_full | |
| return basename_full.chomp(extname_full) | |
| end | |
| # # File pathname_builtin.rb, line 292 | |
| # def sub_ext(repl) | |
| # ext = File.extname(@path) | |
| # | |
| # # File.extname("foo.bar:stream") returns ".bar" on NTFS and not ".bar:stream" | |
| # # (see ruby_enc_find_extname()). | |
| # # The behavior of Pathname#sub_ext is to replace everything | |
| # # from the start of the extname until the end of the path with repl. | |
| # unless @path.end_with?(ext) | |
| # ext = @path[@path.rindex(ext)..] | |
| # end | |
| # | |
| # self.class.new(@path.chomp(ext) + repl) | |
| # end | |
| def chomp(*args) | |
| self.class.new to_s.chomp(*args) | |
| end | |
| def slice(*args) | |
| self.class.new to_s.slice(*args) | |
| end | |
| def length | |
| to_s.length | |
| end | |
| def to_h | |
| { | |
| dirname: dirname, | |
| stemname: stemname, | |
| extname: extname, | |
| stat: stat, | |
| } | |
| end | |
| def to_a | |
| dirname.split + [stemname, extname] | |
| end | |
| class << self | |
| def build(dir: nil, base: nil, stem: nil, ext: nil) | |
| if !base && stem | |
| base = stem + ext.to_s | |
| end | |
| if dir.is_a?(Array) | |
| dir = File.join *dir.flatten | |
| end | |
| if dir && base | |
| return self.new(File.join dir, base) | |
| elsif dir || base | |
| return self.new(dir || base) | |
| else | |
| raise ArgumentError.new("Invalid args: #{{dir: dir, base: base, stem: stem, ext: ext}}") | |
| end | |
| end | |
| end # class << self | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment