20190811のRubyに関する記事は11件です。

【Ruby】Ruby初心者がよく使うと思う配列のメソッド

はじめに

いま、Rubyプログラマに勧めてもらったチェリー本を使って学習を進めています。
Rubyの勉強を開始してから1週間くらいしか経っていない初心者が、覚えておきたい配列のメソッドを調べました。
個人的な振り返りメモも兼ねています。
ぜひ間違えていたら、コメントや編集リクエストで教えていただけると嬉しいです。

参考文献

プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで Software Design plus | 伊藤 淳一 | コンピュータ・IT | Kindleストア | Amazon
start_with? (String) - Rubyリファレンス
class Array (Ruby 2.6.0)
Rubyのeachでindexを取得する:each_with_index | UX MILK
【Ruby】each_with_indexは知ってたけどeach.with_indexは知らなかった… - 訳も知らないで
class Enumerator (Ruby 2.6.0)

動作確認環境

  • Windows 10
  • ruby 2.5.5p157

eachメソッドでループする

今回勉強に使わせてもらっているチェリー本によると、for文ではなく、eachメソッドを使用することが多いとのことです。

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
arr.each do |n|
  puts n
end

実行結果

Spring
Summer
Autumn
Winter

eachメソッドでindex(添字)を取得したい

Enumerableモジュールのメソッドの一つであるeach_with_indexを使用します。

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
arr.each_with_index do |n, index|
  puts "#{index}, #{n}"
end

実行結果

0, Spring
1, Summer
2, Autumn
3, Winter

index(添字)の始まりの値を設定したい

Enumeratorクラスのメソッドの一つであるwith_indexメソッドを使用します。
サンプルは、2からindexを開始するという意味です。

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
arr.each.with_index(2) do |n, index|
  puts "#{index}, #{n}"
end

実行結果

2, Spring
3, Summer
4, Autumn
5, Winter

配列同士を比較したい

サンプルコード

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
arr_compare = ['Spring', 'Summer', 'Autumn']
puts arr.eql?arr_compare   # false
arr_compare.push('Winter') # 要素を追加してから比較
puts arr.eql?arr_compare   # true

配列が空かどうか確認

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
arr_empty = []
puts arr_empty.empty? # true
puts arr.empty?       # false

指定した範囲の配列要素を取得する

サンプルコード

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
p arr[1...3] # 3を含まない
p arr[1..3]  # 3を含む

実行結果

["Summer", "Autumn"]
["Summer", "Autumn", "Winter"]

条件に一致する要素を取り出して新しい配列を作る

サンプルコード

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
# 文字列の先頭がSの要素を抽出
p arr.select { |n| n.start_with?("S") }

実行結果

["Spring", "Summer"]

条件と不一致の要素を取り出して新しい配列を作る

サンプルコード

arr = ['Spring', 'Summer', 'Autumn', 'Winter']
# 文字列の最後尾がrの要素を抽出
p arr.reject { |n| n.end_with?("r") }

実行結果

["Spring", "Autumn"]

全要素に対してブロック内で評価した結果で新しい配列を作る

p arr.map { |n| n.start_with?("S") }

実行結果

[true, true, false, false]

条件に一致する最初の要素を返す

サンプルコード

# uを含む文字列を検索
p arr.find { |n| n.index("u")}

実行結果

"Summer"

おわりに(おまけ)

実はチェリー本を購入する前に、
この記事の下書きを作っていたのですが、
だいたい(もしかしたら全部)チェリー本に書いていました。

まとめた意味がなくなってしまい、すごく悲しくなりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby プログラミングノート 1~3章

はじめに

Ruby on Rails チュートリアルの実施と並行してRubyの学習を行い
自身の記憶定着のためプログラミングノートとして書き起こす。

Progateおよびチェリー本
で学習を行った

RubyとRuby on Railsとの違い

Ruby Rails
プログラミング言語
(Python等と同様)
Rubyを用いたWebアプリケーションの
開発用のフレームワーク
文字列、数値、true/false、nilのすべてがオブジェクト
(オブジェクトに対してメソッドが呼べる)
MVCモデルの提供
M=Model(モデル) データの処理
V=View(ビュー) 見た目の処理
C=Controller(コントローラ) ModelとViewを制御する

Rubyの基本

Rubyファイルの実行

$ ruby ファイル名(~.rb)

Ex.
$ ruby sample.rb

ライブラリの種類

ライブラリのインポート

  • インストール不要
require "ライブラリ名"
require "ファイルパス"
※ファイル名指定時に拡張子の「.rb」は不要

Ex.
  require "date"         (Dateクラス)
  require "./home/start" (home/start.rbファイル)
  • インストール必要 gem(外部ライブラリ)

変数宣言

変数名 = 値(型の宣言が不要)
※変数名だけ定義はできない

コンソールへの入出力(putsとgets)

  • コンソールへの表示
puts 文字列
puts 変数
  • コンソールへの入力
  変数名 = gets       (改行付き)
  変数名 = gets.chomp (改行外し)

文字列

  • 定義
    クオーテーション「""」と「''」

  • 変数の埋め込み
    "・・・#{変数名}・・・"

  • 文字列の連結
    文字列 + 文字列
    ※数値 + 文字列は使えない

  • 文字列 ⇔ 数値の変換
    (→文字列)変数.to_s
    (→数値) 変数.to_i

Ex. 
   num_age = 19
   str_age = '19'
   puts num_age + "歳"   → エラー
   puts "#{num_age}歳"   → 19歳
   puts 'str_age' + '歳' → 19歳

「""」と「''」の違い

  • 文字列に埋め込んだ変数を展開する・・・「""」
  • 文字列に埋め込んだ変数を展開しない・・・「''」
Ex. 
  name = "田中"
  puts "やあ#{name}さん" → やあ田中さん
  puts 'やあ#{name}さん' → やあ#{name}さん

if文のフォーマット

  • 年号からうるう年を判別する
Ex.
  year = 2019
  if year % 4 != 0 
    puts "うるう年ではありません"
  elsif year % 100 == 0 && year % 400 != 0
    puts "うるう年ではありません
  elsif year % 100 == 0 || year % 4 == 0
    puts "うるう年です"
  end

- if文の判定結果をTrue,false
  if shipping_free?(3000)
    puts "3000以上の数"
  else
    puts "3000より小さい"
  end

テストの自動化

Minitestの利用

  • Fizzbuzzのテストを作成する メソッドから出力される値が期待通りかを検証できる
FizzBuzz.rb
def fizzbuzz(input_num)
  if input_num % 15 == 0
    'Fizz Buzz'
  elsif input_num % 5 == 0
    'Buzz'
  elsif input_num % 3 == 0
    'Fizz'
  else 
    input_num.to_s
  end
end
FizzBuzz_test.rb
require 'minitest/autorun'
require 'FizzBuzz'

class FizzBuzzTest < Minitest::Test
  def test_fizz_buzz
    assert_equal '1', fizzbuzz(1)
    assert_equal 'Fizz', fizzbuzz(3)
    assert_equal 'Buzz', fizzbuzz(5)
    assert_equal 'Fizz Buzz', fizzbuzz(15)
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby プログラミングノート Part1

はじめに

Ruby on Rails チュートリアルの実施と並行してRubyの学習を行い
自身の記憶定着のためプログラミングノートとして書き起こす。

Progateおよびチェリー本の1~3章での学習結果の書き起こしになる

RubyとRuby on Railsとの違い

Ruby Rails
プログラミング言語
(Python等と同様)
Rubyを用いたWebアプリケーションの
開発用のフレームワーク
文字列、数値、true/false、nilのすべてがオブジェクト
(オブジェクトに対してメソッドが呼べる)
MVCモデルの提供
M=Model(モデル) データの処理
V=View(ビュー) 見た目の処理
C=Controller(コントローラ) ModelとViewを制御する

Rubyの基本

Rubyファイルの実行

$ ruby ファイル名(~.rb)

Ex.
$ ruby sample.rb

ライブラリの種類

ライブラリのインポート

  • インストール不要
require "ライブラリ名"
require "ファイルパス"
※ファイル名指定時に拡張子の「.rb」は不要

Ex.
  require "date"         (Dateクラス)
  require "./home/start" (home/start.rbファイル)
  • インストール必要 gem(外部ライブラリ)

変数宣言

変数名 = 値(型の宣言が不要)
※変数名だけ定義はできない

コンソールへの入出力(putsとgets)

  • コンソールへの表示
puts 文字列
puts 変数
  • コンソールへの入力
  変数名 = gets       (改行付き)
  変数名 = gets.chomp (改行外し)

文字列

  • 定義
    クオーテーション「""」と「''」

  • 変数の埋め込み
    "・・・#{変数名}・・・"

  • 文字列の連結
    文字列 + 文字列
    ※数値 + 文字列は使えない

  • 文字列 ⇔ 数値の変換
    (→文字列)変数.to_s
    (→数値) 変数.to_i

Ex. 
   num_age = 19
   str_age = '19'
   puts num_age + "歳"   → エラー
   puts "#{num_age}歳"   → 19歳
   puts 'str_age' + '歳' → 19歳

「""」と「''」の違い

  • 文字列に埋め込んだ変数を展開する・・・「""」
  • 文字列に埋め込んだ変数を展開しない・・・「''」
Ex. 
  name = "田中"
  puts "やあ#{name}さん" → やあ田中さん
  puts 'やあ#{name}さん' → やあ#{name}さん

if文のフォーマット

  • 年号からうるう年を判別する
Ex.
  year = 2019
  if year % 4 != 0 
    puts "うるう年ではありません"
  elsif year % 100 == 0 && year % 400 != 0
    puts "うるう年ではありません
  elsif year % 100 == 0 || year % 4 == 0
    puts "うるう年です"
  end

- if文の判定結果をTrue,false
  if shipping_free?(3000)
    puts "3000以上の数"
  else
    puts "3000より小さい"
  end

テストの自動化

Minitestの利用

  • Fizzbuzzのテストを作成する メソッドから出力される値が期待通りかを検証できる
FizzBuzz.rb
def fizzbuzz(input_num)
  if input_num % 15 == 0
    'Fizz Buzz'
  elsif input_num % 5 == 0
    'Buzz'
  elsif input_num % 3 == 0
    'Fizz'
  else 
    input_num.to_s
  end
end
FizzBuzz_test.rb
require 'minitest/autorun'
require 'FizzBuzz'

class FizzBuzzTest < Minitest::Test
  def test_fizz_buzz
    assert_equal '1', fizzbuzz(1)
    assert_equal 'Fizz', fizzbuzz(3)
    assert_equal 'Buzz', fizzbuzz(5)
    assert_equal 'Fizz Buzz', fizzbuzz(15)
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オブジェクト指向とは

今日は中々打ち合わせやらで、自分の勉強が進まなかったんだけど、
極力毎日ブログは書きたいので、簡単なものを書こうかなと。

しばらくAWSの流れだったんだけど、AWSは理解が難しいので今日はオブジェクト指向ってやつについて書くよ。

僕はプログラミング初学者なわけでRubyをずっと使ってきたんだけど、Rubyはオブジェクト指向言語と言われているらしい。

で、オブジェクト指向ってそもそもなんだよっていう話。今回はRubyを用いてまとめていこうかと思うよ。

オブジェクト指向とは

オブジェクト指向とは、複数のオブジェクトを組み合わせてプログラムを構築する考え方。

オブジェクトとはデータと処理の集まりのことですが、漠然として集合体のことではなく、一つのテーマを持った集合体のことです。

人であれば「名前」、「年齢」、「出身地」などのデータを持ちます。

オブジェクト(今回のテーマは人)であれば、こういったデータの他に「振る舞い」があります。

例えば名前を聞くという「振る舞い」と、それに対して、自分の名前を返すという「振る舞い」。
ここでいう「振る舞い」をオブジェクト指向で考えると処理にあたるということです。

概念的ではありますが、特別理解できないということではないと思います。

オブジェクト指向って何?という問いに対して、「現実と一緒だ」なんて回答もあるくらいです。

オブジェクト指向とクラス

オブジェクト指向の概念を説明しても、じゃあプログラミングに落とし込んだらどうなるか中々想像できないかと思います。

そこで必要になるのがクラスの概念です。

クラスとは

オブジェクト指向言語において、データと処理をひとまとめにしたもの。
オブジェクトの設計図とも呼ばれる。

実際にRubyで書いてみます。

class Person
  def initialize(name, age , birthplace)
    @name = name
    @age = age
    @birthday = birthday
  end

  def answer_name
    puts @name
  end
end

人(person)クラスを定義して、名前や生年月日を持たせています。これがオブジェクト指向におけるデータのことです。

人(person)クラスで定義された人は、answer_nameメソッドという「振る舞い」をします。これがオブジェクト指向における処理のことです。

ここで定義されたクラスもオブジェクト、@nameといったインスタンス変数もオブジェクト、answer_methodもオブジェクトということになります。

結局、オブジェクト指向で生まれたものは全てオブジェクトと呼ばれることになります。

その中でもクラスは設計図、インスタンスは実体化したデータ、メソッドは実体化した処理とでもイメージすればいいのかなと思います。

いいか?結局、現実と一緒だ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】 自己学習メモ まとめ

前置き

転職活動をキッカケに始めた新しい言語の勉強が思いのほか楽しくなってきたので、Rubyにも手をつけることにしました。
最終目標としては、「Rubyで何かシステムを作り、一般公開する」ですが、Qiitaへの投稿内容としては、勉強したコトのまとめです。

このエントリは、今後投稿していく自己学習メモや、それに関する情報へのリンク集、その他Tips集のような内容としたいと思います。

開発環境

端末:MacBook Pro(macOS 10.14.5)
Macの場合は初期段階ですでにRuby導入済のため、「ソースを書いて、ターミナルで実行してみる」というレベルであれば追加でなにかインストールや設定を行う必要はなし。

Hello World

ターミナルでの実行方法、および稼動確認をかねて、ごく基本的なソースの書き方を確認。

インストール済みのRubyバージョン確認

$ ruby -v
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18]

ファイルの実行

Rubyソースファイルの拡張子は"rb"
"Hello World"を表示するごく簡単なソースを書きます。

HelloWorld.rb
message = "Hello World!"
puts message

ファイルを指定して実行するには、rubyコマンドの後に、ファイル名を指定するだけ。
実行結果は以下の通り。

$ ruby HelloWorld.rb
Hello World!

putsは改行ありの標準出力。
printは改行なしの標準出力。

よって、以下のようなソースでも上記と同様の出力結果となる。

HelloWorld2.rb
message = "Hello"
print message

message = " World!"
puts message
$ ruby HelloWorld2.rb
Hello World!

学習メモ リンク

これから追加していきます。

関連リンク集

これから追加していきます。

時間の都合上、いったんここまで。
改めて随時加筆修正予定。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Railsの環境構築した時に出たエラーとか

はじめに

サーバーサイドの知識があまりなかったため、Railsをなんとなーく導入してみようと思い、なんとなーく環境構築を勧めていたら、無知も相まって色々と悩んだのでメモを残しておく。今回予め、Gitlab,Redmineあたりを勉強ついでに導入しており、その関係でRails側の設定やインストール工程を一部省いたりもしたため、rubyとかbundlerとかpostgresqlとかをrailsのためにインストールし直したりはしていない。

Railsを導入するにあたって参考にしたサイト

環境

  • OS (CentOS7)
  • ruby (2.4.1)
  • bundler (1.17.3)
  • gem (3.0.4)
  • rails (5.2.3)
  • postgresql (9.2.24)

本題

bundler command not found: spring

Bundle complete! 18 Gemfile dependencies, 60 gems now installed.
Gems in the groups development and test were not installed.
Bundled gems are installed into `./vendor/bundle`
         run  bundle exec spring binstub --all
bundler: command not found: spring
Install missing gem executables with `bundle install`

rails new 'アプリ名' -d postgresqlを実行した時に出たエラー。
単純にspringというコマンドがなく、次の工程に進めないという話なのだけど、なぜ存在しないのかが分からなかった。
結論から言うとbundlerのconfigに問題があり、developmentとtestグループがBUNDLE_WITHOUTに設定されていたため、Gemfileの特定の行を通っていなかった。
参考URL(http://ruby.studio-kingdom.com/bundler/bundle_config/)

.bundle/config
---
BUNDLE_PATH: "vendor/bundle"
BUNDLE_WITHOUT: "development:test"

ひとまず以下の様に修正

.bundle/config
---
BUNDLE_PATH: "vendor/bundle"
BUNDLE_WITHOUT: "test"

これでspringコマンド含め、諸々インストールされた。

Could not find a JavaScript runtime

JSのランタイムがないとかなんとか。nodejsインストールで解決した。
参考URL(http://djandjan.hateblo.jp/entry/2018/07/25/224929)

Address already in use

正しくは

Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE) 

と出力されていた。
多分3000番ポートが既に使用されているので、ポートの使用状況を lsof -i:3000 で確認してみたら、どうやらGitlabで使われてるっぽい...のでRailsのポートを変更することにした。
以下のコマンドでひとまず解決。

$ rails s -p 3001

Linux上ではひとまず起動したようなので、よしこれでページアクセスできるわ!と思い、ブラウザーにアドレス入力。エンターキーに渾身の力をこめてターンッしたら想定していたページが表示されない。このサイトにアクセスできませんとのこと。
これについては、下のURLに詳しいことが書いてあった。
参考URL
結果

$ rails s -b 0.0.0.0 -p 3001

これでアクセス"は"できるようになった。

あとファイアウォールのポートの設定忘れてるとアクセスできないので注意。

role "ユーザー名" does not exist

データベース側の設定ができておらんのでアクセスできてもページの表示ができなかった。
まずはユーザーが存在しないところから。下記URLの通りにすれば作成できた。ユーザー名はRails sを実行しているユーザー名にすればいい思う。(多分)
自分の場合はrootでやっていたので、

$ sudo su – postgres
$ createuser -s -r root

で作成は完了。
参考URL(https://kirohi.com/rails_pg_error_role_doesnotexist)

データベースが存在しない。

下記URLの通り設定していきましょう。"Rails の設定とか"の辺りに詳しく書いてある。
データベースの名前はエラーページに表示されている通り。(***の部分はrails new で作成したアプリの名前)
***_development
***_test
***_production
参考URL

余談

改めて記事にしてみて、アドレスの指定のところとか、そもそもDBまわりの知識があまりないとかちらほらあったので改めて調べ直したら記事にして考えを整理したいと思う。

また、もし誤った情報があれば、ご指摘いただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyで競プロ、ちょっと高速化テク(ABC137D)

abc137d, abc128eのネタバレを含むので、
ネタバレ無しで解きたい方は説いてから御覧ください。

問題

https://atcoder.jp/contests/abc137/tasks/abc137_d

解説

https://img.atcoder.jp/abc137/editorial.pdf

手順

解答フロー

[報酬がもらえるまでの日付, 報酬]を日付で昇順ソートして、

今日からM日後 までにもらえる報酬を最大化するための仕事の割り振りを、
今日から考えるのではなくM-1日後の仕事の予定から埋めていくイメージになります。

M-1日後にやって、1日後(今日からM日後)までに報酬がもらえる仕事の内最大の報酬の仕事を取る、
M-2日後にやって、2日後(今日からM日後)までに報酬がもらえる仕事の内最大の報酬の仕事を取る、
...
今日やってM日後までに報酬がもらえる仕事の内最大の報酬の仕事を取る。

という形で報酬の最大化ができます。(自明)

1日後に報酬がもらえる仕事の報酬を最大Heap(親ノードの方が必ずでかい)にぶっこんで、1個pop(最大値を取り出す)、
2日後に報酬がもらえる仕事の報酬を最大Heapに全部ぶっこんで、1個pop
...
という形で時間内に答えることが出来るはずです。

こういうデータ構造はABCのDぐらいだとちょくちょく求められるので予め作っておいた方が無難です。

https://github.com/k-karen/ruby-samples/blob/master/heap/pop_heap.rb

私の最大Heapを置いておきます、よろしければご利用ください。

高速化テク

ということで今回は[日付, 報酬]の配列を日付でsortしたいという場面が出てくると思います。

普通にやると

n, m = gets.split.map(&:to_i)
datas1 = []
n.times do
  datas1 << gets.split.map(&:to_i)
end
datas1.sort_by!(&:first)

と書くと思いますが、 sort_by!(&:first)は(後述の方法より)早くないです。
今回は入力が全部正の値で、その上限が10^5程度とわかっていますので、
これを利用して以下のように書くことができます

# (10**5).bit_length #=> 17
# 17ビットずらせば、2つの値を独立に保存できる
n, m = gets.split.map(&:to_i)
datas2 = []
n.times do
  tmp = gets.split.map(&:to_i)
  datas2 << (tmp[0] << 17) + tmp[1]
end
datas2.sort!

これだと気持ち早くなります。

値を取り出すときは予めビットマスクを用意しておいて、それとandを取れば良いです。

mask = (1 << 17) - 1 
datas.each do |day_salary|
  day = day_salary >> 17
  salary = day_salary & mask
end

どんぐらい早くなるか

before( max 817ms )
https://atcoder.jp/contests/abc137/submissions/6816390
after ( max 775ms )
https://atcoder.jp/contests/abc137/submissions/6840374

今回はあまり効果がありませんが、
多重キーソートも値の順番を正しく配置すればいい感じに行えます(ABC128E)
降順と昇順が入り交じる場合は、入力の上限から引いた値を入れるなどの工夫が必要になります。

俗に言うイベントソートで大活躍する手法です。
そもそもそんな小手先の高速化を行うなら、
RubyじゃなくてC++でかけという話、ごもっともなので勘弁してください。

最後に、同じような手法で出来る問題置いておきます。
https://atcoder.jp/contests/abc128/tasks/abc128_e

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby ハッシュの取り出し

ハッシュの取り出しの復習!!

配列の内部に、複数のユーザーの情報をハッシュとして持つ変数user_data
ターミナルでの結果を以下としたい。
George
Alice
Taro

問題
、、、rb
user_data = [
{
user: {
profile: {
name: 'George'
}
}
},
{
user: {
profile: {
name: 'Alice'
}
}
},
{
user: {
profile: {
name: 'Taro'
}
}
}
]
、、、

答え

、、、
user_data.each do |u|
puts u[:user][:profile][:name]
end
、、、
あるいは
、、、
user_data.each{ |u| puts u.dig(:user, :profile, :name) }
、、、

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列の範囲指定をうっかり間違えたために本当にあった怖い話

要点

  • Rubyの配列の要素取り出しは ary[p..q]ary[p...q] という表記があって、Python の ary[p:q] に相当するのは後者。
  • オーディオサンプリング周波数 44100 を 4 倍して 1 足すと素数になる (←知ってました?)。
  • FFT の一番広く使われている Cooley-Tukey のアルゴリズムはデータを因数分解した数に分けて細切れにしていく。

以上で何がいいたいかわかった方はそれで十分です。気をつけましょう…

本当にあった怖くて恥ずかしい話

Python の numpy で 4 s のオーディオ信号を FFT するプログラムがありました。

ぼくは Python が嫌いなので、それを mrkn 氏の素晴らしい Pycall (https://github.com/mrkn/pycall.rb) を使って Ruby に移植しました。その際、Python で 4 s 切り出す data[ptr:ptr + 44100 * 4] という感じの部分を、うっかりdata[ptr..(ptr + 44100 * 4)] と書いてしまった のです。もちろん正解は .. ではなく ... です。

その結果 謎のフリーズ。いや実際は単に計算に時間がかかっていただけなんですが、10 s 以上も固まれば、そりゃ ^C 押しますって。そして何は原因なんだろうpycallかな、などとあらぬ疑いを頓珍漢な方向に向けたりして リアルに3-4時間くらい時間を無駄にしました。(恥ずかしい。)

衝撃の再現コード

巷では Python の方が人気と聞くので Python のみで動くように書きました。実行すれば驚きを体験できます。

#!/usr/bin/python3
import numpy as np
fs = 44100
duration = 4
data = np.random.randn(fs * 10)           # dummy data
print("test 1")
y = np.fft.fft(data[0:fs * duration])
print("test 2")
y = np.fft.fft(data[0:fs * duration + 1])

本当はいろいろ Ruby で書きたいんだけど numpy とか keras とかがないから必要悪と割り切って Python を使っている人は pycall.rb (やそれを使った numpy.rb) を使いましょう!上記のコードならこんな↓感じにほぼベタ移植できます。すごい > pycall

#!/usr/bin/ruby
require "numpy"                           # gem install numpy
fs = 44100
duration = 4
data = Numpy.random.randn(fs * 10)        # dummy data
puts "test 1"
y = Numpy.fft.fft(data[0...fs * duration])
puts "test 2"
y = Numpy.fft.fft(data[0..fs * duration])

おわりに

  • Ruby は文法がきれいで書きやすくて好きなんですが、まさかこういうハマり方をするとは思ってもいませんでした。自分が悪いんですけど。
  • $44100\times4+1$ という大きめの覚えやすい素数が手に入ったのは収穫。ちなみに $44100\times4-1 = 419\times 421$ も ふたつの素数の積なので注意。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails Tutorialの知識から【ポートフォリオ】を作って勉強する話 #7 ログイン下準備編

こんな人におすすめ

  • プログラミング初心者でポートフォリオの作り方が分からない
  • Rails Tutorialをやってみたが理解することが難しい
  • ポートフォリオを作成しながら勉強したい

リードミー

  • 目的:ポートフォリオを作成して会社に面接を受ける準備をする
  • AWSによるCloud9で作成
  • 間違いの可能性大、一緒に勉強させてください:pray:

ログインまでの色々を実装する

Tutorialは8.1 セッションに突入。
これからログインするまでのあれこれを実装していこう:thumbsup:
流れとしては下記の3つを行う。

  • コントローラ生成
  • ビュー生成
  • それらのテスト生成

機能としてのログインは次回#8。

ログインのためのコントローラ生成

とりあえずTutorial通りにSessionsコントローラを生成する。
くどいけどコントローラテストはRequest specで書く。

bash
$ rails g controller Sessions new
$ rails g rspec:request session
spec/requests/sessions_spec.rb
require 'rails_helper'

RSpec.describe "Sessions", type: :request do

  describe "GET /login" do
    it "returns http success" do
      get login_path
      expect(response).to have_http_status(:success)
    end
  end
end

あとはホーム画面の'Login'ボタンのリンク先も書く。

app/views/layouts/_header.html.erb
<!-- 中略 -->
<div id="menu" class="collapse navbar-collapse">
  <ul class="navbar-nav ml-auto">
    <li class="nav-item">
      <%= link_to "Login", login_path, class: "btn btn-info btn-md" %>
    </li>
  </ul>
</div>
<!-- 中略 -->

以前failureとなったテストがようやくこれで通る。
ではSessionsコントローラを実装しよう。

app/controllers/sessions_controller.rb
class SessionsController < ApplicationController

  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      # ユーザーログイン後にユーザー情報のページにリダイレクトする
    else
      # エラーメッセージを作成する
      render 'new'
    end
  end

  def destroy
  end
end

createアクションにこんな記述があると思うけど、

if user && user.authenticate(params[:session][:password])

Tutorialではこんな風に述べてくれている。

Rubyではnilとfalse以外のすべてのオブジェクトは、真偽値ではtrueになる

だからUserクラスが真偽値っぽくなくてもif文が通るのね。


あと何気にuserがインスタンスじゃないのも特徴。
createアクションに対するビューとかが必要なく(ログインできましたよ!みたいな画面を別で作るなら考慮してよい)アクション内で収まるのでインスタンスでない。

ログインのためのビュー生成

form_for(:session, url: login_path)について考える

続いてログイン画面を作ろうと思うんだけど、Tutorialでこんな記述がある。

form_for(@user)

Railsでは上のように書くだけで、「フォームのactionは/usersというURLへのPOSTである」と自動的に判定しますが、セッションの場合はリソースの名前とそれに対応するURLを具体的に指定する必要があります。

form_for(:session, url: login_path)

なにこれ??最初は意味が分かりませんでした。
で調べたわけだけど、リソース名を'session'にすることでparams[:session]にキーと値が保存されるのね。

つまり渡しているのはそれぞれこう。

form_for(@user)  params[:user]
form_for(:session, url: login_pash)  params[:session]

このあたりはこちらが分かりやすい!↓
rails ログイン機能のform_forの作りについての疑問
[Rails4.0] フォームの基本とStrongParametersを理解する

form_withで書き換える

このポートフォリオではform_forではなくform_withを使う(理由は#6)。
その際はリソース名をscopeに指定するので、最終的にはこうなる。

app/views/sessions/new.html.erb
<% provide(:title, "ログイン") %>
<div class="container form-container login-container">
  <div class="row">
    <div class="col">
      <div class="form-logo-img">
        <%= link_to image_tag('lantern_lantern_logo.png', width: 100), root_path, class: "logo-img" %>
      </div>
      <h1 class="form-title">ログイン</h1>
      <%= form_with(scope: :session, url: login_path, local: true) do |form| %>

        <div class="form-group">
          <%= form.email_field :email, class: 'form-control', placeholder: "メールアドレス" %>
        </div>

        <div class="form-group">
          <%= form.password_field :password, class: 'form-control', placeholder: "パスワード" %>
        </div>

        <div class="form-group">
          <%= form.submit "ログイン", class: "btn btn-info btn-lg form-submit" %>
        </div>
      <% end %>

      <p class="form-go-to-signup-or-login">新しくはじめる方は<%= link_to "こちら", signup_path %></p>
    </div>
  </div>
</div>

書き換えでお世話になりました↓
【Ruby】チュートリアルのform_forをform_withで書き換え (おまけ:capybaraでのテスト)

ログインのE2Eテスト生成

Tutorial 8.1.5 フラッシュのテストにならってテストをSystem specで書こう。
Tutorialとの差分も用意する。

bash
$ touch spec/systems/login_spec.rb
spec/systems/login_spec.rb(RSpec:ポートフォリオ)
require 'rails_helper'

RSpec.describe "Logins", type: :system do

  context "login with invalid information" do
    it "is invalid because it has no information" do
      visit login_path
      expect(page).to have_selector '.login-container'
      fill_in 'メールアドレス', with: ''
      fill_in 'パスワード', with: ''
      click_on 'ログイン'
      expect(page).to have_selector '.login-container'
      expect(page).to have_selector '.alert-danger'
    end

    it "disappears flash messages when users input invalid information then other links" do
      visit login_path
      expect(page).to have_selector '.login-container'
      fill_in 'メールアドレス', with: ''
      fill_in 'パスワード', with: ''
      click_on 'ログイン'
      expect(page).to have_selector '.login-container'
      expect(page).to have_selector '.alert-danger'
      visit root_path
      expect(page).not_to have_selector '.alert-danger'
    end
  end
end
test/integration/users_login_test.rb(Minitest:Tutorial)
require 'test_helper'

class UsersLoginTest < ActionDispatch::IntegrationTest

  test "login with invalid information" do
    get login_path
    assert_template 'sessions/new'
    post login_path, params: { session: { email: "", password: "" } }
    assert_template 'sessions/new'
    assert_not flash.empty?
    get root_path
    assert flash.empty?
  end
end

大きな変更点は5つ。

  1. テストは1つから2つに
  2. getはvisitに
  3. assert_templateはhave_selectorに
  4. postはfill_inに
  5. flash_empty?はhave_selectorに

1.
・フォームに入力しない場合エラーが発生する
・その場合別ページでflashが消える
を独立させたかったので2つに分けた。

2.
System specでgetやpostを指定するとうまくいかない。
代わりにvisitを使おう。

3.
assert_templateもRequest specでしか動作が確認できないので、have_selectorを使用しdivを検証することで描画をテストする。

4.
E2Eテストの性格上、直接postをリクエストするのではなくフォームに値を入力する方がテストらしいのでfill_inを使う。

5.
flashに対してbe_emptyを使用したテストは実装できなかった。
System specではこういう書き方もできない。

expect(flash[:danger]).to be_truthy
bash
NoMethodError:
       undefined method `flash' for nil:NilClass

(Request specでは無事機能する)
Request specと異なりSystem specはコントローラで使用できるFlashHashオブジェクトと紐づいていないっぽい??
代わりにalert時に生成されるdiv要素を検証した。

参考にさせていただきました↓
Ruby on Rails ガイド 5.2 Flash

次回はいよいよ機能としてのログイン実装

おそらく次回がログインのメインです。
Sessionsヘルパーに各メソッドを与えます。
(超初心者向け)解説が載っているのでぜひご参考に〜:stuck_out_tongue_closed_eyes:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsチュートリアル1章まとめ

はじめに

Railsチュートリアルで発生したエラーとか詰まったところをまとめていこうと思います。
備忘録として。
2週目の今回はbitbucketではなくgithubで進めていこうと思います。

rails newの時点でエラー発生

$rails _5.1.6_ new hello_app2

#エラー発生
can't find gem railties (= 5.1.6) with executable rails (Gem::GemNotFoundException)

対処方法が下記コマンド

$gem install rails -v 5.1.6

こちらで再度rails newコマンドすれば無事作成できました。

githubでのリポジトリ作成

いつもはgithubからローカルにクローンするやり方でやってたので今回はこちらで。
ローカルからプッシュするやり方で。

まずgithubでリポジトリ作成する。
名前はhello_app2にしました。

# ローカルリポジトリを作成するディレクトリに移動する
cd hello_app2

# ローカルリポジトリを作成する
$ git init
$ git add .
$ git commit -m "first commit

# リモートリポジトリのアクセス先を設定する
$ git remote add origin https://github.com/GitHubのユーザ名/GitHubのリポジトリ名(こちらではhello_app2).git

# pushする
$ git push -u origin master

git push heroku でエラー

エラー文

remote:  !
remote:  !     Could not detect rake tasks
remote:  !     ensure you can run `$ bundle exec rake -P` against your app
remote:  !     and using the production group of your Gemfile.
remote:  !     Activating bundler (2.0.1) failed:
remote:  !     Could not find 'bundler' (2.0.1) required by your /tmp/build_b85aaac02a3a812e844f20844711c628/Gemfile.lock.
remote:  !     To update to the latest version installed on your system, run `bundle update --bundler`.
remote:  !     To install the missing version, run `gem install bundler:2.0.1`
remote:  !     Checked in 'GEM_PATH=vendor/bundle/ruby/2.5.0', execute `gem env` for more information
remote:  !     
remote:  !     To install the version of bundler this project requires, run `gem install bundler -v '2.0.1'`
remote:  !

こちらのエラー分の中にあるように下記コマンド

$ gem install bundler -v 2.0.1
$ rm Gemfile.lock
$ bundle install
$ git add .
$ git commit -m 'hoge'
$ git push heroku master

こちらで解決し無事デプロイ完了しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む