- 投稿日:2019-02-28T23:52:55+09:00
railsでIndex name 'xxxxxxxxxxxxxxxxxxx' on table 'テーブル名' is too long; the limit is 64 characters
経緯
railsのmigrationで
Index name 'xxxxxxxxxxxxxxxxxxx' on table 'テーブル名' is too long; the limit is 64 characters
と怒られる
テーブル名、カラム名などなどが長くなり、自動付与されるインデックス名が長くなりすぎることが原因対応
t.references :my_field, index: { name: 'my_index_name' }
でindex名を指定してやればOK!add_indexでindexを別で設定する場合は以下の記事を参考
https://qiita.com/ezawa800/items/9a63a96fb36a7c1de04d参考
- 投稿日:2019-02-28T23:50:43+09:00
Railsチュートリアルに再挑戦する
前に挫折してしまったRailsチュートリアルに再挑戦してみようと思います。
過度に完璧主義にならずに、適度にサボりながら周回を重ねていこうと思います。
testは後回しにしたり、課題を後回しにしたり、後回しでもいいと言われたところは後回しにしたり。
まずは一周して全体を掴んでいこうと思います。
1周目はCloud9で、2周目以降はローカル開発に挑戦していきたいですね。
- 投稿日:2019-02-28T22:39:11+09:00
RubyのライブラリをGoに移植したくなった話
TL;DR
- Rubyのライブラリである、RedBlocks をGoに移植している話
- Rubyの継承などはEmbeddingで解決した
- 仕方なくReflectionを使ってしまったが案外速度は問題なさそう
何を移植したくなったか
RubyにはRedisのset/zsetの操作(
SINTERSTORE
,ZINTERSTORE
)とデータの取得を宣言的に扱うためのライブラリであるRedBlocks というのが存在します。
Readmeからリンクされている[ブログ](を見てみるとclass RegionSet < RedBlocks::Set def initialize(region) raise ArgumentError unless Project::REGIONS.include?(region) @region = region end def key_suffix @region end def get Project.where(region_cd: @region).pluck(:id) end endregion1_set = RegionSet.new('hokkaido') region2_set = RegionSet.new('kanto') regions_set = RedBlocks::UnionSet.new([region1_set, region2_set]) regions_set.ids #=> [921, 324, 21, 39, 101]http://takenos.link/post/173086712782/redis-sorted-set-in-oop
このような形で、北海道もしくは関東の募集(=
Project
)が取得できます。実際Redisを直に触ってしまうとこのような計算はもっと複雑になってしまいます。
これを使い、Goでも同じように楽にRedisの操作がしたくなりました。何が問題か
問題点は基本的に2つありました。
1. Rubyの継承をどうGoで再現するか
2. クラス名(GoではStruct名)をどう取得するか基本的に
RedBlocks
は継承を前提としており、RedBlocks::Set
の場合、3つのメソッドを定義するだけでids
といったメソッドが自動で生えてきます。
これをGoでどうやるべきでしょうか。また、RedBlocksでは半自動でキー名を作成してきます。
基本的にキーはクラス名とユーザーが設定するキーからなります。RedBlocks::Set#key 。
そのうち、クラス名に関してはGoではどう取るべきかが悩ましいです。できたもの
RedBlocksをGoで実装したものがredblocks-go になります。
先程のRegionを作り、北海道または関東のものを取ってくる例がこちらになります。
func NewRegionSet(region string) set.Set { return regionSetImp{region} } type regionSetImp struct { region string } func (r regionSetImp) KeySuffix() string { return r.region } func (r regionSetImp) Get(ctx context.Context) ([]set.IDWithScore, error) { ... } func (r regionSetImp) CacheTime() time.Duration { return time.Second * 10 } store := store.NewRedisStore(newPool()) tokyo := compose.Compose(NewRegionSet("tokyo"), store) osaka := compose.Compose(NewRegionSet("kanto"), store) set := operator.NewUnionSet(store, time.Second*100, tokyo, kanto) set.IDs(ctx, options.WithPagenation(0, -1))どう移植したか
Rubyの継承をどうGoで再現するか
GoにはEmbeddingというのがあります。Goのドキュメントにもあります https://golang.org/doc/effective_go.html#embedding 。
redblocks-goの例を出すと、次のようになりますtype Set interface { KeySuffix() string Get(ctx context.Context) ([]IDWithScore, error) CacheTime() time.Duration NotAvailableTTL() time.Duration // NotAvailableTTL < CacheTime. For processing }https://github.com/rerost/redblocks-go/blob/master/pkg/set/set.go
type ComposedSet interface { set.Set Key() string Update(ctx context.Context) error Available(ctx context.Context) (bool, error) Warmup(ctx context.Context) error IDs(ctx context.Context, opts ...options.PagenationOption) ([]store.ID, error) IDsWithScore(ctx context.Context, opts ...options.PagenationOption) ([]store.IDWithScore, error) }https://github.com/rerost/redblocks-go/blob/master/pkg/compose/set.go
このように、ユーザーが定義すべきものを
Set
というinterface
にし、それをembed
したComposedSet
というinterface
を定義しています。
で、Set
からComposedSet
の必要なメソッドを定義する関数をCompose
としています。クラス名(GoではStruct名)をどう取得するか
正直速度の観点から、Reflection をできるだけ使いたくないと思っていました。
しかし、実際クラス名の取得だけだとベンチマークを走らせてみると10%程度の違いしかなさそうなので問題ないと思っています。~/.go/src/github.com/rerost/redblocks-go/pkg/compose (rerost/not-use-reflection) $ go test -bench BenchmarkKey goos: darwin goarch: amd64 pkg: github.com/rerost/redblocks-go/pkg/compose BenchmarkKey-4 5000000 277 ns/op PASS ok github.com/rerost/redblocks-go/pkg/compose 1.870s~/.go/src/github.com/rerost/redblocks-go/pkg/compose (master) user $ go test -bench BenchmarkKey goos: darwin goarch: amd64 pkg: github.com/rerost/redblocks-go/pkg/compose BenchmarkKey-4 5000000 309 ns/op PASS ok github.com/rerost/redblocks-go/pkg/compose 2.060s終わりに
RedBlocksのGo実装はまだ部分的に機能が足りないのですが、まあまあ使えるものにはなったかと思います。
以上です。
- 投稿日:2019-02-28T22:21:51+09:00
超初歩的なRubyのスクリプトで残業代を計算する。
元ネタはこちら
Rubyでユーザのキーボード入力を対話的に受け取るRubyスクリプト最近、仕事する時間が長くなってきて、コンソール上でこっそり残業代を計算するスクリプトが欲しいなーと思ったのでRuby超初心者が書いてみました。
やりたかったこと
- スマホを取り出して電卓アプリを起動するものもはや面倒なのでなるべくキーボードから手を離さずになにか計算したい。
- RubyのMatzさんの講演会を聞いたのでとりあえずなんでもいいからRubyでなにか書きたかった。
- まあ、とりあえずやることが大事というモチベーションを維持したい。
実行環境
OS: MacOS
Ruby: ruby 2.3.7特にOSによる環境差異はないと思うのでRuby入れれば動くはず
ちょっと時間がかかったこと
問題点
gets.chomp
で対話的に入力値を取れるかな思ったけどString型になってしまうことを理解していなったので計算実行時こんなエラーが起きたHow_much_money.rb:51:in `calc_money': undefined local variable or method `"\u201D\u3042\u306A\u305F\u306E\u6B8B\u696D\u4EE3\u306F"' for #<HowMuchMoneyClass:0x00007fc50a8c4e58> (NameError) from How_much_money.rb:58:in `<main>' MacBook-Pro:Ruby pcuser$ ruby How_much_money.rb How_much_money.rb:51: syntax error, unexpected tIDENTIFIER, expecting keyword_end解決策
計算のためには整数でないといけないのでInt型に変換するように
gets.to_i
で数値を受け取って上げればおKスクリプト本体
コンソールで使う場合は以下のように実行
$ ruby How_much_money.rb今のこんな感じで出力されます。(要改良)
---------------------------- 自分の残業代を計算しますか? 計算する場合は yes、キャンセルする場合は no と入力して下さい. yes 計算を実行します. ---------------------------- 基準とする時給を入力してください 入力例:)1250 900 ---------------------------- 仕事をした時間を入力してください。 入力例:)80 40 あなたの残業代は 36000 円です今の所こっそり感はゼロですが、まあ気にしない
特にひねりはないですがソースはこんな感じ
ruby How_much_money.rb#!/bin/env ruby ## ---------------------------- # ユーザからのキーボードの入力を受け取り、 # yes と入力されたらスクリプトを実行する、no と入力されたらスクリプトを終了します. ## ---------------------------- class HowMuchMoneyClass def initialize puts <<-EOT ---------------------------- 自分の残業代を計算しますか? 計算する場合は yes、キャンセルする場合は no と入力して下さい. EOT end def get_keyboard_input_yes_no case gets.chomp when "yes", "YES", "y" puts " 計算を実行します." when "no", "NO", "n" puts " スクリプトを終了します." exit 1 else puts " yes または no を入力して下さい." confirm = HowMuchMoneyClass.new confirm.get_keyboard_input_yes_no end end def calc_money # 計算する場所 puts <<-EOT ---------------------------- 基準とする時給を入力してください 入力例:)1250 EOT base_monoey = gets.to_i puts <<-EOT ---------------------------- 仕事をした時間を入力してください。 入力例:)80 EOT money_time = gets.to_i #計算結果を返す result = base_monoey * money_time puts "あなたの残業代は #{result} 円です" end end confirm = HowMuchMoneyClass.new() confirm.get_keyboard_input_yes_no confirm.calc_money感想
コンフィグファイル的なやつを入れれば、コンソールに金額とかの情報を載せずともできそうなので今度改良してみようかなと思いました。
シェルとかPythonとか自分の好きな言語でこういうツールを作ってみるのもいいかもしれないですね。
他の人みたいにエクセレントな設計とかできないので思いついたものから地味にやっていくのがいいかな
- 投稿日:2019-02-28T22:13:59+09:00
『オブジェクト指向設計実践ガイド』第1章まとめ
本投稿は書籍『オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方』を読んだ際にまとめた備忘録です。
オブジェクト指向設計とは「オブジェクト同士の依存関係を管理する」こと
【オブジェクト】
=>「それぞれが自身の振る舞いを持ち、そして互いに作用し合うもの」【アプリケーションの設計が解決する問題】
=> アプリケーションの変更を容易にする【アプリケーションの変更が困難な理由】
=> オブジェクト間の依存が変更の邪魔をする【オブジェクト間の依存】
=> 部品Aが部品Bを「知っている」という状態のこと
=> 相手にメッセージを送るためにはこの「相手を知っている」状態である必要がある【設計の実用的な定義】
=>「未来を受け入れるための選択肢を保護する」もの
=>「あとにでも」設計をできるようにすること、第一の目標は変更コストの削減オブジェクト指向の設計者の道具 = 原則とパターン
【設計原則】
=> SOLID
1.単一責任(Single Responsibility)
2.オープン・クローズド(Open-Closed)
3.リスコフの置換(Liskov Substitution)
4.インターフェース分離(Interface Segregation)
5.依存性逆転(Dependency Inversion)【設計(デザイン)パターン】
「オブジェクト指向ソフトフェア設計において遭遇する様々な問題に対して、簡単でかつ明瞭な解を与える」ものであり「設計プロダクトの柔軟性、モジュール性、再利用性、および理解のしやすさをより高める」ために使えるもの
【設計が失敗する原因】
1.設計が十分でない <= 設計が失敗する最初の原因
2.「良かれと思って設計しすぎる」 <= 多少の経験を積んだプログラマの失敗
3.設計の行為と実装の行為が乖離した時 <= 設計とは漸進的な発見のプロセスであり、繰り返しのフィードバックを頼りに進んでいくもの【設計を行うタイミング】
=>詳細設計はしない。小さな追加の繰り返しで作っていくべきで、開発を繰り返すことで本当に必要なものに近づけていく(アジャイル開発?)*詳細設計
=>提案されたアプリケーションのすべての機能、想定される未来の内部動作をすべて特定し、完全に文書化したもの【詳細設計における問題点】
=>本当に必要な機能は作っていく中で新たに見つかるもので、詳細設計のような事前に考えたものでは本当に顧客に必要なものを満たせない【「設計を判断する」】
=>設計の損益分岐点に従ってその程度を判断すること例) 初学者の場合 => 設計努力をする意味はほとんどない 熟練者の場合 => 設計努力の意味は濃い=>設計者の目標は、機能あたりのコストが最も低い方法でソフトウェアを書くことであり、この決断は「プログラマのスキル」と「結果が出るまでの時間」による
第1章終わり:オブジェクト指向/オブジェクト指向設計の理解しやすい方法を考える
様々な書籍でオブジェクト指向について触れられていますが、よく見かけるのが「オブジェクト指向は手順ではなく操作するように扱えるもの」「ものとして扱う」みたいな記述が多くて「ん?」となることもあったので、自分なりの例をあげて今回のオブジェクト指向/オブジェクト指向設計の理解を確認してみます。
オブジェクト指向はサッカーゲームを例に考えてみると、理解しやすい気がします。
サッカーゲームの場合オブジェクトA = 操作する選手 オブジェクトB = 自チームの操作している以外の選手 オブジェクトC = 敵チームの選手 オブジェクトD = 観客 オブジェクトA~Cの振る舞い = パス、シュート、ドリブル、ダッシュ、クリア、スライディングタックル..etc オブジェクトDの振る舞い = オブジェクトAが所属するチームを応援する オブジェクトAは味方であるオブジェクトBにはメッセージは送れる(Bにパスする、等) オブジェクトCは敵であるオブジェクトAにメッセージを送れる(Aにスライディングタックルする、等) オブジェクトAは観客であるオブジェクトDにはメッセージを送れない(Dにパスする、等) ⇨選手であるオブジェクトAは観客であるオブジェクトDについての知識は持たせる必要はないプログラミング難しい。
- 投稿日:2019-02-28T22:13:59+09:00
オブジェクト指向/オブジェクト指向設計とはなんぞや?
本投稿は書籍『オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方』を読んだ際にまとめた備忘録です。
オブジェクト指向設計とは「オブジェクト同士の依存関係を管理する」こと
【オブジェクト】
=>「それぞれが自身の振る舞いを持ち、そして互いに作用し合うもの」【アプリケーションの設計が解決する問題】
=> アプリケーションの変更を容易にする【アプリケーションの変更が困難な理由】
=> オブジェクト間の依存が変更の邪魔をする【オブジェクト間の依存】
=> 部品Aが部品Bを「知っている」という状態のこと
=> 相手にメッセージを送るためにはこの「相手を知っている」状態である必要がある【設計の実用的な定義】
=>「未来を受け入れるための選択肢を保護する」もの
=>「あとにでも」設計をできるようにすること、第一の目標は変更コストの削減オブジェクト指向の設計者の道具 = 原則とパターン
【設計原則】
=> SOLID
1.単一責任(Single Responsibility)
2.オープン・クローズド(Open-Closed)
3.リスコフの置換(Liskov Substitution)
4.インターフェース分離(Interface Segregation)
5.依存性逆転(Dependency Inversion)【設計(デザイン)パターン】
「オブジェクト指向ソフトフェア設計において遭遇する様々な問題に対して、簡単でかつ明瞭な解を与える」ものであり「設計プロダクトの柔軟性、モジュール性、再利用性、および理解のしやすさをより高める」ために使えるもの
【設計が失敗する原因】
1.設計が十分でない <= 設計が失敗する最初の原因
2.「良かれと思って設計しすぎる」 <= 多少の経験を積んだプログラマの失敗
3.設計の行為と実装の行為が乖離した時 <= 設計とは漸進的な発見のプロセスであり、繰り返しのフィードバックを頼りに進んでいくもの【設計を行うタイミング】
=>詳細設計はしない。小さな追加の繰り返しで作っていくべきで、開発を繰り返すことで本当に必要なものに近づけていく(アジャイル開発?)*詳細設計
=>提案されたアプリケーションのすべての機能、想定される未来の内部動作をすべて特定し、完全に文書化したもの【詳細設計における問題点】
=>本当に必要な機能は作っていく中で新たに見つかるもので、詳細設計のような事前に考えたものでは本当に顧客に必要なものを満たせない【「設計を判断する」】
=>設計の損益分岐点に従ってその程度を判断すること例) 初学者の場合 => 設計努力をする意味はほとんどない 熟練者の場合 => 設計努力の意味は濃い=>設計者の目標は、機能あたりのコストが最も低い方法でソフトウェアを書くことであり、この決断は「プログラマのスキル」と「結果が出るまでの時間」による
オブジェクト指向/オブジェクト指向設計の理解しやすい方法を考える
様々な書籍でオブジェクト指向について触れられていますが、よく見かけるのが「オブジェクト指向は手順ではなく操作するように扱えるもの」「ものとして扱う」みたいな記述が多くて「ん?」となることもあったので、自分なりの例をあげて今回のオブジェクト指向/オブジェクト指向設計の理解を確認してみます。
オブジェクト指向はサッカーゲームを例に考えてみると、理解しやすい気がします。
サッカーゲームの場合オブジェクトA = 操作する選手 オブジェクトB = 自チームの操作している以外の選手 オブジェクトC = 敵チームの選手 オブジェクトD = 観客 オブジェクトA~Cの振る舞い = パス、シュート、ドリブル、ダッシュ、クリア、スライディングタックル..etc オブジェクトDの振る舞い = オブジェクトAが所属するチームを応援する オブジェクトAは味方であるオブジェクトBにはメッセージは送れる(Bにパスする、等) オブジェクトCは敵であるオブジェクトAにメッセージを送れる(Aにスライディングタックルする、等) オブジェクトAは観客であるオブジェクトDにはメッセージを送れない(Dにパスする、等) ⇨選手であるオブジェクトAは観客であるオブジェクトDについての知識は持たせる必要はない
- 投稿日:2019-02-28T20:46:40+09:00
deviseを日本語化する方法の備忘録
deviseを日本語化する方法の備忘録です。
gemをインストール
gemfilegem 'devise-i18n' gem 'devise-i18n-views'$bundle installを実行する。
日本語翻訳ファイルを生成
$rails g devise:views:local ja
config/locales/devise.viwes.ja.ymlja: activerecord: attributes: user: current_password: "現在のパスワード" email: "メールアドレス" password: "パスワード" password_confirmation: "確認用パスワード" remember_me: "ログインを記憶" models: user: "ユーザ" devise: confirmations: new: resend_confirmation_instructions: "アカウント確認メール再送" mailer: confirmation_instructions: action: "アカウント確認" greeting: "ようこそ、%{recipient}さん!" instruction: "次のリンクでメールアドレスの確認が完了します:" reset_password_instructions: action: "パスワード変更" greeting: "こんにちは、%{recipient}さん!" instruction: "誰かがパスワードの再設定を希望しました。次のリンクでパスワードの再設定が出来ます。" instruction_2: "あなたが希望したのではないのなら、このメールは無視してください。" instruction_3: "上のリンクにアクセスして新しいパスワードを設定するまで、パスワードは変更されません。" unlock_instructions: action: "アカウントのロック解除" greeting: "こんにちは、%{recipient}さん!" instruction: "アカウントのロックを解除するには下のリンクをクリックしてください。" message: "ログイン失敗が繰り返されたため、アカウントはロックされています。" passwords: edit: change_my_password: "パスワードを変更する" change_your_password: "パスワードを変更" confirm_new_password: "確認用新しいパスワード" new_password: "新しいパスワード" new: forgot_your_password: "パスワードを忘れましたか?" send_me_reset_password_instructions: "パスワードの再設定方法を送信する" registrations: edit: are_you_sure: "本当に良いですか?" cancel_my_account: "アカウント削除" currently_waiting_confirmation_for_email: "%{email} の確認待ち" leave_blank_if_you_don_t_want_to_change_it: "空欄のままなら変更しません" title: "%{resource}編集" unhappy: "気に入りません" update: "更新" we_need_your_current_password_to_confirm_your_changes: "変更を反映するには現在のパスワードを入力してください" new: sign_up: "アカウント登録" sessions: new: sign_in: "ログイン" shared: links: back: "戻る" didn_t_receive_confirmation_instructions: "アカウント確認のメールを受け取っていませんか?" didn_t_receive_unlock_instructions: "アカウントの凍結解除方法のメールを受け取っていませんか?" forgot_your_password: "パスワードを忘れましたか?" sign_in: "ログイン" sign_in_with_provider: "%{provider}でログイン" sign_up: "アカウント登録" unlocks: new: resend_unlock_instructions: "アカウントの凍結解除方法を再送する"必要に応じてメッセージを変更する。
localeの設定
config/application.rbconfig.i18n.default_locale = :ja上のコードをconfig/application.rbに記述する。
localeを設定することで日本語化できるようです。まとめ
以上が今回私が実施したdeviseを日本語化する方法です。
- 投稿日:2019-02-28T19:06:40+09:00
Rails で Web API 開発(Part. 5 R(CRUD) の実装)
はじめに
本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
最終的なプロダクトは、 Rails API Sample に置いておきます。各記事
- Rails で Web API 開発(Part. 1 概要)
- Rails で Web API 開発(Part. 2 Docker 関連)
- Rails で Web API 開発(Part. 3 DB 関連)
- Rails で Web API 開発(Part. 4 CORS 関連)
- Rails で Web API 開発(Part. 5 R(CRUD) の実装)
記事の構成
前回の記事
前回は、CORS の設定を行いました。
今回の記事
今回は、実際に CRUD のうちの R の実装をおこなっていきたいと思います。
次回の記事
次回は、ひきつづき CRUD のうちの CUD の実装をおこなっていきたいと思います。
API 仕様書 の作成
Swagger Editor の起動
早速実装を…!といきたいのですが、ひとまず仕様書をちゃんと作ろうということで、 Swagger Editor を扱えるようにしていきましょう。
以下のコマンドを実行しましょう。
$ docker pull swaggerapi/swagger-editor
$ docker run -d --rm -p 80:8080 swaggerapi/swagger-editor
おそらく、
localhost
にブラウザ上からアクセスすれば Swagger Editor が起動しているのを確認できるはずです。
画面左部に以下を記述してみましょう。 swagger の記述方法については、解説しませんので今後記述していくうえで演繹的に感じていただけたらと思います。# This Docs Information swagger: "2.0" info: version: "0.0.1" title: "Rails API Sample" schemes: - "http" host: "localhost:40000" basePath: "/api" produces: - application/json paths: /users: get: tags: - "users - action" summary: "User 全体取得 API" responses: 200: description: "OK" schema: type: array items: type: object properties: id: type: integer name: type: string created_at: type: string updated_at: type: string /users/{id}: get: tags: - "users - action" summary: "User 全体取得 API" parameters: - in: path name: "id" type: integer required: true responses: 200: description: "OK" schema: type: object properties: id: type: integer name: type: string created_at: type: string updated_at: type: string以下のような画面になるはずです。
yaml ファイルの保存
また念の為、この yaml ファイル は、 docs 配下 に保存しておくことにします。
API の実装
さて、それでは実際に API を実装していきましょう。
エラー処理機構の実装
さっそく実装を!!といきたいのですが、まずは先にエラー処理機構を整えることにしましょう。
I18n で日本語化
Rails の I18n という機能を用いて、Message の管理をおこなっていきます。
まずは、以下のコマンドで、デフォルトの ja.yml ファイルをダウンロードしましょう。
Mac の場合は、$ brew install wget
とかうてば wget コマンド うてるようになるのかな?
$ wget https://raw.github.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml -P config/locales/ja/default.yml
次に、 config/application.rb に追記し、起動時に locales 配下の *.yml が読み込まれるようにします。
# I18n の設定 config.i18n.default_locale = :ja config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]最後に、 config/locales/ja/error.yml を作成しましょう。この部分に、各エラーの情報を記載していきます.
ja: errors: ApiErrors::FilterParamsError: status_code: 400 error_code: E001 error_description: リクエストパラメーターが異常です。 ApiErrors::GenerateJSONError: status_code: 500 error_code: E002 error_description: JSON 生成時にエラーが発生しました。 other: status_code: 500 error_code: E999 error_description: サーバー内でエラーが発生しました。エラー処理機構
app/controllers/application_controller.rb を以下のように編集しましょう。
この部分で、エラーを処理して response を返すようにします。また、先に記述した yml ファイル を読み込むような設定もこの部分でしています.class ApplicationController < ActionController::API rescue_from Exception, with: :render_error private def render_error(error) error_description = I18n.t("errors.#{error.class}", default: :'errors.other') response = { error_code: error_description[:error_code], error_description: error_description[:error_description] } render json: response, status: error_description[:status_code] end endエラークラス
最後に、今後発生するであろうエラークラスを app/errors/api_errors.rb に定義しておきます。
module ApiErrors class FilterParamsError < StandardError end class GenerateJSONError < StandardError end endModel の実装
それでは、以下のような app/models/user.rb と app/models/micropost.rb を作成しましょう。
class User < ApplicationRecord self.table_name = 'users' has_many :microposts endclass Micropost < ApplicationRecord self.table_name = 'microposts' belongs_to :user endValidation 等のビジネスロジック(ビジネスロジックとは何か…。はおいておきます…。)は、いっさいかきません。
Rails では、よく Controller 層 / Model 層の肥大化が問題となっているので、今回は Trailblazer という gem を扱います。Routing の設定
それでは、 config/routes.rb を以下のように編集しましょう。
Rails.application.routes.draw do namespace :api do resources :users, only: %i[show index] end endOperation(JSON 生成層) の実装
名付けがよくわからなかったので、とりあえず Operation(JSON 生成層)の実装をおこなっていきます。
以下のような全ての Operation が継承をする app/concepts/apprication_operation.rb を作成します。
ここでは、Operation で引き起こされるであろう Error について記述しておきます。ここで引き起こされた Error は、 application_controller.rb で処理されます。
また、日付を format する関数をここに記述しておきます.class ApplicationOperation < Trailblazer::Operation protected def handle_filter_params_error!(*) raise ApiErrors::FilterParamsError end def handle_generate_json_error!(*) raise ApiErrors::GenerateJSONError end def simple_format_time(time) time.strftime('%Y-%m-%d %H:%M:%S') end endそれでは、具体的に show / index method の実装をおこなっていきます。
以下のような app/concepts/users/operation/show.rb ・ app/concepts/users/operation/index.rb を作成します。class Users::Operation::Show < ApplicationOperation step :filter_params failure :handle_filter_params_error! step :generate_json failure :handle_generate_json_error! private def filter_params(options, params, **) options['user'] = User.find_by(id: params[:id]) end def generate_json(options, **) # 抽出するカラムを選択 response = options['user'].slice(:id, :name, :created_at, :updated_at) # value を整形 response[:created_at] = simple_format_time(response[:created_at]) response[:updated_at] = simple_format_time(response[:updated_at]) # json を生成 options['json'] = response.to_json end endclass Users::Operation::Index < ApplicationOperation step :generate_json failure :handle_generate_json_error! private def generate_json(options, **) # 抽出するカラムを選択 response = User.all.pluck(:id, :name, :created_at, :updated_at) # hash 形式に変更 keys = %i[id name created_at updated_at] response.map! do |response| Hash[*[keys, response].transpose.flatten] end # value を整形 response.map! do |response| response[:created_at] = simple_format_time(response[:created_at]) response[:updated_at] = simple_format_time(response[:updated_at]) response end # json を生成 options['json'] = response.to_json end endController の実装
最後に Controller を実装すれば、おしまいですね!
以下のような app/controllers/api/users_controller.rb を作成しましょう。class Api::UsersController < ApplicationController def show result = Users::Operation::Show.call( id: params[:id] ) render json: result['json'], status: 200 end def index result = Users::Operation::Index.call() render json: result['json'], status: 200 end endおわりに
今回は、 CRUD の R だけをとりあえず実装しようと思ったのですが、色々とやることがありましたね…。次回は、 Rails で Web API 開発(Part. 6 CUD(CRUD) の実装) をおこなっていきます!
- 投稿日:2019-02-28T19:04:56+09:00
Rails で Web API 開発(Part. 4 CORS 関連)
はじめに
本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
最終的なプロダクトは、 Rails API Sample に置いておきます。各記事
- Rails で Web API 開発(Part. 1 概要)
- Rails で Web API 開発(Part. 2 Docker 関連)
- Rails で Web API 開発(Part. 3 DB 関連)
- Rails で Web API 開発(Part. 4 CORS 関連)
- Rails で Web API 開発(Part. 5 R(CRUD) の実装)
記事の構成
前回の記事
前回は、DB の設定を行いました。
今回の記事
今回は、API を実装するうえで欠かせない CORS の設定をおこなっていきます。
次回の記事
次回は、実際に CRUD のうちの R の実装をおこなっていきたいと思います。
CORS の設定
Rack Cors
今回、CORS の設定を行うために、 Rack Cors という gem を扱います。最初の Gemfile に記述済みですので、今回新しくインストールのために何かやる必要はないです。
さて、おそらくすでに config/initializers/cors.rb というファイルがあるかと思います。このファイルを以下のように編集しましょう。
$ docker-compose down; docker-compose up
を行えば、設定が反映されるはずです。Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do # 全ての origin(Host) からの リクエストを許可する。 origins '*' # /api/ 以下全てのリソースに対して、 resource '/api/*', # 本サーバに対するリクエストにどんな header もつけてもよいとする。 headers: :any, # 本サーバに対するリクエストに以下の method であれば許可をする。 methods: %i[get, post, put, patch, delete, options, head], # 本サーバからのレスポンスの HTTP ヘッダとして公開することを許可する。 expose: %i[] end endおわりに
ちょっと今回は、はやくなりすぎてしまいました…。次回は、Rails で Web API 開発(Part. 5 R(CRUD) の実装)を行います。
- 投稿日:2019-02-28T19:04:35+09:00
Rails で Web API 開発(Part. 3 DB 関連)
はじめに
本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
最終的なプロダクトは、 Rails API Sample に置いておきます。各記事
- Rails で Web API 開発(Part. 1 概要)
- Rails で Web API 開発(Part. 2 Docker 関連)
- Rails で Web API 開発(Part. 3 DB 関連)
- Rails で Web API 開発(Part. 4 CORS 関連)
- Rails で Web API 開発(Part. 5 R(CRUD) の実装)
記事の構成
前回の記事
前回は、Docker 上で開発をするうえでの下準備を行いました。
今回の記事
今回は、前回開発した Docker 上で DB の設定を行い、実際に
curl コマンド
が通るところまで行います。次回の記事
次回は、API を実装するうえでかかせない CORS の設定をおこなっていきたいと思います。
ER 図の作成
MySQL Workbench
ER 図を作成するために、今回は MySQL Workbench を使用します。今回は、使用方法については控えますが(ごにょごにょして)以下のような ER 図を作成しました。(今後、設計図等はリポジトリの docs 配下 に置いておくことにします。)
- DB 名: rails_api_sample
また、MySQL Workbench の機能を利用して、以下のような SQL 文を作成しました。
-- MySQL Script generated by MySQL Workbench -- Wed Feb 27 15:05:04 2019 -- Model: New Model Version: 1.0 -- MySQL Workbench Forward Engineering SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES'; -- ----------------------------------------------------- -- Schema rails_api_sample -- ----------------------------------------------------- -- ----------------------------------------------------- -- Schema rails_api_sample -- ----------------------------------------------------- CREATE SCHEMA IF NOT EXISTS `rails_api_sample` DEFAULT CHARACTER SET utf8 ; USE `rails_api_sample` ; -- ----------------------------------------------------- -- Table `rails_api_sample`.`users` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `rails_api_sample`.`users` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `name` VARCHAR(64) NOT NULL, `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE = InnoDB; -- ----------------------------------------------------- -- Table `rails_api_sample`.`microposts` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `rails_api_sample`.`microposts` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `content` TEXT NOT NULL, `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL, `user_id` BIGINT NOT NULL, PRIMARY KEY (`id`), INDEX `fk_microposts_users_idx` (`user_id` ASC), CONSTRAINT `fk_microposts_users` FOREIGN KEY (`user_id`) REFERENCES `rails_api_sample`.`users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; SET SQL_MODE=@OLD_SQL_MODE; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;テーブルの作成
実際に、Docker 上の DB に接続しテーブルを作成していきましょう。今回は、 Sequel Pro という MySQL の可視化ツールを用いたいと思います。
前回の作業をおこなっていれば、以下のような設定で疎通が確認できるはずです。先ほど作成した SQL 文を(Sequel Pro 上で)実際に入力することでテーブルが作成できることが確認できます。
以下は、 SQL 文 入力をし、実行をおこなった後の画面になります。database.yml の編集
Docker Compose 上で環境変数を流しているために、以下のような設定を行うことで疎通が行えるはずです。
記述した後に、再度$ docker-compose down; docker-compose up
を行えば、$ curl localhost:40000
で疎通確認が行えるはずです。default: &default adapter: mysql2 encoding: utf8 pool: 5 host: <%= ENV['MYSQL_HOST'] %> username: <%= ENV['MYSQL_USER'] %> password: <%= ENV['MYSQL_PASSWORD'] %> port: <%= ENV['MYSQL_PORT'] %> database: rails_api_sample development: <<: *default test: <<: *default database: rails_api_sample_test production: <<: *defaultMigration の管理
DB というものは、実装をしていくうえでよく変わりうるものです。上記の ER図 を用いて運用上でうまい感じにやっていくというのもできないこともないですが、ちょっと面倒です。
今回、Migration の管理を行うために、 Ridgepole という gem を扱います。最初の Gemfile に記述済みですので、今回新しくインストールのために何かやる必要はないです。Ridgepole タスクの作成
Ridgepole を扱うための Rake タスクを作成してきましょう。今回は、以下のようなファイルを作成します。
若干コメント文にもありますが 既存の DB から Schemafile を作成することと、またその逆ができるようになります。# (lib/tasks/ridgepole.rake) # Schema -> DB # ./bin/bundle exec rails ridgepole:apply "env" # # ex) ./bin/bundle exec rails ridgepole:apply RAILS_ENV=development # # DB -> Schema # ./bin/bundle exec rails ridgepole:export "env" # # ex) ./bin/bundle exec rails ridgepole:export RAILS_ENV=development namespace :ridgepole do task export: :environment do options = [ '--export', '--split', "--output #{schemafile_path}" ] exec_ridgepole(options) end task apply: :environment do options = [ '--apply', "--file #{schemafile_path}" ] exec_ridgepole(options) end def exec_ridgepole(options) yml_file_path = Rails.root.join('config', 'database.yml') default_options = [ "--env #{Rails.env}", "--config #{yml_file_path}" ] sh("bundle exec ridgepole #{default_options.join(' ')} #{options.join(' ')}") end def schemafile_path Rails.root.join('db', 'schemas', 'Schemafile') end end既存の DB から Schemafile を作成 / 更新
以下のコマンドを実行することで、DB の作成 / 更新を行えるようになっているはずです。作成された Schemafile は、 db/schemas に保存されているはずです。
$ docker-compose run --rm app ./bin/bundle exec rails ridgepole:export RAILS_ENV=development
既存の Schemafile から テーブル を作成 / 更新
以下のコマンドを実行することで、テーブルの作成 / 更新を行えるようになっているはずです。
$ docker-compose run --rm app ./bin/bundle exec rails ridgepole:apply RAILS_ENV=development
おわりに
今回は、DB 周りのことに関してお話しました。次回は、Rails で Web API 開発(Part. 4 CORS 関連)を行います。
- 投稿日:2019-02-28T19:04:13+09:00
Rails で Web API 開発(Part. 2 Docker 関連)
はじめに
本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
最終的なプロダクトは、 Rails API Sample に置いておきます。各記事
- Rails で Web API 開発(Part. 1 概要)
- Rails で Web API 開発(Part. 2 Docker 関連)
- Rails で Web API 開発(Part. 3 DB 関連)
- Rails で Web API 開発(Part. 4 CORS 関連)
- Rails で Web API 開発(Part. 5 R(CRUD) の実装)
記事の構成
前回の記事
前回は、Mac 上でとりあえず
$ rails server
が動くところまでやりました。今回の記事
今回は、Docker Container 上で
$ rails server
が動くようにします。次回の記事
次回は、しっかりと DB 部分の実装をおこなっていきます。
各種 Docker ファイルの作成
docker-compose.yaml の作成
以下のような docker-compose.yaml を作成します。
version: '3' services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql ports: - "40050:3306" restart: always # 環境変数は、Docker 上から流すことにします。 environment: TZ: "Asia/Tokyo" MYSQL_ROOT_PASSWORD: rails_api_sample MYSQL_DATABASE: rails_api_sample MYSQL_USER: rails_api_sample MYSQL_PASSWORD: rails_api_sample app: build: . volumes: - .:/rails_api_sample depends_on: - db ports: - "40000:3000" tty: true stdin_open: true # 環境変数は、Docker 上から流すことにします。 environment: TZ: "Asia/Tokyo" MYSQL_HOST: db MYSQL_DB: rails_api_sample MYSQL_PORT: 3306 MYSQL_USER: rails_api_sample MYSQL_PASSWORD: rails_api_sample volumes: db_data: {}Dockerfile の作成
以下のような Dockerfile を作成します。
FROM ruby:2.6.1 RUN mkdir -p /rails_api_sample WORKDIR /rails_api_sample RUN apt-get update -qq && \ apt-get install -y build-essential mysql-client nodejs tzdata COPY Gemfile* /rails_api_sample/ RUN mkdir -p /rails_api_sample/bin COPY bin/* /rails_api_sample/bin/ RUN ./bin/bundle install --path vendor/bundle COPY . /rails_api_sample # Add a script to be executed every time the container starts. COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["./bin/bundle", "exec", "rails", "server", "-p", "3000", "-b", "0.0.0.0", "-e", "development"]Docker 上で rails server
docker-compose up
以下のコマンドを実行します。
$ docker-compose build
次に、以下のコマンドを実行します。
$ docker-compose run --rm app ./bin/bundle install --path vendor/bundle
最後に、以下のコマンドを実行します。
$ docker-compose up
以下のようになったら、とりあえず完了です!( curl コマンド 等で確認してもおそらく DB 周りの設定ができていないのでちゃんとはかえってこないです…。)
各種コマンド
覚えておいたほうがよいコマンドに関して少しだけ記述しておきます。
$ docker-compose up
: docker-compose を起動します。
$ docker-compose down
: docker-compose を停止します。
$ docker-compose run --rm ${SERVICE_NAME} ${COMMAND}
: ${SERVICE_NAME} 内で、指定のコマンドを実行します。 ex)$ docker-compose run --rm app bash
$ docker attach ${CONTAINER_NAME}
: ${CONTAINER_NAME} 内に、入れます。次の例では、binding.pry
等を実行する際によく使います。 ex)$ docker attach rails_api_sample_app
おわりに
まだまだ DB 関連が整っていないです…。次回は、Rails で Web API 開発(Part. 3 DB 関連)を行います。
- 投稿日:2019-02-28T19:03:46+09:00
Rails で Web API 開発(Part. 1 概要)
はじめに
現在、執筆中です。
本記事は、自身が今までの Ruby on Rails で開発してきた知識 / 知見の総まとめをおこなったものです。
「ここは、もっとこうしたほうがいいよ!こういうものがあるよ!」というようなことがあれば、随時おしらせください!
最終的なプロダクトは、 Rails API Sample に置いておきます。対象
- Mac での開発者
- ある程度 Rails / Docker の知識があるとよいかな…。と
各記事
- Rails で Web API 開発(Part. 1 概要)
- Rails で Web API 開発(Part. 2 Docker 関連)
- Rails で Web API 開発(Part. 3 DB 関連)
- Rails で Web API 開発(Part. 4 CORS 関連)
- Rails で Web API 開発(Part. 5 R(CRUD) の実装)
記事の構成
今回の記事
今回は、全体の記事について記述します。また、とりあえずローカルで
$ rails server
コマンドが動くところまで記述します。次回の記事
Docker を用いた開発を行う上での下準備をおこなっていきます。
主に扱うもの
- Ruby(ver. 2.6.1) + Ruby on Rails(ver. 5.2.2)
- Docker + Docker-Compose(コンテナ 関連)
- MySQL + MySQL Workbench + Sequel Pro + Ridgepole (DB 関連)
- Rspec + Factory Girl + Shoulda Matcher(テスト 関連)
Rails プロジェクトの作成
Version
先述のとおり、Ruby / Ruby on Rails の各 Version は、以下の通りです。
rails new
以下のコマンドを実行しましょう。( DBには、MySQL を使用し 、 API モードで 、 Minitest は使わない ようにするオプション。)
$ rails new rails_api_sample --database=mysql --api -T
$ cd rails_api_sample
Gemfile の編集
今回扱う Gemfile は、以下のようにしています。
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.6.1' gem 'rails', '5.2.2' # DB(MySQL) の設定に必要な gem gem 'mysql2' # JSON の管理に必要な gem gem 'jbuilder' # 'rails server' 起動時に必要な gem gem 'bootsnap', require: false gem 'puma' # CORS の設定に必要な gem gem 'rack-cors' # Migration の管理に必要な gem gem 'ridgepole' # Trailblazer を扱うのに必要な gem gem 'reform-rails' gem 'trailblazer-loader' gem 'trailblazer-rails' group :development, :test do # 便利コマンド 'binding.pry' を使用するのに必要な gem gem 'pry-byebug' gem 'pry-doc' gem 'pry-rails' # ソースコードが綺麗かどうか Check する gem gem 'rubocop' end group :development do # ファイルの変更を監視する gem gem 'listen' # 起動を早くするために必要な gem gem 'spring' gem 'spring-watcher-listen' end group :test do # TEST 用 DB の管理をする gem gem 'database_rewinder' # TEST 用 データの管理をする gem gem 'factory_bot_rails' gem 'faker' # Rspec で TEST をするために必要な gem gem 'rspec-json_matcher' gem 'rspec-rails' gem 'rspec_junit_formatter' # モデルの関連を TEST するために必要な gem gem 'shoulda-matchers' endbundle install
以下のコマンドを実行しましょう。( vendor/bundle 配下にインストール するオプション。)
$ bundle install --path vendor/bundle
rails server
以下のコマンドを実行しましょう。( $ rails s は $ rails server の省略コマンド。 -p はポート指定。-b はIP Address指定。-e は環境指定。)
$ bundle exec rails s -p 3000 -b '127.0.0.1' -e 'development'
以下のようになったら、とりあえず完了です!( curl コマンド 等で確認してもおそらく DB 周りの設定ができていないのでちゃんとはかえってこないです…。)
おわりに
今回は、とりあえず
$ rails server
コマンドまでを行いました。次回は、Rails で Web API 開発(Part. 2 Docker 関連)を行います。
- 投稿日:2019-02-28T16:17:03+09:00
bundle installしたら、Traceback (most recent call last):が出た時の対処
- 投稿日:2019-02-28T14:55:21+09:00
Ruby if文,case文
動作環境はMacとなります。
if文
条件によって処理を出し分けたいときに使う
記述方法
if 条件1
条件 1が真(true)だった場合の処理
elsif 条件2
条件2が真(true)だった場合の処理
elsif 条件3
条件3が真(true)だった場合の処理
else
上記のいずれにも当てはまらなかった場合の処理
end条件が真になったタイミングで処理を抜ける。
後の処理は実行されない。※elsifの綴りはelseifではないため、注意
実践1
テストの点数が
90点以上 大変よくできました
80点以上 よくできました
60点以上 普通です
60点未満 頑張りましょうと出力されるプログラムを実際に書いてみる
if.rbscore = x(任意の数字を入れる) if score >= 90 puts "大変よくできました" elsif score >= 80 puts "よくできました" elsif score >= 60 puts "普通です" else puts "頑張りましょう" end処理結果
$ruby if.rb 普通です #score60点以上 $ruby if.rb 頑張りましょう #score60点未満(59点以下) $ruby if.rb 大変よくできました #score90点以上 $ruby if.rb よくできました #score80点以上 kouya:ruby_proje #条件が真(true)になった段階でif文を抜けている。 #また、59点以下の場合はelse内の処理が実行されている。実践2
catならmeow
dogならbowwow
cowならmoomoo
上記以外ならNot foundと出力されるプログラム
if2.rbanimal = X(任意の変数が入る) if animal == "cat" puts "meow" elsif animal == "dog" puts "bowwow" elsif animal == "cow" puts "moomoo" else puts "Not found" end # =は右辺を左辺に代入するとき ==は右辺と左辺が等しいときに使用するので注意出力結果
$ ruby if2.rb meow #animalがcat $ ruby if2.rb bowwow #animalがdog $ ruby if2.rb moomoo #animalがcow $ ruby if2.rb Not found " #animalが上記以外実践3
遊園地の入場料のプログラム
12歳以上 入場料 5,000円
6歳以上12歳未満 入場料 2,500円
6歳未満 1,000円if3.rbage = x(任意の値が入る) if age >= 12 puts 5000 elsif age >= 6 puts 2500 else age < 6 puts 1000 end出力結果
kouya:ruby_projects toripurug884$ ruby if3.rb 1000 #6歳未満 kouya:ruby_projects toripurug884$ ruby if3.rb 5000 #12歳以上 kouya:ruby_projects toripurug884$ ruby if3.rb 2500 #6歳未満12歳以上
unless文
記述方法
unless 条件
条件が偽(false)だった場合の処理
else
上記に当てはまらなかった場合の処理
end※unlessにelsifは書かない。
条件が偽になったタイミングで処理を抜ける。
後の処理は実行されない。
nが0で無かった場合、出力するプログラムを書く
if文の場合
unless.rbn = 1 if !n.zero? puts "Not zero" endunless文の場合
unless.rbn = 1 unless n.zero? puts "This is zero" end$ ruby unless.rb Not zero Not zero0の場合に出力するプログラムを unless文で追加
unless.rbn = 0 unless n.zero? puts "Not zero" else puts "This is zero" end出力結果
unless.rb$ ruby unless.rb This is zerounlessは無理に使う必要はなく、ifでも読み易ければOK
case文
記述方法
case 対象のオブジェクトや式
when
値1に一致する場合の処理
when
値2に一致する場合の処理
when
値3に一致する場合の処理
else
上記のいずれにも該当しない場合
end
実践
下記のプログラムを実装
誕生石がrubyだった場合 July
誕生石がperidotだった場合 August
誕生石がsapphireだった場合 September
上記意外だった場合 Not foundifで書いた場合
case.rbstone = x(任意の値を代入) if stone == "ruby" puts "July" elsif stone == "peridot" puts "August" elsif stone == "sapphire" puts "September" else puts "Not Found" endcase.rb$ ruby case.rb July #ruby $ ruby case.rb August #peridot $ ruby case.rb September #sappire $ ruby case.rb Not Found #上記以外case文で書いた場合
case.rbstone = x (任意の値が入る) case stone when "ruby" puts "July" when "peridot" puts "August" when "sapphire" puts "September" else puts "Not found" end出力結果
$ ruby case.rb July #ruby $ ruby case.rb August #peridot $ ruby case.rb September #sapphire $ ruby case.rb Not found #上記以外
if文で書くより、caseで書いた方がシンプルでわかりやすいことがある。
特に、複数の条件に分岐する場合はcaseの方が見やすい場合が多い。まとめ
複数人で開発場合、特ににコードの見易さやメンテナンス性が重要視される
自分にしかわからないコードを書くのではなく、相手にわかりやすいコードを書くように心がける必要がある。
- 投稿日:2019-02-28T12:37:22+09:00
なぜコスプレ?
日本の最高のゲームショーケースでよく見られるように、今年の東京ゲームショーは、さまざまなニンテンドー(および非ニンテンドー)のフランチャイズからの素晴らしいコスプレでした。 会社の最も有名な顔のいくつか、そしてもちろん少数のカルト的なお気に入りを含む、すべてのビッグネームが表示されていました。
ここにあなたの鑑賞の喜びのためのイベントからの最高のfgo コスプレ 衣装の一部があります。 下記のコメントを投稿して、個人的なお気に入りをお知らせください。私たちの集団であると一緒に、トランスフェムと卓越した卓越性のために、ナイトライフに安全な空間を提供するために努力しています。ここで最高のダンスミュージック、見事なルックス、そして変貌する装飾の要素を地下の奇妙な雰囲気にまとめたいと思います。
https://www.sukicos.com/kamigame-costume-fun.html
何を着ている?
私達は両方とも私達の魅力の空想を完了するためにビンテージミンクを着ています。ゲームは常に冒険リンクをたどりますが、彼が途中で出会った様々な異なるキャラクター(そして彼が取った様々な形態)は、自家製のファッションに目を向けた人々に多くのインスピレーションを提供します。 才能のあるファンのこの多様なコミュニティを祝うために、私たちは地球上のコスプレイヤーから私たちのお気に入りのゼルダをテーマにした10のコスプレを集めました。
何に影響を受けていますか?
私たちはいたるところからインスピレーションを得ています。ポップカルチャー、自然、芸術、社会正義など私たちはしばしば80年代のファッションの派手な色と角度、そしてディスコ時代の輝きと魅力に引き付けられています。私達は、シェール、グレースジョーンズ、プリンス、アマンダルポア、リベレースのような星やスタイルアイコンに触発されています…しかし、ほとんどの場合、私たちはクィアの歴史やシルビアリベラ、マーシャP.ゲイ解放戦線の設立を手助けした活動家たちは、ストーンウォール暴動の間の中心的人物であった。彼らは我々のコミュニティが今日のものになる道を開いた。
https://www.sukicos.com/costume-re-zero.html
今まで聞いたことがある初心者のための最高のコスプレ衣装のヒントの1つは分岐についてです。大会で他人と話すのを恐れないでください。信じられないほどのコスプレをした人を見かけたら、ぜひ、彼らに近づいて彼らを褒め、どうやってそれを作ったのか尋ねてください。
尋ねることに恥ずべきことはありません、そしておそらくあなたはたいていのコスプレイヤーが何らかのガイダンスを共有して幸せであることに気付くでしょう。実際、コスプレはあなたが参加できる最も歓迎されるコミュニティの1つであると多くの人が言うかもしれません。あなたが縫うことを学びたいのなら、それはあなたがあなたを教えることができる他の人に手を差し伸べるためにうまくいくでしょう。
「お金と名声のためではなく、あなたがそれを愛するからそれをしなさい」。有名なコスプレイヤーはいましたか?もちろんです。彼らの素晴らしい衣装のためにお金を稼ぐことになったコスプレイヤーはいましたか?はい。しかし、彼らはまた、彼らが技術に情熱を持っているのでコスプレをする傾向があります。次のになりたい初心者のための最高のコスプレのヒントの一つは、それは良い考えではないかもしれないということです。プロのコスプレは非常に競争力があり、それはまだ何よりもまずコミュニティです。さらに、それはその技術を非常に真剣に考えるコミュニティです。私はコスプレの相互愛が最近の記憶に一緒に2つのより記憶に残るビデオゲームの悪人をもたらしたものになると予測することはなかったでしょう。 恐らく彼らが熱望している自警団員を街の通りから取り除くことができるように団結しているのは、ホラーゲーム役目はロシアのコスプレイヤーです。 ここでは堅実なコスプレが行われていますが、このデュオはコスプレの世界ではあまり見られないシリーズに取り組むためのボーナスポイントを獲得します。
https://www.sukicos.com/fate-grand-order-cosplay-series.html
ここで、私たちから逃げるための同じように思い出深いバディを与えてくれることを願っています。おそらく人類史上最大の悲劇となりました。
- 投稿日:2019-02-28T10:51:33+09:00
Ruby から FFI で Go にバイト列のポインタを渡す
Ruby を書いていると、バイナリ処理を Go で書いて FFI 呼び出すことでいい感じにしたくなることがあります。
バイナリの受け渡しをする際は、String を使うと NULL 文字で終端されてしまう 1 ため、ポインタで渡してあげる必要があります。
C での書き方は ffi/ffi の wiki に載っていますが、Go での書き方は調べてもあまり出てこないので、ここに書いておきます。
main.gopackage main import ( "C" "bytes" "unsafe" ) //export hoge func hoge(pointer unsafe.Pointer, size C.int) *C.char { // ポインタからバイト列を取り出す var data []byte = C.GoBytes(pointer, size) // バイト列を使って何か処理する var result string = do_something(data) // Go の string を C の string に変換して返す return C.CString(result) } func do_something(data []byte) string { return "xxx" } func main() { }hoge.rbrequire 'ffi' module Hoge extend FFI::Library # 上記の Go を shared library にコンパイルしたファイル ffi_lib 'hoge.so' attach_function :hoge, [:pointer, :uint], :string class << self # ポインタを渡す必要があるので private にしてインターフェイスを call_hoge に統一する private :hoge # 文字列をポインタに変換してから hoge を呼ぶ def call_hoge(string) mem_buf = FFI::MemoryPointer.from_string(string) hoge(mem_buf, data.bytesize) end end end
Binary data · ffi/ffi Wiki https://github.com/ffi/ffi/wiki/Binary-data ↩
- 投稿日:2019-02-28T10:15:41+09:00
RubyでXMLから欲しい情報のハッシュを作成
RubyでXMLから欲しい情報のハッシュを作成
もし、もっと良い方法があればコメントください!!
PC環境
- Mac OS Mojave 10.14.1
- Ruby 2.4.0
何がしたいのか
ゲスエンジニアのとださんが先日rubyの問題をnoteで出題していました。
上記noteは以下のurlを参照ください。
https://note.mu/cohki0305/n/n339931e3f705Rubyで天気予報のプログラムを作成するのですが、
ライブドアのお天気サービスのAPIを用いるとき、
http://weather.livedoor.com/forecast/rss/primary_area.xml にて
あらかじめ場所の
city id
を知っていないといけません。調べたい場所が変わるごとに
city id
を設定し直すのは面倒です。だったら、
http://weather.livedoor.com/forecast/rss/primary_area.xml の情報から
場所をキー、
city id
を値としたハッシュを作成してしまえば手間が省けるのではないかと考えました。実際のハッシュ作成プログラム
実際に作成したプログラムです。
require 'open-uri' require "rexml/document" require 'active_support' require 'active_support/core_ext' xml_url = open("http://weather.livedoor.com/forecast/rss/primary_area.xml").read.toutf8 xml_doc = REXML::Document.new(xml_url) xml_hash = Hash.from_xml(xml_doc.to_s) city_id_hash = {} xml_hash["rss"]["channel"]["source"]["pref"].each do |key| count = 0 #ハッシュ作成 while key["city"][count] != nil do city_id_hash[key["city"][count]["title"]] = key["city"][count]["id"] count += 1 end end #確認用 puts city_id_hash実行結果は次の通りです。
{"稚内"=>"011000", "旭川"=>"012010", "留萌"=>"012020", "網走"=>"013010", "北見"=>"013020", "紋別"=>"013030", "根室"=>"014010", "釧路"=>"014020", "帯広"=>"014030", "室蘭"=>"015010", "浦河"=>"015020", "札幌"=>"016010", "岩見沢"=>"016020", "倶知安"=>"016030", "函館"=>"017010", "江差"=>"017020", "青森"=>"020010", "むつ"=>"020020", "八戸"=>"020030", "盛岡"=>"030010", "宮古"=>"030020", "大船渡"=>"030030", "仙台"=>"040010", "白石"=>"040020", "秋田"=>"050010", "横手"=>"050020", "山形"=>"060010", "米沢"=>"060020", "酒田"=>"060030", "新庄"=>"060040", "福島"=>"070010", "小名浜"=>"070020", "若松"=>"070030", "水戸"=>"080010", "土浦"=>"080020", "宇都宮"=>"090010", "大田原"=>"090020", "前橋"=>"100010", "みなかみ"=>"100020", "さいたま"=>"110010", "熊谷"=>"110020", "秩父"=>"110030", "千葉"=>"120010", "銚子"=>"120020", "館山"=>"120030", "東京"=>"130010", "大島"=>"130020", "八丈島"=>"130030", "父島"=>"130040", "横浜"=>"140010", "小田原"=>"140020", "新潟"=>"150010", "長岡"=>"150020", "高田"=>"150030", "相川"=>"150040", "富山"=>"160010", "伏木"=>"160020", "金沢"=>"170010", "輪島"=>"170020", "福井"=>"180010", "敦賀"=>"180020", "甲府"=>"190010", "河口湖"=>"190020", "長野"=>"200010", "松本"=>"200020", "飯田"=>"200030", "岐阜"=>"210010", "高山"=>"210020", "静岡"=>"220010", "網代"=>"220020", "三島"=>"220030", "浜松"=>"220040", "名古屋"=>"230010", "豊橋"=>"230020", "津"=>"240010", "尾鷲"=>"240020", "大津"=>"250010", "彦根"=>"250020", "京都"=>"260010", "舞鶴"=>"260020", "神戸"=>"280010", "豊岡"=>"280020", "奈良"=>"290010", "風屋"=>"290020", "和歌山"=>"300010", "潮岬"=>"300020", "鳥取"=>"310010", "米子"=>"310020", "松江"=>"320010", "浜田"=>"320020", "西郷"=>"320030", "岡山"=>"330010", "津山"=>"330020", "広島"=>"340010", "庄原"=>"340020", "下関"=>"350010", "山口"=>"350020", "柳井"=>"350030", "萩"=>"350040", "徳島"=>"360010", "日和佐"=>"360020", "松山"=>"380010", "新居浜"=>"380020", "宇和島"=>"380030", "高知"=>"390010", "室戸岬"=>"390020", "清水"=>"390030", "福岡"=>"400010", "八幡"=>"400020", "飯塚"=>"400030", "久留米"=>"400040", "佐賀"=>"410010", "伊万里"=>"410020", "長崎"=>"420010", "佐世保"=>"420020", "厳原"=>"420030", "福江"=>"420040", "熊本"=>"430010", "阿蘇乙姫"=>"430020", "牛深"=>"430030", "人吉"=>"430040", "大分"=>"440010", "中津"=>"440020", "日田"=>"440030", "佐伯"=>"440040", "宮崎"=>"450010", "延岡"=>"450020", "都城"=>"450030", "高千穂"=>"450040", "鹿児島"=>"460010", "鹿屋"=>"460020", "種子島"=>"460030", "名瀬"=>"460040", "那覇"=>"471010", "名護"=>"471020", "久米島"=>"471030", "南大東"=>"472000", "宮古島"=>"473000", "石垣島"=>"474010", "与那国島"=>"474020"}なかなかの力技のような気はしますが、とりあえずはできました。
作成に至るまでの試行錯誤
まず
xml_url = open("http://weather.livedoor.com/forecast/rss/primary_area.xml").read.toutf8 xml_doc = REXML::Document.new(xml_url) xml_hash = Hash.from_xml(xml_doc.to_s)で http://weather.livedoor.com/forecast/rss/primary_area.xml の情報をハッシュに変換します。
次に
city_id_hash = {} xml_hash["rss"]["channel"]["source"]["pref"].each do |key| count = 0 #ハッシュ作成 while key["city"][count] != nil do city_id_hash[key["city"][count]["title"]] = key["city"][count]["id"] count += 1 end endで地名とそれに対応する
city id
だけを抜き出してハッシュを作成しています。
作成中にはどのキーに地名やcity id
が埋まっているかわからないので、xml_hash["rss"]["channel"]["source"]["pref"]に関しては、
xml_hash.keys
やxml_hash["rss"].keys
を何回も繰り返して地道に見つけていきました笑while文の条件、
key["city"][count] != nil
はなぜこのようにしているかというと、
都道府県ごとに所有している地名が異なるからです。
この実装については実際にputs key["city"]
をループ中に挿入して動作を確認していただくと理解できると思います。ぜひ考えてみてください。現状の問題点
実行速度が遅い気がする。
もっと良い方法があるのならばぜひコメントください!
まとめ
今回の実装のポイントは
1. xmlをhashとして読み込む
2. 読み込んだhashのデータ構造を調査する
3. 欲しい情報を抜き出し、求めていたハッシュを完成させるでした。
参考記事
- 『kzfm’s trial and error 本腰いれてRubyやPHPを覚えていくブログ。』
- XMLをParseする (Ruby)
- http://kzfm-s.hateblo.jp/entry/2015/06/07/014735
- 投稿日:2019-02-28T09:53:54+09:00
Ruby 演算子,真偽値
動作環境はMacとなります。
比較演算子
演算子による値の比較
2つの値の大小と同じ値かを調べる方法比較演算子の記号
※マークダウン方式の影響で、より大きいの記述がおかしくなってます。より大きい > ⇦これ
= 以上
< より小さい
<= 以下
== 等しい
!= 等しくない
式が成り立つ場合 true
式が成り立たない場合falseを返すirb#1(main):001:0> 1 < 2 => true irb#1(main):002:0> 1 <= 2 => true irb#1(main):003:0> 1 > 2 => false irb#1(main):004:0> 1 >= 2 => false irb#1(main):005:0> 1 == 2 => false irb#1(main):006:0> 1 != 2 => true演算子の優先順位
irb#1(main):007:0> 1.0 + 2.0 * 3.0 / 4.0 => 2.5 irb#1(main):008:0> (1.0 + 2.0) * 3.0 / 4.0 #()で優先順位を上げる => 2.25高い ::
[]
+(単項) ! ~
**
-(単項)
* / %
+ -
<< >>
&
| ^
> >= < <=
<=> == === != =~ !~
&&
||
.. ...
?:(条件演算子)
=(+=, -= ... )
not
低い and or
数値と文字列は暗黙的に変換されない
数値と文字列を連結するとエラー
irb#1(main):009:0> 1 + "1" TypeError: String can't be coerced into Integer from (irb#1):9:in `+' from (irb#1):9文字列を数値に変換
irb#1(main):011:0> 1 + "1".to_i #整数クラスに変換 => 2 irb#1(main):012:0> 1 + "1.1".to_f #浮動小数点クラスに変換 => 2.1出力された!
数値を文字列に変換
irb#1(main):015:0> num = 10 => 10 irb#1(main):021:0> "Number name is " + num TypeError: no implicit conversion of Integer into String from (irb#1):21:in `+' from (irb#1):21 #numが変数のため、わかりにくいが文字列と数値の足し算はエラー irb#1(main):020:0> "Number name is " + num.to_s => "Number name is 10" #数値を文字列に変換出力された!
インクリメントとディクリメント
・インクリメント
数値に1を足す・ディクリメント
数値から1を引く他のプログラミング言語のように++や--で表すことができない点に注意!
irb#1(main):022:0> n = 1 => 1 irb#1(main):023:0> n = n + 1 => 2 irb#1(main):024:0> n += 1 => 3 irb#1(main):025:0> n = n - 1 => 2 irb#1(main):026:0> n -= 1 => 1 #どちらの表記でも大丈夫だが、+=や-=で表した方がスマート真偽値
Rubyでは、nilかfalseの場合は偽(false)
それ以外は真(true)trueの例
- trueそのもの・・・true
- 全ての数値・・・1,1.5,2/3
- 全ての文字列 ・・・"false","true",""(空文字)
論理演算子
&&や||で複数の条件の式を真偽値で返すことが可能になる。
論理積
&&(かつ)=全ての条件が真の場合trueを返す論理和
||(または)=少なくとも一つの条件が当てはまれば真になり、trueを返すand,or,not
&&,||,!とほぼ同じ役割
ただし計算の優先順位が異なるため、式に混在させないこと
irb(main):001:0> t1 = true => true irb(main):002:0> t2 = true => true irb(main):003:0> f1 = false => false irb(main):004:0> f2 = false => false irb(main):005:0> t1 and t2 => true irb(main):006:0> t1 and f1 => false irb(main):007:0> t1 or t2 => true irb(main):008:0> f1 or f2 => false irb(main):009:0> !t1 || t1 #trueとfalse => true#混在させると非常にわかりにくくなるため注意 irb(main):010:0> not t1 || t1 => false irb(main):011:0> t1 || t2 && f1 #&&の方が優先順位が高いため、t2とf1の計算が先にされた後、t1との和が計算される。 => true irb(main):012:0> t1 or t2 and f1 #orとandの優先順位は等しいので、左から計算 => false#()で囲ったりわかりやすくすることは複数人で開発するときには欠かせないスキル irb(main):013:0> (t1 || t2) && f1 => falseまとめ
リファレンスに書いてある優先順位が高いものと低いものを混在させると非常にわかりにくい。
また、優先順位を上げたいときは()でくくるなど、直感的でわかりやすいプログラムを書くことが重要。シンプルに記述するように心がけよう!
参考文献
- 投稿日:2019-02-28T08:14:48+09:00
Ruby オブジェクト指向、数値、文字列
動作環境はMacとなります。
主に自分の勉強用メモとして残しています。オブジェクト指向プログラミング言語
- コンピュータ・プログラミングの概念の一つ。
- オブジェクト指向の概念や手法を取り入れたもの。
- プログラムを、データとその振る舞いが結びつけられたオブジェクトの集まりとして構成する。
オブジェクトとは?
データと処理の集まりのこと。文字列、配列、数値、nilなど全てオブジェクト。オブジェクト指向とは?
オブジェクト同士が相互に関係しあうことで、システムの振る舞いを捉える考え方。クラス
オブジェクトの設計図インスタンス
クラス(設計図)から作成した、実態。メソッド
- クラスの中に定義されていて、複数の処理を1つにまとめて、扱いやすくしたもの
- クラスに所属する関数のようなもの
数値(Numeric)
Numericは親クラス
- Numeric ・・・ 数値クラス
- Integer ・・・ 整数クラス(整数を扱うクラス)
- Float ・・・浮動小数点クラス(小数点以下を扱うクラス)
動的型付け
変数に格納した時に自動的に型が設定されるため、明示的にクラスを書く必要はない。
例)
i = 1はOK
int i = 0はNG
四則演算
irb(main):045:0> 1 + 1 => 2 irb(main):046:0> 10 - 1 => 9 irb(main):047:0> 13 * 2 #掛け算 => 26 irb(main):048:0> 100 / 5 #割り算 => 20irb(main):049:0> x = 1 #xに1を代入 => 1 irb(main):050:0> - x #入れた変数に-をつけると符号を反転させることができる => -1割り算の注意点
irb(main):053:0* 3 / 2 #小数点の計算がされない => 1 #どちらかまたはどちらの数値にも小数点をつける必要がある irb(main):054:0> 3.0 / 2 => 1.5 irb(main):055:0> 3 / 2.0 => 1.5 irb(main):056:0> 3.0 / 2.0 => 1.5irb(main):001:0> 10 % 3 #剰余 => 1 irb(main):002:0> 10 ** 3 #べき乗 => 1000irb(main):004:0> x = 5 #5を代入 => 5 irb(main):005:0> x.to_f #小数に変換 => 5.0 irb(main):006:0> x.to_f / 7 #5を小数に変換し、7で割る => 0.7142857142857143 irb(main):007:0> x / 7 #5 / 7の出力結果 ※小数点は出力されない => 0#クラスの確認 irb(main):008:0> 1.class => Integer irb(main):009:0> 1.1.class => Float #クラスのメソッドの確認 irb(main):010:0> 1.methods => [:%, :&, :*, :+, :-, :/, :<, :>, :^, :|, :~, :-@, :**, :<=>, :<<, :>>, :<=, :>=, :==, :===, :[], :inspect, :size, :succ, :to_int, :to_s, :to_i, :to_f, :next, :div, :upto, :chr, :ord, :coerce, :divmod, :fdiv, :modulo, :remainder, :abs, :magnitude, :integer?, :floor, :ceil, :round, :truncate, :odd?, :even?, :downto, :times, :pred, :bit_length, :digits, :to_r, :numerator, :denominator, :rationalize, :gcd, :lcm, :gcdlcm, :+@, :eql?, :singleton_method_added, :i, :real?, :zero?, :nonzero?, :finite?, :infinite?, :step, :positive?, :negative?, :quo, :arg, :rectangular, :rect, :polar, :real, :imaginary, :imag, :abs2, :angle, :phase, :conjugate, :conj, :to_c, :between?, :clamp, :instance_of?, :kind_of?, :is_a?, :tap, :public_send, :public_method, :singleton_method, :remove_instance_variable, :define_singleton_method, :method, :instance_variable_set, :extend, :to_enum, :enum_for, :=~, :!~, :respond_to?, :freeze, :object_id, :send, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variable_get, :instance_variables, :instance_variable_defined?, :!, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]文字列(String)
文字列はシングルクオートかダブルクオートで囲む。
挙動の違い
irb(main):006:0> "abcde" => "abcde" irb(main):007:0> 'abcde' => "abcde" #この時点での違いはない。irb(main):001:0> puts "Ruby\nProgramming" Ruby Programming => nil irb(main):002:0> puts 'Ruby\nProgramming' Ruby\nProgramming => nil #ダブルクオートで囲むと、文字列の途中で改行される #シングルクオートで囲むと、改行されない ※バックスラッシュはoptionキー+¥キーirb(main):003:0> first_name = "Yuta" => "Yuta" irb(main):004:0> last_name = "Nakamura" => "Nakamura" irb(main):006:0> "My name is #{first_name} #{last_name}" => "My name is Yuta Nakamura" irb(main):007:0> 'My name is #{first_name} #{last_name}' => "My name is \#{first_name} \#{last_name}" #ダブクオートで囲むと#{}で囲んだ文字列が式展開される #シングルクオートではそのまま表示されるまとめ
ダブルクオートを使う場合・・・式展開、改行したい時
シングルクオートを使う場合・・・それ以外
その他文字列の使い方
irb(main):010:0> puts "kengo" + "kaneki" kengokaneki => nil irb(main):011:0> puts "kengo" + " " + "kaneki" kengo kaneki #スペースを開けたい場合、" "を連結破壊的メソッド メソッド名の最後に!を記述
irb(main):017:0> name = 'ken' => "ken" irb(main):018:0> puts name ken => nil #upcaseメソッドの破壊的メソッド irb(main):019:0> name.upcase => "KEN" irb(main):020:0> name => "ken" #変数の中身に変化はない irb(main):021:0> name.upcase! => "KEN" irb(main):022:0> name => "KEN" #変数の中身自体が大文字に書き換わるクラスの確認
irb(main):023:0> "ken".class => Stringメソッドの確認
irb(main):024:0> "ken".methods => [:include?, :%, :*, :+, :to_c, :unicode_normalize, :unicode_normalize!, :unicode_normalized?, :count, :partition, :unpack, :unpack1, :sum, :next, :casecmp, :casecmp?, :insert, :bytesize, :match, :match?, :succ!, :+@, :-@, :index, :rindex, :<=>, :replace, :clear, :upto, :getbyte, :==, :===, :setbyte, :=~, :scrub, :[], :[]=, :chr, :scrub!, :dump, :byteslice, :upcase, :next!, :empty?, :eql?, :downcase, :capitalize, :swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :lines, :reverse, :chars, :codepoints, :prepend, :bytes, :concat, :<<, :freeze, :inspect, :intern, :end_with?, :crypt, :ljust, :reverse!, :chop, :scan, :gsub, :ord, :start_with?, :length, :size, :rstrip, :succ, :center, :sub, :chomp!, :sub!, :chomp, :rjust, :lstrip!, :gsub!, :chop!, :strip, :to_str, :to_sym, :rstrip!, :tr, :tr_s, :delete, :to_s, :to_i, :tr_s!, :delete!, :squeeze!, :each_line, :squeeze, :strip!, :each_codepoint, :lstrip, :slice!, :rpartition, :each_byte, :each_char, :to_f, :slice, :ascii_only?, :encoding, :force_encoding, :b, :valid_encoding?, :tr!, :encode, :encode!, :hash, :to_r, :<, :>, :<=, :>=, :between?, :clamp, :instance_of?, :kind_of?, :is_a?, :tap, :public_send, :public_method, :singleton_method, :remove_instance_variable, :define_singleton_method, :method, :instance_variable_set, :extend, :to_enum, :enum_for, :!~, :respond_to?, :object_id, :send, :display, :nil?, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variable_get, :instance_variables, :instance_variable_defined?, :!, :!=, :__send__, :
空白文字の使い方
irb(main):025:0> 1 + 2 => 3 irb(main):026:0> 1+2 => 3 irb(main):027:0> 1 +2 + 3 => 6 #スペースはいくら開けても開けなくても挙動に違いはない。 基本的にはスペースを一文字ずつ空けるのが定説
- 投稿日:2019-02-28T07:41:24+09:00
条件分岐の組み替え(Recompose Conditional)
1つずつリファクタリング技法まとめ
個人的に簡単かつ取り入れ易いと思うものから目的
すぐ引き出せるようにする
基本作業サイクル
- システムを動かして仕様を精査
- テストメソッドを作成
- テストの失敗を確認
- テストの成功を確認
- 小さい変更、随時テスト実行(失敗確認->成功確認)
- 最後テスト実行
- 最後動作確認
条件分岐の組み替え(Recompose Conditional)とは
言語独自の構文要素を使うこと
イディオム(条件などに使用できる記号)など完結に実現できるものを使うポイント
- 記述量が減る
- 誰がみても分かるかという意味ではRubyの習熟度に依存する部分がややある
例
- 三項演算子はイディオムのORの演算子を利用して表現できる
user.age = age ? age : '年齢不詳'↓
user.age = age || '年齢不詳'
- returnはガード節(早期return)以外基本いらない
- 条件式の中行われている処理が1つだけならば、return if構文を使用できる
def talk(age) if age < 2 'おぎゃー' else '話せるよ' end end↓
def talk(age) return 'おぎゃー'if age < 2 '話せるよ' end書籍情報
Jay Fields (著), Shane Harvie (著), Martin Fowler (著), Kent Beck (著),
長尾 高弘(訳), リファクタリング:Rubyエディション
https://amzn.to/2VlyWML雑感
凝りすぎずにシンプルさと読み易さを意識する。
- 投稿日:2019-02-28T07:39:56+09:00
条件分岐の組み替え(Recompose Conditional)
1つずつリファクタリング技法まとめ
個人的に簡単かつ取り入れ易いと思うものから目的
すぐ引き出せるようにする
基本作業サイクル
- システムを動かして仕様を精査
- テストメソッドを作成
- テストの失敗を確認
- テストの成功を確認
- 小さい変更、随時テスト実行(失敗確認->成功確認)
- 最後テスト実行
- 最後動作確認
条件分岐の組み替え(Recompose Conditional)とは
言語独自の構文要素を使うこと
イディオム(条件などに使用できる記号)など完結に実現できるものを使うポイント
- 記述量が減る
- 誰がみても分かるかという意味ではRubyの習熟度に依存する部分がややある
例
- 三項演算子はイディオムのORの演算子を利用して表現できる
user.age = age ? age : '年齢不詳'↓
user.age = age || '年齢不詳'
- returnはガード節(早期return)以外基本いらない
- 条件式の中行われている処理が1つだけならば、return if構文を使用できる
def talk(age) if age < 2 'おぎゃー' else '話せるよ' end end↓
def talk(age) return 'おぎゃー'if age < 2 '話せるよ' end書籍情報
Jay Fields (著), Shane Harvie (著), Martin Fowler (著), Kent Beck (著),
長尾 高弘(訳), リファクタリング:Rubyエディション
https://amzn.to/2VlyWML雑感
凝りすぎずにシンプルさと読み易さを意識する。