はじめに
Progate楽しいマンです。
最近学んだことリスト【主にCSS】に続き、Rubyをやりました。
今回は1つの記事にまとまった!あと、少し見やすく書けました。(^^)
相変わらずなっがいので、気になった見出しがあれば見てみてください。
メモず
Rubyの"
と'
は区別なし
言語によっては区別あるので……Rubyは緩い方。
コメントは#
シンプルですこ (^^)
余り計算は%
でOK
`mod`
も好きだけどね
Rubyのputs
の挙動一覧
puts "str " int # 間違った構文
puts "str ", int # "str"<br>int
puts "str #{int}" # str int テンプレート記法
puts 'str #{int}' # str #{int} シングルクォーテーション(')だとテンプレート記法と認識しない。
テンプレート記法は"
の中に#{}
で書くことができる。
文字列と同じ書き方でできる、最高です(^^)
Javascriptでは`
の中に${}
なので混同しないように注意。
Rubyの変数はvarname =
で特定の宣言文はない
変数名はキャメルケースではなくスネークケース
俺のキャメルケースが……
+=
は可能
else if
ではなくelsif
ちょっとキモい……
倫理演算子は ==
, !=
, &&
, ||
===
じゃなくていい!素晴らしい!
or
は||
なので、二個にするの忘れないように。
全部2個だと見た目がそろうのでいいね!素晴らしい設計。
each / for of 文:arr.each do |e|
連想配列は{"key"=>value, ...}
or{:key=>value}
or`{key:value}
JSと違い、key
を"
で囲わなきゃいけない。key
を文字列にしなかった場合は、変数として扱われる(まじかよ)
key = "name"
hash = {key => "John Doe"}
この場合、
hash
のキーは"name"
の文字列となります
Ruby1.9以降では、以下の構文が導入
hash = {key: value} #キーは:keyシンボル
シンボル:key
と文字列"key"
の違いって?
シンボルと文字列の違い
-
イミュータビリティ(変更不可能性):
-
文字列: 文字列は変更可能です。例えば、
str = "hello"
とした後でstr[0] = "H"
によりstr
を"Hello"
に変更できます。 - シンボル: シンボルはイミュータブル(変更不可能)です。一度作成されると、その値は変更できません。
-
文字列: 文字列は変更可能です。例えば、
-
オブジェクトID:
- 文字列: 同じ内容の文字列でも、それぞれが異なるオブジェクトとして作成されます。つまり、毎回新しいメモリが割り当てられます。
- シンボル: 同じ内容のシンボルはアプリケーション全体で同じオブジェクトを参照します。これにより、メモリ使用効率が良くなります。
-
パフォーマンス:
- 文字列: 文字列の比較は内容を1文字ずつチェックするため、比較に時間がかかることがあります。
- シンボル: シンボルの比較はオブジェクトIDの比較になるため、高速です。
混同した場合の影響
-
ハッシュのキーとしての使用: Rubyではハッシュのキーとして文字列とシンボルのどちらも使用できますが、これらは異なるキーとして扱われます。たとえば、
{ :key => "value1" }
と{ "key" => "value2" }
は異なるキーを持つハッシュです。これらを混同すると、意図しない挙動を引き起こす可能性があります。 -
メモリ使用: 文字列を頻繁に作成すると、同じ内容でも異なるオブジェクトがメモリ上に作成されるため、メモリ使用量が増加します。一方、シンボルは同じ内容であれば同じオブジェクトを再利用するため、メモリ効率が良いです。
-
変更可能性: 文字列は変更可能なので、アプリケーションの状態を変更する可能性があります。シンボルは変更不可能なので、このような副作用はありません。
Rubyではnil
と false
以外のすべての値は真と評価される
つまり、undefined
が存在しない。
例えば、連想配列の存在しないキーにアクセスした場合、JSだとundefined
を返すが、Rubyだとnil
を返す。
豆知識:JSのnull
、Rubyのnil
はfalsy
と呼び、false
ではないがfalse
として扱われることがある。
&.
演算子
Rubyの場合、ハッシュに存在しないキーにアクセスしたときは nil
が返されるので、一般的には安全です。ただし、その後に nil
に対してメソッドやさらなるキーへのアクセスを試みるとエラーが発生します。したがって、element[:values]
が nil
でないことを確認することは重要ですが、より簡潔に書く方法もあります。
例えば、以下のように &.
演算子(セーフナビゲーション演算子)を使用すると、element[:values]
が nil
の場合には、それに続くメソッド呼び出しが無視されます:
array = [{values: {a: "v", b: "v2"}}, ...]
array.each do |element|
puts element[:values]&.[](:b)
#[](:key)は[:key]のもともとの形。ここではメソッド呼び出しをしている。
end
この場合、element[:values]
が nil
であれば、[:b]
の呼び出しは無視され、nil
が返されます。これにより、element[:values]
が存在しない場合にエラーを防ぐことができます。また、element[:values]
が存在していても、それがハッシュであり :b
キーが存在しない場合には、やはり nil
が返されます。
この方法は、Ruby 2.3 以降で利用可能です。それ以前のバージョンでは、条件分岐を使用してキーの存在を確認する必要があります。
hash[:key]
はhash.[](:key)
の糖衣構文
そうなん!!いわれてみれば確かに🦀
[](:b)
と [:b]
の違い
element[:values]&.[](:b)
と element[:values]&.[:b]
は実質的に同じ動作をします。ただし、&.
演算子を使用してメソッド呼び出しを行う場合、[](:b)
の形式を使用することで、element[:values]
が nil
であった場合にメソッド呼び出しを無視することができます。一方で、element[:values]&.[:b]
は文法的に不正です。
element[:values]&.[:b]
ではなく element[:values]&.[](:b)
を使用する理由は、セーフナビゲーション演算子 &.
がメソッド呼び出しにのみ適用されるためです。[:b]
はハッシュのキーへのアクセスを示すブラケット構文ですが、これを直接 &.
と組み合わせることはできません。そのため、メソッド呼び出しの形式 [](:b)
を使用します。
Rubyにはfunction
という概念がない!!
すべてメソッドと呼ばれる。
命名規則:真偽値を返すメソッドは末尾に?
をつける
negative?
など
キーワード引数※超便利!!全オブジェクト指向言語に導入すべき
それに対して、普通のを位置引数
と呼ぶ。
キーワード引数は
def method(arg1:, arg2:)
puts "#{arg1}, #{arg2}"
end
method(arg2:"hoge", arg1:"ruby")
method("ruby", "hoge") #error. キーワード引数は位置引数として呼び出せない。
これで機能する。すごい。
あと、発展形として
def method(arg1, arg2:"arg2!!")
puts "#{arg1}, #{arg2}"
end
method("ruby", arg2:"hoge") # ruby, hoge
method("ruby") # ruby, arg2!! ※初期値arg2!!が設定されているため
method(arg2:"hoge", "ruby") #error. キーワード引数は位置引数の後。
初期値の設定、キーワード引数と位置引数の混合も可能。
どっちも便利だなあ……
毎回呼び出さない、いわばアディショナルになる引数はキーワードで初期値を設定しておいて、それ以外は位置引数で毎回渡す、ってことが可能
例
#今日の日付を取得
today = Date.today
#日記を保存する
def diary(title, content, date:today)
#日記を作成。日付がdate, タイトルがtitle, 内容がcontent
end
#今日の日記
diary("rubyを学んだ", "キーワード引数とか、おもしろいことがいっぱいあった")
#書き忘れた昨日の日記
diary("CSSを学んだ", "デザインって、やっぱ楽しいなと思った", date:"2024-01-12")
なお、初期値の設定はJSでもできるようになってたっぽい(ES6)
知らなかった……
function greet(name, greeting = "Hello") {
return `${greeting}, ${name}!`;
}
console.log(greet("Alice")); // "Hello, Alice!"
console.log(greet("Alice", "Hi")); // "Hi, Alice!"
命名規則:クラスは大文字で始める
class Menu
てきな
ボクが苦手な「クラス」という概念
@
:インスタンス変数
オブジェクトごとに存在する変数
initialize
:コンストラクタ
new
したときに実行されるメソッド。rubyではdef initialize
例
class Person
def initialize(name, age)
@name = name # インスタンス変数の設定
@age = age # インスタンス変数の設定
end
def greet
"Hello, my name is #{@name} and I am #{@age} years old."
end
end
# クラスからオブジェクトを生成
alice = Person.new("Alice", 30)
# オブジェクトのメソッドを呼び出す
puts alice.greet # => "Hello, my name is Alice and I am 30 years old."
なお、@name = name
とself.name = name
どちらでも機能するが、大きな違いがある。
@name = name
-
@name = name
は、インスタンス変数@name
にローカル変数name
の値を直接割り当てます。 - この表現は、Rubyのインスタンス変数に直接アクセスし、値を設定する最も基本的な方法です。
self.name = name
-
self.name = name
は、name=
という名前のセッターメソッドを呼び出し、そのメソッドを通じて@name
インスタンス変数に値を設定します。 - この方法は、
attr_accessor
またはattr_writer
によって自動的に生成されたセッターメソッドを利用します。 - セッターメソッドを通じて値を設定することで、追加の検証や処理を行うことができます。
どちらを使用するべきか
-
直接割り当て (
@name = name
): 値を直接設定するだけの場合、または特別な検証や処理が不要な場合に適しています。 -
セッターメソッド経由 (
self.name = name
): セッターメソッドに特別なロジック(例えば、検証、変換、ロギングなど)が含まれている場合に適しています。また、将来的にセッターメソッドの挙動を変更する可能性がある場合にも有用です。
attr_accessor
:ゲッターとセッターを設定
アトリビュート(属性・プロパティ)へのアクセサを設定する。
具体的には以下の2つ
- ゲッターメソッド: インスタンス変数の値を取得するメソッド
-
セッターメソッド: インスタンス変数に値を設定するメソッド
例
class Person
attr_accessor :name, :age
def initialize(name, age)
@name = name
@age = age
end
end
person = Person.new("Alice", 30)
puts person.name # => Alice #ゲッターメソッド
person.name = "Bob" #セッターメソッド
puts person.name # => Bob
類似メソッドとして、以下のものがある
-
attr_reader
: ゲッターメソッドのみを生成 -
attr_writer
: セッターメソッドのみを生成
なんでわざわざattr_accessor
と記述しないと記述しないとアクセスできないの?
不便じゃない?と思ったキミ!
危険なのだ!不必要なアクセスはバグの温床なのだ!
インスタンスメソッド
new
でインスタンスを作った後に使われるメソッド
インスタンスから呼び出す。当然クラスからは呼び出せない。
例
class Person
def initialize(name)
@name = name
end
def greet #インスタンスメソッド
"Hello, my name is #{@name}"
end
end
alice = Person.new("Alice")
puts alice.greet # => "Hello, my name is Alice"
なお、initialize
もインスタンスメソッドに属する。ただし直接呼び出すことはできない。
クラスメソッド
クラス自体に属するメソッド。インスタンスからは呼び出せない。
def self.method_name
やclass名
を用いて定義される。
例
class Person
def self.describe #Person.describeでも同じ。ただ、selfの方がクラス名の変更に対応できる。
"This is a Person class"
end
end
puts Person.describe # => "This is a Person class"
me = Person.new
puts me.describe # これはエラーになります
クラシックな例
class MyClass
@class_instance_var = "初期値"
# クラスインスタンス変数へのアクセス用のクラスメソッド
def self.class_instance_var
@class_instance_var
end
# クラスインスタンス変数を設定するためのクラスメソッド
def self.class_instance_var=(value)
@class_instance_var = value
end
end
# クラスメソッドを通じてクラスインスタンス変数を取得
puts MyClass.class_instance_var # => "初期値"
# クラスメソッドを通じてクラスインスタンス変数を設定
MyClass.class_instance_var = "新しい値"
puts MyClass.class_instance_var # => "新しい値"
クラスの継承<
class Food < Menu
など
オーバーライド&super
親クラスのメソッドを子クラスで「上書き」すること
class Person
def initialize(name, age)
@name = name
@age = age
end
def info
"Name: #{@name}, Age: #{@age}"
end
end
class Employee < Person
def initialize(name, age, job)
super(name, age) # 親クラスのinitializeメソッドを呼び出し
@job = job # 従業員固有の属性
end
def info
"#{super}, Job: #{@job}"
end
end
employee = Employee.new("Alice", 30, "Developer")
puts employee.info # => "Name: Alice, Age: 30, Job: Developer"
#キーワード引数の場合
def initialize(name:, price:, calorie:)
super(name: name, price: price) #(parent_keyword_arg: child_arg)
self.calorie = calorie
end
require
:インポート文
require "./parts
など。.rb
拡張子は省略するのが通例。
Rubyの
require
メソッドはデフォルトで.rb
または.so
(またはプラットフォームに応じた適切なバイナリファイルの拡張子)を探します。他の種類のファイルを読み込む場合、特に.js
や.json
などの非Rubyファイルを読み込む場合は、明示的に拡張子を指定する必要があります。
gets.chomp
:コンソールからの入力を取得
gets
:コンソールを入力待機状態にする
chomp
:文字列の末尾にある改行文字(\n
や \r\n
)を取り除く。主に「がぶりとかじる」や「むしゃむしゃ食べる」といった意味で使われる動詞
gets.chomp
取得された文字列には、ユーザーがEnterキーを押した際に生成される改行文字(\n
)が含まれているため、chomp
と併せて使用される。
.to_i
おもろい。確かにこの命名でいいよなあ、ってなる。
他
.to_f
:float
.to_s
:string
.to_sym
:symbol
←初めて見た。文字列に対して使うっぽい。
.to_h
:hash
←すごい。
[["key1", "value1"], ["key2", "value2"]].to_h
# => {"key1" => "value1", "key2" => "value2"}`
追記:extend
とinclude
モジュールの読み込み方
extend
はクラスメソッドとして
include
はインスタンスメソッドとして読み込む
終わりに
久しぶりにコードかけて気持ち良かった……
CSSも楽しかったけど、やっぱ動くのがいいですね。
次はRails!SNSを作れるとのことで、非常に楽しみ。SNSのレイアウトを使って実装したいアイデアもあるので、モチベ高めです。明日から。