Extracted `Dry::CLI::Utils::Files` into `dry-files` (#114)

This commit is contained in:
Luca Guidi 2021-04-22 08:56:51 +02:00 committed by GitHub
parent de6f685796
commit 505c4f5ef3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 0 additions and 1524 deletions

View File

@ -1,35 +0,0 @@
---
title: File Utilities
layout: gem-single
name: dry-cli
---
File utilities are a set of useful methods to manipulate files and directories, which must be required manually. [API doc](http://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files)
```ruby
require 'dry/cli/utils/files'
```
## List of implemented commands
- [append](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#append-class_method) - adds a new line at the bottom of the file;
- [cp](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#cp-class_method) - copies source into destination;
- [delete](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#delete-class_method) - deletes given path (file);
- [delete_directory](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#delete_directory-class_method) - deletes given path (directory);
- [directory?](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#directory?-class_method) - checks if path is a directory;
- [exist?](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#exist?-class_method) - checks if `path` exist;
- [inject_line_after](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#inject_line_after-class_method) - inject `contents` in `path` after `target`;
- [inject_line_after_last](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#inject_line_after_last-class_method) - inject `contents` in `path` after last `target`;
- [inject_line_before](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#inject_line_before-class_method) - inject `contents` in `path` before `target`;
- [inject_line_before_last](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#inject_line_before_last-class_method) - inject `contents` in `path` after last `target`;
- [mkdir](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#mkdir-class_method) - creates a directory for the given path;
- [mkdir_p](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#mkdir_p-class_method) - creates a directory for the given path;
- [remove_block](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#remove_block-class_method) - removes `target` block from `path`;
- [remove_line](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#remove_ine-class_method) - removes line from `path`, matching `target`;
- [replace_first_line](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#replace_first_line-class_method) - replace first line in `path` that contains `target` with `replacement`;
- [replace_last_line](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#replace_last_line-class_method) - replace last line in `path` that contains `target` with `replacement`;
- [touch](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#touch-class_method) - creates an empty file for the given path;
- [unshift](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#unshift-class_method) - adds a new line at the top of the file;
- [write](https://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files#write-class_method) - creates a new file or rewrites the contents of an existing file for the given path and content All the intermediate directories are created;
You can find more information in [API doc](http://www.rubydoc.info/gems/dry-cli/Dry/CLI/Utils/Files).

View File

@ -12,7 +12,6 @@ sections:
- variadic-arguments
- commands-with-subcommands-and-params
- callbacks
- file-utilities
---
`dry-cli` is a general-purpose framework for developing Command Line Interface (CLI) applications. It represents commands as objects that can be registered and offers support for arguments, options and forwarding variadic arguments to a sub-command.

View File

@ -1,443 +0,0 @@
# frozen_string_literal: true
require "pathname"
require "fileutils"
module Dry
class CLI
module Utils
# Files utilities
#
# @since 0.3.1
module Files # rubocop:disable Metrics/ModuleLength
# Creates an empty file for the given path.
# All the intermediate directories are created.
# If the path already exists, it doesn't change the contents
#
# @param path [String,Pathname] the path to file
#
# @since 0.3.1
def self.touch(path)
mkdir_p(path)
FileUtils.touch(path)
end
# Creates a new file or rewrites the contents
# of an existing file for the given path and content
# All the intermediate directories are created.
#
# @param path [String,Pathname] the path to file
# @param content [String, Array<String>] the content to write
#
# @since 0.3.1
def self.write(path, *content)
mkdir_p(path)
open(path, ::File::CREAT | ::File::WRONLY | ::File::TRUNC, *content) # rubocop:disable Security/Open - this isn't a call to `::Kernel.open`, but to `self.open`
end
# Copies source into destination.
# All the intermediate directories are created.
# If the destination already exists, it overrides the contents.
#
# @param source [String,Pathname] the path to the source file
# @param destination [String,Pathname] the path to the destination file
#
# @since 0.3.1
def self.cp(source, destination)
mkdir_p(destination)
FileUtils.cp(source, destination)
end
# Creates a directory for the given path.
# It assumes that all the tokens in `path` are meant to be a directory.
# All the intermediate directories are created.
#
# @param path [String,Pathname] the path to directory
#
# @since 0.3.1
#
# @see .mkdir_p
#
# @example
# require "dry/cli/utils/files"
#
# Dry::CLI::Utils::Files.mkdir("path/to/directory")
# # => creates the `path/to/directory` directory
#
# # WRONG this isn't probably what you want, check `.mkdir_p`
# Dry::CLI::Utils::Files.mkdir("path/to/file.rb")
# # => creates the `path/to/file.rb` directory
def self.mkdir(path)
FileUtils.mkdir_p(path)
end
# Creates a directory for the given path.
# It assumes that all the tokens, but the last, in `path` are meant to be
# a directory, whereas the last is meant to be a file.
# All the intermediate directories are created.
#
# @param path [String,Pathname] the path to directory
#
# @since 0.3.1
#
# @see .mkdir
#
# @example
# require "dry/cli/utils/files"
#
# Dry::CLI::Utils::Files.mkdir_p("path/to/file.rb")
# # => creates the `path/to` directory, but NOT `file.rb`
#
# # WRONG it doesn't create the last directory, check `.mkdir`
# Dry::CLI::Utils::Files.mkdir_p("path/to/directory")
# # => creates the `path/to` directory
def self.mkdir_p(path)
Pathname.new(path).dirname.mkpath
end
# Deletes given path (file).
#
# @param path [String,Pathname] the path to file
#
# @raise [Errno::ENOENT] if the path doesn't exist
#
# @since 0.3.1
def self.delete(path)
FileUtils.rm(path)
end
# Deletes given path (directory).
#
# @param path [String,Pathname] the path to file
#
# @raise [Errno::ENOENT] if the path doesn't exist
#
# @since 0.3.1
def self.delete_directory(path)
FileUtils.remove_entry_secure(path)
end
# Adds a new line at the top of the file
#
# @param path [String,Pathname] the path to file
# @param line [String] the line to add
#
# @raise [Errno::ENOENT] if the path doesn't exist
#
# @see .append
#
# @since 0.3.1
def self.unshift(path, line)
content = ::File.readlines(path)
content.unshift("#{line}\n")
write(path, content)
end
# Adds a new line at the bottom of the file
#
# @param path [String,Pathname] the path to file
# @param contents [String] the contents to add
#
# @raise [Errno::ENOENT] if the path doesn't exist
#
# @see .unshift
#
# @since 0.3.1
def self.append(path, contents)
mkdir_p(path)
content = ::File.readlines(path)
content << "\n" unless content.last.end_with?("\n")
content << "#{contents}\n"
write(path, content)
end
# Replace first line in `path` that contains `target` with `replacement`.
#
# @param path [String,Pathname] the path to file
# @param target [String,Regexp] the target to replace
# @param replacement [String] the replacement
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @see .replace_last_line
#
# @since 0.3.1
def self.replace_first_line(path, target, replacement)
content = ::File.readlines(path)
content[index(content, path, target)] = "#{replacement}\n"
write(path, content)
end
# Replace last line in `path` that contains `target` with `replacement`.
#
# @param path [String,Pathname] the path to file
# @param target [String,Regexp] the target to replace
# @param replacement [String] the replacement
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @see .replace_first_line
#
# @since 0.3.1
def self.replace_last_line(path, target, replacement)
content = ::File.readlines(path)
content[-index(content.reverse, path, target) - 1] = "#{replacement}\n"
write(path, content)
end
# Inject `contents` in `path` before `target`.
#
# @param path [String,Pathname] the path to file
# @param target [String,Regexp] the target to replace
# @param contents [String] the contents to inject
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @see .inject_line_after
# @see .inject_line_before_last
# @see .inject_line_after_last
#
# @since 0.3.1
def self.inject_line_before(path, target, contents)
_inject_line_before(path, target, contents, method(:index))
end
# Inject `contents` in `path` after last `target`.
#
# @param path [String,Pathname] the path to file
# @param target [String,Regexp] the target to replace
# @param contents [String] the contents to inject
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @see .inject_line_before
# @see .inject_line_after
# @see .inject_line_after_last
#
# @since 1.3.0
def self.inject_line_before_last(path, target, contents)
_inject_line_before(path, target, contents, method(:rindex))
end
# Inject `contents` in `path` after `target`.
#
# @param path [String,Pathname] the path to file
# @param target [String,Regexp] the target to replace
# @param contents [String] the contents to inject
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @see .inject_line_before
# @see .inject_line_before_last
# @see .inject_line_after_last
#
# @since 0.3.1
def self.inject_line_after(path, target, contents)
_inject_line_after(path, target, contents, method(:index))
end
# Inject `contents` in `path` after last `target`.
#
# @param path [String,Pathname] the path to file
# @param target [String,Regexp] the target to replace
# @param contents [String] the contents to inject
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @see .inject_line_before
# @see .inject_line_after
# @see .inject_line_before_last
# @see .inject_line_after_last
#
# @since 1.3.0
def self.inject_line_after_last(path, target, contents)
_inject_line_after(path, target, contents, method(:rindex))
end
# Removes line from `path`, matching `target`.
#
# @param path [String,Pathname] the path to file
# @param target [String,Regexp] the target to remove
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @since 0.3.1
def self.remove_line(path, target)
content = ::File.readlines(path)
i = index(content, path, target)
content.delete_at(i)
write(path, content)
end
# Removes `target` block from `path`
#
# @param path [String,Pathname] the path to file
# @param target [String] the target block to remove
#
# @raise [Errno::ENOENT] if the path doesn't exist
# @raise [ArgumentError] if `target` cannot be found in `path`
#
# @since 0.3.1
#
# @example
# require "dry/cli/utils/files"
#
# puts File.read("app.rb")
#
# # class App
# # configure do
# # root __dir__
# # end
# # end
#
# Dry::CLI::Utils::Files.remove_block("app.rb", "configure")
#
# puts File.read("app.rb")
#
# # class App
# # end
def self.remove_block(path, target)
content = ::File.readlines(path)
starting = index(content, path, target)
line = content[starting]
size = line[/\A[[:space:]]*/].bytesize
closing = (" " * size) + (target.match?(/{/) ? "}" : "end")
ending = starting + index(content[starting..-1], path, closing)
content.slice!(starting..ending)
write(path, content)
remove_block(path, target) if match?(content, target)
end
# Checks if `path` exist
#
# @param path [String,Pathname] the path to file
#
# @return [TrueClass,FalseClass] the result of the check
#
# @since 0.3.1
#
# @example
# require "dry/cli/utils/files"
#
# Dry::CLI::Utils::Files.exist?(__FILE__) # => true
# Dry::CLI::Utils::Files.exist?(__dir__) # => true
#
# Dry::CLI::Utils::Files.exist?("missing_file") # => false
def self.exist?(path)
File.exist?(path)
end
# Checks if `path` is a directory
#
# @param path [String,Pathname] the path to directory
#
# @return [TrueClass,FalseClass] the result of the check
#
# @since 0.3.1
#
# @example
# require "dry/cli/utils/files"
#
# Dry::CLI::Utils::Files.directory?(__dir__) # => true
# Dry::CLI::Utils::Files.directory?(__FILE__) # => false
#
# Dry::CLI::Utils::Files.directory?("missing_directory") # => false
def self.directory?(path)
File.directory?(path)
end
# private
# @since 0.3.1
# @api private
def self.match?(content, target)
!line_number(content, target).nil?
end
private_class_method :match?
# @since 0.3.1
# @api private
def self.open(path, mode, *content)
::File.open(path, mode) do |file|
file.write(Array(content).flatten.join)
end
end
private_class_method :open
# @since 0.3.1
# @api private
def self.index(content, path, target)
line_number(content, target) ||
raise(ArgumentError, "Cannot find `#{target}' inside `#{path}'.")
end
private_class_method :index
# @since 1.3.0
# @api private
def self.rindex(content, path, target)
line_number(content, target, finder: content.method(:rindex)) ||
raise(ArgumentError, "Cannot find `#{target}' inside `#{path}'.")
end
private_class_method :rindex
# @since 1.3.0
# @api private
def self._inject_line_before(path, target, contents, finder)
content = ::File.readlines(path)
i = finder.call(content, path, target)
content.insert(i, "#{contents}\n")
write(path, content)
end
private_class_method :_inject_line_before
# @since 1.3.0
# @api private
def self._inject_line_after(path, target, contents, finder)
content = ::File.readlines(path)
i = finder.call(content, path, target)
content.insert(i + 1, "#{contents}\n")
write(path, content)
end
private_class_method :_inject_line_after
# @since 0.3.1
# @api private
def self.line_number(content, target, finder: content.method(:index))
finder.call do |l|
case target
when ::String
l.include?(target)
when Regexp
l =~ target
end
end
end
private_class_method :line_number
end
end
end
end

File diff suppressed because it is too large Load Diff