Conversation
kutimiti1234
commented
Jul 7, 2024
- 標準入力を受け取れるように設定
- 複数ファイルを吹けとれるように設定
- "-l" "-w" "-c"のオプションに対応
05.wc/wc.rb
Outdated
| print_output(output_text, max_width) | ||
| end | ||
|
|
||
| DISPLAY_ADJUST_NUMBER = 1 |
There was a problem hiding this comment.
number以外の名前がいいかも?
https://bootcamp.fjord.jp/pages/number-count-size-length
また定数はrequireの下あたりにまとめられることが多いですね
05.wc/wc.rb
Outdated
| { line_display_width: max_lines_width, word_display_width: max_words_width, bytesize_display_width: max_bytesizes_width } | ||
| end | ||
|
|
||
| def parse_and_remove_options(argv) |
05.wc/wc.rb
Outdated
| require 'optparse' | ||
|
|
||
| def main | ||
| argv_options = parse_and_remove_options(ARGV) |
There was a problem hiding this comment.
05.wc/wc.rb
Outdated
|
|
||
| def main | ||
| argv_options = parse_and_remove_options(ARGV) | ||
| output_text = [] |
05.wc/wc.rb
Outdated
| argv_options = parse_and_remove_options(ARGV) | ||
| output_text = [] | ||
| ARGF.each(nil) do |input_text| | ||
| wc_info = [] |
There was a problem hiding this comment.
最後に to_h するのではなく、最初からハッシュとして扱う方が自然だと思います
| wc_info = [] | |
| wc_info = {} |
05.wc/wc.rb
Outdated
| line = output_line[:line]&.to_s&.rjust(max_width[:line_display_width]) | ||
| word = output_line[:word]&.to_s&.rjust(max_width[:word_display_width]) | ||
| bytesize = output_line[:bytesize]&.to_s&.rjust(max_width[:bytesize_display_width]) | ||
| filename = output_line[:filename] == '-' ? '' : output_line[:filename] |
There was a problem hiding this comment.
なるほどー。
その情報が第三者にはぱっとわからないので(=マジックナンバーならぬマジックストリング)、情報を付加した方がいいですね。
そして今回の提出物ではこの処理がなくなってますね。これはなぜ? 🤔
There was a problem hiding this comment.
こちら削除行った理由としては、ARGF以外の処理で受け取れればもしかして標準入力を"-"として受け取らずにすむのではないかと考えて、一旦削除していたためです。
その情報が第三者にはぱっとわからないので(=マジックナンバーならぬマジックストリング)、情報を付加した方がいいですね。
こちらについて今回のpushでより説明的な形で実装しました。
05.wc/wc.rb
Outdated
|
|
||
| def get_max_width(output_text) | ||
| max_lines_width = output_text.map { |entry| entry[:line].to_s.length + DISPLAY_ADJUST_NUMBER }.max || 0 | ||
| max_words_width = output_text.map { |entry| entry[:word].to_s.length }.max + DISPLAY_ADJUST_NUMBER || 0 |
There was a problem hiding this comment.
| max_words_width = output_text.map { |entry| entry[:word].to_s.length }.max + DISPLAY_ADJUST_NUMBER || 0 | |
| max_words_width = output_text.map { |entry| entry[:word].to_s.length + DISPLAY_ADJUST_NUMBER }.max || 0 |
ここだけこうしないのはなぜ?と思いました
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def get_max_width(output_text) | ||
| max_lines_width = output_text.map { |entry| entry[:line].to_s.length + DISPLAY_ADJUST_NUMBER }.max || 0 |
There was a problem hiding this comment.
改めて考えると特に必要ないと思います。
05.wc/wc.rb
Outdated
| max_lines_width = output_text.map { |entry| entry[:line].to_s.length + DISPLAY_ADJUST_NUMBER }.max || 0 | ||
| max_words_width = output_text.map { |entry| entry[:word].to_s.length }.max + DISPLAY_ADJUST_NUMBER || 0 | ||
| max_bytesizes_width = output_text.map { |entry| entry[:bytesize].to_s.length + DISPLAY_ADJUST_NUMBER }.max || 0 | ||
| { line_display_width: max_lines_width, word_display_width: max_words_width, bytesize_display_width: max_bytesizes_width } |
There was a problem hiding this comment.
max_width[:line_display_width] みたいなキーだとちょっと冗長ですね。
max_width[:line] でも十分かなーと思います
05.wc/wc.rb
Outdated
|
|
||
| def print_output(output_text, max_width) | ||
| output_text.each do |output_line| | ||
| puts format_output_line(output_line, max_width) |
There was a problem hiding this comment.
format_output_line はメソッド化しなくてもいい気がしました
https://bootcamp.fjord.jp/pages/when-you-should-define-method
05.wc/wc.rb
Outdated
|
|
||
| require 'optparse' | ||
|
|
||
| DDISPLAY_ADJUST_LENGTH = 1 |
There was a problem hiding this comment.
| DDISPLAY_ADJUST_LENGTH = 1 | |
| DISPLAY_ADJUST_LENGTH = 1 |
で良かったりしません?
あと、このプログラムには display, print, output という用語が出てきますが、それぞれ意図があって使い分けてますか?(僕からするとどれもほぼ同じ意味に思える)
05.wc/wc.rb
Outdated
| wc_info[:bytesize] = input_text.size if options[:c] | ||
| output_texts << wc_info | ||
| end | ||
| output_texts << file_total_info(output_texts) if output_texts.size > MULTIPLE_DISPLAY |
There was a problem hiding this comment.
2以上なら複数(multiple)というのはある意味当たり前なので、MULTIPLE_DISPLAYという定数名はこれといった情報を提供していないことになります。
なので、定数をなくしても構わないかも?
| output_texts << file_total_info(output_texts) if output_texts.size > MULTIPLE_DISPLAY | |
| output_texts << file_total_info(output_texts) if output_texts.size > 1 |
05.wc/wc.rb
Outdated
| wc_info[:line] = input_text.lines.count if options[:l] | ||
| wc_info[:word] = input_text.split(/\s+/).size if options[:w] | ||
| wc_info[:bytesize] = input_text.size if options[:c] | ||
| output_texts << wc_info |
There was a problem hiding this comment.
左辺と右辺の名前を見直してみましょう。
https://bootcamp.fjord.jp/pages/readable-variable-name
05.wc/wc.rb
Outdated
| output_texts << wc_info | ||
| end | ||
| output_texts << file_total_info(output_texts) if output_texts.size > MULTIPLE_DISPLAY | ||
| max_width = get_max_widths(output_texts) |
There was a problem hiding this comment.
05.wc/wc.rb
Outdated
| file_total_info | ||
| end | ||
|
|
||
| def print_output(output_text, max_width) |
There was a problem hiding this comment.
「printする」と「出力する(output)」はほぼ同じ意味なので、もう少し具体性のあるメソッド名を付けた方がいいかも
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def get_max_widths(output_text) | ||
| max_lines_width = output_text.map { |entry| entry[:line].to_s.length + DDISPLAY_ADJUST_LENGTH }.max |
There was a problem hiding this comment.
+ DDISPLAY_ADJUST_LENGTH の処理は名前からして表示のタイミングで行う処理では?と思いました。
get_max_widthsというメソッド名なら純粋に最大の文字列長を取得する方が驚きが少ないと思います。
05.wc/wc.rb
Outdated
| opt.parse!(argv) | ||
| end | ||
|
|
||
| unless options.key?(:l) || options.key?(:w) || options.key?(:c) |
There was a problem hiding this comment.
| unless options.key?(:l) || options.key?(:w) || options.key?(:c) | |
| if options.empty? |
でも同じかな?
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def file_total_info(output_texts) | ||
| file_total_info = output_texts.inject({}) do |result, hash| |
There was a problem hiding this comment.
メソッド名と同じ変数名は避けましょう
https://qiita.com/jnchito/items/fb438aa0786bb3cbf919
あと、hashという名前も抽象的過ぎるのでもっと具体性のある名前にした方がいいと思います
https://bootcamp.fjord.jp/articles/78
05.wc/wc.rb
Outdated
| file_name = ARGF.filename | ||
| wc_info[:filename] = file_name |
There was a problem hiding this comment.
| file_name = ARGF.filename | |
| wc_info[:filename] = file_name | |
| wc_info[:filename] = ARGF.filename |
変数に入れなくていいかも
05.wc/wc.rb
Outdated
| line = output_line[:line]&.to_s&.rjust(max_width[:line_display_width]) | ||
| word = output_line[:word]&.to_s&.rjust(max_width[:word_display_width]) | ||
| bytesize = output_line[:bytesize]&.to_s&.rjust(max_width[:bytesize_display_width]) | ||
| filename = output_line[:filename] == '-' ? '' : output_line[:filename] |
There was a problem hiding this comment.
なるほどー。
その情報が第三者にはぱっとわからないので(=マジックナンバーならぬマジックストリング)、情報を付加した方がいいですね。
そして今回の提出物ではこの処理がなくなってますね。これはなぜ? 🤔
|
コメントしました! |
|
全体的に |
05.wc/wc.rb
Outdated
| counts = [] | ||
| ARGF.each(nil) do |standard_input_or_file| | ||
| count = {} | ||
|
|
||
| count[:filename] = ARGF.filename | ||
| count[:line] = standard_input_or_file.lines.count if options[:l] | ||
| count[:word] = standard_input_or_file.split(/\s+/).size if options[:w] | ||
| count[:bytesize] = standard_input_or_file.size if options[:c] | ||
| counts << count |
There was a problem hiding this comment.
ここではwcコマンドの実際に行っている処理として"count"が一番適当であると考えて、配列をcountsにして、それぞれの集計値をcountとして格納しました。
また"ARGF.each(nil) do |input_text|"のinput_textが抽象的すぎたため、具体的に入力として考えられる2つの要素「標準入力」「ファイル」を表す名前にしました。
There was a problem hiding this comment.
うーん、standard_input_or_file は逆にちょっと具体的過ぎますね。
input_textの方がまだほどよい抽象度だったように思います。
https://bootcamp.fjord.jp/articles/78
05.wc/wc.rb
Outdated
| rows = counts | ||
| # 複数行出力する場合は、集計行を表示する | ||
| rows << get_wc_total_row(counts) if counts.size > 1 | ||
| max_column_widths = get_max_column_widths(rows) |
There was a problem hiding this comment.
countsに集計行を入れてしまうと、countsの実態から外れてしまうため、rowsに集約する形にしました
05.wc/wc.rb
Outdated
| def get_wc_total_row(counts) | ||
| total_row = counts.inject({}) do |result, column_name| | ||
| result.merge(column_name) { |_key, current_val, adding_value| current_val + adding_value } | ||
| end | ||
| total_row[:filename] = TOTAL | ||
| total_row | ||
| end | ||
|
|
||
| def show_wc_rows(rows, max_column_widths) | ||
| rows.each do |row| | ||
| cells = {} | ||
| row.each_pair do |column_name, cell| | ||
| cells[column_name] = if column_name == :filename | ||
| # 標準入力を受け取る際に例外的に"-"が入力されるため除外する | ||
| cell unless cell == STANDARD_INPUT_EXCEPTIONAL_WORD | ||
| else | ||
| cell.to_s.rjust(max_column_widths[column_name] + SHOW_ADJUST_SPACE_SIZE) | ||
| end | ||
| end | ||
| puts "#{cells[:line]}#{cells[:word]}#{cells[:bytesize]} #{cells[:filename]}" | ||
| end | ||
| end |
There was a problem hiding this comment.
最終出力を行う関数について、イメージとしてexcelの表を考えていたため、変数名にrow.column.cellを採用しました。
rowのhashにアクセスする際のkeyとしては、"column_name"で統一しました。count_nameと悩みましたが、filenameの列も存在するため、より包括的と考えられるcolumnを採用しました。
05.wc/wc.rb
Outdated
| counts = [] | ||
| ARGF.each(nil) do |standard_input_or_file| | ||
| count = {} | ||
|
|
||
| count[:filename] = ARGF.filename | ||
| count[:line] = standard_input_or_file.lines.count if options[:l] | ||
| count[:word] = standard_input_or_file.split(/\s+/).size if options[:w] | ||
| count[:bytesize] = standard_input_or_file.size if options[:c] | ||
| counts << count |
There was a problem hiding this comment.
うーん、standard_input_or_file は逆にちょっと具体的過ぎますね。
input_textの方がまだほどよい抽象度だったように思います。
https://bootcamp.fjord.jp/articles/78
05.wc/wc.rb
Outdated
| count[:bytesize] = standard_input_or_file.size if options[:c] | ||
| counts << count | ||
| end | ||
| rows = counts |
There was a problem hiding this comment.
ある変数を別の変数に入れ替える、ということは滅多にやらないですね。
ここはcountsを使い続けるという形でも良いと思ったのですが、そうしなかった理由はありますか?
There was a problem hiding this comment.
こちらについてですが、
rows << get_wc_total_row(counts) if counts.size > 1の左辺と右辺で実態が異なるように考えたためrowsに書き換えました。
05.wc/wc.rb
Outdated
| counts << count | ||
| end | ||
| rows = counts | ||
| # 複数行出力する場合は、集計行を表示する |
There was a problem hiding this comment.
このコメントはWHYを説明してないので不要ですね。(コードを見ればわかる内容になっている)
https://qiita.com/jnchito/items/f0d90af4ed44b7484103
05.wc/wc.rb
Outdated
|
|
||
| def get_wc_total_row(counts) | ||
| total_row = counts.inject({}) do |result, column_name| | ||
| result.merge(column_name) { |_key, current_val, adding_value| current_val + adding_value } |
There was a problem hiding this comment.
filenameも文字列連結されていくのはちょっとメモリの無駄遣いな気がするのでできたら避けたいですね。
(昨今のマシンスペックならメモリの消費もほとんど問題にならないとはいえ)
05.wc/wc.rb
Outdated
| def show_wc_rows(rows, max_column_widths) | ||
| rows.each do |row| | ||
| cells = {} | ||
| row.each_pair do |column_name, cell| |
There was a problem hiding this comment.
| row.each_pair do |column_name, cell| | |
| row.each do |column_name, cell| |
each_pair を使う人って僕の周りでは見たことがないので、eachの方がいいと思います。
(僕もeach_pairってなんだっけ?と思って調べてしまった)
05.wc/wc.rb
Outdated
| row.each_pair do |column_name, cell| | ||
| cells[column_name] = if column_name == :filename | ||
| # 標準入力を受け取る際に例外的に"-"が入力されるため除外する | ||
| cell unless cell == STANDARD_INPUT_EXCEPTIONAL_WORD |
There was a problem hiding this comment.
| cell unless cell == STANDARD_INPUT_EXCEPTIONAL_WORD | |
| cell unless cell == STDIN_FILENAME |
標準入力は除外するんだなーというのが伝われば十分かも
05.wc/wc.rb
Outdated
| # 標準入力を受け取る際に例外的に"-"が入力されるため除外する | ||
| cell unless cell == STANDARD_INPUT_EXCEPTIONAL_WORD | ||
| else | ||
| cell.to_s.rjust(max_column_widths[column_name] + SHOW_ADJUST_SPACE_SIZE) |
There was a problem hiding this comment.
| cell.to_s.rjust(max_column_widths[column_name] + SHOW_ADJUST_SPACE_SIZE) | |
| hoge = max_column_widths[column_name] + SHOW_ADJUST_SPACE_SIZE | |
| cell.to_s.rjust(hoge) |
変数に入れた方が読みやすそうです
05.wc/wc.rb
Outdated
| end | ||
| end | ||
|
|
||
| def get_max_column_widths(wc_rows) |
There was a problem hiding this comment.
戻り値を返すメソッドは何でも get って名付けられますし、Rubyの場合は get_ や set_ で始まるメソッド名を避ける慣習があるのでget以外の動詞を付けたいですね
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def get_max_column_widths(wc_rows) | ||
| max_lines_width = wc_rows.map { |entry| entry[:line].to_s.length }.max |
There was a problem hiding this comment.
| max_lines_width = wc_rows.map { |entry| entry[:line].to_s.length }.max | |
| max_lines_width = wc_rows.map { |entry| entry[:line].to_s.length }.max |
RuboCopに怒られませんでした?
There was a problem hiding this comment.
こちらに関してですが、修正前のコードでrubocopを実行しても特にエラーは出ませんでした。
見た目として揃っていないので、次回の修正に含めたいと思います。
There was a problem hiding this comment.
うーん、おかしいですね。僕が試したらエラーになりました。
wc.rb:55:60: C: [Correctable] Layout/ExtraSpacing: Unnecessary spacing detected.
max = rows.map { |entry| entry[column_name].to_s.length }.max
^
わざとスペースを追加したコードと、それをrubocopにかけたときの結果をスクショで見せてもらえますか?
あと、以下のコマンドの実行結果も見たいです。
rubocop --show-cops Layout/ExtraSpacing
以下のようにEnabled: trueになっていればこのルールは有効化されているはずです。
$ rubocop --show-cops Layout/ExtraSpacing
# Supports --autocorrect
Layout/ExtraSpacing:
Description: Do not use unnecessary spacing.
Enabled: true
VersionAdded: '0.49'
AllowForAlignment: true
AllowBeforeTrailingComments: false
ForceEqualSignAlignment: false
05.wc/wc.rb
Outdated
|
|
||
| require 'optparse' | ||
|
|
||
| SHOW_ADJUST_SPACE_SIZE = 1 |
There was a problem hiding this comment.
| SHOW_ADJUST_SPACE_SIZE = 1 | |
| SEPARATOR_SIZE = 1 |
これぐらいの名前でも十分かも?
05.wc/wc.rb
Outdated
| count[:bytesize] = input_text.size if options[:c] | ||
| counts << count | ||
| end | ||
| counts << calculate_counts_total(counts) if counts.size > 1 |
There was a problem hiding this comment.
| counts << calculate_counts_total(counts) if counts.size > 1 | |
| counts << calculate_total_counts(counts) if counts.size > 1 |
こっちの方が英語として自然かも
05.wc/wc.rb
Outdated
| counts << count | ||
| end | ||
| counts << calculate_counts_total(counts) if counts.size > 1 | ||
| max_column_widths = calculate_wc_max_column_widths(counts) |
There was a problem hiding this comment.
| max_column_widths = calculate_wc_max_column_widths(counts) | |
| max_widths = calculate_max_widths(counts) |
修飾語は省略できそうです
05.wc/wc.rb
Outdated
|
|
||
| def main | ||
| options = parse_options(ARGV) | ||
| counts = [] |
There was a problem hiding this comment.
左辺と右辺で実態が異なるように考えたためrowsに書き換えました
ここですが、テーブル構造(行と列で構成されるデータ)は例外的に左辺と右辺が異なってもいいと思います。
また、14行目のcountはcountsにした方がハッシュである感が出ると思います。
(countだと1や5みたいな数値が入ってそうに見える)
なので、最初からここはrowsにして、
rows << countsみたいな形で書くのはOKです。
05.wc/wc.rb
Outdated
| end | ||
| counts << calculate_counts_total(counts) if counts.size > 1 | ||
| max_column_widths = calculate_wc_max_column_widths(counts) | ||
| show_wc_rows(counts, max_column_widths) |
There was a problem hiding this comment.
| show_wc_rows(counts, max_column_widths) | |
| show_rows(counts, max_column_widths) |
ここもwcは省略できそう
05.wc/wc.rb
Outdated
| counts_without_filename = counts.map { |count| count.except(:filename) } | ||
|
|
||
| total = counts_without_filename.inject({}) do |result, count| | ||
| result.merge(count) do |_key, current_val, adding_value| | ||
| current_val + adding_value | ||
| end | ||
| end |
There was a problem hiding this comment.
| counts_without_filename = counts.map { |count| count.except(:filename) } | |
| total = counts_without_filename.inject({}) do |result, count| | |
| result.merge(count) do |_key, current_val, adding_value| | |
| current_val + adding_value | |
| end | |
| end | |
| total = counts.inject({}) do |result, count| | |
| result.merge(count) do |key, current_val, adding_value| | |
| current_val + adding_value unless key == :filename | |
| end | |
| end |
こうした方が短くなります。
| column_width = max_column_widths[column_name] + SEPARATOR_SIZE | ||
| cell.to_s.rjust(column_width) | ||
| end | ||
| end |
There was a problem hiding this comment.
参考: eachの代わりにto_hメソッドを使う方法もあります。
cells = row.to_h do |column_name, cell|
value = if column_name == :filename
# ...
[column_name, value]
end
05.wc/wc.rb
Outdated
| cell.to_s.rjust(column_width) | ||
| end | ||
| end | ||
| puts "#{cells[:line]}#{cells[:word]}#{cells[:bytesize]} #{cells[:filename]}" |
There was a problem hiding this comment.
44行目を
" #{cell}" unless cell == STDIN_FILENAMEにすると、ここはまとめてjoinできます。
| puts "#{cells[:line]}#{cells[:word]}#{cells[:bytesize]} #{cells[:filename]}" | |
| puts cells.values_at(:line, :word, :bytesize, :filename).join |
05.wc/wc.rb
Outdated
| count[:filename] = ARGF.filename | ||
| count[:line] = input_text.lines.count if options[:l] | ||
| count[:word] = input_text.split(/\s+/).size if options[:w] | ||
| count[:bytesize] = input_text.size if options[:c] |
There was a problem hiding this comment.
| count[:bytesize] = input_text.size if options[:c] | |
| count[:byte] = input_text.size if options[:c] |
全部4文字にすると見た目にスッキリするかも(些細な改善ですが)
05.wc/wc.rb
Outdated
| def calculate_wc_max_column_widths(rows) | ||
| max_lines_width = rows.map { |entry| entry[:line].to_s.length }.max | ||
| max_words_width = rows.map { |entry| entry[:word].to_s.length }.max | ||
| max_bytesizes_width = rows.map { |entry| entry[:bytesize].to_s.length }.max |
There was a problem hiding this comment.
55-57行目はentryに渡している添え字が違うだけなのでDRYにできそうです
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def get_max_column_widths(wc_rows) | ||
| max_lines_width = wc_rows.map { |entry| entry[:line].to_s.length }.max |
There was a problem hiding this comment.
うーん、おかしいですね。僕が試したらエラーになりました。
wc.rb:55:60: C: [Correctable] Layout/ExtraSpacing: Unnecessary spacing detected.
max = rows.map { |entry| entry[column_name].to_s.length }.max
^
わざとスペースを追加したコードと、それをrubocopにかけたときの結果をスクショで見せてもらえますか?
あと、以下のコマンドの実行結果も見たいです。
rubocop --show-cops Layout/ExtraSpacing
以下のようにEnabled: trueになっていればこのルールは有効化されているはずです。
$ rubocop --show-cops Layout/ExtraSpacing
# Supports --autocorrect
Layout/ExtraSpacing:
Description: Do not use unnecessary spacing.
Enabled: true
VersionAdded: '0.49'
AllowForAlignment: true
AllowBeforeTrailingComments: false
ForceEqualSignAlignment: false
05.wc/wc.rb
Outdated
| keys = rows.map(&:keys).flatten.uniq | ||
| keys.each do |key| | ||
| max_widths[key] = rows.map { |entry| entry[key].to_s.length }.max unless key == :filename | ||
| end |
There was a problem hiding this comment.
keys = rows.map(&:keys).flatten.uniqについて、もっと驚きの少ない実装がないか以下の二通りの方法を考えましたが、要件を満たさなさそうだったため上記を採用しました。
- rows.eachを使う方法
- rowのキーを用いることができても、余分なループが生じてしまうこと
- rows[0]などで最初のハッシュを取得してキーを取得する
- 突然最初のハッシュを取得して唐突に思えること。
- 実質的に上記の案と変わらない。
keys = rows.map(&:keys).flatten.uniqについてkeysをnameとするか迷いましたが、左辺と右辺の一致を考えるとmap(&:keys)が右辺にあるのであれば、左辺にnameが来るのは不自然であると思いkeysを採用しました。
max_widths[key] = rows.map { |entry| entry[key].to_s.length }.max unless key == :filename上記の左辺と右辺は、右側に{....}.maxが存在するためmax_widthで問題ないと判断しました。
05.wc/wc.rb
Outdated
| columns[name] = if name == :filename | ||
| value unless value == STDIN_FILENAME | ||
| else | ||
| column_width = max_column_widths[name] |
There was a problem hiding this comment.
| column_width = max_column_widths[name] | |
| width = max_widths[name] |
ここも修飾語はなくしましょう
05.wc/wc.rb
Outdated
| value.to_s.rjust(column_width) + ' ' * SEPARATOR_SIZE | ||
| end | ||
| end | ||
| puts columns.values_at(:line, :word, :byte, :filename).join |
There was a problem hiding this comment.
で実装してしまうと、以下の通りとなってしまうので
あ、すいません、前回のコード例がちょっと間違ってました。
意図してたコードはこうです。
| puts columns.values_at(:line, :word, :byte, :filename).join | |
| puts columns.values_at(:line, :word, :byte, :filename).join(' ') |
SEPARATOR_SIZE はなくしちゃってもいいかもしれませんね
05.wc/wc.rb
Outdated
| keys = rows.map(&:keys).flatten.uniq | ||
| keys.each do |key| |
There was a problem hiding this comment.
もっと驚きの少ない実装がないか以下の二通りの方法を考えましたが
ここはもっとシンプルに考えていいと思います。
| keys = rows.map(&:keys).flatten.uniq | |
| keys.each do |key| | |
| %i[line word byte].each do |key| |
こんな感じで十分かなと思ったのですが、どうでしょうか?
あと、eachの代わりにto_hを使うとこのメソッドの実装をよりシンプルにできそうです
https://docs.ruby-lang.org/ja/latest/method/Array/i/to_h.html
05.wc/wc.rb
Outdated
| if options.empty? | ||
| options[:l] = true | ||
| options[:w] = true | ||
| options[:c] = true | ||
| end | ||
| options |
There was a problem hiding this comment.
| if options.empty? | |
| options[:l] = true | |
| options[:w] = true | |
| options[:c] = true | |
| end | |
| options | |
| options.empty? ? { l: true, w: true, c: true } : options |
こんな感じにするとよりスッキリするかも
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def calculate_total_rows(rows) | ||
| total = rows.inject({}) do |result, count| |
There was a problem hiding this comment.
| total = rows.inject({}) do |result, count| | |
| total = rows.inject({}) do |result, counts| |
14行目の命名に合わせるならcountsが良さそうです
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def show_rows(rows, max_column_widths) | ||
| rows.each do |row| |
There was a problem hiding this comment.
| rows.each do |row| | |
| rows.each do |counts| |
rowsの中身はcountsと呼ぶ、と一貫性を持たせると良いかもと思いました
| rows = [] | ||
| ARGF.each(nil) do |input_text| | ||
| counts = {} | ||
|
|
||
| counts[:filename] = ARGF.filename | ||
| counts[:line] = input_text.lines.count if options[:l] | ||
| counts[:word] = input_text.split(/\s+/).size if options[:w] | ||
| counts[:byte] = input_text.size if options[:c] | ||
| rows << counts | ||
| end |
There was a problem hiding this comment.
| rows = [] | |
| ARGF.each(nil) do |input_text| | |
| counts = {} | |
| counts[:filename] = ARGF.filename | |
| counts[:line] = input_text.lines.count if options[:l] | |
| counts[:word] = input_text.split(/\s+/).size if options[:w] | |
| counts[:byte] = input_text.size if options[:c] | |
| rows << counts | |
| end | |
| rows = build_rows(options) |
rowsを作る処理もメソッド化するとmainメソッドの見通しが良くなりそうです。
05.wc/wc.rb
Outdated
| columns = {} | ||
| counts.each do |name, value| | ||
| columns[name] = if name == :filename | ||
| value unless value == STDIN_FILENAME |
There was a problem hiding this comment.
正規表現で置き換えるのも一手です。
STDIN_PATTERN = /^-$/
value.sub(STDIN_PATTERN, '')正規表現の見方については https://qiita.com/jnchito/items/893c887fbf19e17d3ff9 のその1とその3をチェックしてみてください
05.wc/wc.rb
Outdated
| columns = {} | ||
| counts.each do |name, value| | ||
| columns[name] = if name == :filename | ||
| value unless value == STDIN_FILENAME | ||
| else | ||
| width = max_widths[name] | ||
| value.to_s.rjust(width) | ||
| end | ||
| end |
There was a problem hiding this comment.
参考:ややトリッキーですが、to_hを使ってかなり行数を減らすこともできます。
| columns = {} | |
| counts.each do |name, value| | |
| columns[name] = if name == :filename | |
| value unless value == STDIN_FILENAME | |
| else | |
| width = max_widths[name] | |
| value.to_s.rjust(width) | |
| end | |
| end | |
| columns = counts.to_h do |name, value| | |
| text = name == :filename ? value.sub(STDIN_PATTERN, '') : value.to_s.rjust(max_widths[name]) | |
| [name, text] | |
| end |
05.wc/wc.rb
Outdated
| max_widths = calculate_max_widths(rows) | ||
| show_rows(rows, max_widths) |
There was a problem hiding this comment.
| max_widths = calculate_max_widths(rows) | |
| show_rows(rows, max_widths) | |
| show_rows(rows) |
rowsだけ渡してもらえればあとはいい感じに出力しておきまっせ、という設計の方がメソッドの再利用性が高そうです
JunichiIto
left a comment
There was a problem hiding this comment.
1点コメントしましたが大きな問題ではないのでこれでOKです!🙆♂️
| rows = [] | ||
| ARGF.each(nil) do |input_text| | ||
| counts = {} | ||
|
|
||
| counts[:filename] = ARGF.filename | ||
| counts[:line] = input_text.lines.count if options[:l] | ||
| counts[:word] = input_text.split(/\s+/).size if options[:w] | ||
| counts[:byte] = input_text.size if options[:c] | ||
| rows << counts | ||
| end |
There was a problem hiding this comment.
| rows = [] | |
| ARGF.each(nil) do |input_text| | |
| counts = {} | |
| counts[:filename] = ARGF.filename | |
| counts[:line] = input_text.lines.count if options[:l] | |
| counts[:word] = input_text.split(/\s+/).size if options[:w] | |
| counts[:byte] = input_text.size if options[:c] | |
| rows << counts | |
| end | |
| rows = ARGF.each(nil).map do |input_text| | |
| counts = { filename: ARGF.filename } | |
| counts[:line] = input_text.lines.count if options[:l] | |
| counts[:word] = input_text.split(/\s+/).size if options[:w] | |
| counts[:byte] = input_text.size if options[:c] | |
| counts | |
| end |
空の配列を用意してループで詰め込むだけの処理はmapで置き換えられます。(チェリー本参照)
あとfilenameは最初から入れてしまうのもアリです



