20191112のRubyに関する記事は24件です。

[Ruby]使用頻度は高くないがここぞという時に知っていたら便利そうなメソッドたち

使用頻度は高くないので忘れちゃいそうだけど、ここぞという時に知っていたら便利そうなメソッドを備忘のためにまとめておきます。
(便利かつ高頻度で使うものは忘れないと思うのでここには書きません)

今後も便利そうだと思うメソッドがあったら随時追加していく予定です。

clamp

数値の上限・下限を制限する

523.clamp(0, 100)
# => 100

email_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"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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,
  baz

Layout/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
  end

Layout/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
   SQL

Lint/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|
  # ...
end

Style/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.select

Style/ConstantVisibility

定数は全て明示的にスコープを宣言することを推奨するもの。

# bad
class Foo
  BAR = 42
  BAZ = 43
end

# good
class Foo
  BAR = 42
  private_constant :BAR

  BAZ = 43
  public_constant :BAZ
end

Style/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
end

Style/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
end

Style/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.c

Style/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
end

Style/MultilineMethodSignature

メソッドシグネチャが複数行に渡るの禁止。

# good

def foo(bar, baz)
end

# bad

def foo(bar,
        baz)
end

Style/OptionHash

キーワード引数をサポートしているのでそっちを使ってほしいとのこと。

# bad
def fry(options = {})
  temperature = options.fetch(:temperature, 300)
  # ...
end

# good
def fry(temperature: 300)
  # ...
end

Style/ReturnNil

return nilreturn か、どっちか統一しろとのこと。
デフォルトでは return の方を使うのが推奨。

# bad
def foo(arg)
  return nil if arg
end

# good
def foo(arg)
  return if arg
end

Style/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 というメソッドの存在を初めて知りました。

以上です。
ご査収ください。

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

Ruby勉強日誌3

クラス

class.rb
   class ◯◯◯◯◯
     attr_accessor :□□□, :△△△
   end

インスタンス

instance.rb
   変数 = クラス名.new
   変数.属性 = ✖️✖︎
   puts 変数.属性

インスタンス変数:名前が@で始まる変数

initializeメソッド:インスタンス作成時の初期値を設定

initialize.rb
   class BillRecord 
   attr_accessor :name, :bill
   def initialize(name, bill)
     @name = name
     @bill = bill
    end
   end
   data = BillRecord.new("◯◯","✖︎✖︎")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby技術者認定試験Silverを25日間で取得した話:準備編

Silverを取得したのが2019年7月31日、あれから3ヶ月以上経ってからこれを書いている。
すぐ書かなかった理由はGold取得に向けての勉強を優先したからであった。

...という言い訳。3:)

この記事では、私がSilver試験に合格するために過ごした25日間の記録を残しています。
また、同じスタートラインや期間で資格習得を目指す人に向け、何か参考になれたら幸いです。

書きたいことが多いので、以下3本でお送りします。
準備編
・受験編
・その後編

拙い文章ですが、よろしくおねがいします。

はじめに

本記事を読むにあたり以下に1つでも当て嵌まる方は是非とも読んでいただけたらと思います:)

  • 「Rubyはおろか、プログラミング言語のプの字も知らないよ。」

  • 「勉強の仕方が分からないし、お金をかけたくないんだけど〜」

  • Silverの資格を取得して変化あった?」

そもそもそもRuby技術者認定試験ってなんゾ?

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の勉強を始めた。

筆者について

fullsizeoutput_b.jpeg

当時はソフトウェア/アプリケーションのQAエンジニアだったが、紆余曲折あってWebエンジニアに転向する機会を得られた。
いずれ自分も開発にシフトするゾ!と思いながらテスト業務を続けてたら7年くらい経ってた。
情報系の学校を出たわけでもない:angel:

勉強場所と費やした時間

◇場所

当時の筆者は自宅で勉強するのがあまり好きではなく、
もっぱらカフェか会社での学習が中心でした。この記事もスタバで書いてるゾ。
移動中はスマホで「Ruby試験」の記事を読んだり「YouTubeの学習動画」を見てました。
あと英語も必要だと言われたので「英語学習アプリ」とかで適当に英文を読んでました。

出来るだけ勉強時間を設ける!というよりも「Rubyと触れ合う時間」を作るようにして、
生活の一部にしてしまうイメージでいた方が自分には合っていました。

◇時間

前提として、最低でも1日にこの時間は学習に充てることを自分と約束しました。

・平日:4時間
・休日:6時間
※もちろんぶっ通しでってのは集中力が持たないので、1時間くらいやったら休憩入れてました。
※おおよそですが、Silver取得までにかかった時間は合計120〜150時間くらいです。

言わずもがな、地頭の良い方/既にプログラミングを学んでいる方はより少ない時間で十分だと思います。

取り巻く環境(モチベーション)について

とてもラッキーなことに筆者には強力な協力者たちがいたので、
勉強を始める人は周りに知見者がいるかどうかがとても重要になってくると思います。:raised_hands:

  • 「24時間いつでも質問して良いよ」という人がいた(休日でも夜中でも対応、例題もたくさん作ってくれた)
  • 一緒に勉強してくれる人がいた(各々Ruby以外の勉強もしていました)

学習に使用した書籍/サイト/動画について

◇書籍

●Ruby技術者認定試験合格教本 Silver/Gold対応 (Ruby公式資格教科書)


◇どんな本?

Ruby技術者認定試験を受ける人ならほぼ必ずこれを読むことになると思います。
何故なら、試験対策本として世の中にあるのはこの1冊だけだからです:eyes:
Silverのワンランク上の資格であるGoldの対策本でもあります。

試験対策本なので、Silver/Goldの試験範囲の内容と合わせて、
実際に出題される問題を想定した基礎・演習問題や模擬試験問題が掲載されているので、
この書籍を中心に勉強していくのが安定して試験対策になると思います。

筆者はこの本を2~3回読んで、分からないとこがあれば一つずつ潰していくようにしていました。

◇個人的に思ったこと

◇オススメしたいところ
・試験範囲はしっかりカバーしているので、とりあえず読んで間違いない。
・対策問題の数が多いので、自分でアレンジした問題をgitにコピーして、オリジナル問題を作るなど色々使える。
・Gold試験にも使えたり、Rubyの基礎本としても読めるので持ち腐れになりにくい。

◇気を付けて欲しいところ
・所々に誤植があるので、Rubyに慣れていても惑わされる可能性があります。
:point_right:サポートページで誤植について掲載があるので、確認した方が良いです。

・教本の演習問題の答えを丸暗記しても、合格できませんので読むだけじゃダメです。
:point_right: 重要なのは問題の答えではなく「どういった処理が行われいるか」理解するように学習することです。

◇動画

●七海有里佳とRubyの基礎

今流行りのバーチャルユーチューバー(Vtuber)が、プログラミングを教えてくれるというものです。
動画はYoutubeや公式サイトにてもちろん無料で公開されています。
2019年11月現在は私が確認している限りだと、Rubyコース以外にも、Pythonコースがあります。

◇どんな動画(コンセプト)?

Programastar.comalt

Programastar.comとは
Programastar公式サイトから引用

「プログラマとして輝けるまでの道のりを提供する」をモットーとして掲げ、プログラミング習得を目指す初心者にとって、とことん分かり易くて挫折しにくい、完全無料の学習機会を提供することを目的に立ち上げたプログラミング教育サービスです。
女子中高生の美少女プログラマたちが、まったりほのぼのとプログラミングを教えてくれる、ユーザーが癒されながら学ぶことができる『日常系プログラミング学習サイト』として、プログラミング習得を目指す人にとって有益なサービスを目指していきます。

七海有里佳は右から2番目の子でした。どうでもいいか?

◇個人的に思ったこと

◇オススメしたいところ
・初心者向け
・irbで実際にコードを動かしてくれるので、写経しながらやれば身に付きやすい
・代表的なところは押さえている(配列,eachなど)
・声は女性なので聴きやすい←

◇気を付けて欲しいところ
・動画でやっていることは自分でもコードを写経して動かしてみること=これしないと覚えません。
:point_right:勉強するときはしっかり集中すること、休む時は休むとメリハリをつけないと頭は疲れてしまいます。

・動画を見すぎて目や体に負担がかかる可能性がある。
:point_right:姿勢悪い人は腰や肩にくる。

◇Qiita記事など

●当時読んだ記事の中でもとても役に立った記事

Ruby Silver試験前に見直すと幸せになれるメモ
Ruby技術者認定試験 Silver/Gold 対策の個人的なハマり問題集
Ruby技術者認定試験 Silver version 2.1を受けて…

「Ruby Silver試験前に見直すと幸せになれるメモ」は絶対に読んだ方が良いです。

◇学習に使用したものについて

◇勉強に使うものは少なくて良い

私の上司は「Ruby技術者認定試験合格教本」だけでSiverに合格したと言っていたので、
記事の閲覧や動画を視聴するのが難しくても、教本だけでも勉強できますし、合格も可能だと思います。

(プログラミング完全未経験ではない場合なので、未経験者と比較するのは難しいところもありますが、、)

◇やって(使って)おけば良かったと思うもの(こと)

●Progate(プロゲート)

Progate_Logo_CMYK.jpg

はい、お前使ってなかったんかい!!ってツッコミが来そうな気がしてならないProgateです。
当時から存在は知っていましたが、筆者は使用せずに勉強していました。今ではとても後悔しています。

Progateの説明はほぼ不要だと思いますが、エンジニアを対象にしたオンライン学習サービスです。
Web版/スマホ版がリリースされていますが、両者で受講できるコースや解答方法が異なるので注意して下さい。
一部のコースは無料ですが、有料会員でないと受講できないものもあります。

初心者であればあるほどさっさと有料会員になって「Rubyコース」を全部やることをオススメします。
1ヶ月1000円くらいなので、1ヶ月以内に全部やれば良いだけの話ですし。
ある種ゲーム感覚で学べるように作られているので、テンポ良く進められると思います。

また、HTML/CSS/Git/Linuxなど開発を行う上では避けて通れないものも学ぶことができます。
Ruby on Rails(フレームワーク)コースもあり、今になって筆者は有料会員で学習中ですが、
実務でも役に立つ内容もあると感じています。

実際にコードを書くスタイルなので、リファクタの練習にもなります。
筆者はよくendを忘れて怒られます。。

●ひたすらコードを書く(写経する)

スクリーンショット 2019-11-21 20.49.38.png

あなたは自分で書いたコードの動きを人に説明できますか?
出来なかったり、理解に詰まってしまう場合は「分からない部分」について調べて実際にコードを書いてください。
Silver試験においては、ほぼほぼ暗記だけでいけるという記事が結構ありますが、それはほぼ間違い無いです。

しかし、「問題の形式」が変わると「暗記や形」で覚えているので応用ができず、対応できなくなってしまいます。
腐っても試験なのでどこに罠が仕掛けられているか分からないのです。

Q1.eachメソッドはどんな処理ができますか
Q2.実際にeachを用いてコードを書いてください
Q3.Q2で書いたものを「do end」 を使用しないで書いてください
Q4.ブロックを「{」と「}」で囲うか「do」と「end」で囲うかとで違いはありますか

eachメソッドで一例を考えてみましたが、こんな感じでしょうか。
上記のようなことを聞かれても答えられるまで勉強しましょう。

●問題集をやる場合は、出来るだけ解答選択肢を見ないで答えてみる

スクリーンショット 2019-11-21 20.55.58.png

基本的に4択から正解を選ぶ例題が多いと思いますが、
ある程度コード読めるようになったら筆者は解答欄を見ずに解答することをオススメします。

これは「問題を形で覚える」ことを防止することができ、
しっかりコードを読んで動きを理解することを意識させるためです。
実際の試験で出るものに似た問題もありますが、うまい具合(言い方を変えると意地悪)に内容が変わっているので、
コードを読むクセをつけて、実際の動きを考られるようになれば、本番で正答できる確率はグっと上がるはずです。

準備編のまとめと感想..

色々ぐちゃぐちゃに散らかった記事になってしまった気がする。
ある程度書くことは事前にまとめていましたが、書き始めるとあれもこれもで記載量が増えちゃいました。
自分で当時のことを今回初めて振り返っていますが、中々に濃い25日間だったようです:rolling_eyes:

◇次回:受験編

次はいよいよ受験当日〜合格について書こうと思います。
完成までしばらくお待ちください。

icon.ruby_.png

オサキデス。

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

sort_byを使用してみて

meibo2.rb
personal_data = [
['john','m','18'],
['paul','m','20'],
['alice','f','15'],
['dabid','m','17'],
['jasmin','f','17']
]

この配列が存在した時に最後のカラムである年齢順に並べたい時

sort_by.rb
personal_data.sort_by!{|personal| 
  personal[2].to_i
}

と文字列を数字の列に変換してsort_byメソッドを使用することで数字が小さい順に並び替えが起こります。
sort_by!の最後の!は、破壊的なメソッドで前後の処理に影響するので注意を払って書いた。
自分が躓いてしまった点は

.sort_by {|k, v| v }

のようにkeyとvalueが存在し整数などの数字を順番に並べたいので

to_i

メソッドを使用しなければいけないことにきずいた。
メソッドにおいて基本的な形を意識して文字列、整数を使う意識を実感できた。

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

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.rb
class 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という例外が発生し、登録に失敗していることがわかる。

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

Ruby 文法の学習メモ・チートシート(自分用)

Ruby 2.6.5
完全に自分用なのであしからず。多分何かしら間違っています。

if

if value==2
  # 略
elsif value%2==0 # else ifではない
  # 略
else
  # 略
end

times, while

5.times do|i|
  puts "#{i}回目のループ" # => 0,1,2,3,4回目のループ
end

n=0
while n<10 do
  puts n
  n += 1 # インクリメント(++)は使えない
end

each, 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 ...
end

begin, rescue

begin
  i = gets.to_i #標準入力を数字に変換
  puts 100/i
rescue => e
  puts e #エラーメッセージを出力
  retry #beginに飛ばす
end

raiseもある。

クラス

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

以上。こんな記事を最後までお読みいただきありがとうございます。
また学んだことがあれば更新します。

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

【Ruby】7桁の整数で保存した郵便番号にハイフン(-)を入れる方法

1234567のように、DBに7桁の整数で郵便番号を保存。
一方、ビューでは123-4567のようにハイフンを入れて表示したい場合。

以下のように記述すればOKです。

1234567.to_s.insert(3, "-")

to_sで整数を文字列に変換。
insert(3, "-")で3文字目の後にハイフンを挿入しています。

参考になった記事
https://qiita.com/_kkoichi/items/f8758a438b2363943922

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

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

わざわざ全ての数字を記入しなくても範囲を指定してあげるだけで済みます。

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

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 %>
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsでEC系に良く出てくるカート機能を解説 / 実装してみた

参考にした記事

Rails5でカート機能を作るためのロジックを作ってみた

おそらくこの記事を読みに来てくださる読者の方は上記の記事も読んでる可能性が高いのでモデルの設計は似せようと思います。

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

上記の内容でマイグレートを通した後であればコンソールで軽く遊んでみたりしてデフォルト値が設定されているかとか確認しておくと良いかもですね。

スクリーンショット 2019-11-12 9.58.58.png

(因みに補足ですが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 な感じで

スクリーンショット 2019-11-12 10.08.11.png

詳しくは本家の 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'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby Dateクラスの使い方2

今日の日付のDateインスタンスを取得する

Dateクラスのインスタンスを作るためにDate.newを使ってきたが、Dateクラスでは、Date.todayとすることで、今日の日付のインスタンスを作ることができるようになっている。

date.rb
require "date"
date1 = Date.today
puts date1

結果

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

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] #=> nil

stringと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
     => :tomohisa

paramsの中身を眺めていたときに、なんでこれまでsymbolとstringテキトーにやってきたのに値がとれてたんだ?と思って知ったことでした。

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

bundle execとは

rails s bundle execbundle exec、聞いたことあるけど特に書かなくても問題なく動いてきたのでずっと「なんかgemをいい感じにしてくれるもの」くらいの認識でいました。
多分、そろそろきちんと知っておいた方がいいので調べてみた。

bundle execはなぜ必要なのか

要するに、gemをいい感じにしてくれるものでした。

…それでは何もアップデートがないので、もう少し踏み込んでまとめると、gem Agem Bがあるとする。
プロジェクトAではA,B両方使っていて依存関係があり、プロジェクトBではAだけ使っている場合、gemBにアップデートがあるなんてことがあるとプロジェクトBでは勝手にアップデートしてくれという感じだがプロジェクトAではgem Aに影響が出てしまうのでそれは困る。
ここら辺を、プロジェクトごとに臨機応変にバージョン管理してくれるのがbundlerの役割らしい。

便利やん!!

今作っているようなプロダクトだとほとんどgemを使っていないので特に問題ないが、gemがいっぱいあるときには必須なのだと思いました。

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

Ruby initializeメソッド

initializeメソッドを使う

initializeメソッドは、他のインスタンスメソッドと同じように定義することができる。

[例1]

hoge.rb
class Hoge
 # 〜###〜

  def initialize
    puts "インスタンスが生成されました"
  end

  # 〜###〜
end

hoge1 = Hoge.new

Hoge.newが実行されると自動でinitializeメソッドが呼び出されます。

  • 結果
インスタンスが生成されました

initializeメソッドでインスタンス変数を使う

fuga.rb
Class Fuga
  # ・・・・
  def initialize
    # インスタンス生成直後に "piyo"をインスタンス変数nameに代入している
    self.name = piyo
  end

  # ・・・

end
fuga1 = Fuga.new
puts menu1.name

インスタンスメソッド内では、self.変数名でインスタンス変数を使うことができる。
よって、self.変数名 = 値でインスタンス変数に値を代入することができる。

  • 結果
piyo

以上 initializeメソッドの簡単にしてみました。

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

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.rb
driver = 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

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

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.rb
driver = 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

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

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-dataTZInfoが参照するタイムゾーン情報を提供するgem。
TZInfoはRubyからタイムゾーン情報を参照し、その情報に基づいて時間をコンバートするためのライブラリ。

解決方法

この問題についてググってみると、githubのtzinfo-dataの作者のコメントに解決方法が書いてあった。

解決方法は4つあって下記のいずれかを実行すれば良い。

  1. Gemfileのtzinfo-data行のplatforms: [:mingw, :mswin, :x64_mingw, :jruby]を削除し、bundle updateを実行。プラットフォーム関係なくtzinfo-dataのタイムゾーンを参照する設定。

  2. Gemfileからtzinfo-data行を削除。tzinfo-dataではなくシステムのタイムゾーンを参照するようになる。Windowsの場合は、tzinfo-dataを削除すると、TZInfo::DataSourceNotFound例外が発生してしまう。

  3. bundle lock --add-platform mingw, mswin, x64_mingw, jrubyを実行。Gemfile.lockに依存プラットフォーム情報を記述してしまう方法。

  4. bundle config --local disable_platform_warnings trueを実行(Bundlerのバージョンが1.17.0以上であることが必須)。Bundler自体のwarningを出させないようにする設定。

4はカレントディレクトリのRailsアプリにだけ適用する方法で、システムのカレントユーザに対して非表示にしたければ、下記のように--localを省いて実行すればOK!

bundle config disable_platform_warnings true

Gemfileに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を入れる必要はないそう。

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

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.rb
Rails.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.rb
 def self.search(search)
    return Sample.all unless search
    Sample.where('title LIKE(?)', "%#{search}%")
  end

今回はtitleで検索をかけていきます。
モデルの中でメソッドを定義する際に、メソッド名の頭にself.を付けるとコントローラーで使えるクラスメソッドという物になります。

上記でLIKE句whereメソッドが出てきました
簡単に説明するとLIKE句とは、曖昧検索と言われる物に使われるもので、前方一致や後方一致などを指定するときに使います。
whereメソッドとは、モデル.where(条件)のように引数部分に条件を指定することで、テーブル内の条件に一致したレコードのインスタンスを配列の形で取得できます。そして今回は条件式に前述したLIKE句を使っています。
ちなみに上記の記述方法をif文を使い、よりわかりやすく書くと下記のようになります。

sample.rb
def self.search(search)
    if search
      Sample.where('title LIKE(?)', "%#{search}%")
    else
      Sample.all
    end
  end

Sampleテーブルから曖昧検索をかけて絞るのか、全てを出すのかという簡単な式を作ることができます。

searchアクションをコントローラーに定義

次はコントローラーにアクションを設定し先ほど定義したsearchメソッド使っていきます。

sample_controller.rb
 def search
    @sample = Sample.search(params[:keyword])
  end

params[:keyword]と書くことで、formで入力した、:keywordを取得することができます。
もしparamsのなかに何が入っているかを確認したい時は

sample_controller
def 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つのアクションのみで実装する方法も調べてみてください。
この先インクリメンタルサーチを実装したりするかどうかはまた少し工夫が必要になってきますが、ベースは今回記述した検索機能になります。
この記事が検索機能実装でつまずいてしまった人の助けになれれば幸いです。
ではでは!!

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

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】今日のプログラミング学習時間を入力すると、学習進捗を教えてくれるプログラム - Qiita

2.パラシュート学習法「まずやってみる」

私の通っているプログラミング教室が提唱しているパラシュート学習法。
パラシュート勉強法のやり方

教科書の1ページ目からこつこつとやるのではなく、作りたいもの(ピンポイント)に的を絞ってやりたいことから学習していく方法。まずやりたいことからやってみて、詳細は後から学んでいくというやりかただ。

具体的にいうと、HTMLやCSSの大枠をざっと学んだあと、やりたいビューを実装していると、自然とBEMやリファクタリングの概念がわかってきたのがよかった。

多分BEMやリファクタリングをコツコツ学んでても理解にかなり時間がかかったと思う。プログラミングにおいても「まずやってみる」という大事さがわかった。

3.一緒に勉強する仲間をつくる

一緒にプログラミングをする仲間ができたのは、プログラミング教室に通ってよかったことのひとつだ。
辛い時も、モチベーションが下がってる時も、仲のいい同期が頑張っているといい焦りになった。

たまたま一番仲良くなった女の子が、アウトプットをめちゃくちゃがんばる子なので私もそれに触発されている。一人じゃ頑張れないので一緒に頑張る仲間がいると心強い。

改善したいこと

いいことばかりじゃなくて、反省点もいっぱいある。

1.わからないことを調べず進めた。

パラシュート学習法を意識して、どんどん次に進めようとするあまり、ひとつひとつをしっかり理解していないまま次の学習に移っていた。
例えばRubyのクラスとインスタンスや引数に関して、しっかり理解しないまま進めていたので、今絶賛つまづき中。

基礎ができていないのに応用はできないので、今必死にProgateで基礎をやり直している最中だ。
もし100日前に戻れるならちゃんと基礎をやれ!と言いたい。

2.時間の確保

フルタイムで働いているのでなかなか平日の学習時間の確保が難しかった。100時間/月の学習目標に対してだいたい80〜90時間/月しか勉強ができなかった。

朝から起きてやればいいんだけど、それもなかなか続かず。。
朝から早起きして一緒にプログラミングの勉強をしてくれる人を募集しています。

3.自分で何のサービスも作れなかった。

自分の欲しいサービスを作りたい!と言って始めたわりには、なにもアウトプットするものを作れなかった。
自分の欲しいものから作るともっとプログラミングの勉強が楽しくだろうとわかっているのに…!

プログラミングの学習時間を計測する簡単なWebアプリくらいは年内に作りたいとおもう。

総括

プログラミング向いていないなと思うこともあるが、前に比べるとできることが多くなっているのが嬉しい。私でもちょっとはコードが書けるようになったので、ホリエモンがいう通り「プログラミングは簡単、だれでもできるもの」なのかもしれない。

ねむいのでここまで!引き続きがんばる!

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

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】今日のプログラミング学習時間を入力すると、学習進捗を教えてくれるプログラム - Qiita

2.パラシュート学習法「まずやってみる」

私の通っているプログラミング教室が提唱しているパラシュート学習法。
パラシュート勉強法のやり方

教科書の1ページ目からこつこつとやるのではなく、作りたいもの(ピンポイント)に的を絞ってやりたいことから学習していく方法。まずやりたいことからやってみて、詳細は後から学んでいくというやりかただ。

具体的にいうと、HTMLやCSSの大枠をざっと学んだあと、やりたいビューを実装していると、自然とBEMやリファクタリングの概念がわかってきたのがよかった。

多分BEMやリファクタリングをコツコツ学んでても理解にかなり時間がかかったと思う。プログラミングにおいても「まずやってみる」という大事さがわかった。

3.一緒に勉強する仲間をつくる

一緒にプログラミングをする仲間ができたのは、プログラミング教室に通ってよかったことのひとつだ。
辛い時も、モチベーションが下がってる時も、仲のいい同期が頑張っているといい焦りになった。

たまたま一番仲良くなった女の子が、アウトプットをめちゃくちゃがんばる子なので私もそれに触発されている。一人じゃ頑張れないので一緒に頑張る仲間がいると心強い。

改善したいこと

いいことばかりじゃなくて、反省点もいっぱいある。

1.わからないことを調べず進めた。

パラシュート学習法を意識して、どんどん次に進めようとするあまり、ひとつひとつをしっかり理解していないまま次の学習に移っていた。
例えばRubyのクラスとインスタンスや引数に関して、しっかり理解しないまま進めていたので、今絶賛つまづき中。

基礎ができていないのに応用はできないので、今必死にProgateで基礎をやり直している最中だ。
もし100日前に戻れるならちゃんと基礎をやれ!と言いたい。

2.時間の確保

フルタイムで働いているのでなかなか平日の学習時間の確保が難しかった。100時間/月の学習目標に対してだいたい80〜90時間/月しか勉強ができなかった。

朝から起きてやればいいんだけど、それもなかなか続かず。。
朝から早起きして一緒にプログラミングの勉強をしてくれる人を募集しています。

3.自分で何のサービスも作れなかった。

自分の欲しいサービスを作りたい!と言って始めたわりには、なにもアウトプットするものを作れなかった。
自分の欲しいものから作るともっとプログラミングの勉強が楽しくだろうとわかっているのに…!

プログラミングの学習時間を計測する簡単なWebアプリくらいは年内に作りたいとおもう。

総括

プログラミング向いていないなと思うこともあるが、前に比べるとできることが多くなっているのが嬉しい。私でもちょっとはコードが書けるようになったので、ホリエモンがいう通り「プログラミングは簡単、だれでもできるもの」なのかもしれない。

ねむいのでここまで!引き続きがんばる!

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

【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?メソッドは、指定した文字列が対象に含まれるかを確認します。
これにユーザーの入力機能を組み合わせることで検索機能を実装できました。

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

【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
=> 280

3行。無駄に長い。


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 ―― 名前の違いに見る発想の違い

おわりに

(:+)ってクマに見えませんか?笑:relaxed:

参考にさせて頂いたサイト(いつもありがとうございます)

instance method Enumerable#inject (Ruby 2.6.0)
map と collect、reduce と inject ―― 名前の違いに見る発想の違い
Rubyいろんな処理のベンチマーク選手権 - Qiita
Rubyで配列の要素を合計するベストな方法 - Qiita

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

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

ソースコードで使用したもの

後でまとめます

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