reenrb 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/Gemfile.lock +1 -1
- data/README.md +17 -17
- data/Rakefile +4 -4
- data/bin/reen +78 -13
- data/lib/reenrb/actions/delete.rb +20 -0
- data/lib/reenrb/actions/file_rename.rb +20 -0
- data/lib/reenrb/actions/nothing.rb +17 -0
- data/lib/reenrb/change.rb +119 -0
- data/lib/{changes.rb → reenrb/changes.rb} +19 -9
- data/lib/reenrb/changes_file.rb +42 -0
- data/lib/reenrb/reen.rb +40 -0
- data/lib/reenrb/version.rb +1 -1
- data/lib/reenrb.rb +4 -48
- metadata +9 -5
- data/lib/change.rb +0 -108
- data/lib/changes_file.rb +0 -27
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8f607120ef687c5ace8a02b12e3fb6306abc16aa45b6f906f3e853f995df9a51
|
|
4
|
+
data.tar.gz: 0d4b19262e64584508daf56c0ec2024603ff1a375d134fc000774d1e9233714e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 420f2980c0e6a22ddeb7dbfc9a6abc62a9c8845f19f0902ba975c13996e87c371da9dd003b1d70fbdca9a14ebfeae36e85bd883671bb8b9eec27aa622a1e4fe1
|
|
7
|
+
data.tar.gz: 971cade35548d6fbde58a07ebd3707f34e95da5933e37c37d4eef1f8f108a1714b789aa873ccbcd2331a0214c330bd93a83c4b4f52f295f04130802efff0a726
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
1
8
|
## [Unreleased]
|
|
2
9
|
|
|
10
|
+
## [0.2.1] - 2022-11-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Simplified API for passing block to request/execute
|
|
15
|
+
|
|
3
16
|
## [0.1.0] - 2022-11-05
|
|
4
17
|
|
|
5
|
-
- Initial release
|
|
18
|
+
- Initial release: CLI and API working
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -14,26 +14,29 @@ Or add this line to your Ruby application's Gemfile for programmatic use:
|
|
|
14
14
|
gem 'reenrb'
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
And then execute:
|
|
18
|
-
|
|
19
|
-
$ bundle install
|
|
20
|
-
|
|
21
|
-
Or install it yourself as:
|
|
22
|
-
|
|
23
|
-
$ gem install reenrb
|
|
24
|
-
|
|
25
17
|
## Usage
|
|
26
18
|
|
|
27
19
|
### Command line
|
|
28
20
|
|
|
29
21
|
From command line, run `reen` with file list:
|
|
30
22
|
|
|
31
|
-
reen [
|
|
23
|
+
reen files [options]
|
|
24
|
+
|
|
25
|
+
where `files` are a list of files or wildcard pattern (defaults to `*`; see examples)
|
|
26
|
+
|
|
27
|
+
Options include:
|
|
28
|
+
|
|
29
|
+
- `--help` or `-h`' to see options help
|
|
30
|
+
- `--editor EDITOR` or `-e EDITOR`' to set the editor (defaults to $VISUAL or $EDITOR otherwise) such as `emacs` or `vi`. For Visual Studio Code use `'code -w'` to block until editor finishes.
|
|
31
|
+
- `--review` or `-r` request to review and confirm changes
|
|
32
32
|
|
|
33
33
|
Examples:
|
|
34
34
|
|
|
35
|
-
reen *
|
|
36
|
-
reen
|
|
35
|
+
reen # reen all files (*)
|
|
36
|
+
reen **/* # reen all files in all subfolders
|
|
37
|
+
reen myfolder/**/*.mov # reen all mov files in subfolders
|
|
38
|
+
reen *.md --editor vi # reen all markdown files using vi
|
|
39
|
+
reen --editor 'code -w' # reen all markdown files using vscode
|
|
37
40
|
|
|
38
41
|
### Ruby application
|
|
39
42
|
|
|
@@ -45,13 +48,10 @@ require 'reenrb'
|
|
|
45
48
|
glob = Dir.glob("*")
|
|
46
49
|
reen = Reenrb::Reen.new(editor: nil)
|
|
47
50
|
|
|
48
|
-
reen.execute(glob) do |
|
|
49
|
-
lines = File.read(tmpfile_path).split("\n")
|
|
50
|
-
|
|
51
|
+
reen.execute(glob) do |file|
|
|
51
52
|
# Rename LICENSE.txt -> LICENSE.md
|
|
52
|
-
index =
|
|
53
|
-
|
|
54
|
-
File.write(tmpfile_path, lines.join("\n"))
|
|
53
|
+
index = file.list.index { |l| l.include? "LICENSE.txt" }
|
|
54
|
+
file.list[index] = file.list[index].gsub("txt", "md")
|
|
55
55
|
end
|
|
56
56
|
```
|
|
57
57
|
|
data/Rakefile
CHANGED
|
@@ -4,7 +4,7 @@ require "bundler/gem_tasks"
|
|
|
4
4
|
require "rake/testtask"
|
|
5
5
|
|
|
6
6
|
Rake::TestTask.new(:spec) do |t|
|
|
7
|
-
t.libs << "
|
|
7
|
+
t.libs << "spec"
|
|
8
8
|
t.libs << "lib"
|
|
9
9
|
t.test_files = FileList["spec/**/spec_*.rb"]
|
|
10
10
|
end
|
|
@@ -14,18 +14,18 @@ task :respec do
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
namespace :example do
|
|
17
|
-
task :
|
|
17
|
+
task :helper do
|
|
18
18
|
require_relative "spec/fixture_helper"
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
desc "Recreates the example fixture folder"
|
|
22
|
-
task :recreate => :
|
|
22
|
+
task :recreate => :helper do
|
|
23
23
|
FixtureHelper.recreate_example_dir
|
|
24
24
|
puts "Example fixture recreated"
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
desc "Deletes the example fixture folder"
|
|
28
|
-
task :remove => :
|
|
28
|
+
task :remove => :helper do
|
|
29
29
|
FixtureHelper.remove_example_dirs
|
|
30
30
|
puts "Example fixture removed"
|
|
31
31
|
end
|
data/bin/reen
CHANGED
|
@@ -1,22 +1,87 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
EDITOR_MSG = "Editor not set in $EDITOR or $VISUAL -- please set one of those environment variables"
|
|
5
|
-
|
|
6
|
-
def exit_with_error(err)
|
|
7
|
-
puts err
|
|
8
|
-
exit(false)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
4
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
|
12
5
|
require "reenrb"
|
|
6
|
+
require "optparse"
|
|
7
|
+
|
|
8
|
+
# Reen command line application
|
|
9
|
+
class ReenCLI
|
|
10
|
+
EDITOR_MSG = "Editor not set in $EDITOR or $VISUAL -- please set one of those environment variables"
|
|
11
|
+
Options = Struct.new(:editor, :review) do
|
|
12
|
+
def initialize(editor: nil, review: false)
|
|
13
|
+
editor ||= ENV["VISUAL"] || ENV["EDITOR"] # rubocop:disable Style/FetchEnvVar
|
|
14
|
+
super(editor, review)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_reader :options, :files
|
|
19
|
+
|
|
20
|
+
def initialize(args)
|
|
21
|
+
@options = Options.new
|
|
22
|
+
optparse = OptionParser.new { |parser| setup_options(parser) }
|
|
23
|
+
optparse.parse!(args, into: @options)
|
|
24
|
+
|
|
25
|
+
exit_with_msg(EDITOR_MSG) unless options.editor
|
|
26
|
+
|
|
27
|
+
@files = args.empty? ? Dir.glob("*") : args
|
|
28
|
+
rescue OptionParser::InvalidOption => e
|
|
29
|
+
puts "#{e.message}\n\n"
|
|
30
|
+
exit_with_msg(optparse)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def setup_options(parser)
|
|
34
|
+
parser.banner = "Usage: reen files [options]"
|
|
35
|
+
parser.version = Reenrb::VERSION
|
|
13
36
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
exit_with_error(EDITOR_MSG) if editor.empty?
|
|
37
|
+
parser.on("-e", "--editor EDITOR", "Specify EDITOR to use")
|
|
38
|
+
parser.on("-r", "--review", "Require review and confirmation of changes")
|
|
17
39
|
|
|
18
|
-
|
|
40
|
+
parser.on("-h", "--help", "Show help for options") do
|
|
41
|
+
exit_with_msg(parser)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
19
44
|
|
|
20
|
-
|
|
45
|
+
def exit_with_msg(message)
|
|
46
|
+
puts message
|
|
47
|
+
exit(false)
|
|
48
|
+
end
|
|
21
49
|
|
|
22
|
-
|
|
50
|
+
def review_changes
|
|
51
|
+
puts
|
|
52
|
+
puts @requests.change_requested.summarize
|
|
53
|
+
print "\nContinue? (y/n) "
|
|
54
|
+
confirmation = %w[y yes].include?($stdin.gets.chomp.downcase)
|
|
55
|
+
exit_with_msg("Nothing changed") unless confirmation
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def check_inputs
|
|
59
|
+
@files = files.empty? ? Dir.glob("*") : files
|
|
60
|
+
exit_with_msg(EDITOR_MSG) unless options.editor
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def user_review?
|
|
64
|
+
@options.review && @requests.changes_requested?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def call
|
|
68
|
+
@requests = Reenrb::Reen.new(editor: options.editor).request(files)
|
|
69
|
+
review_changes if user_review?
|
|
70
|
+
|
|
71
|
+
changes = @requests
|
|
72
|
+
.execute_all
|
|
73
|
+
.change_requested
|
|
74
|
+
|
|
75
|
+
if user_review? && changes.all_executed?
|
|
76
|
+
puts "Changes made"
|
|
77
|
+
else
|
|
78
|
+
puts changes.summarize
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
ReenCLI.new(ARGV).call
|
|
85
|
+
rescue Reenrb::Error => e
|
|
86
|
+
puts "#{e.message}\n"
|
|
87
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reenrb
|
|
4
|
+
module Actions
|
|
5
|
+
# Deletes a file
|
|
6
|
+
class FileDelete
|
|
7
|
+
def initialize(old_name, new_name)
|
|
8
|
+
@old_name = old_name
|
|
9
|
+
@new_name = new_name
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
File.delete(@old_name)
|
|
14
|
+
nil
|
|
15
|
+
rescue Errno::ENOENT
|
|
16
|
+
"Could not delete"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reenrb
|
|
4
|
+
module Actions
|
|
5
|
+
# Renames files
|
|
6
|
+
class FileRename
|
|
7
|
+
def initialize(old_name, new_name)
|
|
8
|
+
@old_name = old_name
|
|
9
|
+
@new_name = new_name
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
File.rename(@old_name, @new_name)
|
|
14
|
+
nil
|
|
15
|
+
rescue Errno::ENOENT
|
|
16
|
+
"No such target file or directory"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reenrb
|
|
4
|
+
module Actions
|
|
5
|
+
# Does nothing to items
|
|
6
|
+
class DoNothing
|
|
7
|
+
def initialize(old_name, new_name)
|
|
8
|
+
@old_name = old_name
|
|
9
|
+
@new_name = new_name
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "actions/delete"
|
|
4
|
+
require_relative "actions/file_rename"
|
|
5
|
+
require_relative "actions/nothing"
|
|
6
|
+
|
|
7
|
+
module Reenrb
|
|
8
|
+
# Change to an orignal file
|
|
9
|
+
class Change
|
|
10
|
+
attr_reader :original, :requested, :change, :status
|
|
11
|
+
|
|
12
|
+
module STATUS
|
|
13
|
+
ACCEPTED = :accepted
|
|
14
|
+
REJECTED = :rejected
|
|
15
|
+
EXECUTED = :executed
|
|
16
|
+
FAILED = :failed
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module CHANGE
|
|
20
|
+
NONE = :none
|
|
21
|
+
DELETE = :delete
|
|
22
|
+
RENAME = :rename
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
ACTION_HANDLER = {
|
|
26
|
+
CHANGE::NONE => Actions::DoNothing,
|
|
27
|
+
CHANGE::DELETE => Actions::FileDelete,
|
|
28
|
+
CHANGE::RENAME => Actions::FileRename
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
CHANGES_DESC = {
|
|
32
|
+
CHANGE::NONE => "Nothing",
|
|
33
|
+
CHANGE::DELETE => "Deleting",
|
|
34
|
+
CHANGE::RENAME => "Renaming"
|
|
35
|
+
}.freeze
|
|
36
|
+
|
|
37
|
+
def initialize(original, requested)
|
|
38
|
+
@original = original
|
|
39
|
+
@requested = requested
|
|
40
|
+
@change = compare
|
|
41
|
+
consider
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def compare
|
|
45
|
+
if original == requested
|
|
46
|
+
CHANGE::NONE
|
|
47
|
+
elsif requested.start_with? "-"
|
|
48
|
+
CHANGE::DELETE
|
|
49
|
+
else
|
|
50
|
+
CHANGE::RENAME
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def consider
|
|
55
|
+
if request_full_dir? && request_delete?
|
|
56
|
+
@status = STATUS::REJECTED
|
|
57
|
+
@reason = "Directories with files cannot be changed"
|
|
58
|
+
else
|
|
59
|
+
@status = STATUS::ACCEPTED
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def execute
|
|
64
|
+
return(self) if not_accepted?
|
|
65
|
+
|
|
66
|
+
@status = STATUS::EXECUTED
|
|
67
|
+
error = ACTION_HANDLER[@change].new(original, requested).call
|
|
68
|
+
|
|
69
|
+
if error
|
|
70
|
+
@status = STATUS::FAILED
|
|
71
|
+
@reason = error
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Predicates
|
|
78
|
+
|
|
79
|
+
def request_dir? = Dir.exist?(@original)
|
|
80
|
+
|
|
81
|
+
def request_nothing? = @change == CHANGE::NONE
|
|
82
|
+
|
|
83
|
+
def request_rename? = @change == CHANGE::RENAME
|
|
84
|
+
|
|
85
|
+
def request_delete? = @change == CHANGE::DELETE
|
|
86
|
+
|
|
87
|
+
def request_empty_dir? = Dir.empty?(@original)
|
|
88
|
+
|
|
89
|
+
def accepted? = @status == STATUS::ACCEPTED
|
|
90
|
+
|
|
91
|
+
def not_accepted? = !accepted?
|
|
92
|
+
|
|
93
|
+
def executed? = @status == STATUS::EXECUTED
|
|
94
|
+
|
|
95
|
+
def rejected? = @status == STATUS::REJECTED
|
|
96
|
+
|
|
97
|
+
def failed? = @status == STATUS::FAILED
|
|
98
|
+
|
|
99
|
+
def request_full_dir? = request_dir? && !request_empty_dir?
|
|
100
|
+
|
|
101
|
+
def executed_or_rejected? = %i[executed rejected].include?(@status)
|
|
102
|
+
|
|
103
|
+
# Decoration
|
|
104
|
+
|
|
105
|
+
def to_s
|
|
106
|
+
file_desc =
|
|
107
|
+
case @change
|
|
108
|
+
when CHANGE::RENAME
|
|
109
|
+
"#{@original} -> #{@requested}"
|
|
110
|
+
else
|
|
111
|
+
@original
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
reason_desc = rejected? || failed? ? " (failed: #{@reason})" : ""
|
|
115
|
+
|
|
116
|
+
"#{CHANGES_DESC[@change]}: #{file_desc}#{reason_desc}"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "change"
|
|
4
|
+
|
|
3
5
|
module Reenrb
|
|
4
6
|
# Change to an orignal file
|
|
5
7
|
class Changes
|
|
@@ -9,35 +11,43 @@ module Reenrb
|
|
|
9
11
|
@list = changes_list
|
|
10
12
|
end
|
|
11
13
|
|
|
12
|
-
def
|
|
14
|
+
def execute_all
|
|
13
15
|
@list.map(&:execute)
|
|
14
16
|
self
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
#
|
|
19
|
+
# Queries
|
|
18
20
|
|
|
19
21
|
def rename_requested
|
|
20
|
-
Changes.new(@list.select
|
|
22
|
+
Changes.new(@list.select(&:request_rename?))
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
def delete_requested
|
|
24
|
-
Changes.new(@list.select
|
|
26
|
+
Changes.new(@list.select(&:request_delete?))
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def change_requested
|
|
28
|
-
Changes.new(@list.reject
|
|
30
|
+
Changes.new(@list.reject(&:request_nothing?))
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
def rejected
|
|
32
|
-
Changes.new(@list.select
|
|
34
|
+
Changes.new(@list.select(&:rejected?))
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def accepted
|
|
36
|
-
Changes.new(@list.select
|
|
38
|
+
Changes.new(@list.select(&:accepted?))
|
|
37
39
|
end
|
|
38
40
|
|
|
39
41
|
def executed
|
|
40
|
-
Changes.new(@list.select
|
|
42
|
+
Changes.new(@list.select(&:executed?))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def failed
|
|
46
|
+
Changes.new(@list.select(&:failed?))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def any?
|
|
50
|
+
!@list.empty?
|
|
41
51
|
end
|
|
42
52
|
|
|
43
53
|
def count
|
|
@@ -55,7 +65,7 @@ module Reenrb
|
|
|
55
65
|
# Predicates
|
|
56
66
|
|
|
57
67
|
def no_changes_requested?
|
|
58
|
-
list.map(&:change).all?
|
|
68
|
+
list.map(&:change).all? Change::CHANGE::NONE
|
|
59
69
|
end
|
|
60
70
|
|
|
61
71
|
def changes_requested?
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tempfile"
|
|
4
|
+
|
|
5
|
+
module Reenrb
|
|
6
|
+
# Manages a temporary file with requested changes
|
|
7
|
+
class ChangesFile
|
|
8
|
+
INSTRUCTIONS = <<~COMMENTS
|
|
9
|
+
# Edit the names of any files/folders to rename or move them
|
|
10
|
+
# - Put a preceeding dash to delete a file or empty folder
|
|
11
|
+
|
|
12
|
+
COMMENTS
|
|
13
|
+
|
|
14
|
+
attr_accessor :list
|
|
15
|
+
|
|
16
|
+
def initialize(requested_list)
|
|
17
|
+
@list_file = Tempfile.new("reenrb-")
|
|
18
|
+
@list_file.write(INSTRUCTIONS)
|
|
19
|
+
@list_file.write(requested_list.join("\n"))
|
|
20
|
+
@list_file.close
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def allow_changes(editor, &block)
|
|
24
|
+
await_editor(editor) if editor
|
|
25
|
+
@list = File.read(path).split("\n").map(&:strip)
|
|
26
|
+
.reject { |line| line.start_with?("#") || line.empty? }
|
|
27
|
+
|
|
28
|
+
block&.call(self)
|
|
29
|
+
@list
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def path
|
|
35
|
+
@list_file.path
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def await_editor(editor)
|
|
39
|
+
`#{editor} #{@list_file.path}`
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/reenrb/reen.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reenrb
|
|
4
|
+
# Renames pattern of files with given editor
|
|
5
|
+
# Examples:
|
|
6
|
+
# Reenrb::Reen.new(editor: "code -w").call("spec/fixtures/example/*")
|
|
7
|
+
# Reenrb::Reen.new(editor: nil).call("spec/fixtures/example/*") { ... }
|
|
8
|
+
class Reen
|
|
9
|
+
DEL_ERROR = "Do not remove any file/folder names (no changes made)"
|
|
10
|
+
|
|
11
|
+
attr_reader :changes
|
|
12
|
+
|
|
13
|
+
def initialize(editor: "emacs", options: {})
|
|
14
|
+
@editor = editor
|
|
15
|
+
@options = options
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def request(original_list, &block)
|
|
19
|
+
changed_list = ChangesFile.new(original_list).allow_changes(@editor, &block)
|
|
20
|
+
|
|
21
|
+
raise(Error, DEL_ERROR) if changed_list.size != original_list.size
|
|
22
|
+
|
|
23
|
+
@changes = compare_lists(original_list, changed_list)
|
|
24
|
+
.then { |change_array| Changes.new(change_array) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def execute(original_list, &block)
|
|
28
|
+
@changes ||= request(original_list, &block)
|
|
29
|
+
@changes = @changes.execute_all
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def compare_lists(original_list, changed_list)
|
|
35
|
+
original_list.zip(changed_list).map do |original, revised|
|
|
36
|
+
Change.new(original, revised)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/reenrb/version.rb
CHANGED
data/lib/reenrb.rb
CHANGED
|
@@ -1,55 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "reenrb/version"
|
|
4
|
-
require_relative "changes_file"
|
|
5
|
-
require_relative "change"
|
|
6
|
-
require_relative "changes"
|
|
4
|
+
require_relative "reenrb/changes_file"
|
|
5
|
+
require_relative "reenrb/change"
|
|
6
|
+
require_relative "reenrb/changes"
|
|
7
|
+
require_relative "reenrb/reen"
|
|
7
8
|
|
|
8
9
|
module Reenrb
|
|
9
10
|
class Error < StandardError; end
|
|
10
|
-
|
|
11
|
-
# Renames pattern of files with given editor
|
|
12
|
-
# Examples:
|
|
13
|
-
# Reenrb::Reen.new(editor: "code -w").call("spec/fixtures/example/*")
|
|
14
|
-
# Reenrb::Reen.new(editor: nil).call("spec/fixtures/example/*") { ... }
|
|
15
|
-
class Reen
|
|
16
|
-
DEL_ERROR = "Do not delete any file/folder names"
|
|
17
|
-
|
|
18
|
-
attr_reader :changes
|
|
19
|
-
|
|
20
|
-
def initialize(editor: "emacs", options: {})
|
|
21
|
-
@editor = editor
|
|
22
|
-
@options = options
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def request(original_list, &block) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
26
|
-
changed_list = ChangesFile.new(original_list).allow_changes do |file|
|
|
27
|
-
file.blocking_edit(@editor) if @editor
|
|
28
|
-
|
|
29
|
-
if block
|
|
30
|
-
lines = File.read(file.path).split("\n")
|
|
31
|
-
new_lines = block.call(lines) || lines
|
|
32
|
-
File.write(file.path, new_lines.join("\n"))
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
raise(Error, DEL_ERROR) if changed_list.size != original_list.size
|
|
37
|
-
|
|
38
|
-
@changes = compare_lists(original_list, changed_list)
|
|
39
|
-
.then { |change_array| Changes.new(change_array) }
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def execute(original_list, &block)
|
|
43
|
-
@changes ||= request(original_list, &block)
|
|
44
|
-
@changes = @changes.execute!
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
private
|
|
48
|
-
|
|
49
|
-
def compare_lists(original_list, changed_list)
|
|
50
|
-
original_list.zip(changed_list).map do |original, revised|
|
|
51
|
-
Change.new(original, revised)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
11
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: reenrb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Soumya Ray
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-11-
|
|
11
|
+
date: 2022-11-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -110,10 +110,14 @@ files:
|
|
|
110
110
|
- README.md
|
|
111
111
|
- Rakefile
|
|
112
112
|
- bin/reen
|
|
113
|
-
- lib/change.rb
|
|
114
|
-
- lib/changes.rb
|
|
115
|
-
- lib/changes_file.rb
|
|
116
113
|
- lib/reenrb.rb
|
|
114
|
+
- lib/reenrb/actions/delete.rb
|
|
115
|
+
- lib/reenrb/actions/file_rename.rb
|
|
116
|
+
- lib/reenrb/actions/nothing.rb
|
|
117
|
+
- lib/reenrb/change.rb
|
|
118
|
+
- lib/reenrb/changes.rb
|
|
119
|
+
- lib/reenrb/changes_file.rb
|
|
120
|
+
- lib/reenrb/reen.rb
|
|
117
121
|
- lib/reenrb/version.rb
|
|
118
122
|
- reenrb.gemspec
|
|
119
123
|
- sig/reenrb.rbs
|
data/lib/change.rb
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Reenrb
|
|
4
|
-
# Change to an orignal file
|
|
5
|
-
class Change
|
|
6
|
-
attr_reader :original, :requested, :change, :status
|
|
7
|
-
|
|
8
|
-
module STATUS
|
|
9
|
-
ACCEPTED = :accepted
|
|
10
|
-
REJECTED = :rejected
|
|
11
|
-
EXECUTED = :executed
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
module CHANGE
|
|
15
|
-
NONE = :none
|
|
16
|
-
DELETE = :delete
|
|
17
|
-
RENAME = :rename
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
CHANGES_DESC = {
|
|
21
|
-
none: "Nothing",
|
|
22
|
-
delete: "Deleting",
|
|
23
|
-
rename: "Renaming"
|
|
24
|
-
}.freeze
|
|
25
|
-
|
|
26
|
-
def initialize(original, requested)
|
|
27
|
-
@original = original
|
|
28
|
-
@requested = requested
|
|
29
|
-
@change = compare
|
|
30
|
-
consider
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def compare
|
|
34
|
-
if original == requested
|
|
35
|
-
:none
|
|
36
|
-
elsif requested.start_with? "-"
|
|
37
|
-
:delete
|
|
38
|
-
else
|
|
39
|
-
:rename
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def consider
|
|
44
|
-
if request_full_directory? && request_delete?
|
|
45
|
-
@status = STATUS::REJECTED
|
|
46
|
-
@reason = "Directories with files cannot be changed"
|
|
47
|
-
else
|
|
48
|
-
@status = STATUS::ACCEPTED
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def execute
|
|
53
|
-
return(self) if executed_or_rejected?
|
|
54
|
-
|
|
55
|
-
case @change
|
|
56
|
-
when :rename
|
|
57
|
-
File.rename(@original, @requested)
|
|
58
|
-
when :delete
|
|
59
|
-
File.delete(@original)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
@status = STATUS::EXECUTED
|
|
63
|
-
self
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Inspection
|
|
67
|
-
|
|
68
|
-
def request_directory?
|
|
69
|
-
Dir.exist? @original
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def request_delete?
|
|
73
|
-
@change == CHANGE::DELETE
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def request_empty_directory?
|
|
77
|
-
Dir.empty? @original
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def executed?
|
|
81
|
-
@status == STATUS::EXECUTED
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def request_full_directory?
|
|
85
|
-
request_directory? && !request_empty_directory?
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def executed_or_rejected?
|
|
89
|
-
%i[executed rejected].include? @status
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Decoration
|
|
93
|
-
|
|
94
|
-
def to_s
|
|
95
|
-
file_desc =
|
|
96
|
-
case @change
|
|
97
|
-
when :rename
|
|
98
|
-
"#{@original} -> #{@requested}"
|
|
99
|
-
else
|
|
100
|
-
@original
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
reason_desc = @status == STATUS::REJECTED ? " (failed: #{@reason})" : ""
|
|
104
|
-
|
|
105
|
-
"#{CHANGES_DESC[@change]}: #{file_desc}#{reason_desc}"
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
data/lib/changes_file.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "tempfile"
|
|
4
|
-
|
|
5
|
-
module Reenrb
|
|
6
|
-
# Manages a temporary file with requested changes
|
|
7
|
-
class ChangesFile
|
|
8
|
-
def initialize(requested_list)
|
|
9
|
-
@list_file = Tempfile.new("reenrb-")
|
|
10
|
-
@list_file.write(requested_list.join("\n"))
|
|
11
|
-
@list_file.close
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def path
|
|
15
|
-
@list_file.path
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def allow_changes(&block)
|
|
19
|
-
block.call(self)
|
|
20
|
-
File.read(path).split("\n")
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def blocking_edit(editor)
|
|
24
|
-
`#{editor} #{@list_file.path}`
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|