動機
スクレイピング結果をTSVで保存していくが、5回目ぐらいからcol_sep: "\t"
を書くのが苦痛になってきた。
require "tsv"; tsv = TSV.open("path/to/file.tsv", "w");
みたいに書きたい!書いてやる!!!
解答
ご自身のsite_ruby
フォルダに下記のファイルを配置するだけ。
# frozen_string_literal: true
require "csv"
class TSV < CSV
DEFAULT_OPTIONS = {
col_sep: "\t",
row_sep: :auto,
quote_char: '"',
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
header_converters: nil,
skip_blanks: false,
force_quotes: false,
skip_lines: nil,
liberal_parsing: false,
quote_empty: true,
}.freeze
def initialize(data,
col_sep: "\t",
row_sep: :auto,
quote_char: '"',
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
write_headers: nil,
header_converters: nil,
skip_blanks: false,
force_quotes: false,
skip_lines: nil,
liberal_parsing: false,
internal_encoding: nil,
external_encoding: nil,
encoding: nil,
nil_value: nil,
empty_value: "",
quote_empty: true)
super
end
end
解答に至るまで
CSVライブラリでcol_sep: "\t"
と指定されていれば、望むTSVライブラリそのものです。
CSVライブラリで用いられるキーワード引数のデフォルト値だけ変更したTSVクラスを定義し、そのファイルを$:
(= $LOAD_PATH
= $-I
)のどこかに配置すれば良いでしょう。
CSVライブラリの観察
まずCSVライブラリがどこにあるのかを探します。
ライブラリがどこにあるのか探すコマンド gem which
を用いましょう。
>gem which csv
C:/Ruby261-x64/lib/ruby/2.6.0/csv.rb
# こんな感じに配置されている
C:/Ruby261-x64/lib/ruby/2.6.0
├── 他のファイル・ディレクトリ郡
├── csv.rb
└── csv
├── core_ext
│ ├── array.rb
│ └── string.rb
├── fields_converter.rb
├── match_p.rb
├── parser.rb
├── row.rb
├── table.rb
├── version.rb
└── writer.rb
これらのファイルからキーワード引数col_sep
と重要そうな部分だけ見ていきます。
class CSV
# 略
DEFAULT_OPTIONS = {
col_sep: ",", # ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
row_sep: :auto,
quote_char: '"',
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
header_converters: nil,
skip_blanks: false,
force_quotes: false,
skip_lines: nil,
liberal_parsing: false,
quote_empty: true,
}.freeze
# 略
def initialize(data,
col_sep: ",", # ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
row_sep: :auto,
quote_char: '"',
field_size_limit: nil,
converters: nil,
unconverted_fields: nil,
headers: false,
return_headers: false,
write_headers: nil,
header_converters: nil,
skip_blanks: false,
force_quotes: false,
skip_lines: nil,
liberal_parsing: false,
internal_encoding: nil,
external_encoding: nil,
encoding: nil,
nil_value: nil,
empty_value: "",
quote_empty: true)
raise ArgumentError.new("Cannot parse nil as CSV") if data.nil?
# create the IO object we will read from
@io = data.is_a?(String) ? StringIO.new(data) : data
@encoding = determine_encoding(encoding, internal_encoding)
@base_fields_converter_options = {
nil_value: nil_value,
empty_value: empty_value,
}
@initial_converters = converters
@initial_header_converters = header_converters
@parser_options = {
column_separator: col_sep, # ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
row_separator: row_sep,
quote_character: quote_char,
field_size_limit: field_size_limit,
unconverted_fields: unconverted_fields,
headers: headers,
return_headers: return_headers,
skip_blanks: skip_blanks,
skip_lines: skip_lines,
liberal_parsing: liberal_parsing,
encoding: @encoding,
nil_value: nil_value,
empty_value: empty_value,
}
@parser = nil
@writer_options = {
encoding: @encoding,
force_encoding: (not encoding.nil?),
force_quotes: force_quotes,
headers: headers,
write_headers: write_headers,
column_separator: col_sep, # ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
row_separator: row_sep,
quote_character: quote_char,
quote_empty: quote_empty,
}
@writer = nil
writer if @writer_options[:write_headers]
end
# 略
end
他に重要そうなファイルはありませんでした。
csv.rb
のDEFAULT_OPTIONS
とinitialize
のcol_sep
の値を変更すれば良さそうです。
TSVライブラリを作る
わざわざCSVライブラリを構成する全ファイルをどこかにコピーして編集して…なんて面倒です。
CSVクラスを継承したTSVクラスを定義し、col_sep
の部分だけ変えます。
コードは解答を参照。
引数のデフォルト値を変えただけなので、initialize
の中身はただのsuper
でOKです。
super
は、メソッド呼び出し(super・ブロック付き・yield) (Ruby 2.6.0)で以下のように書かれています。
super は現在のメソッドがオーバーライドしているメソッドを呼び出します。括弧と引数が省略された場合には現在のメソッドの引数がそのまま引き 渡されます。
TSVライブラリをrequire
できる場所に配置する
自分の環境でrequire
できる場所がどこか確認してみます。
>ruby -e 'puts $:'
C:/Ruby261-x64/lib/ruby/gems/2.6.0/gems/did_you_mean-1.3.0/lib
C:/Ruby261-x64/lib/ruby/site_ruby/2.6.0
C:/Ruby261-x64/lib/ruby/site_ruby/2.6.0/x64-msvcrt
C:/Ruby261-x64/lib/ruby/site_ruby
C:/Ruby261-x64/lib/ruby/vendor_ruby/2.6.0
C:/Ruby261-x64/lib/ruby/vendor_ruby/2.6.0/x64-msvcrt
C:/Ruby261-x64/lib/ruby/vendor_ruby
C:/Ruby261-x64/lib/ruby/2.6.0
C:/Ruby261-x64/lib/ruby/2.6.0/x64-mingw32
置き場所が沢山あって困りますね。variable $-I (Ruby 2.6.0)を参考にしましょう。
私はベンダーでもないですし、TSVライブラリはCSVライブラリに依存しているのでバージョン依存でもないでしょう。
site_ruby
(C:/Ruby261-x64/lib/ruby/site_ruby
)に配置することにしました。
anyenv
やrbenv
を使用している場合は、環境変数RUBYLIB
を設定し、そこに配置すればOKです。
参考:環境変数 (Ruby 2.6.0)
感想
EASYで助かった。