From dce024ca5f6c2204c7407b4bb39de5639d020d2e Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Tue, 10 Jun 2014 16:25:41 -0700 Subject: [PATCH 1/9] first two tests passing, stuck on weird error with third --- PART_1.md | 29 +++++++++++++++++++++++ samples/part1/bin/ruby-ls | 9 ++++--- samples/part1/command_result.txt | 30 ++++++++++++++++++++++++ samples/part1/lib/ruby_ls.rb | 1 + samples/part1/lib/ruby_ls/application.rb | 21 +++++++++++++++++ samples/part1/ls_tests.rb | 7 +++--- 6 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 samples/part1/command_result.txt create mode 100644 samples/part1/lib/ruby_ls.rb create mode 100644 samples/part1/lib/ruby_ls/application.rb diff --git a/PART_1.md b/PART_1.md index 0cbeecb..499750a 100644 --- a/PART_1.md +++ b/PART_1.md @@ -15,37 +15,66 @@ and exercises. **Q1:** What steps are involved in making a Ruby scripts runnable as a command line utility? (i.e. directly runnable like `rake` or `gem` rather than having to type `ruby my_script.rb`) +A shebang line needs to be placed above the ruby code in a script that points to the location of the ruby environment, +in order to execute the script. #! /usr/bin/env ruby **Q2:** What is `ARGF` stream used for in Ruby? +Is used in a Ruby script to process files that are passes in as command line arguments. It works in conjunction with ARGV so when a file is read from ARGF it is removed from the ARGV array, **Q3:** What is `$?` used for in Bash/Ruby? +It is a global variable in Ruby that returns information about a Process's status. It is an instance of the Process::Status class. + **Q4:** What does an exit status of zero indicate when a command line script terminates? How about a non-zero exit status? +Zero indicates that there were no errors in the execution, while a non zero exit status indicates the error and I would think a well designed command line script would have some meaning to various non-zero values. **Q5:** What is the difference between the `STDOUT` and `STDERR` output streams? +STDOUT is a stream to print non-error related messages to, for instance puts prints to standard out. STDERR is the +output stream for errors, so raise "Some message" would print to STDERR. **Q6:** When executing shell commands from within a Ruby script, how can you capture what gets written to `STDOUT`? How do you go about capturing both `STDOUT` and `STDERR` streams? +The ruby standard libraru Open3 provides a simple way to access stdout and stderr without having to do any parsing of one's own. **Q7:** How can you efficiently write the contents of an input file to `STDOUT` with empty lines omitted? Being efficient in this context means avoiding storing the full contents of the input file in memory and processing the stream in a single pass. +File.open("samplefile.txt").readline do |line| + puts line unless line.chomp.empty? +end + **Q8:** How would you go about parsing command line arguments that contain a mixture of flags and file arguments? (i.e. something like `ls -a -l foo/*.txt`) +I would use a library like OptionParser to first extract the flags that I'm looking for. + +Ex. + +params = {} +parser = OptionParser.new + +parser.on("-a") { params[:all_files] ||= true } +parser.on("-l") { params[:show_permission] = true } + +files = parser.parse(ARGV) + +parser.parse extracts the -a and -l from ARGV and sets the rest equal to files. **Q9:** What features are provided by Ruby's `String` class to help with fixed width text layouts? (i.e. right aligning a column of numbers, or left aligning a column of text with some whitespace after it to keep the total column width uniform) +String provides methods such as rjust and ljust that take an integer in order to right or left justify the string. **Q10:** Suppose your script encounters an error and has to terminate itself. What is the idiomatic Unix-style way of reporting that the command did not run successfully? +It would be to first have the application be aware of differing types of erros from incorrect input to failure during processing and then to show to the end user the command they called, an error message and when applicable a helpful tip. One immediate example that comes to mind is git where if I type a command like git commt it will be smart enough to suggest to me 'do you mean commit'. + ## Exercises > NOTE: The supporting materials for these exercises are in `samples/part1`. diff --git a/samples/part1/bin/ruby-ls b/samples/part1/bin/ruby-ls index f10c79a..a84a4dd 100755 --- a/samples/part1/bin/ruby-ls +++ b/samples/part1/bin/ruby-ls @@ -1,4 +1,7 @@ #!/usr/bin/env ruby - -## FIXME: Replace this code with a pure Ruby clone of the ls utility -system("ls", *ARGV) +require_relative "../lib/ruby_ls" +begin + RubyLs::Application.new(ARGV).run +rescue Errno::ENOENT => err + abort "ruby-ls: #{err.message}" +end diff --git a/samples/part1/command_result.txt b/samples/part1/command_result.txt new file mode 100644 index 0000000..49959f3 --- /dev/null +++ b/samples/part1/command_result.txt @@ -0,0 +1,30 @@ +foo hello.sh hello.txt + +apple.md banana.md bar.txt baz.txt quux.txt + +foo/bar.txt foo/baz.txt foo/quux.txt + +total 16 +drwxr-xr-x 7 Kavinder staff 238 May 24 19:40 foo +-rwxr-xr-x 1 Kavinder staff 39 May 24 19:40 hello.sh +-rw-r--r-- 1 Kavinder staff 13 May 24 19:40 hello.txt + +. .secret hello.sh +.. foo hello.txt + +total 24 +drwxr-xr-x 6 Kavinder staff 204 May 24 19:40 . +drwxr-xr-x 6 Kavinder staff 204 Jun 9 11:00 .. +-rw-r--r-- 1 Kavinder staff 9 May 24 19:40 .secret +drwxr-xr-x 7 Kavinder staff 238 May 24 19:40 foo +-rwxr-xr-x 1 Kavinder staff 39 May 24 19:40 hello.sh +-rw-r--r-- 1 Kavinder staff 13 May 24 19:40 hello.txt + +-rw-r--r-- 1 Kavinder staff 8 May 24 19:40 foo/bar.txt +-rw-r--r-- 1 Kavinder staff 8 May 24 19:40 foo/baz.txt +-rw-r--r-- 1 Kavinder staff 10 May 24 19:40 foo/quux.txt + +ls: missingdir: No such file or directory + +ls: illegal option -- Z +usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...] \ No newline at end of file diff --git a/samples/part1/lib/ruby_ls.rb b/samples/part1/lib/ruby_ls.rb new file mode 100644 index 0000000..f1d50a8 --- /dev/null +++ b/samples/part1/lib/ruby_ls.rb @@ -0,0 +1 @@ +require_relative "ruby_ls/application" \ No newline at end of file diff --git a/samples/part1/lib/ruby_ls/application.rb b/samples/part1/lib/ruby_ls/application.rb new file mode 100644 index 0000000..c5cd647 --- /dev/null +++ b/samples/part1/lib/ruby_ls/application.rb @@ -0,0 +1,21 @@ +module RubyLs + class Application + + def initialize(argv) + @dir = argv.first + @stuff = argv + end + + def run + if @dir =~ /\./ + puts Dir.glob("#{@dir}") + elsif @dir + Dir.chdir("#{@dir}") + puts Dir.glob("*") + else + puts Dir.glob("*") + end + end + + end +end \ No newline at end of file diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index 4371b25..b60f415 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -5,11 +5,9 @@ check("No arguments", "") -# TODO: Uncomment each test below and get it to pass. +check("Dir listing", "foo") -# check("Dir listing", "foo") - -# check("File glob", "foo/*.txt") +check("File glob", "foo/*.txt") # check("Detailed output", "-l") @@ -38,6 +36,7 @@ require "open3" def check(test_name, args) + ls_stdout, ls_stderr, ls_status = Open3.capture3("ls #{args}") rb_stdout, rb_stderr, rb_status = Open3.capture3("ruby-ls #{args}") From 51b25e0ab11145262759786217dd435782c49860 Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Fri, 4 Jul 2014 17:02:28 -0700 Subject: [PATCH 2/9] -l implementation --- samples/part1/lib/ruby_ls.rb | 5 ++- samples/part1/lib/ruby_ls/application.rb | 21 ++++++++--- samples/part1/lib/ruby_ls/display.rb | 47 ++++++++++++++++++++++++ samples/part1/lib/ruby_ls/file_info.rb | 39 ++++++++++++++++++++ samples/part1/ls_tests.rb | 2 +- 5 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 samples/part1/lib/ruby_ls/display.rb create mode 100644 samples/part1/lib/ruby_ls/file_info.rb diff --git a/samples/part1/lib/ruby_ls.rb b/samples/part1/lib/ruby_ls.rb index f1d50a8..46a1e3a 100644 --- a/samples/part1/lib/ruby_ls.rb +++ b/samples/part1/lib/ruby_ls.rb @@ -1 +1,4 @@ -require_relative "ruby_ls/application" \ No newline at end of file +require 'optparse' +require_relative "ruby_ls/application" +require_relative "ruby_ls/display" +require_relative "ruby_ls/file_info" \ No newline at end of file diff --git a/samples/part1/lib/ruby_ls/application.rb b/samples/part1/lib/ruby_ls/application.rb index c5cd647..d181049 100644 --- a/samples/part1/lib/ruby_ls/application.rb +++ b/samples/part1/lib/ruby_ls/application.rb @@ -2,20 +2,31 @@ module RubyLs class Application def initialize(argv) - @dir = argv.first - @stuff = argv + @params, @args = parse_options(argv) + @dir = @args.first + @display = RubyLs::Display.new(@params) end def run if @dir =~ /\./ - puts Dir.glob("#{@dir}") + @display.render(@args) elsif @dir Dir.chdir("#{@dir}") - puts Dir.glob("*") + @display.render(Dir.glob("*")) else - puts Dir.glob("*") + @display.render(Dir.glob("*")) end end + private + + def parse_options(argv) + params = {} + parser = OptionParser.new + parser.on("-l") {params[:detail] = true} + dir = parser.parse(argv) + [params, dir] + end + end end \ No newline at end of file diff --git a/samples/part1/lib/ruby_ls/display.rb b/samples/part1/lib/ruby_ls/display.rb new file mode 100644 index 0000000..3669a3c --- /dev/null +++ b/samples/part1/lib/ruby_ls/display.rb @@ -0,0 +1,47 @@ +require 'etc' +module RubyLs + class Display + + def initialize(params) + @details = params[:detail] + end + + def render(data) + if @details + details = get_details(data) + output, total_blocks = build_details_output(details) + print_total_blocks + print_output + else + puts data + end + end + + private + + def get_details(data) + data.inject([]) do |info, file| + info << FileInfo.new(file).details + info + end + end + + def print_total_blocks + puts "total #{@total_blocks}" + end + + def print_output + puts @output + end + + def build_details_output(details, total_blocks=0) + @output = details.inject([]) do |output, d| + output << "#{d[:permissions]} #{d[:link_count]} #{d[:owner]} #{d[:group]} #{d[:size].to_s.rjust(4)} #{d[:time]} #{d[:name]}" + total_blocks += d[:blocks] + output + end + @total_blocks = total_blocks + end + + end +end \ No newline at end of file diff --git a/samples/part1/lib/ruby_ls/file_info.rb b/samples/part1/lib/ruby_ls/file_info.rb new file mode 100644 index 0000000..d7a0091 --- /dev/null +++ b/samples/part1/lib/ruby_ls/file_info.rb @@ -0,0 +1,39 @@ +module RubyLs + class FileInfo + + MODES = { "0" => "---", "1" => "--x", "2" => "-w-", "3" => "-wx", + "4" => "r--", "5" => "r-x", "6" => "rw-", "7" => "rwx" } + + attr_reader :file + + def initialize(file) + @file = file + end + + def details + file_info + end + + private + + def file_info + stats = File::Stat.new(file) + { + permissions: permission_string(stats.mode), + link_count: stats.nlink, + owner: Etc.getpwuid(stats.uid).name, + group: Etc.getgrgid(stats.gid).name, + size: File.size(file), + time: stats.mtime.strftime("%b %e %H:%M"), + name: file, + blocks: stats.blocks + } + end + + def permission_string(mode) + dir_flag = mode[15] == 0 ? "d" : "-" + ugw_codes = (mode & 0777).to_s(8).chars + dir_flag + ugw_codes.map { |n| MODES[n] }.join + end + end +end \ No newline at end of file diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index b60f415..a855c0b 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -9,7 +9,7 @@ check("File glob", "foo/*.txt") -# check("Detailed output", "-l") +check("Detailed output", "-l") # check("Hidden files", "-a") From d02d594b0fa5ac6a9e823b946dbe86821d09e736 Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Sat, 5 Jul 2014 11:32:51 -0700 Subject: [PATCH 3/9] show hidden files --- samples/part1/lib/ruby_ls/application.rb | 11 ++++++++--- samples/part1/lib/ruby_ls/display.rb | 1 + samples/part1/ls_tests.rb | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/samples/part1/lib/ruby_ls/application.rb b/samples/part1/lib/ruby_ls/application.rb index d181049..9a77537 100644 --- a/samples/part1/lib/ruby_ls/application.rb +++ b/samples/part1/lib/ruby_ls/application.rb @@ -9,12 +9,12 @@ def initialize(argv) def run if @dir =~ /\./ - @display.render(@args) + @display.render(@args) elsif @dir Dir.chdir("#{@dir}") - @display.render(Dir.glob("*")) + @display.render(files) else - @display.render(Dir.glob("*")) + @display.render(files) end end @@ -24,9 +24,14 @@ def parse_options(argv) params = {} parser = OptionParser.new parser.on("-l") {params[:detail] = true} + parser.on("-a") {params[:hidden] = true} dir = parser.parse(argv) [params, dir] end + def files + @params[:hidden] ? Dir.entries(".") : Dir.glob("*") + end + end end \ No newline at end of file diff --git a/samples/part1/lib/ruby_ls/display.rb b/samples/part1/lib/ruby_ls/display.rb index 3669a3c..24d9ab2 100644 --- a/samples/part1/lib/ruby_ls/display.rb +++ b/samples/part1/lib/ruby_ls/display.rb @@ -4,6 +4,7 @@ class Display def initialize(params) @details = params[:detail] + @hidden = params[:hidden] end def render(data) diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index a855c0b..2d41bd6 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -11,7 +11,7 @@ check("Detailed output", "-l") -# check("Hidden files", "-a") +check("Hidden files", "-a") # check("Hidden files with detailed output", "-a -l") From 8f99013797019201bf18afdc35471447b9b68259 Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Sat, 5 Jul 2014 11:32:59 -0700 Subject: [PATCH 4/9] show hidden files --- samples/part1/ls_tests.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index 2d41bd6..45bc9bf 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -13,7 +13,7 @@ check("Hidden files", "-a") -# check("Hidden files with detailed output", "-a -l") +check("Hidden files with detailed output", "-a -l") # check("File glob with detailed output", "-l foo/*.txt") From 977cfd9a85bc655af0ae712b2fd82569e181d1d0 Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Sat, 5 Jul 2014 11:48:56 -0700 Subject: [PATCH 5/9] check if a directory --- samples/part1/lib/ruby_ls/application.rb | 10 +++++++--- samples/part1/lib/ruby_ls/display.rb | 4 ++-- samples/part1/ls_tests.rb | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/samples/part1/lib/ruby_ls/application.rb b/samples/part1/lib/ruby_ls/application.rb index 9a77537..1c5f7bb 100644 --- a/samples/part1/lib/ruby_ls/application.rb +++ b/samples/part1/lib/ruby_ls/application.rb @@ -9,12 +9,12 @@ def initialize(argv) def run if @dir =~ /\./ - @display.render(@args) + @display.render(@args, directory?) elsif @dir Dir.chdir("#{@dir}") - @display.render(files) + @display.render(files, directory?) else - @display.render(files) + @display.render(files, directory?) end end @@ -33,5 +33,9 @@ def files @params[:hidden] ? Dir.entries(".") : Dir.glob("*") end + def directory? + @args.empty? || (@args.count == 1 && File.directory?(@args.first)) + end + end end \ No newline at end of file diff --git a/samples/part1/lib/ruby_ls/display.rb b/samples/part1/lib/ruby_ls/display.rb index 24d9ab2..593b782 100644 --- a/samples/part1/lib/ruby_ls/display.rb +++ b/samples/part1/lib/ruby_ls/display.rb @@ -7,11 +7,11 @@ def initialize(params) @hidden = params[:hidden] end - def render(data) + def render(data, directory=false) if @details details = get_details(data) output, total_blocks = build_details_output(details) - print_total_blocks + print_total_blocks if directory print_output else puts data diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index 45bc9bf..6cb1c37 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -15,7 +15,7 @@ check("Hidden files with detailed output", "-a -l") -# check("File glob with detailed output", "-l foo/*.txt") +check("File glob with detailed output", "-l foo/*.txt") # check("Invalid directory", "missingdir") From 04c3da7dad30ec1692a93d4a9d18462a990edb18 Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Mon, 7 Jul 2014 17:19:56 -0700 Subject: [PATCH 6/9] getting file glob long form working, refactoring needed soon --- samples/part1/lib/ruby_ls/display.rb | 18 ++++++++++++------ samples/part1/lib/ruby_ls/file_info.rb | 7 ++++++- samples/part1/ls_tests.rb | 1 + 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/samples/part1/lib/ruby_ls/display.rb b/samples/part1/lib/ruby_ls/display.rb index 593b782..e1dd0a2 100644 --- a/samples/part1/lib/ruby_ls/display.rb +++ b/samples/part1/lib/ruby_ls/display.rb @@ -5,6 +5,8 @@ class Display def initialize(params) @details = params[:detail] @hidden = params[:hidden] + @column_widths = Hash.new(0) + @total_blocks = 0 end def render(data, directory=false) @@ -12,7 +14,7 @@ def render(data, directory=false) details = get_details(data) output, total_blocks = build_details_output(details) print_total_blocks if directory - print_output + print_output(details) else puts data end @@ -31,15 +33,19 @@ def print_total_blocks puts "total #{@total_blocks}" end - def print_output - puts @output + def print_output(details) + details.each do |d| + puts "#{d[:permissions]} #{d[:link_count].to_s.rjust(@column_widths[:link_count] + 1, " ")} #{d[:owner]} #{d[:group]} #{d[:size].to_s.rjust(@column_widths[:size] + 1, " ")} #{d[:time]} #{d[:name]}" + end end def build_details_output(details, total_blocks=0) - @output = details.inject([]) do |output, d| - output << "#{d[:permissions]} #{d[:link_count]} #{d[:owner]} #{d[:group]} #{d[:size].to_s.rjust(4)} #{d[:time]} #{d[:name]}" + @output = details.each do |d| + d.keys.each do |k| + @column_widths[k] = [@column_widths[k], d[k].to_s.size].max + end + #output << "#{d[:permissions]} #{d[:link_count].to_s.rjust(@column_widths[:link_count] + 1, " ")} #{d[:owner]} #{d[:group]} #{d[:size].to_s.rjust(@column_widths[:size] + 1, " ")} #{d[:time]} #{d[:name]}" total_blocks += d[:blocks] - output end @total_blocks = total_blocks end diff --git a/samples/part1/lib/ruby_ls/file_info.rb b/samples/part1/lib/ruby_ls/file_info.rb index d7a0091..ce10b84 100644 --- a/samples/part1/lib/ruby_ls/file_info.rb +++ b/samples/part1/lib/ruby_ls/file_info.rb @@ -1,6 +1,7 @@ module RubyLs class FileInfo + attr_reader :data MODES = { "0" => "---", "1" => "--x", "2" => "-w-", "3" => "-wx", "4" => "r--", "5" => "r-x", "6" => "rw-", "7" => "rwx" } @@ -14,11 +15,15 @@ def details file_info end + def keys + @data.keys + end + private def file_info stats = File::Stat.new(file) - { + @data = { permissions: permission_string(stats.mode), link_count: stats.nlink, owner: Etc.getpwuid(stats.uid).name, diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index 6cb1c37..9ec5ab5 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -15,6 +15,7 @@ check("Hidden files with detailed output", "-a -l") + check("File glob with detailed output", "-l foo/*.txt") # check("Invalid directory", "missingdir") From 66f6f4368d1b3f34ab56e5a14d41085defb6fcf0 Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Tue, 8 Jul 2014 14:16:03 -0700 Subject: [PATCH 7/9] error handling for missing file --- samples/part1/lib/ruby_ls/application.rb | 20 ++++++++++++-------- samples/part1/ls_tests.rb | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/samples/part1/lib/ruby_ls/application.rb b/samples/part1/lib/ruby_ls/application.rb index 1c5f7bb..f79338f 100644 --- a/samples/part1/lib/ruby_ls/application.rb +++ b/samples/part1/lib/ruby_ls/application.rb @@ -8,14 +8,18 @@ def initialize(argv) end def run - if @dir =~ /\./ - @display.render(@args, directory?) - elsif @dir - Dir.chdir("#{@dir}") - @display.render(files, directory?) - else - @display.render(files, directory?) - end + begin + if @dir =~ /\./ + @display.render(@args, directory?) + elsif @dir + Dir.chdir("#{@dir}") + @display.render(files, directory?) + else + @display.render(files, directory?) + end + rescue SystemCallError => e + abort("ls: #{@dir}: No such file or directory") + end end private diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index 9ec5ab5..530e4c3 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -18,7 +18,7 @@ check("File glob with detailed output", "-l foo/*.txt") -# check("Invalid directory", "missingdir") + check("Invalid directory", "missingdir") # check("Invalid flag", "-Z") From 83a7ba2d1189f6ad74e8fb2daab78258f38b88e9 Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Thu, 10 Jul 2014 16:27:26 -0700 Subject: [PATCH 8/9] invalid flag test passing --- samples/part1/lib/ruby_ls/application.rb | 8 +++++++- samples/part1/ls_tests.rb | 5 ++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/samples/part1/lib/ruby_ls/application.rb b/samples/part1/lib/ruby_ls/application.rb index f79338f..467e968 100644 --- a/samples/part1/lib/ruby_ls/application.rb +++ b/samples/part1/lib/ruby_ls/application.rb @@ -29,7 +29,13 @@ def parse_options(argv) parser = OptionParser.new parser.on("-l") {params[:detail] = true} parser.on("-a") {params[:hidden] = true} - dir = parser.parse(argv) + begin + dir = parser.parse(argv) + rescue OptionParser::InvalidOption => e + invalid_flag = e.message[/invalid option: -(.*)/, 1] + abort "ls: illegal option -- #{invalid_flag}\n"+ + "usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]" + end [params, dir] end diff --git a/samples/part1/ls_tests.rb b/samples/part1/ls_tests.rb index 530e4c3..4f2b6f8 100644 --- a/samples/part1/ls_tests.rb +++ b/samples/part1/ls_tests.rb @@ -15,12 +15,11 @@ check("Hidden files with detailed output", "-a -l") - check("File glob with detailed output", "-l foo/*.txt") - check("Invalid directory", "missingdir") +check("Invalid directory", "missingdir") -# check("Invalid flag", "-Z") +check("Invalid flag", "-Z") puts "You passed the tests, yay!" From 441304d92963c49024dd0f4003e40e85d380220e Mon Sep 17 00:00:00 2001 From: Kavinder Dhaliwal Date: Sat, 12 Jul 2014 17:39:23 -0700 Subject: [PATCH 9/9] cleanup --- samples/part1/lib/ruby_ls/application.rb | 30 +++++++++++------------- samples/part1/lib/ruby_ls/display.rb | 16 +++++++++---- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/samples/part1/lib/ruby_ls/application.rb b/samples/part1/lib/ruby_ls/application.rb index 467e968..fbe8929 100644 --- a/samples/part1/lib/ruby_ls/application.rb +++ b/samples/part1/lib/ruby_ls/application.rb @@ -2,21 +2,14 @@ module RubyLs class Application def initialize(argv) - @params, @args = parse_options(argv) + @options, @args = parse_options(argv) @dir = @args.first - @display = RubyLs::Display.new(@params) + @display = RubyLs::Display.new(@options) end def run begin - if @dir =~ /\./ - @display.render(@args, directory?) - elsif @dir - Dir.chdir("#{@dir}") - @display.render(files, directory?) - else - @display.render(files, directory?) - end + @display.render(files, directory?) rescue SystemCallError => e abort("ls: #{@dir}: No such file or directory") end @@ -25,22 +18,27 @@ def run private def parse_options(argv) - params = {} + options = {} parser = OptionParser.new - parser.on("-l") {params[:detail] = true} - parser.on("-a") {params[:hidden] = true} + parser.on("-l") {options[:detail] = true} + parser.on("-a") {options[:hidden] = true} begin - dir = parser.parse(argv) + args = parser.parse(argv) + [options, args] rescue OptionParser::InvalidOption => e invalid_flag = e.message[/invalid option: -(.*)/, 1] abort "ls: illegal option -- #{invalid_flag}\n"+ "usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]" end - [params, dir] end def files - @params[:hidden] ? Dir.entries(".") : Dir.glob("*") + if @dir =~/\./ + @args + else + Dir.chdir("#{@dir}") if @dir + @options[:hidden] ? Dir.entries(".") : Dir.glob("*") + end end def directory? diff --git a/samples/part1/lib/ruby_ls/display.rb b/samples/part1/lib/ruby_ls/display.rb index e1dd0a2..314f30e 100644 --- a/samples/part1/lib/ruby_ls/display.rb +++ b/samples/part1/lib/ruby_ls/display.rb @@ -5,8 +5,8 @@ class Display def initialize(params) @details = params[:detail] @hidden = params[:hidden] - @column_widths = Hash.new(0) - @total_blocks = 0 + @column_widths = Hash.new(0) + @total_blocks = 0 end def render(data, directory=false) @@ -20,7 +20,7 @@ def render(data, directory=false) end end - private + private def get_details(data) data.inject([]) do |info, file| @@ -35,7 +35,14 @@ def print_total_blocks def print_output(details) details.each do |d| - puts "#{d[:permissions]} #{d[:link_count].to_s.rjust(@column_widths[:link_count] + 1, " ")} #{d[:owner]} #{d[:group]} #{d[:size].to_s.rjust(@column_widths[:size] + 1, " ")} #{d[:time]} #{d[:name]}" + output = [d[:permissions], + d[:link_count].to_s.rjust(@column_widths[:link_count] + 1, " "), + d[:owner] + " ", + d[:group], + d[:size].to_s.rjust(@column_widths[:size] + 1, " "), + d[:time], + d[:name]] + puts output.join(" ") end end @@ -44,7 +51,6 @@ def build_details_output(details, total_blocks=0) d.keys.each do |k| @column_widths[k] = [@column_widths[k], d[k].to_s.size].max end - #output << "#{d[:permissions]} #{d[:link_count].to_s.rjust(@column_widths[:link_count] + 1, " ")} #{d[:owner]} #{d[:group]} #{d[:size].to_s.rjust(@column_widths[:size] + 1, " ")} #{d[:time]} #{d[:name]}" total_blocks += d[:blocks] end @total_blocks = total_blocks