Ruby

こんにちは、しきゆらです。
今回は、最近意図的に行っている「良いといわれているライブラリのコードを読む」一環として、
Ruby on Railsの便利メソッドの一つ「blank?」の定義を見てみます。

 

なぜこんなことしているの???

私は、これまでライブラリ等を使わずに自分であれこれコードを書いてきました。
しかし、自分の中でいいコーディングの方法が確立できているわけではないので、設計や記述が悪くスクラップ&ビルド状態でうまく作り続けることができませんでした。

そんな中、先輩から「一般的に良いといわれているコードに触れておくと勉強になる」ということを伺い、実践してみようと思い立ったわけです。
読む者は、良く触れるものであれば何かあったときに対応しやすそうだと思ったのでRailsを選びました。
コードが複雑であり、Ruby自体を拡張するというRubyの機能をフル活用しているっぽい印象もあったのも選んだ理由ですね。

 

本題

ここから、実際に定義を見てみます。

今回見ていくメソッドは、ここにあります。

ターゲット:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/object/blank.rb

 

blank?メソッドは、Active Supportの中で定義されていました。
Railsでよく使われる便利メソッドの多くがここで定義されているようです。
Rubyで定義されているメソッドを拡張したり、あると便利な機能をオープンクラスを使って拡張したりと凶悪な側面もあります。

では、実際に中身を見てみます。

 

定義

[ruby]
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
[/ruby]

定義はシンプルですね。
empty?メソッドが定義されていればそれを返し、そうでなければ自分自身の否定を返しています。
つまり、基本的にはempty?と似たような動きをしています。

「自分自身の否定」というのは、例えばRubyの場合は0もtrueとして扱うので「!0」はfalseとして返します。
Rubyのオブジェクトでfalse扱いになるのはfalseとnilだけであり、それ以外のオブジェクトはtrueとして扱われています。

挙動としては、メソッド名の通り「""」のような空文字や空配列など空白であるときにtrueを返します。
便利なところとしては、nilクラスにも定義されているので便利。

[ruby]
class NilClass
  def blank?
    true
  end
end
[/ruby]

NilClassと同様に、TrueClassやFalseClassにも定義されています。
また、ArrayやHashではempty?メソッドのaliasとしてblank?を定義しています。
つまり、どのクラスでも同じメソッドで呼べるようになっています。

注目すべきは、このblank?メソッドはObjectクラスで定義されているということですね。
Rubyで定義されているObjectクラスはすべてのクラスの親クラスなので、どのクラスでも使えるようになります。
便利ですね。

 

オープンクラス

どういうものか、ということは調べるとたくさん資料が出てきますが、簡単に言えば以下の通り。

オープンクラスとは、言語仕様として、クラスや継承やミックスインといった手続きなしに、既存のクラスを自在に拡張するようなコードを書けることを示します。

難しいが強力! Rubyのメタプログラミング、self、特異クラス/メソッド、オープンクラスとモンキーパッチ – @IT

ということで、ArrayやStringなどのRubyが提供しているクラス自体に独自に機能を追加することができるわけです。
頑張れば、メソッド定義などを動的に行うようなこともできてしまいます(いわゆる黒魔術)。
なお、Rubyの+や%など、ほかの言語では演算子と呼ばれるものもメソッドとして定義されているため、安易に上書きするとRuby自体を壊すこともできてしまいます。

Active Supportさんは、この強力であり怖さもあるオープンクラスを利用して、便利機能を追加しているわけです。

 

関連するメソッド

「blank?」に関連して、オブジェクトの存在確認に使われるメソッドとして「present?」があります。
このメソッドの定義も見てみましょう。

定義

[ruby]
def present?
  !blank?
end
[/ruby]

という感じで、blankでなければtrueを返します。
これもObjectクラスで定義されているために、すべてのクラスから利用することができるようになっています。

 

まとめ

さて、今回はRailsさんのコードを読んでみました。
本来であればactive_support.rbから読むべきなんでしょうが、処理が複雑だったり知らない書式が多いと先に進まないので簡単そうな部分から読んでみました。

メソッドの定義自体はシンプルなものであり、どこからでも同じように利用できるように工夫されていました。
こういうものを見ると、便利メソッドでも案外簡単な記述で書かれていることがわかりました。

また、Active Supportのコードを見てみると、実際の記述よりも説明に関するコメントが多いことがわかります。
どのような挙動をするのかを知ることができるので便利です。

今後も、不定期だとは思いますが適宜コードを読んでいこうと思います。
面白そうなものがあれば、またまとめます。

 

今回はここまで。
おわり

Ruby,Windows

こんにちは、しきゆらです。
今回は、Railsさんと仲良くなるための施策として、公式のチュートリアルを進めながら理解を深めていこうと思います。

Railsと戯れることが多いのですが、まだまだ仲がいいとは言えません。
デプロイで苦戦した記憶があるのと、Rails流のお作法をきちんと把握しきれていないことが要因です。
そこで、手軽にできて楽しそうなRailsチュートリアルを一通りふれながらRails流のお作法を学んで行きます。

今回は、Rails Guidesにある「Railsをはじめよう」というものをやっていきます。
基本はガイドにある通りですが、一部違うことをすることがあるかもしれません。
この時はきちんと記載します。

 

0. なぜ本ではなく無料のガイドを使うの?

Railsに強い先輩に、良さげな本はないかを聞いたところ、本よりも公式情報のほうがよい、ということを伺いました。
実際、少し見てみるとブログや技術系サイトの情報よりもわかりやすかった気がします。

あとは、大きい要因としては公式情報なので信用できるはずだからです。
発売されている本は、間違っていないか等をきちんと調査しているとは思いますが、動かなかった場合

  • 自分の環境・記述が悪い
  • 本の内容が間違えている
  • Rails、関連するライブラリのバグ

等々様々な要因が考えられるわけです。

たいていの場合、自分の環境や記述が間違えていることが多いですが、本の内容自体が間違えていることも意外と多くあります。
また、本の場合は情報の更新がされないので、本革のミスの場合は正誤表を確認しながら作業を進めないといけません。
これは面倒ですよね。

その点、Rails Guidesは(ほぼ)公式情報である上に、きちんと最新情報も書かれているようです。
安心感が違いますよね。
一応、公式サイトや定義を確認しようということもいわれたので、公式のものを使っていきます。

では、実際にガイドをもとに作業を進めていきます。

Ruby,Windows,環境構築

2020/08/19 追記

こちらの記事が割と検索に引っかかってみてくれているようなので追記しておきます。
最近関連した記事を追加したので、よろしければこちらもどうぞ。
【Ruby/Win】Windows上のAtomからWSL2上のrubocopを利用する 2020年版

本文

こんにちは、しきゆらです。
今回は、Windows上でRubyの開発環境を整える方法をメモしておきます。

以前までは、DockerやWSLを使って開発ができそうな状態までをメモしてきました。
しかし、少し前に画期的なものがMicrosoftから発表されました。
そう、WSL2です。

以前までのWSL(以下、WSL1)から大きく改善され、個人的には普段使いできるのでは?という状態までなっています。
今回は、WSL2を導入してWindows上でRuby環境を構築、rubocopで変なコードを怒ってもらうところまでをまとめます。

Linux,Ruby,Windows

皆さん、Sinatra使っていますか?
簡単なWebアプリであれば一瞬でできてしまうような、Webアプリケーションフレームワークです。

しかし、簡単なので機能をたくさん増やしていたり、処理が多くなってくるとどうしても起こるのが「全体像が見えにくくなる」ということ。
機能やエンドポイントごとに分割したい、と思うこともあるでしょう。
私は思いました。
その方法を調べてみたので、まとめておきます。

例として、以下のような形でアプリケーションを作成しているとします。

[ruby]
# app.rb
require 'sinatra’
class MyApp < Sinatra::Application
get '/’ do
'hello’
end
end
[/ruby]

今回は、エンドポイントごとにファイルを分割していきます。

 

Ruby,Windows

こんにちは、しきゆらです。

タイトルが長くてよくわからないかもしれません。
問題と解決方法を、メモしておきます。

問題

WSL上にrbenvを用いてRuby2.6.3をインストールして簡単なWebアプリを作成しようとしていました。
適当なディレクトリにbundlerを使ってSinatraとUnicornをインストールし、起動テストを行いました。
最初は問題なくUnicornが起動したので、一度停止させておきました。
再びUnicornを立ち上げると、うまく立ち上がりません。

Unicornはデフォルトではターミナルにエラー等を表示しないので、エラーログをファイルに吐き出すようにしてありました。
エラーログの中には、このようなエラーが記録されていました。
code:error
F, [2019-05-22T22:52:13.998205 #22482] FATAL — : error adding listener addr=/path/to/sinatra_app/tmp/sockets/unicorn.sock
ArgumentError: socket=/path/to/sinatra_app/tmp/sockets/unicorn.sock specified but it is not a socket!

どうやら、ソケットファイルが問題のようです。

解決方法

根本的な解決方法ではありませんが、tmp/sockets/unicorn.sockファイルを削除すると問題なく起動するようになりました。

しかし、再度Unicornを停止した後Unicornを再起動すると再び上記のエラーが表示されます。
Unicorn停止とsockファイルの削除は同時に行うと、無駄な時間がかからないかともいます。

解決方法があればコメントやTwitter等から教えてほしいです。
というか、そもそもsockファイルと普通のファイルの違いなどもきちんと理解できているわけではないので、この辺も含めて調べる必要がありそうです。

今回は、場当たり的な対処法までをまとめておきました。

 

おわり

Ruby

こんにちは、しきゆらです。
今回はタイトルの通り、Rubyで文字列を判定するときに大文字小文字を無視して判定する方法を知ったのでメモしておきます。

記述としては、

[ruby]
/Test/i
[/ruby]

と記述することで

  • test
  • Test
  • TEST

など、大文字小文字を無視して判定してくれるようです。

Rubyの正規表現ページにも書いてありました。
きちんと見ないといけないなぁと、何度目かの反省でした。

 

おわり

Ruby

こんにちは、しきゆらです。
今回は、タイトル通りものづくりの中でよく使うであろうrootパスを取得する方法をメモしておきます。

といっても、今回は「すべてのコマンドや実行はrootディレクトリから行う」という方針で考えています。
これを決めておけば、簡単です。

方法

すべてrootディレクトリから行うと決めてしまえば、難しいことはありません。
RubyさんはDirというディレクトリ操作のためのクラスや、Pathnameというパス名操作のためのクラスがあります。
これらを使えばよいですね。

pwd -> String
カレントディレクトリのフルパスを文字列で返します。

https://docs.ruby-lang.org/ja/latest/method/Dir/s/getwd.html

class Pathname
パス名をオブジェクト指向らしく扱うクラスです。

https://docs.ruby-lang.org/ja/latest/class/Pathname.html

コードは以下の通り。

ROOT_PATH = Pathname.new(Dir.pwd)

Dir.pwdは作業中のディレクトリを取得できるので、Pathnameで囲んでおきます。
これを定義しておけば、読み込みたいファイルをjoinでつなげていけばいいので便利。

 

まとめ

今回は、rootパスを取得する方法をメモしました。
といっても、コマンド実行しているディレクトリをrootパスとして決め撃ちしているので本来の指定方法ではないのかもしれません。

いい方法があれば教えてください。

 

今回は、ここまで。
おわり

JavaScript

こんにちは、しきゆらです。
今回は、DOMに対してクラス名を外す処理とつける処理を1行でやる方法を知ったのでメモしておきます。

DOMへのクラス追加・削除

DOMに対してクラスを追加・削除するには、それぞれadd/removeというメソッドが定義されています。
これらを使えば、動的にDOMのクラスを変更することができます。

しかし、例えば既存のAというクラスを外してBというクラスをつける
という処理を書く場合、素直に書くならば以下のように2行になってしまいます。

dom.classList.remove('A');
dom.classList.add('B');

 

クラスの追加・削除をまとめる

上記のようなコードを1行で書くには、以下の方法で行えます。

dom.classList.replace('A', 'B');

replace( oldClass, newClass )
既存のクラスを新しいクラスで置き換えます。
Element.classList – MDN

MDNを眺めていて見つけました。
知っていなくてもなんとかなるけど、知っているとコードがスッキリするやつですね。
知っているつもりでも、改めて見てみると知らないことがあるので、時々見てみるといいかもしれません。

 

まとめ

今回は、DOMの追加・削除を1行で行うメソッドを発見したのでメモしてみました。
置き換えるという方法でできる処理は1行で書けるので、知っていると少しだけコードが短くなると思います。

 

今回は、ここまで。
おわり

JavaScript

こんにちは、しきゆらです。
今回は、以前に少しだけ触れたparcelを使って開発環境を構築してみました。
また、個人的に以前まで疑問だった、JSとSCSSを用いた場合にどう管理するのか問題を解決することができたので合わせてメモしておきます。

parcelに関しては、以前少しだけ記事にしたことがありました。
=> 以前の記事:【JS】フロントエンド界隈で話題のparcelことはじめ
以前まではWebpackを利用していましたが、難解な設定や多様なプラグイン等、気軽に使うにはハードルが高い状況でした。
そんな中で、parcelは面倒で難解な設定ファイルを作成せずとも、自動で関連するファイルを監視し、変更があれば適宜処理を走らせてくれます。

そんなparcelさんですが、実際にparcelを使ったものづくりをするときにどうすればいいのかわからない部分がありました。
それは、SCSSを使った場合の読み込み方です。
HTMLからSCSSを読み込んでも、ブラウザは反映してくれません。
それをどう読み込めるようにするのかが疑問でした。
これを解決することができたので、合わせて記録しておきます。

Ruby

こんにちは、しきゆらです。

今回は、タイトル通りmysql2のインストールに失敗したのをなんとかする方法をメモしておきます。

環境としては、

  • Mac
  • Ruby2.6.0
  • Rails5.2.2
  • MySQL8.0.13

という状態。

普通にbundle installすると、エラーが。

Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/user_name/path/to/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.2/ext/mysql2
/usr/local/Ruby/bin/ruby -I /usr/local/Ruby/lib/ruby/2.6.0 -r ./siteconf20181231-27997-6j2jh2.rb extconf.rb
--with-ldflags\=-L/usr/local/opt/openssl/lib\ --with-cppflags\=-I/usr/local/opt/openssl/include
checking for rb_absint_size()... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
    --with-opt-dir
    --without-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/usr/local/Ruby/bin/$(RUBY_BASE_NAME)
/usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:467:in `try_do': The compiler failed to generate an executable file. (RuntimeError)
You have to install development tools first.
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:552:in `try_link0'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:570:in `try_link'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:782:in `try_func'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:1069:in `block in have_func'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:959:in `block in checking_for'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:361:in `block (2 levels) in postpone'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:331:in `open'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:361:in `block in postpone'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:331:in `open'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:357:in `postpone'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:958:in `checking_for'
    from /usr/local/Ruby/lib/ruby/2.6.0/mkmf.rb:1068:in `have_func'
    from extconf.rb:25:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can be found here:

/Users/user_name/path/to/vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/mysql2-0.5.2/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in
/Users/user_name/path/to/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.2 for inspection.
Results logged to
/Users/user_name/path/to/vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/mysql2-0.5.2/gem_make.out

An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2

mysql2のインストールに失敗したようです。

調べてみると、以下のような解決方法がいくつも提示されていました。

以下のコードを打ち込む。

bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include

RailsにMySQLを導入したらかなりハマった件について – 大学生Webエンジニアの記録

調べてみると、どうやらbundlerにはgemをビルドするときにフラグやオプションを渡すことができる機能を持っているようです。

上記コードは、mysql2のビルドオプションを渡すコードのようです。

Build Options

You can use bundle config to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem.

bundle config build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config

Bundler: bundle config – Bundler Docs

似たコードが書かれています。

オプションを追加し、再びbundle install。

・・・エラー直らず。

途方に暮れていると、こんな情報が。

ログ見たら –with-cppflags オプションに対応してないとのこと。
ldflagsのみで実行してみる

bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"

mysqlのbundle installに失敗する – Qiita

なんと、cppflagsはいらないようです。

実際、上記の設定後にbundle install すると問題なくインストールできました。

$ bundle install
...
Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Fetching pry 0.12.2
...

先人たちの体験談には頭が上がりません。

感謝です。

今回はここまで。

おわり