Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -i/--in-place option #116

Merged
merged 5 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ Style/StderrPuts:
Enabled: false

Style/GlobalVars:
Exclude:
- mrblib/rf/container.rb
AllowedVariables: [ $output, $F ]

Style/SpecialGlobalVars:
Exclude:
Expand Down
10 changes: 10 additions & 0 deletions build_config.rb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ builds:
branch: master
commit: bb773da39517f3ae7232538c7e9c476d45f3d9b7
version: 0.0.0
https://github.com/mrbgems/mruby-tempfile.git:
url: https://github.com/mrbgems/mruby-tempfile.git
branch: master
commit: 48073012c932f540dc3773b2dc6b079caf71a70d
version: 0.0.0
linux-amd64:
https://github.com/mattn/mruby-json.git:
url: https://github.com/mattn/mruby-json.git
Expand Down Expand Up @@ -224,3 +229,8 @@ builds:
branch: master
commit: bb773da39517f3ae7232538c7e9c476d45f3d9b7
version: 0.0.0
https://github.com/mrbgems/mruby-tempfile.git:
url: https://github.com/mrbgems/mruby-tempfile.git
branch: master
commit: 48073012c932f540dc3773b2dc6b079caf71a70d
version: 0.0.0
2 changes: 1 addition & 1 deletion mrbgem.rake
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ MRuby::Gem::Specification.new('rf') do |spec|
spec.add_dependency 'mruby-binding', core: 'mruby-binding'

%w[
mruby-file-stat
mruby-json
mruby-optparse
].each do |mgem|
spec.add_dependency mgem, mgem:
end
spec.add_dependency 'mruby-yaml', github: 'buty4649/mruby-yaml'
spec.add_dependency 'mruby-onig-regexp', github: 'buty4649/mruby-onig-regexp'
spec.add_dependency 'mruby-tempfile', github: 'mrbgems/mruby-tempfile'
end
9 changes: 9 additions & 0 deletions mrblib/core_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ def try_to_f
nil
end
end

class Tempfile
def close(real: false)
super()
delete if real

nil
end
end
1 change: 1 addition & 0 deletions mrblib/rf/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def run(argv) # rubocop:disable Metrics/AbcSize
filter: config.filter,
grep_mode: config.grep_mode,
inlude_filename: config.inlude_filename,
in_place: config.in_place,
slurp: config.slurp,
quiet: config.quiet,
recursive: config.recursive,
Expand Down
8 changes: 7 additions & 1 deletion mrblib/rf/config.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Rf
class Config
attr_accessor :command, :files, :filter, :grep_mode, :inlude_filename,
attr_accessor :command, :files, :filter, :grep_mode, :inlude_filename, :in_place,
:slurp, :script_file, :quiet, :recursive, :with_filename

def self.parse(argv)
Expand Down Expand Up @@ -101,6 +101,9 @@ def global_options # rubocop:disable Metrics/AbcSize
opt.on('-g', '--grep', 'Interpret command as a regex pattern for searching (like grep)') do
@config.grep_mode = true
end
opt.on('-i[SUFFIX]', '--in-place[=SUFFIX]', 'edit files in place (makes backup if SUFFIX supplied)') do |v|
@config.in_place = v || ''
end
opt.on('-n', '--quiet', 'suppress automatic printing') { @config.quiet = true }
opt.on('-s', '--slurp', 'read all reacords into an array') { @config.slurp = true }
opt.on('--help', 'show this message') { print_help_and_exit }
Expand Down Expand Up @@ -128,6 +131,9 @@ def parse(argv)
@config.command = parameter.shift
end
@config.files = parameter unless parameter.empty?

raise ConflictOptions, %w[-R -i] if @config.recursive && @config.in_place

@config
end

Expand Down
6 changes: 4 additions & 2 deletions mrblib/rf/container.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
$output = $stdout

module Rf
class Container
attr_accessor :filename, :with_filename
Expand Down Expand Up @@ -35,8 +37,8 @@ def hash?
end

def puts(*)
$stdout.write("#{filename}: ") if with_filename && filename
$stdout.puts(*)
$output.write("#{filename}: ") if with_filename && filename
$output.puts(*)
end

%i[gsub gsub! sub sub! tr tr!].each do |sym|
Expand Down
13 changes: 13 additions & 0 deletions mrblib/rf/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,18 @@ def initialize(path)
end
end

class ConflictOptions < Error
def initialize(options)
opts = options.is_a?(Array) ? options.join(', ') : options
super "#{opts}: conflict options"
end
end

class NotRegularFile < Error
def initialize(path)
super "#{path}: not a regular file"
end
end

class SyntaxError < Error; end
end
40 changes: 33 additions & 7 deletions mrblib/rf/runner.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
module Rf
class Runner
class Runner # rubocop:disable Metrics/ClassLength
def self.run(...)
new(...).run
end

attr_reader :container, :bind, :command, :filter, :grep_mode, :inputs, :with_filename
attr_reader :container, :bind, :command, :filter, :grep_mode, :inputs, :in_place, :with_filename

# @param [Hash<String>] opts
# :command => String
# :files => Array<String>
# :filter => Rf::Filter
# :grep_mode => Boolean
# :inlude_filename => String or nil
# :in_place => String or nil
# :slurp => Boolean
# :recursive => Boolean
# :quiet => Boolean
Expand All @@ -20,6 +21,7 @@ def initialize(opts) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplex
@command = opts[:command]
@filter = opts[:filter]
@grep_mode = opts[:grep_mode]
@in_place = opts[:in_place]
@slurp = opts[:slurp]
@quiet = opts[:quiet]

Expand Down Expand Up @@ -56,7 +58,15 @@ def run # rubocop:disable Metrics/AbcSize

inputs.each do |filename|
@container.filename = filename
records = Record.read(filter.new(self.open(filename)))
input = read_open(filename)

if in_place
write_file = write_open(filename, in_place)
$output = write_file
tempfile = write_file if in_place.empty?
end

records = Record.read(filter.new(input))
if slurp?
r = records.to_a
do_action(r, 1, r)
Expand All @@ -67,14 +77,18 @@ def run # rubocop:disable Metrics/AbcSize
end
end
post_action

next unless tempfile

tempfile.close
input.close
File.rename(tempfile.path, filename)
end
end

def open(file)
def read_open(file)
return $stdin if file == '-'

stat = File::Stat.new(file)
raise IsDirectory, file if stat.directory?
raise IsDirectory, file if File.directory?(file)

File.open(file)
rescue Errno::ENOENT
Expand All @@ -83,6 +97,18 @@ def open(file)
raise PermissionDenied, file
end

def write_open(file, in_place)
if in_place.empty?
dir = File.dirname(file)
Tempfile.new('.rf', dir)
else
raise NotFound, file unless File.exist?(file)
raise NotRegularFile, file unless File.file?(file)

File.open("#{file}#{in_place}", 'w')
end
end

def split(val)
case val
when Array
Expand Down
10 changes: 10 additions & 0 deletions spec/error_message_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,14 @@
it { expect(last_command_started).not_to be_successfully_executed }
it { expect(last_command_started).to have_output_on_stderr include_output_string error_message }
end

context 'when conflict options' do
let(:input) { "test\n" }
let(:error_message) { 'Error: -R, -i: conflict options' }

before { run_rf('-R -i _', input) }

it { expect(last_command_started).not_to be_successfully_executed }
it { expect(last_command_started).to have_output_on_stderr include_output_string error_message }
end
end
48 changes: 48 additions & 0 deletions spec/global_option_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
describe 'Global options' do
context 'with -R option' do
let(:output) do
<<~OUTPUT
./a/b/c: abc
./foo/bar: foobar
OUTPUT
end

before do
FileUtils.mkdir_p(expand_path('a/b'))
write_file('a/b/c', 'abc')
FileUtils.mkdir_p(expand_path('foo'))
write_file('foo/bar', 'foobar')

run_rf('-R _ .')
end

it { expect(last_command_started).to be_successfully_executed }
it { expect(last_command_started).to have_output output_string_eq output }
end

describe '-i/--in-place option' do
let(:output) { '' }

where(:option, :suffix) do
[
['-i', ''],
['--in-place', ''],
['-i', '.bak'],
['--in-place=', '.bak']
]
end

with_them do
before do
write_file('foo', 'foo')
run_rf(%(#{option}#{suffix} '"bar"' foo))
end

let(:actucal) { read_file("foo#{suffix}") }

it { expect(last_command_started).to be_successfully_executed }
it { expect(last_command_started).to have_output output_string_eq output }
it { expect(actucal).to eq "bar\n" }
end
end
end
22 changes: 0 additions & 22 deletions spec/glonal_options_spec.rb

This file was deleted.

1 change: 1 addition & 0 deletions spec/help_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
--include-filename searches for files matching a regex pattern
-f, --file=program_file executed the contents of program_file
-g, --grep Interpret command as a regex pattern for searching (like grep)
-i, --in-place[=SUFFIX] edit files in place (makes backup if SUFFIX supplied)
-n, --quiet suppress automatic printing
-s, --slurp read all reacords into an array
--help show this message
Expand Down
6 changes: 5 additions & 1 deletion spec/support/aruba.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ def run_rf(args, input = nil)
close_input
end

command
command.wait
end

def read_file(path)
File.read(expand_path(path))
end