Skip to content
Open
58 changes: 58 additions & 0 deletions 07.ls_object/file.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# frozen_string_literal: true

module LS
class File
FILE_TYPE_ABBRV = {
'file' => '-',
'directory' => 'd',
'characterSpecial' => 'c',
'blockSpecial' => 'b',
'fifo' => 'p',
'link' => 'l',
'socket' => 's'
}.freeze

FILE_PERMISSION_TEXT = {
'0' => '---',
'1' => '--x',
'2' => '-w-',
'3' => '-wx',
'4' => 'r--',
'5' => 'r-x',
'6' => 'rw-',
'7' => 'rwx'
}.freeze

attr_reader :file_name, :file_mode, :nlink, :user, :group, :size, :mod_month, :mod_day, :mod_time

def initialize(file_name)
raw_stat = ::File.lstat(file_name)
@file_name = file_name
@file_mode = file_mode_text(raw_stat)
@nlink = raw_stat.nlink.to_s
@user = Etc.getpwuid(raw_stat.uid).name
@group = Etc.getgrgid(raw_stat.gid).name
@size = raw_stat.size.to_s
@mod_month = raw_stat.mtime.month.to_s
@mod_day = raw_stat.mtime.day.to_s
@mod_time = raw_stat.mtime.strftime('%H:%M')
end

def stat
[file_mode, nlink, user, group, size, mod_month, mod_day, mod_time]
end

private

def convert_file_mode_to_octal_string(mode)
mode.to_s(8)
end

def file_mode_text(stat)
type = FILE_TYPE_ABBRV[stat.ftype]
octalized_file_mode = convert_file_mode_to_octal_string(stat.mode)
file_mode = octalized_file_mode.length == 5 ? "0#{octalized_file_mode}" : octalized_file_mode
"#{type}#{file_mode[3..5].chars.map { |c| FILE_PERMISSION_TEXT[c] }.join}"
end
end
end
64 changes: 64 additions & 0 deletions 07.ls_object/file_list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

require_relative 'file'

module LS
class FileList
attr_reader :files
attr_accessor :reverse_order, :long_format, :max_column

def initialize(options)
file_names = options.include?(:a) ? Dir.glob('*', ::File::FNM_DOTMATCH) : Dir.glob('*')
file_names.reverse! if options.include?(:r)
@files = file_names.map { |file_name| LS::File.new(file_name) }
@reverse_order = options.include?(:r)
@long_format = options.include?(:l)
@max_column = long_format ? 1 : 3
end

def current_directory_stats
file_stats_array = files.map { |file| file.stat }
file_stats_array_per_column = file_stats_array.transpose

max_length_per_column = {}
file_stats_array_per_column.each_with_index do |file_stats, idx|
max_length_per_column[idx] = file_stats.max_by(&:length).length
end

file_stats_array.map.with_index do |file_stats, idx|
justify_file_stats = file_stats.map.with_index do
_1.rjust(max_length_per_column[_2])
end

file_names = []
file_names[idx] = (justify_file_stats << file_names[idx]).join(' ')
end
end

def show
matrix.map { |m| m.join.rstrip!.concat("\n") }.join
end

private

def matrix
num_of_files = files.size

return [] if num_of_files == 0

formatted_files = long_format ? current_directory_stats : files.map { |file| file.file_name }

num_of_display_rows = (num_of_files % max_column).zero? ? num_of_files.div(max_column) : num_of_files.div(max_column) + 1

formatted_files.each_slice(num_of_display_rows).map do |matrix_col|
matrix_col.fill('', matrix_col.size..(num_of_display_rows - 1)) unless matrix_col.size == num_of_display_rows
longest_file_name = matrix_col.max_by(&:length).length

matrix_col.map do |file_name|
diff = longest_file_name - file_name.length
"#{file_name}#{' ' * diff if diff.positive?}#{' ' * 4}"
end
end.transpose
end
end
end
14 changes: 14 additions & 0 deletions 07.ls_object/ls.rb
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • このファイルが持っている処理がまだ多すぎるように見えます 👀 基本的にはすべての処理は何らかのクラスに持たせることができるはずだからです。このファイルは「何らかのクラスに対して処理を一度呼び、表示すべき文字列(lsコマンドの結果として表示すべき形式になったファイル一覧)を取得する」「その文字列を puts する」というくらいが妥当です。

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env ruby

# frozen_string_literal: true

require 'etc'

require_relative 'option'
require_relative 'file_list'

options = LS::OptionParser.new(ARGV).options

files = LS::FileList.new(options)

puts files.show
37 changes: 37 additions & 0 deletions 07.ls_object/option.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require 'optparse'

module LS
class OptionParser
BANNER = 'Usage: ./ls.rb [options]'
OPTION_CHOICES = {
'-a': 'Include directory entries whose names begin with a dot (‘.’).',
'-r': 'Display files in reverse order.',
'-l': 'List files in the long format.'
}

attr_reader :options

def initialize(argv)
@options = parse(argv)
end

def parse(argv)
parser = ::OptionParser.new do |opts|
opts.banner = BANNER
OPTION_CHOICES.each { |name, description| opts.on(name, description) }
end

begin
opts = {}
parser.parse!(ARGV, into: opts)
opts
rescue ::OptionParser::ParseError => e
puts e.message
puts opts.help
exit
end
end
end
end