ためすう

Ruby でファイルを操作する

2019-05-14

やったこと

Ruby でファイルの書き込み、読み込み、削除をやってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

ファイルの書き込み

File.open('test.md', 'w') do |file|
  file.puts 'hogehoge'
end

ファイルの読み込み

File.open('test.md', 'r') do |file|
  file = file.read
  p file
end

ファイルの削除

File.delete('test.md')

ファイルの存在チェック

if File.exist?('test.md')
  p 'test.md is exist'
end

参考

Rails5 でコールバックを使う

2019-05-14

やったこと

Rails5 で Active Record のコールバックを使ってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

コールバックについて

コールバックとは、オブジェクトのライフサイクル期間における特定の瞬間に呼び出されるメソッドのことです。コールバックを利用することで、Active Recordオブジェクトが作成/保存/更新/削除/検証/データベースからの読み込み、などのイベント発生時に常に実行されるコードを書くことができます。

動作確認

今回は、 after_initialize を使ってみます。

app/controllers/tasks_controller.rb

class TasksController < ApplicationController
  def index
    @task = Task.new
  end
end

app/models/task.rb

class Task < ApplicationRecord
  after_initialize :hogehoge

  def hogehoge
    logger.debug('called hogehoge with after_initialize')
  end
end

after_initialize を使えば、initialize をオーバーライドしなくても良くなります。

after_initializeコールバックは、Active Recordオブジェクトが1つインスタンス化されるたびに呼び出されます。インスタンス化は、直接newを実行する他にデータベースからレコードが読み込まれるときにも行われます。これを利用すれば、Active Recordのinitializeメソッドを直接オーバーライドせずに済みます。

参考

第1章 Python ではじめる機械学習 (実践機械学習システム)

2019-05-12

メモ

機械学習の目的は、データの裏側に潜むパターンや関係性を学ぶことで、データについてより深い洞察を得ることです。

作業の流れ

  1. データを読み込み、データを整形する
  2. 入力データの調査および解釈を行う
  3. 学習アルゴリズムにどのような形でデータを入力するのが相応しいか分析を行う
  4. 正しいモデルと学習アルゴリズムを選択する
  5. 結果に対して正確な評価を行う

改良したデータに対して単純なアルゴリズムを用いるほうが、生データに対して洗練されたアルゴリズムを用いるより、結果が良いことがほとんど です。

データを改良する行為を「特徴エンジニアリング (feature engineering)」と呼ばれます。

機械学習の初心者にとって最も間違いを起こしやすい場所は、性能を評価する段階です。

たとえば、まず全データの数%だけを保持 (ホールドアウト) しておき、残りのデータを使って学習を行うとします。そして保持したデータを用い て誤差を計算するのです。

まとめ

大切なこと

  • 機械学習の作業において最も大切なことは、データを理解しデータを扱いやすい形に整形すること。
  • 正しい評価を行うこと。正しい評価を行うにあたって、訓練データとテストデータを区別する。

参考

  • 実践機械学習システム

Ruby で inject を使う

2019-05-12

やったこと

Ruby で inject メソッドについて調べます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

inject は

リストのたたみこみ演算を行います。

$ rails c
irb(main):001:0> [1, 3, 5].inject { |result, item| result + item }
=> 9
irb(main):002:0> [1, 3, 5].inject { |result, item| result + item**2 }
=> 35
irb(main):003:0> [1, 3, 5].inject(10) { |result, item| result + item**2 }
=> 45
irb(main):004:0> [1, 3, 5].inject(:+)
=> 9

ちなみに、同じ処理をするために each を使っても出来ます。

参考

Rails5 で rescue_from を使う

2019-05-12

やったこと

Rails5 の rescue_from メソッドについて調べます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

app/controllers/tasks_controller.rb

class TasksController < ApplicationController
  rescue_from Exception, with: :render_500

  def index
    raise Exception.new
  end

  def render_500
    logger.debug('render_500')
  end
end

※ 任意のコントローラに記述してください

注意点

ApplicationControllerクラスでは一部の例外についてrescueできないものがあります。その理由は、コントローラが初期化されてアクションが実行される前に発生する例外があるからです。

と説明があるので、コントローラが初期化される前に、例外が発生した場合は捕捉できない場合があります。

参考

Ruby でキーワード引数を使う

2019-05-12

やったこと

キーワード引数を使ってみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

test.rb

class Sample
  def initialize(params)
    p params

    # a を取りだす
    p params[:a]
  end
end

Sample.new(a: 111, b: 222)

出力結果

$ ruby test.rb
{:a=>111, :b=>222}
111

情報を探しても見つかりませんでしたが、関数の引数に ** を付きなくても キーワード引数のハッシュとして、扱えるようです。

Rails5 で try を使う

2019-05-12

やったこと

try メソッドについて調べます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

レシーバーのクラスがnilの場合

$ rails c
irb(main):001:0> @number.try(:nest)
=> nil
irb(main):002:0> @number.try!(:nest)
=> nil

try, try! のどちらを使っても nil が返されました。

レシーバーのクラスが存在する場合

$ rails c
Running via Spring preloader in process 21611
Loading development environment (Rails 5.2.3)
irb(main):001:0> class Sample
irb(main):002:1>   def nest
irb(main):003:2>     p 3
irb(main):004:2>   end
irb(main):005:1> end
=> :nest
irb(main):006:0> @number = Sample.new
=> #<Sample:0x00007f96c024adc0>
irb(main):007:0> @number.try!(:nest)
3
=> 3
irb(main):008:0> @number.try!(:nest_nothing)
Traceback (most recent call last):
        1: from (irb):8
NoMethodError (undefined method `nest_nothing' for #<Sample:0x00007f96c024adc0>)
irb(main):009:0> @number.try(:nest)
3
=> 3
irb(main):010:0> @number.try(:nest_nothing)
=> nil

try だと存在しないメソッドを呼び出そうとしても nil が返されることが分かります。

try について

nilでない場合にのみオブジェクトのメソッドを呼び出したい場合、最も単純な方法は条件文を追加することですが、どこか冗長になってしまいます。そこでtryメソッドを使うという手があります。tryはObject#sendと似ていますが、nilに送信された場合にはnilを返す点が異なります。

tryメソッドは、NoMethodErrorを握りつぶして代わりにnilを返す点に注意が必要です。メソッド名の誤りを防ぎたい場合はtry!を使います。

try を使うには、 Active Support を読み込んでおく必要があります。

Rails の場合は、すぐに使えるようです。

Ruby on Railsアプリケーションでは、基本的にすべてのActive Supportを読み込みます。

参考

Ruby での参照渡しについて

2019-05-10

やったこと

Ruby での参照渡しについて、調べてみます。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

調査

関数に渡す引数の変数について、object_id を調べてみます。 また変数の代入もしてみます。

test.rb

def test(a, b)
  p "a: #{a.object_id} in test"
  p "b: #{b.object_id} in test"
end

a = 1
b = 2

c = b

p "a: #{a.object_id}"
p "b: #{b.object_id}"
p "c: #{c.object_id}"

test(a, b)

出力結果

$ ruby test.rb
"a: 3"
"b: 5"
"c: 5"
"a: 3 in test"
"b: 5 in test"

どうやら、引数として渡す前、渡した後のオブジェクトは同じもののようです。

つまり、引数に対して関数内で引数のオブジェクトに直接変更を加えると 関数を抜けた後も影響を受けます。

test.rb

def test2(a, b)
  a.upcase!
end

a = 'abc'
b = 'jkl'

test2(a, b)

p a
p b

出力結果

"ABC"
"jkl"

参考

class Object (Ruby 2.6.0)

Rails5 でエラーページを表示する

2019-05-09

やったこと

Rails5 にて、エラーページを表示する方法を調べました。

静的なページ、動的なページのどちらにするかで方法が変わります。

確認環境

$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

静的なページを表示

すでに用意されているものを利用します。

config/environments/development.rb

config.consider_all_requests_local = false

例えば存在していないページにアクセスした時、 public/404.html が使われます。

動的なページを表示

config/environments/development.rb

config.consider_all_requests_local = false

エラーページの view を用意します。

app/views/errors/error_404.html.erb

404 dayo

例外を制御します。今回は 404エラーの時の振る舞いを定義します

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  rescue_from ActionController::RoutingError, with: :render_404

  def render_404
    logger.debug(9999)
    render template: 'errors/error_404', status: 404, layout: 'application',  content_type: 'text/html'
  end
end

最後にルーティングの一番下に下記を追加してください

config/routes.rb

get '*path', controller: 'application', action: 'render_404'

参考

Rails5 で日付のバリデーションを行う

2019-05-09

やったこと

Rails5 で日付、日時をフォーマットする方法を調べます。

確認環境

$ ruby --version
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin17]

$ rails --version
Rails 5.2.3

調査

やったこと

Rails5 ではデフォルトで日付のバリデーションがないようなので、実装方法を調べました。

task.expire_date という タスクの有効期限について、日付のバリデーションをかけます。

調査

app/models/task.rb

class Task < ApplicationRecord
  validate :expire_date_is_valid?

  private
  def expire_date_is_valid?
    begin
      Date.parse self.expire_date.to_s if self.expire_date.present?
    rescue ArgumentError
      errors.add(
        :expire_date,
        '無効な日付です'
      )
    end
  end
end

Date.parse の挙動も試してみました。

$ rails c

irb(main):001:0> Date.parse(888)
Traceback (most recent call last):
        2: from (irb):1
        1: from (irb):1:in `parse'
TypeError (no implicit conversion of Integer into String)
irb(main):002:0> Date.parse('20190509')
=> Thu, 09 May 2019
irb(main):003:0> Date.parse('2019-05-09')
=> Thu, 09 May 2019
irb(main):004:0> Date.parse('19-05-09')
=> Thu, 09 May 2019
irb(main):005:0> Date.parse('9919-05-09')
=> Fri, 09 May 9919
irb(main):006:0> Date.parse('11')
=> Sat, 11 May 2019

これをみると、厳密なチェックは出来ていないので、使用するときは注意してください。

参考