├── .ruby-version
├── README.md
├── ruby-book
├── Rakefile
├── lib
│ ├── convert_hash_syntax.rb
│ ├── convert_length.rb
│ ├── effects.rb
│ ├── fizz_buzz.rb
│ ├── fizz_buzz_chapter_02.rb
│ ├── gate.rb
│ ├── log_formatter.rb
│ ├── rainbowable.rb
│ ├── regexp_checker.rb
│ ├── rgb.rb
│ ├── ticket.rb
│ └── word_synth.rb
└── test
│ ├── convert_hash_syntax_test.rb
│ ├── convert_length_test.rb
│ ├── effects_test.rb
│ ├── fizz_buzz_test.rb
│ ├── gate_test.rb
│ ├── log_formatter_test.rb
│ ├── rainbowable_test.rb
│ ├── rgb_test.rb
│ └── word_synth_test.rb
└── sample-codes
├── chapter_01
├── code_01_06_01.rb
├── code_01_06_02.rb
└── column_01_01.rb
├── chapter_02
├── code_02_01_02.rb
├── code_02_02_01.rb
├── code_02_02_02.rb
├── code_02_02_03.rb
├── code_02_02_04.rb
├── code_02_02_06.rb
├── code_02_02_07.rb
├── code_02_02_08.rb
├── code_02_03_01.rb
├── code_02_03_02.rb
├── code_02_04_00.rb
├── code_02_04_01.rb
├── code_02_04_02.rb
├── code_02_04_03.rb
├── code_02_05_01.rb
├── code_02_05_02.rb
├── code_02_05_03.rb
├── code_02_06_00.rb
├── code_02_06_01.rb
├── code_02_06_02.rb
├── code_02_07_02.rb
├── code_02_07_03.rb
├── code_02_08_01.rb
├── code_02_08_02.rb
├── code_02_08_03.rb
├── code_02_08_04.rb
├── code_02_08_05.rb
├── code_02_08_06.rb
├── code_02_09_01.rb
├── code_02_09_02.rb
├── code_02_09_03.rb
├── code_02_09_04.rb
├── code_02_10_01.rb
├── code_02_10_02.rb
├── code_02_10_03.rb
├── code_02_10_04.rb
├── code_02_10_05.rb
├── code_02_11_01.rb
├── code_02_11_02.rb
├── code_02_11_03.rb
├── code_02_11_04.rb
├── code_02_12_02.rb
├── code_02_12_03.rb
├── code_02_12_04.rb
├── code_02_12_05.rb
├── code_02_12_07.rb
├── code_02_12_08.rb
├── column_02_01.rb
├── column_02_02.rb
├── column_02_03.rb
├── column_02_04.rb
└── column_02_05.rb
├── chapter_03
├── code_03_02_01.rb
├── code_03_02_02.rb
├── code_03_02_04.rb
├── code_03_02_05.rb
├── code_03_03_01.rb
├── code_03_03_02.rb
└── column_03_01.rb
├── chapter_04
├── code_04_01_02.rb
├── code_04_02_00.rb
├── code_04_02_01.rb
├── code_04_02_02.rb
├── code_04_03_01.rb
├── code_04_03_02.rb
├── code_04_03_03.rb
├── code_04_03_04.rb
├── code_04_03_05.rb
├── code_04_04_01.rb
├── code_04_04_02.rb
├── code_04_04_03.rb
├── code_04_04_04.rb
├── code_04_04_05.rb
├── code_04_05_00.rb
├── code_04_05_01.rb
├── code_04_05_02.rb
├── code_04_05_03.rb
├── code_04_05_04.rb
├── code_04_05_05.rb
├── code_04_06_00.rb
├── code_04_06_01.rb
├── code_04_06_02.rb
├── code_04_06_03.rb
├── code_04_06_04.rb
├── code_04_06_05.rb
├── code_04_07_01.rb
├── code_04_07_02.rb
├── code_04_07_03.rb
├── code_04_07_04.rb
├── code_04_07_05.rb
├── code_04_07_06.rb
├── code_04_07_07.rb
├── code_04_07_08.rb
├── code_04_07_09.rb
├── code_04_07_10.rb
├── code_04_07_11.rb
├── code_04_07_12.rb
├── code_04_07_13.rb
├── code_04_07_14.rb
├── code_04_08_01.rb
├── code_04_08_02.rb
├── code_04_08_03.rb
├── code_04_08_04.rb
├── code_04_08_05.rb
├── code_04_08_06.rb
├── code_04_08_07.rb
├── code_04_08_08.rb
├── code_04_09_01.rb
├── code_04_10_01.rb
├── code_04_10_02.rb
├── code_04_10_03.rb
├── code_04_10_04.rb
├── code_04_10_05.rb
├── code_04_10_06.rb
├── code_04_10_07.rb
├── code_04_11_01.rb
├── code_04_11_02.rb
├── code_04_11_03.rb
├── code_04_11_04.rb
├── code_04_11_05.rb
├── column_04_01.rb
├── column_04_02.rb
├── column_04_03.rb
└── column_04_04.rb
├── chapter_05
├── code_05_01_02.rb
├── code_05_02_00.rb
├── code_05_02_01.rb
├── code_05_02_02.rb
├── code_05_02_03.rb
├── code_05_03_00.rb
├── code_05_03_01.rb
├── code_05_03_02.rb
├── code_05_04_01.rb
├── code_05_04_02.rb
├── code_05_04_03.rb
├── code_05_05_00.rb
├── code_05_05_01.rb
├── code_05_05_02.rb
├── code_05_05_03.rb
├── code_05_06_01.rb
├── code_05_06_02.rb
├── code_05_06_03.rb
├── code_05_06_04.rb
├── code_05_06_05.rb
├── code_05_06_06.rb
├── code_05_06_07.rb
├── code_05_06_08.rb
├── code_05_06_09.rb
├── code_05_06_10.rb
├── code_05_07_01.rb
├── code_05_07_02.rb
├── code_05_07_03.rb
├── column_05_01.rb
├── column_05_02.rb
├── column_05_03.rb
├── column_05_04.rb
└── column_05_05.rb
├── chapter_06
├── code_06_01_01.rb
├── code_06_01_02.rb
├── code_06_02_01.rb
├── code_06_03_00.rb
├── code_06_03_02.rb
├── code_06_03_03.rb
├── code_06_03_04.rb
├── code_06_03_05.rb
├── code_06_04_00.rb
├── code_06_04_01.rb
├── code_06_04_02.rb
├── code_06_05_01.rb
├── code_06_05_02.rb
├── code_06_05_03.rb
├── code_06_05_04.rb
└── code_06_05_05.rb
├── chapter_07
├── code_07_01_01.rb
├── code_07_02_01.rb
├── code_07_02_02.rb
├── code_07_03_00.rb
├── code_07_03_01.rb
├── code_07_03_02.rb
├── code_07_03_03.rb
├── code_07_03_04.rb
├── code_07_03_05.rb
├── code_07_04_00.rb
├── code_07_04_01.rb
├── code_07_04_02.rb
├── code_07_04_03.rb
├── code_07_04_04.rb
├── code_07_04_05.rb
├── code_07_05_00.rb
├── code_07_05_01.rb
├── code_07_05_02.rb
├── code_07_05_03.rb
├── code_07_06_02.rb
├── code_07_06_03.rb
├── code_07_06_04.rb
├── code_07_06_05.rb
├── code_07_06_06.rb
├── code_07_06_07.rb
├── code_07_07_01.rb
├── code_07_07_02.rb
├── code_07_07_03.rb
├── code_07_07_04.rb
├── code_07_07_05.rb
├── code_07_07_06.rb
├── code_07_07_07.rb
├── code_07_08_00.rb
├── code_07_08_01.rb
├── code_07_08_02.rb
├── code_07_09_01.rb
├── code_07_09_02.rb
├── code_07_09_03.rb
├── code_07_10_01.rb
├── code_07_10_02.rb
├── code_07_10_03.rb
├── code_07_10_04.rb
├── code_07_10_05.rb
├── code_07_10_06.rb
├── code_07_10_07.rb
├── code_07_10_08.rb
├── code_07_10_09.rb
├── column_07_01.rb
├── column_07_02.rb
├── column_07_03.rb
├── column_07_04.rb
├── column_07_05.rb
├── column_07_06.rb
└── column_07_07.rb
├── chapter_08
├── code_08_01_01.rb
├── code_08_02_02.rb
├── code_08_03_01.rb
├── code_08_03_02.rb
├── code_08_03_03.rb
├── code_08_04_00.rb
├── code_08_04_01.rb
├── code_08_04_02.rb
├── code_08_04_03.rb
├── code_08_04_04.rb
├── code_08_04_05.rb
├── code_08_05_01.rb
├── code_08_05_02.rb
├── code_08_05_03.rb
├── code_08_05_04.rb
├── code_08_05_05.rb
├── code_08_05_06.rb
├── code_08_05_07.rb
├── code_08_05_08.rb
├── code_08_06_01.rb
├── code_08_06_02.rb
├── code_08_06_03.rb
├── code_08_06_04.rb
├── code_08_06_05.rb
├── code_08_07_01.rb
├── code_08_07_02.rb
├── code_08_07_03.rb
├── code_08_07_04.rb
├── code_08_08_00.rb
├── code_08_09_01.rb
├── code_08_09_02.rb
├── code_08_09_03.rb
├── code_08_09_04.rb
├── code_08_09_05.rb
├── column_08_01.rb
├── column_08_02.rb
└── column_08_03.rb
├── chapter_09
├── code_09_02_01.rb
├── code_09_02_02.rb
├── code_09_02_03.rb
├── code_09_02_04.rb
├── code_09_02_05.rb
├── code_09_02_06.rb
├── code_09_02_07.rb
├── code_09_02_08.rb
├── code_09_03_00.rb
├── code_09_04_02.rb
├── code_09_04_03.rb
├── code_09_04_04.rb
├── code_09_04_05.rb
├── code_09_04_06.rb
├── code_09_05_03.rb
├── code_09_05_04.rb
├── code_09_05_05.rb
├── code_09_06_01.rb
├── code_09_06_02.rb
├── code_09_06_03.rb
├── code_09_06_04.rb
├── code_09_06_05.rb
├── code_09_06_06.rb
├── code_09_06_07.rb
├── code_09_06_08.rb
├── code_09_06_09.rb
└── column_09_01.rb
├── chapter_10
├── code_10_01_01.rb
├── code_10_02_01.rb
├── code_10_02_02.rb
├── code_10_03_01.rb
├── code_10_03_02.rb
├── code_10_03_03.rb
├── code_10_03_04.rb
├── code_10_03_05.rb
├── code_10_04_00.rb
├── code_10_04_01.rb
├── code_10_04_03.rb
├── code_10_04_04.rb
├── code_10_04_05.rb
├── code_10_04_06.rb
├── code_10_04_07.rb
├── code_10_05_01.rb
├── code_10_05_02.rb
├── code_10_05_03.rb
├── column_10_01.rb
├── column_10_02.rb
└── column_10_03.rb
├── chapter_11
├── code_11_01_01.rb
├── code_11_02_00.rb
├── code_11_02_01.rb
├── code_11_03_01.rb
├── code_11_03_02.rb
├── code_11_03_03.rb
├── code_11_03_04.rb
├── code_11_03_05.rb
├── code_11_03_06.rb
├── code_11_03_07.rb
├── code_11_04_00.rb
├── code_11_04_01.rb
├── code_11_04_02.rb
├── code_11_04_03.rb
├── code_11_04_04.rb
├── code_11_04_05.rb
├── code_11_04_06.rb
├── code_11_05_01.rb
├── code_11_05_02.rb
├── code_11_05_03.rb
├── code_11_05_04.rb
└── column_11_01.rb
├── chapter_12
├── code_12_02_00.rb
├── code_12_03_06.rb
├── code_12_03_08.rb
├── code_12_04_01.rb
├── code_12_04_02.rb
├── code_12_04_03.rb
├── code_12_04_04.rb
└── code_12_05_05.rb
└── chapter_13
├── code_13_02_00.rb
├── code_13_03_00.rb
├── code_13_04_01.rb
├── code_13_04_02.rb
├── code_13_04_03.rb
├── code_13_05_00.rb
├── code_13_05_01.rb
├── code_13_06_00.rb
├── code_13_07_00.rb
├── code_13_08_01.rb
├── code_13_08_02.rb
├── code_13_09_01.rb
├── code_13_09_02.rb
├── code_13_09_04.rb
├── code_13_10_01.rb
├── code_13_10_02.rb
├── code_13_11_01.rb
├── code_13_11_02.rb
├── code_13_11_03.rb
├── code_13_11_04.rb
├── column_13_01.rb
├── column_13_02.rb
└── column_13_03.rb
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.0.1
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ruby-book-codes-v2
2 |
3 | Sample codes for "[Introduction to Ruby programming for future professionals 2nd edition](https://gihyo.jp/book/2021/978-4-297-12437-3)" book.
4 |
5 | 書籍「[プロを目指す人のためのRuby入門 改訂2版](https://gihyo.jp/book/2021/978-4-297-12437-3)(2021年12月発売)」のサンプルコードです。
6 |
7 |
8 |
9 | 第1版(2017年11月発売)のサンプルコードを参照する場合は以下のリポジトリにアクセスしてください。
10 |
11 | https://github.com/JunichiIto/ruby-book-codes
12 |
13 |
14 | ## ディレクトリ構成
15 |
16 | - [ruby-book](https://github.com/JunichiIto/ruby-book-codes-v2/tree/master/ruby-book) : 例題の解答コード(各解答における最終形)を格納しています。
17 | - [sample-codes](https://github.com/JunichiIto/ruby-book-codes-v2/tree/master/sample-codes) : 本文中のサンプルコードを格納しています。
18 |
19 | ## 注意事項
20 |
21 | - 本文中のサンプルコードと、このリポジトリのコードが異なる場合は、本文中のコードを正としてください(差異を見つけた場合は[issue](https://github.com/JunichiIto/ruby-book-codes-v2/issues)等で報告してもらえると助かります)。
22 | - このリポジトリのコードはブログやWeb記事等で引用してもらってもかまいません。ただし、その際は必ず引用元を明記してください。
23 | - このリポジトリのコードは、情報の提供のみを目的としています。したがってこのリポジトリのコードを用いた運用は、必ずお客様自身の責任と判断によって行ってください。これらの情報の運用の結果について、技術評論社および筆者はいかなる責任も負いません。
24 |
25 | ## Copyright
26 |
27 | Ⓒ 伊藤 淳一(Junichi Ito)
28 |
--------------------------------------------------------------------------------
/ruby-book/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rake/testtask'
2 |
3 | Rake::TestTask.new do |t|
4 | t.pattern = 'test/**/*_test.rb'
5 | end
6 |
7 | task default: :test
8 |
--------------------------------------------------------------------------------
/ruby-book/lib/convert_hash_syntax.rb:
--------------------------------------------------------------------------------
1 | def convert_hash_syntax(old_syntax)
2 | old_syntax.gsub(/:(\w+) *=> */) do
3 | "#{$1}: "
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/ruby-book/lib/convert_length.rb:
--------------------------------------------------------------------------------
1 | UNITS = { m: 1.0, ft: 3.28, in: 39.37 }
2 | def convert_length(length, from: :m, to: :m)
3 | (length / UNITS[from] * UNITS[to]).round(2)
4 | end
5 |
--------------------------------------------------------------------------------
/ruby-book/lib/effects.rb:
--------------------------------------------------------------------------------
1 | module Effects
2 | def self.reverse
3 | ->(words) do
4 | words.split(' ').map(&:reverse).join(' ')
5 | end
6 | end
7 |
8 | def self.echo(rate)
9 | ->(words) do
10 | words.each_char.map { |c| c == ' ' ? c : c * rate }.join
11 | end
12 | end
13 |
14 | def self.loud(level)
15 | ->(words) do
16 | words.split(' ').map { |word| word.upcase + '!' * level }.join(' ')
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/ruby-book/lib/fizz_buzz.rb:
--------------------------------------------------------------------------------
1 | def fizz_buzz(n)
2 | if n % 15 == 0
3 | 'Fizz Buzz'
4 | elsif n % 3 == 0
5 | 'Fizz'
6 | elsif n % 5 == 0
7 | 'Buzz'
8 | else
9 | n.to_s
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/ruby-book/lib/fizz_buzz_chapter_02.rb:
--------------------------------------------------------------------------------
1 | def fizz_buzz(n)
2 | if n % 15 == 0
3 | 'Fizz Buzz'
4 | elsif n % 3 == 0
5 | 'Fizz'
6 | elsif n % 5 == 0
7 | 'Buzz'
8 | else
9 | n.to_s
10 | end
11 | end
12 |
13 | puts fizz_buzz(1)
14 | puts fizz_buzz(2)
15 | puts fizz_buzz(3)
16 | puts fizz_buzz(4)
17 | puts fizz_buzz(5)
18 | puts fizz_buzz(6)
19 | puts fizz_buzz(15)
20 |
--------------------------------------------------------------------------------
/ruby-book/lib/gate.rb:
--------------------------------------------------------------------------------
1 | class Gate
2 | STATIONS = [:umeda, :juso, :mikuni]
3 | FARES = [160, 190]
4 |
5 | def initialize(name)
6 | @name = name
7 | end
8 |
9 | def enter(ticket)
10 | ticket.stamp(@name)
11 | end
12 |
13 | def exit(ticket)
14 | fare = calc_fare(ticket)
15 | fare <= ticket.fare
16 | end
17 |
18 | def calc_fare(ticket)
19 | from = STATIONS.index(ticket.stamped_at)
20 | to = STATIONS.index(@name)
21 | distance = to - from
22 | FARES[distance - 1]
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/ruby-book/lib/log_formatter.rb:
--------------------------------------------------------------------------------
1 | require 'net/http'
2 | require 'uri'
3 | require 'json'
4 |
5 | module LogFormatter
6 | def self.format_log
7 | uri = URI.parse('https://samples.jnito.com/access-log.json')
8 | json = Net::HTTP.get(uri)
9 | log_data = JSON.parse(json, symbolize_names: true)
10 |
11 | log_data.map do |log|
12 | case log
13 | in {request_id:, path:, status: 404 | 500 => status, error:}
14 | "[ERROR] request_id=#{request_id}, path=#{path}, status=#{status}, error=#{error}"
15 | in {request_id:, path:, duration: 1000.. => duration}
16 | "[WARN] request_id=#{request_id}, path=#{path}, duration=#{duration}"
17 | in {request_id:, path:}
18 | "[OK] request_id=#{request_id}, path=#{path}"
19 | end
20 | end.join("\n")
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/ruby-book/lib/rainbowable.rb:
--------------------------------------------------------------------------------
1 | module Rainbowable
2 | def rainbow
3 | to_s.each_char.map.with_index do |char, count|
4 | color = 31 + count % 6
5 | "\e[#{color}m#{char}"
6 | end.join + "\e[0m"
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/ruby-book/lib/regexp_checker.rb:
--------------------------------------------------------------------------------
1 | print 'Text?: '
2 | text = gets.chomp
3 |
4 | begin
5 | print 'Pattern?: '
6 | pattern = gets.chomp
7 | regexp = Regexp.new(pattern)
8 | rescue RegexpError => e
9 | puts "Invalid pattern: #{e.message}"
10 | retry
11 | end
12 |
13 | matches = text.scan(regexp)
14 | if matches.size > 0
15 | puts "Matched: #{matches.join(', ')}"
16 | else
17 | puts "Nothing matched."
18 | end
19 |
--------------------------------------------------------------------------------
/ruby-book/lib/rgb.rb:
--------------------------------------------------------------------------------
1 | def to_hex(r, g, b)
2 | [r, g, b].sum('#') do |n|
3 | n.to_s(16).rjust(2, '0')
4 | end
5 | end
6 |
7 | def to_ints(hex)
8 | hex.scan(/\w\w/).map(&:hex)
9 | end
10 |
--------------------------------------------------------------------------------
/ruby-book/lib/ticket.rb:
--------------------------------------------------------------------------------
1 | class Ticket
2 | attr_reader :fare, :stamped_at
3 |
4 | def initialize(fare)
5 | @fare = fare
6 | end
7 |
8 | def stamp(name)
9 | @stamped_at = name
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/ruby-book/lib/word_synth.rb:
--------------------------------------------------------------------------------
1 | class WordSynth
2 | def initialize
3 | @effects = []
4 | end
5 |
6 | def add_effect(effect)
7 | @effects << effect
8 | end
9 |
10 | def play(original_words)
11 | words = original_words
12 | @effects.each do |effect|
13 | words = effect.call(words)
14 | end
15 | words
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/ruby-book/test/convert_hash_syntax_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/convert_hash_syntax'
3 |
4 | class ConvertHashSyntaxTest < Minitest::Test
5 | def test_convert_hash_syntax
6 | old_syntax = <<~TEXT
7 | {
8 | :name => 'Alice',
9 | :age=>20,
10 | :gender => :female
11 | }
12 | TEXT
13 | expected = <<~TEXT
14 | {
15 | name: 'Alice',
16 | age: 20,
17 | gender: :female
18 | }
19 | TEXT
20 | assert_equal expected, convert_hash_syntax(old_syntax)
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/ruby-book/test/convert_length_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/convert_length'
3 |
4 | class ConvertLengthTest < Minitest::Test
5 | def test_convert_length
6 | assert_equal 39.37, convert_length(1, from: :m, to: :in)
7 | assert_equal 0.38, convert_length(15, from: :in, to: :m)
8 | assert_equal 10670.73, convert_length(35000, from: :ft, to: :m)
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/ruby-book/test/effects_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/effects'
3 |
4 | class EffectsTest < Minitest::Test
5 | def test_reverse
6 | effect = Effects.reverse
7 | assert_equal 'ybuR si !nuf', effect.call('Ruby is fun!')
8 | end
9 |
10 | def test_echo
11 | effect = Effects.echo(2)
12 | assert_equal 'RRuubbyy iiss ffuunn!!', effect.call('Ruby is fun!')
13 |
14 | effect = Effects.echo(3)
15 | assert_equal 'RRRuuubbbyyy iiisss fffuuunnn!!!', effect.call('Ruby is fun!')
16 | end
17 |
18 | def test_loud
19 | effect = Effects.loud(2)
20 | assert_equal 'RUBY!! IS!! FUN!!!', effect.call('Ruby is fun!')
21 |
22 | effect = Effects.loud(3)
23 | assert_equal 'RUBY!!! IS!!! FUN!!!!', effect.call('Ruby is fun!')
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/ruby-book/test/fizz_buzz_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/fizz_buzz'
3 |
4 | class FizzBuzzTest < Minitest::Test
5 | def test_fizz_buzz
6 | assert_equal '1', fizz_buzz(1)
7 | assert_equal '2', fizz_buzz(2)
8 | assert_equal 'Fizz', fizz_buzz(3)
9 | assert_equal '4', fizz_buzz(4)
10 | assert_equal 'Buzz', fizz_buzz(5)
11 | assert_equal 'Fizz', fizz_buzz(6)
12 | assert_equal 'Fizz Buzz', fizz_buzz(15)
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/ruby-book/test/gate_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/gate'
3 | require_relative '../lib/ticket'
4 |
5 | class GateTest < Minitest::Test
6 | def setup
7 | @umeda = Gate.new(:umeda)
8 | @juso = Gate.new(:juso)
9 | @mikuni = Gate.new(:mikuni)
10 | end
11 |
12 | def test_umeda_to_juso
13 | ticket = Ticket.new(160)
14 | @umeda.enter(ticket)
15 | assert @juso.exit(ticket)
16 | end
17 |
18 | def test_umeda_to_mikuni_when_fare_is_not_enough
19 | ticket = Ticket.new(160)
20 | @umeda.enter(ticket)
21 | refute @mikuni.exit(ticket)
22 | end
23 |
24 | def test_umeda_to_mikuni_when_fare_is_enough
25 | ticket = Ticket.new(190)
26 | @umeda.enter(ticket)
27 | assert @mikuni.exit(ticket)
28 | end
29 |
30 | def test_juso_to_mikuni
31 | ticket = Ticket.new(160)
32 | @juso.enter(ticket)
33 | assert @mikuni.exit(ticket)
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/ruby-book/test/log_formatter_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/log_formatter'
3 |
4 | class LogFormatterTest < Minitest::Test
5 | def test_format_log
6 | text = LogFormatter.format_log
7 | lines = text.lines(chomp: true)
8 | assert_equal '[OK] request_id=1, path=/products/1', lines[0]
9 | assert_equal '[ERROR] request_id=2, path=/wp-login.php, status=404, error=Not found', lines[1]
10 | assert_equal '[WARN] request_id=3, path=/products, duration=1023.8', lines[2]
11 | assert_equal '[ERROR] request_id=4, path=/dangerous, status=500, error=Internal server error', lines[3]
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/ruby-book/test/rainbowable_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/rainbowable'
3 |
4 | class RainbowableTest < Minitest::Test
5 | def setup
6 | String.include Rainbowable
7 | Array.include Rainbowable
8 | end
9 |
10 | def test_rainbow
11 | expected = "\e[31mH\e[32me\e[33ml\e[34ml\e[35mo\e[36m,\e[31m \e[32mw\e[33mo\e[34mr\e[35ml\e[36md\e[31m!\e[0m"
12 | assert_equal expected, 'Hello, world!'.rainbow
13 |
14 | expected = "\e[31m[\e[32m1\e[33m,\e[34m \e[35m2\e[36m,\e[31m \e[32m3\e[33m]\e[0m"
15 | assert_equal expected, [1, 2, 3].rainbow
16 | end
17 | end
18 |
19 |
--------------------------------------------------------------------------------
/ruby-book/test/rgb_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/rgb'
3 |
4 | class RgbTest < Minitest::Test
5 | def test_to_hex
6 | assert_equal '#000000', to_hex(0, 0, 0)
7 | assert_equal '#ffffff', to_hex(255, 255, 255)
8 | assert_equal '#043c78', to_hex(4, 60, 120)
9 | end
10 |
11 | def test_to_ints
12 | assert_equal [0, 0, 0], to_ints('#000000')
13 | assert_equal [255, 255, 255], to_ints('#ffffff')
14 | assert_equal [4, 60, 120], to_ints('#043c78')
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/ruby-book/test/word_synth_test.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/word_synth'
3 | require_relative '../lib/effects'
4 |
5 | class WordSynthTest < Minitest::Test
6 | def test_play_without_effects
7 | synth = WordSynth.new
8 | assert_equal 'Ruby is fun!', synth.play('Ruby is fun!')
9 | end
10 |
11 | def test_play_with_reverse
12 | synth = WordSynth.new
13 | synth.add_effect(Effects.reverse)
14 | assert_equal 'ybuR si !nuf', synth.play('Ruby is fun!')
15 | end
16 |
17 | def test_play_with_many_effects
18 | synth = WordSynth.new
19 | synth.add_effect(Effects.echo(2))
20 | synth.add_effect(Effects.loud(3))
21 | synth.add_effect(Effects.reverse)
22 | assert_equal '!!!YYBBUURR !!!SSII !!!!!NNUUFF', synth.play('Ruby is fun!')
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/sample-codes/chapter_01/code_01_06_01.rb:
--------------------------------------------------------------------------------
1 | 1 + 2 #=> 3
2 |
3 | a = 'Hello, world!'
4 | a #=> "Hello, world!"
5 |
6 | exit
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_01/code_01_06_02.rb:
--------------------------------------------------------------------------------
1 | puts 1 + 2
2 |
3 | a = 'Hello, world!'
4 | puts a
5 |
6 | b = 'こんにちは'
7 | puts b
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_01/column_01_01.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | # コラム:マジックコメントを使ったスクリプトエンコーディングの指定
3 |
4 | puts 'こんにちは'
5 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_01_02.rb:
--------------------------------------------------------------------------------
1 | fizz_buzz(1) #=> "1"
2 | fizz_buzz(2) #=> "2"
3 | fizz_buzz(3) #=> "Fizz"
4 | fizz_buzz(4) #=> "4"
5 | fizz_buzz(5) #=> "Buzz"
6 | fizz_buzz(6) #=> "Fizz"
7 | fizz_buzz(15) #=> "Fizz Buzz"
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_02_01.rb:
--------------------------------------------------------------------------------
1 | # 文字列
2 | '1'.to_s #=> "1"
3 | # 数値
4 | 1.to_s #=> "1"
5 | # nil
6 | nil.to_s #=> ""
7 | # true
8 | true.to_s #=> "true"
9 | # false
10 | false.to_s #=> "false"
11 | # 正規表現
12 | /\d+/.to_s #=> "(?-mix:\\d+)"
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_02_02.rb:
--------------------------------------------------------------------------------
1 | # 数値の1を文字列に変換する(カッコあり)
2 | 1.to_s() #=> "1"
3 |
4 | # 数値の1を文字列に変換する(カッコなし)
5 | 1.to_s #=> "1"
6 |
7 | # 数値を16進数の文字列に変換する(カッコあり)
8 | 10.to_s(16) #=> "a"
9 |
10 | # 数値を16進数の文字列に変換する(カッコなし)
11 | 10.to_s 16 #=> "a"
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_02_03.rb:
--------------------------------------------------------------------------------
1 | # 改行ごとにメソッドが実行される
2 | 1.to_s #=> "1"
3 | nil.to_s #=> ""
4 | 10.to_s(16) #=> "a"
5 |
6 | # ----------------------------------------
7 |
8 | # セミコロンを使って、3つの文を1行に押し込める
9 | 1.to_s; nil.to_s; 10.to_s(16)
10 |
11 | # ----------------------------------------
12 |
13 | # ( で改行しているので、カッコが閉じられるまで改行してもエラーにならない
14 | 10.to_s(
15 | 16
16 | ) #=> "a"
17 |
18 | # ( がない場合は10.to_sと16という2つの文だと見なされる
19 | 10.to_s #=> "10"
20 | 16 #=> 16
21 |
22 | # ----------------------------------------
23 |
24 | # バックスラッシュを使って10.to_s 16を改行して書く
25 | 10.to_s \
26 | 16 #=> "a"
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_02_04.rb:
--------------------------------------------------------------------------------
1 | # この行はコメントです。
2 | 1.to_s # 行の途中でもコメントが入れられます
3 |
4 | # ----------------------------------------
5 |
6 | =begin
7 | ここはコメントです。
8 | ここもコメントです。
9 | ここもコメントです。
10 | =end
11 |
12 | # ----------------------------------------
13 |
14 | # ここはコメントです。
15 | # ここもコメントです。
16 | # ここもコメントです。
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_02_06.rb:
--------------------------------------------------------------------------------
1 | (5+1 - 2)* 3
2 | def
3 | add (a,b)
4 |
5 |
6 | a+ b
7 | end
8 | add( 4, 5 )
9 |
10 | # ----------------------------------------
11 |
12 | (5 + 1 - 2) * 3 #=> 12
13 | def add(a, b)
14 | a + b
15 | end
16 | add(4, 5) #=> 9
17 |
18 | # ----------------------------------------
19 |
20 | # スペースを空けずに呼び出した場合は有効な構文
21 | add(4, 5)
22 | #=> 9
23 |
24 | # スペースを空けて呼び出した場合は無効な構文(構文エラー)
25 | add (4, 5)
26 | #=> syntax error, unexpected ',', expecting ')' (SyntaxError)
27 | # add (4, 5)
28 | # ^
29 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_02_07.rb:
--------------------------------------------------------------------------------
1 | # 数値(整数)
2 | 123
3 |
4 | # 文字列
5 | "Hello"
6 |
7 | # 配列
8 | [1, 2, 3]
9 |
10 | # ハッシュ
11 | { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
12 |
13 | # 正規表現
14 | /\d+-\d+/
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_03_01.rb:
--------------------------------------------------------------------------------
1 | 'これは文字列です。'
2 | "これも文字列です。"
3 |
4 | # ----------------------------------------
5 |
6 | # ダブルクオートで囲むと\nが改行文字として機能する
7 | puts "こんにちは\nさようなら"
8 | #=> こんにちは
9 | # さようなら
10 |
11 | # シングルクオートで囲むと\nはただの文字列になる
12 | puts 'こんにちは\nさようなら'
13 | #=> こんにちは\nさようなら
14 |
15 | # ----------------------------------------
16 |
17 | name = 'Alice'
18 | puts "Hello, #{name}!" #=> Hello, Alice!
19 |
20 | i = 10
21 | puts "#{i}は16進数にすると#{i.to_s(16)}です" #=> 10は16進数にするとaです
22 |
23 | # ----------------------------------------
24 |
25 | name = 'Alice'
26 | puts 'Hello, #{name}!' #=> Hello, #{name}!
27 |
28 | # ----------------------------------------
29 |
30 | name = 'Alice'
31 | puts 'Hello, ' + name + '!' #=> Hello, Alice!
32 |
33 | # ----------------------------------------
34 |
35 | puts "こんにちは\\nさようなら" #=> こんにちは\nさようなら
36 |
37 | name = 'Alice'
38 | puts "Hello, \#{name}!" #=> Hello, #{name}!
39 |
40 | # ----------------------------------------
41 |
42 | puts 'He said, "Don\'t speak."' #=> He said, "Don't speak."
43 |
44 | puts "He said, \"Don't speak.\"" #=> He said, "Don't speak."
45 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_03_02.rb:
--------------------------------------------------------------------------------
1 | 'ruby' == 'ruby' #=> true
2 | 'ruby' == 'Ruby' #=> false
3 | 'ruby' != 'perl' #=> true
4 | 'ruby' != 'ruby' #=> false
5 |
6 | # ----------------------------------------
7 |
8 | 'a' < 'b' #=> true
9 | 'a' < 'A' #=> false
10 | 'a' > 'A' #=> true
11 | 'abc' < 'def' #=> true
12 | 'abc' < 'ab' #=> false
13 | 'abc' < 'abcd' #=> true
14 | 'あいうえお' < 'かきくけこ' #=> true
15 |
16 | # ----------------------------------------
17 |
18 | # bytesメソッドを使うと文字列のバイト値が配列で返る(配列は第4章で詳しく説明します)
19 | 'a'.bytes #=> [97]
20 | 'b'.bytes #=> [98]
21 | 'A'.bytes #=> [65]
22 | 'abc'.bytes #=> [97, 98, 99]
23 | 'あ'.bytes #=> [227, 129, 130]
24 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_04_00.rb:
--------------------------------------------------------------------------------
1 | # 正の整数
2 | 10
3 | # 小数
4 | 1.5
5 | # 負の整数
6 | -3
7 | # 負の小数
8 | -4.75
9 |
10 | # ----------------------------------------
11 |
12 | 1_000_000_000 #=> 1000000000
13 |
14 | # ----------------------------------------
15 |
16 | 10 + 20 #=> 30
17 | 100 - 25 #=> 75
18 | 12 * 5 #=> 60
19 | 20 / 5 #=> 4
20 |
21 | # ----------------------------------------
22 |
23 | n = 1
24 | -n #=> -1
25 |
26 | # ----------------------------------------
27 |
28 | # 0.5ではなく0になる
29 | 1 / 2 #=> 0
30 |
31 | # ----------------------------------------
32 |
33 | 1.0 / 2 #=> 0.5
34 |
35 | 1 / 2.0 #=> 0.5
36 |
37 | # ----------------------------------------
38 |
39 | n = 1
40 | n.to_f #=> 1.0
41 | n.to_f / 2 #=> 0.5
42 |
43 | # ----------------------------------------
44 |
45 | 8 % 3 #=> 2
46 |
47 | # ----------------------------------------
48 |
49 | 2 ** 3 #=> 8
50 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_04_01.rb:
--------------------------------------------------------------------------------
1 | 1 < 2 #=> true
2 | 1 <= 2 #=> true
3 | 1 > 2 #=> false
4 | 1 >= 2 #=> false
5 | 1 == 2 #=> false
6 | 1 == 1 #=> true
7 | 1 != 2 #=> true
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_04_02.rb:
--------------------------------------------------------------------------------
1 | # 以下の計算は(2 * 3) + (4 * 5) - (6 / 2)と同じ
2 | 2 * 3 + 4 * 5 - 6 / 2 #=> 23
3 |
4 | # ----------------------------------------
5 |
6 | 2 * (3 + 4) * (5 - 6) / 2 #=> -7
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_04_03.rb:
--------------------------------------------------------------------------------
1 | n = 1
2 |
3 | # ++は構文として無効
4 | # n++
5 |
6 | # nを1増やす(n = n + 1と同じ)
7 | n += 1 #=> 2
8 |
9 | # nを1減らす(n = n - 1と同じ)
10 | n -= 1 #=> 1
11 |
12 | # ----------------------------------------
13 |
14 | n = 2
15 |
16 | # nを3倍にする
17 | n *= 3 #=> 6
18 |
19 | # nを2で割る
20 | n /= 2 #=> 3
21 |
22 | # nを2乗する
23 | n **= 2 #=> 9
24 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_05_01.rb:
--------------------------------------------------------------------------------
1 | # trueそのもの
2 | true
3 |
4 | # すべての数値
5 | 1
6 | 0
7 | -1
8 |
9 | # すべての文字列
10 | 'true'
11 | 'false'
12 | ''
13 |
14 | # ----------------------------------------
15 |
16 | data = find_data
17 | if data != nil
18 | 'データがあります'
19 | else
20 | 'データはありません'
21 | end
22 |
23 | # ----------------------------------------
24 |
25 | data = find_data
26 | if data
27 | 'データがあります'
28 | else
29 | 'データはありません'
30 | end
31 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_05_02.rb:
--------------------------------------------------------------------------------
1 | t1 = true
2 | t2 = true
3 | f1 = false
4 | t1 && t2 #=> true
5 | t1 && f1 #=> false
6 |
7 | # ----------------------------------------
8 |
9 | t1 = true
10 | f1 = false
11 | f2 = false
12 | t1 || f1 #=> true
13 | f1 || f2 #=> false
14 |
15 | # ----------------------------------------
16 |
17 | t1 = true
18 | t2 = true
19 | f1 = false
20 | f2 = false
21 | t1 && t2 || f1 && f2 #=> true
22 | # 上の式と下の式は同じ意味
23 | (t1 && t2) || (f1 && f2) #=> true
24 |
25 | # ----------------------------------------
26 |
27 | t1 = true
28 | t2 = true
29 | f1 = false
30 | f2 = false
31 | t1 && (t2 || f1) && f2 #=> false
32 |
33 | # ----------------------------------------
34 |
35 | t1 = true
36 | f1 = false
37 | !t1 #=> false
38 | !f1 #=> true
39 |
40 | # ----------------------------------------
41 |
42 | t1 = true
43 | f1 = false
44 | t1 && f1 #=> false
45 | !(t1 && f1) #=> true
46 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_06_00.rb:
--------------------------------------------------------------------------------
1 | def add(a, b)
2 | a + b
3 | end
4 | add(1, 2) #=> 3
5 |
6 | # ----------------------------------------
7 |
8 | # メソッド名はスネークケースで書く
9 | def hello_world
10 | 'Hello, world!'
11 | end
12 |
13 | # キャメルケースは使わない(エラーにはならないが一般的ではない)
14 | def helloWorld
15 | 'Hello, world!'
16 | end
17 |
18 | # アンダースコアでメソッド名を書き始める(アンダースコアで始まることは少ない)
19 | def _hello_world
20 | 'Hello, world!'
21 | end
22 |
23 | # メソッド名に数字を入れる
24 | def hello_world_2
25 | 'Hello, world!!'
26 | end
27 |
28 | # 数字から始まるメソッド名は使えない(エラーになる)
29 | def 2_hello_world
30 | 'Hello, world!!'
31 | end
32 | #=> trailing `_' in number (SyntaxError)
33 | # def 2_hello_world
34 | # ^
35 |
36 | # メソッド名をひらがなにする(一般的ではない)
37 | def あいさつする
38 | 'はろー、わーるど!'
39 | end
40 | # ひらがなのメソッドを呼び出す
41 | あいさつする #=> "はろー、わーるど!"
42 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_06_01.rb:
--------------------------------------------------------------------------------
1 | def add(a, b)
2 | # returnも使えるが、使わない方が主流
3 | return a + b
4 | end
5 | add(1, 2) #=> 3
6 |
7 | # ----------------------------------------
8 |
9 | def greet(country)
10 | # "こんにちは"または"hello"がメソッドの戻り値になる
11 | if country == 'japan'
12 | 'こんにちは'
13 | else
14 | 'hello'
15 | end
16 | end
17 | greet('japan') #=> "こんにちは"
18 | greet('us') #=> "hello"
19 |
20 | # ----------------------------------------
21 |
22 | def greet(country)
23 | # countryがnilならメッセージを返してメソッドを抜ける
24 | # (nil?はオブジェクトがnilの場合にtrueを返すメソッド)
25 | return 'countryを入力してください' if country.nil?
26 |
27 | if country == 'japan'
28 | 'こんにちは'
29 | else
30 | 'hello'
31 | end
32 | end
33 | greet(nil) #=> "countryを入力してください"
34 | greet('japan') #=> "こんにちは"
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_06_02.rb:
--------------------------------------------------------------------------------
1 | # 引数がない場合は( )を付けない方が主流
2 | def greet
3 | 'こんにちは'
4 | end
5 |
6 | # ----------------------------------------
7 |
8 | # ()を付けてもよいが、省略されることが多い
9 | def greet()
10 | 'こんにちは'
11 | end
12 |
13 | # ----------------------------------------
14 |
15 | # ( )を省略できるが、引数がある場合は( )を付ける方が主流
16 | def greet country
17 | if country == 'japan'
18 | 'こんにちは'
19 | else
20 | 'hello'
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_07_02.rb:
--------------------------------------------------------------------------------
1 | puts 'Hello, world!'
2 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_08_01.rb:
--------------------------------------------------------------------------------
1 | 'abc'.class #=> String
2 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_08_02.rb:
--------------------------------------------------------------------------------
1 | # %q! !はシングルクオートで囲んだことと同じになる
2 | puts %q!He said, "Don't speak."! #=> He said, "Don't speak."
3 |
4 | # %Q! !はダブルクオートで囲んだことと同じになる(改行文字や式展開が使える)
5 | something = "Hello."
6 | puts %Q!He said, "#{something}"! #=> He said, "Hello."
7 |
8 | # %! !もダブルクオートで囲んだことと同じになる
9 | something = "Bye."
10 | puts %!He said, "#{something}"! #=> He said, "Bye."
11 |
12 | # ----------------------------------------
13 |
14 | puts 'He said, "Don\'t speak."' #=> He said, "Don't speak."
15 |
16 | something = "Hello."
17 | puts "He said, \"#{something}\"" #=> He said, "Hello."
18 |
19 | something = "Bye."
20 | puts "He said, \"#{something}\"" #=> He said, "Bye."
21 |
22 | # ----------------------------------------
23 |
24 | # ?を区切り文字として使う
25 | puts %q?He said, "Don't speak."? #=> He said, "Don't speak."
26 |
27 | # { }を区切り文字として使う
28 | puts %q{He said, "Don't speak."} #=> He said, "Don't speak."
29 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_08_04.rb:
--------------------------------------------------------------------------------
1 | sprintf('%0.3f', 1.2) #=> "1.200"
2 |
3 | # ----------------------------------------
4 |
5 | '%0.3f' % 1.2 #=> "1.200"
6 |
7 | # ----------------------------------------
8 |
9 | sprintf('%0.3f + %0.3f', 1.2, 0.48) #=> "1.200 + 0.480"
10 | '%0.3f + %0.3f' % [1.2, 0.48] #=> "1.200 + 0.480"
11 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_08_05.rb:
--------------------------------------------------------------------------------
1 | # 数値を文字列に変換する
2 | 123.to_s #=> "123"
3 |
4 | # 配列を連結して一つの文字列にする
5 | [10, 20, 30].join #=> "102030"
6 |
7 | # *演算子を使って文字列を繰り返す
8 | 'Hi!' * 10 #=> "Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!Hi!"
9 |
10 | # String.newを使って新しい文字列を作る(あまり使わない)
11 | String.new('hello') #=> "hello"
12 |
13 | # ----------------------------------------
14 |
15 | # 以下は'abcdef'と書いたのと同じ(めったに使わない)
16 | 'abc' 'def'
17 | #=> "abcdef"
18 |
19 | # スペースがなくても可(こちらもめったに使わない)
20 | 'abc''def'
21 | #=> "abcdef"
22 |
23 | # ----------------------------------------
24 |
25 | "\u3042\u3044\u3046" #=> "あいう"
26 |
27 | # ----------------------------------------
28 |
29 | puts "\u3042\u3044\u3046"
30 |
31 | # ----------------------------------------
32 |
33 | # NG: 4桁でないのでエラー
34 | puts "\u41" #=> invalid Unicode escape (SyntaxError)
35 |
36 | # OK: 0埋めして4桁にする
37 | puts "\u0041" #=> A
38 |
39 | # OK: もしくは\u{ }の形式を使う
40 | puts "\u{41}" #=> A
41 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_08_06.rb:
--------------------------------------------------------------------------------
1 | # 1文字でも文字列
2 | 'a' #=> "a"
3 |
4 | # 2文字以上でも文字列
5 | 'abc' #=> "abc"
6 |
7 | # 0文字でも文字列
8 | '' #=> ""
9 |
10 | # ----------------------------------------
11 |
12 | ?a #=> "a"
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_09_01.rb:
--------------------------------------------------------------------------------
1 | # 2進数
2 | 0b11111111 #=> 255
3 | # 8進数
4 | 0377 #=> 255
5 | 0o377 #=> 255
6 | # 16進数
7 | 0xff #=> 255
8 |
9 | # ----------------------------------------
10 |
11 | # 10進数(0dを付けなくても同じなので、普通は付けない)
12 | 0d255 #=> 255
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_09_02.rb:
--------------------------------------------------------------------------------
1 | sprintf '%#b', (0b1010 & 0b1100) #=> "0b1000"
2 | sprintf '%#b', (0b1010 | 0b1100) #=> "0b1110"
3 | sprintf '%#b', (0b1010 ^ 0b1100) #=> "0b110"
4 | sprintf '%#b', (0b1010 >> 1) #=> "0b101"
5 | sprintf '%#b', (0b1010 << 1) #=> "0b10100"
6 | sprintf '%#b', ~0b1010 #=> "0b..10101"
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_09_03.rb:
--------------------------------------------------------------------------------
1 | 2e-3 #=> 0.002
2 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_09_04.rb:
--------------------------------------------------------------------------------
1 | 10.class #=> Integer
2 | 1.5.class #=> Float
3 |
4 | # ----------------------------------------
5 |
6 | # 有理数リテラルを使う(3rが有理数リテラル)
7 | r = 2 / 3r
8 | r #=> (2/3)
9 | r.class #=> Rational
10 |
11 | # 文字列から有理数に変換する
12 | r = '2/3'.to_r
13 | r #=> (2/3)
14 | r.class #=> Rational
15 |
16 | # 複素数リテラルを使う(0.5iが複素数リテラル)
17 | c = 0.3 - 0.5i
18 | c #=> (0.3-0.5i)
19 | c.class #=> Complex
20 |
21 | # 文字列から複素数に変換する
22 | c = '0.3-0.5i'.to_c
23 | c #=> (0.3-0.5i)
24 | c.class #=> Complex
25 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_10_01.rb:
--------------------------------------------------------------------------------
1 | 1 && 2 && 3 #=> 3
2 | 1 && nil && 3 #=> nil
3 | 1 && false && 3 #=> false
4 |
5 | nil || false #=> false
6 | false || nil #=> nil
7 | nil || false || 2 || 3 #=> 2
8 |
9 | # ----------------------------------------
10 |
11 | # Alice、Bob、Carolと順に検索し、最初に見つかったユーザー(nilまたはfalse以外の値)を変数に格納する
12 | user = find_user('Alice') || find_user('Bob') || find_user('Carol')
13 |
14 | # 正常なユーザーであればメールを送信する(左辺が偽であればメール送信は実行されない)
15 | user.valid? && send_email_to(user)
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_10_03.rb:
--------------------------------------------------------------------------------
1 | status = 'error'
2 | if status != 'ok'
3 | '何か異常があります'
4 | end
5 | #=> "何か異常があります"
6 |
7 | # ----------------------------------------
8 |
9 | status = 'error'
10 | unless status == 'ok'
11 | '何か異常があります'
12 | end
13 | #=> "何か異常があります"
14 |
15 | # ----------------------------------------
16 |
17 | status = 'ok'
18 | unless status == 'ok'
19 | '何か異常があります'
20 | else
21 | '正常です'
22 | end
23 | #=> "正常です"
24 |
25 | # ----------------------------------------
26 |
27 | status = 'error'
28 |
29 | # unlessの結果を変数に代入する
30 | message =
31 | unless status == 'ok'
32 | '何か異常があります'
33 | else
34 | '正常です'
35 | end
36 |
37 | message #=> "何か異常があります"
38 |
39 | # unlessを修飾子として使う
40 | '何か異常があります' unless status == 'ok'
41 | #=> "何か異常があります"
42 |
43 | # ----------------------------------------
44 |
45 | status = 'error'
46 | unless status == 'ok' then
47 | '何か異常があります'
48 | end
49 | #=> "何か異常があります"
50 |
51 | # ----------------------------------------
52 |
53 | status = 'error'
54 | # unlessを無理に使わなくてもよい
55 | if status != 'ok'
56 | '何か異常があります'
57 | end
58 | #=> "何か異常があります"
59 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_10_05.rb:
--------------------------------------------------------------------------------
1 | n = 11
2 | if n > 10
3 | '10より大きい'
4 | else
5 | '10以下'
6 | end
7 | #=> "10より大きい"
8 |
9 | # ----------------------------------------
10 |
11 | n = 11
12 | n > 10 ? '10より大きい' : '10以下' #=> "10より大きい"
13 | #=> "10より大きい"
14 |
15 | # ----------------------------------------
16 |
17 | n = 11
18 | message = n > 10 ? '10より大きい' : '10以下'
19 | message #=> "10より大きい"
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_11_02.rb:
--------------------------------------------------------------------------------
1 | # 空文字列であればtrue、そうでなければfalse
2 | ''.empty? #=> true
3 | 'abc'.empty? #=> false
4 |
5 | # 引数の文字列が含まれていればtrue、そうでなければfalse
6 | 'watch'.include?('at') #=> true
7 | 'watch'.include?('in') #=> false
8 |
9 | # 奇数ならtrue、偶数ならfalse
10 | 1.odd? #=> true
11 | 2.odd? #=> false
12 |
13 | # 偶数ならtrue、奇数ならfalse
14 | 1.even? #=> false
15 | 2.even? #=> true
16 |
17 | # オブジェクトがnilであればtrue、そうでなければfalse
18 | nil.nil? #=> true
19 | 'abc'.nil? #=> false
20 | 1.nil? #=> false
21 |
22 | # ----------------------------------------
23 |
24 | # 3の倍数ならtrue、それ以外はfalseを返す
25 | def multiple_of_three?(n)
26 | n % 3 == 0
27 | end
28 | multiple_of_three?(4) #=> false
29 | multiple_of_three?(5) #=> false
30 | multiple_of_three?(6) #=> true
31 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_11_03.rb:
--------------------------------------------------------------------------------
1 | a = 'ruby'
2 |
3 | # upcaseだと変数aの値は変化しない
4 | a.upcase #=> "RUBY"
5 | a #=> "ruby"
6 |
7 | # upcase!だと変数aの値も大文字に変わる
8 | a.upcase! #=> "RUBY"
9 | a #=> "RUBY"
10 |
11 | # ----------------------------------------
12 |
13 | # 引数の内容を変更しない安全バージョン
14 | def reverse_upcase(s)
15 | s.reverse.upcase
16 | end
17 |
18 | # 引数の内容を破壊的に変更してしまう危険バージョン
19 | def reverse_upcase!(s)
20 | s.reverse!
21 | s.upcase!
22 | s
23 | end
24 |
25 | s = 'ruby'
26 |
27 | # 安全バージョンは引数として渡した変数sの内容はそのまま
28 | reverse_upcase(s) #=> "YBUR"
29 | s #=> "ruby"
30 |
31 | # 危険バージョンは引数として渡した変数sの内容が変更される
32 | reverse_upcase!(s) #=> "YBUR"
33 | s #=> "YBUR"
34 |
35 | # ----------------------------------------
36 |
37 | odd? = 1.odd?
38 | #=> syntax error, unexpected '=' (SyntaxError)
39 | # odd? = 1.odd?
40 | # ^
41 |
42 | upcase! = 'ruby'.upcase!
43 | #=> syntax error, unexpected '=' (SyntaxError)
44 | # upcase! = 'ruby'.upcase!
45 | # ^
46 |
47 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_11_04.rb:
--------------------------------------------------------------------------------
1 | # 通常のメソッド定義
2 | def greet
3 | 'Hello!'
4 | end
5 |
6 | # エンドレスメソッド定義(=に続けて処理や戻り値を書く)
7 | def greet = 'Hello!'
8 |
9 | # 呼び出し方はどちらも同じ
10 | greet #=> "Hello!"
11 |
12 | # ただし、メソッド名と=の間にスペースがないと構文エラー
13 | def greet= 'Hello!'
14 | #=> syntax error, unexpected string literal, expecting ';' or '\n'
15 |
16 |
17 | # 通常のメソッド定義(引数を持つ場合)
18 | def add(a, b)
19 | a + b
20 | end
21 |
22 | # エンドレスメソッド定義
23 | def add(a, b) = a + b
24 |
25 | add(1, 2) #=> 3
26 |
27 | # ただし、引数の()を省略すると構文エラー
28 | def add a, b = a + b
29 | #=> circular argument reference - b
30 | # syntax error, unexpected end-of-input
31 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_12_02.rb:
--------------------------------------------------------------------------------
1 | # lengthもsizeも、どちらも文字数を返す
2 | 'hello'.length #=> 5
3 | 'hello'.size #=> 5
4 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_12_03.rb:
--------------------------------------------------------------------------------
1 | # if文が値を返すので変数に代入できる
2 | a =
3 | if true
4 | '真です'
5 | else
6 | '偽です'
7 | end
8 | a #=> "真です"
9 |
10 | # メソッドの定義も実は値(シンボル)を返している(シンボルについては第4章で説明します)
11 | b = def foo; end
12 | b #=> :foo
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_12_04.rb:
--------------------------------------------------------------------------------
1 | true = 1
2 | #=> Can't assign to true (SyntaxError)
3 | # true = 1
4 | # ^~~~
5 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_12_05.rb:
--------------------------------------------------------------------------------
1 | # aとbはどちらも同じ文字列だが、オブジェクトとしては別物
2 | a = 'hello'
3 | b = 'hello'
4 | a.object_id #=> 70182231931400
5 | b.object_id #=> 70182236321960
6 |
7 | # cにbを代入する。bとcはどちらも同じオブジェクト
8 | c = b
9 | c.object_id #=> 70182236321960
10 |
11 | # メソッドの引数にcを渡す。引数として受け取ったdはcと同じオブジェクト
12 | def m(d)
13 | d.object_id
14 | end
15 | m(c) #=> 70182236321960
16 |
17 | # equal?メソッドを使ってもよい(trueなら同じオブジェクト)
18 | a.equal?(b) #=> false
19 | b.equal?(c) #=> true
20 |
21 | # ----------------------------------------
22 |
23 | # b、cは同じオブジェクト、aは異なるオブジェクト
24 | a = 'hello'
25 | b = 'hello'
26 | c = b
27 |
28 | # 渡された文字列を破壊的に大文字に変換するメソッドを定義する
29 | def m!(d)
30 | d.upcase!
31 | end
32 |
33 | # cにm!メソッドを適用する
34 | m!(c)
35 |
36 | # b、cはいずれも大文字になる
37 | b #=> "HELLO"
38 | c #=> "HELLO"
39 |
40 | # aは別のオブジェクトので大文字にならない
41 | a #=> "hello"
42 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_12_07.rb:
--------------------------------------------------------------------------------
1 | # Dateクラスは組み込みライブラリではないので、そのままでは使用できない
2 | Date.today #=> NameError (uninitialized constant Date)
3 |
4 | # dateライブラリを読み込むとDateクラスが使えるようになる
5 | require 'date'
6 | Date.today #=> #
7 |
8 | # ----------------------------------------
9 |
10 | # foo/hello.rbから見た相対パスでbar/bye.rbを読み込む
11 | require_relative '../bar/bye'
12 |
13 | # ----------------------------------------
14 |
15 | # 自ファイル(hello.rb)と同じディレクトリにあるbye.rbを読み込む
16 | require_relative 'bye'
17 |
18 | # ----------------------------------------
19 |
20 | # requireで自作Rubyプログラムを読み込むこともできる(が、非推奨)
21 | require './foo/bye'
22 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/code_02_12_08.rb:
--------------------------------------------------------------------------------
1 | # pメソッドではネストした配列が横並びになってしまい確認しづらい
2 | p Encoding.aliases.take(5)
3 | #=> [["BINARY", "ASCII-8BIT"], ["CP437", "IBM437"], ["CP720", "IBM720"], ["CP737", "IBM737"], ["CP775", "IBM775"]]
4 |
5 | # ppメソッドを使うと配列が見やすく整形される
6 | pp Encoding.aliases.take(5)
7 | #=> [["BINARY", "ASCII-8BIT"],
8 | # ["CP437", "IBM437"],
9 | # ["CP720", "IBM720"],
10 | # ["CP737", "IBM737"],
11 | # ["CP775", "IBM775"]]
12 |
13 | # ----------------------------------------
14 |
15 | # 文字列をinspectすると、ダブルクオート付きの文字列が返る
16 | 'abc'.inspect #=> "\"abc\""
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/column_02_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:シングルクオートかダブルクオートか
2 |
3 | # シングルクオートでもダブルクオートでもどちらでも良い
4 | 'Hello, world!'
5 | "Hello, world!"
6 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/column_02_02.rb:
--------------------------------------------------------------------------------
1 | # コラム:数値と文字列は暗黙的に変換されない
2 |
3 | # 数値と文字列を+演算子で加算することはできない
4 | 1 + '10' #=> String can't be coerced into Integer (TypeError)
5 |
6 | # 文字列は数値に変換する必要がある
7 | # 整数に変換
8 | 1 + '10'.to_i #=> 11
9 |
10 | # 小数に変換
11 | 1 + '10.5'.to_f #=> 11.5
12 |
13 | # ----------------------------------------
14 |
15 | number = 3
16 |
17 | # 文字列に数値を+演算子で連結することはできない
18 | 'Number is ' + number #=> no implicit conversion of Integer into String (TypeError)
19 |
20 | # 数値を文字列に変換する必要がある
21 | 'Number is ' + number.to_s #=> "Number is 3"
22 |
23 | # ----------------------------------------
24 |
25 | number = 3
26 | "Number is #{number}" #=> "Number is 3"
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/column_02_03.rb:
--------------------------------------------------------------------------------
1 | # コラム:小数を使う場合は丸め誤差に注意
2 |
3 | 0.1 * 3.0 #=> 0.30000000000000004
4 |
5 | # ----------------------------------------
6 |
7 | 0.1 * 3.0 == 0.3 #=> false
8 | 0.1 * 3.0 <= 0.3 #=> false
9 |
10 | # ----------------------------------------
11 |
12 | # Rationalクラスを使うと小数ではなく「10分の3」という計算結果が返る
13 | 0.1r * 3.0r #=> (3/10)
14 |
15 | # Rationalクラスであれば期待した通りに値の比較ができる
16 | 0.1r * 3r == 0.3 #=> true
17 |
18 | 0.1r * 3r <= 0.3 #=> true
19 |
20 | # ----------------------------------------
21 |
22 | a = 0.1
23 | b = 3.0
24 | a.rationalize * b.rationalize #=> (3/10)
25 |
26 | # ----------------------------------------
27 |
28 | (0.1r * 3.0r).to_f #=> 0.3
29 |
30 | # ----------------------------------------
31 |
32 | require 'bigdecimal'
33 |
34 | (BigDecimal("0.1") * BigDecimal("3.0")).to_f #=> 0.3
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/column_02_04.rb:
--------------------------------------------------------------------------------
1 | # コラム:== true や == false は冗長なので書かない
2 |
3 | s = ''
4 |
5 | # (empty?は文字列が空文字列だったときにtrueを返し、それ以外はfalseを返すメソッド)
6 | # こうではなく...
7 | if s.empty? == true
8 | '空文字列です'
9 | end
10 |
11 | # こう書く
12 | if s.empty?
13 | '空文字列です'
14 | end
15 |
16 | # ----------------------------------------
17 |
18 | n = 123
19 |
20 | # (zero?は数値が0だったときにtrueを返し、それ以外はfalseを返すメソッド)
21 | # こうではなく......
22 | if n.zero? == false
23 | 'ゼロではありません'
24 | end
25 |
26 | # こう書く(unless n.zero?でも可)
27 | if !n.zero?
28 | 'ゼロではありません'
29 | end
30 |
31 | # ----------------------------------------
32 |
33 | user = nil
34 |
35 | # こうではなく......
36 | if user == nil
37 | 'nilです'
38 | end
39 |
40 | # こう書く(unless userでも可)
41 | if !user
42 | 'nilです'
43 | end
44 |
45 | # またはnil?メソッドを使う
46 | if user.nil?
47 | 'nilです'
48 | end
49 |
50 | # ----------------------------------------
51 |
52 | some_value = true
53 |
54 | # 1や'OK'ではなく、trueであるかどうかを判定したい
55 | if some_value == true
56 | 'trueそのものです'
57 | end
58 |
--------------------------------------------------------------------------------
/sample-codes/chapter_02/column_02_05.rb:
--------------------------------------------------------------------------------
1 | # コラム:メソッド呼び出しでカッコを付ける/付けないの使い分け
2 |
3 | # 10.to_s() よりも...
4 | 10.to_s
5 |
6 | # greet() よりも...
7 | greet
8 |
9 | # ----------------------------------------
10 |
11 | # puts('Hello, world!')よりも...
12 | puts 'Hello, world!'
13 |
14 | # ----------------------------------------
15 |
16 | # require('date')よりも...
17 | require 'date'
18 |
19 | # raise('Something went wrong.')よりも...
20 | raise 'Something went wrong.'
21 |
22 | # ----------------------------------------
23 |
24 | # オブジェクトに対するメソッド呼び出しで、なおかつ引数がある
25 | 10.to_s(16)
26 |
27 | # 独自に定義したメソッドで、なおかつ引数がある
28 | greet('Alice')
29 |
30 | # ----------------------------------------
31 |
32 | # 引数と{}のブロックを付けてメソッド呼び出しする場合は()を省略できない(省略すると構文エラー)
33 | [1, 2, 3].delete(100) { 'NG' }
34 |
35 | # 第1引数にハッシュの{}が来る場合は()を省略できない(省略すると構文エラー)
36 | puts({a: 1})
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_03/code_03_02_01.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | class SampleTest < Minitest::Test
4 | def test_sample
5 | assert_equal 'RUBY', 'ruby'.upcase
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_03/code_03_02_02.rb:
--------------------------------------------------------------------------------
1 | # aがbと等しければパスする
2 | assert_equal b, a
3 |
4 | # aが真であればパスする
5 | assert a
6 |
7 | # aが偽であればパスする
8 | refute a
9 |
--------------------------------------------------------------------------------
/sample-codes/chapter_03/code_03_02_04.rb:
--------------------------------------------------------------------------------
1 | # わざとcapitalizeメソッド(最初の1文字だけを大文字にするメソッド)を呼ぶ
2 | assert_equal 'RUBY', 'ruby'.capitalize
3 |
--------------------------------------------------------------------------------
/sample-codes/chapter_03/code_03_02_05.rb:
--------------------------------------------------------------------------------
1 | # nilは文字列ではないので、upcaseメソッドを呼ぶことはできない
2 | assert_equal 'RUBY', nil.upcase
3 |
--------------------------------------------------------------------------------
/sample-codes/chapter_03/code_03_03_02.rb:
--------------------------------------------------------------------------------
1 | def fizz_buzz(n)
2 | if n % 15 == 0
3 | 'Fizz Buzz'
4 | elsif n % 3 == 0
5 | 'Fizz'
6 | elsif n % 5 == 0
7 | 'Buzz'
8 | else
9 | n.to_s
10 | end
11 | end
12 |
13 | # ----------------------------------------
14 |
15 | require 'minitest/autorun'
16 |
17 | class FizzBuzzTest < Minitest::Test
18 | def test_fizz_buzz
19 | assert_equal '1', fizz_buzz(1)
20 | assert_equal '2', fizz_buzz(2)
21 | assert_equal 'Fizz', fizz_buzz(3)
22 | assert_equal '4', fizz_buzz(4)
23 | assert_equal 'Buzz', fizz_buzz(5)
24 | assert_equal 'Fizz', fizz_buzz(6)
25 | assert_equal 'Fizz Buzz', fizz_buzz(15)
26 | end
27 | end
28 |
29 | # ----------------------------------------
30 |
31 | require 'minitest/autorun'
32 | require_relative '../lib/fizz_buzz'
33 |
34 | class FizzBuzzTest < Minitest::Test
35 | # 省略
36 |
--------------------------------------------------------------------------------
/sample-codes/chapter_03/column_03_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:Minitest以外のフレームワーク
2 |
3 | require_relative '../lib/fizz_buzz'
4 |
5 | RSpec.describe 'Fizz Buzz' do
6 | example 'fizz_buzz' do
7 | expect(fizz_buzz(1)).to eq '1'
8 | expect(fizz_buzz(2)).to eq '2'
9 | expect(fizz_buzz(3)).to eq 'Fizz'
10 | # 省略
11 | end
12 | end
13 |
14 | # ----------------------------------------
15 |
16 | require 'test/unit'
17 | require_relative '../lib/fizz_buzz'
18 |
19 | class FizzBuzzTest < Test::Unit::TestCase
20 | def test_fizz_buzz
21 | assert_equal '1', fizz_buzz(1)
22 | assert_equal '2', fizz_buzz(2)
23 | assert_equal 'Fizz', fizz_buzz(3)
24 | # 省略
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_01_02.rb:
--------------------------------------------------------------------------------
1 | to_hex(0, 0, 0) #=> "#000000"
2 | to_hex(255, 255, 255) #=> "#ffffff"
3 | to_hex(4, 60, 120) #=> "#043c78"
4 | to_ints('#000000') #=> [0, 0, 0]
5 | to_ints('#ffffff') #=> [255, 255, 255]
6 | to_ints('#043c78') #=> [4, 60, 120]
7 |
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_02_00.rb:
--------------------------------------------------------------------------------
1 | # 空の配列を作成し、そのクラス名を確認する
2 | [].class #=> Array
3 |
4 | # ----------------------------------------
5 |
6 | a = [1, 2, 3]
7 |
8 | # ----------------------------------------
9 |
10 | a = [
11 | 1,
12 | 2,
13 | 3
14 | ]
15 |
16 | # ----------------------------------------
17 |
18 | a = [
19 | 1,
20 | 2,
21 | 3,
22 | ]
23 |
24 | # ----------------------------------------
25 |
26 | a = ['apple', 'orange', 'melon']
27 |
28 | # ----------------------------------------
29 |
30 | a = [1, 'apple', 2, 'orange', 3, 'melon']
31 |
32 | # ----------------------------------------
33 |
34 | a = [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
35 |
36 | # ----------------------------------------
37 |
38 | a = [1, 2, 3]
39 | # 1つ目の要素を取得
40 | a[0] #=> 1
41 | # 2つ目の要素を取得
42 | a[1] #=> 2
43 | # 3つ目の要素を取得
44 | a[2] #=> 3
45 |
46 | # ----------------------------------------
47 |
48 | a = [1, 2, 3]
49 | a[100] #=> nil
50 |
51 | # ----------------------------------------
52 |
53 | a = [1, 2, 3]
54 | a.size #=> 3
55 | a.length #=> 3
56 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_02_01.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3]
2 | a[1] = 20
3 | a #=> [1, 20, 3]
4 |
5 | # ----------------------------------------
6 |
7 | a = [1, 2, 3]
8 | a[4] = 50
9 | a #=> [1, 2, 3, nil, 50]
10 |
11 | # ----------------------------------------
12 |
13 | a = []
14 | a << 1
15 | a << 2
16 | a << 3
17 | a #=> [1, 2, 3]
18 |
19 | # ----------------------------------------
20 |
21 | a = [1, 2, 3]
22 | # 2番目の要素を削除する(削除した値が戻り値になる)
23 | a.delete_at(1) #=> 2
24 | a #=> [1, 3]
25 |
26 | # 存在しない添え字を指定するとnilが返る
27 | a.delete_at(100) #=> nil
28 | a #=> [1, 3]
29 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_02_02.rb:
--------------------------------------------------------------------------------
1 | a, b = 1, 2
2 | a #=> 1
3 | b #=> 2
4 |
5 | # ----------------------------------------
6 |
7 | # 配列を使って多重代入する
8 | a, b = [1, 2]
9 | a #=> 1
10 | b #=> 2
11 |
12 | # 右辺の数が少ない場合はnilが入る
13 | c, d = [10]
14 | c #=> 10
15 | d #=> nil
16 |
17 | # 右辺の数が多い場合ははみ出した値が切り捨てられる
18 | e, f = [100, 200, 300]
19 | e #=> 100
20 | f #=> 200
21 |
22 | # ----------------------------------------
23 |
24 | # divmodは商と余りを配列で返す
25 | 14.divmod(3) #=> [4, 2]
26 |
27 | # 戻り値を配列のまま受け取る
28 | quo_rem = 14.divmod(3)
29 | "商=#{quo_rem[0]}, 余り=#{quo_rem[1]}" #=> "商=4, 余り=2"
30 |
31 | # 多重代入で別々の変数として受け取る
32 | quotient, remainder = 14.divmod(3)
33 | "商=#{quotient}, 余り=#{remainder}" #=> "商=4, 余り=2"
34 |
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_03_01.rb:
--------------------------------------------------------------------------------
1 | < 10
8 | JavaScript
9 |
10 | # ----------------------------------------
11 |
12 | < 10
19 | JavaScript
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_03_02.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4]
2 | sum = 0
3 | numbers.each do |n|
4 | sum += n
5 | end
6 | sum #=> 10
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_03_03.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3, 1, 2, 3]
2 | # 配列から値が2の要素を削除する
3 | a.delete(2)
4 | a #=> [1, 3, 1, 3]
5 |
6 | # ----------------------------------------
7 |
8 | a = [1, 2, 3, 1, 2, 3]
9 | # 配列から値が奇数の要素を削除する
10 | a.delete_if do |n|
11 | n.odd?
12 | end
13 | a #=> [2, 2]
14 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_03_05.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4]
2 | sum = 0
3 | # ブロックをあえて改行せずに書く
4 | numbers.each do |n| sum += n end
5 | sum #=> 10
6 |
7 | # ----------------------------------------
8 |
9 | numbers = [1, 2, 3, 4]
10 | sum = 0
11 | # do ... endの代わりに{}を使う
12 | numbers.each { |n| sum += n }
13 | sum #=> 10
14 |
15 | # ----------------------------------------
16 |
17 | numbers = [1, 2, 3, 4]
18 | sum = 0
19 | # {}でブロックを作り、なおかつ改行を入れる
20 | numbers.each { |n|
21 | sum += n
22 | }
23 | sum #=> 10
24 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_04_01.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4, 5]
2 | new_numbers = []
3 | numbers.each { |n| new_numbers << n * 10 }
4 | new_numbers #=> [10, 20, 30, 40, 50]
5 |
6 | # ----------------------------------------
7 |
8 | numbers = [1, 2, 3, 4, 5]
9 | # ブロックの戻り値が新しい配列の各要素になる
10 | new_numbers = numbers.map { |n| n * 10 }
11 | new_numbers #=> [10, 20, 30, 40, 50]
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_04_02.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4, 5, 6]
2 | # 戻り値が真になった要素だけが集められる
3 | even_numbers = numbers.select { |n| n.even? }
4 | even_numbers #=> [2, 4, 6]
5 |
6 | # ----------------------------------------
7 |
8 | numbers = [1, 2, 3, 4, 5, 6]
9 | # 3の倍数を除外する(3の倍数以外を集める)
10 | non_multiples_of_three = numbers.reject { |n| n % 3 == 0 }
11 | non_multiples_of_three #=> [1, 2, 4, 5]
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_04_03.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4, 5, 6]
2 | # ブロックの戻り値が最初に真になった要素を返す
3 | even_number = numbers.find { |n| n.even? }
4 | even_number #=> 2
5 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_04_04.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4]
2 | numbers.sum #=> 10
3 |
4 | # ----------------------------------------
5 |
6 | numbers = [1, 2, 3, 4]
7 | # 各要素を2倍しながら合計する
8 | numbers.sum { |n| n * 2 } #=> 20
9 |
10 | # ----------------------------------------
11 |
12 | numbers = [1, 2, 3, 4]
13 | # 初期値に5を指定する(5 + 1 + 2 + 3 + 4 = 15)
14 | numbers.sum(5) #=> 15
15 |
16 | # ----------------------------------------
17 |
18 | chars = ['a', 'b', 'c']
19 | # 文字列を連結する('' + 'a' + 'b' + 'c' = 'abc')
20 | chars.sum('') #=> "abc"
21 |
22 | # ----------------------------------------
23 |
24 | chars = ['a', 'b', 'c']
25 | chars.join #=> "abc"
26 |
27 | # ----------------------------------------
28 |
29 | chars = ['a', 'b', 'c']
30 | # 区切り文字をハイフンにして各要素を連結する
31 | chars.join('-') #=> "a-b-c"
32 |
33 | # ----------------------------------------
34 |
35 | data = ['a', 2, 'b', 4]
36 | # 配列に数値が含まれていても連結可能(to_sメソッドで文字列に変換されるため)
37 | data.join #=> "a2b4"
38 |
39 | # ----------------------------------------
40 |
41 | chars = ['a', 'b', 'c']
42 | # 先頭に'>'を付け、各要素を大文字にして連結する
43 | chars.sum('>') { |c| c.upcase } #=> ">ABC"
44 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_04_05.rb:
--------------------------------------------------------------------------------
1 | # このコードは、
2 | ['ruby', 'java', 'python'].map { |s| s.upcase } #=> ["RUBY", "JAVA", "PYTHON"]
3 | # こう書き換えられる
4 | ['ruby', 'java', 'python'].map(&:upcase) #=> ["RUBY", "JAVA", "PYTHON"]
5 |
6 | # このコードは、
7 | [1, 2, 3, 4, 5, 6].select { |n| n.odd? } #=> [1, 3, 5]
8 | # こう書き換えられる
9 | [1, 2, 3, 4, 5, 6].select(&:odd?) #=> [1, 3, 5]
10 |
11 | # ----------------------------------------
12 |
13 | # ブロックの中でメソッドではなく演算子を使っている
14 | [1, 2, 3, 4, 5, 6].select { |n| n % 3 == 0 }
15 |
16 | # ブロック内のメソッドで引数を渡している
17 | [9, 10, 11, 12].map { |n| n.to_s(16) }
18 |
19 | # ブロックの中で複数の文を実行している
20 | [1, 2, 3, 4].map do |n|
21 | m = n * 4
22 | m.to_s
23 | end
24 |
25 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_05_00.rb:
--------------------------------------------------------------------------------
1 | 1..5
2 | 1...5
3 | 'a'..'e'
4 | 'a'...'e'
5 |
6 | # ----------------------------------------
7 |
8 | (1..5).class #=> Range
9 | (1...5).class #=> Range
10 |
11 | # ----------------------------------------
12 |
13 | # ..を使うと5が範囲に含まれる(1以上5以下)
14 | range = 1..5
15 | range.include?(0) #=> false
16 | range.include?(1) #=> true
17 | range.include?(4.9) #=> true
18 | range.include?(5) #=> true
19 | range.include?(6) #=> false
20 |
21 | # ...を使うと5が範囲に含まれない(1以上5未満)
22 | range = 1...5
23 | range.include?(0) #=> false
24 | range.include?(1) #=> true
25 | range.include?(4.9) #=> true
26 | range.include?(5) #=> false
27 | range.include?(6) #=> false
28 |
29 | # ----------------------------------------
30 |
31 | # ()で囲まずにメソッドを呼び出すとエラーになる
32 | 1..5.include?(1) #=> undefined method `include?' for 5:Integer (NoMethodError)
33 | # ()で囲めばエラーにならない
34 | (1..5).include?(1) #=> true
35 |
36 | # ----------------------------------------
37 |
38 | 1..(5.include?(1))
39 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_05_01.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3, 4, 5]
2 | # 2番目から4番目までの要素を取得する
3 | a[1..3] #=> [2, 3, 4]
4 |
5 | # ----------------------------------------
6 |
7 | a = 'abcdef'
8 | # 2文字目から4文字目までを抜き出す
9 | a[1..3] #=> "bcd"
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_05_02.rb:
--------------------------------------------------------------------------------
1 | # 不等号を使う場合
2 | def liquid?(temperature)
3 | # 0度以上100度未満であれば液体、と判定したい
4 | 0 <= temperature && temperature < 100
5 | end
6 | liquid?(-1) #=> false
7 | liquid?(0) #=> true
8 | liquid?(99) #=> true
9 | liquid?(100) #=> false
10 |
11 | # 範囲オブジェクトを使う場合
12 | def liquid?(temperature)
13 | (0...100).include?(temperature)
14 | end
15 | liquid?(-1) #=> false
16 | liquid?(0) #=> true
17 | liquid?(99) #=> true
18 | liquid?(100) #=> false
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_05_03.rb:
--------------------------------------------------------------------------------
1 | def charge(age)
2 | case age
3 | # 0歳から5歳までの場合
4 | when 0..5
5 | 0
6 | # 6歳から12歳までの場合
7 | when 6..12
8 | 300
9 | # 13歳から18歳までの場合
10 | when 13..18
11 | 600
12 | # それ以外の場合
13 | else
14 | 1000
15 | end
16 | end
17 | charge(3) #=> 0
18 | charge(12) #=> 300
19 | charge(16) #=> 600
20 | charge(25) #=> 1000
21 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_05_04.rb:
--------------------------------------------------------------------------------
1 | (1..5).to_a #=> [1, 2, 3, 4, 5]
2 | (1...5).to_a #=> [1, 2, 3, 4]
3 |
4 | ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
5 | ('a'...'e').to_a #=> ["a", "b", "c", "d"]
6 |
7 | ('bad'..'bag').to_a #=> ["bad", "bae", "baf", "bag"]
8 | ('bad'...'bag').to_a #=> ["bad", "bae", "baf"]
9 |
10 | # ----------------------------------------
11 |
12 | [*1..5] #=> [1, 2, 3, 4, 5]
13 | [*1...5] #=> [1, 2, 3, 4]
14 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_05_05.rb:
--------------------------------------------------------------------------------
1 | # 範囲オブジェクトを配列に変換してから繰り返し処理を行う
2 | numbers = (1..4).to_a
3 | sum = 0
4 | numbers.each { |n| sum += n }
5 | sum #=> 10
6 |
7 | # ----------------------------------------
8 |
9 | sum = 0
10 | # 範囲オブジェクトに対して直接eachメソッドを呼び出す
11 | (1..4).each { |n| sum += n }
12 | sum #=> 10
13 |
14 | # ----------------------------------------
15 |
16 | numbers = []
17 | # 1から10まで2回ごとに繰り返し処理を行う
18 | (1..10).step(2) { |n| numbers << n }
19 | numbers #=> [1, 3, 5, 7, 9]
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_06_00.rb:
--------------------------------------------------------------------------------
1 | to_hex(0, 0, 0) #=> "#000000"
2 | to_hex(255, 255, 255) #=> "#ffffff"
3 | to_hex(4, 60, 120) #=> "#043c78"
4 | to_ints('#000000') #=> [0, 0, 0]
5 | to_ints('#ffffff') #=> [255, 255, 255]
6 | to_ints('#043c78') #=> [4, 60, 120]
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_06_02.rb:
--------------------------------------------------------------------------------
1 | def to_hex(r, g, b)
2 | '#' +
3 | r.to_s(16).rjust(2, '0') +
4 | g.to_s(16).rjust(2, '0') +
5 | b.to_s(16).rjust(2, '0')
6 | end
7 |
8 | # ----------------------------------------
9 |
10 | def to_hex(r, g, b)
11 | hex = '#'
12 | [r, g, b].each do |n|
13 | hex += n.to_s(16).rjust(2, '0')
14 | end
15 | hex
16 | end
17 |
18 | # ----------------------------------------
19 |
20 | def to_hex(r, g, b)
21 | [r, g, b].sum('#') do |n|
22 | n.to_s(16).rjust(2, '0')
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_06_04.rb:
--------------------------------------------------------------------------------
1 | def to_ints(hex)
2 | r = hex[1..2]
3 | g = hex[3..4]
4 | b = hex[5..6]
5 | ints = []
6 | [r, g, b].each do |s|
7 | ints << s.hex
8 | end
9 | ints
10 | end
11 |
12 | # ----------------------------------------
13 |
14 | def to_ints(hex)
15 | r = hex[1..2]
16 | g = hex[3..4]
17 | b = hex[5..6]
18 | [r, g, b].map do |s|
19 | s.hex
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_06_05.rb:
--------------------------------------------------------------------------------
1 | def to_ints(hex)
2 | r, g, b = hex[1..2], hex[3..4], hex[5..6]
3 | [r, g, b].map do |s|
4 | s.hex
5 | end
6 | end
7 |
8 | # ----------------------------------------
9 |
10 | def to_ints(hex)
11 | r, g, b = hex.scan(/\w\w/)
12 | [r, g, b].map do |s|
13 | s.hex
14 | end
15 | end
16 |
17 | # ----------------------------------------
18 |
19 | '#12abcd'.scan(/\w\w/) #=> ["12", "ab", "cd"]
20 |
21 | # ----------------------------------------
22 |
23 | def to_ints(hex)
24 | hex.scan(/\w\w/).map do |s|
25 | s.hex
26 | end
27 | end
28 |
29 | # ----------------------------------------
30 |
31 | def to_ints(hex)
32 | hex.scan(/\w\w/).map(&:hex)
33 | end
34 |
35 | # ----------------------------------------
36 |
37 | # リファクタリング前
38 | def to_ints(hex)
39 | r = hex[1..2]
40 | g = hex[3..4]
41 | b = hex[5..6]
42 | ints = []
43 | [r, g, b].each do |s|
44 | ints << s.hex
45 | end
46 | ints
47 | end
48 |
49 | # リファクタリング後
50 | def to_ints(hex)
51 | hex.scan(/\w\w/).map(&:hex)
52 | end
53 |
54 | # ----------------------------------------
55 |
56 | # Ruby 3.0であればこんな書き方も可能
57 | def to_ints(hex) = hex.scan(/\w\w/).map(&:hex)
58 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_01.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3, 4, 5]
2 | a[1, 3] #=> [2, 3, 4]
3 |
4 | # ----------------------------------------
5 |
6 | a = [1, 2, 3, 4, 5]
7 | a.values_at(0, 2, 4) #=> [1, 3, 5]
8 |
9 | # ----------------------------------------
10 |
11 | a = [1, 2, 3]
12 | # 最後の要素を取得する
13 | a[a.size - 1] #=> 3
14 |
15 | # ----------------------------------------
16 |
17 | a = [1, 2, 3]
18 |
19 | # 最後の要素を取得する
20 | a[-1] #=> 3
21 |
22 | # 最後から2番目の要素を取得する
23 | a[-2] #=> 2
24 |
25 | # 最後から2番目の要素から2つの要素を取得する
26 | a[-2, 2] #=> [2, 3]
27 |
28 | # ----------------------------------------
29 |
30 | a = [1, 2, 3]
31 | a.last #=> 3
32 | a.last(2) #=> [2, 3]
33 |
34 | # ----------------------------------------
35 |
36 | a = [1, 2, 3]
37 | a.first #=> 1
38 | a.first(2) #=> [1, 2]
39 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_02.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3]
2 | a[-3] = -10 #=> [-10, 2, 3]
3 |
4 | # 指定可能な負の値よりも小さくなるとエラーが発生する
5 | a[-4] = 0 #=> index -4 too small for array; minimum: -3 (IndexError)
6 |
7 | # ----------------------------------------
8 |
9 | a = [1, 2, 3, 4, 5]
10 | # 2つ目から3要素ぶんを100で置き換える
11 | a[1, 3] = 100
12 | a #=> [1, 100, 5]
13 |
14 | # ----------------------------------------
15 |
16 | a = []
17 | a.push(1) #=> [1]
18 | a.push(2, 3) #=> [1, 2, 3]
19 |
20 | # ----------------------------------------
21 |
22 | a = [1, 2, 3, 1, 2, 3]
23 | # 値が2である要素を削除する(削除した値が戻り値になる)
24 | a.delete(2) #=> 2
25 | a #=> [1, 3, 1, 3]
26 |
27 | # 存在しない値を指定するとnilが返る
28 | a.delete(5) #=> nil
29 | a #=> [1, 3, 1, 3]
30 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_03.rb:
--------------------------------------------------------------------------------
1 | a = [1]
2 | b = [2, 3]
3 | a.concat(b) #=> [1, 2, 3]
4 |
5 | # aは変更される(破壊的)
6 | a #=> [1, 2, 3]
7 |
8 | # bは変更されない
9 | b #=> [2, 3]
10 |
11 | # ----------------------------------------
12 |
13 | a = [1]
14 | b = [2, 3]
15 | a + b #=> [1, 2, 3]
16 |
17 | # aもbも変更されない(非破壊的)
18 | a #=> [1]
19 | b #=> [2, 3]
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_04.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3]
2 | b = [3, 4, 5]
3 | a | b #=> [1, 2, 3, 4, 5]
4 |
5 | # ----------------------------------------
6 |
7 | a = [1, 2, 3]
8 | b = [3, 4, 5]
9 | a - b #=> [1, 2]
10 |
11 | # ----------------------------------------
12 |
13 | a = [1, 2, 3]
14 | b = [3, 4, 5]
15 | a & b #=> [3]
16 |
17 | # ----------------------------------------
18 |
19 | require 'set'
20 |
21 | a = Set[1, 2, 3]
22 | b = Set[3, 4, 5]
23 | a | b #=> #
24 | a - b #=> #
25 | a & b #=> #
26 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_05.rb:
--------------------------------------------------------------------------------
1 | e, f = 100, 200, 300
2 | e #=> 100
3 | f #=> 200
4 |
5 | # ----------------------------------------
6 |
7 | e, *f = 100, 200, 300
8 | e #=> 100
9 | f #=> [200, 300]
10 |
11 | # ----------------------------------------
12 |
13 | # 100だけeに格納して、残りの要素は無視する
14 | e, * = 100, 200, 300
15 | e #=> 100
16 |
17 | # ----------------------------------------
18 |
19 | # *を省略して200と300を無視する
20 | e, = 100, 200, 300
21 | e #=> 100
22 |
23 | # ----------------------------------------
24 |
25 | a, *b, c, d = 1, 2, 3, 4, 5
26 | a #=> 1
27 | b #=> [2, 3]
28 | c #=> 4
29 | d #=> 5
30 |
31 | # ----------------------------------------
32 |
33 | # 1がa、2がc、3がdに対応する。右辺に残りの要素はなくなったのでbは空の配列になる
34 | a, *b, c, d = 1, 2, 3
35 | a #=> 1
36 | b #=> []
37 | c #=> 2
38 | d #=> 3
39 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_06.rb:
--------------------------------------------------------------------------------
1 | a = []
2 | a.push(1) #=> [1]
3 | # 2と3を一度に追加する
4 | a.push(2, 3) #=> [1, 2, 3]
5 |
6 | # ----------------------------------------
7 |
8 | a = []
9 | b = [2, 3]
10 | a.push(1) #=> [1]
11 | # 配列をそのまま追加する(a.push([2, 3])と同じ)
12 | a.push(b)
13 | a #=> [1, [2, 3]]
14 |
15 | # ----------------------------------------
16 |
17 | a = []
18 | b = [2, 3]
19 | a.push(1) #=> [1]
20 | # 配列を*付きで追加する(a.push(2, 3)と同じ)
21 | a.push(*b) #=> [1, 2, 3]
22 |
23 | # ----------------------------------------
24 |
25 | jp = ['japan', '日本']
26 | country = '日本'
27 | case country
28 | # *により配列が展開され、when 'japan', '日本'と書いたのと同じ意味になる
29 | when *jp
30 | 'こんにちは'
31 | end
32 | #=> "こんにちは"
33 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_07.rb:
--------------------------------------------------------------------------------
1 | def greet(*names)
2 | "#{names.join('と')}、こんにちは!"
3 | end
4 | greet('田中さん') #=> "田中さん、こんにちは!"
5 | greet('田中さん', '鈴木さん') #=> "田中さんと鈴木さん、こんにちは!"
6 | greet('田中さん', '鈴木さん', '佐藤さん') #=> "田中さんと鈴木さんと佐藤さん、こんにちは!"
7 |
8 | # ----------------------------------------
9 |
10 | a, *b, c, d = 1, 2, 3, 4, 5
11 | a #=> 1
12 | b #=> [2, 3]
13 | c #=> 4
14 | d #=> 5
15 |
16 | # ----------------------------------------
17 |
18 | # 多重代入の例の左辺と同じように引数を設定する
19 | def foo(a, *b, c, d)
20 | puts "a=#{a}, b=#{b}, c=#{c}, d=#{d}"
21 | end
22 |
23 | # 多重代入の例の右辺と同じ形の引数でメソッドを呼び出す
24 | # すると、多重代入のときと同じように引数が渡される
25 | foo(1, 2, 3, 4, 5)
26 | #=> a=1, b=[2, 3], c=4, d=5
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_08.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3]
2 |
3 | # []の中にそのまま配列を置くと、入れ子になった配列(ネストした配列)になる
4 | [a] #=> [[1, 2, 3]]
5 |
6 | # *付きで配列を置くと、展開されて別々の要素になる
7 | [*a] #=> [1, 2, 3]
8 |
9 | # ----------------------------------------
10 |
11 | a = [1, 2, 3]
12 | [-1, 0, *a, 4, 5] #=> [-1, 0, 1, 2, 3, 4, 5]
13 |
14 | # ----------------------------------------
15 |
16 | a = [1, 2, 3]
17 | [-1, 0] + a + [4, 5] #=> [-1, 0, 1, 2, 3, 4, 5]
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_09.rb:
--------------------------------------------------------------------------------
1 | # 配列が等しい場合
2 | [1, 2, 3] == [1, 2, 3] #=> true
3 |
4 | # 配列が等しくない場合
5 | [1, 2, 3] == [1, 2, 4] #=> false
6 | [1, 2, 3] == [1, 2] #=> false
7 | [1, 2, 3] == [1, 2, 3, 4] #=> false
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_10.rb:
--------------------------------------------------------------------------------
1 | # []で文字列の配列を作成する
2 | ['apple', 'melon', 'orange'] #=> ["apple", "melon", "orange"]
3 |
4 | # %wで文字列の配列を作成する(!で囲む場合)
5 | %w!apple melon orange! #=> ["apple", "melon", "orange"]
6 |
7 | # %wで文字列の配列を作成する(丸カッコで囲む場合)
8 | %w(apple melon orange) #=> ["apple", "melon", "orange"]
9 |
10 | # 空白文字(スペースや改行)が連続した場合もひとつの区切り文字と見なされる
11 | %w(
12 | apple
13 | melon
14 | orange
15 | )
16 | #=> ["apple", "melon", "orange"]
17 |
18 | # ----------------------------------------
19 |
20 | %w(big\ apple small\ melon orange) #=> ["big apple", "small melon", "orange"]
21 |
22 | # ----------------------------------------
23 |
24 | prefix = 'This is'
25 | %W(#{prefix}\ an\ apple small\nmelon orange)
26 | #=> ["This is an apple", "small\nmelon", "orange"]
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_11.rb:
--------------------------------------------------------------------------------
1 | 'Ruby'.chars #=> ["R", "u", "b", "y"]
2 |
3 | # ----------------------------------------
4 |
5 | 'Ruby,Java,Python'.split(',')
6 | #=> ["Ruby", "Java", "Python"]
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_12.rb:
--------------------------------------------------------------------------------
1 | # 以下のコードはa = []と同じ
2 | a = Array.new
3 |
4 | # ----------------------------------------
5 |
6 | # 要素が5つの配列を作成する
7 | a = Array.new(5)
8 | a #=> [nil, nil, nil, nil, nil]
9 |
10 | # ----------------------------------------
11 |
12 | # 要素が5つで0をデフォルト値とする配列を作成する
13 | a = Array.new(5, 0)
14 | a #=> [0, 0, 0, 0, 0]
15 |
16 | # ----------------------------------------
17 |
18 | # 1, 2, 3, 1, 2, 3...と繰り返す配列を作る
19 | a = Array.new(10) { |n| n % 3 + 1 }
20 | a #=> [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
21 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_13.rb:
--------------------------------------------------------------------------------
1 | # 要素が5つで'default'をデフォルト値とする配列を作成する
2 | a = Array.new(5, 'default')
3 | a #=> ["default", "default", "default", "default", "default"]
4 |
5 | # 1番目の要素を取得する
6 | str = a[0]
7 | str #=> "default"
8 |
9 | # 1番目の要素を大文字に変換する(破壊的変更)
10 | str.upcase!
11 | str #=> "DEFAULT"
12 |
13 | # 配列の要素すべてが大文字に変わってしまった!
14 | a #=> ["DEFAULT", "DEFAULT", "DEFAULT", "DEFAULT", "DEFAULT"]
15 |
16 | # ----------------------------------------
17 |
18 | # ブロックを使って、ブロックの戻り値をデフォルト値とする
19 | # (ブロックパラメータには添え字が渡されるが、ここでは使わないのでブロックパラメータを省略)
20 | a = Array.new(5) { 'default' }
21 | a #=> ["default", "default", "default", "default", "default"]
22 |
23 | # 1番目の要素を取得する
24 | str = a[0]
25 | str #=> "default"
26 |
27 | # 1番目の要素を大文字に変換する(破壊的変更)
28 | str.upcase!
29 | str #=> "DEFAULT"
30 |
31 | # 1番目の要素だけが大文字になり、ほかは変わらない
32 | a #=> ["DEFAULT", "default", "default", "default", "default"]
33 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_07_14.rb:
--------------------------------------------------------------------------------
1 | # 要素が5つで0を初期値とする配列を作成する
2 | a = Array.new(5, 0)
3 | a #=> [0, 0, 0, 0, 0]
4 |
5 | # 1番目の要素を取得する
6 | n = a[0]
7 | n #=> 0
8 |
9 | # 数値だと破壊的な変更(たとえば強制的に負の数に変更する等)はできない
10 | # n.negative!
11 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_08_01.rb:
--------------------------------------------------------------------------------
1 | fruits = ['apple', 'orange', 'melon']
2 | # ブロック引数のiには0、1、2・・・と要素の添え字が入る
3 | fruits.each_with_index { |fruit, i| puts "#{i}: #{fruit}" }
4 | #=> 0: apple
5 | # 1: orange
6 | # 2: melon
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_08_02.rb:
--------------------------------------------------------------------------------
1 | fruits = ['apple', 'orange', 'melon']
2 | # mapとして処理しつつ、添え字も受け取る
3 | fruits.map.with_index { |fruit, i| "#{i}: #{fruit}" }
4 | #=> ["0: apple", "1: orange", "2: melon"]
5 |
6 | # ----------------------------------------
7 |
8 | fruits = ['apple', 'orange', 'melon']
9 | # 名前に"a"を含み、なおかつ添え字が奇数である要素を削除する
10 | fruits.delete_if.with_index { |fruit, i| fruit.include?('a') && i.odd? }
11 | #=> ["apple", "melon"]
12 |
13 | # ----------------------------------------
14 |
15 | fruits = ['apple', 'orange', 'melon']
16 | # ブロック無しでメソッドを呼び出すとEnumeratorオブジェクトが返される
17 | p fruits.each #=> #
18 | p fruits.map #=> #
19 | p fruits.delete_if #=> #
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_08_03.rb:
--------------------------------------------------------------------------------
1 | fruits = ['apple', 'orange', 'melon']
2 |
3 | # eachで繰り返しつつ、1から始まる添え字を取得する
4 | fruits.each.with_index(1) { |fruit, i| puts "#{i}: #{fruit}" }
5 | #=> 1: apple
6 | # 2: orange
7 | # 3: melon
8 |
9 | # mapで処理しつつ、10から始まる添え字を取得する
10 | fruits.map.with_index(10) { |fruit, i| "#{i}: #{fruit}" }
11 | #=> ["10: apple", "11: orange", "12: melon"]
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_08_06.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4]
2 | sum = 0
3 | # ブロックの外にあるsumとは別物の変数sumを用意する
4 | numbers.each do |n; sum|
5 | # 別物のsumを10で初期化し、ブロックパラメータの値を加算する
6 | sum = 10
7 | sum += n
8 | # 加算した値をターミナルに表示する
9 | puts sum
10 | end
11 | #=> 11
12 | # 12
13 | # 13
14 | # 14
15 |
16 | # ブロックの中で使っていたsumは別物なので、ブロックの外にsumには変化がない
17 | sum #=> 0
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_08_07.rb:
--------------------------------------------------------------------------------
1 | # sample.txtを開いて文字列を書き込む(クローズ処理は自動的に行われる)
2 | File.open('./sample.txt', 'w') do |file|
3 | file.puts('1行目のテキストです。')
4 | file.puts('2行目のテキストです。')
5 | file.puts('3行目のテキストです。')
6 | end
7 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_08_08.rb:
--------------------------------------------------------------------------------
1 | a = [1, 2, 3]
2 |
3 | # ブロックを渡さないときは指定した値が見つからないとnilが返る
4 | a.delete(100) #=> nil
5 |
6 | # ブロックを渡すとブロックの戻り値が指定した値が見つからないときの戻り値になる
7 | a.delete(100) do
8 | 'NG'
9 | end
10 | #=> "NG"
11 |
12 | # ----------------------------------------
13 |
14 | a.delete 100 do
15 | 'NG'
16 | end
17 | #=> "NG"
18 |
19 | # ----------------------------------------
20 |
21 | a.delete 100 { 'NG' }
22 | #=> syntax error, unexpected '{', expecting end-of-input (SyntaxError)
23 |
24 | # ----------------------------------------
25 |
26 | a.delete(100) { 'NG' }
27 | #=> "NG"
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_09_01.rb:
--------------------------------------------------------------------------------
1 | # 10以上を表す範囲オブジェクト(Ruby 2.6以降)
2 | (10..)
3 |
4 | # 終端を省略する代わりにnilを指定しても同じ
5 | 10..nil
6 |
7 | # ----------------------------------------
8 |
9 | # 10以下を範囲オブジェクト(Ruby 2.7以降)
10 | (..10)
11 |
12 | # 始端を省略する代わりにnilを指定しても同じ
13 | nil..10
14 |
15 | # ----------------------------------------
16 |
17 | numbers = [10, 20, 30, 40, 50]
18 |
19 | # 3番目以降の要素を取得
20 | numbers[2..] #=> [30, 40, 50]
21 |
22 | # 2番目以前の要素を取得
23 | numbers[..1] #=> [10, 20]
24 |
25 | # ----------------------------------------
26 |
27 | # 全範囲を表す範囲オブジェクト(いずれも同じ意味)
28 | nil..nil
29 | (nil..)
30 | (..nil)
31 |
32 | # nilを両方とも省略すると構文エラー
33 | (..)
34 | #=> syntax error, unexpected ')' (SyntaxError)
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_10_01.rb:
--------------------------------------------------------------------------------
1 | sum = 0
2 | # 処理を5回繰り返す。nには0, 1, 2, 3, 4が入る
3 | 5.times { |n| sum += n }
4 | sum #=> 10
5 |
6 | # ----------------------------------------
7 |
8 | sum = 0
9 | # sumに1を加算する処理を5回繰り返す
10 | 5.times { sum += 1 }
11 | sum #=> 5
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_10_02.rb:
--------------------------------------------------------------------------------
1 | a = []
2 | 10.upto(14) { |n| a << n }
3 | a #=> [10, 11, 12, 13, 14]
4 |
5 | # ----------------------------------------
6 |
7 | a = []
8 | 14.downto(10) { |n| a << n }
9 | a #=> [14, 13, 12, 11, 10]
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_10_03.rb:
--------------------------------------------------------------------------------
1 | a = []
2 | 1.step(10, 2) { |n| a << n }
3 | a #=> [1, 3, 5, 7, 9]
4 |
5 | # ----------------------------------------
6 |
7 | a = []
8 | 10.step(1, -2) { |n| a << n }
9 | a #=> [10, 8, 6, 4, 2]
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_10_04.rb:
--------------------------------------------------------------------------------
1 | a = []
2 | while a.size < 5
3 | a << 1
4 | end
5 | a #=> [1, 1, 1, 1, 1]
6 |
7 | # ----------------------------------------
8 |
9 | a = []
10 | while a.size < 5 do a << 1 end
11 | a #=> [1, 1, 1, 1, 1]
12 |
13 | # ----------------------------------------
14 |
15 | a = []
16 | a << 1 while a.size < 5
17 | a #=> [1, 1, 1, 1, 1]
18 |
19 | # ----------------------------------------
20 |
21 | a = []
22 |
23 | # 以下のコードは常に条件が偽になるので実行されない
24 | while false
25 | a << 1
26 | end
27 | a #=> []
28 |
29 | # begin ... endで囲むとどんな条件でも最低1回は実行される
30 | begin
31 | a << 1
32 | end while false
33 | a #=> [1]
34 |
35 | # ----------------------------------------
36 |
37 | a = [1, 2, 3, 4, 5]
38 | until a.size <= 3
39 | a.delete_at(-1)
40 | end
41 | a #=> [1, 2, 3]
42 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_10_05.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4]
2 | sum = 0
3 | for n in numbers
4 | sum += n
5 | end
6 | sum #=> 10
7 |
8 | # doを入れて1行で書くことも可能
9 | sum = 0
10 | for n in numbers do sum += n end
11 | sum #=> 10
12 |
13 | # ----------------------------------------
14 |
15 | numbers = [1, 2, 3, 4]
16 | sum = 0
17 | numbers.each do |n|
18 | sum += n
19 | end
20 | sum #=> 10
21 |
22 | # ----------------------------------------
23 |
24 | numbers = [1, 2, 3, 4]
25 | sum = 0
26 | numbers.each do |n|
27 | sum_value = n.even? ? n * 10 : n
28 | sum += sum_value
29 | end
30 | # ブロックパラメータやブロック内で作成した変数はブロックの外では参照できない
31 | n #=> undefined local variable or method `n' for main:Object (NameError)
32 | sum_value #=> undefined local variable or method `sum_value' for main:Object (NameError)
33 |
34 | sum = 0
35 | for n in numbers
36 | sum_value = n.even? ? n * 10 : n
37 | sum += sum_value
38 | end
39 | # for文の中で作成された変数はfor文の外でも参照できる
40 | n #=> 4
41 | sum_value #=> 40
42 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_10_06.rb:
--------------------------------------------------------------------------------
1 | while true
2 | # 無限ループ用の処理
3 | end
4 |
5 | # ----------------------------------------
6 |
7 | loop do
8 | # 無限ループ用の処理
9 | end
10 |
11 | # ----------------------------------------
12 |
13 | numbers = [1, 2, 3, 4, 5]
14 | loop do
15 | # sampleメソッドでランダムに要素を1つ取得する
16 | n = numbers.sample
17 | puts n
18 | break if n == 5
19 | end
20 | #=> 3
21 | # 2
22 | # 4
23 | # 5
24 |
25 | # ----------------------------------------
26 |
27 | while true
28 | n = numbers.sample
29 | puts n
30 | break if n == 5
31 | end
32 | #=> 4
33 | # 1
34 | # 5
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_10_07.rb:
--------------------------------------------------------------------------------
1 | def factorial(n)
2 | # 引数の値を1減らして、factorialメソッド自身をもう一度呼び出す(一種の繰り返し処理)
3 | # 引数が0になったら1を返して繰り返し処理が終了する
4 | n > 0 ? n * factorial(n - 1) : 1
5 | end
6 | # 5! = 5 * 4 * 3 * 2 * 1を求める
7 | factorial(5) #=> 120
8 | # 0!は1
9 | factorial(0) #=> 1
10 |
11 | # ----------------------------------------
12 |
13 | def factorial(n)
14 | # 再帰呼び出しを使わずに階乗を計算する例
15 | ret = 1
16 | (1..n).each { |n| ret *= n }
17 | ret
18 | end
19 | factorial(5) #=> 120
20 | factorial(0) #=> 1
21 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_11_01.rb:
--------------------------------------------------------------------------------
1 | # shuffleメソッドで配列の要素をランダムに並び替える
2 | numbers = [1, 2, 3, 4, 5].shuffle
3 | numbers.each do |n|
4 | puts n
5 | # 5が出たら繰り返しを脱出する
6 | break if n == 5
7 | end
8 | #=> 3
9 | # 1
10 | # 5
11 |
12 | # ----------------------------------------
13 |
14 | numbers = [1, 2, 3, 4, 5].shuffle
15 | i = 0
16 | while i < numbers.size
17 | n = numbers[i]
18 | puts n
19 | break if n == 5
20 | i += 1
21 | end
22 | #=> 2
23 | # 4
24 | # 5
25 |
26 | # ----------------------------------------
27 |
28 | ret =
29 | while true
30 | break
31 | end
32 | ret #=> nil
33 |
34 | ret =
35 | while true
36 | break 123
37 | end
38 | ret #=> 123
39 |
40 | # ----------------------------------------
41 |
42 | fruits = ['apple', 'melon', 'orange']
43 | numbers = [1, 2, 3]
44 | fruits.each do |fruit|
45 | # 配列の数字をランダムに入れ替え、3が出たらbreakする
46 | numbers.shuffle.each do |n|
47 | puts "#{fruit}, #{n}"
48 | # numbersのループは脱出するが、fruitsのループは継続する
49 | break if n == 3
50 | end
51 | end
52 | #=> apple, 1
53 | # apple, 3
54 | # melon, 2
55 | # melon, 3
56 | # orange, 2
57 | # orange, 1
58 | # orange, 3
59 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_11_02.rb:
--------------------------------------------------------------------------------
1 | fruits = ['apple', 'melon', 'orange']
2 | numbers = [1, 2, 3]
3 | catch :done do
4 | fruits.shuffle.each do |fruit|
5 | numbers.shuffle.each do |n|
6 | puts "#{fruit}, #{n}"
7 | if fruit == 'orange' && n == 3
8 | # すべての繰り返し処理を脱出する
9 | throw :done
10 | end
11 | end
12 | end
13 | end
14 | #=> melon, 2
15 | # melon, 1
16 | # melon, 3
17 | # orange, 1
18 | # orange, 3
19 |
20 | # ----------------------------------------
21 |
22 | fruits = ['apple', 'melon', 'orange']
23 | numbers = [1, 2, 3]
24 | catch :done do
25 | fruits.shuffle.each do |fruit|
26 | numbers.shuffle.each do |n|
27 | puts "#{fruit}, #{n}"
28 | if fruit == 'orange' && n == 3
29 | # catchと一致しないタグをthrowする
30 | throw :foo
31 | end
32 | end
33 | end
34 | end
35 | #=> orange, 1
36 | # orange, 3
37 | # UncaughtThrowError: uncaught throw :foo
38 |
39 | # ----------------------------------------
40 |
41 | ret =
42 | catch :done do
43 | throw :done
44 | end
45 | ret #=> nil
46 |
47 | ret =
48 | catch :done do
49 | throw :done, 123
50 | end
51 | ret #=> 123
52 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_11_03.rb:
--------------------------------------------------------------------------------
1 | def greet(country)
2 | # countryがnilならメッセージを返してメソッドを抜ける
3 | return 'countryを入力してください' if country.nil?
4 |
5 | if country == 'japan'
6 | 'こんにちは'
7 | else
8 | 'hello'
9 | end
10 | end
11 |
12 | # ----------------------------------------
13 |
14 | def calc_with_break
15 | numbers = [1, 2, 3, 4, 5, 6]
16 | target = nil
17 | numbers.shuffle.each do |n|
18 | target = n
19 | # breakで脱出する
20 | break if n.even?
21 | end
22 | target * 10
23 | end
24 | calc_with_break #=> 40
25 |
26 | # ----------------------------------------
27 |
28 | def calc_with_return
29 | numbers = [1, 2, 3, 4, 5, 6]
30 | target = nil
31 | numbers.shuffle.each do |n|
32 | target = n
33 | # returnで脱出する?
34 | return if n.even?
35 | end
36 | target * 10
37 | end
38 | calc_with_return #=> nil
39 |
40 | # ----------------------------------------
41 |
42 | [1, 2, 3].each do |n|
43 | puts n
44 | return
45 | end
46 | #=> 1
47 | # unexpected return (LocalJumpError)
48 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_11_04.rb:
--------------------------------------------------------------------------------
1 | numbers = [1, 2, 3, 4, 5]
2 | numbers.each do |n|
3 | # 偶数であれば中断して次の繰り返し処理に進む
4 | next if n.even?
5 | puts n
6 | end
7 | #=> 1
8 | # 3
9 | # 5
10 |
11 | # ----------------------------------------
12 |
13 | numbers = [1, 2, 3, 4, 5]
14 | i = 0
15 | while i < numbers.size
16 | n = numbers[i]
17 | i += 1
18 | # while文の中でnextを使う
19 | next if n.even?
20 | puts n
21 | end
22 | #=> 1
23 | # 3
24 | # 5
25 |
26 | fruits = ['apple', 'melon', 'orange']
27 | numbers = [1, 2, 3, 4]
28 | fruits.each do |fruit|
29 | numbers.each do |n|
30 | # 繰り返し処理が入れ子になっている場合は、一番内側のループだけが中断される
31 | next if n.even?
32 | puts "#{fruit}, #{n}"
33 | end
34 | end
35 | #=> apple, 1
36 | # apple, 3
37 | # melon, 1
38 | # melon, 3
39 | # orange, 1
40 | # orange, 3
41 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/code_04_11_05.rb:
--------------------------------------------------------------------------------
1 | foods = ['ピーマン', 'トマト', 'セロリ']
2 | foods.each do |food|
3 | print "#{food}は好きですか? => "
4 | # sampleは配列からランダムに1要素を取得するメソッド
5 | answer = ['はい', 'いいえ'].sample
6 | puts answer
7 |
8 | # はいと答えなければもう一度聞き直す
9 | redo unless answer == 'はい'
10 | end
11 | #=> ピーマンは好きですか? => いいえ
12 | # ピーマンは好きですか? => いいえ
13 | # ピーマンは好きですか? => はい
14 | # トマトは好きですか? => はい
15 | # セロリは好きですか? => いいえ
16 | # セロリは好きですか? => はい
17 |
18 | # ----------------------------------------
19 |
20 | foods = ['ピーマン', 'トマト', 'セロリ']
21 | count = 0
22 | foods.each do |food|
23 | print "#{food}は好きですか? => "
24 | # わざと「いいえ」しか答えないようにする
25 | answer = 'いいえ'
26 | puts answer
27 |
28 | count += 1
29 | # やり直しは2回までにする
30 | redo if answer != 'はい' && count < 2
31 |
32 | # カウントをリセット
33 | count = 0
34 | end
35 | #=> ピーマンは好きですか? => いいえ
36 | # ピーマンは好きですか? => いいえ
37 | # トマトは好きですか? => いいえ
38 | # トマトは好きですか? => いいえ
39 | # セロリは好きですか? => いいえ
40 | # セロリは好きですか? => いいえ
41 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/column_04_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:[]や<<を使った文字列の操作
2 |
3 | a = 'abcde'
4 | # 3文字目を取得する
5 | a[2] #=> "c"
6 | # 2文字目から3文字ぶんを取得する
7 | a[1, 3] #=> "bcd"
8 | # 最後の1文字を取得する
9 | a[-1] #=> "e"
10 |
11 | # 1文字目を"X"に置き換える
12 | a[0] = 'X'
13 | a #=> "Xbcde"
14 | # 2文字目から3文字ぶんを"Y"で置き換える
15 | a[1, 3] = 'Y'
16 | a #=> "XYe"
17 | # 末尾に"PQR"を連結する
18 | a << 'PQR'
19 | a #=> "XYePQR"
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/column_04_02.rb:
--------------------------------------------------------------------------------
1 | # コラム ブロックのうしろに別のメソッドを続けて書く
2 |
3 | names = ['田中', '鈴木', '佐藤']
4 | san_names = names.map { |name| "#{name}さん" } #=> ["田中さん", "鈴木さん", "佐藤さん"]
5 | san_names.join('と') #=> "田中さんと鈴木さんと佐藤さん"
6 |
7 | # ----------------------------------------
8 |
9 | names = ['田中', '鈴木', '佐藤']
10 | names.map { |name| "#{name}さん" }.join('と') #=> "田中さんと鈴木さんと佐藤さん"
11 |
12 | # ----------------------------------------
13 |
14 | names = ['田中', '鈴木', '佐藤']
15 | names.map do |name|
16 | "#{name}さん"
17 | end.join('と') #=> "田中さんと鈴木さんと佐藤さん"
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/column_04_03.rb:
--------------------------------------------------------------------------------
1 | # コラム:繰り返し処理とEnummerableモジュール
2 |
3 | # 範囲オブジェクトに対してmapメソッドを呼びだす
4 | (1..4).map { |n| n * 10 } #=> [10, 20, 30, 40]
5 |
6 | # uptoメソッドの戻り値に対してselectメソッドを呼び出す
7 | 1.upto(5).select { |n| n.odd? } #=> [1, 3, 5]
8 |
9 | # ----------------------------------------
10 |
11 | [1, 2, 3].class #=> Array
12 | Array.include?(Enumerable) #=> true
13 |
14 | (1..3).class #=> Range
15 | Range.include?(Enumerable) #=> true
16 |
17 | 1.upto(3).class #=> Enumerator
18 | Enumerator.include?(Enumerable) #=> true
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_04/column_04_04.rb:
--------------------------------------------------------------------------------
1 | # コラム:エイリアスメソッドがたくさんあるのはなぜ?
2 |
3 | # mapはLisp由来、collectはSmalltalk由来
4 | [1, 2, 3].map { |n| n * 10 } #=> [10, 20, 30]
5 | [1, 2, 3].collect { |n| n * 10 } #=> [10, 20, 30]
6 |
7 | # ----------------------------------------
8 |
9 | # 配列の大きさは?
10 | [1, 2, 3].size #=> 3
11 |
12 | # 配列の長さは?
13 | [1, 2, 3].length #=> 3
14 |
15 | # ----------------------------------------
16 |
17 | # thenメソッドの使用例
18 | # nには10が入り、10 * 3 = 30がメソッドの戻り値になる
19 | 10.then { |n| n * 3 } #=> 30
20 |
21 | # ----------------------------------------
22 |
23 | # translateの短縮形としてのtメソッド
24 | I18n.translate 'foo.bar'
25 | I18n.t 'foo.bar'
26 |
27 | # 単数形のdayメソッドと複数形のdaysメソッド
28 | Date.today + 1.day
29 | Date.today + 2.days
30 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_01_02.rb:
--------------------------------------------------------------------------------
1 | convert_length(1, 'm', 'in') #=> 39.37
2 | convert_length(15, 'in', 'm') #=> 0.38
3 | convert_length(35000, 'ft', 'm') #=> 10670.73
4 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_02_00.rb:
--------------------------------------------------------------------------------
1 | # 空のハッシュを作成し、そのクラス名を確認する
2 | {}.class #=> Hash
3 |
4 | # ----------------------------------------
5 |
6 | { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
7 |
8 | # ----------------------------------------
9 |
10 | {
11 | 'japan' => 'yen',
12 | 'us' => 'dollar',
13 | 'india' => 'rupee'
14 | }
15 |
16 | # ----------------------------------------
17 |
18 | {
19 | 'japan' => 'yen',
20 | 'us' => 'dollar',
21 | 'india' => 'rupee',
22 | }
23 |
24 | # ----------------------------------------
25 |
26 | { 'japan' => 'yen', 'japan' => '円' } #=> {"japan"=>"円"}
27 |
28 | # ----------------------------------------
29 |
30 | # ハッシュリテラルの{}
31 | h = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
32 |
33 | # ブロックを作成する{}
34 | [1, 2, 3].each { |n| puts n }
35 |
36 | # ----------------------------------------
37 |
38 | # 空のハッシュ
39 | h = {}
40 |
41 | # 空のブロック(めったに使われない)
42 | [1, 2, 3].each {}
43 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_02_01.rb:
--------------------------------------------------------------------------------
1 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
2 |
3 | # イタリアの通貨を追加する
4 | currencies['italy'] = 'euro'
5 |
6 | currencies #=> {"japan"=>"yen", "us"=>"dollar", "india"=>"rupee", "italy"=>"euro"}
7 |
8 | # ----------------------------------------
9 |
10 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
11 |
12 | # 既存の値を上書きする
13 | currencies['japan'] = '円'
14 |
15 | currencies #=> {"japan"=>"円", "us"=>"dollar", "india"=>"rupee"}
16 |
17 | # ----------------------------------------
18 |
19 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
20 |
21 | currencies['india'] #=> "rupee"
22 |
23 | # ----------------------------------------
24 |
25 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
26 |
27 | currencies['brazil'] #=> nil
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_02_02.rb:
--------------------------------------------------------------------------------
1 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
2 |
3 | currencies.each do |key, value|
4 | puts "#{key} : #{value}"
5 | end
6 | #=> japan : yen
7 | # us : dollar
8 | # india : rupee
9 |
10 | # ----------------------------------------
11 |
12 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
13 |
14 | currencies.each do |key_value|
15 | key = key_value[0]
16 | value = key_value[1]
17 | puts "#{key} : #{value}"
18 | end
19 | #=> japan : yen
20 | # us : dollar
21 | # india : rupee
22 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_02_03.rb:
--------------------------------------------------------------------------------
1 | a = { 'x' => 1, 'y' => 2, 'z' => 3 }
2 |
3 | # すべてのキーと値が同じであればtrue
4 | b = { 'x' => 1, 'y' => 2, 'z' => 3 }
5 | a == b #=> true
6 |
7 | # 並び順が異なっていてもキーと値がすべて同じならtrue
8 | c = { 'z' => 3, 'y' => 2, 'x' => 1 }
9 | a == c #=> true
10 |
11 | # キー'x'の値が異なるのでfalse
12 | d = { 'x' => 10, 'y' => 2, 'z' => 3 }
13 | a == d #=> false
14 |
15 | # ----------------------------------------
16 |
17 | {}.size #=> 0
18 |
19 | { 'x' => 1, 'y' => 2, 'z' => 3 }.size #=> 3
20 |
21 | # ----------------------------------------
22 |
23 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
24 | currencies.delete('japan') #=> "yen"
25 | currencies #=> {"us"=>"dollar", "india"=>"rupee"}
26 |
27 | # ----------------------------------------
28 |
29 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
30 |
31 | # 削除しようとしたキーが見つからないときはnilが返る
32 | currencies.delete('italy') #=> nil
33 |
34 | # ブロックを渡すとキーが見つからないときの戻り値を作成できる
35 | currencies.delete('italy') { |key| "Not found: #{key}" } #=> "Not found: italy"
36 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_03_00.rb:
--------------------------------------------------------------------------------
1 | :apple
2 | :japan
3 | :ruby_is_fun
4 |
5 | # ----------------------------------------
6 |
7 | 'apple'
8 | 'japan'
9 | 'ruby_is_fun'
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_03_01.rb:
--------------------------------------------------------------------------------
1 | :apple.class #=> Symbol
2 | 'apple'.class #=> String
3 |
4 | # ----------------------------------------
5 |
6 | # 文字列よりもシンボルの方が高速に比較できる
7 | 'apple' == 'apple'
8 | :apple == :apple
9 |
10 | # ----------------------------------------
11 |
12 | :apple.object_id #=> 1143388
13 | :apple.object_id #=> 1143388
14 | :apple.object_id #=> 1143388
15 |
16 | 'apple'.object_id #=> 70223819213380
17 | 'apple'.object_id #=> 70223819233120
18 | 'apple'.object_id #=> 70223819227780
19 |
20 | # ----------------------------------------
21 |
22 | # 文字列は破壊的な変更が可能
23 | string = 'apple'
24 | string.upcase!
25 | string #=> "APPLE"
26 |
27 | # シンボルはイミュータブルなので、破壊的な変更は不可能
28 | symbol = :apple
29 | symbol.upcase! #=> undefined method `upcase!' for :apple:Symbol (NoMethodError)
30 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_03_02.rb:
--------------------------------------------------------------------------------
1 | # 文字列をハッシュのキーにする
2 | currencies = { 'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee' }
3 | # 文字列を使って値を取り出す
4 | currencies['japan'] #=> "yen"
5 |
6 | # シンボルをハッシュのキーにする
7 | currencies = { :japan => 'yen', :us => 'dollar', :india => 'rupee' }
8 | # シンボルを使って値を取り出す(文字列より高速)
9 | currencies[:japan] #=> "yen"
10 |
11 | # ----------------------------------------
12 |
13 | # タスクの状態を整数値で管理する(処理効率は良いが、可読性が悪い)
14 | status = 2
15 |
16 | case status
17 | when 0 # todo
18 | 'これからやります'
19 | when 1 # doing
20 | '今やってます'
21 | when 2 # done
22 | 'もう終わりました'
23 | end
24 | #=> "もう終わりました"
25 |
26 | # ----------------------------------------
27 |
28 | # タスクの状態をシンボルで管理する(処理効率も可読性も良い)
29 | status = :done
30 |
31 | case status
32 | when :todo
33 | 'これからやります'
34 | when :doing
35 | '今やってます'
36 | when :done
37 | 'もう終わりました'
38 | end
39 | #=> "もう終わりました"
40 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_04_01.rb:
--------------------------------------------------------------------------------
1 | # ハッシュのキーをシンボルにする
2 | currencies = { :japan => 'yen', :us => 'dollar', :india => 'rupee' }
3 | # シンボルを使って値を取り出す
4 | currencies[:us] #=> "dollar"
5 |
6 | # 新しいキーと値の組み合わせを追加する
7 | currencies[:italy] = 'euro'
8 |
9 | # ----------------------------------------
10 |
11 | # =>ではなく、"シンボル: 値"の記法でハッシュを作成する
12 | currencies = { japan: 'yen', us: 'dollar', india: 'rupee' }
13 | # 値を取り出すときは同じ
14 | currencies[:us] #=> "dollar"
15 |
16 | # ----------------------------------------
17 |
18 | { japan: :yen, us: :dollar, india: :rupee }
19 |
20 | # ----------------------------------------
21 |
22 | { :japan => :yen, :us => :dollar, :india => :rupee }
23 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_04_02.rb:
--------------------------------------------------------------------------------
1 | # 文字列のキーとシンボルのキーを混在させる(良いコードではないので注意)
2 | hash = { 'abc' => 123, def: 456 }
3 |
4 | # 値を取得する場合はデータ型を合わせてキーを指定する
5 | hash['abc'] #=> 123
6 | hash[:def] #=> 456
7 |
8 | # データ型が異なると値は取得できない
9 | hash[:abc] #=> nil
10 | hash['def'] #=> nil
11 |
12 | # ----------------------------------------
13 |
14 | person = {
15 | # 値が文字列
16 | name: 'Alice',
17 | # 値が数値
18 | age: 20,
19 | # 値が配列
20 | friends: ['Bob', 'Carol'],
21 | # 値がハッシュ
22 | phones: { home: '1234-0000', mobile: '5678-0000' }
23 | }
24 |
25 | person[:age] #=> 20
26 | person[:friends] #=> ["Bob", "Carol"]
27 | person[:phones][:mobile] #=> "5678-0000"
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_05_00.rb:
--------------------------------------------------------------------------------
1 | convert_length(1, 'm', 'in') #=> 39.37
2 | convert_length(15, 'in', 'm') #=> 0.38
3 | convert_length(35000, 'ft', 'm') #=> 10670.73
4 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_05_01.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | class ConvertLengthTest < Minitest::Test
4 | def test_convert_length
5 | assert_equal 39.37, convert_length(1, 'm', 'in')
6 | end
7 | end
8 |
9 | # ----------------------------------------
10 |
11 | def convert_length(length, unit_from, unit_to)
12 | 39.37
13 | end
14 |
15 | # ----------------------------------------
16 |
17 | require 'minitest/autorun'
18 | require_relative '../lib/convert_length'
19 |
20 | # 省略
21 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_05_02.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/convert_length'
3 |
4 | class ConvertLengthTest < Minitest::Test
5 | def test_convert_length
6 | assert_equal 39.37, convert_length(1, 'm', 'in')
7 | assert_equal 0.38, convert_length(15, 'in', 'm')
8 | end
9 | end
10 |
11 | # ----------------------------------------
12 |
13 | units = { 'm' => 1.0, 'ft' => 3.28, 'in' => 39.37 }
14 |
15 | # ----------------------------------------
16 |
17 | def convert_length(length, unit_from, unit_to)
18 | units = { 'm' => 1.0, 'ft' => 3.28, 'in' => 39.37 }
19 | (length / units[unit_from] * units[unit_to]).round(2)
20 | end
21 |
22 | # ----------------------------------------
23 |
24 | require 'minitest/autorun'
25 | require_relative '../lib/convert_length'
26 |
27 | class ConvertLengthTest < Minitest::Test
28 | def test_convert_length
29 | assert_equal 39.37, convert_length(1, 'm', 'in')
30 | assert_equal 0.38, convert_length(15, 'in', 'm')
31 | assert_equal 10670.73, convert_length(35000, 'ft', 'm')
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_06_01.rb:
--------------------------------------------------------------------------------
1 | currencies = { japan: 'yen', us: 'dollar', india: 'rupee' }
2 | currencies.keys #=> [:japan, :us, :india]
3 |
4 | # ----------------------------------------
5 |
6 | currencies = { japan: 'yen', us: 'dollar', india: 'rupee' }
7 | currencies.values #=> ["yen", "dollar", "rupee"]
8 |
9 | # ----------------------------------------
10 |
11 | currencies = { japan: 'yen', us: 'dollar', india: 'rupee' }
12 | currencies.has_key?(:japan) #=> true
13 | currencies.has_key?(:italy) #=> false
14 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_06_02.rb:
--------------------------------------------------------------------------------
1 | h = { us: 'dollar', india: 'rupee' }
2 | # 変数hの要素を**で展開させる
3 | { japan: 'yen', **h } #=> {:japan=>"yen", :us=>"dollar", :india=>"rupee"}
4 |
5 | # **を付けない場合は構文エラーになる
6 | { japan: 'yen', h }
7 | #=> syntax error, unexpected '}', expecting => (SyntaxError)
8 | # { japan: 'yen', h }
9 | # ^
10 |
11 | # ----------------------------------------
12 |
13 | h = { us: 'dollar', india: 'rupee' }
14 | { japan: 'yen' }.merge(h) #=> {:japan=>"yen", :us=>"dollar", :india=>"rupee"}
15 |
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_06_03.rb:
--------------------------------------------------------------------------------
1 | # ハッシュを引数として受け取り、疑似キーワード引数を実現する
2 | def buy_burger(menu, options = {})
3 | drink = options[:drink]
4 | potato = options[:potato]
5 | # 省略
6 | end
7 |
8 | buy_burger('cheese', drink: true, potato: true)
9 |
10 | # ----------------------------------------
11 |
12 | # 疑似キーワード引数の場合はどんなキーワードを指定してもエラーにならない
13 | # (無効なキーをエラーにするためにはメソッド側で明示的な実装が必要)
14 | buy_burger('fish', salad: true)
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_06_04.rb:
--------------------------------------------------------------------------------
1 | def buy_burger(menu, drink: true, potato: true)
2 | # 省略
3 | end
4 |
5 | # saladとchickenは未定義のキーワード引数なのでエラーになる
6 | buy_burger('fish', drink: true, potato: false, salad: true, chicken: false)
7 | #=> unknown keywords: :salad, :chicken (ArgumentError)
8 |
9 | # ----------------------------------------
10 |
11 | # 想定外のキーワードはothers引数で受け取る
12 | def buy_burger(menu, drink: true, potato: true, **others)
13 | # othersはハッシュとして渡される
14 | puts others
15 |
16 | # 省略
17 | end
18 |
19 | buy_burger('fish', drink: true, potato: false, salad: true, chicken: false)
20 | #=> {:salad=>true, :chicken=>false}
21 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_06_05.rb:
--------------------------------------------------------------------------------
1 | def buy_burger(menu, drink: true, potato: true)
2 | # ...
3 | end
4 |
5 | # キーワード引数として渡したいハッシュを定義する
6 | params = { drink: true, potato: false }
7 | # ハッシュを引数として渡すと自動的にキーワード引数に変換される(Ruby 2.x)
8 | buy_burger('fish', params)
9 |
10 | # ----------------------------------------
11 |
12 | # Ruby 3.0ではハッシュはキーワード引数に自動変換されないため、エラーが発生する
13 | buy_burger('fish', params)
14 | #=> `buy_burger': wrong number of arguments (given 2, expected 1) (ArgumentError)
15 |
16 | # ----------------------------------------
17 |
18 | # 非推奨警告の出力を有効化する
19 | Warning[:deprecated] = true
20 |
21 | # Ruby 2.7ではキーワード引数への自動変換が行われると警告が出る
22 | buy_burger('fish', params)
23 | #=> warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
24 | # warning: The called method `buy_burger' is defined here
25 |
26 | # ----------------------------------------
27 |
28 | # **付きでハッシュを渡すと、ハッシュがキーワード引数として扱われるようになる
29 | buy_burger('fish', **params)
30 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_06_08.rb:
--------------------------------------------------------------------------------
1 | currencies = { japan: 'yen', us: 'dollar', india: 'rupee' }
2 | currencies.to_a #=> [[:japan, "yen"], [:us, "dollar"], [:india, "rupee"]]
3 |
4 | # ----------------------------------------
5 |
6 | array = [[:japan, "yen"], [:us, "dollar"], [:india, "rupee"]]
7 | array.to_h #=> {:japan=>"yen", :us=>"dollar", :india=>"rupee"}
8 |
9 | # ----------------------------------------
10 |
11 | array = [1, 2, 3, 4]
12 | array.to_h #=> wrong element type Integer at 0 (expected array) (TypeError)
13 |
14 | # ----------------------------------------
15 |
16 | array = [[:japan, "yen"], [:japan, "円"]]
17 | array.to_h #=> {:japan=>"円"}
18 |
19 | # ----------------------------------------
20 |
21 | # 配列の配列をHash[]に渡す
22 | array = [[:japan, "yen"], [:us, "dollar"], [:india, "rupee"]]
23 | Hash[array] #=> {:japan=>"yen", :us=>"dollar", :india=>"rupee"}
24 |
25 |
26 | # キーと値が交互に並ぶフラットな配列をsplat展開してもよい
27 | # splat展開については第4章の「1つの配列を複数の引数として展開する」の項を参照
28 | array = [:japan, "yen", :us, "dollar", :india, "rupee"]
29 | Hash[*array] #=> {:japan=>"yen", :us=>"dollar", :india=>"rupee"}
30 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_06_09.rb:
--------------------------------------------------------------------------------
1 | h = {}
2 | h[:foo] #=> nil
3 |
4 | # ----------------------------------------
5 |
6 | # キーがなければ'hello'を返す
7 | h = Hash.new('hello')
8 | h[:foo] #=> "hello"
9 |
10 | # ----------------------------------------
11 |
12 | h = Hash.new('hello')
13 | a = h[:foo] #=> "hello"
14 | b = h[:bar] #=> "hello"
15 |
16 | # 変数aと変数bは同一オブジェクト
17 | a.equal?(b) #=> true
18 |
19 | # 変数aに破壊的な変更を適用すると、変数bの値も一緒に変わってしまう
20 | a.upcase!
21 | a #=> "HELLO"
22 | b #=> "HELLO"
23 |
24 | # ちなみにハッシュ自身は空のままになっている
25 | h #=> {}
26 |
27 | # ----------------------------------------
28 |
29 | # キーが見つからないとブロックがその都度実行され、ブロックの戻り値がデフォルト値になる
30 | h = Hash.new { 'hello' }
31 | a = h[:foo] #=> "hello"
32 | b = h[:bar] #=> "hello"
33 |
34 | # 変数aと変数bは異なるオブジェクト(ブロックの実行時に毎回新しい文字列が作成される)
35 | a.equal?(b) #=> false
36 |
37 | # 変数aに破壊的な変更を適用しても、変数bの値は変わらない
38 | a.upcase!
39 | a #=> "HELLO"
40 | b #=> "hello"
41 |
42 | # ハッシュは空のまま
43 | h #=> {}
44 |
45 | # ----------------------------------------
46 |
47 | # デフォルト値を返すだけでなく、ハッシュに指定されたキーとデフォルト値を同時に設定する
48 | h = Hash.new { |hash, key| hash[key] = 'hello' }
49 | a = h[:foo] #=> "hello"
50 | b = h[:bar] #=> "hello"
51 |
52 | # ハッシュにキーと値が追加されている
53 | h #=> {:foo=>"hello", :bar=>"hello"}
54 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_07_01.rb:
--------------------------------------------------------------------------------
1 | :apple
2 | :Apple
3 | :ruby_is_fun
4 | :okay?
5 | :welcome!
6 | :_secret
7 | :$dollar
8 | :@at_mark
9 | :+
10 | :==
11 |
12 | # ----------------------------------------
13 |
14 | # 以下のようにシンボルを作ろうとするとエラーになる
15 | :12345 #=> SyntaxError
16 | :ruby-is-fun #=> NameError
17 | :ruby is fun #=> SyntaxError
18 | :() #=> SyntaxError
19 |
20 | # ----------------------------------------
21 |
22 | # シングルクオートで囲むとシンボルとして有効
23 | :'12345' #=> :"12345"
24 | :'ruby-is-fun' #=> :"ruby-is-fun"
25 | :'ruby is fun' #=> :"ruby is fun"
26 | :'()' #=> :"()"
27 |
28 | # ----------------------------------------
29 |
30 | name = 'Alice'
31 | :"#{name.upcase}" #=> :ALICE
32 |
33 | # ----------------------------------------
34 |
35 | # "文字列: 値"の形式で書くと、キーがシンボルになる
36 | hash = { 'abc': 123 } #=> {:abc=>123}
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_07_02.rb:
--------------------------------------------------------------------------------
1 | # !を区切り文字に使う
2 | %s!'ruby is fun.'! #=> :"'ruby is fun.'"
3 |
4 | # ()を区切り文字に使う
5 | %s('ruby is fun!') #=> :"'ruby is fun!'"
6 |
7 | # ----------------------------------------
8 |
9 | %i(apple orange melon) #=> [:apple, :orange, :melon]
10 |
11 | # ----------------------------------------
12 |
13 | name = 'Alice'
14 |
15 | # %iでは改行文字や式展開の構文が、そのままシンボルになる
16 | %i(hello\ngood-bye #{name.upcase}) #=> [:"hello\\ngood-bye", :"\#{name.upcase}"]
17 |
18 | # %Iでは改行文字や式展開が有効になった上でシンボルが作られる
19 | %I(hello\ngood-bye #{name.upcase}) #=> [:"hello\ngood-bye", :ALICE]
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/code_05_07_03.rb:
--------------------------------------------------------------------------------
1 | string = 'apple'
2 | symbol = :apple
3 |
4 | string == symbol #=> false
5 | string + symbol #=> no implicit conversion of Symbol into String (TypeError)
6 |
7 | # ----------------------------------------
8 |
9 | string = 'apple'
10 | symbol = :apple
11 |
12 | string.to_sym #=> :apple
13 | string.to_sym == symbol #=> true
14 |
15 | # ----------------------------------------
16 |
17 | string = 'apple'
18 | symbol = :apple
19 |
20 | symbol.to_s #=> "apple"
21 | string == symbol.to_s #=> true
22 | string + symbol.to_s #=> "appleapple"
23 |
24 | # ----------------------------------------
25 |
26 | # respond_to?メソッドの引数には文字列とシンボルの両方を渡せる
27 | 'apple'.respond_to?('include?') #=> true
28 | 'apple'.respond_to?(:include?) #=> true
29 |
30 | 'apple'.respond_to?('foo_bar') #=> false
31 | 'apple'.respond_to?(:foo_bar) #=> false
32 |
33 | # ----------------------------------------
34 |
35 | # 文字列に'pp'が含まれるか調べる
36 | 'apple'.include?('pp') #=> true
37 |
38 | # シンボルを引数で渡すとエラーになる
39 | 'apple'.include?(:pp) #=> no implicit conversion of Symbol into String (TypeError)
40 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/column_05_01.rb:
--------------------------------------------------------------------------------
1 | def buy_burger(menu, drink: true, potato: true)
2 | # なんで if :drink じゃないの?
3 | if drink
4 | # 省略
5 | end
6 | # なんで if :potato じゃないの?
7 | if potato
8 | # 省略
9 | end
10 | end
11 |
12 | # ----------------------------------------
13 |
14 | def buy_burger(menu, drink: true, potato: true)
15 | # キーワード引数もメソッドの引数のひとつなので、menuと同様にdrinkと書く
16 | if drink
17 | # 省略
18 | end
19 | # ...
20 |
21 | # ----------------------------------------
22 |
23 | def buy_burger(menu, drink: true, potato: true)
24 | # :drinkと書いた場合はメソッドの引数ではなく、ただのシンボルになる
25 | if :drink
26 | # 省略
27 | end
28 | # ...
29 |
30 | # ----------------------------------------
31 |
32 | # buy_burgerメソッドを呼び出す場合の drink: や potato: はシンボルか否か?
33 | buy_burger('cheese', drink: true, potato: true)
34 |
35 | # ----------------------------------------
36 |
37 | # 呼び出す側はどっちの記法でも呼び出せる(ただし通常は上の書き方を使う)
38 | buy_burger('cheese', drink: true, potato: true)
39 | buy_burger('cheese', :drink => true, :potato => true)
40 |
41 | # ----------------------------------------
42 |
43 | # 変数経由で呼び出すこともできる
44 | # 注意:この例はあくまで実験目的であって、実際にこんなコードを書くことはない
45 | key_1 = :drink
46 | key_2 = :potato
47 | buy_burger('cheese', key_1 => true, key_2 => true)
48 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/column_05_02.rb:
--------------------------------------------------------------------------------
1 | # コラム:メソッド定義時の引数の順番
2 |
3 | def foo(a, b, c = 3, d = 4, *ef, g, h, i: 9, j: 10, **kl, &block)
4 | "a: #{a}, b: #{b}, c: #{c}, d: #{d}, ef: #{ef}, g: #{g}, h: #{h}, i: #{i}, j: #{j}, kl: #{kl}, block: #{block}"
5 | end
6 |
7 | foo(1, 2, 3, 4, 5, 6, 7, 8, i: 9, j: 10, k: 11, l: 12) { 13 }
8 | #=> "a: 1, b: 2, c: 3, d: 4, ef: [5, 6], g: 7, h: 8, i: 9, j: 10, kl: {:k=>11, :l=>12}, block: #"
9 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/column_05_03.rb:
--------------------------------------------------------------------------------
1 | # コラム:よく使われるイディオム(1) 条件分岐で変数に代入/&.演算子
2 |
3 | # 国名に応じて通貨を返す(該当する通貨がなければnil)
4 | def find_currency(country)
5 | currencies = { japan: 'yen', us: 'dollar', india: 'rupee' }
6 | currencies[country]
7 | end
8 |
9 | # 指定された国の通貨を大文字にして返す
10 | def show_currency(country)
11 | currency = find_currency(country)
12 | # nilでないことをチェック(nilだとupcaseが呼び出せないため)
13 | if currency
14 | currency.upcase
15 | end
16 | end
17 |
18 | # 通貨が見つかる場合と見つからない場合の結果を確認
19 | show_currency(:japan) #=> "YEN"
20 | show_currency(:brazil) #=> nil
21 |
22 | # ----------------------------------------
23 |
24 | def show_currency(country)
25 | # 条件分岐内で直接変数に代入してしまう(値が取得できれば真、できなければ偽)
26 | if currency = find_currency(country)
27 | currency.upcase
28 | end
29 | end
30 |
31 | # ----------------------------------------
32 |
33 | # nil以外のオブジェクトであれば、a.upcaseと書いた場合と同じ結果になる
34 | a = 'foo'
35 | a&.upcase #=> "FOO"
36 |
37 | # nilであれば、nilを返す(a.upcaseと違ってエラーにはならない)
38 | a = nil
39 | a&.upcase #=> nil
40 |
41 | # ----------------------------------------
42 |
43 | def show_currency(country)
44 | currency = find_currency(country)
45 | # currencyがnilの場合を考慮して、&.演算子でメソッドを呼び出す
46 | currency&.upcase
47 | end
48 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/column_05_04.rb:
--------------------------------------------------------------------------------
1 | # コラム:よく使われるイディオム(2) ||=を使った自己代入
2 |
3 | limit ||= 10
4 |
5 | # ----------------------------------------
6 |
7 | limit = nil
8 | limit ||= 10
9 | limit #=> 10
10 |
11 | limit = 20
12 | limit ||= 10
13 | limit #=> 20
14 |
15 | # ----------------------------------------
16 |
17 | limit || limit = 10
18 |
19 | # ----------------------------------------
20 |
21 | limit = nil
22 | limit ||= begin
23 | a = 10
24 | b = 20
25 | a + b
26 | end
27 | limit #=> 30
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_05/column_05_05.rb:
--------------------------------------------------------------------------------
1 | # コラム:よく使われるイディオム(3) !!を使った真偽値の型変換
2 |
3 | def user_exists?
4 | # データベース等からユーザーを探す(なければnil)
5 | user = find_user
6 | if user
7 | # userが見つかったのでtrue
8 | true
9 | else
10 | # userが見つからないのでfalse
11 | false
12 | end
13 | end
14 |
15 | # ----------------------------------------
16 |
17 | def user_exists?
18 | !!find_user
19 | end
20 |
21 | # ----------------------------------------
22 |
23 | !!true #=> true
24 | !!1 #=> true
25 | !!false #=> false
26 | !!nil #=> false
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_01_01.rb:
--------------------------------------------------------------------------------
1 | # => を使う記法
2 | {
3 | :name => 'Alice',
4 | :age => 20,
5 | :gender => :female
6 | }
7 |
8 | # => を使わない記法
9 | {
10 | name: 'Alice',
11 | age: 20,
12 | gender: :female
13 | }
14 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_01_02.rb:
--------------------------------------------------------------------------------
1 | old_syntax = < 'Alice',
4 | :age=>20,
5 | :gender => :female
6 | }
7 | TEXT
8 |
9 | convert_hash_syntax(old_syntax)
10 | # => {
11 | # name: 'Alice',
12 | # age: 20,
13 | # gender: :female
14 | # }
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_02_01.rb:
--------------------------------------------------------------------------------
1 | text = < ["Ruby", "Python", "Java", "JavaScript"]
8 |
9 | # ----------------------------------------
10 |
11 | text = < 私の郵便番号は123-4567です。
18 | # 僕の住所は677-0056 兵庫県西脇市板波町1234だよ。
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_03_00.rb:
--------------------------------------------------------------------------------
1 | regex = /\d{3}-\d{4}/
2 | regex.class #=> Regexp
3 |
4 | # ----------------------------------------
5 |
6 | # マッチした場合はマッチした文字列の開始位置が返る(つまり真)
7 | '123-4567' =~ /\d{3}-\d{4}/ #=> 0
8 |
9 | # マッチしない場合はnilが返る(つまり偽)
10 | 'hello' =~ /\d{3}-\d{4}/ #=> nil
11 |
12 | # ----------------------------------------
13 |
14 | # if文で=~を使うとマッチしたかどうかを判別できる
15 | if '123-4567' =~ /\d{3}-\d{4}/
16 | puts 'マッチしました'
17 | else
18 | puts 'マッチしませんでした'
19 | end
20 | #=> マッチしました
21 |
22 | # ----------------------------------------
23 |
24 | # 左辺に正規表現を置いても結果は同じ
25 | /\d{3}-\d{4}/ =~ '123-4567' #=> 0
26 | /\d{3}-\d{4}/ =~ 'hello' #=> nil
27 |
28 | # ----------------------------------------
29 |
30 | # マッチしなければtrue
31 | 'hello' !~ /\d{3}-\d{4}/ #=> true
32 |
33 | # マッチすればfalse
34 | '123-4567' !~ /\d{3}-\d{4}/ #=> false
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_03_02.rb:
--------------------------------------------------------------------------------
1 | text = '私の誕生日は1977年7月17日です。'
2 | m = /(\d+)年(\d+)月(\d+)日/.match(text)
3 | m[1] #=> "1977"
4 | m[2] #=> "7"
5 | m[3] #=> "17"
6 |
7 | # ----------------------------------------
8 |
9 | /(\d+)年(\d+)月(\d+)日/.match(text) #=> #
10 | /(\d+)年(\d+)月(\d+)日/.match('foo') #=> nil
11 |
12 | # ----------------------------------------
13 |
14 | text = '私の誕生日は1977年7月17日です。'
15 | # 真偽値の判定とローカル変数への代入を同時にやってしまう
16 | if m = /(\d+)年(\d+)月(\d+)日/.match(text)
17 | # マッチした場合の処理(ローカル変数のmを使う)
18 | else
19 | # マッチしなかった場合の処理
20 | end
21 |
22 | # ----------------------------------------
23 |
24 | text = '私の誕生日は1977年7月17日です。'
25 | m = /(\d+)年(\d+)月(\d+)日/.match(text)
26 | # マッチした部分全体を取得する
27 | m[0] #=> "1977年7月17日"
28 |
29 | # キャプチャの1番目を取得する
30 | m[1] #=> "1977"
31 |
32 | # キャプチャの2番目から2個取得する
33 | m[2, 2] #=> ["7", "17"]
34 |
35 | # 最後のキャプチャを取得する
36 | m[-1] #=> "17"
37 |
38 | # Rangeを使って取得する
39 | m[1..3] #=> ["1977", "7", "17"]
40 |
41 | # ----------------------------------------
42 |
43 | text = '私の誕生日は1977年7月17日です。'
44 | m = text.match(/(\d+)年(\d+)月(\d+)日/) #=> #
45 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_03_03.rb:
--------------------------------------------------------------------------------
1 | text = '私の誕生日は1977年7月17日です。'
2 | m = /(?\d+)年(?\d+)月(?\d+)日/.match(text)
3 | # シンボルで名前を指定してキャプチャの結果を取得する
4 | m[:year] #=> "1977"
5 | m[:month] #=> "7"
6 | m[:day] #=> "17"
7 |
8 | # 文字列で指定することもできる
9 | m['year'] #=> "1977"
10 |
11 | # 連番で指定することもできる
12 | m[2] #=> "7"
13 |
14 | # ----------------------------------------
15 |
16 | text = '私の誕生日は1977年7月17日です。'
17 | # キャプチャの名前がそのままローカル変数に割り当てられる
18 | if /(?\d+)年(?\d+)月(?\d+)日/ =~ text
19 | puts "#{year}/#{month}/#{day}"
20 | end
21 | #=> 1977/7/17
22 |
23 | # ----------------------------------------
24 |
25 | text = '私の誕生日は1977年7月17日です。'
26 | # 正規表現が右辺に来るとローカル変数が作成されない
27 | if text =~ /(?\d+)年(?\d+)月(?\d+)日/
28 | puts "#{year}/#{month}/#{day}"
29 | end
30 | #=> undefined local variable or method `year' for main:Object (NameError)
31 |
32 | # ----------------------------------------
33 |
34 | text = '私の誕生日は1977年7月17日です。'
35 | regexp = /(?\d+)年(?\d+)月(?\d+)日/
36 | # 正規表現オブジェクトが変数に入っている場合も無効
37 | if regexp =~ text
38 | puts "#{year}/#{month}/#{day}"
39 | end
40 | #=> undefined local variable or method `year' for main:Object (NameError)
41 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_03_04.rb:
--------------------------------------------------------------------------------
1 | text = '私の誕生日は1977年7月17日です。'
2 |
3 | # =~やmatchメソッドを使うとマッチした結果が組み込み変数に代入される
4 | text =~ /(\d+)年(\d+)月(\d+)日/
5 |
6 | # MatchDataオブジェクトを取得する
7 | $~ #=> #
8 |
9 | # マッチした部分全体を取得する
10 | $& #=> "1977年7月17日"
11 |
12 | # 1番目~3番目のキャプチャを取得する
13 | $1 #=> "1977"
14 | $2 #=> "7"
15 | $3 #=> "17"
16 |
17 | # 最後のキャプチャ文字列を取得する
18 | $+ #=> "17"
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_04_00.rb:
--------------------------------------------------------------------------------
1 | # キーがシンボルなら新しいハッシュ記法に変換する
2 | old_syntax = < 'Alice',
5 | :age=>20,
6 | :gender => :female
7 | }
8 | TEXT
9 | convert_hash_syntax(old_syntax)
10 | #=> {
11 | # name: 'Alice',
12 | # age: 20,
13 | # gender: :female
14 | # }
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_04_01.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/convert_hash_syntax'
3 |
4 | class ConvertHashSyntaxTest < Minitest::Test
5 | def test_convert_hash_syntax
6 | assert_equal '{}', convert_hash_syntax('{}')
7 | end
8 | end
9 |
10 | # ----------------------------------------
11 |
12 | def convert_hash_syntax(old_syntax)
13 | # 何も変換せずに返す
14 | old_syntax
15 | end
16 |
17 | # ----------------------------------------
18 |
19 | require 'minitest/autorun'
20 | require_relative '../lib/convert_hash_syntax'
21 |
22 | class ConvertHashSyntaxTest < Minitest::Test
23 | def test_convert_hash_syntax
24 | assert_equal '{}', convert_hash_syntax('{}')
25 |
26 | old_syntax = <<~TEXT
27 | {
28 | :name => 'Alice',
29 | :age=>20,
30 | :gender => :female
31 | }
32 | TEXT
33 | expected = <<~TEXT
34 | {
35 | name: 'Alice',
36 | age: 20,
37 | gender: :female
38 | }
39 | TEXT
40 | assert_equal expected, convert_hash_syntax(old_syntax)
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_04_02.rb:
--------------------------------------------------------------------------------
1 | def convert_hash_syntax(old_syntax)
2 | old_syntax.gsub(/:(\w+) *=> */) do
3 | "#{$1}: "
4 | end
5 | end
6 |
7 | # ----------------------------------------
8 |
9 | # 実行結果をいったん変数に入れて、コンソールに出力する
10 | actual = convert_hash_syntax(old_syntax)
11 | puts actual
12 | assert_equal expected, actual
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_05_01.rb:
--------------------------------------------------------------------------------
1 | # /\d{3}-\d{4}/と書いた場合と同じ
2 | Regexp.new('\d{3}-\d{4}')
3 |
4 | # ----------------------------------------
5 |
6 | # スラッシュで囲むと、スラッシュをエスケープする必要がある
7 | /http:\/\/example\.com/
8 |
9 | # %rを使うとスラッシュをエスケープしなくてよい
10 | %r!http://example\.com!
11 |
12 | # !ではなく{}を区切り文字にする
13 | %r{http://example\.com}
14 |
15 | # ----------------------------------------
16 |
17 | pattern = '\d{3}-\d{4}'
18 | # 変数が展開されるので/\d{3}-\d{4}/と書いたことと同じになる
19 | '123-4567' =~ /#{pattern}/ #=> 0
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_05_02.rb:
--------------------------------------------------------------------------------
1 | text = '03-1234-5678'
2 |
3 | case text
4 | when /^\d{3}-\d{4}$/
5 | puts '郵便番号です'
6 | when /^\d{4}\/\d{1,2}\/\d{1,2}$/
7 | puts '日付です'
8 | when /^\d+-\d+-\d+$/
9 | puts '電話番号です'
10 | end
11 | #=> 電話番号です
12 |
13 | # ----------------------------------------
14 |
15 | $& #=> "03-1234-5678"
16 | $~ #=> #
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_05_04.rb:
--------------------------------------------------------------------------------
1 | text = '私の誕生日は1977年7月17日です。'
2 |
3 | # =~演算子等を使うと、マッチした結果をRegexp.last_matchで取得できる
4 | text =~ /(\d+)年(\d+)月(\d+)日/
5 |
6 | # MatchDataオブジェクトを取得する
7 | Regexp.last_match #=> #
8 |
9 | # マッチした部分全体を取得する
10 | Regexp.last_match(0) #=> "1977年7月17日"
11 |
12 | # 1番目~3番目のキャプチャを取得する
13 | Regexp.last_match(1) #=> "1977"
14 | Regexp.last_match(2) #=> "7"
15 | Regexp.last_match(3) #=> "17"
16 |
17 | # 最後のキャプチャ文字列を取得する
18 | Regexp.last_match(-1) #=> "17"
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_06/code_06_05_05.rb:
--------------------------------------------------------------------------------
1 | # マッチすればtrueを返す
2 | /\d{3}-\d{4}/.match?('123-4567') #=> true
3 |
4 | # マッチしても組み込み変数やRegexp.last_matchを書き換えない
5 | $~ #=> nil
6 | Regexp.last_match #=> nil
7 |
8 | # 文字列と正規表現を入れ替えてもOK
9 | '123-4567'.match?(/\d{3}-\d{4}/) #=> true
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_01_01.rb:
--------------------------------------------------------------------------------
1 | # 改札機オブジェクトの作成
2 | umeda = Gate.new(:umeda)
3 | mikuni = Gate.new(:mikuni)
4 |
5 | # 160円の切符を購入して梅田で乗車し、三国で降車する(NG)
6 | ticket = Ticket.new(160)
7 | umeda.enter(ticket)
8 | mikuni.exit(ticket) #=> false
9 |
10 | # 190円の切符を購入して梅田で乗車し、三国で降車する(OK)
11 | ticket = Ticket.new(190)
12 | umeda.enter(ticket)
13 | mikuni.exit(ticket) #=> true
14 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_02_02.rb:
--------------------------------------------------------------------------------
1 | # 「Alice Rubyさん、20歳」というユーザーのオブジェクトを作成する
2 | alice = User.new('Alice', 'Ruby', 20)
3 | # 「Bob Pythonさん、30歳」というユーザーのオブジェクトを作成する
4 | bob = User.new('Bob', 'Python', 30)
5 |
6 | # どちらもfull_nameメソッドを持つが、保持しているデータが異なるので戻り値は異なる
7 | alice.full_name
8 | #-> "Alice Ruby"
9 |
10 | bob.full_name
11 | #-> "Bob Python"
12 |
13 | # ----------------------------------------
14 |
15 | user = User.new('Alice', 'Ruby', 20)
16 | user.first_name
17 |
18 | # ----------------------------------------
19 |
20 | user = User.new('Alice', 'Ruby', 20)
21 | user.first_name
22 |
23 | # ----------------------------------------
24 |
25 | class User
26 | # first_nameの読み書きを許可する
27 | attr_accessor :first_name
28 | # 省略
29 | end
30 | user = User.new('Alice', 'Ruby', 20)
31 | user.first_name #=> "Alice"
32 | # first_nameを変更する
33 | user.first_name = 'ありす'
34 | user.first_name #=> "ありす"
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_03_00.rb:
--------------------------------------------------------------------------------
1 | # Userクラスの定義
2 | class User
3 | end
4 |
5 | # OrderItemクラスの定義
6 | class OrderItem
7 | end
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_03_01.rb:
--------------------------------------------------------------------------------
1 | User.new
2 |
3 | # ----------------------------------------
4 |
5 | class User
6 | def initialize
7 | puts 'Initialized.'
8 | end
9 | end
10 | User.new
11 | #=> Initialized.
12 |
13 | # ----------------------------------------
14 |
15 | user = User.new
16 | user.initialize
17 | #=> private method `initialize' called for # (NoMethodError)
18 |
19 | # ----------------------------------------
20 |
21 | class User
22 | def initialize(name, age)
23 | puts "name: #{name}, age: #{age}"
24 | end
25 | end
26 | User.new #=> wrong number of arguments (given 0, expected 2) (ArgumentError)
27 | User.new('Alice', 20) #=> name: Alice, age: 20
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_03_02.rb:
--------------------------------------------------------------------------------
1 | class User
2 | # インスタンスメソッドの定義
3 | def hello
4 | "Hello!"
5 | end
6 | end
7 |
8 | user = User.new
9 | # インスタンスメソッドの呼び出し
10 | user.hello #=> "Hello!"
11 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_03_04.rb:
--------------------------------------------------------------------------------
1 | class User
2 | def initialize(name)
3 | @name = name
4 | end
5 |
6 | # これはインスタンスメソッド
7 | def hello
8 | # @nameの値はインスタンスによって異なる
9 | "Hello, I am #{@name}."
10 | end
11 | end
12 | alice = User.new('Alice')
13 | # インスタンスメソッドはインスタンス(オブジェクト)に対して呼び出す
14 | alice.hello #=> "Hello, I am Alice."
15 |
16 | bob = User.new('Bob')
17 | # インスタンスによって内部のデータが異なるので、helloメソッドの結果も異なる
18 | bob.hello #=> "Hello, I am Bob."
19 |
20 | # ----------------------------------------
21 |
22 | class User
23 | def initialize(name)
24 | @name = name
25 | end
26 |
27 | # self.を付けるとクラスメソッドになる
28 | def self.create_users(names)
29 | # mapメソッドを忘れた人は「4.4.1 map/collect」の項を参照
30 | names.map do |name|
31 | User.new(name)
32 | end
33 | end
34 |
35 | # これはインスタンスメソッド
36 | def hello
37 | "Hello, I am #{@name}."
38 | end
39 | end
40 |
41 | names = ['Alice', 'Bob', 'Carol']
42 | # クラスメソッドの呼び出し
43 | users = User.create_users(names)
44 | users.each do |user|
45 | # インスタンスメソッドの呼び出し
46 | puts user.hello
47 | end
48 | #=> Hello, I am Alice.
49 | # Hello, I am Bob.
50 | # Hello, I am Carol.
51 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_03_05.rb:
--------------------------------------------------------------------------------
1 | class Product
2 | # デフォルトの価格を定数として宣言する
3 | DEFAULT_PRICE = 0
4 |
5 | attr_reader :name, :price
6 |
7 | # 第2引数priceのデフォルト値を定数DEFAULT_PRICE(つまり0)とする
8 | def initialize(name, price = DEFAULT_PRICE)
9 | @name = name
10 | @price = price
11 | end
12 | end
13 |
14 | product = Product.new('A free movie')
15 | product.price #=> 0
16 |
17 | # ----------------------------------------
18 |
19 | # 定数名の例
20 | DEFAULT_PRICE = 0
21 | UNITS = { m: 1.0, ft: 3.28, in: 39.37 }
22 |
23 | # ----------------------------------------
24 |
25 | class Product
26 | DEFAULT_PRICE = 0
27 |
28 | def self.default_price
29 | # クラスメソッドから定数を参照する
30 | DEFAULT_PRICE
31 | end
32 |
33 | def default_price
34 | # インスタンスメソッドから定数を参照する
35 | DEFAULT_PRICE
36 | end
37 | end
38 |
39 | Product.default_price #=> 0
40 |
41 | product = Product.new
42 | product.default_price #=> 0
43 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_04_00.rb:
--------------------------------------------------------------------------------
1 | # 改札機オブジェクトの作成
2 | umeda = Gate.new(:umeda)
3 | mikuni = Gate.new(:mikuni)
4 |
5 | # 160円の切符を購入して梅田で乗車し、三国で降車する(NG)
6 | ticket = Ticket.new(160)
7 | umeda.enter(ticket)
8 | mikuni.exit(ticket) #=> false
9 |
10 | # 190円の切符を購入して梅田で乗車し、三国で降車する(OK)
11 | ticket = Ticket.new(190)
12 | umeda.enter(ticket)
13 | mikuni.exit(ticket) #=> true
14 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_04_01.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/gate'
3 |
4 | class GateTest < Minitest::Test
5 | def test_gate
6 | # とりあえずオブジェクトが作れることを確認する
7 | assert Gate.new
8 | end
9 | end
10 |
11 | # ----------------------------------------
12 |
13 | class Gate
14 | end
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_04_02.rb:
--------------------------------------------------------------------------------
1 | class GateTest < Minitest::Test
2 | def test_gate
3 | umeda = Gate.new(:umeda)
4 | juso = Gate.new(:juso)
5 |
6 | ticket = Ticket.new(160)
7 | umeda.enter(ticket)
8 | assert juso.exit(ticket)
9 | end
10 | end
11 |
12 | # ----------------------------------------
13 |
14 | class Gate
15 | def initialize(name)
16 | @name = name
17 | end
18 | end
19 |
20 | # ----------------------------------------
21 |
22 | class Ticket
23 | def initialize(fare)
24 | @fare = fare
25 | end
26 | end
27 |
28 | # ----------------------------------------
29 |
30 | require 'minitest/autorun'
31 | require_relative '../lib/gate'
32 | require_relative '../lib/ticket'
33 |
34 | class GateTest < Minitest::Test
35 | # 省略
36 |
37 | # ----------------------------------------
38 |
39 | class Gate
40 | # 省略
41 |
42 | def enter(ticket)
43 | end
44 |
45 | def exit(ticket)
46 | true
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_04_04.rb:
--------------------------------------------------------------------------------
1 | # 省略
2 |
3 | class GateTest < Minitest::Test
4 | def test_gate
5 | umeda = Gate.new(:umeda)
6 | juso = Gate.new(:juso)
7 |
8 | ticket = Ticket.new(160)
9 | umeda.enter(ticket)
10 | assert juso.exit(ticket)
11 | end
12 |
13 | def test_umeda_to_mikuni_when_fare_is_not_enough
14 | umeda = Gate.new(:umeda)
15 | mikuni = Gate.new(:mikuni)
16 |
17 | ticket = Ticket.new(160)
18 | umeda.enter(ticket)
19 | refute mikuni.exit(ticket)
20 | end
21 | end
22 |
23 | # ----------------------------------------
24 |
25 | class GateTest < Minitest::Test
26 | def test_umeda_to_juso
27 | # 省略
28 |
29 | # ----------------------------------------
30 |
31 | class GateTest < Minitest::Test
32 | # テストメソッドが実行される前にこのメソッドが毎回呼ばれる
33 | def setup
34 | @umeda = Gate.new(:umeda)
35 | @juso = Gate.new(:juso)
36 | @mikuni = Gate.new(:mikuni)
37 | end
38 |
39 | def test_umeda_to_juso
40 | ticket = Ticket.new(160)
41 | @umeda.enter(ticket)
42 | assert @juso.exit(ticket)
43 | end
44 |
45 | def test_umeda_to_mikuni_when_fare_is_not_enough
46 | ticket = Ticket.new(160)
47 | @umeda.enter(ticket)
48 | refute @mikuni.exit(ticket)
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_04_05.rb:
--------------------------------------------------------------------------------
1 | class GateTest < Minitest::Test
2 | # 省略
3 |
4 | def test_umeda_to_mikuni_when_fare_is_enough
5 | ticket = Ticket.new(190)
6 | @umeda.enter(ticket)
7 | assert @mikuni.exit(ticket)
8 | end
9 |
10 | def test_juso_to_mikuni
11 | ticket = Ticket.new(160)
12 | @juso.enter(ticket)
13 | assert @mikuni.exit(ticket)
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_05_00.rb:
--------------------------------------------------------------------------------
1 | class User
2 | attr_accessor :name
3 |
4 | def initialize(name)
5 | @name = name
6 | end
7 |
8 | def hello
9 | # selfなしでnameメソッドを呼ぶ
10 | "Hello, I am #{name}."
11 | end
12 |
13 | def hi
14 | # self付きでnameメソッドを呼ぶ
15 | "Hi, I am #{self.name}."
16 | end
17 |
18 | def my_name
19 | # 直接インスタンス変数の@nameにアクセスする
20 | "My name is #{@name}."
21 | end
22 | end
23 | user = User.new('Alice')
24 | user.hello #=> "Hello, I am Alice."
25 | user.hi #=> "Hi, I am Alice."
26 | user.my_name #=> "My name is Alice."
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_05_01.rb:
--------------------------------------------------------------------------------
1 | class User
2 | attr_accessor :name
3 |
4 | def initialize(name)
5 | @name = name
6 | end
7 |
8 | def rename_to_bob
9 | # selfなしでname=メソッドを呼ぶ(?)
10 | name = 'Bob'
11 | end
12 |
13 | def rename_to_carol
14 | # self付きでname=メソッドを呼ぶ
15 | self.name = 'Carol'
16 | end
17 |
18 | def rename_to_dave
19 | # 直接インスタンス変数を書き換える
20 | @name = 'Dave'
21 | end
22 | end
23 | user = User.new('Alice')
24 |
25 | # Bobにリネーム...できていない!!
26 | user.rename_to_bob
27 | user.name #=> "Alice"
28 |
29 | # Carolにリネーム
30 | user.rename_to_carol
31 | user.name #=> "Carol"
32 |
33 | # Daveにリネーム
34 | user.rename_to_dave
35 | user.name #=> "Dave"
36 |
37 | # ----------------------------------------
38 |
39 | def rename_to_bob
40 | name = 'Bob'
41 | end
42 |
43 | # ----------------------------------------
44 |
45 | def rename_to_bob
46 | # メソッド内でセッターメソッドを呼び出す場合はselfを必ず付ける!!
47 | self.name = 'Bob'
48 | end
49 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_05_03.rb:
--------------------------------------------------------------------------------
1 | class Product
2 | attr_reader :name, :price
3 |
4 | def initialize(name, price)
5 | @name = name
6 | @price = price
7 | end
8 |
9 | # 金額を整形するクラスメソッド
10 | def self.format_price(price)
11 | "#{price}円"
12 | end
13 |
14 | def to_s
15 | # インスタンスメソッドからクラスメソッドを呼び出す
16 | formatted_price = Product.format_price(price)
17 | "name: #{name}, price: #{formatted_price}"
18 | end
19 | end
20 |
21 | product = Product.new('A great movie', 1000)
22 | product.to_s #=> "name: A great movie, price: 1000円"
23 |
24 | # ----------------------------------------
25 |
26 | # クラス名.メソッドの形式でクラスメソッドを呼び出す
27 | Product.format_price(price)
28 |
29 | # self.class.メソッドの形式でクラスメソッドを呼び出す
30 | self.class.format_price(price)
31 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_06_02.rb:
--------------------------------------------------------------------------------
1 | class User
2 | end
3 |
4 | # ----------------------------------------
5 |
6 | user = User.new
7 | user.to_s #=> "#"
8 | user.nil? #=> false
9 |
10 | # ----------------------------------------
11 |
12 | User.superclass #=> Object
13 |
14 | # ----------------------------------------
15 |
16 | user = User.new
17 | user.methods.sort #=> [:!, :!=, :!~, :<=>, :==, (省略) :untrust, :untrusted?]
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_06_03.rb:
--------------------------------------------------------------------------------
1 | user = User.new
2 | user.class #=> User
3 |
4 | # ----------------------------------------
5 |
6 | user = User.new
7 |
8 | # userはUserクラスのインスタンスか?
9 | user.instance_of?(User) #=> true
10 |
11 | # userはStringクラスのインスタンスか?
12 | user.instance_of?(String) #=> false
13 |
14 | # ----------------------------------------
15 |
16 | user = User.new
17 |
18 | # instance_of?はクラスが全く同じでないとtrueにならない
19 | user.instance_of?(Object) #=> false
20 |
21 | # is_a?はis-a関係にあればtrueになる
22 | user.is_a?(User) #=> true
23 | user.is_a?(Object) #=> true
24 | user.is_a?(BasicObject) #=> true
25 |
26 | # is-a関係にない場合はfalse
27 | user.is_a?(String) #=> false
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_06_04.rb:
--------------------------------------------------------------------------------
1 | class Product
2 | end
3 |
4 | # ----------------------------------------
5 |
6 | # DVDクラスはProductクラスを継承する
7 | class DVD < Product
8 | end
9 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_06_07.rb:
--------------------------------------------------------------------------------
1 | class Foo
2 | def self.hello
3 | 'hello'
4 | end
5 | end
6 |
7 | class Bar < Foo
8 | end
9 |
10 | # Fooを継承したBarでもクラスメソッドのhelloが呼び出せる
11 | Foo.hello #=> "hello"
12 | Bar.hello #=> "hello"
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_07_01.rb:
--------------------------------------------------------------------------------
1 | class User
2 | # デフォルトはpublic
3 | def hello
4 | 'Hello!'
5 | end
6 | end
7 | user = User.new
8 | # publicメソッドなのでクラスの外部から呼び出せる
9 | user.hello #=> "Hello!"
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_07_02.rb:
--------------------------------------------------------------------------------
1 | class User
2 | # ここから下で定義されたメソッドはprivate
3 | private
4 |
5 | def hello
6 | 'Hello!'
7 | end
8 | end
9 | user = User.new
10 | # privateメソッドなのでクラスの外部から呼び出せない
11 | user.hello #=> private method `hello' called for # (NoMethodError)
12 |
13 | # ----------------------------------------
14 |
15 | class User
16 | def hello
17 | # Ruby 2.6以前 = selfを付けるとエラー
18 | # Ruby 2.7以降 = selfを付けても付けなくてもOK
19 | "Hello, I am #{self.name}."
20 | end
21 |
22 | private
23 |
24 | def name
25 | 'Alice'
26 | end
27 | end
28 | user = User.new
29 |
30 | # Ruby 2.6以前 = エラーになる
31 | user.hello
32 | #=> NoMethodError (private method `name' called for #)
33 |
34 | # Ruby 2.7以降 = エラーにならない
35 | user.hello
36 | #=> "Hello, I am Alice."
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_07_03.rb:
--------------------------------------------------------------------------------
1 | class User
2 | # ここから下はprivateメソッド
3 | private
4 |
5 | def foo
6 | end
7 |
8 | # ここから下はpublicメソッド
9 | public
10 |
11 | def bar
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_07_05.rb:
--------------------------------------------------------------------------------
1 | class User
2 | private
3 |
4 | # クラスメソッドもprivateメソッドになる?
5 | def self.hello
6 | 'Hello!'
7 | end
8 | end
9 | # クラスメソッドはprivateメソッドにならない!
10 | User.hello #=> "Hello!"
11 |
12 | # ----------------------------------------
13 |
14 | class User
15 | class << self
16 | # class << selfの構文ならクラスメソッドでもprivateが機能する
17 | private
18 |
19 | def hello
20 | 'Hello!'
21 | end
22 | end
23 | end
24 | User.hello #=> private method `hello' called for User:Class (NoMethodError)
25 |
26 | # ----------------------------------------
27 |
28 | class User
29 | def self.hello
30 | 'Hello!'
31 | end
32 | # 後からクラスメソッドをprivateに変更する
33 | private_class_method :hello
34 | end
35 | User.hello #=> private method `hello' called for User:Class (NoMethodError)
36 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_08_01.rb:
--------------------------------------------------------------------------------
1 | class Product
2 | DEFAULT_PRICE = 0
3 | # 再代入して定数の値を書き換える
4 | DEFAULT_PRICE = 1000
5 | end
6 | #=> warning: already initialized constant Product::DEFAULT_PRICE
7 |
8 | # 再代入後の値が返る
9 | Product::DEFAULT_PRICE #=> 1000
10 |
11 | # クラスの外部からでも再代入が可能
12 | Product::DEFAULT_PRICE = 3000
13 | #=> warning: already initialized constant Product::DEFAULT_PRICE
14 |
15 | Product::DEFAULT_PRICE #=> 3000
16 |
17 | # ----------------------------------------
18 |
19 | # クラスを凍結する
20 | Product.freeze
21 |
22 | # freezeすると変更できなくなる
23 | Product::DEFAULT_PRICE = 5000 #=> can't modify frozen #: Product (FrozenError)
24 |
25 | # ----------------------------------------
26 |
27 | class Product
28 | DEFAULT_PRICE = 0
29 | # freezeすれば再代入を防止できるが、デメリットの方が大きいので普通はしない
30 | freeze
31 | DEFAULT_PRICE = 1000 #=> can't modify frozen #: Product (FrozenError)
32 | end
33 |
34 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_09_03.rb:
--------------------------------------------------------------------------------
1 | # グローバル変数の宣言と値の代入
2 | $program_name = 'Awesome program'
3 |
4 | # グローバル変数に依存するクラス
5 | class Program
6 | def initialize(name)
7 | $program_name = name
8 | end
9 |
10 | def self.name
11 | $program_name
12 | end
13 |
14 | def name
15 | $program_name
16 | end
17 | end
18 |
19 | # $program_nameにはすでに名前が代入されている
20 | Program.name #=> "Awesome program"
21 |
22 | program = Program.new('Super program')
23 | program.name #=> "Super program"
24 |
25 | # Program.newのタイミングで$program_nameが"Super program"に変更される
26 | Program.name #=> "Super program"
27 | $program_name #=> "Super program"
28 |
29 | # ----------------------------------------
30 |
31 | # $foobarが未定義であれば(つまり、一度も代入されていなければ)nilが返る
32 | $foobar #=> nil
33 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_10_01.rb:
--------------------------------------------------------------------------------
1 | s = 'Hello'
2 | s.length #=> 5
3 | s.size #=> 5
4 |
5 | # ----------------------------------------
6 |
7 | class User
8 | def hello
9 | 'Hello!'
10 | end
11 |
12 | # helloメソッドのエイリアスメソッドとしてgreetを定義する
13 | alias greet hello
14 | end
15 |
16 | user = User.new
17 | user.hello #=> "Hello!"
18 | user.greet #=> "Hello!"
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_10_02.rb:
--------------------------------------------------------------------------------
1 | class User
2 | # freezeメソッドの定義を削除する
3 | undef freeze
4 | end
5 | user = User.new
6 | # freezeメソッドを呼び出すとエラーになる
7 | user.freeze #=> undefined method `freeze' for # (NoMethodError)
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_10_03.rb:
--------------------------------------------------------------------------------
1 | class User
2 | class BloodType
3 | attr_reader :type
4 |
5 | def initialize(type)
6 | @type = type
7 | end
8 | end
9 | end
10 |
11 | blood_type = User::BloodType.new('B')
12 | blood_type.type #=> "B"
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_10_07.rb:
--------------------------------------------------------------------------------
1 | alice = 'I am Alice.'
2 | bob = 'I am Bob.'
3 |
4 | # aliceのオブジェクトにだけ、shuffleメソッドを定義する
5 | def alice.shuffle
6 | chars.shuffle.join
7 | end
8 |
9 | # aliceはshuffleメソッドを持つが、bobは持たない
10 | alice.shuffle #=> "m le a.icIA"
11 | bob.shuffle #=> undefined method `shuffle' for "I am Bob.":String (NoMethodError)
12 |
13 | # ----------------------------------------
14 |
15 | n = 1
16 | def n.foo
17 | 'foo'
18 | end
19 | #=> can't define singleton (TypeError)
20 |
21 | sym = :alice
22 | def sym.bar
23 | 'bar'
24 | end
25 | #=> can't define singleton (TypeError)
26 |
27 | # ----------------------------------------
28 |
29 | alice = 'I am Alice.'
30 | # aliceというオブジェクトに特異メソッドを追加するもう一つの方法
31 | class << alice
32 | def shuffle
33 | chars.shuffle.join
34 | end
35 | end
36 | alice.shuffle #=> " ci Ama.lIe"
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/code_07_10_08.rb:
--------------------------------------------------------------------------------
1 | # クラスメソッドを定義するコード例
2 | class User
3 | def self.hello
4 | 'Hello.'
5 | end
6 |
7 | class << self
8 | def hi
9 | 'Hi.'
10 | end
11 | end
12 | end
13 |
14 | # 特異メソッドを定義するコード例
15 | alice = 'I am alice.'
16 |
17 | def alice.hello
18 | 'Hello.'
19 | end
20 |
21 | class << alice
22 | def hi
23 | 'Hi.'
24 | end
25 | end
26 |
27 | # ----------------------------------------
28 |
29 | class User
30 | end
31 |
32 | # クラス構文の外部でクラスメソッドを定義する方法1
33 | def User.hello
34 | 'Hello.'
35 | end
36 |
37 | # クラス構文の外部でクラスメソッドを定義する方法2
38 | class << User
39 | def hi
40 | 'Hi.'
41 | end
42 | end
43 |
44 | User.hello #=> "Hello."
45 | User.hi #=> "Hi."
46 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/column_07_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:irb上でクラス定義を繰り返す際の注意点
2 |
3 | class User
4 | def hello
5 | 'Hello.'
6 | end
7 | end
8 |
9 | # このクラス定義は既存のUserクラスにbyeメソッドを追加することになる
10 | class User
11 | def bye
12 | 'Bye.'
13 | end
14 | end
15 |
16 | user = User.new
17 | # helloメソッドもbyeメソッドも呼び出せる
18 | user.hello #=> "Hello."
19 | user.bye #=> "Bye."
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/column_07_02.rb:
--------------------------------------------------------------------------------
1 | limit ||= 10
2 |
3 | # ----------------------------------------
4 |
5 | class User
6 | # ...
7 |
8 | def icon_url
9 | twitter_data[:icon]
10 | end
11 |
12 | def location
13 | twitter_data[:location]
14 | end
15 |
16 | def twitter_data
17 | # Twitter APIからデータを取得して変数dataに代入する処理を書く
18 | # .
19 | # .
20 | data
21 | end
22 | end
23 |
24 | # ----------------------------------------
25 |
26 | def twitter_data
27 | # インスタンス変数と||=を使ったメモ化(データの保持)
28 | @twitter_data ||= begin
29 | # Twitter APIからデータを取得する処理を書く
30 | # .
31 | # .
32 | end
33 | end
34 |
35 | # ----------------------------------------
36 |
37 | # 遅延初期化を使わない場合
38 | class Foo
39 | attr_reader :bar
40 |
41 | # この場合、Foo.newするだけで時間がかかってしまう
42 | def initialize
43 | @bar = # 何か重い処理で@barを初期化...
44 | end
45 | end
46 |
47 | # 遅延初期化を使う場合
48 | class Foo
49 | # initializeでは何もしないため、Foo.newが即座に終わる
50 | # def initialize
51 | # end
52 |
53 | # 遅延初期化のテクニックを使ってbarの値を返す
54 | def bar
55 | @bar ||= # 何か重い処理で@barを初期化...
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/column_07_04.rb:
--------------------------------------------------------------------------------
1 | # コラム:継承したら同名のインスタンス変数に注意
2 |
3 | class Parent
4 | def initialize
5 | @first = 1
6 | @second = 2
7 | @third = 3
8 | end
9 |
10 | # 毎回"1.2.3"という文字列が返るはず(?)
11 | def number
12 | "#{@first}.#{@second}.#{@third}"
13 | end
14 | end
15 |
16 | class Child < Parent
17 | def initialize
18 | super
19 | @hour = 6
20 | @minute = 30
21 | # 偶然スーパークラスと同じ名前のインスタンス変数を使ってしまった!
22 | @second = 59
23 | end
24 |
25 | def time
26 | "#{@hour}:#{@minute}:#{@second}"
27 | end
28 | end
29 |
30 | parent = Parent.new
31 | parent.number #=> "1.2.3"
32 |
33 | child = Child.new
34 | child.time #=> "6:30:59"
35 |
36 | # @secondが上書きされているので、意図しない結果になってしまった!
37 | child.number #=> "1.59.3"
38 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/column_07_05.rb:
--------------------------------------------------------------------------------
1 | # コラム:クラスを可視性を変える方法
2 |
3 | class Foo
4 | # このようなクラス定義は無意味
5 | # (場合によってはエラーにならないこともあるが、クラスの可視性が変わるわけではない)
6 | private class Bar
7 | # 省略
8 | end
9 | end
10 | #=> nil is not a symbol nor a string (TypeError)
11 |
12 | # ----------------------------------------
13 |
14 | class Foo
15 | class Bar
16 | # 省略
17 | end
18 |
19 | # Barクラスの可視性をprivateにする
20 | private_constant :Bar
21 | end
22 |
23 | # Barクラスはprivateなクラスになったため、Fooクラスの外からは参照できない
24 | Foo::Bar.new
25 | #=> private constant Foo::Bar referenced (NameError)
26 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/column_07_06.rb:
--------------------------------------------------------------------------------
1 | # コラム:メソッドの有無を調べるrespond_to?
2 |
3 | s = 'Alice'
4 |
5 | # Stringクラスはsplitメソッドを持つ
6 | s.respond_to?(:split) #=> true
7 |
8 | # nameメソッドは持たない
9 | s.respond_to?(:name) #=> false
10 |
11 | # ----------------------------------------
12 |
13 | def display_name(object)
14 | if object.respond_to?(:name)
15 | # nameメソッドが呼び出せる場合
16 | puts "Name is <<#{object.name}>>"
17 | else
18 | # nameメソッドが呼び出せない場合
19 | puts 'No name.'
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/sample-codes/chapter_07/column_07_07.rb:
--------------------------------------------------------------------------------
1 | # コラム:Rubyでメソッドのオーバーロード?
2 |
3 | def add_ten(n)
4 | # nが整数以外の場合にも対応するためto_iで整数に変換する
5 | n.to_i + 10
6 | end
7 |
8 | # 整数を渡す
9 | add_ten(1) #=> 11
10 |
11 | # 文字列やnilを渡す
12 | add_ten('2') #=> 12
13 | add_ten(nil) #=> 10
14 |
15 | # ----------------------------------------
16 |
17 | # 引数にデフォルト値を付ける
18 | def add_numbers(a = 0, b = 0)
19 | a + b
20 | end
21 |
22 | # 引数の個数はゼロでも1個でも2個でもよい
23 | add_numbers #=> 0
24 | add_numbers(1) #=> 1
25 | add_numbers(1, 2) #=> 3
26 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_01_01.rb:
--------------------------------------------------------------------------------
1 | puts 'Hello, world!'.rainbow
2 | #=> Hello, world!
3 |
4 | puts [1, 2, 3].rainbow
5 | #=> [1, 2, 3]
6 |
7 | # ----------------------------------------
8 |
9 | "\e[31mABC\e[0m"
10 |
11 | # ----------------------------------------
12 |
13 | # 紙面では再現できないが"ABC"の文字列が赤色で出力される
14 | puts "\e[31mABC\e[0m"
15 | #=> ABC
16 |
17 | # ----------------------------------------
18 |
19 | # 文字列でも配列でもどちらでもrainbowメソッドが呼び出せる
20 | puts 'Hello, world!'.rainbow
21 | puts [1, 2, 3].rainbow
22 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_02_02.rb:
--------------------------------------------------------------------------------
1 | # helloメソッドをもつGreetableモジュールを定義
2 | module Greetable
3 | def hello
4 | 'hello'
5 | end
6 | end
7 |
8 | # ----------------------------------------
9 |
10 | # モジュールのインスタンスは作成できない
11 | greeter = Greetable.new #=> undefined method `new' for Greetable:Module (NoMethodError)
12 |
13 | # 他のモジュールを継承して新しいモジュールを作ることはできない
14 | module AwesomeGreetable < Greetable
15 | end
16 | #=> syntax error, unexpected '<' (SyntaxError)
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_03_02.rb:
--------------------------------------------------------------------------------
1 | module Taggable
2 | def price_tag
3 | # priceメソッドはinclude先で定義されているはず、という前提
4 | "#{price}円"
5 | end
6 | end
7 |
8 | class Product
9 | include Taggable
10 |
11 | def price
12 | 1000
13 | end
14 | end
15 |
16 | product = Product.new
17 | product.price_tag #=> "1000円"
18 |
19 | # ----------------------------------------
20 |
21 | module Taggable
22 | def price_tag
23 | # あえてselfを付けて呼びだしてもよい
24 | # selfはinclude先のクラス(たとえばProductクラス)のインスタンスになる
25 | "#{self.price}円"
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_03_03.rb:
--------------------------------------------------------------------------------
1 | # モジュールの定義はさっきと同じ
2 | module Loggable
3 | def log(text)
4 | puts "[LOG] #{text}"
5 | end
6 | end
7 |
8 | class Product
9 | # Loggableモジュールのメソッドを特異メソッド(クラスメソッド)としてミックスインする
10 | extend Loggable
11 |
12 | def self.create_products(names)
13 | # logメソッドをクラスメソッド内で呼び出す
14 | #(つまりlogメソッド自体もクラスメソッドになっている)
15 | log 'create_products is called.'
16 | # 他の実装は省略
17 | end
18 | end
19 |
20 | # クラスメソッド経由でlogメソッドが呼び出される
21 | Product.create_products([]) #=> [LOG] create_products is called.
22 |
23 | # Productクラスのクラスメソッドとして直接呼び出すことも可能
24 | Product.log('Hello.') #=> [LOG] Hello.
25 |
26 | # ----------------------------------------
27 |
28 | class Product
29 | extend Loggable
30 |
31 | # logメソッドをクラス構文の直下で呼び出す
32 | #(クラスが読み込まれるタイミングで、このlogメソッドも実行される)
33 | log 'Defined Product class.'
34 | end
35 | #=> [LOG] Defined Product class.
36 |
37 | # ----------------------------------------
38 |
39 | # クラス構文の内部でinclude/extendを使う代わりに、クラス名.include、
40 | # またはクラス名.extendの形式でモジュールをinclude/extendする
41 | Product.include Loggable
42 | Product.extend Loggable
43 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_04_00.rb:
--------------------------------------------------------------------------------
1 | # 文字列でも配列でもどちらでもrainbowメソッドが呼び出せる
2 | puts 'Hello, world!'.rainbow
3 | puts [1, 2, 3].rainbow
4 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_04_01.rb:
--------------------------------------------------------------------------------
1 | module Rainbowable
2 | def rainbow
3 | # rainbowメソッドの実装
4 | end
5 | end
6 |
7 | # ----------------------------------------
8 |
9 | String.include Rainbowable
10 | Array.include Rainbowable
11 |
12 | # ----------------------------------------
13 |
14 | class String
15 | include Rainbowable
16 | end
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_04_02.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/rainbowable'
3 |
4 | class RainbowableTest < Minitest::Test
5 | def test_rainbow
6 | # とりあえずモジュールが参照できることを確認する
7 | assert Rainbowable
8 | end
9 | end
10 |
11 | # ----------------------------------------
12 |
13 | module Rainbowable
14 | def rainbow
15 | # 実装はあとで
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_04_04.rb:
--------------------------------------------------------------------------------
1 | module Rainbowable
2 | def rainbow
3 | colored_chars = []
4 | to_s.each_char.with_index do |char, count|
5 | color = 31 + count % 6
6 | colored_chars << "\e[#{color}m#{char}"
7 | end
8 | colored_chars.join + "\e[0m"
9 | end
10 | end
11 |
12 | # ----------------------------------------
13 |
14 | module Rainbowable
15 | def rainbow
16 | to_s.each_char.map.with_index do |char, count|
17 | color = 31 + count % 6
18 | "\e[#{color}m#{char}"
19 | end.join + "\e[0m"
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_04_05.rb:
--------------------------------------------------------------------------------
1 | def setup
2 | # StringクラスやArrayクラスではなく、ObjectクラスにRainbowableモジュールをincludeする
3 | Object.include Rainbowable
4 | end
5 |
6 | # ----------------------------------------
7 |
8 | def test_rainbow
9 | # 省略
10 |
11 | # ハッシュや範囲オブジェクトなど、任意のオブジェクトに対してrainbowメソッドを呼びだしてみる
12 | puts({foo: 123, bar: 456}.rainbow)
13 | puts (10..20).rainbow
14 | puts true.rainbow
15 | puts false.rainbow
16 | end
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_05_01.rb:
--------------------------------------------------------------------------------
1 | module Loggable
2 | # 省略
3 | end
4 |
5 | class Product
6 | include Loggable
7 | # 省略
8 | end
9 |
10 | # ----------------------------------------
11 |
12 | Product.include?(Loggable) #=> true
13 |
14 | # ----------------------------------------
15 |
16 | Product.included_modules #=> [Loggable, Kernel]
17 |
18 | # ----------------------------------------
19 |
20 | Product.ancestors #=> [Product, Loggable, Object, Kernel, BasicObject]
21 |
22 | # ----------------------------------------
23 |
24 | product = Product.new
25 | # product.classはProductクラスを返す
26 | product.class.include?(Loggable) #=> true
27 | product.class.included_modules #=> [Loggable, Kernel]
28 |
29 | # ----------------------------------------
30 |
31 | product = Product.new
32 | # 引数が自クラス、スーパークラス、includeしているモジュールのいずれかに該当すればtrue
33 | product.is_a?(Product) #=> true
34 | product.is_a?(Loggable) #=> true
35 | product.is_a?(Object) #=> true
36 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_05_02.rb:
--------------------------------------------------------------------------------
1 | Array.include?(Enumerable) #=> true
2 | Hash.include?(Enumerable) #=> true
3 | Range.include?(Enumerable) #=> true
4 |
5 | # ----------------------------------------
6 |
7 | # 配列、ハッシュ、範囲でmapメソッドを使う
8 | [1, 2, 3].map { |n| n * 10 } #=> [10, 20, 30]
9 | { a: 1, b: 2, c: 3 }.map { |k, v| [k, v * 10] } #=> [[:a, 10], [:b, 20], [:c, 30]]
10 | (1..3).map { |n| n * 10 } #=> [10, 20, 30]
11 |
12 | # 配列、ハッシュ、範囲でcountメソッドを使う
13 | [1, 2, 3].count #=> 3
14 | { a: 1, b: 2, c: 3 }.count #=> 3
15 | (1..3).count #=> 3
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_05_04.rb:
--------------------------------------------------------------------------------
1 | Object.include?(Kernel) #=> true
2 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_05_05.rb:
--------------------------------------------------------------------------------
1 | # ここはどこ?私は誰?
2 |
3 | class User
4 | # Userクラスの定義
5 | end
6 |
7 | # ----------------------------------------
8 |
9 | # ここはトップレベル
10 | p self #=> main
11 | p self.class #=> Object
12 |
13 | class User
14 | # ここはクラスの内部
15 | p self #=> User
16 | p self.class #=> Class
17 | end
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_05_06.rb:
--------------------------------------------------------------------------------
1 | class User
2 | end
3 |
4 | # Userクラス自身のクラスはClassクラス
5 | User.class #=> Class
6 |
7 | # ClassクラスのスーパークラスはModuleクラス
8 | Class.superclass #=> Module
9 |
10 | module Loggable
11 | end
12 |
13 | # Loggableモジュール自身のクラスはModuleクラス
14 | Loggable.class #=> Module
15 |
16 | # ModuleクラスのスーパークラスはObjectクラス
17 | Module.superclass #=> Object
18 |
19 | # ----------------------------------------
20 |
21 | class User
22 | p self #=> User
23 | p self.class #=> Class
24 | end
25 |
26 | module Loggable
27 | p self #=> Loggable
28 | p self.class #=> Module
29 | end
30 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_05_07.rb:
--------------------------------------------------------------------------------
1 | module NameChangeable
2 | def change_name
3 | # include先のクラスのインスタンス変数を変更する
4 | @name = 'ありす'
5 | end
6 | end
7 |
8 | class User
9 | include NameChangeable
10 |
11 | attr_reader :name
12 |
13 | def initialize(name)
14 | @name = name
15 | end
16 | end
17 |
18 | user = User.new('alice')
19 | user.name #=> "alice"
20 |
21 | # モジュールで定義したメソッドでインスタンス変数を書き換える
22 | user.change_name
23 | user.name #=> "ありす"
24 |
25 | # ----------------------------------------
26 |
27 | module NameChangeable
28 | def change_name
29 | # セッターメソッド経由でデータを変更する
30 | # (ミックスイン先のクラスでセッターメソッドが未定義であれば、エラーが発生して実装上の問題に気づける)
31 | self.name = 'ありす'
32 | end
33 | end
34 |
35 | class User
36 | include NameChangeable
37 |
38 | # ゲッターメソッドとセッターメソッドを用意する
39 | attr_accessor :name
40 |
41 | def initialize(name)
42 | @name = name
43 | end
44 | end
45 |
46 | # Userクラスの使い方は先ほどと同じ
47 | user = User.new('alice')
48 | user.change_name
49 | user.name #=> "ありす"
50 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_05_08.rb:
--------------------------------------------------------------------------------
1 | module Loggable
2 | def log(text)
3 | puts "[LOG] #{text}"
4 | end
5 | end
6 |
7 | s = 'abc'
8 |
9 | # 文字列は通常logメソッドを持たない
10 | s.log('Hello.') #=> undefined method `log' for "abc":String (NoMethodError)
11 |
12 | # 文字列sにLoggableモジュールのメソッドを特異メソッドとしてミックスインする
13 | s.extend Loggable
14 |
15 | # Loggableモジュールのlogメソッドが呼び出せるようになる
16 | s.log('Hello.') #=> [LOG] Hello.
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_06_01.rb:
--------------------------------------------------------------------------------
1 | class Second
2 | def initialize(player, uniform_number)
3 | @player = player
4 | @uniform_number = uniform_number
5 | end
6 | end
7 |
8 | # ----------------------------------------
9 |
10 | class Second
11 | def initialize(digits)
12 | @digits = digits
13 | end
14 | end
15 |
16 | # ----------------------------------------
17 |
18 | # 二塁手のAliceを作成したい(が、区別できない)
19 | Second.new('Alice', 13)
20 |
21 | # 時計の13秒を作成したい(が、区別できない)
22 | Second.new(13)
23 |
24 | # ----------------------------------------
25 |
26 | module Baseball
27 | # これはBaseballモジュールに属するSecondクラス
28 | class Second
29 | def initialize(player, uniform_number)
30 | @player = player
31 | @uniform_number = uniform_number
32 | end
33 | end
34 | end
35 |
36 | module Clock
37 | # これはClockモジュールに属するSecondクラス
38 | class Second
39 | def initialize(digits)
40 | @digits = digits
41 | end
42 | end
43 | end
44 |
45 | # ----------------------------------------
46 |
47 | # 二塁手のAliceを作成する(ちゃんと区別できる)
48 | Baseball::Second.new('Alice', 13)
49 |
50 | # 時計の13秒を作成する(ちゃんと区別できる)
51 | Clock::Second.new(13)
52 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_06_02.rb:
--------------------------------------------------------------------------------
1 | require "active_support/core_ext/string/conversions"
2 |
3 | module ActiveRecord
4 | module Associations
5 | # Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
6 | class AliasTracker # :nodoc:
7 | # 省略
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_06_03.rb:
--------------------------------------------------------------------------------
1 | # すでにBaseballモジュールが定義されている
2 | module Baseball
3 | end
4 |
5 | # モジュール名::クラス名の形でクラスを定義できる
6 | class Baseball::Second
7 | def initialize(player, uniform_number)
8 | @player = player
9 | @uniform_number = uniform_number
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_07_01.rb:
--------------------------------------------------------------------------------
1 | module Loggable
2 | # 特異メソッドとしてメソッドを定義する
3 | def self.log(text)
4 | puts "[LOG] #{text}"
5 | end
6 | end
7 |
8 | # ほかのクラスにミックスインしなくてもモジュール単体でそのメソッドを呼び出せる
9 | Loggable.log('Hello.') #=> [LOG] Hello.
10 |
11 | # ----------------------------------------
12 |
13 | module Loggable
14 | class << self
15 | def log(text)
16 | puts "[LOG] #{text}"
17 | end
18 |
19 | # 以下、ほかの特異メソッドを定義
20 | end
21 | end
22 |
23 | Loggable.log('Hello.') #=> [LOG] Hello.
24 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_07_02.rb:
--------------------------------------------------------------------------------
1 | module Loggable
2 | def log(text)
3 | puts "[LOG] #{text}"
4 | end
5 | # logメソッドをミックスインとしても、モジュールの特異メソッドとしても使えるようにする
6 | # (module_functionは対象メソッドの定義よりも下で呼び出すこと)
7 | module_function :log
8 | end
9 |
10 | # モジュールの特異メソッドとしてlogメソッドを呼び出す
11 | Loggable.log('Hello.') #=> [LOG] Hello.
12 |
13 | # Loggableモジュールをincludeしたクラスを定義する
14 | class Product
15 | include Loggable
16 |
17 | def title
18 | # includeしたLoggableモジュールのlogメソッドを呼び出す
19 | log 'title is called.'
20 | 'A great movie'
21 | end
22 | end
23 |
24 | # ミックスインとしてlogメソッドを呼び出す
25 | product = Product.new
26 | product.title
27 | #=> [LOG] title is called.
28 | # "A great movie"
29 |
30 | # ----------------------------------------
31 |
32 | product = Product.new
33 | # logメソッドはprivateなので外部からは呼び出せない
34 | product.log 'Hello.' #=> private method `log' called for # (NoMethodError)
35 |
36 | # ----------------------------------------
37 |
38 | module Loggable
39 | # ここから下のメソッドはすべてモジュール関数
40 | module_function
41 |
42 | def log(text)
43 | puts "[LOG] #{text}"
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_07_03.rb:
--------------------------------------------------------------------------------
1 | module Loggable
2 | # 定数を定義する
3 | PREFIX = '[LOG]'
4 |
5 | def log(text)
6 | puts "#{PREFIX} #{text}"
7 | end
8 | end
9 |
10 | # 定数を参照する
11 | Loggable::PREFIX #=> "[LOG]"
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_07_04.rb:
--------------------------------------------------------------------------------
1 | # モジュールの特異メソッドとしてsqrt(平方根)メソッドを利用する
2 | Math.sqrt(2) #=> 1.4142135623730951
3 |
4 | class Calculator
5 | include Math
6 |
7 | def calc_sqrt(n)
8 | # ミックスインとしてMathモジュールのメソッドを使う
9 | sqrt(n)
10 | end
11 | end
12 |
13 | calculator = Calculator.new
14 | calculator.calc_sqrt(2) #=> 1.4142135623730951
15 |
16 | # ----------------------------------------
17 |
18 | Math::E #=> 2.718281828459045
19 | Math::PI #=> 3.141592653589793
20 |
21 | # ----------------------------------------
22 |
23 | # Kernelモジュールの特異メソッドとしてputsやpを呼び出す
24 | Kernel.puts 'Hello.' #=> Hello.
25 | Kernel.p [1, 2, 3] #=> [1, 2, 3]
26 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_08_00.rb:
--------------------------------------------------------------------------------
1 | # AwesomeApiは何らかのWeb APIを利用するライブラリ、という想定
2 | module AwesomeApi
3 | # 設定値を保持するクラスインスタンス変数を用意する
4 | @base_url = ''
5 | @debug_mode = false
6 |
7 | # クラスインスタンス変数を読み書きするための特異メソッドを定義する
8 | class << self
9 | def base_url=(value)
10 | @base_url = value
11 | end
12 |
13 | def base_url
14 | @base_url
15 | end
16 |
17 | def debug_mode=(value)
18 | @debug_mode = value
19 | end
20 |
21 | def debug_mode
22 | @debug_mode
23 | end
24 |
25 | # 上ではわかりやすくするために明示的にメソッドを定義したが、本来は以下の1行で済む
26 | # attr_accessor :base_url, :debug_mode
27 | end
28 | end
29 |
30 | # 設定値を保存する
31 | AwesomeApi.base_url = 'https://example.com'
32 | AwesomeApi.debug_mode = true
33 |
34 | # 設定値を参照する
35 | AwesomeApi.base_url #=> "https://example.com"
36 | AwesomeApi.debug_mode #=> true
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_09_01.rb:
--------------------------------------------------------------------------------
1 | module A
2 | def to_s
3 | " #{super}"
4 | end
5 | end
6 |
7 | module B
8 | def to_s
9 | " #{super}"
10 | end
11 | end
12 |
13 | class Product
14 | def to_s
15 | " #{super}"
16 | end
17 | end
18 |
19 | class DVD < Product
20 | include A
21 | include B
22 |
23 | def to_s
24 | " #{super}"
25 | end
26 | end
27 |
28 | # ----------------------------------------
29 |
30 | dvd = DVD.new
31 | dvd.to_s #=> " #"
32 |
33 | # ----------------------------------------
34 |
35 | DVD.ancestors #=> [DVD, B, A, Product, Object, Kernel, BasicObject]
36 |
37 | # ----------------------------------------
38 |
39 | # fooメソッドはBasicObjectクラスまで探索しても見つからないのでエラー
40 | dvd.foo #=> NoMethodError: undefined method `foo' for #
41 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_09_02.rb:
--------------------------------------------------------------------------------
1 | module Greetable
2 | def hello
3 | 'hello.'
4 | end
5 | end
6 |
7 | module Aisatsu
8 | # 別のモジュールをincludeする
9 | include Greetable
10 |
11 | def konnichiwa
12 | 'こんにちは。'
13 | end
14 | end
15 |
16 | class User
17 | # Aisatsuモジュールだけをincludeする
18 | include Aisatsu
19 | end
20 |
21 | # ----------------------------------------
22 |
23 | user = User.new
24 |
25 | # Aisatsuモジュールのメソッドを呼び出す
26 | user.konnichiwa #=> "こんにちは。"
27 |
28 | # Greetableモジュールのメソッドを呼び出す
29 | user.hello #=> "hello."
30 |
31 | # ----------------------------------------
32 |
33 | User.ancestors #=> [User, Aisatsu, Greetable, Object, Kernel, BasicObject]
34 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/code_08_09_03.rb:
--------------------------------------------------------------------------------
1 | module A
2 | def to_s
3 | " #{super}"
4 | end
5 | end
6 |
7 | class Product
8 | # includeではなくprependを使う
9 | prepend A
10 |
11 | def to_s
12 | " #{super}"
13 | end
14 | end
15 |
16 | product = Product.new
17 | product.to_s #=> " #"
18 |
19 | # ----------------------------------------
20 |
21 | # prependではなくincludeでモジュールAをミックスインした場合
22 | product.to_s #=> " #"
23 |
24 | # ----------------------------------------
25 |
26 | Product.ancestors #=> [A, Product, Object, Kernel, BasicObject]
27 |
28 | # ----------------------------------------
29 |
30 | Product.ancestors #=> [Product, A, Object, Kernel, BasicObject]
31 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/column_08_01.rb:
--------------------------------------------------------------------------------
1 | self.class #=> Object
2 |
3 | # ----------------------------------------
4 |
5 | # トップレベルにメソッドを定義すると、どのクラスに定義されたことになる?
6 | def greet
7 | 'Hi!'
8 | end
9 |
10 | # ----------------------------------------
11 |
12 | class Object
13 | private
14 |
15 | def greet
16 | 'Hi!'
17 | end
18 | end
19 |
20 | # ----------------------------------------
21 |
22 | # private_instance_methodsはそのクラスで定義されているprivateメソッド名の一覧を配列で返す
23 | # また、grepメソッドは引数にマッチした要素を配列で返す
24 | Object.private_instance_methods.grep(:greet)
25 | #=> [:greet]
26 |
27 | # ----------------------------------------
28 |
29 | def greet
30 | 'Hi!'
31 | end
32 |
33 | class Foo
34 | def bar
35 | # トップレベルで定義したメソッドを呼び出す
36 | greet
37 | end
38 | end
39 |
40 | Foo.new.bar #=> "Hi!"
41 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/column_08_02.rb:
--------------------------------------------------------------------------------
1 | # コラム:モジュールの用途はひとつとは限らない
2 |
3 | # AwesomeApiモジュールは設定値を保持する(用途その1)
4 | module AwesomeApi
5 | @base_url = ''
6 | @debug_mode = false
7 |
8 | class << self
9 | attr_accessor :base_url, :debug_mode
10 | end
11 | end
12 |
13 | # こちらではAwesomeApiモジュールが名前空間として使われる(用途その2)
14 | module AwesomeApi
15 | class Engine
16 | # クラスの定義
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_08/column_08_03.rb:
--------------------------------------------------------------------------------
1 | # コラム:二重コロン(::)とドット(.)の違い
2 |
3 | module Sample
4 | class User
5 | NAME = 'Alice'
6 |
7 | def self.hello(name = NAME)
8 | "Hello, I am #{name}."
9 | end
10 | end
11 | end
12 |
13 | # ----------------------------------------
14 |
15 | Sample::User::NAME #=> "Alice"
16 |
17 | Sample::User.hello #=> "Hello, I am Alice."
18 |
19 | # ----------------------------------------
20 |
21 | Sample::User::hello #=> "Hello, I am Alice."
22 |
23 | # ----------------------------------------
24 |
25 | s = 'abc'
26 | s::upcase #=> "ABC"
27 |
28 | # ----------------------------------------
29 |
30 | # Sample.UserだとUserがメソッドと見なされる
31 | Sample.User::NAME #=> undefined method `User' for Sample:Module (NoMethodError)
32 | # User.NAMEだとNAMEがメソッドと見なされる
33 | Sample::User.NAME #=> undefined method `NAME' for Sample::User:Class (NoMethodError)
34 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_02_01.rb:
--------------------------------------------------------------------------------
1 | 1 + '10'
2 |
3 | # ----------------------------------------
4 |
5 | puts 'Start.'
6 | 1 + '10'
7 | # 上の行で例外が発生するため、ここから下は実行されない
8 | puts 'End.'
9 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_02_02.rb:
--------------------------------------------------------------------------------
1 | puts 'Start.'
2 |
3 | # 例外処理を組み込んで例外に対処する
4 | begin
5 | 1 + '10'
6 | rescue
7 | puts '例外が発生したが、このまま続行する'
8 | end
9 |
10 | # 例外処理を組み込んだので、最後まで実行可能
11 | puts 'End.'
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_02_03.rb:
--------------------------------------------------------------------------------
1 | # method_1にだけ例外処理を記述する
2 | def method_1
3 | puts 'method_1 start.'
4 | begin
5 | method_2
6 | rescue
7 | puts '例外が発生しました'
8 | end
9 | puts 'method_1 end.'
10 | end
11 |
12 | def method_2
13 | puts 'method_2 start.'
14 | method_3
15 | puts 'method_2 end.'
16 | end
17 |
18 | def method_3
19 | puts 'method_3 start.'
20 | # ZeroDivisionErrorを発生させる
21 | 1 / 0
22 | puts 'method_3 end.'
23 | end
24 |
25 | # 処理を開始する
26 | method_1
27 | #=> method_1 start.
28 | # method_2 start.
29 | # method_3 start.
30 | # 例外が発生しました
31 | # method_1 end.
32 |
33 | # ----------------------------------------
34 |
35 | # method_1から例外処理を削除する
36 | def method_1
37 | puts 'method_1 start.'
38 | method_2
39 | puts 'method_1 end.'
40 | end
41 |
42 | # method_2, method_3は同じなので省略
43 |
44 | # 処理を開始する
45 | method_1
46 | #=> method_1 start.
47 | # method_2 start.
48 | # method_3 start.
49 | # divided by 0 (ZeroDivisionError)
50 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_02_04.rb:
--------------------------------------------------------------------------------
1 | begin
2 | 1 / 0
3 | rescue => e
4 | puts "エラークラス: #{e.class}"
5 | puts "エラーメッセージ: #{e.message}"
6 | puts "バックトレース -----"
7 | puts e.backtrace
8 | puts "-----"
9 | end
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_02_05.rb:
--------------------------------------------------------------------------------
1 | begin
2 | 1 / 0
3 | rescue ZeroDivisionError
4 | puts '0で除算しました'
5 | end
6 | #=> 0で除算しました
7 |
8 | # ----------------------------------------
9 |
10 | begin
11 | # NoMethodErrorを発生させる
12 | 'abc'.foo
13 | rescue ZeroDivisionError
14 | puts '0で除算しました'
15 | end
16 | #=> undefined method `foo' for "abc":String (NoMethodError)
17 |
18 | # ----------------------------------------
19 |
20 | begin
21 | 'abc'.foo
22 | rescue ZeroDivisionError
23 | puts '0で除算しました'
24 | rescue NoMethodError
25 | puts '存在しないメソッドが呼び出されました'
26 | end
27 | #=> 存在しないメソッドが呼び出されました
28 |
29 | # ----------------------------------------
30 |
31 | begin
32 | 'abc'.foo
33 | rescue ZeroDivisionError, NoMethodError
34 | puts '0で除算したか、存在しないメソッドが呼び出されました'
35 | end
36 | #=> 0で除算したか、存在しないメソッドが呼び出されました
37 |
38 | # ----------------------------------------
39 |
40 | begin
41 | 'abc'.foo
42 | rescue ZeroDivisionError, NoMethodError => e
43 | puts "0で除算したか、存在しないメソッドが呼び出されました"
44 | puts "エラー: #{e.class} #{e.message}"
45 | end
46 | #=> 0で除算したか、存在しないメソッドが呼び出されました
47 | # エラー: NoMethodError undefined method `foo' for "abc":String
48 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_02_06.rb:
--------------------------------------------------------------------------------
1 | begin
2 | # 例外が起きそうな処理
3 | rescue
4 | # StandardErrorとそのサブクラスのみ捕捉される
5 | end
6 |
7 | # ----------------------------------------
8 |
9 | # 例外処理の悪い例
10 | begin
11 | # 例外が起きそうな処理
12 | rescue Exception
13 | # Exceptionとそのサブクラスが捕捉される。つまり、NoMemoryErrorやSystemExitまで捕捉されてしまう
14 | end
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_02_08.rb:
--------------------------------------------------------------------------------
1 | retry_count = 0
2 | begin
3 | puts '処理を開始します。'
4 | # わざと例外を発生させる
5 | 1 / 0
6 | rescue
7 | retry_count += 1
8 | if retry_count <= 3
9 | puts "retryします。(#{retry_count}回目)"
10 | retry
11 | else
12 | puts 'retryに失敗しました。'
13 | end
14 | end
15 | #=> 処理を開始します。
16 | # retryします。(1回目)
17 | # 処理を開始します。
18 | # retryします。(2回目)
19 | # 処理を開始します。
20 | # retryします。(3回目)
21 | # 処理を開始します。
22 | # retryに失敗しました。
23 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_04_02.rb:
--------------------------------------------------------------------------------
1 | # 大量のユーザーにメールを送信する(例外が起きても最後まで続行する)
2 | users.each do |user|
3 | begin
4 | # メール送信を実行する
5 | send_mail_to(user)
6 | rescue => e
7 | # full_messageメソッドを使って例外のクラス名、エラーメッセージ、バックトレースをターミナルに出力
8 | # (ログファイルがあればそこに出力するほうがベター)
9 | puts e.full_message
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_04_03.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | # 令和の日付文字列をDateオブジェクトに変換する
4 | def convert_reiwa_to_date(reiwa_text)
5 | # 例外処理の対象が無駄に広すぎるので好ましくない
6 | begin
7 | m = reiwa_text.match(/令和(?\d+)年(?\d+)月(?\d+)日/)
8 | year = m[:jp_year].to_i + 2018
9 | month = m[:month].to_i
10 | day = m[:day].to_i
11 | Date.new(year, month, day)
12 | rescue
13 | # 例外が起きたら(=無効な日付が渡されたら)nilを返したい
14 | nil
15 | end
16 | end
17 |
18 | # ----------------------------------------
19 |
20 | def convert_reiwa_to_date(reiwa_text)
21 | m = reiwa_text.match(/令和(?\d+)年(?\d+)月(?\d+)日/)
22 | year = m[:jp_year].to_i + 2018
23 | month = m[:month].to_i
24 | day = m[:day].to_i
25 | # 例外処理の範囲を狭め、捕捉する例外クラスを限定する
26 | begin
27 | Date.new(year, month, day)
28 | rescue ArgumentError
29 | # 無効な日付であればnilを返す
30 | nil
31 | end
32 | end
33 |
34 | convert_reiwa_to_date('令和3年12月31日') #=> #
35 | convert_reiwa_to_date('令和3年99月99日') #=> nil
36 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_04_04.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | def convert_reiwa_to_date(reiwa_text)
4 | m = reiwa_text.match(/令和(?\d+)年(?\d+)月(?\d+)日/)
5 | year = m[:jp_year].to_i + 2018
6 | month = m[:month].to_i
7 | day = m[:day].to_i
8 | # 正しい日付の場合のみ、Dateオブジェクトを作成する
9 | if Date.valid_date?(year, month, day)
10 | Date.new(year, month, day)
11 | end
12 | end
13 |
14 | convert_reiwa_to_date('令和3年12月31日') #=> #
15 | convert_reiwa_to_date('令和3年99月99日') #=> nil
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_04_05.rb:
--------------------------------------------------------------------------------
1 | # elseを用意しないパターン(良くない例)
2 | def currency_of(country)
3 | case country
4 | when :japan
5 | 'yen'
6 | when :us
7 | 'dollar'
8 | when :india
9 | 'rupee'
10 | end
11 | end
12 | # 想定外の国名を渡すとnilが返る
13 | currency_of(:italy) #=> nil
14 |
15 | # ----------------------------------------
16 |
17 | currency = currency_of(:italy)
18 | # 戻り値が常にStringオブジェクトだと思い込んでしまい、upcaseメソッドを呼びだしてしまった
19 | currency.upcase #=>undefined method `upcase' for nil:NilClass (NoMethodError)
20 |
21 | # ----------------------------------------
22 |
23 | # elseを:indiaとして扱うパターン(良くない例)
24 | def currency_of(country)
25 | case country
26 | when :japan
27 | 'yen'
28 | when :us
29 | 'dollar'
30 | else
31 | 'rupee'
32 | end
33 | end
34 | # 矛盾した値が返ってきてしまう
35 | currency_of(:italy) #=> "rupee"
36 |
37 | # ----------------------------------------
38 |
39 | # elseに入ったら例外を発生させるパターン(良い例)
40 | def currency_of(country)
41 | case country
42 | when :japan
43 | 'yen'
44 | when :us
45 | 'dollar'
46 | when :india
47 | 'rupee'
48 | else
49 | raise ArgumentError, "無効な国名です。#{country}"
50 | end
51 | end
52 | # 例外が発生する
53 | currency_of(:italy) #=> 無効な国名です。italy (ArgumentError)
54 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_04_06.rb:
--------------------------------------------------------------------------------
1 | def some_method
2 | 1 / 0
3 | rescue => e
4 | # full_messageと書くつもりがfull_mesageと書いてしまった
5 | puts "ERROR! #{e.full_mesage}"
6 | end
7 |
8 | # rescue節で別の例外が起きたために、本来出力されるべき"ERROR!"の文字が出力されない
9 | some_method
10 | #=> undefined method `full_mesage' for # (NoMethodError)
11 | # (以下略)
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_05_03.rb:
--------------------------------------------------------------------------------
1 | # getsメソッドを呼ぶとプログラムはユーザーの入力を待つ
2 | input = gets
3 | # (Helloと入力してからリターンキーを押す)
4 | input #=> "Hello\n"
5 |
6 | # ----------------------------------------
7 |
8 | input = gets
9 | # (Helloと入力してからリターンキーを押す)
10 | input = input.chomp
11 | input #=> "Hello"
12 |
13 | # ----------------------------------------
14 |
15 | input = gets.chomp
16 | # (Helloと入力してからリターンキーを押す)
17 | input #=> "Hello"
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_05_04.rb:
--------------------------------------------------------------------------------
1 | print 'Text?: '
2 | text = gets.chomp
3 | # 動作確認のため変数の中身を表示
4 | puts text
5 |
6 | # ----------------------------------------
7 |
8 | print 'Text?: '
9 | text = gets.chomp
10 | print 'Pattern?: '
11 | pattern = gets.chomp
12 |
13 | # ----------------------------------------
14 |
15 | print 'Text?: '
16 | text = gets.chomp
17 | print 'Pattern?: '
18 | pattern = gets.chomp
19 |
20 | regexp = Regexp.new(pattern)
21 | matches = text.scan(regexp)
22 | if matches.size > 0
23 | puts "Matched: #{matches.join(', ')}"
24 | else
25 | puts 'Nothing matched.'
26 | end
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_05_05.rb:
--------------------------------------------------------------------------------
1 | print 'Text?: '
2 | text = gets.chomp
3 |
4 | # 例外処理を組み込んで再入力可能にする
5 | begin
6 | print 'Pattern?: '
7 | pattern = gets.chomp
8 | regexp = Regexp.new(pattern)
9 | rescue RegexpError => e
10 | puts "Invalid pattern: #{e.message}"
11 | retry
12 | end
13 |
14 | matches = text.scan(regexp)
15 | if matches.size > 0
16 | puts "Matched: #{matches.join(', ')}"
17 | else
18 | puts "Nothing matched."
19 | end
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_01.rb:
--------------------------------------------------------------------------------
1 | # 書き込みモードでファイルを開く
2 | file = File.open('some.txt', 'w')
3 |
4 | begin
5 | # ファイルに文字列を書き込む
6 | file << 'Hello'
7 | ensure
8 | # 例外の有無にかかわらず必ずファイルをクローズする
9 | file.close
10 | end
11 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_02.rb:
--------------------------------------------------------------------------------
1 | # ブロック付きでオープンすると、メソッドの実行後に自動的にクローズされる
2 | File.open('some.txt', 'w') do |file|
3 | file << 'Hello'
4 | end
5 |
6 | # ----------------------------------------
7 |
8 | File.open('some.txt', 'w') do |file|
9 | file << 'Hello'
10 | # わざと例外を発生させる
11 | 1 / 0
12 | end
13 | # 例外は発生するものの、openメソッドによってクローズ処理自体は必ず行われる
14 | #=> divided by 0 (ZeroDivisionError)
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_03.rb:
--------------------------------------------------------------------------------
1 | begin
2 | # 例外が発生するかもしれない処理
3 | rescue
4 | # 例外が発生した場合の処理
5 | else
6 | # 例外が発生しなかった場合の処理
7 | ensure
8 | # 例外の有無にかかわらず実行する処理
9 | end
10 |
11 | # ----------------------------------------
12 |
13 | # else節を使う場合
14 | begin
15 | puts 'Hello.'
16 | rescue
17 | puts '例外が発生しました。'
18 | else
19 | puts '例外は発生しませんでした。'
20 | end
21 | #=> Hello.
22 | # 例外は発生しませんでした。
23 |
24 | # else節を使わない場合
25 | begin
26 | puts 'Hello.'
27 | puts '例外は発生しませんでした。'
28 | rescue
29 | puts '例外が発生しました。'
30 | end
31 | #=> Hello.
32 | # 例外は発生しませんでした。
33 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_04.rb:
--------------------------------------------------------------------------------
1 | # 正常に終了した場合
2 | ret =
3 | begin
4 | 'OK'
5 | rescue => e
6 | 'error'
7 | ensure
8 | 'ensure'
9 | end
10 | ret #=> "OK"
11 |
12 | # 例外が発生した場合
13 | ret =
14 | begin
15 | 1 / 0 # ZeroDivisionErrorを発生させる
16 | 'OK'
17 | rescue => e
18 | 'error'
19 | ensure
20 | 'ensure'
21 | end
22 | ret #=> "error"
23 |
24 | # ----------------------------------------
25 |
26 | def some_method(n)
27 | begin
28 | 1 / n
29 | 'OK'
30 | rescue => e
31 | 'error'
32 | ensure
33 | 'ensure'
34 | end
35 | end
36 |
37 | some_method(1) #=> "OK"
38 | some_method(0) #=> "error"
39 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_05.rb:
--------------------------------------------------------------------------------
1 | # 例外が発生しない場合
2 | 1 / 1 rescue 0 #=> 1
3 |
4 | # 例外が発生する場合
5 | 1 / 0 rescue 0 #=> 0
6 |
7 | # ----------------------------------------
8 |
9 | require 'date'
10 |
11 | def to_date(string)
12 | begin
13 | # 文字列のパースを試みる
14 | Date.parse(string)
15 | rescue ArgumentError
16 | # パースできない場合はnilを返す
17 | nil
18 | end
19 | end
20 |
21 | # パース可能な文字列を渡す
22 | to_date('2021-01-01') #=> #
23 |
24 | # パース不可能な文字列を渡す
25 | to_date('abcdef') #=> nil
26 |
27 | # ----------------------------------------
28 |
29 | def to_date(string)
30 | Date.parse(string) rescue nil
31 | end
32 |
33 | to_date('2021-01-01') #=> #
34 | to_date('abcdef') #=> nil
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_06.rb:
--------------------------------------------------------------------------------
1 | # rescue節で例外情報を変数に格納する
2 | begin
3 | 1 / 0
4 | rescue => e
5 | puts "#{e.class} #{e.message}"
6 | puts e.backtrace
7 | end
8 | #=> ZeroDivisionError divided by 0
9 | # (バックトレースは省略)
10 |
11 | # 組み込み変数に格納された例外情報を使う
12 | begin
13 | 1 / 0
14 | rescue
15 | puts "#{$!.class} #{$!.message}"
16 | puts $@
17 | end
18 | #=> ZeroDivisionError divided by 0
19 | # (バックトレースは省略)
20 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_08.rb:
--------------------------------------------------------------------------------
1 | def fizz_buzz(n)
2 | if n % 15 == 0
3 | 'Fizz Buzz'
4 | elsif n % 3 == 0
5 | 'Fizz'
6 | elsif n % 5 == 0
7 | 'Buzz'
8 | else
9 | n.to_s
10 | end
11 | rescue => e
12 | # 発生した例外をログやメールに残す(ここはputsで代用)
13 | puts "[LOG] エラーが発生しました: #{e.class} #{e.message}"
14 | # 捕捉した例外を再度発生させ、プログラム自体は異常終了させる
15 | raise
16 | end
17 |
18 | fizz_buzz(nil)
19 | #=> [LOG] エラーが発生しました: NoMethodError undefined method `%' for nil:NilClass
20 | # undefined method `%' for nil:NilClass (NoMethodError)
21 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/code_09_06_09.rb:
--------------------------------------------------------------------------------
1 | class NoCountryError < StandardError
2 | # 独自の例外クラス名を与えるだけで、機能的にはStandardErrorと同じにするため、実装コードは特に書かない
3 | end
4 |
5 | def currency_of(country)
6 | case country
7 | when :japan
8 | 'yen'
9 | when :us
10 | 'dollar'
11 | when :india
12 | 'rupee'
13 | else
14 | # 独自に定義したNoCountryErrorを発生させる
15 | raise NoCountryError, "無効な国名です。#{country}"
16 | end
17 | end
18 |
19 | currency_of(:italy) #=> 無効な国名です。italy (NoCountryError)
20 |
21 | # ----------------------------------------
22 |
23 | class NoCountryError < StandardError
24 | # 国名を属性として取得できるようにする
25 | attr_reader :country
26 |
27 | def initialize(message, country)
28 | @country = country
29 | super("#{message} #{country}")
30 | end
31 | end
32 |
33 | def currency_of(country)
34 | case country
35 | when :japan
36 | 'yen'
37 | when :us
38 | 'dollar'
39 | when :india
40 | 'rupee'
41 | else
42 | # NoCountryErrorを発生させる
43 | raise NoCountryError.new('無効な国名です。', country)
44 | end
45 | end
46 |
47 | begin
48 | currency_of(:italy)
49 | rescue NoCountryError => e
50 | # エラーメッセージと国名を出力する
51 | puts e.message
52 | puts e.country
53 | end
54 | #=> 無効な国名です。 italy
55 | # italy
56 |
--------------------------------------------------------------------------------
/sample-codes/chapter_09/column_09_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:ensure節ではreturnを使わない
2 |
3 | def some_method(n)
4 | begin
5 | 1 / n
6 | 'OK'
7 | rescue => e
8 | 'error'
9 | ensure
10 | # ensure節にreturnを書く
11 | return 'ensure'
12 | end
13 | end
14 |
15 | some_method(1) #=> "ensure"
16 | some_method(0) #=> "ensure"
17 |
18 | # ----------------------------------------
19 |
20 | def some_method(n)
21 | begin
22 | 1 / n
23 | 'OK'
24 | ensure
25 | # rescue節なしでensure節にreturnを書く(良くない例)
26 | return 'ensure'
27 | end
28 | end
29 |
30 | some_method(1) #=> "ensure"
31 |
32 | # ZeroDivisionErrorが発生して異常終了しそうだが、正常終了してしまう
33 | some_method(0) #=> "ensure"
34 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_03_01.rb:
--------------------------------------------------------------------------------
1 | # "Hello!"という文字列を返すProcオブジェクトを作成する
2 | hello_proc = Proc.new do
3 | 'Hello!'
4 | end
5 |
6 | # do ... endのかわりに{}を使ってもよい
7 | hello_proc = Proc.new { 'Hello!' }
8 |
9 | # ----------------------------------------
10 |
11 | # "Hello!"という文字列を返すProcオブジェクトを作成する
12 | hello_proc = Proc.new { 'Hello!' }
13 | # Procオブジェクトを実行する(文字列が返る)
14 | hello_proc.call #=> "Hello!"
15 |
16 | # ----------------------------------------
17 |
18 | add_proc = Proc.new { |a, b| a + b }
19 | add_proc.call(10, 20) #=> 30
20 |
21 | # ----------------------------------------
22 |
23 | add_proc = Proc.new { |a = 0, b = 0| a + b }
24 | add_proc.call #=> 0
25 | add_proc.call(10) #=> 10
26 | add_proc.call(10, 20) #=> 30
27 |
28 | # ----------------------------------------
29 |
30 | # Proc.newのかわりにprocメソッドを使う
31 | add_proc = proc { |a, b| a + b }
32 |
33 | # ----------------------------------------
34 |
35 | # RubyでProcオブジェクトを作成し、その処理を呼び出す
36 | add_proc = Proc.new { |a, b| a + b }
37 | add_proc.call(10, 20) #=> 30
38 |
39 | # ----------------------------------------
40 |
41 | < a + b
44 | addProc(10, 20) //=> 30
45 | JavaScript
46 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_03_02.rb:
--------------------------------------------------------------------------------
1 | def greet(&block)
2 | puts 'おはよう'
3 | text = block.call('こんにちは')
4 | puts text
5 | puts 'こんばんは'
6 | end
7 |
8 | # ----------------------------------------
9 |
10 | def greet(&block)
11 | # blockのクラス名を表示する
12 | puts block.class
13 |
14 | puts 'おはよう'
15 | text = block.call('こんにちは')
16 | puts text
17 | puts 'こんばんは'
18 | end
19 |
20 | greet do |text|
21 | text * 2
22 | end
23 | #=> Proc
24 | # おはよう
25 | # こんにちはこんにちは
26 | # こんばんは
27 |
28 | # ----------------------------------------
29 |
30 | def greet(&block)
31 | puts 'おはよう'
32 | text = block.call('こんにちは')
33 | puts text
34 | puts 'こんばんは'
35 | end
36 |
37 | # Procオブジェクトを作成し、それをブロックの代わりとしてgreetメソッドに渡す
38 | repeat_proc = proc { |text| text * 2 }
39 | greet(&repeat_proc)
40 | #=> おはよう
41 | # こんにちはこんにちは
42 | # こんばんは
43 |
44 | # ----------------------------------------
45 |
46 | # &なしで呼び出すと普通の引数を1つ渡したことになる
47 | greet(repeat_proc) #=> wrong number of arguments (given 1, expected 0) (ArgumentError)
48 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_03_03.rb:
--------------------------------------------------------------------------------
1 | # ブロックではなく、1個のProcオブジェクトを引数として受け取る
2 | def greet(arrange_proc)
3 | puts 'おはよう'
4 | text = arrange_proc.call('こんにちは')
5 | puts text
6 | puts 'こんばんは'
7 | end
8 |
9 | # Procオブジェクトを普通の引数としてgreetメソッドに渡す(&を付けない)
10 | repeat_proc = proc { |text| text * 2 }
11 | greet(repeat_proc)
12 | #=> おはよう
13 | # こんにちはこんにちは
14 | # こんばんは
15 |
16 | # ----------------------------------------
17 |
18 | # 3種類のProcオブジェクトを受け取り、それぞれのあいさつ文字列に適用するgreetメソッド
19 | def greet(proc_1, proc_2, proc_3)
20 | puts proc_1.call('おはよう')
21 | puts proc_2.call('こんにちは')
22 | puts proc_3.call('こんばんは')
23 | end
24 |
25 | # greetメソッドに渡すProcオブジェクトを用意する
26 | shuffle_proc = proc { |text| text.chars.shuffle.join }
27 | repeat_proc = proc { |text| text * 2 }
28 | question_proc = proc { |text| "#{text}?" }
29 |
30 | # 3種類のProcオブジェクトをgreetメソッドに渡す
31 | greet(shuffle_proc, repeat_proc, question_proc)
32 | #=> はおうよ
33 | # こんにちはこんにちは
34 | # こんばんは?
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_03_05.rb:
--------------------------------------------------------------------------------
1 | # Proc.newの場合
2 | add_proc = Proc.new { |a, b| a + b }
3 | add_proc.class #=> Proc
4 | add_proc.lambda? #=> false
5 |
6 | # ラムダの場合
7 | add_lambda = ->(a, b) { a + b }
8 | add_lambda.class #=> Proc
9 | add_lambda.lambda? #=> true
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_04_00.rb:
--------------------------------------------------------------------------------
1 | # エフェクトなし
2 | synth = WordSynth.new
3 | synth.play('Ruby is fun!') #=> "Ruby is fun!"
4 |
5 | # リバースエフェクトを適用
6 | synth = WordSynth.new
7 | synth.add_effect(Effects.reverse)
8 | synth.play('Ruby is fun!') #=> "ybuR si !nuf"
9 |
10 | # 全エフェクトを一度に適用
11 | synth = WordSynth.new
12 | synth.add_effect(Effects.echo(2))
13 | synth.add_effect(Effects.loud(3))
14 | synth.add_effect(Effects.reverse)
15 | synth.play('Ruby is fun!') #=> "!!!YYBBUURR !!!SSII !!!!!NNUUFF"
16 |
17 | # ----------------------------------------
18 |
19 | class WordSynth
20 | def initialize
21 | @effects = []
22 | end
23 |
24 | def add_effect(effect)
25 | @effects << effect
26 | end
27 |
28 | def play(original_words)
29 | words = original_words
30 | @effects.each do |effect|
31 | # 効果を適用する
32 | words = effect.call(words)
33 | end
34 | words
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_04_01.rb:
--------------------------------------------------------------------------------
1 | module Effects
2 | def self.reverse
3 | # Procオブジェクト(ラムダ)をメソッドの戻り値にする
4 | ->(words) do
5 | # スペースで分解 > 逆順に並び替え > スペースで連結
6 | words.split(' ').map(&:reverse).join(' ')
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_04_03.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require_relative '../lib/effects'
3 |
4 | class EffectsTest < Minitest::Test
5 | def test_reverse
6 | # とりあえずモジュールが参照できることを確認する
7 | assert Effects
8 | end
9 | end
10 |
11 | # ----------------------------------------
12 |
13 | require 'minitest/autorun'
14 | require_relative '../lib/word_synth'
15 | require_relative '../lib/effects'
16 |
17 | class WordSynthTest < Minitest::Test
18 | def test_play
19 | # とりあえずクラスとモジュールが参照できることを確認する
20 | assert WordSynth
21 | assert Effects
22 | end
23 | end
24 |
25 | # ----------------------------------------
26 |
27 | module Effects
28 | def self.reverse
29 | # 実装はあとで
30 | end
31 | end
32 |
33 | # ----------------------------------------
34 |
35 | class WordSynth
36 | def play(original_words)
37 | # 実装はあとで
38 | end
39 | end
40 |
41 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_04_04.rb:
--------------------------------------------------------------------------------
1 | class EffectsTest < Minitest::Test
2 | def test_reverse
3 | effect = Effects.reverse
4 | assert_equal 'ybuR si !nuf', effect.call('Ruby is fun!')
5 | end
6 | end
7 |
8 | # ----------------------------------------
9 |
10 | module Effects
11 | def self.reverse
12 | ->(words) do
13 | words.split(' ').map(&:reverse).join(' ')
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_04_05.rb:
--------------------------------------------------------------------------------
1 | class EffectsTest < Minitest::Test
2 | # 省略
3 |
4 | def test_echo
5 | effect = Effects.echo(2)
6 | assert_equal 'RRuubbyy iiss ffuunn!!', effect.call('Ruby is fun!')
7 |
8 | effect = Effects.echo(3)
9 | assert_equal 'RRRuuubbbyyy iiisss fffuuunnn!!!', effect.call('Ruby is fun!')
10 | end
11 | end
12 |
13 | # ----------------------------------------
14 |
15 | module Effects
16 | # 省略
17 |
18 | def self.echo(rate)
19 | ->(words) do
20 | # スペースならそのまま返す
21 | # スペース以外ならその文字を指定された回数だけ繰り返す
22 | words.each_char.map { |c| c == ' ' ? c : c * rate }.join
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_04_06.rb:
--------------------------------------------------------------------------------
1 | class EffectsTest < Minitest::Test
2 | # 省略
3 |
4 | def test_loud
5 | effect = Effects.loud(2)
6 | assert_equal 'RUBY!! IS!! FUN!!!', effect.call('Ruby is fun!')
7 |
8 | effect = Effects.loud(3)
9 | assert_equal 'RUBY!!! IS!!! FUN!!!!', effect.call('Ruby is fun!')
10 | end
11 | end
12 |
13 | # ----------------------------------------
14 |
15 | module Effects
16 | # 省略
17 |
18 | def self.loud(level)
19 | ->(words) do
20 | # スペースで分割 > 大文字変換と"!"の付与 > スペースで連結
21 | words.split(' ').map { |word| word.upcase + '!' * level }.join(' ')
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_05_01.rb:
--------------------------------------------------------------------------------
1 | add_proc = Proc.new { |a, b| a + b }
2 |
3 | # callメソッドを使う
4 | add_proc.call(10, 20) #=> 30
5 | # yieldメソッドを使う
6 | add_proc.yield(10, 20) #=> 30
7 | # .()を使う
8 | add_proc.(10, 20) #=> 30
9 | # []を使う
10 | add_proc[10, 20] #=> 30
11 |
12 | # ----------------------------------------
13 |
14 | add_proc === [10, 20] #=> 30
15 |
16 | # ----------------------------------------
17 |
18 | def judge(age)
19 | # 20より大きければtrueを返すProcオブジェクト
20 | adult = proc { |n| n > 20 }
21 | # 20より小さければtrueを返すProcオブジェクト
22 | child = proc { |n| n < 20 }
23 |
24 | case age
25 | when adult
26 | '大人です'
27 | when child
28 | '子どもです'
29 | else
30 | 'はたちです'
31 | end
32 | end
33 |
34 | judge(25) #=> "大人です"
35 | judge(18) #=> "子どもです"
36 | judge(20) #=> "はたちです"
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/code_10_05_03.rb:
--------------------------------------------------------------------------------
1 | def generate_proc(array)
2 | counter = 0
3 | # Procオブジェクトをメソッドの戻り値とする
4 | Proc.new do
5 | # ローカル変数のcounterを加算する
6 | counter += 10
7 | # メソッド引数のarrayにcounterの値を追加する
8 | array << counter
9 | end
10 | end
11 |
12 | # ----------------------------------------
13 |
14 | values = []
15 | sample_proc = generate_proc(values)
16 | values #=> []
17 |
18 | # ----------------------------------------
19 |
20 | # Procオブジェクトを実行するとgenerate_procメソッドの引数だったvaluesの中身が書き換えられる
21 | sample_proc.call
22 | values #=> [10]
23 |
24 | # generate_procメソッド内のローカル変数counterも加算され続ける
25 | sample_proc.call
26 | values #=> [10, 20]
27 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/column_10_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:メソッドチェーンを使ってコードを書く
2 |
3 | def self.loud(level)
4 | ->(words) do
5 | words.split(' ').map { |word| word.upcase + '!' * level }.join(' ')
6 | end
7 | end
8 |
9 | # ----------------------------------------
10 |
11 | def self.loud(level)
12 | ->(words) do
13 | words
14 | .split(' ')
15 | .map { |word| word.upcase + '!' * level }
16 | .join(' ')
17 | end
18 | end
19 |
20 | # ----------------------------------------
21 |
22 | def self.loud(level)
23 | ->(words) do
24 | # 行末にドットを付けて改行するメソッドチェーンの例
25 | words.
26 | split(' ').
27 | map { |word| word.upcase + '!' * level }.
28 | join(' ')
29 | end
30 | end
31 |
32 | # ----------------------------------------
33 |
34 | def self.loud(level)
35 | ->(words) do
36 | # Ruby 2.7からはメソッドチェーンの行間にコメントが挟める
37 | words
38 | # 半角スペースで文字列を分割する
39 | .split(' ')
40 | # 各文字列を大文字にして"!"を指定された回数分付与する
41 | .map { |word| word.upcase + '!' * level }
42 | # 半角スペースで各文字列を連結する
43 | .join(' ')
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/column_10_02.rb:
--------------------------------------------------------------------------------
1 | # コラム:injectメソッドを使ったplayメソッドのリファクタリング
2 |
3 | numbers = [1, 2, 3, 4]
4 | sum = numbers.inject(0) { |result, n| result + n }
5 | sum #=> 10
6 |
7 | # ----------------------------------------
8 |
9 | ((((0 + 1) + 2) + 3) + 4)
10 |
11 | # ----------------------------------------
12 |
13 | def play(original_words)
14 | @effects.inject(original_words) do |words, effect|
15 | effect.call(words)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_10/column_10_03.rb:
--------------------------------------------------------------------------------
1 | # コラム:で、yieldやProcってどこで使うの?
2 |
3 | class Guitar < ApplicationRecord
4 | scope :gold, -> { where(color: 'gold') }
5 | end
6 |
7 | # ----------------------------------------
8 |
9 | # 処理の開始時と終了時にログを記録する共通メソッド
10 | # (ここでは実際にログに記録する代わりにputsで代用)
11 | def with_logging(name)
12 | puts "[LOG] START: #{name}"
13 | ret = yield
14 | puts "[LOG] END: #{name}"
15 | ret
16 | end
17 |
18 | # ----------------------------------------
19 |
20 | # ログ付きで数字の加算を実行する
21 | answer = with_logging('add numbers') do
22 | 1 + 2
23 | end
24 | #=> [LOG] START: add numbers
25 | # [LOG] END: add numbers
26 | answer
27 | #=> 3
28 |
29 | # ----------------------------------------
30 |
31 | # ログ付きでmapメソッドを実行する
32 | numbers = with_logging('Array#map') do
33 | [1, 2, 3].map { |n| n * 10 }
34 | end
35 | #=> [LOG] START: Array#map
36 | # [LOG] END: Array#map
37 | numbers
38 | #=> [10, 20, 30]
39 |
--------------------------------------------------------------------------------
/sample-codes/chapter_11/code_11_01_01.rb:
--------------------------------------------------------------------------------
1 | < name, age: 18.. => age}
10 | # => 変数名 の形式でマッチしたオブジェクトを変数に代入できる(asパターン)
11 | "name=#{name}, age=#{age}"
12 | end
13 | #=> "name=Alice, age=20"
14 |
15 | # ----------------------------------------
16 |
17 | case {name: 'Alice', age: 20, gender: :female}
18 | in {name: String, age: 18..} => person
19 | # マッチしたハッシュ全体を変数personに代入できる
20 | "person=#{person}"
21 | end
22 | #=> "person={:name=>\"Alice\", :age=>20, :gender=>:female}"
23 |
--------------------------------------------------------------------------------
/sample-codes/chapter_11/code_11_03_07.rb:
--------------------------------------------------------------------------------
1 | case [1, 2, 3, 4, 5]
2 | in [first, *]
3 | "first=#{first}"
4 | end
5 | #=> "first=1"
6 |
7 | case [1, 2, 3, 4, 5]
8 | in [*, last]
9 | "last=#{last}"
10 | end
11 | #=> "last=5"
12 |
13 | # ----------------------------------------
14 |
15 | case [13, 11, 9, 6, 12, 10, 15, 5, 7, 14]
16 | in [*, 10.. => a, 10.. => b, 10.. => c, *]
17 | # findパターンで配列のなから10以上の整数が3つ連続する部分を抜き出す
18 | # 3つの整数はそれぞれ変数a, b, cに代入される
19 | "a=#{a}, b=#{b}, c=#{c}"
20 | end
21 | #=> "a=12, b=10, c=15"
22 |
23 | # ----------------------------------------
24 |
25 | # FindパターンはRuby 3.0では実験的機能であるため警告が表示される
26 | case [1, 2, 3]
27 | in [*, n, *]
28 | # ...
29 | end
30 | #=> warning: Find pattern is experimental, and the behavior may change in future versions of Ruby!
31 |
--------------------------------------------------------------------------------
/sample-codes/chapter_11/code_11_04_00.rb:
--------------------------------------------------------------------------------
1 | < duration}
18 | # asパターンで:durationの値を変数durationに代入する
19 | "[WARN] request_id=#{request_id}, path=#{path}, duration=#{duration}"
20 | in {request_id:, path:}
21 | "[OK] request_id=#{request_id}, path=#{path}"
22 | end
23 | end.join("\n")
24 |
--------------------------------------------------------------------------------
/sample-codes/chapter_11/code_11_04_06.rb:
--------------------------------------------------------------------------------
1 | log_data.map do |log|
2 | # 注:values_atメソッドは指定したキーに対応するハッシュの値を配列として返すメソッド
3 | # 返ってきた値は多重代入のテクニック(2.2.8項参照)を使って複数の変数に同時に代入する
4 | request_id, path, status, duration, error =
5 | log.values_at(:request_id, :path, :status, :duration, :error)
6 |
7 | if status == 404 || status == 500
8 | "[ERROR] request_id=#{request_id}, path=#{path}, status=#{status}, error=#{error}"
9 | elsif duration >= 1000
10 | "[WARN] request_id=#{request_id}, path=#{path}, duration=#{duration}"
11 | else
12 | "[OK] request_id=#{request_id}, path=#{path}"
13 | end
14 | end.join("\n")
15 |
--------------------------------------------------------------------------------
/sample-codes/chapter_11/code_11_05_01.rb:
--------------------------------------------------------------------------------
1 | data = [[1, 2, 3], [5, 4, 6]]
2 | data.each do |numbers|
3 | case numbers
4 | in [a, b, c] if b == a + 1 && c == b + 1
5 | # 要素が3つの配列かつ、3つの連続した整数であればマッチ
6 | # 値が連続しているかどうかはガード式で判定する
7 | puts "matched: #{numbers}"
8 | else
9 | puts "not matched: #{numbers}"
10 | end
11 | end
12 | #=> matched: [1, 2, 3]
13 | # not matched: [5, 4, 6]
14 |
15 | # ----------------------------------------
16 |
17 | # n, 2のパターンは1, 2にマッチする。ガード条件も真となる(マッチ成功)
18 | case [1, 2, 3, 2, 1]
19 | in [*, n, 2, *] if n == 1
20 | "matched: #{n}"
21 | else
22 | 'not matched'
23 | end
24 | #=> "matched: 1"
25 |
26 | # n, 2のパターンは1, 2にマッチするが、ガード条件は偽となる
27 | # データ上、3, 2にもマッチするが、再検索は行われない(マッチ失敗)
28 | case [1, 2, 3, 2, 1]
29 | in [*, n, 2, *] if n == 3
30 | "matched: #{n}"
31 | else
32 | 'not matched'
33 | end
34 | #=> "not matched"
35 |
--------------------------------------------------------------------------------
/sample-codes/chapter_11/code_11_05_03.rb:
--------------------------------------------------------------------------------
1 | # 先にローカル変数のnameを定義しておく
2 | name = 'Alice'
3 |
4 | # パターンマッチを実行する
5 | case {name: 'Bob', age: 25}
6 | in {name:, age:}
7 | "name=#{name}, age=#{age}"
8 | end
9 | #=> "name=Bob, age=25"
10 |
11 | # 変数nameはパターンマッチによって上書きされる
12 | name #=> "Bob"
13 |
14 | # パターンマッチを抜けてもパターンマッチ内で代入された変数は使用可能
15 | age #=> 25
16 |
17 | # ----------------------------------------
18 |
19 | # (望ましくないコード例)
20 | case {name: 'Bob', age: 25}
21 | in {name:, age: 30.. => age}
22 | # :ageの条件がマッチしないのでここは実行されない
23 | else
24 | # 上のin節で変数の代入が完了しており、ここで変数nameやageが使えてしまうが、
25 | # 未定義の挙動であるため、こうしたコードを書いてはいけない
26 | "not matched: name=#{name}, age=#{age}"
27 | end
28 | #=> "not matched: name=Bob, age=25"
29 |
--------------------------------------------------------------------------------
/sample-codes/chapter_11/column_11_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:in節に書くのはあくまで「パターン」
2 |
3 | # これは配列っぽい
4 | in [1, 2, 3]
5 |
6 | # これはハッシュっぽい
7 | in {x: 10, y: 20}
8 |
9 | # ----------------------------------------
10 |
11 | # パターンとしては有効だが配列リテラルとしては無効(なのでこれは配列ではなくパターン)
12 | in 1, 2, 3
13 |
14 | # パターンとしては有効だがハッシュリテラルとしては無効(なのでこれはハッシュではなくパターン)
15 | in x:, y:
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_02_00.rb:
--------------------------------------------------------------------------------
1 | require_relative 'ticket'
2 | require_relative 'gate'
3 |
4 | juso = Gate.new(:juso)
5 | mikuni = Gate.new(:mikuni)
6 | ticket = Ticket.new(160)
7 |
8 | juso.enter(ticket)
9 | puts mikuni.exit(ticket)
10 |
11 | # ----------------------------------------
12 |
13 | def calc_fare(ticket)
14 | from = STATIONS.index(ticket.stamped_at)
15 | to = STATIONS.index(@name)
16 | distance = to - from
17 | FARES[distanse - 1]
18 | end
19 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_03_06.rb:
--------------------------------------------------------------------------------
1 | def factorial(n)
2 | # 終了条件を書き忘れたため永遠に再帰呼び出しが発生する
3 | n * factorial(n - 1)
4 |
5 | # 本来であれば次のような条件分岐を作って終了させる必要がある
6 | # n == 0 ? 1 : n * factorial(n - 1)
7 | end
8 |
9 | factorial(5)
10 | #=> stack level too deep (SystemStackError)
11 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_03_08.rb:
--------------------------------------------------------------------------------
1 | # 以下のコードはputs({ foo: 1, bar: 2 })のように丸カッコが必要
2 | puts { foo: 1, bar: 2 }
3 | #=> syntax error, unexpected ':', expecting '}' (SyntaxError)
4 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_04_01.rb:
--------------------------------------------------------------------------------
1 | def to_hex(r, g, b)
2 | # 変数(ブロックパラメータ)の中身をターミナルに出力する
3 | [r, g, b].sum('#') do |n|
4 | # 変数(ブロック引数)の中身をターミナルに出力する
5 | puts hex
6 | hex + n.to_s(16).rjust(2, '0')
7 | end
8 | end
9 |
10 | # ----------------------------------------
11 |
12 | def greet(country)
13 | # greetメソッドが呼ばれたことを確認
14 | puts 'greet start.'
15 | return 'countryを入力してください' if country.nil?
16 |
17 | if country == 'japan'
18 | # 真の分岐に入ったことを確認
19 | puts 'japan'
20 | 'こんにちは'
21 | else
22 | # 偽の分岐に入ったことを確認
23 | puts 'other'
24 | 'hello'
25 | end
26 | end
27 |
28 | # ----------------------------------------
29 |
30 | def calc_fare(ticket)
31 | from = STATIONS.index(ticket.stamped_at)
32 | to = STATIONS.index(@name)
33 | # to - fromの結果をターミナルに出力しつつ、変数distanceに代入する
34 | distance = p to - from
35 | FARES[distance - 1]
36 | end
37 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_04_02.rb:
--------------------------------------------------------------------------------
1 | # ブロック引数のsには、tapメソッドのレシーバ(ここでは文字列の"hello")が入る
2 | a = 'hello'.tap { |s| puts "<<#{s}>>" }
3 | #=> <>
4 |
5 | # tapメソッドはレシーバをそのまま返す(つまり a = 'hello' と同じ結果になる)
6 | a #=> "hello"
7 |
8 | # ----------------------------------------
9 |
10 | # メソッドチェーンを使っているこのコードをデバッグしたい
11 | '#043c78'.scan(/\w\w/).map(&:hex)
12 |
13 | # tapメソッドを使って、scanメソッドの戻り値をターミナルに表示する
14 | '#043c78'.scan(/\w\w/).tap { |rgb| p rgb }.map(&:hex)
15 | #=> ["04", "3c", "78"]
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_04_03.rb:
--------------------------------------------------------------------------------
1 | class User < ApplicationRecord
2 | def facebook_username
3 | info = facebook_auth.auth_info.info
4 | # ログに変数info.nameの値を出力する
5 | logger.debug "[DEBUG] info.name : #{info.name}"
6 | info.name
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_04_04.rb:
--------------------------------------------------------------------------------
1 | require 'debug'
2 |
3 | def fizz_buzz(n)
4 | binding.break
5 | if n % 15 == 0
6 | 'Fizz Buzz'
7 | elsif n % 3 == 0
8 | 'Fizz'
9 | elsif n % 5 == 0
10 | 'Buzz'
11 | else
12 | n.to_s
13 | end
14 | end
15 |
16 | # ----------------------------------------
17 |
18 | # Ruby 2.6または2.7の場合
19 | gem 'debug'
20 | require 'debug'
21 |
--------------------------------------------------------------------------------
/sample-codes/chapter_12/code_12_05_05.rb:
--------------------------------------------------------------------------------
1 | # underscoreメソッドは文字列をスネークケースに変換するメソッド
2 | 'OrderItem'.underscore #=> "order_item"
3 |
4 | # このメソッドが定義されているのはactivesupport gemのinflections.rbの143行目
5 | 'OrderItem'.method(:underscore).source_location
6 | #=> ["/(gemがインストールされているパス)/activesupport-6.1.3.1/lib/active_support/core_ext/string/inflections.rb", 143]
7 |
8 | # ----------------------------------------
9 |
10 | # upcaseメソッドは組み込みライブラリのメソッド
11 | 'HelloWorld'.method(:upcase).source_location #=> nil
12 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_02_00.rb:
--------------------------------------------------------------------------------
1 | # Timeクラスで日時を表すオブジェクトを作成する
2 | time = Time.new(2021, 1, 31, 23, 30, 59) #=> 2021-01-31 23:30:59 +0900
3 |
4 | # dateライブラリをrequireするとDateクラスとDateTimeクラスが使えるようになる
5 | require 'date'
6 |
7 | # Dateクラスで日付を表すオブジェクトを作成する
8 | date = Date.new(2021, 1, 31) #=> #
9 |
10 | # DateTimeクラスで日時を表すオブジェクトを作成する(非推奨)
11 | date_time = DateTime.new(2021, 1, 31, 23, 30, 59)
12 | #=> #
13 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_03_00.rb:
--------------------------------------------------------------------------------
1 | # カレントディレクトリに"secret.txt"が存在するか?
2 | File.exist?('./secret.txt')
3 |
4 | # カレントディレクトリに"secret_folder"が存在するか?
5 | Dir.exist?('./secret_folder')
6 |
7 | # ----------------------------------------
8 |
9 | # libディレクトリにあるfizz_buzz.rbの行数をターミナルに表示する
10 | File.open('./lib/fizz_buzz.rb', 'r') do |f|
11 | puts f.readlines.count
12 | end
13 |
14 | # libディレクトリにhello_world.txtを作成して文字を書き込む
15 | File.open('./lib/hello_world.txt', 'w') do |f|
16 | f.puts 'Hello, world!'
17 | end
18 |
19 | # ----------------------------------------
20 |
21 | require 'fileutils'
22 |
23 | # libディレクトリのhello_world.txtをhello_world.rbに移動(リネーム)する
24 | FileUtils.mv('./lib/hello_world.txt', './lib/hello_world.rb')
25 |
26 | # ----------------------------------------
27 |
28 | require 'pathname'
29 |
30 | # カレントディレクトリ配下にあるlibディレクトリを表すオブジェクトを作る
31 | lib = Pathname.new('./lib')
32 |
33 | # ファイルか?
34 | lib.file? #=> false
35 |
36 | # ディレクトリか?
37 | lib.directory? #=> true
38 |
39 | # libディレクトリ配下にあるsample.txtへのパス文字列を作る
40 | # (区切り文字のスラッシュは自動的に付与される)
41 | lib.join('sample.txt').to_s #=> "./lib/sample.txt"
42 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_04_01.rb:
--------------------------------------------------------------------------------
1 | require 'csv'
2 |
3 | # CSVファイルの出力
4 | CSV.open('./lib/sample.csv', 'w') do |csv|
5 | # ヘッダ行を出力する
6 | csv << ['Name', 'Email', 'Age']
7 | # 明細行を出力する
8 | csv << ['Alice', 'alice@example.com', 20]
9 | end
10 |
11 | # タブ区切りのCSV(TSV)ファイルを読み込む
12 | CSV.foreach('./lib/sample.tsv', col_sep: "\t") do |row|
13 | # 各行について、1列目から3列目の値をターミナルに表示する
14 | puts "1: #{row[0]}, 2: #{row[1]}, 3: #{row[2]}"
15 | end
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_04_02.rb:
--------------------------------------------------------------------------------
1 | # jsonライブラリをrequireすると配列やハッシュでto_jsonメソッドが使えるようになる
2 | require 'json'
3 |
4 | user = { name: 'Alice', email: 'alice@example.com', age: 20 }
5 |
6 | # ハッシュをJSON形式の文字列に変換する(Rubyのハッシュに似ているがこれはJSON形式)
7 | user_json = user.to_json
8 | puts user_json #=> {"name":"Alice","email":"alice@example.com","age":20}
9 |
10 | # JSON文字列をパースしてハッシュに変換する(デフォルトではキーは文字列になる)
11 | JSON.parse(user_json)
12 | #=> {"name"=>"Alice", "email"=>"alice@example.com", "age"=>20}
13 |
14 | # symbolize_namesオプションを指定するとキーがシンボルになる
15 | JSON.parse(user_json, symbolize_names: true)
16 | #=> {:name=>"Alice", :email=>"alice@example.com", :age=>20}
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_04_03.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 | # YAML形式のテキストデータを用意する
4 | yaml = < {"alice"=>{"name"=>"Alice", "email"=>"alice@example.com", "age"=>20}}
13 |
14 | # ハッシュに新しい要素を追加する
15 | users['alice']['gender'] = :female
16 |
17 | # ハッシュからYAMLテキストに変換する
18 | puts YAML.dump(users)
19 | #=> ---
20 | # alice:
21 | # name: Alice
22 | # email: alice@example.com
23 | # age: 20
24 | # gender: :female
25 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_05_00.rb:
--------------------------------------------------------------------------------
1 | # 環境変数MY_NAMEの値を取得する
2 | name = ENV['MY_NAME']
3 |
4 | # ----------------------------------------
5 |
6 | # 1番目と2番目の起動時引数を取得する
7 | email = ARGV[0]
8 | age = ARGV[1]
9 |
10 | # ----------------------------------------
11 |
12 | name = ENV['MY_NAME']
13 | email = ARGV[0]
14 | age = ARGV[1]
15 |
16 | puts "name: #{name}, email: #{email}, age: #{age}"
17 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_05_01.rb:
--------------------------------------------------------------------------------
1 | STDOUT #=> #>
2 | RUBY_VERSION #=> "3.0.1"
3 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_06_00.rb:
--------------------------------------------------------------------------------
1 | # Ruby 3.0では警告対象だが、そのままでは警告が出ない
2 | lambda(&proc{})
3 |
4 | # ----------------------------------------
5 |
6 | # -W:deprecatedオプションを付けてrubyコマンドやirbを実行すると警告が出力される
7 | lambda(&proc{})
8 | #=> warning: lambda without a literal block is deprecated; use the proc without lambda instead
9 |
10 | # ----------------------------------------
11 |
12 | # 非推奨警告を出力するようtrueをセット
13 | Warning[:deprecated] = true
14 |
15 | # 非推奨機能を使うと警告が出力される
16 | lambda(&proc{})
17 | #=> warning: lambda without a literal block is deprecated; use the proc without lambda instead
18 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_07_00.rb:
--------------------------------------------------------------------------------
1 | # 文字列にRubyのコードを格納する
2 | code = '[1, 2, 3].map { |n| n * 10 }'
3 |
4 | # evalメソッドに渡すと、文字列がRubyのコードとして実行される
5 | eval(code) #=> [10, 20, 30]
6 |
7 | # ----------------------------------------
8 |
9 | # OSのcatコマンドでテキストファイルの中身を表示する
10 | puts `cat lib/fizz_buzz.rb`
11 | #=> def fizz_buzz(n)
12 | # if n % 15 == 0
13 | # 'Fizz Buzz'
14 | # 以下省略
15 |
16 | # ----------------------------------------
17 |
18 | puts `type lib\\fizz_buzz.rb`
19 |
20 | # ----------------------------------------
21 |
22 | puts %x{cat lib/fizz_buzz.rb}
23 |
24 | # ----------------------------------------
25 |
26 | str = 'a,b,c'
27 |
28 | # str.upcaseを呼ぶのと同じ
29 | str.send(:upcase) #=> "A,B,C"
30 |
31 | # str.split(',')を呼ぶのと同じ
32 | str.send(:split, ',') #=> ["a", "b", "c"]
33 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_08_01.rb:
--------------------------------------------------------------------------------
1 | # hello_worldという名前のタスクを定義する
2 | task :hello_world do
3 | # ブロックの中がタスクとして実行される処理になる
4 | puts 'Hello, world!'
5 | end
6 |
7 | # ----------------------------------------
8 |
9 | # タスクの説明を入れる
10 | desc 'テスト用のタスクです。'
11 | task :hello_world do
12 | puts 'Hello, world!'
13 | end
14 |
15 | # ----------------------------------------
16 |
17 | # 名前空間を使ってタスクをグループ分けする
18 | namespace :my_tasks do
19 | desc 'テスト用のタスクです。'
20 | task :hello_world do
21 | puts 'Hello, world!'
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_08_02.rb:
--------------------------------------------------------------------------------
1 | require 'rake/testtask'
2 |
3 | Rake::TestTask.new do |t|
4 | t.pattern = 'test/**/*_test.rb'
5 | end
6 |
7 | task default: :test
8 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_09_01.rb:
--------------------------------------------------------------------------------
1 | require 'faker'
2 | Faker::Name.name #=> "Torrey Hodkiewicz"
3 | Faker::Name.name #=> "Magnus Glover"
4 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_09_02.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6 |
7 | # gem "rails"
8 |
9 | # ----------------------------------------
10 |
11 | # frozen_string_literal: true
12 |
13 | source "https://rubygems.org"
14 |
15 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
16 |
17 | gem 'faker'
18 |
19 | # ----------------------------------------
20 |
21 | require 'faker'
22 |
23 | puts Faker::VERSION
24 | puts Faker::Name.name
25 |
26 | # ----------------------------------------
27 |
28 | # 省略
29 |
30 | gem 'faker', '2.16.0'
31 |
32 | # ----------------------------------------
33 |
34 | # 省略
35 |
36 | gem 'faker', '2.16.0'
37 | gem 'awesome_print'
38 |
39 | # ----------------------------------------
40 |
41 | require 'faker'
42 | require 'awesome_print'
43 |
44 | puts Faker::VERSION
45 | puts Faker::Name.name
46 |
47 | # apはAwesome Printによって追加されるターミナル出力メソッド
48 | ap ['Alice', 'Bob', 'Carol']
49 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_09_04.rb:
--------------------------------------------------------------------------------
1 | # バージョンはBundlerにおまかせ
2 | gem 'faker'
3 |
4 | # ----------------------------------------
5 |
6 | # 2.17.0に固定
7 | gem 'faker', '2.17.0'
8 |
9 | # ----------------------------------------
10 |
11 | # 2.17.0以上(上は制限なし)
12 | gem 'faker', '>= 2.17.0'
13 |
14 | # ----------------------------------------
15 |
16 | # 2.17.0以上かつ2.18未満(2.17.1などは良いが、2.18.0はNG)
17 | gem 'faker', '~> 2.17.0'
18 |
19 | # ----------------------------------------
20 |
21 | # 2.17以上かつ3.0未満(2.19.0などは良いが、3.0.0はNG)
22 | gem 'faker', '~> 2.17'
23 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_11_01.rb:
--------------------------------------------------------------------------------
1 | # requireで他のプログラムやライブラリを読み込む
2 | require 'minitest/autorun'
3 | require_relative '../lib/fizz_buzz'
4 |
5 | class FizzBuzzTest < Minitest::Test
6 | # 省略
7 |
8 | # ----------------------------------------
9 |
10 | class UsersController < ApplicationController
11 | def index
12 | # user.rbはRailsによって自動的にrequireされる
13 | @users = User.all
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_11_02.rb:
--------------------------------------------------------------------------------
1 | class Foo::Bar < ApplicationRecord
2 | # クラスの定義
3 | end
4 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/code_13_11_04.rb:
--------------------------------------------------------------------------------
1 | class User
2 | def initialize(name)
3 | # @nameはオブジェクトの属性値を保存するためのインスタンス変数
4 | # (オブジェクト指向プログラミングにおけるインスタンス変数)
5 | @name = name
6 | end
7 |
8 | def hello
9 | "Hello, I am #{@name}."
10 | end
11 | end
12 |
13 | # ----------------------------------------
14 |
15 | class BooksController < ApplicationController
16 | def index
17 | # @booksはコントローラからビューにデータを渡すために使われるインスタンス変数
18 | # (Railsの規約としてそうなっているだけ)
19 | @books = Book.all
20 | end
21 | end
22 |
23 | # ----------------------------------------
24 |
25 | <
27 |
28 |
29 |
30 | <%= yield %>
31 |
32 |
33 | ERB
34 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/column_13_01.rb:
--------------------------------------------------------------------------------
1 | # コラム:requireの単位はライブラリ
2 |
3 | # URIモジュールのopenメソッドは、もともとprivateメソッドなので呼び出せない
4 | URI.open 'https://example.com'
5 | #=> private method `open' called for URI:Module (NoMethodError)
6 |
7 | # ただし、open-uriライブラリをrequireするとopenメソッドが使えるようになる
8 | require 'open-uri'
9 | URI.open 'https://example.com'
10 | #=> # {
24 | puts('Hello, world!');
25 | });
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/sample-codes/chapter_13/column_13_03.rb:
--------------------------------------------------------------------------------
1 | # コラム:もうひとつの型検査ツール = Sorbet
2 |
3 | # typed: true
4 | extend T::Sig
5 |
6 | sig {params(name: String).returns(Integer)}
7 | def main(name)
8 | puts "Hello, #{name}!"
9 | name.length
10 | end
11 |
12 | main("Sorbet") # ok!
13 | main() # error: Not enough arguments provided
14 | man("") # error: Method `man` does not exist
15 |
--------------------------------------------------------------------------------