File manipulation utility methods
FileUtils provide very robust apis for dealing with files, this library aims to provide level of abstraction that is much convenient with useful logging capabilities.
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
$ gem install tty-file
- 1. Usage
- 2. Interface
TTY::File.replace_in_file('Gemfile', /gem 'rails'/, "gem 'hanami'")
The following are methods available for creating and manipulating files.
If you wish to silence verbose output use
verbose: false. Similarly if you wish to run action without actually triggering any action use
To check whether a file is a binary file, i.e. image, executable etc. do:
TTY::File.binary?('image.png') # => true
To generate checksum for a file, IO object or String use
checksum_file. By default
MD5 algorithm is used which can be changed by passing second argument.
Among supported message digest algorithms are:
For example, to create digest for string using
TTY::File.checksum_file("Some content\nThe end", 'sha1') # => "289388f187404135e6c15b21460442cf867180dd"
To change file modes use
chmod like so:
There are number of constants available to represent common mode bits such as
TTY::File::O_X and can be used as follows:
TTY::File.chmod('filename.rb', TTY::File::U_R | TTY::File::O_X)
Apart from traditional octal number definition for file permissions, you can use more convenient permission notation accepted by Unix
o specify the user, group, and other parts of the mode bits. The
a symbol is equivalent to
Copies a file content from relative source to relative destination.
TTY::File.copy_file 'Gemfile', 'Gemfile.bak'
If you provide a block then the file content is yielded:
TTY::File.copy_file('Gemfile', 'app/Gemfile') do |content| "https://rubygems.org\n" + content end
If the source file is an
ERB template then you can provide
:context in which the file gets evaluted or if
TTY::File gets included as a module then approprite object context will be used by default. To use
variables = OpenStruct.new variables[:foo] = 'bar' TTY::File.copy_file('templates/application.html.erb', context: variables)
You can also specifie template name surrounding any dynamic variables with
% to be evaluted:
variables = OpenStruct.new variables[:file_name] = 'foo' TTY::File.copy_file('templates/%file_name%.rb', context: variables) # => Creates templates/foo.rb
If the destination is a directory, then copies source inside that directory.
TTY::File.copy_file 'docs/README.md', 'app'
If the destination file already exists, a prompt menu will be displayed to enquire about action:
If you wish to preserve original owner, group, permission and modified time use
TTY::File.copy_file 'docs/README.md', 'app', preserve: true
To create a file at a given destination with the given content use
TTY::File.create_file 'docs/README.md', '## Title header'
On collision with already existing file, a menu is displayed:
You can force to always overwrite file with
:force option or always skip by providing
To recursively copy a directory of files from source to destination location use
copy_directory or its alias 'copy_dir'.
Assuming you have the following directory structure:
# doc/ # subcommands/ # command.rb.erb # README.md # %name%.rb
you can copy
doc folder to
docs by invoking:
TTY::File.copy_directory('doc', 'docs', context: ...)
context needs to respond to
name message and given it returns
foo value the following directory gets created:
# docs/ # subcommands/ # command.rb # README.md # foo.rb
If you only need to copy top level files use option
TTY::File.copy_directory('doc', 'docs', recursive: false)
:exclude option you can instruct the method to ignore any files including the given pattern:
TTY::File.copy_directory('doc', 'docs', exclude: 'subcommands')
To create directory use
create_directory or its alias
create_dir passing as a first argument file path:
or a data structure describing the directory tree including any files with or without content:
tree = 'app' => [ 'README.md', ['Gemfile', "gem 'tty-file'"], 'lib' => [ 'cli.rb', ['file_utils.rb', "require 'tty-file'"] ] 'spec' =>  ]
TTY::File.create_dir(tree) # => # app # app/README.md # app/Gemfile # app/lib # app/lib/cli.rb # app/lib/file_utils.rb # app/spec
As a second argument you can provide a parent directory, otherwise current directory will be assumed:
To compare files line by line in a system independent way use
TTY::File.diff('file_a', 'file_b') # => # @@ -1,4 +1,4 @@ # aaa # -bbb # +xxx # ccc
You can also pass additional arguments such as
Accepted formats are
:reverse_ed, by default the
:unified format is used.
:context_lines specifies how many extra lines around the differing lines to include in the output. By default its 3 lines.
:threshold sets maximum file size in bytes, by default files larger than
10Mb are not processed.
TTY::File.diff('file_a', 'file_b', format: :old) # => # 1,4c1,4 # < aaa # < bbb # < ccc # --- # > aaa # > xxx # > ccc
Equally, you can perform a comparison between a file content and a string content like so:
TTY::File.diff('/path/to/file', 'some long text')
To download a content from a given address and to save at a given relative location do:
If you pass a block then the content will be yielded to allow modification:
TTY::File.download_file("https://gist.github.com/4701967", "doc/README.md") do |content| content.gsub("\n", " ") end
download_file will follow maximum 3 redirects. This can be changed by passing
TTY::File.download_file("https://gist.github.com/4701967", "doc/README.md", limit: 5) # => raises TTY::File::DownloadError
Inject content into a file at a given location
TTY::File.inject_into_file 'filename.rb', after: "Code below this line\n" do "text to add" end
You can also use Regular Expressions in
:before to match file location. The
prepend_to_file allow you to add content at the end and the begging of a file.
Replace content of a file matching condition by calling
TTY::File.replace_in_file 'filename.rb', /matching condition/, 'replacement'
The replacement content can be provided in a block
TTY::File.gsub_file 'filename.rb', /matching condition/ do 'replacement' end
Appends text to a file. You can provide the text as a second argument:
TTY::File.append_to_file('Gemfile', "gem 'tty'")
or inside a block:
TTY::File.append_to_file('Gemfile') do "gem 'tty'" end
Prepends text to a file. You can provide the text as a second argument:
TTY::File.prepend_to_file('Gemfile', "gem 'tty'")
or inside a block:
TTY::File.prepend_to_file('Gemfile') do "gem 'tty'" end
To remove a file do:
You can also pass in
:force to remove file ignoring any errors:
TTY::File.remove_file 'doc/README.md', force: true
After checking out the repo, run
bin/setup to install dependencies. Then, run
rake spec to run the tests. You can also run
bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run
bundle exec rake install. To release a new version, update the version number in
version.rb, and then run
bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the
.gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/tty-file. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.
Copyright (c) 2016-2017 Piotr Murach. See LICENSE for further details.