Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

銀座Rails版 「Rubyプログラミング問題に チャレンジ!」公開コードレビュー / gin...

Junichi Ito
January 25, 2022

銀座Rails版 「Rubyプログラミング問題に チャレンジ!」公開コードレビュー / ginzarails code review

銀座Rails#41で使用したスライドです。
https://ginza-rails.connpass.com/event/234304/

- Links -

全視情協:点字とは - 点字のしくみ
http://www.naiiv.net/braille/?tenji-sikumi

点字 - Wikipedia
https://ja.wikipedia.org/wiki/点字

レビュー対象のプルリクエスト
https://github.com/JunichiIto/tenji-maker-challenge-for-ginza-rails/pull/5

Rubyプログラミング問題にチャレンジ! -改訂版・チェリー本発売記念- Advent Calendar 2021
https://qiita.com/advent-calendar/2021/ruby-challenge

Qiitaアドベントカレンダーの最優秀作品
https://qiita.com/haruguchiyuma/items/7d93a8feca11a325bee9

出題者(@jnchito)の模範解答
https://github.com/JunichiIto/tenji-maker-challenge-for-ginza-rails/tree/answer

辛口バージョンのテストパターン
https://gist.github.com/JunichiIto/1c8565bbffd0b5cf589b905f9ad2388f

辛口バージョンの模範解答
https://github.com/JunichiIto/tenji-maker-challenge-for-ginza-rails/blob/karakuchi-answer/lib/tenji.rb

プロを目指す人のためのRuby入門 [改訂2版]
https://gihyo.jp/book/2021/978-4-297-12437-3

Rubyコミッタ辻本さんによる推薦の言葉
https://twitter.com/k_tsj/status/1469535631995191303

Twitter
https://twitter.com/jnchito

Blog
https://blog.jnito.com/

第2回 ツクってアソぶハッカソン
https://tsukuaso.connpass.com/event/234370/

Everyday Rails - RSpecによるRailsテスト入門
https://leanpub.com/everydayrailsrspec-jp/

Junichi Ito

January 25, 2022
Tweet

More Decks by Junichi Ito

Other Decks in Technology

Transcript

  1. 2෼ͰΘ͔Δ఺ࣈͷ࢓૊Έ • ʮ͍͋͏͓͑ʯ͸͜͏Ͱ͢ʢ͜Ε͸֮͑Δ͚ͩʣ ᶃ ʔ ʔ ʔ ʔ ʔ ᶃ

    ʔ ᶄ ʔ ʔ ʔ ᶃ ᶆ ʔ ʔ ʔ ʔ ᶃ ᶆ ᶄ ʔ ʔ ʔ ʔ ᶆ ᶄ ʔ ʔ ʔ ͋ɹɹ͍ɹɹ͏ɹɹ͑ɹɹ͓
  2. 2෼ͰΘ͔Δ఺ࣈͷ࢓૊Έ • ʮ͔͖͚͘͜ʯ͸ʮ͍͋͑͏͓ʯʹᶈͷ఺ΛՃ͑·͢ ᶃ ʔ ʔ ʔ ʔ ᶈ ᶃ

    ʔ ᶄ ʔ ʔ ᶈ ᶃ ᶆ ʔ ʔ ʔ ᶈ ᶃ ᶆ ᶄ ʔ ʔ ᶈ ʔ ᶆ ᶄ ʔ ʔ ᶈ ͔ɹɹ͖ɹɹ͘ɹɹ͚ɹɹ͜
  3. 2෼ͰΘ͔Δ఺ࣈͷ࢓૊Έ • ʮͤͦ͢͞͠ʯ͸ʮ͍͋͑͏͓ʯʹᶇͱᶈͷ఺ΛՃ͑·͢ ᶃ ʔ ʔ ᶇ ʔ ᶈ ᶃ

    ʔ ᶄ ᶇ ʔ ᶈ ᶃ ᶆ ʔ ᶇ ʔ ᶈ ᶃ ᶆ ᶄ ᶇ ʔ ᶈ ʔ ᶆ ᶄ ᶇ ʔ ᶈ ͞ɹɹ͠ɹɹ͢ɹɹͤɹɹͦ
  4. ೖྗςΩετͷྫ • ͋ͻΔ = A HI RU • ͖ΓΜ =

    KI RI N • ͠·͏· = SI MA U MA • ʹΘͱΓ = NI WA TO RI • ͻΑ͜ = HI YO KO • ͖ͭͶ = KI TU NE • ҟৗͳೖྗ஋Λߟྀ͢Δඞཁ͸͋Γ·ͤΜ
  5. ࡞੒ͨ͠ϓϩάϥϜͷఏग़ํ๏ • GitHubͷ਽ܗϦϙδτϦΛϑΥʔΫ͠ɺίʔυΛॻ͘ • ϓϧϦΫΤετΛ࡞੒͠ɺCIͷςετ͕શ෦ύεͨ͠ΒOK class TenjiMakerTest < Minitest::Test def

    setup @tenji_maker = TenjiMaker.new end def test_a_hi_ru tenji = @tenji_maker.to_tenji('A HI RU') assert_equal <<~TENJI.chomp, tenji o- o- oo -- o- -o -- oo -- TENJI end # ҎԼɺςετ͕ଓ͘
  6. ๻͕ॻ͍ͨίʔυ͸͜Μͳײ͡ (1/3) class TenjiMaker def to_tenji(text) tenji_list = text.split(' ').map

    { |romaji| Tenji.new(romaji) } join(tenji_list) end private def join(tenji_list) tenji_list .map { |tenji| tenji.to_s.split("\n") } .transpose .map { |row| row.join(' ') } .join("\n") end end
  7. ๻͕ॻ͍ͨίʔυ͸͜Μͳײ͡ (2/3) class Tenji DAN = { 'A' => 0b100000,

    'I' => 0b101000, 'U' => 0b110000, 'E' => 0b111000, 'O' => 0b011000, } GYO = { 'K' => 0b000001, 'S' => 0b000101, 'T' => 0b000110, 'N' => 0b000010, 'H' => 0b000011, 'M' => 0b000111, 'Y' => 0b010000, 'R' => 0b000100, } def initialize(romaji) @romaji = romaji end # ͭͮ͘
  8. ๻͕ॻ͍ͨίʔυ͸͜Μͳײ͡ (3/3) # ͖ͭͮ def to_i case @romaji.chars in ['Y'

    => gyo, 'A' | 'U' => dan] then GYO[gyo] | (DAN[dan] >> 4) in ['Y' => gyo, 'O' => dan] then GYO[gyo] | (DAN[dan] >> 2) in ['W', 'A' => dan] then DAN[dan] >> 4 in [gyo, dan] then GYO[gyo] | DAN[dan] in ['N'] then 0b000111 in [dan] then DAN[dan] end end def to_s sprintf('%06b', to_i).tr('01', '-o').scan(/../).join("\n") end end
  9. ఺ࣈΛͲͷΑ͏ʹߏங͢Δ͔ʁ • 2ਐ਺ͷ੔਺஋͸࿦ཧ࿨ (OR) Λ࢖ͬͯɺ2ͭͷ஋Λ߹੒Ͱ͖Δ • ʮ͖ʯΛ࡞Δ৔߹ ᶃ ʔ ᶅ

    ʔ ʔ ᶈ ͖ ͍ஈ 0b101000 ͔ߦ 0b000001 ͖ɹ 0b101001 0b101000 | 0b000001 #=> 0b101001 1 2 3 4 5 6
  10. ʮ΍ΏΑʯ͸Ͳ͏͢Δʁ • ӈϏοτγϑτ͕࢖͑ͦ͏ ʔ ʔ ᶅ ᶆ ʔ ʔ 0b110000

    >> 2 ↓ 0b001100 2ͭӈʹϏοτγϑτ ͢Ε͹1ஈԼ͕Δ
  11. ʮ΍ΏΑʯ͸Ͳ͏͢Δʁ • ӈϏοτγϑτ͕࢖͑ͦ͏ ʔ ʔ ʔ ʔ ᶇ ᶈ 0b110000

    >> 4 ↓ 0b000011 4ͭӈʹϏοτγϑτ ͢Ε͹2ஈԼ͕Δ
  12. ʮ΍ΏΑʯ͸Ͳ͏͢Δʁ • ӈϏοτγϑτͨ͠஋ʹ࿦ཧ࿨Ͱʮ΍ߦʯΛද͢ᶄͷυοτΛ߹੒͢Ε͹OK (0b011000 >> 2) | 0b010000 #=> 0b010110

    ʔ ᶄ ᶅ ʔ ʔ ʔ ʔ ʔ ʔ ᶆ ᶇ ʔ → ͓ (0b110000 >> 4) | 0b010000 #=> 0b010011 ᶃ ᶄ ʔ ʔ ʔ ʔ ʔ ʔ ʔ ʔ ᶇ ᶈ → ͏
  13. ʮ΍ΏΑʯ͸Ͳ͏͢Δʁ • ӈϏοτγϑτͨ͠஋ʹ࿦ཧ࿨Ͱʮ΍ߦʯΛද͢ᶄͷυοτΛ߹੒͢Ε͹OK (0b011000 >> 2) | 0b010000 #=> 0b010110

    ʔ ᶄ ᶅ ʔ ʔ ʔ ʔ ᶄ ʔ ᶆ ᶇ ʔ → ͓ Α (0b110000 >> 4) | 0b010000 #=> 0b010011 ᶃ ᶄ ʔ ʔ ʔ ʔ ʔ ᶄ ʔ ʔ ᶇ ᶈ → ͏ Ώ
  14. ʮΘʯ͸Ͳ͏͢Δʁ • ʮ͋ʯΛҰ൪Լ·ͰԼΖ͢ ʹ 4ͭӈʹϏοτγϑτ͢Δ ᶃ ʔ ʔ ʔ ʔ

    ʔ ʔ ʔ ʔ ʔ ᶇ ʔ → 0b100000 >> 4 #=> 0b000010 ͋ Θ
  15. ஈͱߦͷϚοϐϯάදʢϋογϡʣΛ࡞Δ • ฼ԻʢஈʣͱࢠԻʢߦʣͷରԠؔ܎ΛϋογϡͰ·ͱΊΔ • ʮΜʯ͸ͨͩͷݻఆ஋ͳͷͰɺ͜ͷϋογϡʹ͸ؚΊͳ͍ class Tenji DAN = {

    'A' => 0b100000, 'I' => 0b101000, 'U' => 0b110000, 'E' => 0b111000, 'O' => 0b011000, } GYO = { 'K' => 0b000001, 'S' => 0b000101, 'T' => 0b000110, 'N' => 0b000010, 'H' => 0b000011, 'M' => 0b000111, 'Y' => 0b010000, 'R' => 0b000100, }
  16. ϩʔϚࣈΛͲ͏΍ͬͯߦͱஈʹ෼͚Δ͔ʁ • charsϝιουͰϩʔϚࣈ͸ஈͱߦʹ෼ղ͢Δ • Ϛοϐϯάද͔Β਺஋Λऔಘ͠࿦ཧ࿨Λฦ͢ / ʮ͍͋͏͓͑ʯ͸ஈ͚ͩฦ͢ # gyo="K", dan="I"

    ͕୅ೖ͞ΕΔ gyo, dan = "KI".chars # GYO["K"]=0b000001, DAN["I"]=0b101000 Ͱ࿦ཧ࿨͸ 0b101001 GYO[gyo] | DAN[dan] # dan="A" ͕୅ೖ͞ΕΔ dan, = "A".chars # DAN["A"]=0b100000 DAN[dan]
  17. 2จࣈͱ1จࣈͷͱ͖ͰͲ͏৚݅෼ذ͢Δʁ • ύλʔϯϚονʢcase/inࣜʣΛ࢖ͬͯ഑ྻͷߏ଄ʹண໨͢Δͱศརͦ͏ def to_i case @romaji.chars in [gyo, dan]

    GYO[gyo] | DAN[dan] in [dan] DAN[dan] end end charsͷ໭Γ஋͕["K", "I"]ͳΒ͜͜ʹϚον ͞Βʹɺม਺gyoʹ"K"͕ɺม਺danʹ"I"͕ ͦΕͧΕ୅ೖ͞ΕΔ
  18. 2จࣈͱ1จࣈͷͱ͖ͰͲ͏৚݅෼ذ͢Δʁ • ύλʔϯϚονʢcase/inࣜʣΛ࢖ͬͯ഑ྻͷߏ଄ʹண໨͢Δͱศརͦ͏ def to_i case @romaji.chars in [gyo, dan]

    GYO[gyo] | DAN[dan] in [dan] DAN[dan] end end charsͷ໭Γ஋͕["A"]ͳΒ͜͜ʹϚον ͞Βʹɺม਺danʹ"A"͕୅ೖ͞ΕΔ
  19. ʮ΍ΏΑʯ͸Ͳ͏͢Δʁ • ͜Ε΋ύλʔϯϚονͰରԠՄೳ def to_i case @romaji.chars in ['Y' =>

    gyo, 'A' | 'U' => dan] GYO[gyo] | (DAN[dan] >> 4) in ['Y' => gyo, 'O' => dan] GYO[gyo] | (DAN[dan] >> 2) in [gyo, dan] # ҎԼུ ["Y", "A"] ͔ ["Y", "U"] ͳΒϚον gyo ʹ͸ "Y" ͕ dan ʹ͸ "A" ͔ "U" ͕ ͦΕͧΕ୅ೖ͞ΕΔ
  20. ʮ΍ΏΑʯ͸Ͳ͏͢Δʁ • ͜Ε΋ύλʔϯϚονͰରԠՄೳ def to_i case @romaji.chars in ['Y' =>

    gyo, 'A' | 'U' => dan] GYO[gyo] | (DAN[dan] >> 4) in ['Y' => gyo, 'O' => dan] GYO[gyo] | (DAN[dan] >> 2) in [gyo, dan] # ҎԼུ ["Y","O"] ͳΒϚον gyo ʹ͸ "Y" ͕ dan ʹ͸ "O" ͕ ͦΕͧΕ୅ೖ͞ΕΔ
  21. ʮΘʯ͸Ͳ͏͢Δʁ • ͜Ε΋ύλʔϯϚονͰରԠՄೳ def to_i case @romaji.chars # লུ in

    ['W', 'A' => dan] DAN[dan] >> 4 in [gyo, dan] # ҎԼུ ["W","A"] ͳΒϚον dan ʹ͸ "A" ͕୅ೖ͞ΕΔ
  22. ʮΜʯ͸Ͳ͏͢Δʁ • ͜Ε΋ύλʔϯϚονͰରԠՄೳ def to_i case @romaji.chars # লུ in

    ['N'] 0b000111 in [dan] DAN[dan] end end ["N"] ͳΒϚον ม਺͸࢖Θͣݻఆ஋Λฦ͢
  23. શ෦·ͱΊΔͱɺ͜͏ • εϖʔεͷ౎߹্ɺthenͰߦ਺Λઅ໿͠·ͨ͠ def to_i case @romaji.chars in ['Y' =>

    gyo, 'A' | 'U' => dan] then GYO[gyo] | (DAN[dan] >> 4) in ['Y' => gyo, 'O' => dan] then GYO[gyo] | (DAN[dan] >> 2) in ['W', 'A' => dan] then DAN[dan] >> 4 in [gyo, dan] then GYO[gyo] | DAN[dan] in ['N'] then 0b000111 in [dan] then DAN[dan] end end
  24. ͜ΕͰϩʔϚࣈΛ2ਐ਺ʹม׵Ͱ͖Δʂ • to_i ϝιουͷڍಈ͸͜Μͳײ͡ Tenji.new('KI').to_i #=> 0b101001 Tenji.new('A').to_i #=> 0b100000

    Tenji.new('YU').to_i #=> 0b010011 Tenji.new('WA').to_i #=> 0b000010 Tenji.new('N').to_i #=> 0b000111
  25. 2ਐ਺Λ఺ࣈͷจࣈྻʹม׵͢Δ • ͋ͱ͸ػցతʹม׵͢Δ͚ͩ # to_i ͕ 0b101001 Λฦ͢৔߹ def to_s

    sprintf('%06b', to_i) .tr('01', '-o') .scan(/../) .join("\n") end จࣈྻ "101001" ʹม׵
  26. 2ਐ਺Λ఺ࣈͷจࣈྻʹม׵͢Δ • ͋ͱ͸ػցతʹม׵͢Δ͚ͩ # to_i ͕ 0b101001 Λฦ͢৔߹ def to_s

    sprintf('%06b', to_i) .tr('01', '-o') .scan(/../) .join("\n") end "0"Λ"-"ʹɺ"1"Λ"o"ʹม׵ ͭ·Γɺ "o-o--o" ͕Ͱ͖͕͋Δ
  27. 2ਐ਺Λ఺ࣈͷจࣈྻʹม׵͢Δ • ͋ͱ͸ػցతʹม׵͢Δ͚ͩ # to_i ͕ 0b101001 Λฦ͢৔߹ def to_s

    sprintf('%06b', to_i) .tr('01', '-o') .scan(/../) .join("\n") end 2จࣈͣͭ഑ྻʹ෼ׂ͢Δ ͭ·Γɺ ["o-", "o-", "-o"] ͕Ͱ͖͕͋Δ
  28. 2ਐ਺Λ఺ࣈͷจࣈྻʹม׵͢Δ • ͋ͱ͸ػցతʹม׵͢Δ͚ͩ # to_i ͕ 0b101001 Λฦ͢৔߹ def to_s

    sprintf('%06b', to_i) .tr('01', '-o') .scan(/../) .join("\n") end ֤ཁૉΛվߦจࣈͰ࿈݁ → ʢ׬੒ʂʣ o- o- -o
  29. TenjiΫϥεͷશମ૾ (1/2) class Tenji DAN = { 'A' => 0b100000,

    'I' => 0b101000, 'U' => 0b110000, 'E' => 0b111000, 'O' => 0b011000, } GYO = { 'K' => 0b000001, 'S' => 0b000101, 'T' => 0b000110, 'N' => 0b000010, 'H' => 0b000011, 'M' => 0b000111, 'Y' => 0b010000, 'R' => 0b000100, } def initialize(romaji) @romaji = romaji end # ͭͮ͘
  30. TenjiΫϥεͷશମ૾ (2/2) # ͖ͭͮ def to_i case @romaji.chars in ['Y'

    => gyo, 'A' | 'U' => dan] then GYO[gyo] | (DAN[dan] >> 4) in ['Y' => gyo, 'O' => dan] then GYO[gyo] | (DAN[dan] >> 2) in ['W', 'A' => dan] then DAN[dan] >> 4 in [gyo, dan] then GYO[gyo] | DAN[dan] in ['N'] then 0b000111 in [dan] then DAN[dan] end end def to_s sprintf('%06b', to_i).tr('01', '-o').scan(/../).join("\n") end end
  31. TenjiMakerΫϥεͷॲཧ΋ඇৗʹػցత class TenjiMaker def to_tenji(text) tenji_list = text.split(' ').map {

    |romaji| Tenji.new(romaji) } join(tenji_list) end private def join(tenji_list) tenji_list .map { |tenji| tenji.to_s.split("\n") } .transpose .map { |row| row.join(' ') } .join("\n") end end
  32. TenjiMakerΫϥεͷॲཧ΋ඇৗʹػցత class TenjiMaker def to_tenji(text) tenji_list = text.split(' ').map {

    |romaji| Tenji.new(romaji) } join(tenji_list) end private def join(tenji_list) tenji_list .map { |tenji| tenji.to_s.split("\n") } .transpose .map { |row| row.join(' ') } .join("\n") end end ೖྗ஋ΛεϖʔεͰ෼ׂͯ͠ TenjiΫϥεͷ഑ྻΛ࡞Δ
  33. TenjiMakerΫϥεͷॲཧ΋ඇৗʹػցత class TenjiMaker def to_tenji(text) tenji_list = text.split(' ').map {

    |romaji| Tenji.new(romaji) } join(tenji_list) end private def join(tenji_list) tenji_list .map { |tenji| tenji.to_s.split("\n") } .transpose .map { |row| row.join(' ') } .join("\n") end end ֤఺ࣈΛߦ͝ͱʹ෼ׂͯ͠ ഑ྻͷঢ়ଶʹ໭͢ [ ["o-", "o-", "--"], ͍ ["oo", "--", "o-"] ͵ ] o- oo o- -- -- o- ͍ɹ͵ →
  34. TenjiMakerΫϥεͷॲཧ΋ඇৗʹػցత class TenjiMaker def to_tenji(text) tenji_list = text.split(' ').map {

    |romaji| Tenji.new(romaji) } join(tenji_list) end private def join(tenji_list) tenji_list .map { |tenji| tenji.to_s.split("\n") } .transpose .map { |row| row.join(' ') } .join("\n") end end ߦྻΛ൓సͤ͞Δ [ ["o-", "oo"], ["o-", "--"], ["--", "o-"] ] [ ["o-", "o-", "--"], ͍ ["oo", "--", "o-"] ͵ ] ͍ɹɹɹ͵ ↓
  35. TenjiMakerΫϥεͷॲཧ΋ඇৗʹػցత class TenjiMaker def to_tenji(text) tenji_list = text.split(' ').map {

    |romaji| Tenji.new(romaji) } join(tenji_list) end private def join(tenji_list) tenji_list .map { |tenji| tenji.to_s.split("\n") } .transpose .map { |row| row.join(' ') } .join("\n") end end ߦ಺ͷ֤ཁૉΛεϖʔεͰ࿈݁͢Δ [ ["o-", "oo"], ["o-", "--"], ["--", "o-"] ] ͍ɹɹɹ͵ [ "o- oo", "o- --", "-- o-" ] ͍ɹ͵ ↓
  36. TenjiMakerΫϥεͷॲཧ΋ඇৗʹػցత class TenjiMaker def to_tenji(text) tenji_list = text.split(' ').map {

    |romaji| Tenji.new(romaji) } join(tenji_list) end private def join(tenji_list) tenji_list .map { |tenji| tenji.to_s.split("\n") } .transpose .map { |row| row.join(' ') } .join("\n") end end ֤ߦΛվߦจࣈͰ࿈݁͢Δʢ׬੒ʂʣ [ "o- oo", "o- --", "-- o-" ] ͍ɹ͵ o- oo o- -- -- o- ͍ɹ͵ ↓
  37. ϓϩΛ໨ࢦ͢ਓͷͨΊͷ3VCZೖ໳ [վగ2൛] ҏ౻ ३Ұ ஶ ൃച೔ 2021೥12݄2೔ ٕज़ධ࿦ࣾ / 3,278ԁʢ੫ࠐʣ

    ͦΜͳ͋ͳͨʹʂ • վగ2൛Ͱ͸Ruby 3.0ʹϑϧରԠ • Ϗοτԋࢉ΋ύλʔϯϚον΋શ෦ ࡌͬͯ·͢ • ಛʹύλʔϯϚονͷઆ໌ʹؔͯ͠͸ ੈքτοϓϨϕϧʂʁ
  38. About me • ҏ౻ ३Ұ • ιχοΫΨʔσϯͷRailsϓϩάϥϚ • ϑΟϤϧυϒʔτΩϟϯϓͷϝϯλʔ •

    QiitaϥϯΩϯά1Ґʢ2022೥1݄ݱࡏʣ • Twitter @jnchito • Blog https://blog.jnito.com/
  39. Everyday Rails RSpecʹΑΔRailsςετೖ໳ Aaron Sumner ஶɺҏ౻ ३Ұ ༁ ൢചՁ֨ 19.00

    USD ࠓ͚ͩ16.99 USD Ξοϓσʔτ͠·ͨ͠ʂ • αϯϓϧΞϓϦΛRails 7.0Խ • ࠷৽ͷRSpec΍gemʹରԠ • ظؒݶఆͰ 16.99υϧͰൢചத • RSpecΛϚελʔ͍ͨ͠ํ͸ͥͻʂ https://leanpub.com/everydayrailsrspec-jp/