From 1cf469b2207fce797073562c57bb606c75ae26f5 Mon Sep 17 00:00:00 2001 From: "William T. Blackerby" Date: Mon, 19 May 2014 12:45:21 -0500 Subject: [PATCH] First go at getting all tests to pass --- samples/part1/bin/ruby-ls | 7 +- samples/part1/lib/ruby-ls.rb | 2 + samples/part1/lib/ruby-ls/application.rb | 30 +++++++ samples/part1/lib/ruby-ls/display.rb | 110 +++++++++++++++++++++++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 samples/part1/lib/ruby-ls.rb create mode 100644 samples/part1/lib/ruby-ls/application.rb create mode 100644 samples/part1/lib/ruby-ls/display.rb diff --git a/samples/part1/bin/ruby-ls b/samples/part1/bin/ruby-ls index f10c79a..074e218 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 'optparse' +require 'etc' +require_relative '../lib/ruby-ls' + +RubyLS::Application.new(ARGV).run diff --git a/samples/part1/lib/ruby-ls.rb b/samples/part1/lib/ruby-ls.rb new file mode 100644 index 0000000..6298c28 --- /dev/null +++ b/samples/part1/lib/ruby-ls.rb @@ -0,0 +1,2 @@ +require_relative "ruby-ls/application" +require_relative "ruby-ls/display" diff --git a/samples/part1/lib/ruby-ls/application.rb b/samples/part1/lib/ruby-ls/application.rb new file mode 100644 index 0000000..c19f20f --- /dev/null +++ b/samples/part1/lib/ruby-ls/application.rb @@ -0,0 +1,30 @@ +module RubyLS + class Application + def initialize(argv) + @params, @dirs = parse_options(argv) + @display = RubyLS::Display.new(@params) + end + + def run + @display.render(@dirs) + end + + def parse_options(argv) + params = {} + parser = OptionParser.new + + parser.on("-l") { params[:display_format] = :long } + parser.on("-a") { params[:show_hidden] = true } + + begin + dirs = parser.parse(argv) + rescue OptionParser::InvalidOption + $stderr.puts "ls: illegal option -- #{argv[0][1]}" + $stderr.puts "usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]" + exit(1) + end + + [params, dirs] + end + end +end diff --git a/samples/part1/lib/ruby-ls/display.rb b/samples/part1/lib/ruby-ls/display.rb new file mode 100644 index 0000000..298ddf4 --- /dev/null +++ b/samples/part1/lib/ruby-ls/display.rb @@ -0,0 +1,110 @@ +module RubyLS + class Display + attr_reader :display_format, :show_hidden, :glob, :files + + def initialize(params) + @display_format = params[:display_format] + @show_hidden = params[:show_hidden] + @glob = false + end + + def render(data) + report = '' + + if data.empty? + @files = get_directory(Dir.pwd) + else + @files = [] + data.each do |dir| + @files.push(*get_directory(dir)) + end + end + + glob = @files.none? { |d| File.directory?(d) } + + if display_format + block_total = 0 + @files.each do |file| + block_total += File.stat(file).blocks + report << build_long_report(file) + end + puts "total #{block_total}" unless glob + else + @files.each do |file| + report << "#{file}\n" + end + end + puts report + end + + def get_directory(dir) + if !File.file?(dir) && !File.directory?(dir) + $stderr.puts "ls: #{dir}: No such file or directory" + exit(1) + end + + if Dir.exists?(dir) + Dir.chdir(dir) + files = show_hidden == true ? Dir.entries('.') : Dir.glob('*') + else + files = Dir.glob(dir) + end + end + + def padding(files) + files.map { |f| File.stat(f).size.to_s.size }.max + end + + def build_long_report(dir) + output = '' + + uid = File.stat(dir).uid + gid = File.stat(dir).gid + mode = get_mode_string(dir) + links = File.stat(dir).nlink.to_s + size = File.stat(dir).size.to_s + mtime = File.stat(dir).mtime + mtime = mtime.strftime("%b %e %H:%M") + uname = Etc.getpwuid(uid).name + gname = Etc.getgrgid(gid).name + output << mode + ' ' + output << links + ' ' + output << uname + ' ' + output << gname + ' ' + output << size.rjust(padding(files)) + ' ' + output << mtime + ' ' + output << dir + output << "\n" + end + + def get_mode_string(file) + read_idx = [0, 3, 6] + write_idx = [1, 4, 7] + exe_idx = [2, 5, 8] + mode_string = '' + + if Dir.exists?(file) + mode_string << 'd' + else + mode_string << '-' + end + + mode = File.stat(file).mode + mode_bits = mode.to_s(2).split(//).last(9) + mode_bits.each_with_index do |b, i| + if b == "1" + if read_idx.include?(i) + mode_string << 'r' + elsif write_idx.include?(i) + mode_string << 'w' + elsif exe_idx.include?(i) + mode_string << 'x' + end + else + mode_string << '-' + end + end + mode_string + end + end +end