├── .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 | --------------------------------------------------------------------------------