ためすう

Ruby で private_class_method を使ってみる

2019-07-16

やったこと

Ruby で private_class_method を使ってみます。

確認環境

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

調査

ruby-private-class-method.rb

class Sample
  def self.hoge
    p __method__
  end

  def self.hoge2
    p __method__
  end

  def hoge3
    p __method__
  end

  private_class_method :hoge
end

検証

$ irb
...

irb(main):007:0> require './ruby-private-class-method'
=> true
irb(main):008:0> Sample.hoge
Traceback (most recent call last):
        4: from /Users/hogehoge/.rbenv/versions/2.6.3/bin/irb:23:in `<main>'
        3: from /Users/hogehoge/.rbenv/versions/2.6.3/bin/irb:23:in `load'
        2: from /Users/hogehoge/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        1: from (irb):8
NoMethodError (private method `hoge' called for Sample:Class)
Did you mean?  hoge2
irb(main):009:0> Sample.hoge2
:hoge2
=> :hoge2
irb(main):010:0> Sample.new.hoge3
:hoge3
=> :hoge3

参考

Ruby で uniq を使ってみる

2019-07-15

やったこと

Ruby で uniq を使ってみます。

確認環境

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

調査

$ irb
irb(main):001:0> p [1, 1, 1].uniq
[1]
=> [1]
irb(main):002:0> p [1, 2, 3, '1'].uniq
[1, 2, 3, "1"]
=> [1, 2, 3, "1"]
irb(main):003:0> p [1, 2, 3, '1'].uniq {|n| n.to_s}
[1, 2, 3]
=> [1, 2, 3]

参考

Ruby で insert を使ってみる

2019-07-15

やったこと

Ruby で insert を使ってみます。

確認環境

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

調査

test.rb

ary = [
  {a: 1},
  {a: 2},
  {a: 3},
]

p ary

ary.insert(1, {a: 999})
p ary

ary.insert(10, {a: 10})
p ary

出力結果

$ ruby test.rb
[{:a=>1}, {:a=>2}, {:a=>3}]
[{:a=>1}, {:a=>999}, {:a=>2}, {:a=>3}]
[{:a=>1}, {:a=>999}, {:a=>2}, {:a=>3}, nil, nil, nil, nil, nil, nil, {:a=>10}]

参考

Ruby で tap を使ってみる

2019-07-14

やったこと

Ruby で tap を使ってみます。

確認環境

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

調査

メソッドチェインの途中で直ちに操作結果を表示するために メソッドチェインに “入り込む” ことが、このメソッドの主目的です。

$ irb
irb(main):001:0> (1..10).tap {|x| puts "original: #{x}" }.
irb(main):002:0* to_a.tap {|x| puts "array: #{x}"}.
irb(main):003:0* select {|x| x.even? }.tap {|x| puts "evens: #{x}"}
original: 1..10
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens: [2, 4, 6, 8, 10]
=> [2, 4, 6, 8, 10]

参考

Ruby で map の &: を使ってみる

2019-07-13

やったこと

Ruby で map(&:) を使ってみます。

確認環境

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

調査

$ irb
irb(main):001:0> numbers = [1, 3, 5, 7]
=> [1, 3, 5, 7]
irb(main):002:0> numbers.map(&:to_s)
=> ["1", "3", "5", "7"]
irb(main):003:0> numbers.map {|i| i.to_s}
=> ["1", "3", "5", "7"]

map メソッドの &: を使うと簡潔に書くことができます。

参考

Rails の config で eager_load を設定してみる

2019-07-13

やったこと

Rails の config で eager_load を設定してみます。

確認環境

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

$ rails --version
Rails 5.2.3

調査

config.eager_load: trueにすると、config.eager_load_namespacesに登録された事前一括読み込み(eager loading)用の名前空間をすべて読み込みます。ここにはアプリケーション、エンジン、Railsフレームワークを含むあらゆる登録済み名前空間が含まれます。

共通で使う、下記のようなファイルを作成します。

app/models/hogehoge/abc.rb

module Hogehoge
  class Abc < Abc
  end
end

config.eager_load = false の時

$ rails c
irb(main):001:0> Object.const_defined?('Hogehoge::Abc')
=> false
irb(main):002:0> Hogehoge::Abc
=> Hogehoge::Abc
irb(main):003:0> Object.const_defined?('Hogehoge::Abc')
=> true

config.eager_load = true の時

$ rails c
irb(main):001:0> Object.const_defined?('Hogehoge::Abc')
=> true

参考

Rails5 の require_dependency を使ってみる

2019-07-11

やったこと

Rails の require_dependency を使ってみます。

確認環境

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

$ rails --version
Rails 5.2.3

調査

クラス名が衝突する

app/controllers/concerns/hoge/piyo_controller.rb

このファイルがロードされる時、Hoge::ApplicationController が呼ばれていないと

::ApplicationController を見に行ってしまいます。

module Hoge
  class PiyoController < ApplicationController
  end
end

app/helpers/application_controller.rb

module Hoge
  class ApplicationController
    def abc
      p "method: #{__method__}"
    end
  end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  def root_app
    p "method: #{__method__}"
  end
end

出力結果

irb(main):009:0> Hoge::PiyoController.new.abc
Traceback (most recent call last):
        1: from (irb):9
NoMethodError (undefined method `abc' for #<Hoge::PiyoController:0x00007fb4244b20c8>)
irb(main):010:0> Hoge::PiyoController.new.root_app
"method: root_app"
=> "method: root_app"

以上より、::ActionController が継承されていることが分かります。

クラス名の衝突を解決する

変更があるファイルだけ載せます。

解決方法は下記の方法があるようでした。

  • 名前空間をきっちり記述する
  • require_dependency を使う

今回は require_dependency を使います。

require_dependency 'app/helpers/application_controller'

module Hoge
  class PiyoController < ApplicationController
  end
end

出力結果

irb(main):012:0> Hoge::PiyoController.new.abc
"method: abc"
=> "method: abc"
irb(main):013:0> Hoge::PiyoController.new.root_app
Traceback (most recent call last):
        1: from (irb):13
NoMethodError (undefined method `root_app' for #<Hoge::PiyoController:0x00007fb423ee5a00>)

Hoge::ApplicationController が継承されていることが分かりました。

ちなみに

Rails がファイルを読み込むときのパスは下記のようになっています。

irb(main):001:0> puts ActiveSupport::Dependencies.autoload_paths
/Users/demo/app/assets
/Users/demo/app/channels
/Users/demo/app/controllers
/Users/demo/app/controllers/concerns
/Users/demo/app/helpers
/Users/demo/app/jobs
/Users/demo/app/mailers
/Users/demo/app/models
/Users/demo/app/models/concerns
/Users/demo/app/workers
/Users/demo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activestorage-5.2.3/app/assets
/Users/demo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activestorage-5.2.3/app/controllers
/Users/demo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activestorage-5.2.3/app/controllers/concerns
/Users/demo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activestorage-5.2.3/app/javascript
/Users/demo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activestorage-5.2.3/app/jobs
/Users/demo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activestorage-5.2.3/app/models
/Users/demo/spec/mailers/previews

参考

Ruby でマジックコメントの frozen_string_literal を使ってみる

2019-07-09

やったこと

Ruby でマジックコメントの frozen_string_literal を使ってみます。

確認環境

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

調査

test.rb

# frozen_string_literal: true

a = 'abc'

puts a.frozen?

puts a.upcase

# 例外が発生します
puts a.upcase!

出力結果

$ ruby test.rb
true
ABC
Traceback (most recent call last):
	1: from ruby-frozen.rb:9:in `<main>'
ruby-frozen.rb:9:in `upcase!': can't modify frozen String (FrozenError)

参考

Ruby で concat を使ってみる

2019-07-08

やったこと

Ruby で concat を使ってみます。

確認環境

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

調査

$ irb
irb(main):001:0> a = [1, 2]
=> [1, 2]
irb(main):002:0> b = [4, 3]
=> [4, 3]
irb(main):003:0> a.concat(b)
=> [1, 2, 4, 3]
irb(main):004:0> a
=> [1, 2, 4, 3]

concat を呼び出した a に破壊的な変更が入ります。

$ irb
irb(main):001:0> a = [1, 2]
=> [1, 2]
irb(main):002:0> b = [8, 9]
=> [8, 9]
irb(main):003:0> a + b
=> [1, 2, 8, 9]
irb(main):004:0> a
=> [1, 2]
irb(main):005:0> b
=> [8, 9]

Array の + を使うと、破壊的な変更を入れずに配列の結合ができます。

参考

Rails で generate コマンドを使った時に自動生成される rspec を制御する

2019-07-07

やったこと

Rails の generate コマンドを使った時、rspec のファイルも自動生成されますが

今回、自動生成される rspec のファイルを制御します。

確認環境

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

$ rails --version
Rails 5.2.3

$ gem list | grep rspec-rails
rspec-rails (3.8.2)

調査

変更前

$ rails g controller Users new
Running via Spring preloader in process 49766
      create  app/controllers/users_controller.rb
       route  get 'users/new'
      invoke  erb
      create    app/views/users
      create    app/views/users/new.html.erb
      invoke  rspec
      create    spec/controllers/users_controller_spec.rb
      create    spec/views/users
      create    spec/views/users/new.html.erb_spec.rb
      invoke  helper
      create    app/helpers/users_helper.rb
      invoke    rspec
      create      spec/helpers/users_helper_spec.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss

変更後

config/application.rb

module Sample2
  class Application < Rails::Application
    # 途中コードはスキップ

    config.generators do |g|
      g.test_framework :rspec,
        fixtures: false,
        view_specs: false,
        helper_specs: false,
        routing_specs: false
    end
  end
end
$ rails g controller Users new
Running via Spring preloader in process 51917
      create  app/controllers/users_controller.rb
       route  get 'users/new'
      invoke  erb
      create    app/views/users
      create    app/views/users/new.html.erb
      invoke  rspec
      create    spec/controllers/users_controller_spec.rb
      invoke  helper
      create    app/helpers/users_helper.rb
      invoke    rspec
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss

参考

  • Everyday Rails - RSpecによるRailsテスト入門 (2. RSpecのインストール)