-
Notifications
You must be signed in to change notification settings - Fork 0
wcコマンドの修正 #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: my-wc
Are you sure you want to change the base?
wcコマンドの修正 #10
Conversation
Define methods directly without defining separate classes or modules. * 05.wc/lib/wc_methods.rb: Remove file. * 05.wc/lib/word_count.rb: Remove file. * 05.wc/wc.rb: Merge into this file.
* 05.wc/wc.rb (#word_count): 上から順番に読めるようになった。 (#word_count_for_string, #word_count_for_string_per_type): Remove method. (#count_newline, #count_word, #count_bytesize): New method.
yoshitsugu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
コメントしました!
| require 'optparse' | ||
|
|
||
| errno = main(ARGV) | ||
| OPTION_STRING = 'lwc' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AVAILABLE_OPTION_CHARS とかですかね。下の DEFAULT_OPTION_CHARS と同じ OPTION_CHARS だとわかるほうがよいかなと思います。
05.wc/wc.rb
Outdated
|
|
||
| option_chars = extract_option_chars(options) | ||
|
|
||
| format_string = generate_format_string(args, option_chars) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここでは args が OptionParser.getopts によって破壊的に変更されていることが前提になっていると思います。こういった実行順により暗黙的に状態が変わってしまうようなコードはあとあと見つけづらいバグを埋めこんでしまう可能性が高いため、できるだけ状態変化が明示的にわかるようなコードにしたほうがよいです。
今回であればたとえば、
def parse_commandline_options
options = OptionParser.getopts(ARGV, OPTION_STRING)
[options, ARGV]
endのように、破壊的変更と外部環境(ARGV)への依存を閉じ込めたメソッドを作ってあげて、
options, filenames = parse_commandline_optionsとするなど、できるだけ明示的なコードになるとよいと思います。
05.wc/wc.rb
Outdated
| option_chars = extract_option_chars(options) | ||
|
|
||
| format_string = generate_format_string(args, option_chars) | ||
| results = word_count_results(args, option_chars) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
何らかの働きをするメソッドは動詞 ( print, load, show など) や動詞 + 目的語 (print_filenames など) という命名にするとわかりやすいです。今回ですと、 count_words_by_options などですかね。
05.wc/wc.rb
Outdated
| option_chars.to_h { [_1, 0] } | ||
| .merge!(*results.filter_map { _1[:count] }) { |_, total, count| total + count } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここもちょっとややこしいので、もうちょっと素朴に書けるかなと思います。
init_value_for_total = option_chars.to_h { [_1, 0] }
count_total = results.each_with_object(init_value_for_total) do |result, total|
option_chars.each do |option|
total[option] += result[:count][option]
end
endなどですかね。
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def word_count_results(parsed_args, option_chars = DEFAULT_OPTION_CHARS) | ||
| paths = parsed_args.empty? ? ['-'] : parsed_args |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
実際に - というファイル名のファイルがあったら困るので、 - は使わないほうがよいと思います。 nil にするとか、文字列じゃないものにしましょう。
05.wc/wc.rb
Outdated
| word_count['l'] = count_newline(lines) if option_chars.include?('l') | ||
| word_count['w'] = count_word(lines) if option_chars.include?('w') | ||
| word_count['c'] = (file?(path) ? size(path) : count_bytesize(lines)) if option_chars.include?('c') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
効率は落ちますが、ここではとりあえず全部計算しておいて、オプションによる条件づけは表示時のみでもよいですよ。
05.wc/wc.rb
Outdated
| num = 0 | ||
| line.split { num += 1 if _1.match?(/[[:graph:]]/) } | ||
| num |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
これってたとえば lines.flat_map(&:split).compact.count とかではだめなんでしょうか。
ただ空白で分割して数える、のほうが素直に思いました。
05.wc/wc.rb
Outdated
| end | ||
|
|
||
| def count_newline(lines) | ||
| lines.sum { |line| line.count("\n") } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lines.count ではダメなんでしたっけ?
05.wc/wc.rb
Outdated
| def calc_digit(parsed_args) | ||
| paths = parsed_args.empty? ? ['-'] : parsed_args | ||
|
|
||
| default_digit = paths.any? { exist_non_regular_file?(_1) } ? 7 : 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
今回はプラクティスなので、通常ファイル以外がわたされた場合はあまり考えなくてよいです。
また、やるとしてもただエラー表示するだけでよいかなと思います。
05.wc/wc.rb
Outdated
| format_string = Array.new(enabled_option_count, "%#{digit}d") | ||
|
|
||
| format_string << '%s' unless parsed_args.empty? | ||
|
|
||
| format_string.join(' ') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%dや%sなどの表記は慣れていないと読みづらいので、 rjust などで対応できるならそちらのほうがよいのですが、どうでしょうか。
* 05.wc/wc.rb (#main) <init_value_for_total, count_total>: Separate the initial value and the total processing. (#word_count_results): Create `Hash` simply.
* 05.wc/wc.rb (#main): No arguments are required as `ARGV` is used within the method. (#parse_commandline_options): New method. (#generate_format_string, #calc_digit, #word_count_results): Rename argument.
* 05.wc/wc.rb (#word_count) <buf>: Use `String` instead of `[String]`. (#count_newline, #count_word, #count_bytesize): Stop using `Array#sum`.
* 05.wc/wc.rb (#calc_digit, #word_count_results): Stop treating '-' as standard input. <paths>: Do not rewrite this argument. (#stdin?, #exist_non_regular_file?, #exist?, #regular_file_size) (#file?, #size): Remove unused method. (#word_count): Change the return value to nested `Hash`.
Use `Hash#values_at` or `String#rjust` instead of. * 05.wc/wc.rb (#generate_format_string, #word_count_results) (#print_word_count_result): Remove method. (#main): Extract the process to output the count and its total. <counts>: New variable. (#count_newline_word_byte): Similar to `#word_count`, but counts all items (newline, word, and byte). (#print_counts, #stdin?, #total_counts): New method. (#calc_digit): Change arguments and processing for use with `#print_counts`.
|
@yoshitsugu お疲れさまです。レビューしていただき、ありがとうございます!
|
なるほど。つまり
うーん、それは僕の当初の指摘に答えていないように思います。「こういう実装が既にあるからこうした」というのは、その説明だけ見ると、自分の考えがないように思います。例えば、「今の実装にあるメリットはXXXで、 |
ペアプロでいただいたアドバイスを元に修正した。