Ruby

ruby まあまあ使う自作のメソッドをまとめたメモ

モジュールは適当にrequireする。ruby ver = 2.5.0
ネーミングセンスは皆無なのでアドバイス希望。
より良い書き方のアドバイスも希望。

hashをjson形式でファイル出力するやつ

  def dump_hash2json(filename, hash, writetype = 'w')
    File.open(filename, writetype) do |file|
      JSON.dump(hash, file)
    end
  end

json形式のファイルをhashとして読み込むやつ

  def load_json2hash(filename)
    File.open(filename) do |file|
      JSON.load(file)
    end
  end

配列をcsv形式でファイル出力する

  def dump_csv(filename, writedata, writetype = 'w')
    CSV.open(filename.dup, writetype) do |csv|
      writedata.each do |arr|
        csv << [arr]
      end
    end
  end

ディレクトリ内の正規表現にマッチしたファイル名を取得するやつ

  def get_filenames_matching_regexp(dirpath, regexp)
    Dir.open(dirpath).to_a.grep(/#{regexp}/)
  end

外部コマンド実行

  def mypopen3(cmd)
    Open3.popen3(cmd) do |_stdin, stdout, stderr, _wait_thr|
      begin
        loop do
          IO.select([stdout, stderr]).flatten.compact.each do |io|
            io.each do |line|
              puts line
            end
          end
          break if stdout.eof? && stderr.eof?
        end
      end
    rescue EOFError
    end
  end

ファイル削除

inputinfoがstringかarrayかで処理を分けている

  def mydisplay(level, arg)
    puts "#{level}: #{mytime} #{arg}"
  end

  def mytime
    tm = Time.now
    tm.strftime('%Y-%m-%dT%H:%M:%S.%6N')
  end

  def rmv_files(inputinfo, dirpath = './')
    mydisplay('INFO', "removing.. #{dirpath}, #{inputinfo}")
    intype = inputinfo.class
    if intype == String
      FileUtils.rm_f(Dir.glob("#{dirpath}/#{inputinfo}"))
    elsif intype == Array
      if inputinfo.is_a?(Array)
        inputinfo.map! { |v| FileUtils.rm_f(Dir.glob("#{dirpath}/#{v}")) }
      end
    end
  end

ファイル移動

  def mv_file(path_from, path_to)
    FileUtils.mv(Dir.glob(path_from), path_to)
  end

ファイルに追加

  def add_file(filename, message)
    mydisplay('INFO', "adding.. #{filename}")
    File.open(filename, 'a') do |f|
      f.puts(message)
    end
  end

ディレクトリ作成

  def create_dir(dirpath)
    FileUtils.mkdir_p(dirpath, mode: 755)
  end

zip解凍

  def uncompress(path, outpath)
    entrys = []
    mydisplay('INFO', "unzipping.. #{path}")
    Dir.mkdir(outpath) unless Dir.exist?(outpath)
    Zip::InputStream.open(path, 0) do |input|
      while (entry = input.get_next_entry)
        save_path = File.join(outpath, entry.name)
        File.open(save_path, 'w') do |wf|
          wf.puts(input.read)
        end
        entrys << save_path
      end
    end
    entrys
  end

入れ子のhashから値をとってくるやつ

require 'active_support'
require 'active_support/core_ext'

class Hash
  def get_nested_value(str)
    keys = str.split(',')
    v = self.with_indifferent_access # need active_support
    keys.each do |i|
      v = v[i.to_s]
    end
    v
  end
end

hash = {a: "test", "b": {c: "testtest", d: {e: "testtesttest"}}}

p hash.get_nested_value('a')
p hash.get_nested_value('b,c')
p hash.get_nested_value('b,d,e')

ymlの設定ファイルを読み込むやつ

  def load_yml_settings(path)
    Hashie::Mash.load("#{path}")
  end

postgres操作のなんやかんや

以下の例は環境変数から設定を読み込んでいるので適宜変える。
\copyなどは\のせいで使えなかった。

  def myconnection
    dbhost = ENV['DB_HOST']
    dbuser = ENV['DB_USER']
    dbpass = ENV['DB_PASS']
    dbname = ENV['DB_DBNAME']
    dbport = ENV['DB_PORT']
    connection = PG.connect(host: dbhost,
                            user: dbuser,
                            password: dbpass,
                            dbname: dbname,
                            port: dbport)
    mydisplay('INFO', "DB_CONNECT: #{dbuser}@#{dbhost}:#{dbport} #{dbname}")

    connection.exec('START TRANSACTION ISOLATION LEVEL READ COMMITTED;')
    #connection.exec('SAVEPOINT test001;')
    mydisplay('INFO', "TRANSACTION_STATUS: #{connection.transaction_status}")
    connection
  end

  def endconnection(con)
    mydisplay('INFO', 'DB_CONNECT_END:')
    con.exec('COMMIT;')
  end

  def abortconnection(con)
    mydisplay('INFO', 'DB_ROLLBACK: TRANSACTION ERROR.')
    con.exec("ROLLBACK;")
    #con.exec('ROLLBACK TO test001;')
  end

  def insert_cmd(con, table, head, value)
    cmd = %(insert into #{table}
               #{head}
             values
               (#{value});
    )
    begin
      mydisplay('INFO', "DB_EXEC: #{cmd}")
      con.exec(cmd)
    rescue StandardError => e
      mydisplay('ERR!', "DB INSERT FAILED #{e.backtrace}")
      abortconnection(con)
      add_file("#{ENV['DB_LOG']}/DBERRINFO", e.backtrace.to_s)
      exit 1
    end
  end

  # 配列の各要素をシングルクォーテーションで囲わないとエラーが出た。。
  def get_value_for_insert_db(arr)
    arr.map { |v| "'#{v}'" }.join(', ')
  end

  def get_latest_id(con, table, idname)
    cmd = "select MAX(#{idname}) from #{table}"
    begin
      mydisplay('INFO', "DB_EXEC: #{cmd}")
      rslt = con.exec(cmd)
      return rslt.max.values.join('')
    rescue StandardError => e
      mydisplay('ERR!', "GET ID FAILED #{e.backtrace}")
      abortconnection(con)
      add_file("#{ENV['DB_LOG']}/DBERRINFO", e.backtrace.to_s)
      exit 1
    end
  end

  # テーブルinsertの例
  def insert_test(dbcon, yml, arr)
    table = "#{yml.test[0]}"
    tmp = ['id001','test','hogehoge']
    value = get_value_for_insert_db(tmp)
        insert_cmd(dbcon, table, yml.test[1], value)
      end
    end
  end

  # ymlの例
  # test: ["test_table","(id, testname, contents)"]
  # ...