- 投稿日:2020-07-24T22:57:01+09:00
Python でクラス作成してダックタイピングしてみた
人間クラスと継承、車のクラスで判定
ダックテストというものがあるらしい。Wikipedia様の情報によりますと
"If it walks like a duck and quacks like a duck, it must be a duck"
「もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルに違いない」
という考え方のようです。ここから来たのがダックタイピング。ダックタイピングは例えばRubyだとこんな感じとなります。
Ruby でのダックタイピング
sampleRuby.rb# テスト def test(foo) puts foo.sound end # アヒルの鳴き声 class Duck def sound 'quack' end end # 猫の鳴き声 class Cat def sound 'myaa' end end # 実行 test(Duck.new) test(Cat.new)出力は
# 出力結果 quack myaa要するに、クラスが別であっても同じ名前のメソッドを使用することができ、異なるオブジェクトで同じ操作を切り替えて使うことができるというもののようです。
例えば、人間クラスを若者と大人が継承して、それを車クラスで判定して、ドライバーの資格があるかどうか判定をするとします。
例えば以下のようなサンプルコードはどうでしょう。Pythonです。Python でのダックタイピング
samplePython.py# # 人間のクラス # 2020.07.24 ProOJI # class Person(object): """年齢メソッド""" def __init__(self, age=1): self.age = age """ドライバー資格メソッド""" def drive(self): if self.age >= 18: print('You can drive!') print("Because You're {} years old.".format(self.age)) else: raise Exception('Sorry...you cannot drive.') # 若者のクラス class Young(Person): def __init__(self, age=12): if age < 18: super().__init__(age) else: raise ValueError # 大人のクラス class Adult(Person): def __init__(self, age=18): if age >= 18: super().__init__(age) else: raise ValueError # # 自動車クラス # ドライバー資格の判定 class Car(object): def __init__(self, model=None): self.model = model def ride(self, person): person.drive() # 若者_インスタンスの生成(13歳) young = Young(13) # 大人_インスタンスの生成(46歳) adult = Adult(46)# 自動車_インスタンスの生成_1 car = Car() # 若者の判定 13歳 car.ride(young) # 出力結果 # Exception: Sorry...you cannot drive.# 自動車_インスタンスの生成_2 car = Car() # 若者の判定 46歳 car.ride(adult) # 出力結果 # You can drive! # Because You're 46 years old.まとめ
プログラミングにはポリモーフィズムという概念があり、日本語では多態性・多様性など言われます。これはオブジェクト指向の概念の一つです。
クラスの型が別であっても同じ名前のメソッドがあればそれを使用することができ、異なるオブジェクトで同じ操作を切り替えて使うことができます。
このようなコードをダックタイピング(duck typing)と言うことがわかりました。
- 投稿日:2020-07-24T22:21:16+09:00
deviseのビューファイルに自動でbootstrapのスタイルを適用する
- 投稿日:2020-07-24T20:38:01+09:00
rubyでドローポーカーを作ってみる~実装編5(ゲーム)【完結】~
概要
rubyでドローポーカーを作ってみる~準備編~
↓
rubyでドローポーカーを作ってみる~test-unit準備編~
↓
rubyでドローポーカーを作ってみる~実装編1(カード)~
↓
rubyでドローポーカーを作ってみる~実装編2(役)~
↓
rubyでドローポーカーを作ってみる~実装編3(プレイヤー)~
↓
rubyでドローポーカーを作ってみる~実装編4(山札)~
に続いて。ソース: https://github.com/rytkmt/ruby_poker
ゲームの実装
やってきました。
整理することが多そうなので若干びびってますが、一度すべて洗い出してみたら全体像がつかめて案外・・ってなるかもしれないですね。では、整理していきましょう。
- 山札を作成
- 指定人数分、プレイヤーを作成
- 山札から5枚ずつカードを配る
- 各プレイヤーを順番に変更するカードの確認
- 手札を画面に表示する
- 全カード
- 現在の手札での役
- 変更する場合、枚数分山札からカードを渡し、不要カードを回収し山札の不要カードとして追加する
- 変更後の手札を画面に表示する
- 全カード
- 現在の手札での役
- 全プレイヤーの役を判定する
- 勝者を表示
ゲームの開始
まずゲームは開始するとともに山札を初期化します
ruby_poker/game.rbmodule RubyPoker class Game def initialize @deck = Deck.new end end endゲームの実行
start
って付けようとしていましたが、gameを行うのはplay
のほうが適切だと思ったのでplay
でいきます
このとき、new.play
って毎回するのもあほらしいので、.play
メソッドを用意してしまいますruby_poker/game.rbdef self.play new.send(:play) end private def play puts "<ゲーム開始>" puts "<ゲーム終了>" endプレイヤーの名称を保持
毎回プレイヤー番号を渡し続けるのもしんどいので、プレイヤーの名称を保持しておくように機能強化します。
ruby_poker/player.rbmodule RubyPoker class Player include Comparable - attr_reader :hand + attr_reader :name, :hand - def initialize(cards:) + def initialize(name:, cards:)プレイヤー人数の決定
プレイヤーを初期化するにあたり、人数を入力してもらい、カードを5枚ずつ配ります
人数の入力は間違うこともあるため、間違っている場合は再度入力を促すようにしますruby_poker/game.rbdef init_players(count:) @players = count.times.map { |i| Player.new(name: "プレイヤー#{i + 1}", cards: @deck.draw(count: 5)) } end def input_player_count puts "プレイヤーの参加人数を入力してください(1~7)" player_count = gets.to_i return player_count if (1..7).include?(player_count) puts "入力が間違っています" input_player_count endプレイヤーの手札表示
プレイヤーの手札を表示するために、カード、役などそれぞれ表示用の文字列を生成します。
このとき、コンソール出力はinspect
メソッドを使用するのが一般的なのでそちらで実装します。プレイヤーは各カードと役を表示します。
なので、カード、役にもそれぞれinspect
を定義し、それを合わせて出力するのをプレイヤーの出力で行うようにします。また、カードの表示がわりと見にくいので、色を付けて表示するようにしてみます。
色表示用のgemインストール
Gemrfile+gem "rainbow"
$ bundle installruby_poker.rb+require "rainbow"
これで
puts Rainbow("hoge").red
とかすることでカラー表示できるようになりますカードのinspect
- スートの表示用に記号へ変換
- 数字の記号変換
- スートに応じてカラーを切替
をそれぞれ行います
ruby_poker/card.rbdef inspect suit_str = case @suit when :spade; "♠" when :heart; "♥" when :diamond; "♦" when :club; "♣" end number_str = case @number when 1; "A" when 13; "K" when 12; "Q" when 11; "J" else; @number end color = case @suit when :spade; :blue when :heart; :red when :diamond; :yellow when :club; :green end Rainbow("[#{suit_str} #{number_str}]").send(color) end役のinspect
ruby_poker/hand.rbdef inspect hand_type_name = case @hand_type when :royal_straight_flush; "ロイヤルストレートフラッシュ" when :straight_flush; "ストレートフラッシュ" when :four_of_a_kind; "フォーカード" when :full_house; "フルハウス" when :flush; "フラッシュ" when :straight; "ストレート" when :three_of_a_kind; "スリーカード" when :two_pair; "ツーペア" when :one_pair; "ワンペア" when :high_card; "?" end "役: #{hand_type_name}" endプレイヤーのinspect
最後にプレイヤーです
カード交換の際に番号入力をしてもらうため、各カードに番号をつけて表示します。
ruby_poker/player.rbdef inspect cards_str = @cards.map.with_index(1) do |card, i| "#{i}. #{card.inspect}" end.join(" ") cards_str + "\n" + @hand.inspect + "\n" endこれで、
p player
をすることで こんな感じになります(色はここでは映らないですが・・)
↓1. [♥ 5] 2. [♦ 8] 3. [♣ 4] 4. [♠ 10] 5. [♠ 4] 役: ワンペアプレイヤーのターン処理
- 各プレイヤーの現在の状況を表示
- カード交換を確認
- 入力が間違っていたら再度確認する
- 交換後の手札を表示
ruby_poker/game.rbdef turn(player:) puts "\n#{player.name} のターンです" p player puts "カードの交換ができます" indexes = input_change_indexes return if indexes.empty? new_cards = @deck.draw(count: indexes.size) trushed = player.change(indexes: indexes, new_cards: new_cards) @deck.trush(cards: trushed) p player end def input_change_indexes puts "捨てるカードの番号を半角スペース区切りで入力してください(なければそのままEnter)" indexes = gets.chomp.split.map(&:to_i) return indexes.map { |i| i - 1 }.sort if indexes.all? { |i| (1..5).include?(i) } input_change_indexes endプレイヤーの勝敗判定
ruby_poker/game.rbdef judge puts "----- 結果 -----" @players.each do |player| puts "#{player.name} の手札" p player puts "" end winner = @players.max puts Rainbow("\n#{winner.name} の勝ち ??").underline end実行メソッドにまとめる
ruby_poker/game.rbdef play puts "<ゲーム開始>" init_players(count: input_player_count) @players.each { |player| turn(player: player) } judge puts "<ゲーム終了>" endゲームの実行を簡単にする
RubyPoker::Game.play
となりますが、RubyPoker.paly
がいい。。ruby_poker.rbdef self.play RubyPoker::Game.play end完成
bundle exec console
を実行することでゲームを楽しむことができます。感想
Qiitaで見た1つの記事をきっかけに「やってみよう」と思い今回の記事を書きながら実装しました。
実際に実装していく流れなどをみなさんがどういう風に行っているのか?というところは、いざ仕事で開発をしていると各個人で頭の中で考えて全て整ったプログラムを確認することばかりのため、
あまり実装のプロセスを覗く機会がない印象があります。
今回の記事が少しでも参考になればうれしいです。普段仕事ではrailsのプロジェクトなので、railsやgemを触ることはありますが、
単一のrubyプロジェクトを作ることは無かったためGemfile、Rakefileなど改めてこういう感じで進めるんだ~と自分のなかでもふわっとしていたところが理解できました。
普段使わないgemを触るのも楽しかったです。この記事をもとに同じように刺激をうけ、なにか作ってみよう と思う方がいればうれしいです。
また、流れを公開したことにより、もしここをこういう風にするとより良くなる などのアドバイスがあればぜひ教えてください。お待ちしております。実際のソースはこちらにあります。 https://github.com/rytkmt/ruby_poker
実装に関しての感想
今回、ポーカーに限った実装でしたが、
カードを共通として、プレイヤーと山札の処理をゲームの種別に応じてモジュールを切り替えることによっていろんなゲームを載せる なども出来そうかなーと思いました。また、役判定を完全に切り分けることで、ローカルルールで役を追加する(奇数・偶数でのストレートとかあっても面白そう)などもできるかなと思います
今回jokerは考慮せず作ったため、それを追加するのは少し大変だなーとは思いますが、やってみるのも楽しいかもしれないですね。
以上、かなり記事数も多くなりましたが、長々と見ていただいた方、ありがとうございました。
- 投稿日:2020-07-24T20:34:03+09:00
[Ruby]変数の中身を表示する
- 投稿日:2020-07-24T18:51:38+09:00
bundle install時のエラー
概要
Railsアプリケーションでgemをbundle installした際に発生したエラーと解消方法について記します。
環境
Ruby 2.6.5
Ruby on Rails 6.0.0内容
エラー文
An error occurred while installing pg (1.2.3), and Bundler cannot continue. Make sure that `gem install pg -v '1.2.3' --source 'https://rubygems.org/'` succeeds before bundling.と
Could not find gem 'pg (>= 0.18, < 2.0)' in any of the gem sources listed in your Gemfile.といったエラーです。
解消方法
下記コマンドで解消しました。
brew install postgrespostgresSQLで引っかかっていたみたいです。
- 投稿日:2020-07-24T18:44:22+09:00
[Rails]エラーメッセージの日本語化
概要
Railsアプリケーションのエラーメッセージを日本語化する手順を記します。
入植画面で未入力や不備があった場合に出力する下記の様なメッセージです。環境
Ruby 2.6.
Ruby on Rails 6.0.0手順
①config/application.rbに記述
module Pictweet class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.0 # 日本語の言語設定 config.i18n.default_locale = :ja # 省略 end end②gemfileに記述
gem ‘rails-i18n'bundle install実行
※ここまででカラム名以外は日本語になっています。
③config/locales/devise.en.ymlに以下URLのコードをコピペする
https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml※ここまででdeviseであらかじめ作成されるカラム(emai、password、password確認用)は日本語になっています。
④config/localesにja.yml作成
ja: activerecord: attributes: user: nickname: ニックネーム tweet: text: テキスト image: 画像この記述で、Nickname、Text、Imageが日本語に翻訳されます!
- 投稿日:2020-07-24T18:12:17+09:00
【初心者】環境変数設定-dotenv-rails-
環境変数とは
環境変数とは、Githubにアップロードすることができない情報を入れておく箱のようなものです。
これにより、アプリケーションに直接パスワードなどを記述しなくとも、
OSからデータを渡す事で、情報漏洩の心配なく、アプリを稼働させる事ができます。設定方法
gemのインストール
Gemfilegem 'dotenv-rails'$ bundle install.envファイル作成
Gemfileが置いてあるルートディレクトリに
.envファイルを作成環境変数作成
KEY='*******' #使用したいキーやパスワードを SECRET_KEY='*******'呼び出す時は
ENV['KEY']とすれば呼び出せます。
Git管理下から除外
.gitignore/.envこれを忘れると情報が漏洩してしまうので忘れずに必ず設定してください。
- 投稿日:2020-07-24T18:03:03+09:00
[Rails]Formオブジェクト使用時のエラーメッセージ日本語化
概要
RailsフリマアプリでFormオブジェクトを実装した部分のみ、日本語化がうまく行かなかったので、解消方法を記します。
前提
ja.ymlファイルの作成までは完了している。
Formオブジェクト以外のエラーメッセージについては日本語化ができている。環境
- ruby 2/6/5
- Ruby on Rails 6.0.0
内容
ja.yml
に日本語入力の記述をしても日本語にならないconfig/locales/ja.yml
ja: activerecord: attributes: user: nickname: ニックネーム item: text: テキスト image: 画像 name: 商品名 card_address: postal_code: 郵便番号 city: 市区町村 address: 番地 phone_number: 電話番号以下の内容に修正し解消しました。
ja: activerecord: attributes: user: nickname: ニックネーム item: text: テキスト image: 画像 name: 商品名 activemodel: attributes: card_address: postal_code: 郵便番号 city: 市区町村 address: 番地 phone_number: 電話番号原因
formオブジェクトの記述を行なったforms/card_addressファイルは
ActiveModel
を継承しているファイルだった為、activerecord:(2行目)
では反映されなかったみたいです。
- 投稿日:2020-07-24T17:55:30+09:00
rubyでドローポーカーを作ってみる~実装編4(山札)~
概要
rubyでドローポーカーを作ってみる~準備編~
↓
rubyでドローポーカーを作ってみる~test-unit準備編~
↓
rubyでドローポーカーを作ってみる~実装編1(カード)~
↓
rubyでドローポーカーを作ってみる~実装編2(役)~
↓
rubyでドローポーカーを作ってみる~実装編3(プレイヤー)~
に続いて。ソース: https://github.com/rytkmt/ruby_poker
山札の実装
はい、では今回も同じくまずは要件の整理からいきます。
- はじめは13 x 4のカードを全て使用して山札を作成する
- カードの並び順はばらばら
- 手札交換を行って不要になったカードは回収する
- 山札から任意の枚数をドローする
- ドローする枚数が足りなくなった場合、手札交換にて不要になったカードをまぜてシャッフルしてそこから引く
という感じですかね。
プレイヤーの手札交換の修正
ここで気づいてしまいましたが、前回のプレイヤーの実装にて手札交換でただ手札のカードから削除するだけと実装してしまっていたため
捨てるカードを回収するように修正します・・ruby_poker/player.rbdef change(indexes:, new_cards:) raise(ArgumentError) unless indexes.size == new_cards.size raise(ArgumentError) unless indexes.all? { |i| (0..4).include?(i) } - indexes.sort.reverse_each { |i| @cards.delete_at(i) } + trushed = indexes.sort.reverse.each_with_object([]) { |i, trushed| trushed << @cards.delete_at(i) } @cards += new_cards @hand = Hand.new(cards: @cards) + trushed end山札の作成
ruby_poker/deck.rbmodule RubyPoker class Deck def initialize @cards = init_cards @trushed = [] end private def init_cards RubyPoker::SUITS.each_with_object([]) do |suit, cards| cards.concat( RubyPoker::NUMBERS.map { |number| Card.new(suit: suit, number: number) } ) end.shuffle end end end始め、each_with_object内で
+=
を使って実装したのですが、よくよく考えるとこれは+
で結合したものを=
で変数代入してるので同一の変数に結合した別オブジェクトを格納しているだけで、破壊的な変更を行っているわけではないのでうまくいかなかったです。破壊的にcardsを変更するために
concat
を使います。手札交換によるカードの回収
プレイヤーの
#change
にて返ってきた不要カードを回収して保持しておくだけなので簡単ですruby_poker/deck.rbdef trush(cards:) @trushed += cards endカードのドロー
- 山札から任意の枚数をドローする
- ドローする枚数が足りなくなった場合、手札交換にて不要になったカードをまぜてシャッフルしてそこから引く
ruby/ruby_poker/deck.rbdef draw(count:) merge_trushed if @cards.size < count raise(ArgumentError, "No cards.") if @cards.size < count @cards.shift(count) end private def merge_trushed @cards += @trushed @cards.shuffle! @trushed = [] end足りなくなるってプレイ人数の設定がイケてないだけな気がするので、そこは起こらない前提でエラーを吐くようにしました。
終わりに
山札もシンプルでしたね。
これで次こそゲーム進行回りの実装に入れるかな?と思います。完成も近づいてきました。4連休で終わらせてしまいたいですし最後までやってしまいます。
- 投稿日:2020-07-24T16:55:13+09:00
【cygwin】Redmineをインストール
参考ページ一覧
- https://redmine.jp
- https://rubygems.org
- http://guide.redmine.jp/RedmineInstall/
- cygwinなので読み替えは必要だけど手本となるページ
- http://guide.redmine.jp/RedmineBackupRestore/#sqlite
- バックアップとリストアについて
- http://guide.redmine.jp/RedmineUpgrade/
- アップグレードについて
- https://qiita.com/jnchito/items/d3257a5f46f4f1aee200
- bundleコマンド実行時のメッセージからたどり着いた
- bundle3を見据えた非推奨なオプションなど
- https://www.redmine.org/projects/redmine/wiki/HowTo_install_rmagick_gem_on_Windows
- rmagickのインストール手順
留意点
- 現在(2020-07-24)、bundleがバージョンアップを見据えた対応している。
- この関係もあり、古い情報は
rubygem
,bundle
に注意ダウンロードファイル一覧
- redmine-4.1.1.tar.gz
- rubygems-3.1.4.tgz
cygwinパッケージ一覧
- rubygemインストールで必要
ruby
,ruby-devel
- bundle installに必要
mysql-devel
,libsqlite3-devel
- nokogiriのインストールに必要
libxml2-devel
,libxslt-devel
各バージョン
name version installation ruby 2.6.4p104 cygwin rubygem 3.1.4 rubygems-3.1.4.tgz rails 6.0.3.2 gem redmine 4.1.1 redmine-4.1.1.tar.gz インストール手順
rubygems
$ tar xvzf rubygems-3.1.4.tgz $ cd rubygems-3.1.4 $ ruby setup.rb
/usr/bin/gem
,/usr/bin/bundle
がインストールされます。redmine
redmine動作環境に必要なパッケージの情報として、
GemFile
がredmine-4.1.1.tgz
に含まれています。以下はHOMEから始まります
$ tar xvzf src/redmine-4.1.1.tar.gz $ cd redmine-4.1.1/conf $ cp configuration.yml.example configuration.yml $ cp database.yml.example database.yml $ vi configuration.yml $ vi database.yml
- configuration.ymlの設定箇所
scm_subversion_command
設定例通りに設定scm_cvs_command
設定例通りに設定scm_cvs_path_regexp
一つあるcvs repositoryのフルパスscm_stderr_log_file
設定例通りに設定- database.ymlの設定箇所
mysql2
を無効にしてsqlite3
を有効にした。
- 利用者1名のため
以降に継続
$ bundle config without 'development test' --local $ vi .bundle/config
--local
をつけ忘れると~/.bundle/config
に保存される以降に継続
$ bundle lock --add-platform x86-mingw32 x64-mingw32 x86-mswin32
- 結果として、 "GemFile.lock"が作成される。
以降に継続
$ bundle install $ bundle update$ bundle config build.nokogiri --use-system-libraries --local $ bundle install $ bundle update$ bundle exec rake generate_secret_token $ RAILS_ENV=production bundle exec rake db:migrate $ RAILS_ENV=production REDMINE_LANG=ja bundle exec rake redmine:load_default_dataremine立ち上げ
bundle exec rails server webrick -e productionlocalhost:3000にアクセス
課題
- ImageMagickのインストール
参考
rubygemインストールの様子(要点のみ)
$ ruby setup.rb Successfully built RubyGem Name: bundler Version: 2.1.4 File: bundler-2.1.4.gem Bundler 2.1.4 installed RubyGems 3.1.4 installed Regenerating binstubs Parsing documentation for rubygems-3.1.4 Installing ri documentation for rubygems-3.1.4 … ------------------------------------------------------------------------------ RubyGems installed the following executables: /usr/bin/gem /usr/bin/bundle Ruby Interactive (ri) documentation was installed. ri is kind of like man pages for Ruby libraries. You may access it like this: ri Classname ri Classname.class_method ri Classname#instance_method If you do not wish to install this documentation in the future, use the --no-document flag, or set it as the default in your ~/.gemrc file. See 'gem help env' for details.bundle実行時の警告
参考にしたページに倣って
bundle install --without development test
を実行すると以下のメッセージが黄色で表示される。$ bundle install --without development test [DEPRECATED] The `--without` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set without 'development test'`, and stop using this flag The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x64-mingw32, x86-mswin32. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x64-mingw32 x86-mswin32`. The dependency ffi (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x64-mingw32, x86-mswin32. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x64-mingw32 x86-mswin32`.rubygemインストールの様子(詳細)
$ ruby setup.rb Successfully built RubyGem Name: bundler Version: 2.1.4 File: bundler-2.1.4.gem Bundler 2.1.4 installed RubyGems 3.1.4 installed Regenerating binstubs Parsing documentation for rubygems-3.1.4 Installing ri documentation for rubygems-3.1.4 === 3.1.4 / 2020-06-03 Minor enhancements: * Deprecate rubyforge_project attribute only during build time. Pull request #3609 by Josef Šimánek. * Update links. Pull request #3610 by Josef Šimánek. * Run CI at 3.1 branch head as well. Pull request #3677 by Josef Šimánek. * Remove failing ubuntu-rvm CI flow. Pull request #3611 by Josef Šimánek. === 3.1.3 / 2020-05-05 Minor enhancements: * Resolver: require NameTuple before use. Pull request #3171 by Olle Jonsson. * Use absolute paths with autoload. Pull request #3100 by David Rodríguez. * Avoid changing $SOURCE_DATE_EPOCH. Pull request #3088 by Ellen Marie Dash. * Use Bundler 2.1.4. Pull request #3072 by Hiroshi SHIBATA. * Add tests to check if Gem.ruby_version works with ruby git master. Pull request #3049 by Yusuke Endoh. Bug fixes: * Fix platform comparison check in #contains_requirable_file?. Pull request #3495 by Benoit Daloze. * Improve gzip errors logging. Pull request #3485 by David Rodríguez. * Fix incorrect `gem uninstall --all` message. Pull request #3483 by David Rodríguez. * Fix incorrect bundler version being required. Pull request #3458 by David Rodríguez. * Fix gem install from a gemdeps file with complex dependencies. Pull request #3054 by Luis Sagastume. === 3.1.2 / 2019-12-20 Minor enhancements: * Restore non prompting `gem update --system` behavior. Pull request #3040 by David Rodríguez. * Show only release notes for new code installed. Pull request #3041 by David Rodríguez. * Inform about installed `bundle` executable after `gem update --system`. Pull request #3042 by David Rodríguez. * Use Bundler 2.1.2. Pull request #3043 by SHIBATA Hiroshi. Bug fixes: * Require `uri` in source.rb. Pull request #3034 by mihaibuzgau. * Fix `gem update --system --force`. Pull request #3035 by David Rodríguez. * Move `require uri` to source_list. Pull request #3038 by mihaibuzgau. === 3.1.1 / 2019-12-16 Bug fixes: * Vendor Bundler 2.1.0 again. The version of Bundler with RubyGems 3.1.0 was Bundler 2.1.0.pre.3. Pull request #3029 by SHIBATA Hiroshi. ------------------------------------------------------------------------------ RubyGems installed the following executables: /usr/bin/gem /usr/bin/bundle Ruby Interactive (ri) documentation was installed. ri is kind of like man pages for Ruby libraries. You may access it like this: ri Classname ri Classname.class_method ri Classname#instance_method If you do not wish to install this documentation in the future, use the --no-document flag, or set it as the default in your ~/.gemrc file. See 'gem help env' for details.
- 投稿日:2020-07-24T16:55:13+09:00
【cygwin】Redmineを動かす
留意点
- 現在(2020-07-24)、bundleがバージョンアップを見据えた対応している。
- この関係もあり、古い情報は
rubygem
,bundle
に注意- 個人で利用することを前提に、sqlite3を利用する。
ダウンロードファイル一覧
- redmine-4.1.1.tar.gz
- rubygems-3.1.4.tgz
cygwinパッケージ一覧
- rubygemインストールで必要
ruby
,ruby-devel
- bundle installに必要
mysql-devel
,libsqlite3-devel
- nokogiriのインストールに必要
libxml2-devel
,libxslt-devel
各バージョン
name version installation ruby 2.6.4p104 cygwin rubygem 3.1.4 rubygems-3.1.4.tgz rails 6.0.3.2 gem redmine 4.1.1 redmine-4.1.1.tar.gz インストール手順
rubygems
$ tar xvzf rubygems-3.1.4.tgz $ cd rubygems-3.1.4 $ ruby setup.rb
/usr/bin/gem
,/usr/bin/bundle
がインストールされます。redmine
redmine動作環境に必要なパッケージの情報として、
GemFile
がredmine-4.1.1.tgz
に含まれています。以下はHOMEから始まります
$ tar xvzf src/redmine-4.1.1.tar.gz $ cd redmine-4.1.1/conf $ cp configuration.yml.example configuration.yml $ cp database.yml.example database.yml $ vi configuration.yml $ vi database.yml
- configuration.ymlの設定箇所
scm_subversion_command
設定例通りに設定scm_cvs_command
設定例通りに設定scm_cvs_path_regexp
一つあるcvs repositoryのフルパスscm_stderr_log_file
設定例通りに設定- database.ymlの設定箇所
mysql2
を無効にしてsqlite3
を有効にした。
- 利用者1名のため
以降に継続
$ bundle config without 'development test' --local $ vi .bundle/config
--local
をつけ忘れると~/.bundle/config
に保存される以降に継続
$ bundle lock --add-platform x86-mingw32 x64-mingw32 x86-mswin32
- 結果として、 "GemFile.lock"が作成される。
以降に継続
$ bundle install $ bundle update$ bundle config build.nokogiri --use-system-libraries --local $ bundle install $ bundle update$ bundle exec rake generate_secret_token $ RAILS_ENV=production bundle exec rake db:migrate $ RAILS_ENV=production REDMINE_LANG=ja bundle exec rake redmine:load_default_dataremine立ち上げ
bundle exec rails server webrick -e productionlocalhost:3000にアクセス
課題
- ImageMagickのインストール
参考
rubygemインストールの様子(要点のみ)
$ ruby setup.rb Successfully built RubyGem Name: bundler Version: 2.1.4 File: bundler-2.1.4.gem Bundler 2.1.4 installed RubyGems 3.1.4 installed Regenerating binstubs Parsing documentation for rubygems-3.1.4 Installing ri documentation for rubygems-3.1.4 … ------------------------------------------------------------------------------ RubyGems installed the following executables: /usr/bin/gem /usr/bin/bundle Ruby Interactive (ri) documentation was installed. ri is kind of like man pages for Ruby libraries. You may access it like this: ri Classname ri Classname.class_method ri Classname#instance_method If you do not wish to install this documentation in the future, use the --no-document flag, or set it as the default in your ~/.gemrc file. See 'gem help env' for details.bundle実行時の警告
参考にしたページに倣って
bundle install --without development test
を実行すると以下のメッセージが黄色で表示される。$ bundle install --without development test [DEPRECATED] The `--without` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set without 'development test'`, and stop using this flag The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x64-mingw32, x86-mswin32. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x64-mingw32 x86-mswin32`. The dependency ffi (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x64-mingw32, x86-mswin32. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x64-mingw32 x86-mswin32`.rubygemインストールの様子(詳細)
$ ruby setup.rb Successfully built RubyGem Name: bundler Version: 2.1.4 File: bundler-2.1.4.gem Bundler 2.1.4 installed RubyGems 3.1.4 installed Regenerating binstubs Parsing documentation for rubygems-3.1.4 Installing ri documentation for rubygems-3.1.4 === 3.1.4 / 2020-06-03 Minor enhancements: * Deprecate rubyforge_project attribute only during build time. Pull request #3609 by Josef Šimánek. * Update links. Pull request #3610 by Josef Šimánek. * Run CI at 3.1 branch head as well. Pull request #3677 by Josef Šimánek. * Remove failing ubuntu-rvm CI flow. Pull request #3611 by Josef Šimánek. === 3.1.3 / 2020-05-05 Minor enhancements: * Resolver: require NameTuple before use. Pull request #3171 by Olle Jonsson. * Use absolute paths with autoload. Pull request #3100 by David Rodríguez. * Avoid changing $SOURCE_DATE_EPOCH. Pull request #3088 by Ellen Marie Dash. * Use Bundler 2.1.4. Pull request #3072 by Hiroshi SHIBATA. * Add tests to check if Gem.ruby_version works with ruby git master. Pull request #3049 by Yusuke Endoh. Bug fixes: * Fix platform comparison check in #contains_requirable_file?. Pull request #3495 by Benoit Daloze. * Improve gzip errors logging. Pull request #3485 by David Rodríguez. * Fix incorrect `gem uninstall --all` message. Pull request #3483 by David Rodríguez. * Fix incorrect bundler version being required. Pull request #3458 by David Rodríguez. * Fix gem install from a gemdeps file with complex dependencies. Pull request #3054 by Luis Sagastume. === 3.1.2 / 2019-12-20 Minor enhancements: * Restore non prompting `gem update --system` behavior. Pull request #3040 by David Rodríguez. * Show only release notes for new code installed. Pull request #3041 by David Rodríguez. * Inform about installed `bundle` executable after `gem update --system`. Pull request #3042 by David Rodríguez. * Use Bundler 2.1.2. Pull request #3043 by SHIBATA Hiroshi. Bug fixes: * Require `uri` in source.rb. Pull request #3034 by mihaibuzgau. * Fix `gem update --system --force`. Pull request #3035 by David Rodríguez. * Move `require uri` to source_list. Pull request #3038 by mihaibuzgau. === 3.1.1 / 2019-12-16 Bug fixes: * Vendor Bundler 2.1.0 again. The version of Bundler with RubyGems 3.1.0 was Bundler 2.1.0.pre.3. Pull request #3029 by SHIBATA Hiroshi. ------------------------------------------------------------------------------ RubyGems installed the following executables: /usr/bin/gem /usr/bin/bundle Ruby Interactive (ri) documentation was installed. ri is kind of like man pages for Ruby libraries. You may access it like this: ri Classname ri Classname.class_method ri Classname#instance_method If you do not wish to install this documentation in the future, use the --no-document flag, or set it as the default in your ~/.gemrc file. See 'gem help env' for details.リンク一覧
- https://redmine.jp
- https://rubygems.org
- http://guide.redmine.jp/RedmineInstall/
- cygwinなので読み替えは必要だけど手本となるページ
- http://guide.redmine.jp/RedmineBackupRestore/#sqlite
- バックアップとリストアについて
- http://guide.redmine.jp/RedmineUpgrade/
- アップグレードについて
- https://qiita.com/jnchito/items/d3257a5f46f4f1aee200
- bundleコマンド実行時のメッセージからたどり着いた
- bundle3を見据えた非推奨なオプションなど
- https://www.redmine.org/projects/redmine/wiki/HowTo_install_rmagick_gem_on_Windows
- rmagickのインストール手順
- 投稿日:2020-07-24T16:50:25+09:00
ActiveStorageをクラウドストレージ(GCS,S3, etc)で使ってた時に処理が遅くなる問題
概要
Heroku上で動かしていたRailsアプリの処理が遅かった時の調査メモです。
結論として、画像保存に使用していたGCPのクラウドストレージの部分がボトルネックとなっていました。環境
- Ruby 2.6.3p62
- Rails 6.0.2.2
背景
Herokuの無料プランでRailsを使った趣味のWEBサイトを構築運用しています。
当初から処理はあまり早くないものの、SQLに関してもRedisでキャッシュを入れたりしていたので、まぁ無料ならこんなものかと思っていました。しかしながら、一部のページのみ他のページより早い事に気がつき、何が原因かを調べることとしました。
調査
調査方法
一般的な方法ですが、下記のコマンドでログを出力させて処理時間を調べる事にしました。
heroku logs --tail
デフォルトでRailsはDEBUGログで処理時間を色々出してくれるので、まずはそこを確認する事にしました。
ログの調査結果
当初はキャッシュしていない部分のSQLが遅いのかと思っていましたが、
SQLに関してはキャッシュも効いて遅いクエリも見つかりませんでした。しかしながら、代わりに下記のような処理時間に100ms以上かかっているログが何箇所が見受けられました。
GCS Storage (169.9ms) Checked if file exists at key: variants/xxxx該当のサイトは画像をGCSにアップロードしており、その部分が関連している事が推測できました。
また、variantといったキーワードからActiveStorageの該当機能が影響していることもわかります。Variant
このvariantに関しては下記の参考資料などを見ていただければと思いますが簡単に言えば、アップロードした画像をそのまま使わずにリサイズ等を行う機能です。
参考この機能を使えばわざわざ自分でリサイズ処理などを実装する必要がなく、更に初回アクセス時にリサイズした画像を保存して裏で再利用してくれてかなり便利な機能です。
ですが、今回はきの機能が何か悪影響を与えているようです。ググってみる
これ以上の調査は難しいと判断し、とりあえず似たような症状が他でも起きているのかググってみました。
結果として、AWSのS3などで似たような症状と思われるものが何点か見つかりました。
https://stackoverflow.com/questions/49415911/activestorage-checking-if-file-exists-is-slow
https://github.com/rails/rails/issues/32548
https://github.com/rails/rails/pull/37901拙い英語力で斜め読みした所、下記のように判断しました。
(間違っていたらすみません。)
- 変換し保存した画像の存在チェックを行なっており、そこで時間がかかっている
- 既に対応する修正を行なっており、Railsバージョン(6.1)に含まれる
解決方法
上記を見て、最新版にすれば解決するかと思いましたが、残念ながら6.1はまだリリースされていませんでした・・・。
結論として、varianによる圧縮処理をやめて元の画像を使用する事としました。
元の画像に関して、そもそもアップロード前に手動で画像ツール等でリサイズなどの補正をしているため問題にはならないだろうという判断です。結果として元の100ms以上かかっていたログは消えて、下記のような1ミリ秒の処理に変更され、体感的に速度が早くなったように感じます。
GCS Storage (1.5ms) Generated URL for file at key: xxxxまとめ
という事で、クラウドストレージ(GCS)でActiveStorageで加工した画像を使用する際に処理時間がかかっている事が原因でした。
根本的な対策はせずに機能を使用しないという、微妙な形で対応する事としました。いずれリリースされるRails6.1では対策がされているようなので、アップデート後にはまた機能を使用したいと思います。
S3やGCSなどクラウドストレージをお手軽に使用できるActive Storageですが、裏で色々と隠蔽してくれているおかげで、逆に見えない箇所で性能に影響を与える事がわかりました。
- 投稿日:2020-07-24T16:27:09+09:00
NGSシミュレーションの古典的ソフトwgsimで遊ぶ 〜謎の生物プー〜
はじめに
謎の生物 プー それは、太古から存在するかもしれない 謎の生物です。
wgsimとはなんじゃらほい?
wgsimとはバイオインフォ界の巨星 Heng Liさんが作ったNGSのシミュレーターです。
2011年のソフトですが問題なく動きます。インストール
Biocondaを導入している場合は
conda install wgsim〜 謎の生物プー 〜
謎の生物プーは、まったくの気まぐれから生み出されました。
神は生物を創造します。(進化など言語道断です。)
あなたは神なので、ちょっとしたウイルスと同じぐらいの配列、5000塩基の生物を創造しましょう。この生物の名前を「プー」と名付けました。プーのリファレンス配列は、ランダムで生成しています。(筆者は絶滅危惧種のRuby派なのですが、ほかのプログラミング言語でも同じことができるでしょう。)
genome = Array.new(5000){ %w[A C T G].sample } puts '>poo chr1' genome.each_slice(80) do |l| puts l.join('') endこのスクリプトを実行すると、こんな感じで配列が出力されると思います。
これが謎の生物プーのリファレンスゲノムだッ!!!
>poo chr1 AAAGCGCTGGATCATGCTTTAAGGCTTAGTTTTATGGCCCTAAACACGGAGACTGAAGCCGCTTGAGTCCGGTTTCAGAG AGATTTGGTTTCACCCACAACTGCCAGCATATAATGGACCGTCGGCCGTACACGTTATGAGCCTGGCAGGGGTTACTACG CGCCACGGGCTAGAGACCTAGTGGCGAAACGTGAAGGGCAATTATGGAATCCCGTACGCGCAATAAATGTCTACGCATTC CCGGGGGGTGTTGTAGTCCCACGGCCCCGGACCTGCATTGGTCCAAATTCTCTTCGGTGCATATTAGCTTCATCGGAACC GGCCTTTCTAATTCAGAACTGTTCGGTCATACACTATCTTCCAACACGCCGTGCACGAGTTGCACGGAGATCTAGTTGTT ACTCGACGCGCGTACGACCGAGGCGGGGCTTAACACGCGAGTAGAAGCCCTGGGTTATCCACCACTTAATTTTGTAAAAA GCGCTTTCAGTACTACACGGCTTGACCGTAGCTCTGTCGGACTTGTGACCCCTTCCGGCGAACATTAATTGTACCCCTTC TTCTGACGGATTGGTTAGTAGTCCAAGCAGTCTTCACCCCAGGAGCACTTCTTCTTGCCGCGAGGCCATTCAGTCCAGTT CGTGATGGCGGGGGTACCGATGCAAAAGCTCGTCTTTCTTGAGGCATCCACAGCCAGAGGCGGGGTATTTACGAGATTAA GTTCTATCATTGCACTAGACAAAGCAAGTACAGCTCGGCAAAAAGAAACTCGTGGGCGCGTCTTGACCTGCAGCTAATAC TGACTAGCATCCGTAGATATTACCGATCGTGCCGCACAAGGGAAATCTCGAGGCTGACAACGTCTTTGCCAAGGCAGTGG CCGTGTCTTCTCGCCAGGGGTAAAGGTGCCGCTGGACTAGCGCTAACTTAGTGTCGTAATATCTCCATATGGACGATTTC CCCGATCTTACCGGCTAGCCGCTGGTTGTATGCCGCGCCCAGGCCACCGAGTCTGACATGTTCCAAGGGCCTCATGTGAA AGCGATGTGCTGATCCAGCATGGCCTTCAGCCTCACAAGACTGAGAGTTGGTGTAGAAACCCGGTTTGTTGGTAGTATGA TGCTTAAAAATCGGTTTAATTTAGCTTGGTTAGATTTGAACGTGAAGAGCCTATGTCCAAAGACCAACTAACCTACTCAG ACTAAGATTTACCGATTTCTCGTTTTGACTGAGATACGTAGTTAGCTATACGGGGCGTCGCCATCCTCTACCCCTTGAAT ATGATTCGTAAGTGATGCCATTCTCGTGCTCGTGCGCTATGAATAGCAATGTCACCACAATAGTGCCCGGTGGCCGACAA TCCGAGACCATGTCCGTCCTCATTCATGCGTAGTTAGTAGTGTATCGACTCACCTGGAGATGACCTCTATGTCCTGCTGC GGTACGGCACGGCAGGATCTTTCTAGAAACATCGGCGATGCCCCAGAGGTTCTCTAAACTGTGTCATCTTTTTCTGCGGT GCGTGGCTGGTCAAACCATTCAAATATATGAGAGTCATGCGCTAGCTCCCGGTAAAACCCCACAATAACGGGATTTGGGG TTGAAAATGCGAGGCAGCGCACATGGATCAGGCCATTTAGGGTGTGATTGGTATGTTCCGAAAAAGCTGATGAGAACTAT GCCCCGTTTACTTTGCCAGTAGAAAGAGTAGGAAGTAGTGTAACGCGGGCACCGGAAAACGACCGACACGATACTTTCCC TTGTGCTGGAATTGTTTGATATATTAGGACGAGAATAGTTCTCTCCATTCCGCCGGCGTATAGACCAGGCCATGCCGTTC TATTTCCAAGTTCCTTTGAAGGATCGGTGTTATTTCGGATGTCGTCGAGTAGTCGTGGGGCGTTAGGGTCTAAGCGACCA GTTGTAGCTAATCGGGTGTCCTCCACTAACTGCTATTAGCATAGTACACCATGCTGCTTCAACTCATTTGGGATTTGCAC TACTCTAGGCCAGAGATACAGATGCAAGCCGACTTAGCTGCACTAGCCAAGATTGAGCCCTAGGGCGTAGCGACCCTGAG AATCCTGGCTAGCCCCCCTAGCCCCGGAAACTGCCCGTGTTGCTCTCGAAGCAGTTAGTAATCATCGTAATTTTGTCAAG ATGGCCGTAGAGTGCAACCTGCAAGGCTGCAGGGTGTGTTCGGCATATTAATGCGGACAGTGCAGTGGACAAAGAGTCTC GGAAGCGACGTGTATACAGTAGTGAGTAAATTGTTAAGCTTACTATCGCAGGAACTTCTGATCTGCCCGACCGTCGAGAT CGAGTCTAGTAACAAGATTGCAGTCCTCAAGACTAGAAGTACCTAACTCCCTCAAATGCGAGTCCCAACAACTCATCCTC ACCTCTGGAATCTCACCTCTAAGCATGACAGGCTAGGACCATTTAACATAGTTACAGTGACCTGATACGTAACGCCTCGA AAGGAAAGGCGCGCCTAGGCAGCAATTGCAACGAACTCGGACGTCAGTACTCAACCAACCGAGTTATTTCAGCGTCGCGA ATCTAATGCATCTTCCTGCTTAAGACGTCGTACTCCGGTGTCACCCTTCGACTAACTTAAAATCGCGCATTGGCAAGCAT ACCTCTAATACCGGATCGCTCCCCTCAGGTTTACTTGATGAGCGCTGAACCCAACCATAATTTCGGCAAGGTAATCGCTT ATCGTTCCACCCAGGCGTGAATAATTCATGCCCAATGCAGGTGACCGTATCTCAGGGAGATATAAGTGAAAGTTATGTGG AAGGTATTGTAGTACATTTCAGGGTTCATCTAAGCTTCAGGACCACAGATGCAGAAGACGGGTTAAAGGACATGTCGGCA CGAAGACATATCTTGTGGATCCCTATTCAGTGCCCGTGACTCAACAGATAGACTCATTTTCTCCTTTGGCGTGTCCGCAG GTAAGATAACTTCAGTGTCCGAGCGGCGGAGTGGGTGTTCACGTCGTCGAGTGTCCATTTCGATTGGGGATGTTGGCTCG CATACCACACGACCCTTTAGTGGACGGTCTAGTTTGTATACTCCCCGATTGGACTTTACCCGCGAAGCTAGCACTGTAAA TATTGCCCCGGAGTGGCGGGATACGTTGGATATGCCTATACTGGACCGCAGCCTATTACATCAGATCGGCTTACCGCCAA TCTTAGTGCTCAGCTACCCAGAGCTGTATCCATGGACATAGGCGCTATGACAAGCAGTACTGTAAAGCAGGGACAGCTTT ACTATGTCGACAGCCGGCGTACGTCGTTGGGCTACCGCCGGCCTAGTTCCTAGTCAGTTCCGAGGCATAATCTACAAGTC TAAGTAGGGCGCCATGATGTCACGAGACTTATAGGAGTCCACCGGCAAGTGCGTTGACGTAAATACATATGTGTATGCAG CACTTTTGACAGGCCCGTAGATTTTGCACAAACAGCCGGGTGTGGTTCAAAAAGGGTGTTGCGGTCAGCCGCAGCAGCGC AATTGTAACCAATCTACCTCCCGTTTGCCGACCGCTCGCGCAGATTCATGTAGGAACCGCTAGTTCCCCGTCCGCTACAT TTCAATGGGCTTTTGCATGTCCTATCGCGATACCATCTCTGGTGGCGATGATATTTTATCAGGTTGCATTGGCCCAGTCC ATCTTCGCGGCCGATTGGGCACGCCATTAGTTGCTCTCTGCGCAATCGCAGCTATACTAATGGTATGGTTGGGGAAATCA TTGGAGTGCATTATTCCGCCCTCTTAACCTGTTGTGAACGGAACCGCAGTACGGTAGATTGCAAAGTCCAAGGTTTCTGG ATTGTCTCTGAAAATGAAAGTTCTGCTCTGTCAAGTGATAAACGGAACGTCCTAGGAGGCGCCTACCGCGTTTAGAGAAG TAACCCACGATATCTCGAACAAAAAATCAAAAGCGGTGTAGGTACAAAACGTATCGCTTACATCCCGTGAAGCTTAGTAG GACGCACCCTTCATCTCTCAGGGGGTCGCGTACACGATGTCCGTCTTTTATCGTGCCACGTGTACAAGTAGGGGTGCAGA AATAACTGTACTAATGCAACGTTTCAGTTCTTCTGATGAACATCTCACACGGTTGTCCCCTCTAATATTAGGATTATCGG CCTAGACGTGTTATGCACGCCGACCCCTTTCCCTAAGTGCTTCCGCAATGAAGTCGCGTATTTGTAACACACATTGGGTA TGAATATAACTGTCCCTCCTGGAATAAGGAGTGCGCTTATCCTTTCGGACGTCAGAGCCCAGGGAGGAGACGCGTCAGAT GCCATAGCCTATCGGGATCCGTCGTGCTAGTAGAACCAAAGTAACGGTGCTGTTAAATCGTTCCCTCAGCAGTCCGGGGT TGACAGGTACAGTGTTTCCAACTACTAGAGGATCTCGCTGCTATAGAACGATACCACTGCGGGGGACACCGCCACTTTTC GAGCTGTGGGGCCAGAAGTGCTGTCTGGATAATTCGGTAGGCATCAGCGGACAGCGGAGCTCGTAAGTGCCATGCACTTG TAGCCCATTACGATGAGATCGGTTCCGCCAACTCCGTCAGCACAGGTATCCACGAGGAGTCACCGTCCGGCATGACGCAG GACGGGGGCGGTGGAAATAATCGAGGCGGATACTCTTCATTTGTAGGCGCCAGCTACAGCGGTCCGGCGGGTCAATACCG CATCCGCAGACATAATTGACCTCACTCAGCTCGCACGAACCTCCCTACTCTTTTCTACTCGAGGGTGCCTGATCAGAGAA CGGAAGACGCTATAGGCAAGGCGGGCACGCCTGGAATACAGTCCCTTTCCGAATATTCACACCCGCTACCTATGTCGTAG CGTTGCCGGGCCCGTTATCCAGACCGAACCCGTTGTCTGTTATAACATATTGAGTAATGGGCAGACAAACCCGTGTAGAG TCCTCTCGGTTCCACATATCGAAGAGGGCGATCCGTACGAながい。
poo.fa
として保存します。wgsimを動かす 〜プーの全ゲノムシークエンス〜
さて、謎の生物プーは ヒツジ用の歯磨き粉から発見されました。ところでヒツジってハミガキするんでしょうかね?さあ、私は詳しいことはわかりません。ただ、プーは若いヒツジがこっそり使用していた歯磨き粉から発見されたと報告されてますので、それを信じることにしましょう。学名は、顕微鏡でみた様子がぷるぷるしていることから、プル・プルプルスと言うそうです。(今適当につけた)
さてプーを発見した人はその後人生に山あり谷ありプーに対する興味を失って、その後50年間プーは放置していました。しかし天と地の気のめぐり、赤道の気温の上昇、町内会長のおののき、ほのかな春のおとづれ、会長と社長の和解など、たまたまいろいろな偶然の成り行きがあって、プーが全ゲノムシークエンスされる時がやってきました。さて、あなたは神なのでゲノムシークエンスの結果をwgsimで求めます。
wgsimの実行に先立って、オプションをみてみます。
wgsim --helpOptions: -e FLOAT base error rate [0.020] -d INT outer distance between the two ends [500] -s INT standard deviation [50] -N INT number of read pairs [1000000] -1 INT length of the first read [70] -2 INT length of the second read [70] -r FLOAT rate of mutations [0.0010] -R FLOAT fraction of indels [0.15] -X FLOAT probability an indel is extended [0.30] -S INT seed for random generator [0, use the current time] -A FLOAT discard if the fraction of ambiguous bases higher than FLOAT [0.05] -h haplotype modeところどころ私にはよくわからないオプションがありますが(-s が何の標準偏差なのか、-A とか -h がどう動くのかとか)、それは後で勉強することにしましょう。(しない)
ここではリード数を1000本にします。
wgsim -N 1000 poo.fa poo_1.fq poo_2.fq実行すると突然変異が表示されます。
poo_1.fq
とpoo_2.fq
が生成されたと思います。簡単ですね。poo 977 A W + poo 1210 T W + poo 1655 G K + poo 1874 T K + poo 2043 C S + poo 2378 G T -生成されたfastaファイルの中味を見てみましょう。
head -n 12 poo_1.fq@poo_418_960_2:0:0_1:0:0_0/1 TCGTCGAGTAGTCGTGGGGCGTTAGGGTCTAAGCGACCAGTTGTAGCTAATCGGGTGTCCTCCACTAACT + 2222222222222222222222222222222222222222222222222222222222222222222222 @poo_624_1182_3:0:0_1:0:0_1/1 CTTAGGACATAGGCTCTTCACGTTCAAATCTAACCAAGCTAAATTAAACCGATTTTTAAGCATCATACTA + 2222222222222222222222222222222222222222222222222222222222222222222222 @poo_2608_3166_3:0:0_0:0:0_2/1 GTCCAGTATAGGCATATCCAACGTATCCCGCCACTCCGGGGCAATATTTACAGTGCTAGCTTCGCGGGTA + 2222222222222222222222222222222222222222222222222222222222222222222222まあ、普通リードの後半の方がクオリティスコアが落ちてきたりすると思いますが、そうはなっていませんね。
Fastqcでsequence qualityを見て確認してみましょう。クオリティが一定(しかも低い)ことがわかります。
一般的には下図のようにリードの後方にいくにつれて、クオリティが下がっていくはずです。(画像は Fastqcの公式ホームページから https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)
まあそこのへんは昔のソフトなので仕方がないということで。
BWAを使ってマッピング
さて、全ゲノムシークエンスなので、bwaでマッピングします。なになに。minimap だと? ここは10年前の世界観で、wgsimで遊ぶ記事なんだぞ、ロングリードなんて存在しないんだ!!おっと取り乱してしまいました。神は取り乱さないように気をつけなければなりません。
まずはともあれindexの作成します。
bwa index poo.faプーのゲノムサイズは小さいので一瞬で実行が完了すると思います。
それではbwaをかけてみましょう。(bwa も Heng Li氏の作ったツールです。まさに神といって良いでしょう。)bwa mem poo.fa poo_1.fq poo_2.fq > poo_wgs.samさて、SAM → BAM、BAM → sorted BAM、インデックスまでつけてやりましょう。
samtools view -bS poo_wgs.sam > poo_wgs.bam samtools sort poo_wgs.bam poo_wgs.sorted samtools index poo_wgs.sorted.bamIGVでリードの様子を見てみよう
IGVで、
poo.fa
をリファレンスゲノムに設定し、poo_was.sorted.bam
を開きましょう。うおぉぉぉ!できたよ!できたよ兄さん!(うるさいな)
さてIGVには、実は便利なスプリットビューの機能がついています。これを利用して、突然変異の場所を観察してみましょう。
うおぉぉぉ!兄さん(略)
ちゃんと突然変異が検出されていますね。
おわりに
さて、謎の生物 プー に関する記事を気まぐれで書いてみましたが、思いのほか書いていて楽しいのと、勉強にもなることが判明しました。プーシリーズ、また気が向いたら書くかも。
- 投稿日:2020-07-24T14:18:03+09:00
redirect_toとrenderの違い
はじめに
私はredirect_toとrenderの違いを理解していなかったために、redirect_backを使用しエラーメッセージを表示をすることができず、悩みました。もし、悩んでいる方がいれば少しでも助けになれればと思います。
redirect_to
一回指定したアクションを実行して、そのアクションに対応したビューを表示させる
ちなみにredirect_backはredirect_toと同じ動き方をし、ユーザを直前のページに戻すことができます。render
アクションを実行せずにビューファイルを表示する
2つの動き方
・redirect_to : controller → URL → route → controller → view
・render : controller → view使い分け
・render: ログインや入力形式に失敗した場合など = ただエラーを表示させるだけ
・redirect_to: データ更新/削除が必要な場合 = controllerの処理が必要
- 投稿日:2020-07-24T13:54:23+09:00
rubyでドローポーカーを作ってみる~実装編3(プレイヤー)~
概要
rubyでドローポーカーを作ってみる~準備編~
↓
rubyでドローポーカーを作ってみる~test-unit準備編~
↓
rubyでドローポーカーを作ってみる~実装編1(カード)~
↓
rubyでドローポーカーを作ってみる~実装編2(役)~に続いて。
ソース: https://github.com/rytkmt/ruby_poker
今回はカード、役を扱うプレイヤーの実装に入っていきたいと思います。
プレイヤーの実装
今回もまずは要件を整理してみます。
- 始め5枚のカードをもらう
- 役を判定する
- 任意の枚数、任意のカードを交換する
- 再度、役を判定する
- プレイヤーの勝敗を判定する
- 実質、プレイヤーの持つ役を判定する
ファイルの作成
ruby_poker/player.rbmodule RubyPoker class Player def initialize(cards:) @cards = cards @hand = Hand.new(cards: cards) end end endもらったカードで役を判定するまではこれで出来ました。
ruby_poker.rbrequire "ruby_poker/version" require "active_support/all" -require "ruby_poker/card" -require "ruby_poker/hand" +Dir[__dir__ + "/ruby_poker/*.rb"].each { |p| require p } module RubyPokerrequireも忘れずに行いますが、1ファイルずつ追加していくのもあほらしく感じたので全て読み込むように変更しました。
カードの交換
続いて、任意のカードの交換を実装します。
- いらないカードを捨てる
- 新しいカードをもらう
- 新しいカードにて、再度役を判定する
カードの交換は要素番号をもらい削除するようにしようと思います。
こんとき、要素番号で削除するため小さいものから削除してしまうと要素がそのぶんずれておかしなことになってしまいます。
なので、大きい番号から削除するようにしないといけないので注意して実装します。
検証)x = %i[a b c d e] # a & c & d => [b, e] indexes = [0, 2, 3] indexes.each { |i| x.delete_at(i); p x } # => [:b, :c, :d, :e] # => [:b, :c, :e] # => [:b, :c, :e] x = %i[a b c d e] indexes.sort.reverse_each { |i| x.delete_at(i); p x } # => [:a, :b, :c, :e] # => [:a, :b, :e] # => [:b, :e]カードは山札からもらう必要があるため、捨てるカードの枚数だけ新しいカードをもらえばプレイヤーの責務の範囲は小さくなるかと思いました。
なので、そのように実装してみましょう(あとから変える可能性もありますが、、)kruby_poker/player.rbdef change(indexes:, new_cards:) raise(ArgumentError) unless indexes.size == new_cards.size raise(ArgumentError) unless indexes.all? { |i| (0..4).include?(i) } indexes.sort.reverse_each { |i| @cards.delete_at(i) } @cards += new_cards @hand = Hand.new(cards: @cards) endプレイヤーの勝敗判定
今回も
Comparable
を使用します。
結局は役にて判定するので委譲するようにします。
delegateはactive_support
にてModule
にdelegate
メソッドが拡張で用意されています。
Class
はModule
のサブクラスなので同じくdelegate
が使えます。ruby_poker/player.rbdelegate :<=>, to: :@hand↑ダメでした。。
<=>
のotherが、そのままdelegateだとhandに渡されてしまうため、自分のhandとotherのplayerを比較してしまうことになってしまいました。ruby_poker/player.rbattr_reader :hand def <=>(other) @hand <=> other.hand endおとなしく普通に実装しました。。
これで完了。楽ですねー
終わりに
今回は、勝敗などに関わる機能面での処理のみ実装しました。
ここから、ゲーム進行のことを考えるとコンソール出力回りを実装する必要もでますが、それは次の進行回りを検討するタイミングで追加するようにしていきたいと思います。続き
- 投稿日:2020-07-24T09:54:49+09:00
Ruby on Rails レコード検索、無ければ作成 find_or_create_by メソッド
- 投稿日:2020-07-24T03:18:49+09:00
【Ruby】vendor/bundleにgemがインストールされたはずなのに、requireでエラー
経緯
スクレイピングについて少し学習しようと思い、
Rubyを使って20分でスクレイピングの大元を作るを参考に実装。
「Gemはvendor/bundle配下にインストールするようにします。」とあるので、
指示通りbundle installするときに--path vendor/bundle
のオプションを追加。エラー発生
記事の通りのcodeをmain.rbに書き込み、main.rbを実行すると、
training $ ruby main.rb Traceback (most recent call last): 2: from main.rb:2:in `<main>' 1: from /Users/yusaku/.rbenv/versions/2.6.0/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' /Users/yusaku/.rbenv/versions/2.6.0/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- nokogiri (LoadError)
'require': cannot load such file -- nokogiri (LoadError)
と書かれているが、
nokogiriはvender/bundle
配下にbundle install済みである。training $ ls vendor/bundle/ruby/2.6.0/gems/ byebug-11.1.3 method_source-1.0.0 nokogiri-1.10.10 pry-byebug-3.9.0 coderay-1.1.3 mini_portile2-2.4.0 pry-0.13.1解決
エラーの内容をよくみて見ると、
/Users/yusaku/.rbenv/
配下を探しに行っているように見える。
それでハッとしたのだが、bundle execをしていなかった。training $ bundle exec ruby main.rbこれでエラーも発生せず、main.rbが実行できた(require "nokogiri"もできた)。
bundle exec
をすることによって、同一ディレクトリ配下でgemを探してくれたように見える。
- 投稿日:2020-07-24T03:04:59+09:00
「RSpecが動かない!」原因はspringだったので調べてみた
あるアプリケーションでRSpecを導入し、いざテストコードを実行したらエラーが出てしまった。
何度見直しても設定や記述に問題はないはずなのに、なぜ動かないのか。。原因は「spring」というgemでした。
下記のコマンドをアプリのディレクトリで入力し、再度テストコードを実行すると正常に作動しました。良かった。mac@ myApp % spring stop Spring stopped. ←この表記が出ればOKちなみにこのspringはrailsコマンドを入力すると自動で再始動しますのでご安心を。
このspringというのは何者?
簡単に言えば、railsのキャッシュみたいなものです。
rails newした際に、Gemfileにデフォルトで導入されています。今回の場合だと、RSpecの導入をする前のキャッシュがたまたま残っており、
その状態でテストコードを実行すると「RSpecなんて使えないよ」っていうエラーが出てしまったようですね。ちなみにspringの状態を確認するためにはこんな感じで確認できます。
mac@ myApp % spring status Spring is running: 97404 spring server | myApp | started 10 secs ago 97405 spring app | myApp | started 10 secs ago | development mode
spring stop
→rails c
→exit
→spring status
の順番で入力するとこのようになります。mac@ myApp % spring stop Spring stopped. mac@ myApp % rails c Running via Spring preloader in process 97418 Loading development environment (Rails 6.0.3.2) irb(main):001:0> exit mac@ myApp % spring status Spring is running: 97404 spring server | myApp | started 10 secs ago 97405 spring app | myApp | started 10 secs ago | development mode
ちなみに下記のコマンドではPC内で稼働してるspringを全て確認できます。mac@ ps aux | grep spring mac 97139 101.0 0.5 4370124 43216 ?? Rs 2:24AM 0:00.73 spring app | myApp3 | started 0 secs ago | development mode mac 97106 0.2 0.3 4352516 24104 s002 S 2:24AM 0:00.42 spring server | myApp3 | started 39 secs ago mac 96929 0.0 1.2 4462288 100216 ?? Ss 2:20AM 0:03.23 spring app | myApp2 | started 4 mins ago | development mode mac 77394 0.0 0.1 4352516 8816 ?? S 05PM 0:01.03 spring server | myApp2 | started 56 hours ago mac 4764 0.0 0.0 4486444 472 ?? Ss 5 720 1:18.61 spring app | myApp1 | started 439 hours ago | development mode mac 4760 0.0 0.0 4351492 432 ?? S 5 720 0:01.58 spring server | myApp1 | started 439 hours ago mac 97142 0.0 0.0 4276476 696 s002 S+ 2:24AM 0:00.00 grep springkillコマンドでもstopできるのかな、と思い実行してみましたがすぐ復活して止めることはできませんでした。
やはり該当のディレクトリに移動し、素直にspring stop
した方が良さそうです。
- 投稿日:2020-07-24T01:38:16+09:00
rubyでドローポーカーを作ってみる~実装編2(役)~
概要
rubyでドローポーカーを作ってみる~準備編~
↓
rubyでドローポーカーを作ってみる~test-unit準備編~
↓
rubyでドローポーカーを作ってみる~実装編1(カード)~に続いて。
ソース: https://github.com/rytkmt/ruby_poker
今回は役について実装を行っていきます。
役の実装
改めて要件を整理してみます。
- 役は5枚のカードをもとに判定を行う
- プレイヤーは役をもとに勝敗を比較する
- 役の比較をするために「役」クラスを作りComparable
を使えば比較ができそう
- 役の中でも、同じ役の際に比較するカードを保持する(1枚)
- 役は英語で「 hand 」 ここ大事。ということでいざ実装。
ファイル作成
まずは普通にファイル作成
ruby_poker/hand.rbmodule RubyPoker class Hand def intialize(cards:) end end endruby_poker.rbrequire "ruby_poker/hand"役判定
「役」のクラスを生成しているということは、そのタイミングで判定まで行うべきですよね。。
なので、生成時に判定メソッドを使用し種別と同役時の比較用カードをセットするようにする
生成
ruby_poker/hand.rbattr_reader :hand_type, :comparison_card def intialize(cards:) raise(ArgumentError) if cards.size != 5 @hand_type, @comparison_card = judge(cards: cards) end private def judge(cards:) end役の判定にcardsを使うだけで保持する必要がないためインスタンス変数にはしないようにする。
役判定をどのように実装するか・・・
役は多いので1つ1つメソッドを用意して・・とやるのもなんか切り分けが出来ていない感が残る。。
なので、判定moduleにして切り出すことにしましょう。そして、判定は強い順番に行っていき初めに一致したものをセットすればよいため、
まずはカードの時と同様に、定義を行います。タイプの定義
英語名はこちらを参考に・・笑
https://en.wikipedia.org/wiki/List_of_poker_handsruby_poker.rbHAND_TYPES = %i[ royal_straight_flush straight_flush four_of_a_kind full_house flush straight three_of_a_kind two_pair one_pair high_card ].reverse.freeze動的にモジュールのクラスを取得したいため、スネークケースからキャメルケースに変換を行って
const_get
で取得したい。。
なので、そこの文言変換のためにactive_support
のgemを使用しましょう
(普段rails触ってるとどうしてもこの辺りのかゆいところに手が届くのが便利で使いたくなります)Gemfilegem "activesupport"$ bundle installこれでインストール完了
ruby_poker.rbrequire "active_support/all"読込も忘れず行う
モジュールに判定を移譲
ruby_poker/hand.rbDir[__dir__ + "/hand/hand_type_judgers/*.rb"].each { |p| require p } module RubyPoker class Handruby_poker/hand.rbprivate def judge(cards:) matched_cards = nil matched_type = RubyPoker::HAND_TYPES.find do |type| judger = RubyPoker::Hand::HandTypeJudgers.const_get(type.to_s.classify) # <= ここのためにactive_support matched_cards = judger.judge(cards: cards) end [matched_type, matched_cards.max] endhandの内部処理を切り分ける形で、あくまでhandの責務内だと思ったので、handのインナーモジュールとして実装するようにします
Judgerの.judge
は一致した場合、同役判定の対象となるカードを必ず返すようにし、一致しなかったらnilを返すようにする役判定モジュール実装
ロイヤルストレートフラッシュ
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/royal_straight_flush.rbmodule RubyPoker class Hand module HandTypeJudgers module RoyalStraightFlush def self.judge(cards:) return nil unless cards.map(&:suit).uniq.size == 1 return nil unless cards.sort.map(&:number) == [10, 11, 12, 13, 1] cards end end end end endストレートフラッシュ
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/straight_flush.rbmodule RubyPoker class Hand module HandTypeJudgers module StraightFlush def self.judge(cards:) return nil unless cards.map(&:suit).uniq.size == 1 min_number_level = cards.min.number_level expected = [*min_number_level..min_number_level + 4] return nil unless cards.sort.map(&:number_level) == expected cards end end end end endフォーカード
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/four_of_a_kind.rbmodule RubyPoker class Hand module HandTypeJudgers module FourOfAKind def self.judge(cards:) cards.group_by(&:number).detect { |k, v| v.size == 4 }&.second end end end end endフルハウス
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/full_house.rbmodule RubyPoker class Hand module HandTypeJudgers module FullHouse def self.judge(cards:) grouped_number_cards = cards.group_by(&:number) three_card_number, three_cards = grouped_number_cards.detect { |k, v| v.size == 3 } return nil unless three_card_number grouped_number_cards.delete(three_card_number) return nil unless grouped_number_cards.detect { |k, v| v.size == 2 } three_cards end end end end endフラッシュ
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/flush.rbmodule RubyPoker class Hand module HandTypeJudgers module Flush def self.judge(cards:) return nil unless cards.map(&:suit).uniq.size == 1 cards end end end end endストレート
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/straight.rbmodule RubyPoker class Hand module HandTypeJudgers module Straight def self.judge(cards:) min_number_level = cards.min.number_level expected = [*min_number_level..min_number_level + 4] return nil unless cards.sort.map(&:number_level) == expected cards end end end end endスリーカード
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/three_of_a_kind.rbmodule RubyPoker class Hand module HandTypeJudgers module ThreeOfAKind def self.judge(cards:) cards.group_by(&:number).detect { |k, v| v.size == 3 }&.second end end end end endツーペア
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/two_pair.rbmodule RubyPoker class Hand module HandTypeJudgers module TwoPair def self.judge(cards:) pairs = cards.group_by(&:number_level).select { |k, v| v.size == 2 } return nil unless pairs.size == 2 pairs.max.second end end end end endワンペア
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/one_pair.rbmodule RubyPoker class Hand module HandTypeJudgers module OnePair def self.judge(cards:) cards.group_by(&:number_level).detect { |k, v| v.size == 2 }&.second end end end end endハイカード(豚)
ruby_poker/lib/ruby_poker/hand/hand_type_judgers/high_card.rbmodule RubyPoker class Hand module HandTypeJudgers module HighCard def self.judge(cards:) [cards.max] end end end end endテストの実装も含めて少し大変でしたが実装完了。これで役判定と、同役時の判定用カードの返却までしっかりと行うことができるようになりました。
Comparable用の判定追加
ruby_poker/hand.rb+ include Comparable
ruby_poker/hand.rbdef hand_level RubyPoker::HAND_TYPES.reverse.index(@hand_type) end def <=>(other) hand_comparison = hand_level <=> other.hand_level hand_comparison.zero? ? @comparison_card <=> other.comparison_card : hand_comparison endこれで役の勝敗を
>
などで比較することができるようになりました終わりに
今回の内容にて、カード、役 などゲームに大切な処理は一通り終わったかと思います。
次回は、これらを使うプレイヤーやゲーム進行回りを作っていきたいと思います。続き