yucatio@システムエンジニア

趣味で作ったものいろいろ

RubyMineでRuby on railsの開発をする その2: bundle install の実行

前回の記事で、railsのプロジェクトフォルダの作成(rails new)を行うことができました。

yucatio.hatenablog.com

さっそく自分のアプリを作るぞ、と思いましたが、新しいことを一気に始めると混乱するので、まずはRubyMineを使用して、"パーフェクトRuby on Rails" に掲載されているサンプルアプリ (awesome_events) を作成します。

GemFileの書き換えとbundle install

必要なGemをGemFileに記載します。(slim-rails だけ本とは違います)

f:id:yucatio:20170129223749p:plain

bundle installを行います。 Tools > Bundler > Install を選択します。 f:id:yucatio:20170129224220p:plain

オプション画面が開きます。今回は何も入力せずにInstallボタンを押します。 f:id:yucatio:20170129225235p:plain

bundle installが実行されました。 f:id:yucatio:20170129225011p:plain

次回に続きます。

yucatio.hatenablog.com

環境

RubyMineでRuby on railsの開発をする その1: RubyMineインストールとプロジェクトの作成

JavaからRubyにきて困ったことの1つは、無料のIDEが無いことです。eclipseの便利さになれきった自分には、vimのカスタマイズがおっくうに感じられてしまいました。コマンドラインでいちいちrailsのコマンド入力するのも面倒。 (でもこの、面倒って思う気持ちはエンジニアとして大切だと思う。)

というわけで、有料ですが、RubyMineをいれてみることにしました。

RubyMineのインストール

まずは30日の無料体験版をインストール。

www.jetbrains.com

GET FREE 30-DAY TRIAL からインストールします。

新規プロジェクトの作成

インストールが終わったら起動します。

f:id:yucatio:20170115230518p:plain

Create New Project (プロジェクトの新規作成) を選びます。

f:id:yucatio:20170115230745p:plain

Location (プロジェクトフォルダ)、SDKrailsのバージョン、DBの種類を選びます。

今回はminitestでなくrspecを使用するので、Skip Test::Unit files にチェックを入れます。

rails new が実行され、railsディレクトリが作成されました。

f:id:yucatio:20170115232624p:plain

rails server の実行

サーバを起動してみます。

Run > Run ‘Development: awesome_events’ で起動します。 f:id:yucatio:20170116001600p:plain

Run ‘Development: awesome_events' がない場合は、Run > Run… でダイアログを開き、Run 'Development: awesome_events’ を選択します。 f:id:yucatio:20170116001612p:plain f:id:yucatio:20170116001625p:plain

rails server が実行され、デフォルトのrailsの画面が表示されました。 f:id:yucatio:20170116001657p:plain f:id:yucatio:20170116001709p:plain

サーバを停止するには、Run > Stop ‘Development: awesome_events’ を選択します。 f:id:yucatio:20170116001725p:plain

次回に続きます

yucatio.hatenablog.com

環境
  • Mac : Sierra 10.12.2
  • Ruby : 2.3.3
  • Rails : 4.2.6
  • RubyMine : 2016.3.1

頭の体操[初級] 連続したフィールドの入力で、途中の未入力欄を検知 (Ruby編)

前回の記事の続きです。

yucatio.hatenablog.com

入力の途中で空欄があったらエラーメッセージを表示する機能を実装します。

f:id:yucatio:20160718141604p:plain

実装してみよう

サンプルとして、以下のようなメソッドを作成します。

  • 引数にStringの配列を受け取る
  • 配列の途中に空文字があり、その欄より後に空文字でない要素がある場合は、エラーメッセージを表示する。メッセージ中には何番目の要素がエラーかを表示する。

こんな動作イメージです

arr = ["佐藤", "鈴木", "高橋", "", "伊藤", "", "", "", "", ""]
detect_empty_field arr

# OUTPUT
# 4番目のフィールドが空です。値を入力してください。

簡単のために、以下を前提とします。

  • 引数で渡される配列はnilではない
  • 配列中の各要素はnilでない
  • 配列の各要素はString

この記事ではRubyで実装します。

実装は続きを読むをどうぞ

続きを読む

頭の体操[初級] 連続したフィールドの入力で、途中の未入力欄を検知 (Java編)

以前に、仕事で以下のような挙動をする処理を書く必要がありました(正確には、後輩が実装して自分はレビュー担当)。連続して値を入れるような入力欄で、途中で入力が空になっている場所を検知します。

f:id:yucatio:20160723111152p:plain

実装してみよう

サンプルとして、以下のようなメソッドを作成します。

  • 引数にStringの配列を受け取る
  • 配列の途中に空文字があり、その欄より後に空文字でない要素がある場合は、エラーメッセージを表示する。メッセージ中には何番目の要素がエラーかを表示する。

こんな動作イメージです

detectEmptyField02(new String[]{"佐藤", "鈴木", "高橋", "", "伊藤", "", "", "", "", ""});

// OUTPUT
// 4番目のフィールドが空です。値を入力してください。

簡単のために、以下を前提とします。

  • 引数で渡される配列はnullではない
  • 配列中の各要素はnullでない

自分の勉強のためにも、JavaRuby両方で実装してみます。この記事ではJavaで実装します。

実装は続きを読むをどうぞ

続きを読む

Rubyでクラス宣言直下に書かれたメソッドの実行時期

Railsのスコープ定義文を見ていたら、クラス宣言直下に書かれたメソッドはいつ実行されるのかという疑問がわいてきたので調べました。

Rubyはクラス宣言直下に任意の式が書ける

railsのコードでは、クラス宣言直下でscopeメソッドを呼び出しています。

class Book < ActiveRecord::Base
  scope :costly, -> { where("price > ?", 3000) }
end

"初めてのRuby (Yugui 著)"には、

クラス定義の内には任意の式を書くことができます

と書いてあります。

クラス宣言直下に書かれたメソッドはいつ実行されるのか

クラス定義直下に書かれたメソッドがいつ実行されるのか、コードを書いて確かめます。

class CallUnderClassDefTest
  puts "from under class def 01"

  def method_01
    puts "from method_01"
  end

  puts "from under class def 02"
end

puts "out of class 01"
CallUnderClassDefTest.new.method_01
puts "out of class 02"

実行結果

from undfer class def 01
from under class def 02
out of class 01
from method_01
out of class 02

ファイルの先頭から処理が実行されているようです。 クラスの宣言が終わっていないのにメソッドが実行できるというのは不思議ですが、これもスクリプト言語の特徴なのでしょう。

Javaのstaticブロック

Javaコンパイル言語なので同様の機能は無いのですが、staticブロック内には任意の式を書くことができます。使用用途としては、クラス変数の初期化などです。以下のコードで実行順序を確認してみます。

public class SomeClass {
    private static List<String> fruitList = new ArrayList<String>();
    
    static {
        System.out.println("||static block start||");

        fruitList.add("apple");
        fruitList.add("banana");
        fruitList.add("coconut");
        
        System.out.println("||static block end||");
    }
    
    public static List<String> getFruitList() {
        return fruitList;
    }
}

public class StaticBlockTest {
    public static void main(String[] args) {
        System.out.println("start main");
        List<String> fruits = SomeClass.getFruitList();
        System.out.println("==== fruits ====");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        System.out.println("================");
        System.out.println("end main");

    }
}

実行結果

start main
||static block start||
||static block end||
==== fruits ====
apple
banana
coconut
================
end main

mainメソッドが呼ばれたあとにSomeClassのstaticブロックが実行されています。

Rubyを習い始めた時は、Rubyのクラス宣言直下に書かれた処理は、Javaのようにクラスが呼び出された際に実行されると思っていたので、今回確かめることができ、勉強になりました。

初めてのRuby

初めてのRuby
著者:Yugui
価格:2,376円(税込、送料込)
楽天ブックスで詳細を見る

"初めてのRuby" 本の感想とRubyの印象

Ruby on Railsを勉強する前に、"初めてのRuby"を読みました。本の感想とRubyの印象を書きます。

自身のプログラミング言語経験

本の内容が専門的なので、参考に自身のプログラム経験を書いておきます。

  • 業務で主に使用している言語
    • Java (業務で使用して6年くらい。普段はWEB APIを開発しています)
  • 業務で使ったことのある言語
  • 授業や研修で習った言語

本の感想

他の言語を知っている人向け

本の"はじめに"に書いてある通り、プログラム経験者向けです。特にオブジェクト指向の経験は必須で、"クラス" "インスタンス"などの用語が説明なしに出てきます。

オブジェクト指向でプログラミング経験があれば、自分の知っている言語へ用語を対応づけることで理解できると思います。

個人的には、関数型言語は未習得なので、関数型由来と思われる関数 (select等)は理解するのに時間がかかりました。

説明はあっさり、簡潔

他言語で経験のあるプログラマ向けなので、全体的に、Rubyでコレはこう書きます、といった書き方が多く、冗長な表現はありません。

ページ数が少ないので一気に読める

Rubyがどんな言語かさらっと知りたい場合にはおすすめです。ページ数が205ページと、プログラミング専門書の中では薄いほうなので、Rubyの概要を知るにはよい本です。

本の中でよくわからなかったこと

ブロック付き構文

javaだと関数をそのまま渡すことはできないのでブロック構文の理解に戸惑いました。 Rubyを勉強していくうちに、javascriptのコールバックと同じようなものだと理解しました。

シンボル

文字列とは違うのか、どのようなときに使うのかがいまいち分かりづらかった。

Rubyの印象

perlっぽい

一番強く思ったのがRubyperlっぽいということです。 本の中でも、

Rubyは歴史的には「よりよいPerl」として受け入れられてきた側面があります。

と書かれています。 似ている点は以下

  • スクリプト言語である
  • コメント文の書き方
  • バッククォートでシェルコマンド実行
  • if-elsif-else, if修飾子
  • 正規表現の扱いやすさ
  • ファイルの扱いやすさ

perlよりもよいと思った点は以下

  • 暗号っぽくならない
    • perlに精通した人のコードは記号ばかりで初心者が理解するのは難しいが、Rubyはそのようなことは多くはなさそう

かゆいとことに手が届いている

比較的最近できた言語というだけあって、他の言語を使用していてちょっと不便だなと感じるていたことが、Rubyでは簡単に行えるようになっています。

  • 使い終わったファイルを自動的に閉じてくれる機能が標準でサポートされている
  • 負の添字で配列を後方から参照できる
  • GCを自動で行ってくれる

サーバサイドも書けるしバッチも書ける

普段はJavaでサーバサイドプログラムを書き、たまにperlでバッチを書いているのですが、Rubyならサーバサイドでもバッチ処理でも使えて習得にお得感があります。

個人的な感想

長らくプログラミング言語を新たに習得するということをしていなかったので、そもそも本書を理解できるか不安でしたが、半分以上は理解できたと思います。手続き型言語なので、順次・分岐・繰り返し の構文、オブジェクト指向なのでクラス・メソッド・各種変数があるのはどの言語でも同じだと認識しました。

ただ、JavaRubyでは、equalsと==の意味が逆なので絶対間違えると思う。

本書を読んだ副作用として、思いがけずjavascriptの理解を深めることができました。クロージャという言葉を知れたのが大きいです。javascriptは系統立てて学んでいないので、本を読んで理解することは大切だと痛感しました。

初めてのRuby

初めてのRuby
著者:Yugui
価格:2,376円(税込、送料込)
楽天ブックスで詳細を見る

Rubyでの動的なクラスメソッドの追加方法

メソッドの実行でクラスメソッドが追加される

以下はrailsのscope定義文です。このように書くと、Book.costlyでレコードが取得できます。 メソッド呼び出しでメソッドが動的に追加されます。 メソッドの引数が新しいメソッドのメソッド名になるのです。不思議!Javaではこのようなことはできません。

class Book < ActiveRecord::Base
  scope :costly, -> { where("price > ?", 3000) }
end

どのような方法でメソッドを追加できるのでしょうか。

singleton_class とdefine_methodでクラスメソッドを追加する

Rubyでは動的なメソッド追加は割と普通に行われるようで、define_methodで行うことができます。 クラスメソッドの追加は特異クラスへのメソッド追加として行うことができます。

class Sample
  def self.my_define_method(name)
    singleton_class.send(:define_method, name, -> { puts "This method name is '#{name}'" })
  end

  # クラス内でクラスメソッドを追加
  my_define_method :sample_method
end

# クラス外からクラスメソッドを追加
Sample.my_define_method :sample_method2

# 追加したクラスメソッドを実行
Sample.sample_method
Sample.sample_method2

これを実行すると、以下のように表示され、メソッドの追加に成功したことが分かります

$ ruby sample_01.rb 
This method name is 'sample_method'
This method name is 'sample_method2'

moduleをextendする方法

上記の方法で動的にクラスメソッドを追加することができました。 Ruby on Railsのscopeのコード*1を見ると、Moduleのコードを呼んでいるので、同じような実装を行ってみます。

module ParentModule
  def my_define_method(name)
    singleton_class.send(:define_method, name, -> { puts "This method name is '#{name}'" })
  end
end

class Sample
  extend ParentModule
  
  my_define_method :sample_method
end

Sample.sample_method

実行します。

$ ruby sample_02.rb 
This method name is 'sample_method'

メソッドの追加ができました。Railsのコードに近い形になりました。

クラス定義内でモジュールをextendすることで、モジュールのメソッドを特異メソッド(クラスメソッド)として取り込むことができます。

うまく行かなかった方法たち

define_methodをsingleton_classをレシーバとして呼び出した場合

priveteなメソッドと呼ぶなと怒られます。

class Sample
  def self.my_define_method(name)
    # エラー。priveteメソッドは呼び出せない
    singleton_class.define_method name, -> { puts "This metho name is #{name}" }
    # 正しくは下記
    # singleton_class.send(:define_method, name, -> { puts "This method name is '#{name}'" })
  end
end

# クラスメソッドを追加
Sample.my_define_method :sample_method

# 追加したクラスメソッドを実行
Sample.sample_method
$ ruby sample_01_bad.rb 
sample_01.rb:3:in `my_define_method': private method `define_method' called for #<Class:Sample> (NoMethodError)

singleton_class(オブジェクトの特異クラス)のdefine_methodはプライベートメソッドなので外部から呼び出せません。

ただし、sendメソッドを使用することでprivateメソッドを(強制的に)呼び出すことができます。

define_methodをインスタンスメソッドから実行した場合

インスタンスメソッドとして定義した場合は、そのインスタンスの特異メソッドとして定義され、クラスメソッドにはなりません。

class Sample
  def my_define_method(name)
    singleton_class.send(:define_method, name, -> { puts "This method name is '#{name}'" })
  end
end

instance = Sample.new
# インスタンスのメソッドを追加 
instance.my_define_method :sample_method

# インスタンスメソッドとして実行
instance.sample_method
# エラー。クラスメソッドとしては定義されていない
Sample.sample_method
$ ruby sample_01.rb 
This method name is 'sample_method'
sample_01.rb:14:in `<main>': undefined method `sample_method' for Sample:Class (NoMethodError)

インスタンスの特異クラス(singleton_class)にメソッドを追加したため、インスタンスにメソッドが追加されました。

後記

define_methodの実装も気になりましたが、今回はこの辺で。

環境