yano3nora
7/2/2017 - 1:35 PM

[ruby: Ruby note] #ruby

[ruby: note] Ruby - A programmer's best friend. #ruby

OVERVIEW

Ruby www.ruby-lang.org/ja

日本人 ( Matz まつもとゆきひろ氏 ) の開発した純粋オブジェクト指向・インタプリタ・動的型付けなプログラミング言語。スタートアップ系の WEB アプリ開発で採用例が多く Ruby on Rails という MVC フレームワークがあまりにも有名。

書き方独特だけど、書いてて楽しい。いわゆる「Ruby っぽさ」は Rubyのリファクタリングでイケてないコードを美しいオブジェクト指向設計のコードへ改良するための方法 を読むのがわかりやすい。

Refs

rbenv

rbenv/rbenv - github.com

ruby 言語ランタイムのバージョン管理ツール。nodenv みたいに global では 2.6 を、特定プロジェクトでは 2.4 を ... みたいにバージョンの切り替えができる。

local (特定プロジェクトディレクトリ) では .ruby-version というファイルに ruby バージョンを記載して他開発者と共有するつくり。

追記: 最近言語ランタイムのバージョン管理は anyenv 経由で rbenv を入れて環境構築する方向に統一した

gem / Bundler

gem - パッケージ管理
rubygems.org
Bundler - bundler.io
Bundlerの使い方
bundler、bundle execについて
GemfileでインストールしたGemを削除する
インストールしたgem なのに、requireしないと使えない。 - require についてはこの辺

gem は Ruby のパッケージ管理ツール。端末グローバルに個別に Ruby パッケージをインストールできる。但しこの場合プロジェクト間で依存を引き継いでしまう、これを解決し「アプリケーション毎に gem の依存関係を分離して管理」するために用いる gem が Bundler と呼ばれるパッケージバンドルツール。

Bundler はアプリケーション毎に Gemfile と Gemfile.lock により gem パッケージ群依存を解決・管理する。一般的に端末グローバルには Bundler 以外の gem はインストールせずに、各アプリケーションで必要な gem は全て Bundler 経由でローカル vendor/bundle に導入するのが望ましい。

# gem による個別インストール ( to Global )
$ gem install bundler

# バージョン指定
$ gem install sqlite3 -v "1.3.8"

# Bundler 経由で Gemfile の内容をアプリルートにインストール
# インストール状態のハッシュマップを Gemfile.lock へ反映
$ vi Gemfile
> source 'https://rubygems.org'
> git_source(:github) { |repo| "https://github.com/#{repo}.git" }
> 
> ruby '2.5.1'
> 
> gem 'gemname'
> .....
$ bundle install --path vendor/bundle

# bundler 経由で gem をアンインストール
$ bundle exec gem uninstall gemname
# Gemfile から当該パッケージを削除
# Gemfile.lock からも削除

rbenv と組み合わせて ruby バージョンをファイルから読み取るのもよく見る。

# Gemfile

ruby File.read(File.join(File.dirname(__FILE__), '.ruby-version')).strip

Bundler > Docs > gemfile - bundler.io

  • group で指定された gem は当該 env 以外では「ファイルはインストールされるが require されていない状態になる」
    • require: faise と同等の状態?
  • require 'hoge' の名前が gem 名と異なる gem は自動で require されないため Gemfile で require: 'hoge-gem' とかしないといけない

SYNTAX

  • オープンクラス
    • すでに定義されたクラスのふるまいを後から変更可能
    • A クラスの定義を 2 回に分けて書くと A クラスそのものが拡張される
  • すべてがオブジェクト
    • すべてのデータはインスタンス
    • すべてのインスタンスのクラスは Object クラスを継承
    • Object クラスのふるまいを後から変更すると「全インスタンスのふるまいが変わる」
  • ダックタイピング - Wikipedia
    • あるインスタンスのクラスが何であろうと必要なメソッドに応答さえ出来れば処理を行える ... という思想
    • Object#nil? で全インスタンスは「 NULL 判定メソッド」を持ってたりする
      • こんな感じで「継承階層やインタフェースの実装状態に関係なく」オブジェクトのふるまいを中心にプログラムを組むってことかな?
  • Ruby では false または nil だけが偽それ以外は 0'' も含め全て真 と評価される
    • リテラルもオブジェクトなので

基本構文やリテラル

リテラル

  • メソッド
    • Ruby ではメソッドで return を省略した場合、最後に評価された値が返る
    • return を記載した場合は他言語と同様に以後処理をスキップし return した値を返す
    • return 'hoge', 'fuga', 'piyo' とすることで配列を返せる
    • 上記と 多重代入 を組み合わせて複数の戻り値を受けるようなことができる
  • エンコード
    • 1.9 未満は # coding: utf-8 で指定
    • 2 系からはデフォルトで UTF-8 になっている
  • 真偽値
    • true
      • 0""true
    • false
      • false または nilfalse
    • nil 一般的な言語の null のこと
  • オブジェクト
    • アクセス演算子: .
    • オブジェクトの ID: object.object_id
    • 暗黙トップレベルオブジェクト: main
      • puts メソッドは main オブジェクトのメソッドを self を省略するカタチで呼ばれてたりする
  • 変数
    • 普通のやつ variable
    • グローバル変数: $global_variable
    • インスタンス変数:@variable
      • いわゆる「メンバ変数」
      • クラス定義式内で定義しないでアクセサメソッドで初期化するキマリ
      • クラス定義式内で定義すると「クラス」オブジェクトの「インスタンス変数」というややこしい状態になるので注意
    • クラス変数: @@variable
      • 割と新しいやつで「クラスの全インスタンス間でグローバルに共有されるメンバ変数」みたいなやつ
  • 定数
    • クラス定数: FOO = 'FOO'
  • Array オブジェクト
    • ['hoge', 'fuga', 'piyo']
    • array[key]
  • Hash オブジェクト
    • ['key' => 'value']
    • hash['key']
      • hashnil のとき hash['key'] でアクセスすると undefined method[]' for nil:NilClass` 例外となる
    • hash['not-exists'] # nill
    • hash.fetch('key') # value
    • hash.fetch('not-exists') # KeyError 例外
  • Proc オブジェクト
  • Range オブジェクト
    • 1..31, 2, 3 みたいな Immutable かつ Enumerable なオブジェクト作れる
    • ('a'..'z')a, b, c, ... z とかも
  • シンボル
    • :hoge のようにして「完全に一意なオブジェクトを指す参照値」を定義可能
  • ブロック: {} は使わず基本的に do ... end で表現
  • % 記法: PHP の sprintf() みたいなフォーマッタ
    • puts %w(Alice Bob Chrlie) # ['Alice', 'Bob', 'Chrlie']
  • 変数展開: "variable is #{variable}"
  • 命名規則/慣習
    • 真偽値: visible?
    • 破壊的メソッド: split!
  • モジュール
    • require で外部ファイルを読み込みできる

to_i, to_s ...

'0001'.to_i  # 数値 1 として評価
12345.to_s   # 文字列 '12345' として評価

クラス/メソッドの定義

クラス/メソッドの定義 - docs.ruby-lang.org

# クラス
class Foo < Super
  # いわゆるメンバ変数
  @instance_prop = 0

  # いわゆる定数、クラス定数として FOO::MY_CONSTANT でアクセス
  MY_CONSTANT = 'Foo constant'
    
  # メンバ変数はアクセサ ( 後述 ) を明示しないと外から読み書きできない
  attr_accessor :instance_prop

  # クラス変数
  # 当該クラスや子孫、インスタンスで共有されるグローバル変数的な
  @@class_prop = 'hello'
  
  def instance_method
     # いわゆるメンバメソッド
  end


  def self.class_method
    # 特異メソッドと呼ばれるいわゆるクラスメソッド、他言語では static メソッドとか
    # Foo::class_method で呼べるし、ややこしいが Foo.class_method でも OK
  end    
end


# 特異クラス - 特定のオブジェクトにメソッドやインスタンス変数を定義・追加できる
obj = Object.new
class << obj
  def instance_method
     :
  end
     :
end

# モジュール
module Mod
  Version = '2.3.0'
  
  def hello
    puts 'hello'
  end

  module_function :hello
end

Mod::Version  # 2.3.0
Mod.hello     # hello

class Klass
  include Mod  # モジュール読み込み → インスタンスが Mod モジュールの機能を持つ
               # extend Mod でクラスが ( Static に ) Mod モジュールの機能を持つことも可能
               # また、prepend で mixin すると module 側の定数やメソッドを受け入れ側クラスで上書きできる
end

クラスの Extend / 継承

いつも忘れるRubyの include, prepend, extend の意味。
Rails の ActiveSupport::Concern の存在理由

# Base クラス + ActiveRecord モジュールを継承
class ApplicationRecord < ActiveRecord::Base
end

モジュールの Include / ミックスイン

requireとincludeとextendの違い

モジュールは PHP でいうところの Trait っぽいやつで、Ruby では mix-in と呼ぶみたい。

module Bark
  def initialize
    @cry = 'woo'
  end

  def bark
    puts "#{@cry.capitalize}!! #{@cry.capitalize}!!"
  end
end

class Animal
  include Bark
end

class Cat
  include Bark
  def initialize
    @cry = 'meow'
  end
end

class Dog
  include Bark
  def initialize
    @cry = 'woof'
  end
end

animal = Animal.new
animal.bark  # Woo!! Woo!!

cat = Cat.new
cat.bark     # Meow!! Meow!!

dog = Dog.new
dog.bark     # Woof!! Woof!!

アクセスメソッド

アクセスメソッド
Rubyのattr_accessor等について

Ruby のプロパティは Getter / Setter メソッドを定義しないと外部からは参照できないが、アクセスメソッドにプロパティ名を食わせることで簡単にアクセサを生やすことができる。

  • attr_accessor :variable .variable でアクセス可能な getter / setter メソッドを自動定義
  • attr_reader :variable 上記の getter のみ版
  • attr_writer :variable 上記の setter のみ版
レシーバ

rubyのレシーバとは

レシーバーは特に Ruby の用語というわけではなく、オブジェクト指向一般に使われる用語です。意味は「 . の左側」で間違いありません。オブジェクト指向では処理はメッセージのやり取りによって行うという考え方があります。( car.run() のとき ) car の run メソッドを呼び出すというのをメッセージの観点からいうと car に run のメッセージを送る となります。このため、car はメッセージの受け取り側なので、「レシーバー」と呼ばれています。

Rubyのセッターメソッドとレシーバとselfの話

Rubyは変数の代入とセッターメソッドの違いをselfを使うことで区別するようです。要はセッターメソッドの時にのみselfを付ければ良いわけですね。

Ruby は self など、他言語でいう疑似変数として表現されるレシーバは極力省略する傾向にある。Rubocop に怒られないようにするためには、セッターにはレシーバを明示し ( メンバ変数へのセットとローカル変数へのセットの違いがあるため ) 、メソッドコール ( アトリビュートのゲッター含む ) では省略するのがよろしいみたい。

class Guitar
  attr_accessor :color

  def initialize
    self.color = '赤'
  end

  def say_color
    "このギターは #{self.color} やで!"  # Redundant self detected. で Rubocop 激おこ
    "このギターは #{color} やで!"       # Rubocop もにっこり
  end
end

アクセス修飾子

Ruby の private と protected 。歴史と使い分け
Rubyのprivate修飾子からアクセス修飾子を考える

呼び出し制限 - docs.ruby-lang.org

public に設定されたメソッドは制限なしに呼び出せます。 private に設定されたメソッドは関数形式 ( レシーバ省略形式 ) でしか呼び出せません。 protected に設定されたメソッドは、そのメソッドを持つオブジェクトが selfであるコンテキスト(メソッド定義式やinstance_eval)でのみ呼び出せます。

基本は上記 public / protected / private の 3 パターン。但し Ruby のアクセス修飾子は Access Control として作られている ( = 外部から呼べる呼べないの制御をする ) わけではない ことに注意。あくまでも秘匿している、外部からのコールを想定してないことの「明示 + ちょっと外部コールに制限ある ( レシーバつきで呼べない ) 」程度のもの。Ruby 開発当時は C++ や Java でよくある「外から呼べない private 」がまだ浸透しておらず、Smalltalk の Private Category ( 使わないでねってカテゴリの明示 ) から着想を得て実装したのでこうなったらしい。

class Klass
  def public_method
    puts 'public'
  end

  protected  # 以降は全て protected メソッド

  def protected_method
    puts 'protected'
  end
end
class Parent
  def public_method
    # 'hello ' + self.private_method  # レシーバ付きのため通らない
    'hello ' + private_method         # 関数呼び出しで通る ( 期待通り )
  end

  private

  def private_method
    self.inspect
  end
end

class Child < Parent
  def initialize
    # puts self.private_method  # レシーバ付きなので通らない
    # puts private_method       # 関数呼び出しなので期待に反しこれは通る
    puts public_method
  end
end

Child.new
class Klass
  # 主流じゃないけど最近は個別に宣言もできる
  private def my_private_method
    puts 'private'
  end
end

また、クラスメソッド ( = 特異メソッド def self.hoge ) を private にする際は private_class_method モジュールで定義が必要。

[Ruby] private_class_methodの使い所

class Example
  def self.public_foo  # クラスメソッド ( 特異メソッド )
    puts 'public class method'
  end

  def self.private_bar
    puts 'private class method'
  end
  private_class_method :private_bar  # Module#private_class_method による定義
end

alias / undef / defined? - 定義に関する操作

class Klass
  def foo
    puts 'foo'
  end

  alias :f :foo  # エイリアス - f() で foo() 呼べるよ
  undef foo      # 定義の削除
  defined? foo   # 定義の確認 - 真偽値で定義済みかどうか返却
end

メソッド移譲 / Delegation

Rubyでdelegation(委譲)を簡単にする2つの方法

メソッドを ( クラス継承やモジュールのインクルードなどを介さず ) 柔軟に他のクラスに移譲する機能。

class Base
  def method1
    puts "method1"
  end

  def method2
    puts "method2"
  end

  def method3
    puts "method3"
  end
end
require 'forwardable'

class Delegation
  extend Forwardable

  def_delegators :@base, :method2, :method3

  def initialize(base)
    @base = base
  end

  def method1
    print 'Hello '
    @base.method1
  end
end

=begin

↑ は以下のような
各メソッドの後続処理を Base に移譲した Delegation クラスを手実装した例
と等価になる

class Delegation
  def initialize(base)
    @base = base
  end

  def method1
    print 'Hello '
    @base.method1
  end

  def method2
    @base.method2
  end

  def method3
    @base.method3
  end
end

=end

d = Delegation.new(Base.new)
d.method1 # => Hello method1
d.method2 # => method2
d.method3 # => method3
send + method_missing

上記した Delegation クラスは以下のように send と method_missing を利用しても実現可能。

class Delegation
  def initialize(base)
    @base = base
  end

  def method1
    print 'Hello '
    @base.method1
  end

  # 自インスタンスにコールされたメソッドが存在しない場合に
  # コールされるマジックメソッド、第一引数にコールした
  # メソッド名、第二引数に配列で指定された引数が入る
  #
  def method_missing(name, *args)
    #
    # send は第一引数で呼び出すメソッド名を指定し
    # 以降可変長引数でメソッドに渡す引数を指定する
    # これでインスンタンスのメソッドを動的にコールすることができる
    #
    @base.send name, *args
  end
end

演算子 / Operator

# || 演算子
hash_a = {}
hash_b = { hi: nil }
p hash_a[:hi] || "Hello"     # => "Hello"
p hash_b[:hi] || "Hello"     # => "Hello"
p hash_a.fetch(:hi, "Hello") # => "Hello"
p hash_b.fetch(:hi, "Hello") # => nil
a ||= 1                      # a が偽か未定義ならば1を代入。初期化時のイディオムの一種

# << 演算子 / concat と同じみたい
str = 'abc' << 'def'
puts str  # abcdef

Safe Navigation Operator

Null 条件演算子 - Wikipedia
ぼっち演算子 - Safe Navigation Operator
Ruby2.3のSafe Navigation Operator

これは object が nil でないときにメソッド foo を呼び出します。 Active Support の try! と似ていますが、メソッド名は文法的に必須であるという点が異なります。

str = nil

puts str&.upcase  # 評価なし => nil 出力
puts str.upcase   # NilClass の upcase は NoMethodError として評価

# 引数はメソッドが呼び出された場合のみ評価
obj.try!(:foo, bar())  # bar() は常に評価 ( Rails の try ) 
obj&.foo(bar())        # bar() は条件付きで評価

# 属性値の代入
obj&.attr += 1

# &.each で nil セーフなイテレート
records = [{no: 1}, {no: 2}, {no: 3}, {no: 4}, {no: 5}]

records.each do |record|
  puts record[:no]
end

records = nil

records&.each do |record|  # ご利用は計画的に
  puts record[:no]
end

コメント

# 一行コメント

=begin 
複数行コメント
=end

__END__
ここから下全部コメント

標準出力

# print は純粋な標準出力
name = bob
print "My name is #{name}"  #=> My name is bob

# puts  は改行コードつき + 文字列展開出力
array = [1, 2, 3]
puts  array #=> 1
                2
                3

# p はデバッグ用
my_hash = { name: 'John', age: 20 }  #=> {:name=>'John', :age=>20}

require インポート

PHP の require と同じく「ファイル」を読込/実行するやつ。

require 'uri'

p 'valid@example.com'.match(URI::MailTo::EMAIL_REGEXP).is_a?(MatchData)    #=> true
p 'invalid#example.com'.match(URI::MailTo::EMAIL_REGEXP).is_a?(MatchData)  #=> false

分割代入

https://qiita.com/yancya/items/c557864f307d429bbde4

多重代入とも。

# こんなの
y, m, d = '2019.12.31'.split('.')

a = 1, 2
a #=> [1, 2]

a, b = 1, 2 
a #=> 1
b #=> 2

a, b = 1
a #=> 1
b #=> nil

a, b = 1, 2, 3
a #=> 1
b #=> 2 ( 3 以降はあっても無視される

a, *b = 1, 2, 3
a #=> 1
b #=> [2, 3] * で unpack され配列化

a, (b, c) = 1, [2, 3] #=> [1, [2, 3]]
a #=> 1
b #=> 2 () でネスト構造もうけとれる
c #=> 3

if / case 条件分岐

Rubyのcaseを〇〇(言語名)のswitch文だと思っている人たちにぼくから一言ガツンと申し上げたい

# if
if time < 12
    puts 'AM'
elsif time == 12
    puts 'NOON'
else
    puts 'PM'
end

# unless
unless is_boolean then
    puts 'is_boolean is false'
else
    puts 'is_boolean is true'
end

# case - then は省略可能、case 内で後置 if すると Linter が迷子になるので注意
case variable
when 'hoge' then
  # do something for hoge.
when 'fuga' then
  # do something for fuga.
else
  # do something for else.
end

空っぽいオブジェクトは falsy にならない

Ruby は他スクリプト言語と違って 0''[]if で true 扱いになることに注意。意味的に「空よね?」って聞きたい場合は ''.empty? とする Ruby の流儀があるからなのかしら。

string = ''

if string
  puts 'true'  # '' は true 扱い
else
  puts 'false'
end

if string.empty?
  puts 'empty'  # 空かどうかはちゃんとこれで聞けってこと?
else
  puts 'not empty'
end

integer = 0

if integer
  puts 'true'  # 0 も true 扱い
else
  puts 'false'
end

if integer.nil?
  puts 'nil'
else
  puts 'not nil'  # 数値/真偽値には empty? がないので nil 判定しかできない
end

array = []

if array
  puts 'true'  # 空配列も true 扱い
else
  puts 'false'
end

if array.empty?
  puts 'empty'  # 配列もこれで空かどうか聞けよってことか
else
  puts 'not empty'
end

ループ

# for in 
for i in object do
  puts i
end

# while
while count <= 10 do
  count += 1
end

# each
object.each do |value|
  puts value
end

# each_with_index
['cat', 'doc', 'fox', 'snake'].each_with_index do |animal, count|
  p animal  # cat, dog, fox ...
  p count   # 0, 1, 2 ...
end

each メソッド自体の返り値は「レシーバ自身 = each したオブジェクトそのもの」。なので「n件処理しました」とか返却したければ count みたいな変数つくらずともこんな感じにできる。

def send_mail
  emails = ['foo@example.com', 'bar@example.com']
  emails.each do |email|
    Mailer.send_notification_to_user(email)
  end
end

iterated = send_mail_to_users
puts "メールを #{iterated.length} 通送信しました!"

ループ / ブロック内の制御構文

他の言語と大きく違うのは、ブロック内で return すると 親メソッドも終了 してしまう点。Ruby では「ループかどうか」に限らず、ブロックスコープ内で処理を中断する場合は next を使う。

break  # 中断してループ抜ける
next   # スキップして次のループへ ( continue )
redo   # 同じ条件でループをやり直す

Exception 例外処理

【Ruby】例外処理
そもそもRailsでカスタム例外を定義すべき機会は少ない
【Rubyアンチパターン】ensure節でreturnしてはならない

Ruby / Rails では「システムエラー」は例外で制御するが、いわゆる「業務エラー/ロジックエラー」は返り値で制御する文化がある。例えば ... do_something if Object.new こんな。このため、システム的なエラーは極力 begin rescue による例外のハンドリングに、業務ロジックのエラーはメソッドの戻り値による制御構造のハンドリングに寄せるのが良さそう。

# いわゆる try catch
begin
  raise 'Invalid error occurred.'  # いわゆる throw new RuntimeException
rescue => error 
  puts error.message    # 例外を error に代入せず特殊変数 $! でもよい
  p    error.backtrace  # 例外を error に代入せず特殊変数 $@ でもよい
  # ここで retry を行うと begin 再挑戦 ( 永久ループ化注意 )
ensure
  # ここがいわゆる finally 
end

# 複数例外の受付
begin
  io = File.open(unverified_file)
rescue Errno::ENOENT, Errno::EACCES  # 存在しない・権限ないを拾う
  io = File.open(safe_file)
end

# raise のパターン
raise 'OH MY OH!!'  # RuntimeError Exception
raise SyntaxError   # SyntaxError Exception
raise SyntaxError.new 'OH MY OH!!'  # message つき

begin
  # ...
rescue
  raise  # rescue 内では最後の Exception を再投げ
end

# 修飾子として rescue 使ってこんなこともできちゃう
default_num = Integer(val) rescue 0

ループ中に例外を rescue して next する

5.times do |time|
  begin
    if time === 2
      raise 'Something wrong occurred!'
    end
    puts time
  rescue => e
    puts e.message
    next  # Skip this, then go to next loop.
  end
end

__END__

# Results.
0
1
Something wrong occurred!
3
4

例外クラスのメソッド

https://docs.ruby-lang.org/ja/latest/class/Exception.html

def hoge
  # do something...
rescue => e
  e.message
  e.full_message
  e.backtrace
end

関数ブロック / スコープ / ラムダ Lambda

【Ruby】ブロック・Proc・lambda を理解する

いわゆるクロージャ。

  • ブロック: do end もしくは {} で囲まれた命令文のかたまり
    • レシーバ self などはブロックごとに文脈が変化
    • Ruby は 「メソッドの引数にブロックを渡す」 なんてことができる
      • users.any? { |user| user.name == 'John' }
  • Proc: プロシージャ / 無名関数オブジェクトと呼ばれる、上記ブロックをオブジェクト化したもの
    • my_proc = Proc.new { puts 'hello' }
      • proc{} でも可
    • メソッド引数に & を利用することで「Proc を受け取る引数である」ことを明示可能
      • def my_method(&proc_as_arg) proc_as_arg.call end
  • Lambda/ラムダ: Proc オブジェクトを作る構文の 1 つ
    • lambda{}->{} で生成可能
    • Proc.newproc{} した場合と 以下の点でふるまいが異なる
      • 引数の数が異なる場合に ArgumentError 例外を吐く
      • ループ中の return などで処理を抜けず最後まで実行する
# Lambda
lambda_proc1 = lambda { |arg| puts arg } # lambda{ } による方法
lambda_proc2 = ->(word) { puts word }    # ->{ } による方法
lambda_proc3 = -> { puts "proc" }        # ->{ } による方法

CLASSES & MODULES

主要な標準クラス/モジュール
Ruby力を高めるためには標準メソッドを学べ

標準クラス/モジュールの詳細は別メモ参照。

Integer

# 絶対値を取得
(-1).abs  # 1

# 浮動小数値の丸め
(2.58926).round(2) # 2.59
1.234567.ceil(2)   # 1.24

String

# 文字列置換
str.gsub(/at/, '@') # gsubは該当する全ての要素を置換する ( atatat なら @@@ に変換 )
str.sub(/at/, '@')  # subは最初の要素だけ置換する ( atatat なら @atat に変換 )

# 末尾改行文字を除去
str.chomp

# 大文字、小文字変換
'abcde'.upcase    # ABCDE
'ABCDE'.downcase # abcde

# 文字列 → 配列
'Alice,Bob,Charlie'.split(',')  # ['Alice', 'Bob', 'Charlie']

# 指定した文字列を含んでいるか確認
'abcde'.include?('bc')  # true
'abcde'.include?('zy')  # false

# 指定した文字列を含んでいれば、その開始位置を返す、存在しなければnilを返す
'abcde'.index('a')  # 0
'abcde'.index('c')  # 2
'abcde'.index('z')  # nil

# 文字列の一部抽出
'abcde'[0]    # a
'abcde'[0,3] # abc

Array

# Length
[1,2,3].length  # 3

# To string
ary.to_s

# Max / Min
[1,3,7,2,5].max  # 7
[1,3,7,2,5].min  # 1

# shift / pop
ary = [1,3,7,2,5]
ary.shift  # 1
ary.pop    # 5 
p ary  # [3,7,2]

# push / unshift
[1,2,3].push(4)     # [1,2,3,4]
[1,2,3].unshift(0)  # [0,1,2,3]

# empty?
[].empty?  # true

# include? 
[1,2,3].include?(1)  # true
[1,2,3].include?(10) # false

# ランダム取得
[1,3,7,2,5].sample # 5 ※結果は毎回ランダムで選ばれる。

# 配列の複製
tmp = self.dup

# 指定したインデックスの要素の削除 ※破壊的メソッド
ary = [0,1,2,3]
ary.delete_at(2)
p ary  # [0,1,3]

Hash

hash_1 = { 'name' => 'John', 'age' => 20 }
hash_2 = { :name  => 'John', :age  => 20 }  # シンボルをキーに
hash_3 = { name: 'John'    , age:     20 }  # hash_2 の省略形

# methods
p hash_1.keys    #=> ['name', 'age']
p hash_2.values  #=> ['Jane', 19]
p hash_3.to_a    #=> [[:name, 'Jack'], [:age, 28]]

# new
new_hash = Hash.new('default')
p new_hash['undefined_key']  #=> default

another_hash = Hash.new do |hash, key|
  hash[key] = key.upcase
end
p another_hash['undefined_key']  #=> UNDEFINED_KEY

# store
new_hash.store('new_key', 'new_value')
p new_hash  #=> {'new_key' => 'new_value'}

# fetch
p new_hash['new_key']        #=> new_value
p new_hash.fetch('new_key')  #=> new_value

h = Hash.new
# p h.fetch('N') #=> Exception(IndexError)
p h.fetch('N', 'Nothing Value') #=> 'Nothing Value'
p h.fetch('N') { String.new }   #=> ''


# delete / delete_if
new_hash.delete('new_key')
p new_hash.empty?  #=> true

profile = { name: 'Bob', age: 18, height: 170, weight: 58 }
profile.delete_if { |key, value| key == :weight }
p profile  #=> {:name=>'Bob', :age=>18, :height=>170}

p profile.reject! { |key, value| key == :nick_name }  #=> 該当がないとき戻り値が nil に
p profile  #=> {:name=>'Bob', :age=>18, :height=>170}

profile.clear
p profile  #=> {}