大学生がプログラマーを目指すはなし

ruby初心者の自分が忘れないためのレポート

builderscon2018に行ってきた!

 

初めて外部の勉強会に参加してきました!

行ってよかったですね〜。大学生である自分にとっては良い刺激になりました。

内容としては、幅広くIT関連のディープな話でしたね!

セキュリティに関する真面目な話もあれば、自作キーボードを披露する人もいました。

なかでも一番印象に残ったのは、面白法人カヤックさんのねっしーさんの登壇でしたね〜。数学を用いた様々な事象における分析方法というような内容でして、理学部数学科で学ぶような純粋数学という学問を使ったとても難しい内容でしたが、一番面白かったですね〜。あと3時間くらいは軽く聞ける感じでした笑。

 

どれもこれもとてもユニークでした!

でも内容的に難しくあまり理解できないものもありました。その理解できないっていうのも刺激になりました。

発表する方は、どの方もトップエンジニアだなと感じたので、若い僕は「よーし、僕も頑張っていつかあのステージに立つんだぁ!」と、小さな夢を持つようになりましたとさ。

 

 

スはスペックのス(model)をRspec3, Rails5でやってみた。

こちらの「スはスペックのス」なのですが、とても古い記事でして2018年にrubyの勉強をし始めた僕にとってはversionの観点から少し分かりづらい内容でした。さらにネットの情報も様々なversionで書かれた記事が混在しており、さらにやりにくかったです。   

そんな中、頑張ってとりあえず全部やったのでメモとしてブログに上げます。

スはスペックのス 【第 1 回】 RSpec の概要と、RSpec on Rails (モデル編)

スはスペックのス(model編)

環境

  • Rspec → version 3.8
  • ruby → version 2.5.1
  • Rails → version 5.2.0

0. 準備

インストール

RSpec のリリースバージョンは RubyGems で提供されています。

$ gem install rspec

RSpec が無事にインストールされて、実行できることを確認しましょう。

$ spec -v

1. 簡単な配列のテスト

まず最初にRailsを使ってテストをする前に簡単な配列のテストをして、雰囲気を感じましょう。

適当なディレクトリに array_spec.rb という名前のファイルを用意します。 RSpec によるテストコードのファイル名は接尾辞を _spec とする のが一般的です。なお、RSpecで振舞を記述したファイルのことをスペックファイルと呼びます。

スペックファイルには、次のようにスペックを書きます。

array_spec.rb

describe Array, "when empty" do #ここに何を対象としてテストをするのか書く。
  before do #テスト前準備
    @empty_array = []
  end

  it "should be empty" do #ここにテストの内容を書く。
    expect(@empty_array).to be_empty
  end

  it "should size 0" do #ここにテストの内容を書く。 
    expect(@empty_array.size).to eq 0
  end

  after do #テスト後の後片付け
    @empty_array = nil
  end
end

 こちらのテストを読んでいくと、

まず最初にテストの内容です。

describe Array, "when empty" do #ここに何を対象としてテストをするのか書く。

これは"配列が空のとき"と読めます。

次に、 テスト内容です。

it "should be empty" do #ここにテストの内容を書く。
  @empty_array.should be_empty
end

これの"it"の部分から読んでみると、"それは空であるべきだ"と読めます。

次もテスト内容です。

it "should size 0" do #ここにテストの内容を書く。 
  expect(@empty_array.size).to eq 0
end

 これの"it"の部分から読んでみると、"それは0サイズであるべきだ"と読めます。

まとめると、

 - 配列が空のとき、 describe 〜

 - それは空なのか、 it "should be empty" do

 - 配列の数は0なのか、 it "should size 0" do

これらをテストしているということになります。

RSpec を実行してみます。

$ rspec
..
2 examples, 0 failures

 examplesがテストの数で、failuresがそのうち失敗した数です。つまり、全てのテストは成功したということです。 

2. Railsでmodelテストの作成

railsアプリケーションを作ります。

$ rails new rspec_sample_model
 ...(中略)
 $ cd rspec_sample_model

 Blog modelを作成します。

$ rails g model Blog name:string
 exists  ...
 create  ...
 ...
...

 たくさんファイルができます。

マイグレーションファイルを編集する。

ブログに名前が無いと困るので必須項目にしておきましょう。blogs テーブルの name 属性を null 不可にします。

db/migrate/001_create_blogs.rb

class CreateBlogs < ActiveRecord::Migration[5.2]

  def change

    create_table :blogs do |t|

      t.string :name, :null => false # Not null

 

      t.timestamps

    end

  end

end

DBを作成する。

$ bundle exec rake db:migrate

フィクスチャを編集する。

少し先回りになりますが、こちらを編集しておきます。

kubota:
  id: 1
  name: rspec_practice
kobayashi:
  id: 2
  name: css_practice

3. Blogのバリデーションのスペックを定義する。

spec/models/blog_spec.rb

require 'rails_helper'
describe Blog do before(:each) do @blog = Blog.new end

  it 'is not be valid without name' do
    expect(@blog).not_to be_valid
  end
end 

ここで実行すると失敗するはずです。なぜならまだ Blogクラスにname属性を検証するような実装をしていないからです。

一応、実行してみます。

rspec spec/models/blog_spec.rb

 

F

 

Failures:

 

  1) Blog is not be valid without name

     Failure/Error: expect(@blog).not_to be_valid

       expected #<Blog id: nil, name: nil, created_at: nil, updated_at: nil> not to be valid

     # ./spec/models/blog_spec.rb:11:in `block (2 levels) in <top (required)>'

 

Finished in 0.05637 seconds (files took 1.71 seconds to load)

1 examples, 1 failure 

予想通り失敗しました。

Blogクラスに期待される振舞を実装する。

name 属性の存在を検証するように Blog クラスを実装します。

app/models/blog.rb

class Blog < ActiveRecord::Base

  validates_presence_of :name

end

blog.rb の修正を保存して、再度 rspec を実行します。DBに変更は無いので、そのまま rspecコマンドを叩きます。

rspec spec/models/blog_spec.rb

.

 

Finished in 0.05556 seconds (files took 1.71 seconds to load)

3 examples, 0 failures

予想通り成功しました。 

3. Entryモデルの作成。

次は Blog に投稿された記事を表現する Entry モデルを作成します。 ジェネレータの利用からフィクスチャの設定までは Blog クラスの場合と同様です。

Entryモデルを生成する。

Entry の属性にはタイトル、本文、投稿日を用意します。Blog と関連づけるため の外部参照キーや、管理用の属性として、タイムスタンプも定義します。

$ rails g model entry title:string body:text posted_at:date created_at:timestamp updated_at:timestamp blog_id:integer

exists app/models/

exists spec/models/

create spec/fixtures/

create app/models/entry.rb

create spec/fixtures/entries.yml

create spec/models/entry_spec.rb

exists db/migrate

create db/migrate/002_create_entries.rb

マイグレーションファイルを編集する。

 必須属性を null 不可にします。

db/migrate/002_create_entries.rb

class CreateEntries < ActiveRecord::Migration[5.2]

  def change

    create_table :entries do |t|

      t.string :title, :null => false

      t.text :body, :null => false

      t.timestamp :posted_at

      t.timestamp :created_at

      t.timestamp :updated_at

      t.integer :blog_id, :null => false

 

      t.timestamps

    end

  end

end

投稿日 (posted_at) を created_at や updated_at といった Rails が標準でサポート するタイムスタンプで代用せずに独立させて定義しています。

これは「Blog の記事の投稿日」として扱いたい日付が必ずしもデータベースレコードの作成・更新タイムスタンプと同じとは限らないためです。 

DBを移行する。

$ bundle exec rake db:migrate

development環境のデータベースを変更しましょう。

フィクスチャを編集する。

テスト用の投稿記事を用意しておきます。

spec/fixtures/entries.yml

$ bundle exec rake db:migrate

kubota_earliest:

   id: 1

  blog_id: 1

  title: "昨日は台風"

  body: "せっかくエンジニアの人とランチの約束があったのにダメになった。"

  posted_at: 2001-07-06

kubota_latest:

  id: 2

  blog_id: 1

  title: "最近はRspecにハマっている。"

  body: "なんだかかれこれ1週間くらいやっているなぁ。"

  posted_at: 2007-09-12

kobayashi:

  id: 3

  blog_id: 2

  title: "全然休みがない"

  body: "金もない。"

  posted_at: 2007-06-24

4. BlogとEntryを絡み合わせたspecを定義する。

では実装に入ります。今回作成するブログアプリケーションのモデルを確認しておきます。

両者の関連を確認しておくと:

  • Blog は複数の Entry を所有する (Blog has_many Entry)
  • Entry は特定の Blog に属する (Entry belongs_to Blog)

となります。この 2 つをスペックとして記述します。

せっかく Entry モデルを作成したので、まずは Entry 側の関連からスペックを定 義しましょう。

「Entryは特定のBlogに属すること」をスペックとして定義する。

 Entry から Blog を参照できるという期待をスペックとして記述します。

spec/models/entry_spec.rb

require 'rails_helper' 

describe Entry do

  fixtures :entries, :blogs

  before(:each) do

    @entry = entries(:kubota_earliest)

  end

 

  it 'belongs to a specific blog.' do

    expect(@entry.blog).to eq blogs(:kubota)

  end

end

RSpec on Rails では振舞を記述する際に、Rails 標準のテスティング環境と同様 に fixtures メソッドを使用できます。Rspec on Rails の fixtures と Rails 標準の fixtures との違いは、Rspec on Rails では「fixture_path」が 「$RAILS_APP/spec/fixtures」に設定されていることです。

spec を実行する前に、rake の db:test:prepare タスクを実行します。 entries テーブルを作成した際に、development 環境のデータベーススキーマは 変更しましたが、この変更をまだ test 環境のデータベースには反映していないからです。

$ bundle exec rake db:test:prepare

 ここでテストを実行すると失敗するはずです。なぜならまだEntry.blogを定義していません。

一応実行してみます。

$ rspec spec/models/entry_spec.rb

F

 

Failures:

 

  1) Entry belongs to a specific blog.

     Failure/Error: expect(@entry.blog).to eq blogs(:kakutani)

     

     NoMethodError:

       undefined method `blog' for #<Entry:0x00007f868f774828>

       Did you mean?  blog_id

     # ./spec/models/entry_spec.rb:18:in `block (2 levels) in <top (required)>'

 

Finished in 0.03105 seconds (files took 1.71 seconds to load)

1 example, 1 failure

予想通り失敗しました。 

Entryにbelongs_toを実装する。

振舞の期待通りに Entry を実装しましょう。

app/models/entry.rb 

class Entry < ApplicationRecord

  belongs_to :blog

end

spec を実行します。 

$ rspec spec/models/entry_spec.rb

.

 

Finished in 0.04034 seconds (files took 1.7 seconds to load)

1 example, 0 failures

予想通り成功しました。

とりあえずここまで。 

Rubyでgemを作って公開するまで

0. 準備

まずは準備のためにgemのアップデートとbundlerのアップデートを行います。

# gem自信のアップデート
gem update --system

# bundler未インストールの場合はインストール
gem install bundler

# bundlerインストール済の場合はアップデート
gem update bundler

 

1. ヒナ形の作成

今回はtest_gemという名前のGemを制作していきます。

※実際にRubyGemsで公開する場合はまだ存在していないGem名にしないといけません。

# test_gemのひな形を作成(Rspec付き)
bundle gem test_gem --exe -t

2. 作成されたファイルの確認

今回作成されたファイルの簡単な説明。

bundle gem test_gem -t
  create  test_gem/Gemfile
  create  test_gem/Rakefile
  create  test_gem/LICENSE.txt
  create  test_gem/README.md => このgemの説明や使い方を記述
  create  test_gem/.gitignore
  create  test_gem/test_gem.gemspec => このgemの説明や依存関係などを記述
  create  test_gem/lib/test_gem.rb => プログラムを記述
  create  test_gem/lib/test_gem/version.rb => このgemのバージョン情報を記述
  create  test_gem/.rspec
  create  test_gem/spec/spec_helper.rb
  create  test_gem/spec/test_gem_spec.rb
  create  test_gem/.travis.yml => travisを使う際の設定を記述
    create   test_gem/exe/test_gem => 実行コマンドを追加する際に記述

3. test_gem.gemspecの修正

test_gem.gemspecの中身は以下のようにになっています。

# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'test_gem/version'

Gem::Specification.new do |spec|
spec.name = 'test_gem'
spec.version = TestGem::VERSION
spec.authors = ['kubota-ryotaro']
spec.email = ['kubota@mail.com']
spec.summary = %q{TODO: Write a gem summary}
spec.description = %q{TODO: Write a gem description}
spec.homepage = 'http://namae.github.io'

spec.files = `git ls-files -z`.split("\x0")
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ['lib']

spec.add_development_dependency 'bundler', '~> 1.7'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec'
end

最低限修正が必要な部分を抜き出すと次のようになります。

# このgemの説明をダブルクオートで囲って書き直す
spec.summary       = "Make gem for summary."
spec.description   = "Make gem for description."

# このgemのHomepageを書く(GitHubのURLを入れてください) spec.homepage = "https://github.com/kubota-ryotaro/"
# 依存するgemが存在する場合のみ、次のように指定 spec.add_dependency 'xxxx', '~>x.x' # 開発時だけに必要な依存gemが存在する場合のみ、次のように指定 spec.add_development_dependency 'yyyy', '~>y.y'

4. Gemの実装

今回はテスト的にHello World!と出力するようにします。lib/test_gem.rbを開いて次のように変更します。

require 'test_gem/version'

module TestGem
def self.greet
'Hello World!'
end
end

5. 実行してみよう

では先ほど作成したgemを実行してみます

# gem のインストール
bundle install

# rubyの対話型インタプリタを起動
bundle exec irb [2.1.4]
irb(main):001:0> require 'test_gem'
=> true

irb(main):002:0> TestGem.greet
Hello World!

ということで無事実行できました!

6. RSpecを書こう

先ほどのTestGem.greetのテストをRSepcで書いていきます。spec/test_gem_spec.rbを次のように書き換えます。

require 'spec_helper'

describe TestGem do
it 'has a version number' do
expect(TestGem::VERSION).not_to be nil
end

describe '#greet' do
it 'returns "Hello World!"' do
expect(TestGem.greet).to eq('Hello World!')
end
end
end

7. 実行コマンドを追加

コンソール上でtest_gemというコマンドを使うとgemの内容を実行できるようにしたいので、exe/test_gemに次を書いていきます。

#!/usr/bin/env ruby

require 'test_gem'

puts TestGem.greet

8. Gemをパッケージ化する。

次にGemをパッケージ化します。コマンドとしては、gem build test.gemspecです。

gem build test_gem.gemspec
=> Successfully built RubyGem
=> Name: test_gem
=> Version: 0.0.1
=> File: test_gem-0.0.1.gem
gem install test_gem
=> Successfully installed test_gem-0.0.1
=> 1 gem installed
test_gem
=> "Hello World!"

9. 公開

GitHubと連携して管理するようなので以下のことは前提となります
GitHubアカウントを持っていること
GitHub用にSSHキーの設定を行う:GitHubへssh接続する

rubygems.orgのアカウントを取得
  作ったgemをリリースするまで
  1.「sign up」からアカウントを作成
  2. アカウント作成後、Edit profile(https://rubygems.org/profile/edit) に移動
  3. APIアクセス用の鍵を作成(以下のコマンドが用意されている)

curl -u your_name https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials

GitHub上のリモートリポジトリの設定
現在の作業用ディレクトリをリモートリポジトリに反映させます
Githubにgem名と同じ名前の新規リポジトリを作成する

git init$
git add -A
git commit -m "initial commit"
git remote add origin https://github.com/namae/test_gem.git

git push --set-upstream origin master

③リリース
あとは、releaseするだけ。

bundle exec rake release

 

これでできたはず!

 

 

rakeの基本

前提 rubyプログラムの中でC言語コンパイルして実行する。
1. まず最初に適当な作業ディレクトリを作成し、そこにRakefileを作る。

ここでお約束的な感じでRakefileの頭文字は大文字にしておく。

2. 今回使用するC言語プログラムを作っておく。

今回実行するプログラムはamidakuji.c

3. RakefileにCプログラムをビルドして実行するためのコードを書いていく。

f:id:rk0822ps4:20180707155733p:plain

 $ rake としたらdefaultでamidakujiが呼ばれるようにしておく。

4~6行目で実行プログラムで、8~10行目でビルドだ。

このように芋ずる式で書いていくと良い。

$ rake

で実行できる。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

8時間かけて作ったソースファイル達を rm ./* してしまった。

2日かけて計8時間ほどかけて作ったプログラムがありました。

それをGitHub上にpushしようと思ったんですよね。

だからまずローカルの作業用ディレクトリからpush用のディレクトにコピーしました。そしてそこで一応中身を確認していたら一部気に入らない箇所があり、もう一度作業用ディレクトリの中で訂正しようと思ったんですよね。んで、そのファイル達を一旦消したんですよね。

そしたら...

 

「あれ?」

作業用ディレクトリの中にさっきまで開いていたファイルがないお??

あれ、どこ行ったんだろ...

 

...

.......

「どっこにもねぇ」

 

 

コマンドの履歴を確認してみたところ作業用ディレからpush用ディレにmvしていたようでした。

そして移動させたファイルを綺麗に削除したみたいでした。

 

解決策は基本的になく、もう一回作り直すしかないらしい...。゚(゚´ω`゚)゚。

 

 

その後誰かに聞いたら「そのためのgitじゃね? コミットしーや。」

とのことで解決しましたとさ。

 

debianで使うaptコマンド

aptの基本的なコマンド

debian初心者の自分がメモしたコマンドです。

アプリケーションのインストール、アンインストール、アップデートを行うコマンド

# apt install name

# apt remove name

# apt update name

 

Rake taskでコマンドラインから複数引数を指定する方法

1. taskを作成してみる。

$rake g task file_name

file_nameにてきとうな名前をつける。
すると、rails/lib/task/ に以下のようなファイルが作成される。

file_name.rake
namespace :file_name do
end

 

2. taskに処理を書いてみる。

file_name.rake
namespace :file_name do
  task practice do
print "hello" end end

これで保存する。

 

3. rake taskを確認してみる。

$ rake -vT

# 出力結果
...
rake file_name:practice
...

 こう出力されれば作成されている。

 

4. 実行してみる。

$ rake file_name:practice

# 出力結果
hello

 ここまでくればとりあえず完成である。

 

5. Rake taskでコマンドラインから複数引数を指定する方法

5-1. 概要

rakeコマンド実行時にコマンドラインから複数の引数を入力として受け取るには主に2つの方法があります。

  1. taskを複数定義する。
  2. 環境変数を複数定義する。

5-2. taskを複数定義する。

例えば、

task :practice, 'firstname', 'lastname'

task :practice do |i, args|

  puts "My name is  #{args['first_name']} #{args['last_name']}"

end

 として、実行してあげると

$ rake file_name:practice[Ryotaro,Kubota]

 

# 出力結果

My name is Ryotaro Kubota 

とできる。

5-3. 環境変数を複数定義する

例えば、

task :practice do |t|

  puts "My name is #{ENV['first_name']} #{ENV['last_name']}"

end

 として、実行してあげると

$ rake file_name:practice first_name=Ryotaro last_name=Kubota

# 出力結果

My name is Ryotaro Kubota 

とできる。

 

6. どっちがいいの?

まぁどっちでもいいと思ってしまいますが、強いていうなら環境変数の方が好きかもしれないです。

なぜならtaskを繋げてたくさん書いていくとrake -vTで確認したときに、横にたくさん連なって色々見辛くなります(笑)

$ rake -vT

# 出力結果
...
rake file_name:practice,'sample1','sample2','sample3','sample4'...
...

 こうなっちゃうとdescで説明したところが右側に追いやられてしまうんですよね...

何か良い方法があれば別ですが...