1
0

ruby文法復習用ノート

Last updated at Posted at 2024-03-20

この記事は「こんな書き方もあったな」というのを簡単に 復習 できるように作りました。そのため、実行結果が書いていなかったり、コード内で未定義の変数を使っていたりします。予めご了承ください。

間違い等ありましたら遠慮なくコメントください。

参考

たのしいRuby、高橋征義、後藤裕蔵著、 まつもとゆきひろ監修、SBクリエイティブ株式会社、第6版2019年

1. 基本

  • 動的型付け言語なので、型を明示的に指定はしない
  • オブジェクト指向型言語なので、データをオブジェクトで表現する
  • a = 3
  • b = "文字列"
  • nil : nullのこと
  • 条件ではnilとfalseを偽、それ以外を真としている
  • do endで囲まれている部分をブロックと言う
  • 配列やハッシュに*を付けると、そのオブジェクトを展開することができる
  • Rubyではスネーク方式で命名する
  • Rubyにおけるthenは省略可能
  • do end{ }と書くこともできる
  • b=aとしたとき、aに破壊的な変更をするとbも変わる。a.freezeで防げる
  • a.dupでオブジェクトをコピー

2. 文字列

"文字列"
%Q{ ""とほぼ同じ文字列 } # "がエスケープされる
'特殊文字をそのままにする'
%q| ''とほぼ同じ文字列 | # 'がエスケープされる
"\n"
"\\n"

2.1 メソッド

2.1.1 非破壊的

print "あいう", x , "\n"
print "あいう#{x}\n"
puts # 文字列の最後で改行
p # 型に合わせて表示、特殊文字もそのまま表示 
pp # オブジェクトの構造に合わせて改行もしてくれる
printf("あいうえお") # C言語の`printf`とほぼ同じ
sprintf("あいうえお") # ただ文字列オブジェクトを作るだけ
format("あいうえお") # sprintfと同じ。%bなどで形式をしていする
s.to_sym # シンボルに変換
`コマンド` # コマンドの出力を文字列オブジェクトにする
s.length
s.size # lengthと同じ
s.bytesize
s[0]
s[2,8]
s1 + s2
s1 << s2
"あいう" < "あいえ"
s.freeze # 変更不可能
# # frozen-string-literal :trueとコメントを書くことで、そのスクリプト内の全ての文字列に.freezeを付けたことになる

2.1.2 破壊的

s.index("a")
s.rindex("a")
s.include?("a")

2.1.3 !を付けると破壊的になる

s.chop # 末尾を1文字削る
s.chomp # 末尾の改行を削る
s.strip # 先頭と末尾の空白を取り除く
s.upcase
s.downcase
s.swapcase
s.capitalize
s.tr("a","A")
s.tr("ac","CA")
s.tr("a-e","A-E")

2.2 ヒアドキュメント (筆者の理解が足りてないので簡単に)

<<"EOB" # これは"あいうえお"と同じ
あいうえお
EOB

<<-"EOB" # 区切り文字の行頭の空白文字とタブ文字を無視
あいうえお
EOB

<<~"EOB" # 行頭の空白文字とタブ文字を無視
あいうえお
EOB

3. シンボル

  • 文字列と似たオブジェクト
  • 「シンボル」という型があると考えればよい
  • 以下2つは同じもの
    • x = :a
    • x = :"a"
  • x.to_s : 文字列に変換

4. 配列

  • Rubyは0始まり

4.1 配列の生成

a = Array.new
a = Array.new(3)
a = Array.new(3,0)
a = %w(I like basketball)
a = %i(i like basketball) # 要素がシンボルになる
a = "I,like,basketball".split(',')
a = [1, 3, "hello", 2]

4.2 配列の参照

  • 配列の要素数を超えたインデックスを参照した場合はエラーではなくnilが返る
  • 負の値のインデックス-nを参照した場合は、配列の最後からn番目を返してくれる
puts a[0]

# 配列の要素数を超えたインデックスを参照した場合は、最後の要素を指定したことになる
puts a[0..2] # -1..1とかはだめ
puts a[1,2] # -2..2とかはできるけど、配列の最後から最初に戻ることは無い
puts a.value_at(0,2,3)

a[0] = "hi"
a[1..2] = [4,5,6,7,8]
a[2,3] = [4,5,6,7,8]
a[2,0] = [4,5,6,7,8]

a.each do |i|
  puts i
end

4.3 メソッド

先頭要素を 末尾要素を
加える(破壊的) unshift push
取り出す(破壊的) shift pop
参照する first last

4.3.1 破壊的メソッド

a.unshift(3)
a.push(3)
a << 3
a.shift
a,pop
a.concat(b)
a.delete(3)
a.delete_at(3)
a.delete_if { |i| i>3 }
a.fill(5) # 置き換え
a.fill(5,3)
a.fill(5,3,4)
a.fill(5,3..4)

4.3.2 非破壊的メソッド

a.size
a & b # 積集合
a | b 和集合
a + b # "|"と似ているが、重複を許す
a - b
a.first
a.last
a.sort_by { |i| i.size }
a.zip(b,c){ |i,j,k| puts i+j+k }

4.3.3 !をつけると破壊的になる

a.compac # nilを除く
a.reject { |i| i>3 }
a.uniq # 重複を無くす
a.collect { |i| i*2 } # 置き換え
a.map { |i| i*2 }
a.flatten # 入れ子になった配列を1つの配列にする
a.reverse
a.sort
a.sort { |i, j| i.size <=> j.size }
a.slice(3)
a.slice(3..5)
a.slice(3,2)

4.3.4 初期化

a = Array.new(3,[0,0,0]) # 3つの要素が全て同じオブジェクトになる
a = Array.new(3) do
  [0,0,0]
end
a = Array.new(3) { |i| i**2 }

5. ハッシュ

key1 == key2 && key1.eql?(key2)のときのみ同じキーだと判断される

5.1 基本

h = {:basket=>5, "soccer"=>11, 9=>"baseball"}
h  = {basket: 5, soccer: 11} # シンボルをキーにする場合
h = Hash.new
h = Hash.new(1) # 登録されてないキーを指定された時のデフォルト値
h = Hash.new do |hash, key|
  hash[key] = key.length
end
h.fetch(:basket,1) # 登録していないキーならデフォルト値を返す

h[:basket]
h["soccer"]
h[9]
h[:basker] = 10
h.each do |key, value|
  puts key, value
end

h = {
  :sports => {:basket => 5, :baseball => 9}, 
  :music => {:solo => 1, :duo => 2}
}

# 以下4つは同じ
h.key?(:basket)
h.has_key?(:basket)
h.include?(:basket)
h.member?(:basket)

h.value?(5)
h.has_value?(5)

# キーの数
h.size
h.length

h.empty?

5.2 破壊的メソッド

h.delete(:basket)
h.delete(:no) do |key|
  puts key # キーが存在しないときの処理
end

h.delete_if do |key, value| # 条件に当てはまるのが無い時は元のハッシュを返す
  key == :soccer
end

h.reject! do |key, value| # 条件に当てはまるのが無い時はnilを返す
  key == :soccer
end

h1.merge(h2)

g = h
h.clear

6 コメント

#コメント

=begin
コメント
=end

7 条件

  • 偽 : falsenil
  • 比較演算子 : > < == !=
    • === : 左辺がStringやInteger→==,左辺がRegexp→=~,左辺がクラスオブジェクト→右辺が左辺のインスタンスかどうか
  • 論理演算子 : && || !

7.1 メソッド

  • 語尾に?を付ける
  • empty? : 文字列や配列が空ならtrue
  • nil? : nilならtrue
  • blank? : empty?nil?の倫理和

7.2条件文

if a >= 10 then
  puts "aは10以上"
elsif a >= 0 then
  puts "aは0以上"
else
   puts "aは0未満"
end

puts "aは0" if a == 0

unless a >= 10 then
  puts "aは10以上ではない"
end

puts "aは0でない" unless a == 0

// case文は`===`で判定してる
case a
when 1, 2, 3 then
  puts "aは1or2or3"
when 4 then
  puts "aは2"
when 5, 6 then
  puts "aは5or6"
else
  puts "それ以外"
end

// aの所属するクラスでも分岐できる
case a
when String then
  puts "aはString"
when Numeric then
  puts "aはNumeric"
else
  puts "それ以外"
end

## 7.3 条件演算子(三項演算子)
max = a>b ? a : b

# Rubyにおいて条件文は、最後に評価した値を返す、関数のようなもの
x = if a > b
  a
else
  b
end

8. 繰り返し(イテレーター)

while i<10
  puts i
  i = i+1
end

until i>=10
  puts i
  i = i+1
end

10.times do
  puts "hello"
end

10.times do |i|
  puts "#{i}回目の繰り返し"
  # ※0始まり
end

0.upto(9) do |i|
  puts i
end

9.downto(0) dp |i|
  puts i
end

# => 0,2,4,6,8
0.step(5, 2) do |i|
  puts i
end

object = 1..3
object = ["a", "b", "c"]

# 内部処理はeach文
for i in object do
  puts i
end

object.each do |i|
  puts i
end

loop do
  puts "hello"
end

break:繰り返しを終了
next:次の繰り返しに移動
redo:もう1度同じ繰り返し

9. メソッド

  • インスタンスメソッド
    • オブジェクトをレシーバーとするメソッド
    • a.next
  • クラスメソッド
    • クラスをレシーバーとするメソッド
    • File.open
    • クラス名.メソッド or クラス名::メソッド
    • ドキュメントに書く際はクラス名#メソッド
  • 関数的メソッド
    • レシーバーが省略されているメソッド
    • print

9.1 メソッド定義

  • メソッド名を数字で始めてはいけない
  • returnを省略した場合、メソッドの中で最後に得られる値を返す
  • returnを省略した場合やprintメソッドはnilを返す
  • 仮引数は組み合わせて使える
  • 実引数にハッシュを使うときは{}を省略できる
def f
  puts "Hello"
end

def f(a)
  puts a
end

def f(a,b,c)
  puts a,b,c
end

array = [1,2,3]
f(*array)

def f(a=3)
  puts a
end

# デフォルト値は右から指定する
def f(a, b, c=3)
  puts [a,b,c]
end

def f(a)
  return a
end

# *を付けると配列になる
def f(*a)
  puts a
end

f(1,2,3)

def f(a, *b)
  puts a,b
end

def f(a, *b, c)
  puts a,b,c
end

# キーワード付きで呼び出せる
def f(a:, b:)
  puts a
end

f(a:1, b:2)
hash = {a:1, b:2}
f(hash)

def f(a: 1)
  puts a
end

# 定義していないキーワード引数を呼び出す

def f(**a)
  puts a
end

f(x: 1)

alias new_f f
alias :new_f :f

undef f
undef :f

9.2 ブロック付きメソッド

  • yieldで、与えたブロックをそのまま実行
  • yieldの引数の数とブロックの変数の数が違う場合は、足りない部分はnilとなる。多い部分は受け取らないだけ
  • ブロックの中でbreakを呼ぶと、ブロック付き呼び出しの場所まで一機に帰ってくるため、メソッドの返り値はnilとなる
  • break 0などとすることで返り値を指定できる
def f
  yield
end

f do
  puts "hello"
end

def f
  if block_given?
    yield(3)
  end
end

f do |i|
  puts i*i
end

def f
  if block_given?
    yield(3,4)
  end
end

f { |i, j| puts i*j }

array.each do |a|
  puts a
end

hash.each do |i, h|
  puts i
  puts h
end

file = File.open("a.txt")
file.each_line do |line|
  puts line
end
file.close

# 確実にファイルを閉じてくれる
File.open("a.txt") do |file|
  file.each_line do |line|
    puts line
  end
end

array.sort { |a, b| a.length <=> b.length }
array.sort_by{ |i| i.length }

# 多くのイテレーターはブロックが与えられないときはEnumeratorオブジェクトを返すから、collectやmapなどを続けて呼び出せる
s.each_line.collect do |line|
  line*2
end

s.each_byte.collect do |byte|
  byte & 1
end

s.each_char.collect do |char|
  char.next
end

10. ブロックをオブジェクトとして受け取る

a = Prock.new do |i|
  puts i
end

a.call(3)

# 最後の仮引数に`&`を付けると、実引数は`Proc`オブジェクトに包まれて渡される(ブロック引数)
def f(a, &b)
  puts a
  puts b.call(3)
end

f(5) do |i|
  i**2
end

def g(&c)
  f(&c)
end

array.each do |i; j|
  # iはブロック内だけで有効な変数。ブロックの外側と同じ名前の変数をブロック内で使いたいときとかに。
end

11. 他のファイルを取り込む

  • require "a.rb" : カレントディレクトリからの相対パス。Gemファイルなどを呼び出すのに使う
  • requre_relative "a.rb" : 実行ファイルからの相対パス。自分で作成したファイルなどを呼び出すのに使う
  • .rbは省略可能

12. 変数

  • ローカル変数 : _localまたはlocal
  • グローバル変数 : $glocal
  • インスタンス変数 : @instance
  • クラス変数 : @@classvariable
  • 定数 : Constant

13. 予約語

  • 名前として使えない英単語
__LINE__ __ENCODING__ __FILE__ BEGIN END alias and begin break
case class def defined? do else elsif end ensure
false for if in module next nil not or
redo rescue retry return self super then true undef
unless until when while yield

14. 多重代入

a, b, c = 5, 6, 7
a, b, *c = 5, 6, 7, 8, 9
a, *b, c = 5, 6, 7, 8, 9
a, b = b, a

array = [1, 2]
a, b = array
a, = arrayf

15. クラス

15.1 基本

  • スーパークラス:継承元のクラス
  • サブクラス:継承先のクラス
  • Rubyの全てのクラスはBasicObjectクラスのサブクラス
  • 通常のオブジェクトはObjectクラスのサブクラス
  • インスタンス変数
    • 同じインスタンス内なら値の参照、変更が可能
    • @を付ける
    • 定義する必要は無い
    • 初期化されていない場合nilを返す
  • クラス変数
    • @@を付ける
    • クラスの全てのインスタンスで共通
    • attr_accessorなどは使えない
  • クラス内のメソッドでは、そのメソッドのレシーバーをselfで呼び出せる
  • クラス内のメソッド内でメソッドを呼ぶ際には、レシーバーは暗黙にselfとなる
  • アクセス制限
    • initializeメソッドは常にpublic

    • public

      • インスタンスメソッドとして使えるように公開
    • private

      • レシーバーを省略した形でしか呼び出せなくする
      • 事実上インスタンスの外側から利用することができなくなる
    • protected

      • 同一のクラス、サブクラスなら、インスタンスメソッドとして使える
  • 既存のクラスにメソッドを追加することもできる
a = Array.new
array.class
array.instance_of?(Array)
array.is_a_(Object)
array.ancestors
array.superclass

15.2 クラス定義

class A
  Const = 3
  @@ count = 0
  def initialize(x)
    @x = x
  end

  public :x=

  private
  
  def set_y(y)
    @y = y
  end
  
  def z= (z)
    @z = z
  end

  def output
    puts @x,@y,@z
  end

  public :output
end
  
  
  aa = A.new(1)
  aa.set_y(2)
  aa.z = 3
  aa.output
  A::Const

class B
  attr_reader :x
  attr_writer :y
  attr_accessor :z
end

15.3 クラスメソッド

class << A
  def f
    puts "hello"
  end
end

class A
  class << self
    def f
      puts "hello"
    end
  end
end

class A
  def self.f
    puts "hello"
  end
end

def A.f
  puts "hello"
end

A.hello
A.instance_methods

# 特定のオブジェクトのみメソッドを定義できる(特異メソッド)
str = "hello"

class << str
  def f
    puts "hello"
  end
end

str.hello

15.4 継承

  • Rubyでは単純継承(単一継承)
    • 複数のスーパークラスを持つことができない
class MyArray << Array
  def [](i)
    ii = i % size
    # スーパークラスの同名メソッドを呼び出す
    super(ii)
  end
end

16 モジュール

16.1 基本

  • Rubyでは名前空間
  • 大文字で始める
module M
  def f
    puts "hello"
  end  
  modulle_function :f
end

# モジュール関数
M.f

include M
f

16.2 Mix-in

  • 仮想的なスーパークラスとして振る舞う
  • include
    • インスタンスメソッドを追加
    • moduleを後ろへ追加する
  • prepend
    • インスタンスメソッドを追加
    • moduleを前を追加する
  • extend
    • オブジェクト単位でモジュールをインクルード
    • もう一つの機能としてクラスメソッドを追加できる
# A → M → Object 
class A
  include M
end

aa = A.new
aa.f
A.include?(M)

# M → A → Object 既存のメソッドを変更できる 
class A
  prepend M
end

srt = "hello"
str.extend(M)
str.f

class A
  extend M
end

17. 演算子

17.1 代入演算子

&&= ||= ^= &= |= <<= >>=
+= -= *= /= %= **=

17.2 ビット演算

~ & | ^ >> <<

17.3 論理演算子

  • 左側から順番に評価
  • 論理式の真偽が決定すると、残りの式は評価されない
  • 最後に評価された式が論理式全体の値になる
s = s || "hello"
# 変数にデフォルト値を与える定番の書き方
s ||= "hello"
s = array && array.first
s = array&.first

17.4 範囲演算子

  • 内部的にはsuccメソッドを呼んでいる
r = Range.new(1, 5)
1..5
(1..).take(5)
1...6
"a".."b"
r.to_a

17.5 演算子定義

  • 再定義できない演算子
    • :: && || .. ... ?: not = and or

class A

  # 二項演算子
  # 演算子をメソッド名として、メソッドを定義する
  # 仮引数としてotherを用いることが多い
  def +(other)
    self.class.new( x + other.x, y + other.y)
  end

  # クラス名を入れてしまうと、継承したサブクラスでもAオブジェクトが返ってしまう
  def -(other)
    A.new(x - other.x, y - other.y)
  end


  # 単項演算子
  # `@`を付け絵定義する
  def +@
    dup # オブジェクトの内容をコピーしたものを返す
  end


  # 添え字メソッド
  def [](index)
  end

  def []=(index, val)
  end
end

18. 例外処理

18.1 基本

begin
  # 処理
rescue => e
  puts $!
  puts $@
  puts e.class
  puts e.message
  puts e.backtrace
  retry
end

# 例外クラスを指定しないと、StandardErrorとそのクラスを補足する
begin
  # 処理
rescue Errno::ENOENT, Errno::EACCES
  # 例外処理
end

x = Integer(val) rescue 0

def f
  # 処理
rescue => e
  #例外処理
end

begin
  # 処理
rescue
  # 例外処理
ensure
  # 後処理
end

18.2 例外発生

raise "エラー"
raise StandardError
raise StandardError, "エラー"

# `rescue`節内では、最後に発生した例外をもう一度発生させる
# `rescue`節外では、`RuntimeError`を発生
raise

19. 代表的なエラーメッセージ

  • syntax error : 文法ミス
  • NameError : 定義していないものが使われている
  • ArgumentError : 引数ミス
  • TypeError : メソッドの引数の型が違う
  • LoadError : ライブラリを読み込めない
  • `[BUG] : Rubyや拡張ライブラリのエラー

20. Numeric

  • Rubyはオーバーフローが無いらしい(いくらでも大きな値を扱える)
  • 数値中の_は無視される
  • IntegerFloatの掛け算はFloatになる
  • Math~モジュールに色々なメソッドがある -Math.sin(3.14)`
    • Math.sqrt(2500)
  • 変換 : to_f to_i to_r to_c
123 or 0d123 10進法整数
0123 or 0o123 8進法整数
0x123 16進法整数
0b0101 2進法整数
12.3 or 1.23e2 浮動小数点数
12.3r 有理数
123i 虚数
# 有理数(分数)
a = Rational(1,3)
a.numerator
a.denominator
# 複素数
b = Complex(1,3)
b.real
b.imaginary

3**3
5.div(3) # =>1
5.quo(3) # =>5/3
5.modulo(3) # 5%3
5.remainder(3) #=> 余り。符号は5に等しくなる
5.divmod(3) # => [1,2]

1.23.round
1.23.round(1)
1.23.ceil # => 2
1.23.floor # => 1

21. 乱数

# 0以上1未満のFloat型を返す
Random.rand

# 0以上3未満の整数型を返す
Random.rand(3)

# 0以上3未満のFloat型を返す
Random.rand(3.0)

# 種を与える
Random.new(1)

22. 正規表現

22.1 基本

  • =~で、何文字目で一致したかを返す

  • 大文字小文字の区別無し"abcde" =~ /bc/i

  • -[]の中の最初か最後になることで、単なる文字の-として扱われる

r = /a/
r = Regexp.new("a")
r = Regexp.escape("a") # メタ文字をエスケープする
r = Regexp.quote("a") # escape
r = Regexp.new("a", Regexp::IGNORECASE) # オプションを付ける
r = %r(a) # /がエスケープされる
r = %r<a>
r = %r|a|
r = %r{a}

"abc" =~ /a/
"abc" =~ /^a/ # 行頭 ※文字列の頭ではない
"abc" =~ /a$/ # 行末
"abc" =~ /[abc]/ # aまたはbまたはc
"abc" =~ /[A-Z]/ # A~Z
"abc" =~ /[a-z]/
"abc" =~ /[0-9]/
"abc" =~ /[A-Za-z]/
"abc" =~ /[A-Z0-9p]/
"abc" =~ /[^a]/ # a以外
"abc" =~ /./ # 任意の文字
"abc" =~ /\s/ # 空白、タブ、改行文字、改ページ文字 ※全角空白にはマッチしない
"abc" =~ /\d/ # 0-9 
"abc" =~ /\w/ # A-Za-z0-9
"abc" =~ /\A/ # 文字列の先頭
"abc" =~ /\z/ # 文字列の末尾
"abc" =~ /\[/ # メタ文字を普通の文字として扱う 
"abc" =~ /a*/ # 0回以上の繰り返し(一番長い部分にマッチ)
"abc" =~ /a*?/ # (一番短い部分にマッチ)
"abc" =~ /a+/ # 1回以上(一番長い部分にマッチ)
"abc" =~ /a+?/ # (一番短い部分にマッチ)
"abc" =~ /a?/ # 0または1
"abc" =~ /a{3}/ # 3回の繰り返し 
"abc" =~ /a{3, 5}/ # 3~5回の繰り返し
"abc" =~ /(abc)+/ # abcの繰り返し
"abc" =~ /a|b/ # aまたはb
"abc" =~ /a/i # 大文字小文字の違いを無視 
"abc" =~ /a/x # 正規表現内での空白、#以降を無視する。正規表現内にコメントを書きたいときなど
"abc" =~ /a/m # .が改行文字にもマッチ 
"abc" =~ /a/mi # mとi

22.2 キャプチャ(後方参照)

  • $nでn番目の()内のマッチした文字列を取り出せる
"abc" = /(.)(.)(.)/
$1,$2,$3

"abc" =~ /(.)(?:.)(.)/ # ?:をつけるとキャプチャ時に無視される
$1,$2

"abc" =~ /b/
$` # マッチ部分より前
$& # マッチした部分
$' # マッチした部分より後ろ

22.3.1 破壊的メソッド

s.sub(/a/,"A") # 最初にマッチしたところを置き換える。ブトックを取ることもできる
s.gsub(/a/,"A") # マッチしたところ全てを置き換える

22.3.2 非破壊的メソッド

s.scan(/a/) # マッチする部分を配列の形で取得
s.scan(/(a)(b)/) # 二次元配列になる
s.scan(/a/) do |m| # なぜかこの形式でも書ける
  puts m
end
s.scan(/(a)(b)/) do |a,b|
  puts a,b
end 

23. IOクラス

23.1 基本

  • 標準入力:$stdinからデータを受け取る
  • 標準出力:$stdoutへ出力
  • 標準エラー出力:$stderrへ出力
  • コマンドラインからの読み込み
    • i個目のコマンドライン引数をAGRV[i]のようにして取得できる
    • 0始まり
    • 型は文字列
# 標準出力の出力先をtext.txtに変える
# 標準エラー出力の出力先はコンソールのまま
ruby a.rb > test.txt
$stdin.tty? # 標準入力がコンソールかどうか

23.2 メソッド

# ファイルからの読み込み
file = File.open("a.txt")
file = Open("a.txt")

file = File.open("a.txt","r") #  読み込み専用
file = File.open("a.txt","w") # 書き込み専用、ファイルが無ければ新たに作成、ファイルサイズを0にして書き込む
file = File.open("a.txt","a") # 追加書き込み専用

file = File.open("a.txt","r+") # 読み込み、書き込み 
file = File.open("a.txt","w+")
file = File.open("a.txt","a+")

file.close # File.openにブロックを渡すことで自動的にcloseされる
file = File.open("a.txt")
s = file.read(5) # 5バイト分読み込む。引数省略時は全て読み込む
puts s
file.close

puts File.read("a.txt")

file.closed?
File.binread("a.txt") # バイナリーモード
File.write("a.txt","hello")
Filebinwrite("a.txt", "010101")

# 引数で区切られたものずつ読み込む(引数省略では"\n")
file = File.open("a.txt")
file.each_line do |line|
  p line
end
file.close

file.each("\n") do |line|
  p line
end

while line = file.gets("\n")
    puts line
end

file.each_char do |c| # 1文字ずつ
  puts c
end

while c = file.getc
  puts c
end

file.ungetc("a") # "a"をfileに戻せる(ファイル自体が変更されるわけではない)

file.each_byte do |b| # 1バイトずつ
  puts b
end

while b = file.getbyte
  puts b
end

file.ungetbyte("01") # 1バイト分の文字列をfileに戻す

file.readlines("\n") # 各行を要素とする配列の取得
file.lineno # 何行読み込んだか。変更可能な変数だが、ファイルポインタが変更されるわけではない

# 出力
file.puts 3 # 自動的にto_sが呼び出される
file.putc("abc") # 最初の1文字だけが出力
file.putc(50) # 文字コード50の文字が出力
file.write("abc") # 出力したバイト数を返す
file << "a" << "b"

# ファイルポインタ
file.pos
file.pos = 0
file.seek(5, IO::SEEK_SET) # 5の位置にファイルポインタを移動
file.seek(5, IO::SEEK_CUR) # 今の位置から5先に移動
file.seek(5, IO::SEEK_END) # ファイルの末尾から5の位置に移動
file.rewind # ファイルポインタの戦闘に戻す
file.truncate(5) # ファイルの長さを5に切り詰める
file.truncate(file.pos) # 現在のファイルポインタ以降を削除
file.binmode # バイナリーモードに変更
file.popen("コマンド") # fileから入力されたデータを使ってコマンドを実行する。コマンド実行時に得られる出力を返す


require "open-uri" # urlを普通のファイルのように開ける
require"stringio" # ファイルのような疑似的なオブジェクトを作れる 

24. Fileクラス

File.rename("a.txt","b/c.txt") # a.txtをb/c.txtにする
File.delete("a.txt")
File.unlink("a.txt") # delete
require "fileutils" # ファイルのコピーや移動等
file.stat # ファイルの情報色々
File.ctime("a") # ファイル状態の最終変更時刻
File.mtime("a") # ファイルの最終変更時刻
File.atime("a") # ファイルの最終参照時刻
File.utime(Time.now, Time.now, "a") # atime,mtimeを変更
File.exsist?("a") # 存在するか
File.file?("a") # ファイルか
File.directory?("a") # ディレクトリか
File.readable?("a")
File.writable?("a")
File.size("a")
File.size("a") # aのサイズが0より大きいか
File.zero?("a") # サイズが0か
File.basename("a/b/c") # ファイル名であるcを返す
File.dirname("a/b/c") # a/bを返す
File.extname("a/b/c") # 拡張子を返す
File.split("a/b/c") # ["a/b","c"]
File.join("a/b", "c") # "a/b/c"
File.expand_path("a","b") # ディレクトリb内での相対パスaを、絶対パスにする。bが省略されたときはカレントディレクトリを指定したときになる
__FILE__ # 現在のソースファイル名

require "find" # ファイルを検索できる
require "tempfile" # 一時ファイルの管理に便利
require "fileutils" # ファイルの移動や作成などが簡単にできる

25. Dirクラス

Dir.pwd
Dir.chdir("a") # cd

dir = Dir.open("a") # Fileクラスと同じメソッドが多い
while n = dir.read
  puts n
end
dir.close
dir.each do |n|
  puts n
end
dir.read

# globによって、ターミナルと同じように*や?などのパターンを使うことができる
Dir.glob("*") # カレントディレクトリの全てのファイル名を取得
Dir.glob(".*") # カレントディレクトリの、隠しファイルを含む布部手のファイル名を取得
Dir.mkdir("a")
Dir.rmdir("a")

__dir__ # 現在のソースファイルのディレクトリ名

26. 文字コード

  • Rubyの文字列、正規表現は、文字列のデータと、文字コードをセットで保持している
  • 正規表現は同じエンコーディングの文字列とのみマッチする
  • コマンドラインでruby -E Shift_JIS test.rbirb -E Shift_JISなどと書くことで出力用の文字コードを指定
  • Fileクラスにおいて、openreadなどでもencodingを指定できる
# encoding: Shift_JIS コメントでこれを書くことで、ソースコードの文字コードを指定できる
s.encoding
s.encode("utf-8")

# Encodeクラス
Encoding.compativle?(s1, s2) # s1とs2に互換性があるか(連結できるか) 連結した際の文字コードを返す
Encoding.find("shift_jis") # #<Encoding:Shift_JIS>
Encoding.list # 一覧を返す
Encoding.name_list
Encoding.find("shift_jis").name # "Shift_JIS"

### nkfライブラリ
# s.nkf(オプション文字列、変換する文字列)
# 文字コードのみを変換する場合は、-xm0を常に指定するのが良き
NKF.nkf("-S -x -xm0", s) # Shift_JISをUTF-8にする
NKF.nkf("-x -xm0", s) # 元の文字コードを自動で判別してくれる

27. 日時

27.1 基本

t = Time.new # 現在時刻
Time.now
Time.mktime(2024)
Time.at(300) # 1970/1/1から300秒

t.year
t.month
t.day
t.hour
t.min
t.sec
t.usec # 小数点(マイクロ秒)
t.nsec # 小数点(ナノ秒)
t.wday # 週の何日目か
t.yday # 何の何日目か
t.to_i # 1970年1月1日からの秒数
t.zone # タイムゾーン
t.utc_offset # 標準時との差(秒)
t.utc # タイムゾーンを世界標準時に変更
t.localtime # タイムゾーンをローカルタイムに変更

t1 < t2
t2 - t1

t.to_s

27.2 フォーマッティング

  • t.strftime("%y-%m-%d")のような形でTimeをフォーマッティングできる
コード 説明
%A 曜日 Sunday
%a 曜日 Sun
%B January
%b Jan
%c 日付、時刻 Sun Jan 1 00:00:00 2024
%d 日付 01
%H 時刻(24時間) 01
%I 時刻(12時間) 01
%j その年の何日目か 366
%M 00
%m 01
%p 午前、午後 AM
%S 00
%U その年の何周目か(日曜始まり) 00
%W その年の何周目か(月曜始まり) 00
%w 曜日(日曜日が0) 0
%X 時刻 00:00:00
%x 日付 01/02/24
%Y 西暦 2024
%Z タイムゾーン 東京 (標準時)
%z タイムゾーン +0900
%% %を出力できる %

※プラットフォームによって実行結果が異なる場合がある

27.3 timeライブラリ

require "time"

t.ios8601 # IOS 8601の形式にフォーマッティング
Time.parse("2024/01/01") # 文字列をTimeオブジェクトにできる。様々な文字列に対応している
Time.strptime("11/9/2018", "%m/%d/%Y) # parseでは対応していない文字列もTimeオブジェクトにできる
Time.strptime("令和6年1月1日", "令和%Y年%d月%d日") do |y|
  y + 2018 # ブロックに年以外の情報を渡すことはできない
end
t.strptime("%Y/%m/%d") # 特定の形式で文字列を取り出す

27.4 dateライブラリ

require "date"

d = Date.today
d = Date.new(2024,1,1)
d = Date.new(2024,1,-1) # 2024/1/31
d.year
d.month
d.day
d.wday # 曜日(日曜日が0)
d.yday # 年の何日目か
d2 - d1 # 1ヶ月と3日なら1/3
d + 1 # 1日先を取得
d += 1 # 1日先になる
d >> 2 # 2か月後の同じ日を取得
Date.new(2024,1,31) >> 1 # 2024/2/29
d.strftime("%Y/%m") # timeライブラリと同様に使えるが、時刻は全て0になる
Date.parse("R06.1.1")
t.to_date
d.to_time

28. Procクラス

  • ブロックをオブジェクトにできるイメージ
pr = Proc.new do |s|
  puts s
end

pr = Proc do |s| # newを付けなくても同じ
  puts s
end

pr = proc do |s| # 小文字でも同じ
  puts s
end

pr.call("hello")
pr["hello"]
pr.yield("hello")
pr.("hello")
pr === "hello" # この書き方だと、引数は1つだけ。case文などに使えるようにこの形式が定義されている

pr = Proc do |*a|
  puts a
end

pr.call(1,2,3)
pr.call[1,2,3]

pr = Proc.new {|n| n%2 == 0}

(1..5).each do |i|
  case i
  when pr then puts i
  end
end

# lambdaメソッドでProcオブジェクトを生成
#  引数の数のチェックが厳密になる
#  ブロック内でreturnを使える
#  lambdaメソッドでない場合のreturnは、Procオブジェクトを作成したメソッドから戻ろうとする
#  breakも同様
pr = lambda do|a,b,c|
  puts a,b,c
end

pr = -> (a,b,c) { puts a,b,c }

pr.call(1,2,3)

puts ["a","bc", "c", "defg","h"].sort_by { |a| a.length}

# :length.to_procオブジェクトが暗黙的に呼び出されることで、次のようにブロックを省略して書ける
puts ["a","bc", "c", "defg","h"].sort_by(&:length)

pr.arity # ブロック変数の数を返す ブロック変数が*aのように定義されているときは-1
pr.parameters # ブロック変数について、[種類, 変数名]の配列を返す
pr.lambda? # ラムダ式かどうか
pr.source_location # プロックが定義された位置[ファイル名, 行番号]

# クロージャー
# クラスのように手続きとデータの両方を保持できる
def counter
  c = 0
  Proc.new do
    c += 1
  end
end

c1 = counter
c1.call
c1.call
c2 = counter
c2.call

29. 組み込み変数

こちらの記事でまとめられている

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0