- 投稿日:2019-11-12T23:25:08+09:00
[Ruby]使用頻度は高くないがここぞという時に知っていたら便利そうなメソッドたち
使用頻度は高くないので忘れちゃいそうだけど、ここぞという時に知っていたら便利そうなメソッドを備忘のためにまとめておきます。
(便利かつ高頻度で使うものは忘れないと思うのでここには書きません)今後も便利そうだと思うメソッドがあったら随時追加していく予定です。
clamp
数値の上限・下限を制限する
523.clamp(0, 100) # => 100email_address_with_name
action_mailerのtoに<>や"が含まれていた場合、エスケープしてくれる
# <>や"がnameやemailに入っていてもエスケープしてくれる。 mail(to: email_address_with_name(@user.email, @user.name))squish
スペースやタブ、改行をいい感じに除去してくれる
" \n foo\n\r \t bar \n".squish # => "foo bar"
- 投稿日:2019-11-12T23:10:12+09:00
RubocopでデフォルトOFFにされているものたち
概要
Rubocop には現在400弱の Cop が存在するが、config/default.yml にて
Enabled: false
とされているものについては、明示的に有効化しないとチェックしてくれない。
そこで、デフォルトでオフになっている Cop にはどんなものがあるのかを調べた。2019/11/12 時点での master ブランチ。バージョンは 0.76。
- Bundler/GemComment
- Layout/ClassStructure
- Layout/FirstArrayElementLineBreak
- Layout/FirstHashElementLineBreak
- Layout/FirstMethodArgumentLineBreak
- Layout/FirstMethodParameterLineBreak
- Layout/HeredocArgumentClosingParenthesis
- Layout/MultilineArrayLineBreaks
- Layout/MultilineAssignmentLayout
- Layout/MultilineHashKeyLineBreaks
- Layout/MultilineMethodArgumentLineBreaks
- Lint/HeredocMethodCallPosition
- Lint/NumberConversion
- Migration/DepartmentName
- Style/AutoResourceCleanup
- Style/CollectionMethods
- Style/ConstantVisibility
- Style/Copyright
- Style/DateTime
- Style/DocumentationMethod
- Style/ImplicitRuntimeError
- Style/InlineComment
- Style/IpAddresses
- Style/MethodCallWithArgsParentheses
- Style/MethodCalledOnDoEndBlock
- Style/MissingElse
- Style/MultilineMethodSignature
- Style/OptionHash
- Style/ReturnNil
- Style/Send
- Style/SingleLineBlockParams
- Style/StringHashKeys
- Style/StringMethods
全部で33個。
Enabled: true
が340個くらいあるから、その割合は10%弱くらい。それぞれのCopについて
Bundler/GemComment
Gemfile
に記載されている gem ひとつひとつにコメントを付けなければならない。# bad gem 'foo' # good # Helpers for the foo things. gem 'foo'必ずコメントを求めるってすごい。
gem "rails"
とかにも何かしら書かないといけないのかな?Layout/ClassStructure
クラス内の定義の順番が定められている。
上から順に以下のような構造が推奨されている。
- module_inclusion(
include
,extend
,prepend
)- constants
- association(
has_one
,has_many
)- public_attribute_macros(
attr_accessor
,attr_writer
,attr_reader
)- public_delegate
- macros(
validates
,validate
)- public_class_methods
- initializer
- public_methods
- protected_attribute_macros(
attr_accessor
,attr_writer
,attr_reader
)- protected_methods
- private_attribute_macros(
attr_accessor
,attr_writer
,attr_reader
)- private_delegate
- private_methods
# bad # Expect extend be before constant class Person < ApplicationRecord has_many :orders ANSWER = 42 extend SomeModule include AnotherModule end # good class Person # extend and include go first extend SomeModule include AnotherModule # inner classes CustomError = Class.new(StandardError) # constants are next SOME_CONSTANT = 20 # afterwards we have public attribute macros attr_reader :name # followed by other macros (if any) validates :name # then we have public delegate macros delegate :to_s, to: :name # public class methods are next in line def self.some_method end # initialization goes between class methods and instance methods def initialize end # followed by other public instance methods def some_method end # protected attribute macros and methods go next protected attr_reader :protected_name def some_protected_method end # private attribute macros, delegate macros and methods # are grouped near the end private attr_reader :private_name delegate :some_private_delegate, to: :name def some_private_method end endこれは地味にうれしいかもしれないが、意味のある塊ごとにまとめたい派もいそう。
Layout/FirstArrayElementLineBreak
複数行の配列を書くときは、最初の要素の前に改行を入れること。
# bad [ :a, :b] # good [ :a, :b]Layout/FirstHashElementLineBreak
上の Hash バージョン。
# bad { a: 1, b: 2} # good { a: 1, b: 2 }Layout/FirstMethodArgumentLineBreak
上のメソッド呼び出しバージョン。
複数行にわたるメソッド呼び出しを行う場合は最初の引数の前に改行を入れること。# bad method(foo, bar, baz) # good method( foo, bar, baz) # ignored method foo, bar, bazLayout/FirstMethodParameterLineBreak
上のメソッド定義バージョン。
メソッドパラメータが複数行にわたる場合は最初のパラメータの前に改行を入れること。# bad def method(foo, bar, baz) do_something end # good def method( foo, bar, baz) do_something end # ignored def method foo, bar do_something end余談だが、呼び出し側で渡すものは「引数」、メソッド定義側で定義するのは「パラメータ」と呼ぶ。
https://techracho.bpsinc.jp/hachi8833/2017_04_05/37930
Cop名もArgument
,Parameter
となってますね。Layout/HeredocArgumentClosingParenthesis
ヒアドキュメントを引数として渡す際に、閉じ括弧
)
の位置は、開始タグを含む行の末尾が推奨とされている。# bad foo(<<-SQL bar SQL ) foo(<<-SQL, 123, <<-NOSQL, bar SQL baz NOSQL ) foo( bar(<<-SQL baz SQL ), 123, ) # good foo(<<-SQL) bar SQL foo(<<-SQL, 123, <<-NOSQL) bar SQL baz NOSQL foo( bar(<<-SQL), baz SQL 123, )Layout/MultilineArrayLineBreaks
複数行に渡る配列では、一行に複数の要素を入れてはならない。
# bad [ a, b, c ] # good [ a, b, c ]Layout/MultilineAssignmentLayout
複数行に渡る代入において、代入演算子の後ろに改行を入れるかどうか。
デフォルトでは入れることになっているが、入れないルールに設定することもできる。# bad foo = if expression 'bar' end # good foo = if expression 'bar' end # good foo = begin compute rescue => e nil endLayout/MultilineHashKeyLineBreaks
先に見た
Layout/MultilineArrayLineBreaks
の Hash バージョン。
複数行に渡る Hash では、一行に複数のキーを入れてはならない。# bad { a: 1, b: 2, c: 3 } # good { a: 1, b: 2, c: 3 }Layout/MultilineMethodArgumentLineBreaks
上のメソッド呼び出しバージョン。
複数行に渡るメソッド呼び出しでは、一行に複数の引数を入れてはならない。# bad foo(a, b, c ) # good foo( a, b, c )Lint/HeredocMethodCallPosition
ヒアドキュメンドがレシーバーとなる際の、メソッドコールの順番を定めている。
# bad <<-SQL bar SQL .strip_indent <<-SQL bar SQL .strip_indent .trim # good <<~SQL bar SQL <<~SQL.trim bar SQLLint/NumberConversion
予期せぬエラーを引き起こす可能性のある型変換は避けるように、Numericクラスでのパースを推奨している。
# bad '10'.to_i '10.2'.to_f '10'.to_c # good Integer('10', 10) Float('10.2') Complex('10')こういうことですね。
irb(main):001:0> "hoge".to_i => 0 irb(main):002:0> Integer("hoge", 10) Traceback (most recent call last): 5: from /usr/local/bin/irb:23:in `<main>' 4: from /usr/local/bin/irb:23:in `load' 3: from /usr/local/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>' 2: from (irb):2 1: from (irb):2:in `Integer' ArgumentError (invalid value for Integer(): "hoge")Migration/DepartmentName
ドキュメントがないので不明。
サイドメニューの目次からは消えてるしなくなったっぽい...?
ただdefault.yml
には残っている。Style/AutoResourceCleanup
自動的にリソースのクリーンアップを行ってくれる方を推奨。
自分でファイルを明示的にクローズする必要がないようにブロック付きで呼び出すFile
のやつはおなじみですね。
あと他どんなのがあるんだろう?# bad f = File.open('file') # good File.open('file') do |f| # ... endStyle/CollectionMethods
Eunmerable
モジュールのメソッドに関して、一貫して同じメソッド名を用いることを強制するもの。
どちらのメソッドを使うのかは設定可能。
あるところではcollect
を使っているのに別のところではmap
を使っている、みたいなブレを防止するためにあると思われ。# bad items.collect items.collect! items.inject items.detect items.find_all # good items.map items.map! items.reduce items.find items.selectStyle/ConstantVisibility
定数は全て明示的にスコープを宣言することを推奨するもの。
# bad class Foo BAR = 42 BAZ = 43 end # good class Foo BAR = 42 private_constant :BAR BAZ = 43 public_constant :BAZ endStyle/Copyright
全てのソースファイルにコピーライトを入れること。
値は正規表現でチェックする。Style/Copyright: Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'これは草?
Ruby スタイルガイドのリファレンスがないけどどういう経緯で入ったんだろう。
ライセンス系かな?Style/DateTime
一貫して
DateTime
ではなくTime
を使うように推奨しているが、
複数のタイムゾーンやサマータイムを扱ったりするときなど、
特別なケースでは二つは代替可能なものではないのでデフォルトで Disabled になっているらしい。# bad - uses `DateTime` for current time DateTime.now # good - uses `Time` for current time Time.now # bad - uses `DateTime` for modern date DateTime.iso8601('2016-06-29') # good - uses `Time` for modern date Time.iso8601('2016-06-29') # good - uses `DateTime` with start argument for historical date DateTime.iso8601('1751-04-23', Date::ENGLAND)Style/DocumentationMethod
パブリックなメソッドには必ずドキュメントを書くようにする。
オプションで、パブリック以外も含めた全てのメソッドに適用するように設定できる。# bad class Foo def bar puts baz end end module Foo def bar puts baz end end def foo.bar puts baz end # good class Foo # Documentation def bar puts baz end end module Foo # Documentation def bar puts baz end end # Documentation def foo.bar puts baz endStyle/ImplicitRuntimeError
raise
,fail
において、明示的に投げる例外のクラスを指定するよう強制する。# bad raise 'Error message here' # good raise ArgumentError, 'Error message here'Style/InlineComment
インラインコメント禁止。
# good foo.each do |f| # Standalone comment f.bar end # bad foo.each do |f| f.bar # Trailing inline comment endStyle/IpAddresses
IPアドレスのベタ書き禁止。
# bad ip_address = '127.59.241.29' # good ip_address = ENV['DEPLOYMENT_IP_ADDRESS']変更される可能性があるからデプロイを壊さないように、という意図らしい。
この辺りチェックしてくれるのめずらしい。
IPアドレスくらいだったら正規表現で簡単に検出できるからなんだろうな。Style/MethodCallWithArgsParentheses
引数を伴うメソッド呼び出しの括弧
()
の有無をチェックする。
デフォルトでは括弧が必要。
マクロは無視される。
正規表現かホワイトリストで、他に無視するメソッドを設定できる。
もちろん括弧を使わないルールにすることもできる。# bad array.delete e # good array.delete(e) # good # Operators don't need parens foo == bar # good # Setter methods don't need parens foo.bar = baz # okay with `puts` listed in `IgnoredMethods` puts 'test' # okay with `^assert` listed in `IgnoredPatterns` assert_equal 'test', xこれがデフォルトで有効化されてないのはどんな理由なんだろうか?
Style/MethodCalledOnDoEndBlock
do~endブロックにメソッドをチェーンしないでほしいというやつ。
a do b end.cStyle/MissingElse
if
,case
に対して、else
が存在しないと警告してくれる。
if
だけ、case
だけ、という設定も可能。# warn when an `if` or `case` expression is missing an `else` branch. # bad if condition statement end # bad case var when condition statement end # good if condition statement else # the content of `else` branch will be determined by Style/EmptyElse end # good case var when condition statement else # the content of `else` branch will be determined by Style/EmptyElse endStyle/MultilineMethodSignature
メソッドシグネチャが複数行に渡るの禁止。
# good def foo(bar, baz) end # bad def foo(bar, baz) endStyle/OptionHash
キーワード引数をサポートしているのでそっちを使ってほしいとのこと。
# bad def fry(options = {}) temperature = options.fetch(:temperature, 300) # ... end # good def fry(temperature: 300) # ... endStyle/ReturnNil
return nil
かreturn
か、どっちか統一しろとのこと。
デフォルトではreturn
の方を使うのが推奨。# bad def foo(arg) return nil if arg end # good def foo(arg) return if arg endStyle/Send
ありがちな名前だから再定義されるケースに備えてライブラリでは
__send__
の方を使ってくれと言っています。Foo.send(:bar) quuz.send(:fred) # good Foo.__send__(:bar) quuz.public_send(:fred)Style/SingleLineBlockParams
シングルラインにおけるブロックパラメータの名前をあらかじめ決めておくもの。
設定された名前ではないパラメータ名になっていたら警告される。# bad foo.reduce { |c, d| c + d } foo.reduce { |_, _d| 1 } # good foo.reduce { |a, b| a + b } foo.reduce { |a, _b| a } foo.reduce { |a, (id, _)| a + id } foo.reduce { true } # good foo.reduce do |c, d| c + d endどんなケースで使うのかよくわからん。
Style/StringHashKeys
ハッシュのキーにはシンボルを使うのが推奨。
# bad { 'one' => 1, 'two' => 2, 'three' => 3 } # good { one: 1, two: 2, three: 3 }Style/StringMethods
Stringクラスに関して、一貫して同じ名前のメソッドを使うように強制するもの。
# bad 'name'.intern 'var'.unfavored_method # good 'name'.to_sym 'var'.preferred_method恥ずかしながら
intern
というメソッドの存在を初めて知りました。以上です。
ご査収ください。
- 投稿日:2019-11-12T23:07:57+09:00
Ruby勉強日誌3
クラス
class.rbclass ◯◯◯◯◯ attr_accessor :□□□, :△△△ endインスタンス
instance.rb変数 = クラス名.new 変数.属性 = ✖️✖︎ puts 変数.属性インスタンス変数:名前が@で始まる変数
initializeメソッド:インスタンス作成時の初期値を設定
initialize.rbclass BillRecord attr_accessor :name, :bill def initialize(name, bill) @name = name @bill = bill end end data = BillRecord.new("◯◯","✖︎✖︎")
- 投稿日:2019-11-12T20:41:51+09:00
Ruby技術者認定試験Silverを25日間で取得した話:準備編
Silverを取得したのが2019年7月31日、あれから3ヶ月以上経ってからこれを書いている。
すぐ書かなかった理由はGold取得に向けての勉強を優先したからであった。...という言い訳。3:)
この記事では、私がSilver試験に合格するために過ごした25日間の記録を残しています。
また、同じスタートラインや期間で資格習得を目指す人に向け、何か参考になれたら幸いです。書きたいことが多いので、以下3本でお送りします。
・準備編
・受験編
・その後編拙い文章ですが、よろしくおねがいします。
はじめに
本記事を読むにあたり以下に1つでも当て嵌まる方は是非とも読んでいただけたらと思います:)
「Rubyはおろか、プログラミング言語のプの字も知らないよ。」
「勉強の仕方が分からないし、お金をかけたくないんだけど〜」
「Silverの資格を取得して変化あった?」
そもそもそもRuby技術者認定試験ってなんゾ?
Ruby技術者認定試験制度
※Ruby Association公式サイトから引用Rubyベースのシステムを設計、開発、運用するエンジニア、Rubyでシステム提案を行うコンサルタント、Rubyを教える講師及びRubyを学ぶ学生などを対象とした認定試験制度です。認定者は、Ruby技術者としての技術力を公正に評価され、高い水準のRubyによるシステム開発能力を持つことを認定されます。
認定によりRubyベースでシステム開発を行ううえで必要な基礎的な知識と応用力をもつことをアピールすることができます。試験の合格者は、Rubyアソシエーションにより「 Ruby Association Certified Ruby Programmer Silver/Gold version 2.1」として認定されます。
Ruby Programmer Silver/version 2.1 -試験範囲-
概要 試験時間 :90 分 試験方法 :コンピュータ試験(CBT:Computer Based Testing) 問題数(方式):50 問(選択式) 合格ライン :75 % 対象バージョン :Ruby2.1.x 料金 :16,500円(税込)
出題範囲 コメント リテラル(数値、真偽値、文字列、文字、配列、ハッシュ等) 変数/定数とスコープ 演算子 条件分岐 ループ 例外処理 メソッド呼び出し ブロック メソッド定義 クラス定義 モジュール定義 多言語対応 組み込みライブラリ よく使用されるクラス、モジュール (Object、数値クラス、String、Array、Hash、Kernel、Enumerable、Comparable等) オブジェクト指向 ポリモルフィズム 継承 mix-in 受験の方法や試験開催地については、
試験を配信しているプロメトリック公式サイトで確認して下さい。Ruby技術者認定試験Silverを取得することになったきっかけ
WebエンジニアとしてRuby開発を行うことになったからである。
「RubyはおろかLinuxコマンドも知らない奴」=「何も知らない奴」が
這い上がっていくために、1ヶ月以内にSilver取得を目標にRubyの勉強を始めた。筆者について
当時はソフトウェア/アプリケーションのQAエンジニアだったが、紆余曲折あってWebエンジニアに転向する機会を得られた。
いずれ自分も開発にシフトするゾ!と思いながらテスト業務を続けてたら7年くらい経ってた。
情報系の学校を出たわけでもない勉強場所と費やした時間
◇場所
当時の筆者は自宅で勉強するのがあまり好きではなく、
もっぱらカフェか会社での学習が中心でした。この記事もスタバで書いてるゾ。
移動中はスマホで「Ruby試験」の記事を読んだり「YouTubeの学習動画」を見てました。
あと英語も必要だと言われたので「英語学習アプリ」とかで適当に英文を読んでました。出来るだけ勉強時間を設ける!というよりも「Rubyと触れ合う時間」を作るようにして、
生活の一部にしてしまうイメージでいた方が自分には合っていました。◇時間
前提として、最低でも1日にこの時間は学習に充てることを自分と約束しました。
・平日:4時間
・休日:6時間
※もちろんぶっ通しでってのは集中力が持たないので、1時間くらいやったら休憩入れてました。
※おおよそですが、Silver取得までにかかった時間は合計120〜150時間くらいです。言わずもがな、地頭の良い方/既にプログラミングを学んでいる方はより少ない時間で十分だと思います。
取り巻く環境(モチベーション)について
とてもラッキーなことに筆者には強力な協力者たちがいたので、
勉強を始める人は周りに知見者がいるかどうかがとても重要になってくると思います。
- 「24時間いつでも質問して良いよ」という人がいた(休日でも夜中でも対応、例題もたくさん作ってくれた)
- 一緒に勉強してくれる人がいた(各々Ruby以外の勉強もしていました)
学習に使用した書籍/サイト/動画について
◇書籍
●Ruby技術者認定試験合格教本 Silver/Gold対応 (Ruby公式資格教科書)
Ruby技術者認定試験を受ける人ならほぼ必ずこれを読むことになると思います。
何故なら、試験対策本として世の中にあるのはこの1冊だけだからです
Silverのワンランク上の資格であるGoldの対策本でもあります。試験対策本なので、Silver/Goldの試験範囲の内容と合わせて、
実際に出題される問題を想定した基礎・演習問題や模擬試験問題が掲載されているので、
この書籍を中心に勉強していくのが安定して試験対策になると思います。筆者はこの本を2~3回読んで、分からないとこがあれば一つずつ潰していくようにしていました。
◇個人的に思ったこと
◇オススメしたいところ
・試験範囲はしっかりカバーしているので、とりあえず読んで間違いない。
・対策問題の数が多いので、自分でアレンジした問題をgitにコピーして、オリジナル問題を作るなど色々使える。
・Gold試験にも使えたり、Rubyの基礎本としても読めるので持ち腐れになりにくい。◇気を付けて欲しいところ
・所々に誤植があるので、Rubyに慣れていても惑わされる可能性があります。
サポートページで誤植について掲載があるので、確認した方が良いです。
・教本の演習問題の答えを丸暗記しても、合格できませんので読むだけじゃダメです。
重要なのは問題の答えではなく「どういった処理が行われいるか」理解するように学習することです。
◇動画
●七海有里佳とRubyの基礎
【七海有里佳とRubyの基礎】Lesson1 Rubyについて https://t.co/BmQ9ZqAGWF @YouTubeさんから
— 森 雅之@Take it easy!ლ(╹◡╹ლ) (@nuu_mu) November 12, 2019今流行りのバーチャルユーチューバー(Vtuber)が、プログラミングを教えてくれるというものです。
動画はYoutubeや公式サイトにてもちろん無料で公開されています。
2019年11月現在は私が確認している限りだと、Rubyコース以外にも、Pythonコースがあります。◇どんな動画(コンセプト)?
Programastar.comとは
※Programastar公式サイトから引用「プログラマとして輝けるまでの道のりを提供する」をモットーとして掲げ、プログラミング習得を目指す初心者にとって、とことん分かり易くて挫折しにくい、完全無料の学習機会を提供することを目的に立ち上げたプログラミング教育サービスです。
女子中高生の美少女プログラマたちが、まったりほのぼのとプログラミングを教えてくれる、ユーザーが癒されながら学ぶことができる『日常系プログラミング学習サイト』として、プログラミング習得を目指す人にとって有益なサービスを目指していきます。七海有里佳は右から2番目の子でした。どうでもいいか?
◇個人的に思ったこと
◇オススメしたいところ
・初心者向け
・irbで実際にコードを動かしてくれるので、写経しながらやれば身に付きやすい
・代表的なところは押さえている(配列,eachなど)
・声は女性なので聴きやすい←◇気を付けて欲しいところ
・動画でやっていることは自分でもコードを写経して動かしてみること=これしないと覚えません。
勉強するときはしっかり集中すること、休む時は休むとメリハリをつけないと頭は疲れてしまいます。
・動画を見すぎて目や体に負担がかかる可能性がある。
姿勢悪い人は腰や肩にくる。
◇Qiita記事など
●当時読んだ記事の中でもとても役に立った記事
・Ruby Silver試験前に見直すと幸せになれるメモ
・Ruby技術者認定試験 Silver/Gold 対策の個人的なハマり問題集
・Ruby技術者認定試験 Silver version 2.1を受けて…「Ruby Silver試験前に見直すと幸せになれるメモ」は絶対に読んだ方が良いです。
◇学習に使用したものについて
◇勉強に使うものは少なくて良い
私の上司は「Ruby技術者認定試験合格教本」だけでSiverに合格したと言っていたので、
記事の閲覧や動画を視聴するのが難しくても、教本だけでも勉強できますし、合格も可能だと思います。(プログラミング完全未経験ではない場合なので、未経験者と比較するのは難しいところもありますが、、)
◇やって(使って)おけば良かったと思うもの(こと)
●Progate(プロゲート)
はい、お前使ってなかったんかい!!ってツッコミが来そうな気がしてならないProgateです。
当時から存在は知っていましたが、筆者は使用せずに勉強していました。今ではとても後悔しています。Progateの説明はほぼ不要だと思いますが、エンジニアを対象にしたオンライン学習サービスです。
Web版/スマホ版がリリースされていますが、両者で受講できるコースや解答方法が異なるので注意して下さい。
一部のコースは無料ですが、有料会員でないと受講できないものもあります。初心者であればあるほどさっさと有料会員になって「Rubyコース」を全部やることをオススメします。
1ヶ月1000円くらいなので、1ヶ月以内に全部やれば良いだけの話ですし。
ある種ゲーム感覚で学べるように作られているので、テンポ良く進められると思います。また、HTML/CSS/Git/Linuxなど開発を行う上では避けて通れないものも学ぶことができます。
Ruby on Rails(フレームワーク)コースもあり、今になって筆者は有料会員で学習中ですが、
実務でも役に立つ内容もあると感じています。実際にコードを書くスタイルなので、リファクタの練習にもなります。
筆者はよくendを忘れて怒られます。。●ひたすらコードを書く(写経する)
あなたは自分で書いたコードの動きを人に説明できますか?
出来なかったり、理解に詰まってしまう場合は「分からない部分」について調べて実際にコードを書いてください。
Silver試験においては、ほぼほぼ暗記だけでいけるという記事が結構ありますが、それはほぼ間違い無いです。しかし、「問題の形式」が変わると「暗記や形」で覚えているので応用ができず、対応できなくなってしまいます。
腐っても試験なのでどこに罠が仕掛けられているか分からないのです。Q1.eachメソッドはどんな処理ができますか
Q2.実際にeachを用いてコードを書いてください
Q3.Q2で書いたものを「do end」 を使用しないで書いてください
Q4.ブロックを「{」と「}」で囲うか「do」と「end」で囲うかとで違いはありますかeachメソッドで一例を考えてみましたが、こんな感じでしょうか。
上記のようなことを聞かれても答えられるまで勉強しましょう。●問題集をやる場合は、出来るだけ解答選択肢を見ないで答えてみる
基本的に4択から正解を選ぶ例題が多いと思いますが、
ある程度コード読めるようになったら筆者は解答欄を見ずに解答することをオススメします。これは「問題を形で覚える」ことを防止することができ、
しっかりコードを読んで動きを理解することを意識させるためです。
実際の試験で出るものに似た問題もありますが、うまい具合(言い方を変えると意地悪)に内容が変わっているので、
コードを読むクセをつけて、実際の動きを考られるようになれば、本番で正答できる確率はグっと上がるはずです。準備編のまとめと感想..
色々ぐちゃぐちゃに散らかった記事になってしまった気がする。
ある程度書くことは事前にまとめていましたが、書き始めるとあれもこれもで記載量が増えちゃいました。
自分で当時のことを今回初めて振り返っていますが、中々に濃い25日間だったようです◇次回:受験編
次はいよいよ受験当日〜合格について書こうと思います。
完成までしばらくお待ちください。オサキデス。
- 投稿日:2019-11-12T18:08:01+09:00
sort_byを使用してみて
meibo2.rbpersonal_data = [ ['john','m','18'], ['paul','m','20'], ['alice','f','15'], ['dabid','m','17'], ['jasmin','f','17'] ]この配列が存在した時に最後のカラムである年齢順に並べたい時
sort_by.rbpersonal_data.sort_by!{|personal| personal[2].to_i }と文字列を数字の列に変換してsort_byメソッドを使用することで数字が小さい順に並び替えが起こります。
sort_by!の最後の!は、破壊的なメソッドで前後の処理に影響するので注意を払って書いた。
自分が躓いてしまった点は.sort_by {|k, v| v }のようにkeyとvalueが存在し整数などの数字を順番に並べたいので
to_iメソッドを使用しなければいけないことにきずいた。
メソッドにおいて基本的な形を意識して文字列、整数を使う意識を実感できた。
- 投稿日:2019-11-12T15:32:29+09:00
Rails データ内容の制限
データの内容を制限する
NOT NULL制約
すでに作成してあるhogeテーブルのnameカラムにNOT NULL制約をつける場合。
ターミナル$ rails g migration ChangeHogesNameNotNull Running via Spring preloader in process 6959 invoke active_record create db/migrate/xxxxxxxxxxx_change_hoges_name_not_null.rbマイグレーションファイルが生成されたらそのファイルの中身を編集する。
db/migrate/xxxxxxxxxxx_change_hoges_name_not_null.rbclass ChangeHogesNameNotNull < ActiveRecord::Migration[5.2] def change change_column_null :hoges, :name, false end end編集したら、マイグレーションファイルをデータベースに適用する。
ターミナル$ rails db:migrateこれで、データベースにおいて、hogesテーブルのnameカラムにNULLを入れることができなくなった。
しかし、今の状態だと、""のような空文字を保存できてしまう。この対応の仕方は、hoge.rbの方でバリデーションを記述すれば良い。記述方法は割愛。NOT NULL制約を加えることでどうなるかRailsコンソールで確認する
ターミナル$ rails c Running via Spring preloader in process 7167 Loading development environment (Rails 5.2.3) >> Hoge.new(name: nil).save (0.3ms) BEGIN Hoge Create (27.2ms) INSERT INTO "hoges" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2019-11-12 05:35:19.735447"], ["updated_at", "2019-11-12 05:35:19.735447"]] (0.2ms) ROLLBACK Traceback (most recent call last): 1: from (irb):1 ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR: null value in column "name" violates not-null constraint) DETAIL: Failing row contains (7, null, null, 2019-11-12 05:35:19.735447, 2019-11-12 05:35:19.735447). : INSERT INTO "hoges" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" >>ActiveRecord::NotNullViolationという例外が発生し、登録に失敗していることがわかる。
- 投稿日:2019-11-12T15:01:13+09:00
Ruby 文法の学習メモ・チートシート(自分用)
Ruby 2.6.5
完全に自分用なのであしからず。多分何かしら間違っています。if
if value==2 # 略 elsif value%2==0 # else ifではない # 略 else # 略 endtimes, while
5.times do|i| puts "#{i}回目のループ" # => 0,1,2,3,4回目のループ end n=0 while n<10 do puts n n += 1 # インクリメント(++)は使えない endeach, each_with_index
["a","b","c"].each do |s| puts s end ["a","b","c"].each_with_index do |s, i| puts "#{i}個目の要素は#{s}" # => 0個目の要素はa ... endbegin, rescue
begin i = gets.to_i #標準入力を数字に変換 puts 100/i rescue => e puts e #エラーメッセージを出力 retry #beginに飛ばす endraiseもある。
クラス
class Card attr_accessor :hp, :ap, :dp #アクセサ def initialize(hp, ap, dp) @hp = hp #体力 @ap = ap #攻撃力 @dp = dp #防御力 end def attack(enemy) if self.ap > enemy.dp # もし自分の攻撃力が敵の防御力より大きかったら、敵の体力をその差分だけ減らす enemy.hp -= ( self.ap - enemy.dp ) end end end class SpecialCard < Card # 継承 def hoge #略 end end a = Card.new(15,10,8) b = Card.new(15,10,8) a.attack(b) puts b.hp #13文字列かのどうかの判定
if "文字列".kind_of?(String) #Stringクラスのインスタンスか調べる #略 end
以上。こんな記事を最後までお読みいただきありがとうございます。
また学んだことがあれば更新します。
- 投稿日:2019-11-12T14:50:36+09:00
【Ruby】7桁の整数で保存した郵便番号にハイフン(-)を入れる方法
1234567
のように、DBに7桁の整数で郵便番号を保存。
一方、ビューでは123-4567
のようにハイフンを入れて表示したい場合。以下のように記述すればOKです。
1234567.to_s.insert(3, "-")
to_s
で整数を文字列に変換。
insert(3, "-")
で3文字目の後にハイフンを挿入しています。参考になった記事
https://qiita.com/_kkoichi/items/f8758a438b2363943922
- 投稿日:2019-11-12T13:36:19+09:00
Ruby 配列、範囲オブジェクトについて
配列での範囲オブジェクトの使い方についてさらっと解説します。
配列zに対して1.2.3.4.5の要素を入れたい場合z = [1,2,3,4,5] puts z 1 2 3 4 5とすると思います。
しかし、範囲オブジェクトを使えばz = (1..5)to_a puts z 1 2 3 4 5わざわざ全ての数字を記入しなくても範囲を指定してあげるだけで済みます。
- 投稿日:2019-11-12T13:16:54+09:00
Rails ビューファイルのHTMLにRubyのコードを書く時の<% %>と<%= %>の違い
目的
- あんまりわかっていないビューファイル(HTML)内にRubyのコードを書く時の<% %>と<%= %>の違いをまとめる
簡単に言うと?
- ビューファイルが司るWebページ(以降、Webページと記載する)内に表示したいものは<%= %>の中に記載する。
- Webページに表示したくないものは<% %>の中に記載する。
ちょっとだけ詳しく言うと?
- <%= %>は中に書かれた内容を実行し、結果を評価し、文字として出する。
- <% %>は中に書かれた内容を実行する。
使い分けは?
- あまり難しい事は考えず、ビューファイルに記載するRubyのメソッドやコードの結果をそのWebページに表示したいのか、表示したくないのかで判断する。
- 例えば、とあるテーブル情報を
モデル名.all
で取得し、each文で取得内容を全て出力したいときの変数名A.each do |変数名B|
の処理はWebページに出力する必要はないので<% %>で囲む。- 前述の処理で変数Bに入った内容をWebページに出力したいときは<%= %>で囲む。
書き方の例
- 変数Aにはとあるデータベースのとあるデータが格納されているものとする。
- 変数Bの内容をWebページに出力したい。
each文を使用した書き方の例を下記に記載する。
<!-- 下記の処理は出力したくないので<% %>で囲む --> <% each.変数A do |変数B| %> <!-- 変数Bを出力したいので<%= %>で囲む --> <%= 変数B %> <!-- each文の終了を意味するendも出力したくないので<% %>で囲む --> <% end %>より具体的な例
- usersにはuserテーブルのすべてのデータが格納されているものとする。(
users = User.all
を実行した状態)- userの内容をWebページに出力したい。
each文を使用した書き方の例を下記に記載する。
<!-- 下記の処理は出力したくないので<% %>で囲む --> <% each.users do |user| %> <!-- userを出力したいので<%= %>で囲む --> <%= user %> <!-- each文の終了を意味するendも出力したくないので<% %>で囲む --> <% end %>
- 投稿日:2019-11-12T12:45:32+09:00
RailsでEC系に良く出てくるカート機能を解説 / 実装してみた
参考にした記事
おそらくこの記事を読みに来てくださる読者の方は上記の記事も読んでる可能性が高いのでモデルの設計は似せようと思います。
STEP.1 モデル設計
rails g model product name price:integer rails g model cart rails g model cart_item quantity:integer product:references cart:referencesここらへんは記事と全く一緒です。
因みに補足としてマイグレーション部分のコードをあげとくと以下のようになると思います。
CartItemのデフォルト値のところは後から追記してます。マイグレーションの内容
class CreateProducts < ActiveRecord::Migration[6.0] def change create_table :products do |t| t.string :name t.integer :price t.timestamps end end end class CreateCarts < ActiveRecord::Migration[6.0] def change create_table :carts do |t| t.timestamps end end end class CreateCartItems < ActiveRecord::Migration[6.0] def change create_table :cart_items do |t| t.integer :quantity, default: 0 t.references :product, null: false, foreign_key: true t.references :cart, null: false, foreign_key: true t.timestamps end end end上記の内容でマイグレートを通した後であればコンソールで軽く遊んでみたりしてデフォルト値が設定されているかとか確認しておくと良いかもですね。
(因みに補足ですがCartItemの外部キーは存在しないものを指定するとrollbackするので先にCartとProductを作らないとハマります)
アソシエーションの内容
class Product < ApplicationRecord end class Cart < ApplicationRecord has_many :cart_items end class CartItem < ApplicationRecord belongs_to :product belongs_to :cart end※参考記事と一緒
因みに、もしここのアソシエーションを指定している意味が曖昧な人のために↓
このアソシエーションを追加することで以下のように親のモデルから関連する子のモデルが抽出出来たりするってことですね。
Cart.fitst.cart_items
な感じで詳しくは本家の Active Record の関連付け を
STEP.2 コントローラー設計
次にコントローラーですが無駄なコードは極力無くしてます。
例えばこの記事では一旦、View側まで書かないのでhelper_method
などは記述してません。
必要に応じて設定して頂ければと思います。# app/controllers/application_controller.rb class ApplicationController < ActionController::Base def current_cart Cart.find(session[:cart_id]) rescue ActiveRecord::RecordNotFound cart = Cart.create session[:cart_id] = cart.id cart end end個人的に
find
を使う場合はできるだけ例外処理で丁寧に扱うことを意識しています。class CartsController < ApplicationController before_action :setup_cart_item!, only: [:add_item, :update_item, :delete_item] def show @cart_items = current_cart.cart_items end def add_item if @cart_item.blank? @cart_item = current_cart.cart_items.build(product_id: params[:product_id]) end @cart_item.quantity += params[:quantity].to_i @cart_item.save redirect_to '' end def update_item @cart_item.update(quantity: params[:quantity].to_i) redirect_to '' end def delete_item @cart_item.destroy redirect_to '' end private def setup_cart_item! @cart_item = current_cart.cart_items.find_by(product_id: params[:product_id]) end end
setup_cart_item!
部分でインスタンス変数を使ってますがViewで引っ張ってくる予定がないのであれば普通の変数にリファクタリングして良いと思います。またリダイレクト部分はよしなに変更していけば良いかなと
STEP.3 ルーティング設定
参考記事通り以下の部分を追加すればカート周りは大丈夫そうですね。
resource :carts, only: [:show] post '/add_item' => 'carts#add_item' post '/update_item' => 'carts#update_item' delete '/delete_item' => 'carts#delete_item'
- 投稿日:2019-11-12T12:22:46+09:00
Ruby Dateクラスの使い方2
- 投稿日:2019-11-12T11:43:15+09:00
Railsのparamsはキーのstringとsymbolの違いを隠蔽してくれる
私が今日知ったプチ衝撃の事実!
Railsの
params
では、Hashの機能が拡張されているためキーの型に関係なく値を取ってくることができる!!
つまり…h = { :last_name => "山下", "first_name" => "智久" } #キーに指定した要素の型で値を取ってくることができる h[:last_name] #=> "山下" h["first_name"] #=> "智久" #指定した要素とは違う型で値を取ってくることはできない h["last_name"] #=> nil h[:first_name] #=> nilstringとsymbolが間違っていると取ってくることができない。
#(railsの場合) #railsで受け取ったparams params => <ActionController::Parameters {"last_name"=>"山下", "first_name"=>"智久"}> #paramsの見た目はHashだが、ActionController::Parametersのインスタンス params.class => ActionController::Parameters #キーの型に関係なく値を取ってくることができる! params["last_name"] #=> "山下" params["first_name"] #=> "智久" params[:last_name] #=> "山下" params[:first_name] #=> "智久"railsを書いている限りは、コントローラでparamsを受け取って処理をするときなどキーの型を気にしなくてもよしなにやってくれる。怖い…
ちなみに
string => symbolに変換してくれるmethodは
to_sym
god = "tomohisa" p god.to_sym => :tomohisaparamsの中身を眺めていたときに、なんでこれまでsymbolとstringテキトーにやってきたのに値がとれてたんだ?と思って知ったことでした。
- 投稿日:2019-11-12T11:34:43+09:00
bundle execとは
rails s bundle exec
のbundle exec
、聞いたことあるけど特に書かなくても問題なく動いてきたのでずっと「なんかgemをいい感じにしてくれるもの」くらいの認識でいました。
多分、そろそろきちんと知っておいた方がいいので調べてみた。要するに、gemをいい感じにしてくれるものでした。
…それでは何もアップデートがないので、もう少し踏み込んでまとめると、
gem A
とgem B
があるとする。
プロジェクトA
ではA,B両方使っていて依存関係があり、プロジェクトB
ではAだけ使っている場合、gemB
にアップデートがあるなんてことがあるとプロジェクトB
では勝手にアップデートしてくれという感じだがプロジェクトA
ではgem A
に影響が出てしまうのでそれは困る。
ここら辺を、プロジェクトごとに臨機応変にバージョン管理してくれるのがbundlerの役割らしい。便利やん!!
今作っているようなプロダクトだとほとんどgemを使っていないので特に問題ないが、gemがいっぱいあるときには必須なのだと思いました。
- 投稿日:2019-11-12T11:02:09+09:00
Ruby initializeメソッド
initializeメソッドを使う
initializeメソッドは、他のインスタンスメソッドと同じように定義することができる。
[例1]
hoge.rbclass Hoge # 〜###〜 def initialize puts "インスタンスが生成されました" end # 〜###〜 end hoge1 = Hoge.newHoge.newが実行されると自動でinitializeメソッドが呼び出されます。
- 結果
インスタンスが生成されましたinitializeメソッドでインスタンス変数を使う
fuga.rbClass Fuga # ・・・・ def initialize # インスタンス生成直後に "piyo"をインスタンス変数nameに代入している self.name = piyo end # ・・・ end fuga1 = Fuga.new puts menu1.nameインスタンスメソッド内では、
self.変数名
でインスタンス変数を使うことができる。
よって、self.変数名 = 値
でインスタンス変数に値を代入することができる。
- 結果
piyo以上 initializeメソッドの簡単にしてみました。
- 投稿日:2019-11-12T09:32:39+09:00
Ruby Seleniumで小児科の予約を自動化(の一歩手前まで)
自己紹介
当方、プログラミングはほぼ初心者です。
おかしなところなどありましたら、お教えいただけますとありがたいです。きっかけ
うちの子供が通っている小児科は、webの予約システムを導入しています。
ただ、こちらの小児科は予約が超激戦で…。
毎回手で操作して予約を取っては、予約番号に一喜一憂するのに限界を感じたため
自動化することにしました。
ドクターキューブという予約システムの、自動化プログラムです。最後の画面は自動化していません。
また、今後は予約開始時間になったら自動的に動くようにしたいと思っていますが
そこまで至っていません。環境
Windows10
Ruby 2.5.5
Selenium-webdriver 3.142.6
Firefox 70.0.1準備
gemをインストール
gem install selenium-webdriver実行
ID/PASSを同じプログラムで保存しているのは危ないと思いつつ
家庭内で回すだけのものなので、簡便に作りました。yoyaku.rbdriver = Selenium::WebDriver.for :firefox #firefox起動 driver.manage.timeouts.implicit_wait = 60 # driver全体に、wait処理をする(最大60秒) #URL/ID/PASS url = 'https://ssc●.doctorqube.com/●●●/' id = '●●●' pass = '●●●' #サイトにアクセス driver.navigate.to(url) #「予約をとる」をクリック driver.find_element(:xpath, '//*[@id="yoyakuset"]').click #当院での受診ははじめてですか?「いいえ」をクリック driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/div[2]').click #ID/PASSを入力 driver.find_element(:xpath, '//*[@id="c_code"]').send_key(id) driver.find_element(:xpath, '//*[@id="c_pass"]').send_key(pass) driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/form/input[5]').click #Emailアドレスを確認(アドレス欄がブランクになる場合は、send_keyでアドレスを送る) driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[3]/form/input[5]').click #当日の診療予約 driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/ul/div[1]').click #予約(ここは手で操作。2つめのリンクなら末尾がdiv[2]、3つめならdiv[3]) #driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/ul/div[1]').click #ブラウザを終了する(↑を自動化するまでは使わない) #driver.quit参考にした記事
・Seleniumコマンドチートシート【Ruby】
https://qiita.com/wMETAw/items/8ea0ff9c7a63ca6134b9・RubyでSeleniumを使ってスクレイピング
https://qiita.com/tomerun/items/9cb81d7a98150ff22f53
- 投稿日:2019-11-12T09:32:39+09:00
Ruby Seleniumで病院の予約を自動化(の一歩手前まで)
自己紹介
当方、プログラミングはほぼ初心者です。
おかしなところなどありましたら、お教えいただけますとありがたいです。きっかけ
うちの子供が通っている小児科は、webの予約システムを導入しています。
ただ、こちらの小児科は予約が超激戦で…。
毎回手で操作して予約を取っては、予約番号に一喜一憂するのに限界を感じたため
自動化することにしました。
ドクターキューブという予約システムの、(ほぼ)自動化プログラムです。メールアドレスの認証が済んでいる前提です。
最後の画面は自動化していません。
今後は、予約開始時間になったら自動的に動くようにしたいと思っていますが
そこまで至っていません。環境
Windows10
Ruby 2.5.5
Selenium-webdriver 3.142.6
Firefox 70.0.1準備
gemをインストール
gem install selenium-webdriver実行
ID/PASSを同じプログラムで保存しているのは危ないと思いつつ
家庭内で回すだけのものなので、簡便に作りました。yoyaku.rbdriver = Selenium::WebDriver.for :firefox #firefox起動 driver.manage.timeouts.implicit_wait = 60 # driver全体に、wait処理をする(最大60秒) #URL/ID/PASS url = 'https://ssc●.doctorqube.com/●●●/' id = '●●●' pass = '●●●' #サイトにアクセス driver.navigate.to(url) #「予約をとる」をクリック driver.find_element(:xpath, '//*[@id="yoyakuset"]').click #当院での受診ははじめてですか?「いいえ」をクリック driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/div[2]').click #ID/PASSを入力 driver.find_element(:xpath, '//*[@id="c_code"]').send_key(id) driver.find_element(:xpath, '//*[@id="c_pass"]').send_key(pass) driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/form/input[5]').click #Emailアドレスを確認(アドレス欄がブランクになる場合は、send_keyでアドレスを送る) driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[3]/form/input[5]').click #当日の診療予約 driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/ul/div[1]').click #予約(ここは手で操作。2つめのリンクなら末尾がdiv[2]、3つめならdiv[3]) #driver.find_element(:xpath, '//*[@id="yoyaku"]/div/div[2]/ul/div[1]').click #ブラウザを終了する(↑を自動化するまでは使わない) #driver.quit参考にした記事
・Seleniumコマンドチートシート【Ruby】
https://qiita.com/wMETAw/items/8ea0ff9c7a63ca6134b9・RubyでSeleniumを使ってスクレイピング
https://qiita.com/tomerun/items/9cb81d7a98150ff22f53
- 投稿日:2019-11-12T08:50:25+09:00
bundle installする際のtzinfo-dataのwarningがウザい
問題のエラーメッセージ
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, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
bundle install
実行時に毎回上記warningが出ていたのだが、面倒なので後回しにしていた。
そろそろ重い腰を上げて調査・対処してみる。実行環境
macOS Mojave 10.14.6
Ruby 2.6.1
Rails 6.0.1
Bundler 2.0.2問題の原因
Railsアプリを作成した時にGemfileに書かれる下記行がwarningの原因。
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]tzinfo-dataはTZInfoが参照するタイムゾーン情報を提供するgem。
TZInfoはRubyからタイムゾーン情報を参照し、その情報に基づいて時間をコンバートするためのライブラリ。解決方法
この問題についてググってみると、githubのtzinfo-dataの作者のコメントに解決方法が書いてあった。
解決方法は4つあって下記のいずれかを実行すれば良い。
Gemfileのtzinfo-data行の
platforms: [:mingw, :mswin, :x64_mingw, :jruby]
を削除し、bundle update
を実行。プラットフォーム関係なくtzinfo-dataのタイムゾーンを参照する設定。Gemfileからtzinfo-data行を削除。tzinfo-dataではなくシステムのタイムゾーンを参照するようになる。Windowsの場合は、tzinfo-dataを削除すると、
TZInfo::DataSourceNotFound
例外が発生してしまう。
bundle lock --add-platform mingw, mswin, x64_mingw, jruby
を実行。Gemfile.lockに依存プラットフォーム情報を記述してしまう方法。
bundle config --local disable_platform_warnings true
を実行(Bundlerのバージョンが1.17.0以上であることが必須)。Bundler自体のwarningを出させないようにする設定。4はカレントディレクトリのRailsアプリにだけ適用する方法で、システムのカレントユーザに対して非表示にしたければ、下記のように
--local
を省いて実行すればOK!bundle config disable_platform_warnings trueGemfileにtzinfo-dataを指定している理由
解決方法と同じく、githubのtzinfo-dataの作者のコメントに書いてある。
The purpose of this line is to include the tzinfo-data gem in the bundle on Windows to act as a source of time zone data. This gem is unnecessary on Ubuntu (and Unix-based systems in general) because the system includes time zone data that can be read directly by tzinfo.
コメントによると、Windowsでタイムゾーン情報を取得することを目的として、tzinfo-dataを入れているらしい。Windowsでtzinfo-dataを削除すると例外が発生するのは、tzinfo-dataがないとタイムゾーン情報が取得できないからのようだ。
そもそもUnixベースのOSではtzinfoからシステムのタイムゾーン情報に直接アクセスできるので、このgemを入れる必要はないそう。
- 投稿日:2019-11-12T08:23:34+09:00
Rails 検索機能の付け方
まえがき
今回の、モデルに新しいメソッドを定義し、7つのアクション以外のものを使うというのはどうやら非推奨みたいです。ただし、こちらの方が私的には簡単に作ることができましたので共有させていただきます。
慣れない点がありますので間違い等がありましたらご指摘いただけると嬉しいです。目次
・検索フォームの作成
・searchアクションのルーティング設定
・searchメソッドをモデルに定義
・searchアクションをコントローラーに定義
・検索結果画面のビューファイルを作成検索フォームの作成
まずは検索フォームを付けていきます。今回はform_withを使って書きます。書き方は以下の通りです。
search.html.erb<%= form_with(url: search_sample_path, local: true, method: :get, class: "search-form") do |form| %> <%= form.text_field :keyword, placeholder: "投稿を検索する", class: "search-input" %> <%= form.submit "検索", class: "search-btn" %> <% end %>一つずつ説明していきます。まずurlと指定してある部分はこの後設定する、searchのルーティングで設定されるplefixを書きます。
plefixをパスとして書く時は文字の最後に_pathをつけるような書き方をします。
plefixはターミナル上でrails routesというコマンドを入力したときに一番ひだりに書いてあるものです。次にlocal:trueですが、form_withでは何を指定しなくてもremote: trueになるようなのですが、
remote: trueではXMLHTTPRequestオブジェクトリクエストを自動で送信するので、無効化する為にlocal: trueを指定してあげます。remote:trueだと、非同期通信が発動してしまい、画面が遷移しないようです。
ちなみにXMLHTTPRequestオブジェクトとはXMLHttpRequest (XHR) は、JavaScriptなどのウェブブラウザ搭載のスクリプト言語でサーバとのHTTP通信を行うための、組み込みオブジェクト(API)である。
ということらしいです。簡単にいうと、非同期なデータ通信をするためのAPIです。
今後Ajaxを使う予定がある人は覚えておいても損はないかもしれません。
ちなみにAjaxは(Asynchronous JavaScript + XML)の略です。
method: getは、フォーム送信時のHTTPメソッド(verb)を指定します。
通常は:getや:postを指定するようです。searchアクションのルーティング設定
routes.rbRails.application.routes.draw do devise_for :users root to: 'samples#index' resources :samples do resources :comments, only: :create collection do get 'search' end end resources :users, only: :show end今回はコメント機能の検索をかけるので、samplesコントローラーとcommentsコントローラーがネスト構造になっていることに注意してください。
collection doとはidを付けない書き方です。
今回は検索をするときに詳細の情報は必要ないのでid情報は付けません、もしid情報を付けたい時はmember doというものがあるのでそちらを使いましょう。searchメソッドをモデルに定義
先ほどルーティングにsearchを設定したので今度はモデルにメソッドを定義していきます。現時点だと、.searchというメソッドは使うことができませんが、モデルで設定することにより、コントローラーで使用することができるようになります。
sample.rbdef self.search(search) return Sample.all unless search Sample.where('title LIKE(?)', "%#{search}%") end今回はtitleで検索をかけていきます。
モデルの中でメソッドを定義する際に、メソッド名の頭にself.を付けるとコントローラーで使えるクラスメソッドという物になります。上記でLIKE句とwhereメソッドが出てきました
簡単に説明するとLIKE句とは、曖昧検索と言われる物に使われるもので、前方一致や後方一致などを指定するときに使います。
whereメソッドとは、モデル.where(条件)のように引数部分に条件を指定することで、テーブル内の条件に一致したレコードのインスタンスを配列の形で取得できます。そして今回は条件式に前述したLIKE句を使っています。
ちなみに上記の記述方法をif文を使い、よりわかりやすく書くと下記のようになります。sample.rbdef self.search(search) if search Sample.where('title LIKE(?)', "%#{search}%") else Sample.all end endSampleテーブルから曖昧検索をかけて絞るのか、全てを出すのかという簡単な式を作ることができます。
searchアクションをコントローラーに定義
次はコントローラーにアクションを設定し先ほど定義したsearchメソッド使っていきます。
sample_controller.rbdef search @sample = Sample.search(params[:keyword]) end
params[:keyword]
と書くことで、formで入力した、:keywordを取得することができます。
もしparamsのなかに何が入っているかを確認したい時はsample_controllerdef search binding.pry #このように記述する @sample = Sample.search(params[:keyword]) endこのようにbinding.pryを起動させ、一度ターミナルでparamsと打って、paramsのなかを確認してみると良いでしょう。
今回はparams[:keyword]にはフォームで入力した文字が入るようになっています。search.html.erb# 検索結果画面のビューファイルを作成 <%= form_with(url: search_samples_path, local: true, method: :get, class: "search-form") do |form| %> <%= form.text_field :keyword, placeholder: "投稿を検索する", class: "search-input" %> <%= form.submit "検索", class: "search-btn" %> <% end %> <div class="contents row"> #renderを繰り返し出力する <% @sample.each do |sample| %> <%= render partial: "sample", locals: { sample: sample } %> <% end %> </div>このビューファイルではrenderを用いて、効率よく投稿ができるような記述をしています。
ビューファイルで使うrenderは部分テンプレートのことで、
<%= render partial: "sample", locals: { sample: sample } %>
と記述をすることで、_sample.html.erbというファイルを読み込むことができます。
locals: { sample: sample }
はsampleというeach文で定義した変数を部分テンプレートでなんという変数で扱うかという意味です。右側が、each文で定義した変数で、左側のsampleが部分テンプレート先で扱う変数です。あとがき
あとは、部分テンプレート先で検索結果をどのように表示したいかを記述すれば終了です。
はじめにも書きましたが、7つのアクション以外のものを使って検索機能を作るということは本来推奨されていない方法なので、7つのアクションのみで実装する方法も調べてみてください。
この先インクリメンタルサーチを実装したりするかどうかはまた少し工夫が必要になってきますが、ベースは今回記述した検索機能になります。
この記事が検索機能実装でつまずいてしまった人の助けになれれば幸いです。
ではでは!!
- 投稿日:2019-11-12T03:21:41+09:00
0からプログラミングの勉強を始めて100日。どんな変化があったか振り返りをしてみた。
2019年8月にプログラミングを勉強しようと決めて始めてから、今日でちょうど100日目。
完全に何も知らない0の未経験な状態から、プログラミングの勉強を続けてきて、何ができるようになったのか、よかったことや改善点をまとめた。わたしの前提
- IT企業にてフルタイムで働いているビジネス職(カスタマーサクセス)
- プログラミングは完全に未経験
- やったことあるのは、Paizaとドットインストールくらい。どちらも途中で挫折している。
- 自分が欲しいサービスを作りたいと思って、2019年8月からプログラミングスクールに通い出す。
こんな人に読んでほしい
- これからプログラミングの勉強を0から始めるひと
- 同じように0からプログラミングの勉強を初めてがんばっているひと
- 20代後半でプログラミングを勉強し始めると、どんな変化があるのか知りたいひと
100日間で学んだこと
- HTML/CSS
- Ruby
- Ruby on Rails
- Jaba Script
- Git,GitHub
- SQL
主に100日間で学んだことは下記の通り。
全て同じ量をやっているわけではなく、HTML/CSS、Ruby、Railsをやっている割合がほとんどだった。100日間でできるようになったこと
- ターミナルがつかえるようになった!
- テキストエディタが使えるようになった!
- めっちゃ簡単なHTML/CSSの実装ができるようになった!
- めっちゃ単純なRubyのプログラムを書けるようになった!
- Railsのエラーが出たら何が原因か仮説を立てられて50%くらいはあってる!
- GitHubでマージとかプルリクとかできるようになった!
はじめたての頃は、
- ターミナルとテキストエディタって何が違うんだ・・・そもそもどっちにコード書くの?
- テキストエディタにどうやってファイル開くの?
- コマンド多すぎ…メソッド多すぎ…カタカナ多すぎ無理…
という状態だったので、著しい成長を遂げた(笑)
ただ、未だにわからないことばかりなので、
もっと勉強してできることを増やしていきたい。よかったこと
100日間勉強を続けてこれは良かったなと思うことが3つあるのでシェア。
1.周りに宣言&毎日output
プログラミングの勉強を始めると決めた際に、自社のエンジニア全員が入ってるslackチャンネルに入り、「今日から毎日勉強します。見ててください!」と勝手に宣言をした。
私は自分に甘いので、誰かに宣言することで継続できると思ったからだ。
そこから毎日、勉強したことをエンジニアのアウトプットチャンネルで投稿し続けた。誰かに見られているという緊張感で継続できたし、どんなレベルの低いことでもoutputすると学びの整理になったのでよかった。
初めて書いたQiitaはタイミングよくトレンド入りしてくれた。
【Ruby】今日のプログラミング学習時間を入力すると、学習進捗を教えてくれるプログラム - Qiita2.パラシュート学習法「まずやってみる」
私の通っているプログラミング教室が提唱しているパラシュート学習法。
パラシュート勉強法のやり方教科書の1ページ目からこつこつとやるのではなく、作りたいもの(ピンポイント)に的を絞ってやりたいことから学習していく方法。まずやりたいことからやってみて、詳細は後から学んでいくというやりかただ。
具体的にいうと、HTMLやCSSの大枠をざっと学んだあと、やりたいビューを実装していると、自然とBEMやリファクタリングの概念がわかってきたのがよかった。
多分BEMやリファクタリングをコツコツ学んでても理解にかなり時間がかかったと思う。プログラミングにおいても「まずやってみる」という大事さがわかった。
3.一緒に勉強する仲間をつくる
一緒にプログラミングをする仲間ができたのは、プログラミング教室に通ってよかったことのひとつだ。
辛い時も、モチベーションが下がってる時も、仲のいい同期が頑張っているといい焦りになった。たまたま一番仲良くなった女の子が、アウトプットをめちゃくちゃがんばる子なので私もそれに触発されている。一人じゃ頑張れないので一緒に頑張る仲間がいると心強い。
改善したいこと
いいことばかりじゃなくて、反省点もいっぱいある。
1.わからないことを調べず進めた。
パラシュート学習法を意識して、どんどん次に進めようとするあまり、ひとつひとつをしっかり理解していないまま次の学習に移っていた。
例えばRubyのクラスとインスタンスや引数に関して、しっかり理解しないまま進めていたので、今絶賛つまづき中。基礎ができていないのに応用はできないので、今必死にProgateで基礎をやり直している最中だ。
もし100日前に戻れるならちゃんと基礎をやれ!と言いたい。2.時間の確保
フルタイムで働いているのでなかなか平日の学習時間の確保が難しかった。100時間/月の学習目標に対してだいたい80〜90時間/月しか勉強ができなかった。
朝から起きてやればいいんだけど、それもなかなか続かず。。
朝から早起きして一緒にプログラミングの勉強をしてくれる人を募集しています。3.自分で何のサービスも作れなかった。
自分の欲しいサービスを作りたい!と言って始めたわりには、なにもアウトプットするものを作れなかった。
自分の欲しいものから作るともっとプログラミングの勉強が楽しくだろうとわかっているのに…!プログラミングの学習時間を計測する簡単なWebアプリくらいは年内に作りたいとおもう。
総括
プログラミング向いていないなと思うこともあるが、前に比べるとできることが多くなっているのが嬉しい。私でもちょっとはコードが書けるようになったので、ホリエモンがいう通り「プログラミングは簡単、だれでもできるもの」なのかもしれない。
ねむいのでここまで!引き続きがんばる!
- 投稿日:2019-11-12T03:21:41+09:00
0からプログラミングの勉強を始めて100日が経ったので、できるようになったこと/よかったこと/改善点。
2019年8月にプログラミングを勉強しようと決めて始めてから、今日でちょうど100日目。
完全に何も知らない0の未経験な状態から、プログラミングの勉強を続けてきて、何ができるようになったのか、よかったことや改善点をまとめた。わたしの前提
- IT企業にてフルタイムで働いているビジネス職(カスタマーサクセス)
- プログラミングは完全に未経験
- やったことあるのは、Paizaとドットインストールくらい。どちらも途中で挫折している。
- 自分が欲しいサービスを作りたいと思って、2019年8月からプログラミングスクールに通い出す。
こんな人に読んでほしい
- これからプログラミングの勉強を0から始めるひと
- 同じように0からプログラミングの勉強を初めてがんばっているひと
- 20代後半でプログラミングを勉強し始めると、どんな変化があるのか知りたいひと
100日間で学んだこと
- HTML/CSS
- Ruby
- Ruby on Rails
- Java Script
- Git,GitHub
- SQL
主に100日間で学んだことは下記の通り。
全て同じ量をやっているわけではなく、HTML/CSS、Ruby、Railsをやっている割合がほとんどだった。100日間でできるようになったこと
- ターミナルがつかえるようになった!
- テキストエディタが使えるようになった!
- めっちゃ簡単なHTML/CSSの実装ができるようになった!
- めっちゃ単純なRubyのプログラムを書けるようになった!
- Railsのエラーが出たら何が原因か仮説を立てられて50%くらいはあってる!
- GitHubでマージとかプルリクとかできるようになった!
はじめたての頃は、
- ターミナルとテキストエディタって何が違うんだ・・・そもそもどっちにコード書くの?
- テキストエディタにどうやってファイル開くの?
- コマンド多すぎ…メソッド多すぎ…カタカナ多すぎ無理…
という状態だったので、著しい成長を遂げた(笑)
ただ、未だにわからないことばかりなので、
もっと勉強してできることを増やしていきたい。よかったこと
100日間勉強を続けてこれは良かったなと思うことが3つあるのでシェア。
1.周りに宣言&毎日output
プログラミングの勉強を始めると決めた際に、自社のエンジニア全員が入ってるslackチャンネルに入り、「今日から毎日勉強します。見ててください!」と勝手に宣言をした。
私は自分に甘いので、誰かに宣言することで継続できると思ったからだ。
そこから毎日、勉強したことをエンジニアのアウトプットチャンネルで投稿し続けた。誰かに見られているという緊張感で継続できたし、どんなレベルの低いことでもoutputすると学びの整理になったのでよかった。
初めて書いたQiitaはタイミングよくトレンド入りしてくれた。
【Ruby】今日のプログラミング学習時間を入力すると、学習進捗を教えてくれるプログラム - Qiita2.パラシュート学習法「まずやってみる」
私の通っているプログラミング教室が提唱しているパラシュート学習法。
パラシュート勉強法のやり方教科書の1ページ目からこつこつとやるのではなく、作りたいもの(ピンポイント)に的を絞ってやりたいことから学習していく方法。まずやりたいことからやってみて、詳細は後から学んでいくというやりかただ。
具体的にいうと、HTMLやCSSの大枠をざっと学んだあと、やりたいビューを実装していると、自然とBEMやリファクタリングの概念がわかってきたのがよかった。
多分BEMやリファクタリングをコツコツ学んでても理解にかなり時間がかかったと思う。プログラミングにおいても「まずやってみる」という大事さがわかった。
3.一緒に勉強する仲間をつくる
一緒にプログラミングをする仲間ができたのは、プログラミング教室に通ってよかったことのひとつだ。
辛い時も、モチベーションが下がってる時も、仲のいい同期が頑張っているといい焦りになった。たまたま一番仲良くなった女の子が、アウトプットをめちゃくちゃがんばる子なので私もそれに触発されている。一人じゃ頑張れないので一緒に頑張る仲間がいると心強い。
改善したいこと
いいことばかりじゃなくて、反省点もいっぱいある。
1.わからないことを調べず進めた。
パラシュート学習法を意識して、どんどん次に進めようとするあまり、ひとつひとつをしっかり理解していないまま次の学習に移っていた。
例えばRubyのクラスとインスタンスや引数に関して、しっかり理解しないまま進めていたので、今絶賛つまづき中。基礎ができていないのに応用はできないので、今必死にProgateで基礎をやり直している最中だ。
もし100日前に戻れるならちゃんと基礎をやれ!と言いたい。2.時間の確保
フルタイムで働いているのでなかなか平日の学習時間の確保が難しかった。100時間/月の学習目標に対してだいたい80〜90時間/月しか勉強ができなかった。
朝から起きてやればいいんだけど、それもなかなか続かず。。
朝から早起きして一緒にプログラミングの勉強をしてくれる人を募集しています。3.自分で何のサービスも作れなかった。
自分の欲しいサービスを作りたい!と言って始めたわりには、なにもアウトプットするものを作れなかった。
自分の欲しいものから作るともっとプログラミングの勉強が楽しくだろうとわかっているのに…!プログラミングの学習時間を計測する簡単なWebアプリくらいは年内に作りたいとおもう。
総括
プログラミング向いていないなと思うこともあるが、前に比べるとできることが多くなっているのが嬉しい。私でもちょっとはコードが書けるようになったので、ホリエモンがいう通り「プログラミングは簡単、だれでもできるもの」なのかもしれない。
ねむいのでここまで!引き続きがんばる!
- 投稿日:2019-11-12T02:49:16+09:00
【Ruby】selectメソッドとinclude?メソッドで検索機能を実装する!
はじめに
プログラミング学習中に出会った、
selectメソッドとinclude?メソッドについて簡単にまとめました。selectメソッド
配列やハッシュなどから、ある条件にあった要素だけを取り出します。
例1 色が入ったリストからある条件にあう要素のみ取り出す
list = [ "blue", "red", "yellow" ] color = list.select do |x| x == "red" end puts color # redが書き出される例2 do-endを使わずに書く
list = [ "blue", "red", "yellow" ] color = list.select{|x| x == "red" } puts color # redが書き出されるinclude?メソッド
配列の要素に、指定した文字列(引数で指定)が含まれているか確認できます。
含まれていればtrueを、なければfalseを返します。例 色が入ったリストに引数に指定した要素が含まれているか確認
list = [ "blue", "red", "yellow" ] color = list.include?("red") puts color # trueが返される2つのメソッドを利用して検索機能を持った簡易アプリを作る
list = [ "blue", "red", "yellow" ] puts "blue" puts "red" puts "yellow" puts "3色のうち好きな色を入力してください" index = gets.chomp # ユーザーの入力 color = list.select{ |x| x.include?(index)} # index(入力された文字列)を含む要素を取り出して変数に入れる。 puts color # 入力した文字列を含む色が書き出される。 # 「e」と入力すれば「blue」「red」「yellow」全て書き出されるまとめ
selectメソッドは条件にあった要素を取り出し、
include?メソッドは、指定した文字列が対象に含まれるかを確認します。
これにユーザーの入力機能を組み合わせることで検索機能を実装できました。
- 投稿日:2019-11-12T01:53:55+09:00
【Ruby】`inject(:+)`によるリファクタリングと`:+`の意味
はじめに
配列の各要素を加算する際によく使われる
inject
メソッド。その中でも、
inject(:+)
によるリファクタリングと、:+
の意味について解説します。この記事が役に立つ方
- もっとスッキリコードを書きたい
- Ruby初心者
この記事のメリット
inject(:+)
の意味がわかる- 配列の各要素の演算をする際の引き出しが増える
環境
- Ruby 2.6.3
inject
メソッドとは?リストのたたみこみ演算を行ってくれるメソッド。
詳細はRubyリファレンスマニュアルをご確認下さい。
instance method Enumerable#inject (Ruby 2.6.0)基本構文
inject(init){ |result, item| result + item } # or inject(symbol)2通りあります。
inject(:+)
は後者です。よく使われる用法
主に配列に対して、要素の合計を算出したい場合に用いられます。
一番よく見る記法は、タイトルにもあるinject(:+)
です。前提
整数のみの配列
array
を以下のように定義します。
こちらのarray
の総和result
を求める記法を比較します。array = [1, 4, 6, 34, 235]
each
result = 0 array.each{ |i| result += i } p result => 2803行。無駄に長い。
inject
(通常の記法)result = array.inject{ |sum, i| sum + i} => 280
each
と比べて2行削減出来ました。
inject(:+)
(シンボルを用いた記法)result = array.inject(:+) => 280スッキリ!
逆に何が起こっているのか理解しづらいので、後ほど説明します。
sum
result = array.sum => 280最高にシンプル!
:+
の意味
inject(:+)
の:+
は、Symbolオブジェクトです。自分は最初何をやっているのか全然理解出来なかったので、以下でも試してみました。
きっとこれで「なるほどね!」と理解出来ると思います。
演算子で配列の各要素をつないでくれるイメージですね。
:*
の場合result = array.inject(:*) => 191760 # 1 * 4 * 6 * 34 * 235 = 191760
:-
の場合result = array.inject(:-) => -278 # 1 - 4 - 6 - 34 - 235 = -278各記法ごとの処理速度
こちらの2つの記事で詳細が記載されていました。
具体的でわかりやすい。Rubyいろんな処理のベンチマーク選手権 - Qiita
Rubyで配列の要素を合計するベストな方法 - Qiita
sum
が爆速!
inject(:+)
はその次なんですね。参考になります。【余談】
reduce
との違いは?Rubyでは
inject
メソッドとreduce
メソッドは同じ働きをします。英単語の意味は、
inject
「注射する・注入する」
reduce
「減らす・減少させる」このせいで、最初なんで一緒なの?とすごく疑問だったのですが、以下記事の「reduceとinjectの発想の違い」という箇所で解説されていました。
図まで用意されていて超わかりやすかったです。
気になった方は是非ご確認下さい。reduce は「あるルールに従ってデータ構造内の要素数を縮小していき、最後に残った値を返す」という発想になります。
inject は「値をプールしておくバケツを用意しておき、データ構造内の全ての要素をひとつずつ、ある処理にしたがってバケツに注入していく」という発想になります。
map と collect、reduce と inject ―― 名前の違いに見る発想の違い
おわりに
(:+)
ってクマに見えませんか?笑参考にさせて頂いたサイト(いつもありがとうございます)
instance method Enumerable#inject (Ruby 2.6.0)
map と collect、reduce と inject ―― 名前の違いに見る発想の違い
Rubyいろんな処理のベンチマーク選手権 - Qiita
Rubyで配列の要素を合計するベストな方法 - Qiita
- 投稿日:2019-11-12T00:32:20+09:00
Rubyでトランプの山札からカードを引くアプリを作った(2)
以前作ったアプリを色々仕様追加や改修をしました。
仕様変更
・全てのカードが重複しないようにする。
→「ジョーカーの追加」を設定したら53枚になり、「なし」にすると52枚になる。
・山札からカードを引く。
→カードを引く枚数を指定できる。
・手札の上限枚数までカードを引けるようにする。
・手札を捨てることができる。
→捨てる枚数を指定できる。
・山札を使い切る、もしくはカードを引くことやめると終了する。
→捨て札から山札に戻すことができる。・三項演算子などを用いて行数を短くする。
・何度か行う処理ならメソッド定義化にする。
・for文が流行っていないそうなので、each文を使ってみたりする実際のコード
playing_card.rb# カード判定メソッド def card_judge(i) # 記号判定 mark_no = (i % 13 == 0) ? (i / 13) - 1 : i / 13 # マーク番号:0スペード/1ハート/2ダイア/3クラブ card_mark = case mark_no when 0 then "♠️" #SPADE when 1 then "♥️" #HEART when 2 then "♦️" #DIAMOND when 3 then "♣️" #CRAB when 4 then "JOKER" #JOKER end # 数字判定 card_no = i - ( 13 * mark_no ) # 表示判定 disp_list = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"] if card_mark == 4 disp_num = nil else disp_num = disp_list[(card_no - 1)] end # 戻り値:カードナンバー/カードのマーク/表示される文字 return card_no, card_mark, disp_num end # ドロー処理 def card_draw # デッキから手札に移す draw_card = DECK.shift(1) # ドローしたカードの表示設定を行う disp_joker(draw_card[0]) # カードナンバーを返す return draw_card[0] end # ジョーカー表示処理 def disp_joker(n) if card_judge(n)[1] == "JOKER" puts "JOKER" else puts "#{card_judge(n)[1]} #{card_judge(n)[2]}" end end # 手札の表示 def disp_hand # 手札の表示させる puts "\n手札一覧(#{HAND.length}枚):" HAND.each{|i| disp_joker(i) } end # 捨て札の表示 def disp_trash # 捨て札の表示させる puts "\n捨て札(#{TRASH.length}枚):" TRASH.each{|i| disp_joker(i) } end # 手札を捨てる処理 def hand_trash(i) i.times do |n| TRASH.push(HAND[0]) HAND.delete_at(0) end end # デッキのシャッフル def deck_shuffle DECK.shuffle! end # 捨て札をデッキに戻す処理 def deck_rebuild TRASH.length.times do |m| DECK.push(TRASH[0]) TRASH.delete_at(0) end deck_shuffle puts "デッキの残り枚数は、#{DECK.length}枚\n" end # 初期設定 HAND = [] #手札のセットアップ TRASH = [] #捨て札のセットアップ hand_limit = 7 #手札上限枚数 card_max = 52 #トランプのセットアップ(52=デフォルト) joker_use = 1 #ジョーカーの利用(0=利用しない) # デッキのセットアップ DECK = [*(1..(card_max + joker_use))] # デッキをシャッフルする puts "デッキをシャッフルします\n" deck_shuffle # ドローのループ loop { # 手札の表示させる disp_hand # 捨て札の表示させる disp_trash if DECK.length == 0 # デッキを使い切ったときの挙動 puts "デッキを使い切りました\n捨て札をデッキに戻しますか?(Nで終了)[Y/N]" case gets when /^[yY]/ deck_rebuild when /^[nN]/ then break end elsif HAND.length >= hand_limit # 手札上限チェック puts "上限を超えているのでドローできません\n手札を古い順から何枚捨てますか?(0で終了)[1~#{HAND.length}]" trush_cnt = gets.to_i case trush_cnt when 1..HAND.length hand_trash(trush_cnt) when 0 then break end else # カードをドローして手札に加える hand_possible = hand_limit - HAND.length # ドロー最大数の設定 if DECK.length <= hand_possible hand_possible = DECK.length end # 何枚ドローするか指定して、デッキからドローする puts "デッキからカードを何枚ドローしますか?(0で終了)[〜#{hand_possible}/0]" draw_num = gets.to_i case draw_num when 1..hand_possible draw_num.times{ HAND.push(card_draw) } when 0 then break end puts "デッキの残り枚数は、#{DECK.length}枚\n" end } exitソースコードで使用したもの
後でまとめます