From b446fa6416dba4d3f94e6c4b4d5958d836c649b3 Mon Sep 17 00:00:00 2001 From: buty4649 Date: Sun, 5 Nov 2023 01:32:17 +0900 Subject: [PATCH] Add -R option --- mrblib/rf/cli.rb | 3 +- mrblib/rf/config.rb | 6 ++-- mrblib/rf/directory.rb | 63 +++++++++++++++++++++++++++++++++++++ mrblib/rf/runner.rb | 27 ++++++++++------ spec/glonal_options_spec.rb | 22 +++++++++++++ spec/help_spec.rb | 1 + 6 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 mrblib/rf/directory.rb create mode 100644 spec/glonal_options_spec.rb diff --git a/mrblib/rf/cli.rb b/mrblib/rf/cli.rb index 6853882..5f9034d 100644 --- a/mrblib/rf/cli.rb +++ b/mrblib/rf/cli.rb @@ -2,7 +2,7 @@ module Rf class Cli attr_reader :config - def run(argv) + def run(argv) # rubocop:disable Metrics/AbcSize @config = Config.parse(argv) Runner.run({ command: config.command, @@ -10,6 +10,7 @@ def run(argv) filter: config.filter, slurp: config.slurp, quiet: config.quiet, + recursive: config.recursive, with_filename: config.with_filename }) rescue NotFound => e diff --git a/mrblib/rf/config.rb b/mrblib/rf/config.rb index 1372072..5641b51 100644 --- a/mrblib/rf/config.rb +++ b/mrblib/rf/config.rb @@ -1,6 +1,7 @@ module Rf class Config - attr_accessor :command, :files, :filter, :slurp, :script_file, :quiet, :with_filename + attr_accessor :command, :files, :filter, :slurp, :script_file, :quiet, + :recursive, :with_filename def self.parse(argv) Parser.new.parse(argv) @@ -85,9 +86,10 @@ def banner_and_filter_options end end - def global_options + def global_options # rubocop:disable Metrics/AbcSize @global_options ||= OptionMap.new do |opt| opt.on('-H', '--with-filename', 'print filename with output lines') { @config.with_filename = true } + opt.on('-R', '--recursive', 'read all files under each directory recursively') { @config.recursive = true } opt.on('-f', '--file=program_file', 'executed the contents of program_file') { |f| @config.script_file = f } opt.on('-n', '--quiet', 'suppress automatic priting') { @config.quiet = true } opt.on('-s', '--slurp', 'read all reacords into an array') { @config.slurp = true } diff --git a/mrblib/rf/directory.rb b/mrblib/rf/directory.rb new file mode 100644 index 0000000..0f11e27 --- /dev/null +++ b/mrblib/rf/directory.rb @@ -0,0 +1,63 @@ +module Rf + class Directory + class Node + attr_reader :path + + def initialize(path) + @path = path + @dir = Dir.open(path) + end + + def next + child = loop do + child = @dir.read + return unless child + break child unless %w[. ..].include?(child) + end + + File.join(@path, child) + end + end + + def initialize(root) + @nodes = [Node.new(root)] + end + + def next + loop do + path = @nodes.last.next + unless path + @nodes.pop + break if @nodes.empty? + + next + end + + break path unless File.directory?(path) + + @nodes << Node.new(path) + end + end + + def self.open(paths) + Enumerator.new do |y| + paths.each do |path| + if path == '-' + y << path + next + end + + stat = File::Stat.new(path) + if stat.directory? + dir = Directory.new(path) + while path = dir.next + y << path + end + else + y << path + end + end + end + end + end +end diff --git a/mrblib/rf/runner.rb b/mrblib/rf/runner.rb index fb42b85..a1da829 100644 --- a/mrblib/rf/runner.rb +++ b/mrblib/rf/runner.rb @@ -4,24 +4,32 @@ def self.run(...) new(...).run end - attr_reader :container, :bind, :command, :filter, :files, :with_filename + attr_reader :container, :bind, :command, :filter, :inputs, :with_filename # @param [Hash] opts # :command => String # :files => Array # :filter => Rf::Filter # :slurp => Boolean + # :recursive => Boolean # :quiet => Boolean # :with_filename => Boolean - def initialize(opts) + def initialize(opts) # rubocop:disable Metrics/AbcSize @command = opts[:command] - @files = opts[:files] || %w[-] @filter = opts[:filter] - @slurp = true & opts[:slurp] - @quiet = true & opts[:quiet] + @slurp = opts[:slurp] + @quiet = opts[:quiet] - setup_container - @container.with_filename = opts[:with_filename] || (files.size > 1 && filter == Filter::Text) + files = opts[:files] || %w[-] + recursive = opts[:recursive] + @inputs = recursive ? Directory.open(files) : files + + with_filename = opts[:with_filename] + with_filename ||= filter == Filter::Text && ( + files.size > 1 || (recursive && File.directory?(files.first)) + ) + + setup_container(with_filename) end def slurp? @@ -33,15 +41,16 @@ def quiet? end # enclose the scope of binding - def setup_container + def setup_container(with_filename) @container = Container.new @bind = container.instance_eval { binding } + @container.with_filename = with_filename end def run # rubocop:disable Metrics/AbcSize Rf.add_features - files.each do |filename| + inputs.each do |filename| @container.filename = filename records = Record.read(filter.new(self.open(filename))) if slurp? diff --git a/spec/glonal_options_spec.rb b/spec/glonal_options_spec.rb new file mode 100644 index 0000000..e104906 --- /dev/null +++ b/spec/glonal_options_spec.rb @@ -0,0 +1,22 @@ +describe 'Global options' do + context 'with -R option' do + let(:output) do + <<~OUTPUT + ./foo/bar: foobar + ./a/b/c: abc + OUTPUT + end + + before do + FileUtils.mkdir_p(expand_path('foo')) + write_file('foo/bar', 'foobar') + FileUtils.mkdir_p(expand_path('a/b')) + write_file('a/b/c', 'abc') + + 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 +end diff --git a/spec/help_spec.rb b/spec/help_spec.rb index 0d688c8..8ec21ec 100644 --- a/spec/help_spec.rb +++ b/spec/help_spec.rb @@ -10,6 +10,7 @@ global options: -H, --with-filename print filename with output lines + -R, --recursive read all files under each directory recursively -f, --file=program_file executed the contents of program_file -n, --quiet suppress automatic priting -s, --slurp read all reacords into an array