Slide 1

Slide 1 text

Evolution Of Enumerator Akinori Musha (@knu) Machimachi Inc. 2019-03-23 Rails Developer Meetup 2019

Slide 2

Slide 2 text

ࣗݾ঺հ

Slide 3

Slide 3 text

෢ऀ থل (@knu) • GitHub: https://github.com/knu • Twitter: https://twitter.com/knu • Docker Hub !

Slide 4

Slide 4 text

෢ऀ থل (@knu) • ෢ऀ (Musha) • Kanji: martial/brave-one • Meaning: samurai • থل (Akinori) • Kanji: shine/bright-age/century • Meaning: (My parents' hope) Shine in the next (21st) century • knu • Meaning: ?

Slide 5

Slide 5 text

෢ऀ থل (@knu) • FreeBSD committer (Ports): knu@FreeBSD.org • Ruby committer: knu@ruby-lang.org • (Sorted)Setͷ࡞ऀ • Enumeratorͷ࡞ऀ • Rails: 4.1ʙ (2014) • Team Nokogiri, Team Huginn, … • A Father Of Two !" • Working at Machimachi Inc.

Slide 6

Slide 6 text

झຯ • কع 㽪 !" ΞϚޒஈ (ࢦ͢ɺ؍Δ) • Minecraft ⛏$ • ϥϯν % (ौ୩ɺத໨ࠇɺֶܳେֶɺࣗ༝ٰ͕͋ͨΓ) • ΫϥϑτϏʔϧΛҿΉ: Craft beer • ԻָΛௌ͘ ' (Progressive, metal music)

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

ϚνϚν͸ʮͻΒ͔Εͨɺͭͳ͕Γͷ͋ Δ஍ҬࣾձΛͭ͘Δʯͱ͍͏ϛογϣϯ Λܝ͛ɺ஍Ҭͷ՝୊Λղܾ͢ΔͨΊͷࣾ ձΠϯϑϥΛ࡞ΔҰ؀ͱͯ͠ɺۙ͝ॴ SNSͱ஍Ҭ৘ใϙʔλϧαΠτΛӡӦ͠ ͍ͯ·͢ɻ https://machimachi.com/ ۙ͝ॴ͞Μͱɺ·ͪͷࢠҭͯ΍Φεεϝ ͷ͓ళɾපӃͳͲʹ͍ͭͯ৘ใަ׵͕Ͱ ͖ΔαʔϏεͰ͢ɻ1 1 ͣͬͱ੍໊࣮Ͱ͕ͨ͠ɺ࠷ۙχοΫωʔϜͰؾܰʹࢀՃͰ͖ΔΑ͏ʹͳΓ·͠ ͨɻ

Slide 9

Slide 9 text

ϚνϚνΛࢧ͑Δٕज़ • Ruby / Rails • React.js • PostgreSQL / PostGIS • GCP / GAE Flex Environment ٕज़ϒϩάΛॻ͍͍ͯ·͢ʂ https://tech.machimachi.com/ We are hiring!

Slide 10

Slide 10 text

EnumerableϞδϡʔϧͷྑ͞ • ϝιουʹண໨ͨ͠ػೳ֦ுʢmix-inʣ • ஋Λྻڍ͢ΔeachϝιουΛprimitiveͱͯ͠༻͍ɺmap, select, to_aͳͲΛఆٛ͢Δ • each͑͞ఆٛͯ͠include Enumerable͢Ε͹ɺ੝Γͩ͘ ͞Μͷػೳ͕෇Ճ͞ΕΔ • ͲΜͳίϨΫγϣϯ΋ಉ͡࢖͍উखͰ࢖͑Δ

Slide 11

Slide 11 text

಺෦ΠςϨʔλͱ ֎෦ΠςϨʔλ

Slide 12

Slide 12 text

֎෦ΠςϨʔλ (External Iterator) • ଟ͘ͷݴޠɾϥΠϒϥϦ͸ͪ͜Β͕جຊ • ܁Γฦ͠Λ੍ޚ͢Δ໾ׂ͕ίϨΫγϣϯΦϒδΣΫτ·ͨ͸ϝιουͷ֎෦ɺ ͭ·Γ࢖͏ଆʹ͋Δ • ࢖͏ଆ͕ࣗ༝ͳλΠϛϯάͰΧʔιϧΛਐΊΒΕΔͷͰɺॲཧͷࣗ༝౓͸ߴ͍ • ίϨΫγϣϯΛ࢖͏ଆ͕ϧʔϓม਺Λ؅ཧ͢Δඞཁ͕͋Δ఺͸໘౗ • forจͳͲͷ౶ҥߏจͰࢧԉ͢Δͷ͕௨ྫ • eachʹ͋ͨΔॲཧ͸forจɺmapʹ͋ͨΔॲཧ͸Ϧετ಺แදهɺͷΑ͏ʹಉ͡ ܁Γฦ͠Ͱ΋ߏจͷ࢖͍෼͚͕ඞཁʹͳΔ (each: for, map: list comprehension)

Slide 13

Slide 13 text

಺෦ΠςϨʔλ (Internal Iterator) • Ruby͸ͪ͜Β͕جຊ • ܁Γฦ͠Λ੍ޚ͢Δ໾ׂ͕ίϨΫγϣϯΦϒδΣΫτ·ͨ͸ϝιουͷ಺෦ɺ ͭ·ΓΦϒδΣΫτଆʹ͋Δ • ࣮ମͱͯ͠͸ɺ܁Γฦ͠͝ͱʹ࣮ߦ͢Δؔ਺Λड͚औΔߴ֊ؔ਺ • ཁૉ͝ͱͷίʔϧόοΫؔ਺Λॻ͚ͩ͘ͳͷͰɺఆܕͷϧʔϓॲཧͷهड़͸ͱ ͯ΋؆୯ • ෳ਺ͷίϨΫγϣϯΛಉظతʹᢞΊΔͳͲ͸ۤखʢ͋Δ͍͸ແཧʣ • each΋map΋ಉ͡ߏจͰॻ͚Δ (each & map share a common construct)

Slide 14

Slide 14 text

Rubyͷ಺෦ΠςϨʔλ Internal Iterator In Ruby • each + Enumerable ΛAPIͱͯ͠શ໘࠾༻͍ͯ͠Δ • ߴ֊ؔ਺ͱͯ͠ͷ಺෦ΠςϨʔλΛ࢖͍΍͍͢Α͏ɺϒϩοΫͱ͍͏ಛ घߏจΛ༻ҙ • break, next ͳͲϧʔϓʹదͨ͠δϟϯϓ໋ྩΛఏڙ • ͞Βʹ return Ͱ֎ଆͷϝιου͔Β΋ൈ͚ΒΕΔ • ݁Ռͱͯ͠ɺ֎෦ΠςϨʔλͱḮ৭ͳ͍ॲཧͷදݱྗ

Slide 15

Slide 15 text

Rubyͷ֎෦ΠςϨʔλ External Iterator In Ruby • Ruby 1.8Ҏલ͸ඪ४తͳαϙʔτ͸ͳ͔ͬͨ • IOͳͲ͸ɺgets, eof?ͳͲͷʢ఻౷తͳʣ֎෦ΠςϨʔλܕ ͷAPI΋ఏڙ͍ͯ͠Δ • ഑ྻͳͲఴ͑ࣈΞΫηε͕Ͱ͖ΔίϨΫγϣϯͷ৔߹͸ɺࣗ ྗͰΠϯσοΫεม਺Λૢ࡞ͯ͠whileจͰճ͢ͳͲ

Slide 16

Slide 16 text

ؔ࿈: Ruby 1.8ͷGenerator Ruby 1.8.1ʙ1.8.7ʹ͸ɺࢲ͕ॻ͍ͨ generator ͱ͍͏࣮ݧత ͳ֎෦ΠςϨʔλੜ੒ϥΠϒϥϦ͕ඪ४ఴ෇͞Ε͍ͯ·ͨ͠ɻ (2003-2008)

Slide 17

Slide 17 text

ؔ࿈: Ruby 1.8ͷGenerator • Generator: converts an internal iterator to an external iteretor • ۩ମతʹ͸ɺEnumerableΦϒδΣΫτΛ౉͢ͱɺnextϝιουΛݺͿ౓ʹ͔ͦ͜Β ཁૉ͕ॱʹฦΔΦϒδΣΫτΛ࡞Δ • callcc (!)Λ࢖͍ɺ಺෦ΠςϨʔλͷ܁Γฦ͠ΛࢭΊͨΓ࠶։੍ͯ͠ޚΛୣ͏߽շͳ ࣮૷ ! • ޙʹThreadʹΑΔϦϥΠτ΋ࢼΈΒΕͨ • ͍ͣΕʹͤΑɺຖճ܁Γฦ͠ΛࢭΊͯ͸࠶։ ͢ΔͷͰΦʔόʔϔου͕͍͢͝ • SyncEnumerator: GeneratorΛ࢖ͬͯෳ਺ͷ಺෦ΠςϨʔλΛಉظతʹ܁Γฦ͢ (lazyͳ zip)

Slide 18

Slide 18 text

Generatorͷ࢖༻ྫ 2ͭʢҎ্ʣͷίϨΫγϣϯΛಉظతʹϧʔϓॲཧͰ͖Δɻ require "generator" array1 = ["A", "B", "C", "D"] array2 = ["A", "B", "D", "C"] g1 = Generator.new(array1) g2 = Generator.new(array2) loop do e1 = g1.next e2 = g2.next # compare elements, etc. end

Slide 19

Slide 19 text

eachͰ΋2ͭͷ഑ྻͷ֤ཁૉΛൺֱ͍ͨ͠ ෳ਺ͷeach͸ಉظͰ͖ͳ͍ ! array1 = ["A", "B", "C", "D"] array2 = ["A", "B", "D", "C"] array1.each do |e1| array2.each do |e2| # gets all combinations end end

Slide 20

Slide 20 text

eachͰ΋2ͭͷ഑ྻͷ֤ཁૉΛൺֱ͍ͨ͠ ยํ͚ͩ಺෦ΠςϨʔλΛ࢖͍ɺ΋͏Ұํ͸ఴ͑ࣈΞΫηε͢Ε͹Մೳ array1 = ["A", "B", "C", "D"] array2 = ["A", "B", "D", "C"] array1.each_with_index do |e1, i| e2 = array2[i] # This is OK end ͨͩɺఴ͑ࣈΞΫηεͰ͖ͳ͍ΠςϨʔλಉ࢜ͷ৔߹͸͍ͬͨΜ഑ྻԽ͢ΔͳͲͷલॲཧ͕ඞཁɻ ·ͨɺঢ়گʹΑͬͯยํ͚ͩϙΠϯλΛਐΊΔɺͷΑ͏ͳॲཧ͸Φϑηοτͷ؅ཧ΋ඞཁʹͳ Δɻ

Slide 21

Slide 21 text

ྻڍ͍Ζ͍Ζ

Slide 22

Slide 22 text

ྻڍ͍ͨ͠΋ͷ͍Ζ͍Ζ Things To Enumerate ϋογϡʢHashʣͷ৔߹: • Ωʔͱ஋ͷ૊ʢpairʣ • Ωʔʢkeyʣ • ஋ʢvalueʣ

Slide 23

Slide 23 text

ྻڍ୯Ґ͍Ζ͍Ζ Units For Iteration จࣈྻʢStringʣͷ৔߹: • ࿦ཧߦʢlineʣ • όΠτʢbyteʣ • ʮจࣈʯʢcharʣ • ίʔυϙΠϯτʢcodepointʣ • ॻهૉΫϥελʢgrapheme clusterʣ • ͦͷଞɺޠʢwordʣɺจʢsentenceʣɺஈམʢparagraphʣɺ෺ཧߦʢphysical lineʣͳͲ΋ߟ͑ΒΕ Δɻ

Slide 24

Slide 24 text

Enumeratorͷ஀ੜ·Ͱ

Slide 25

Slide 25 text

Enumerable͕ఏڙ͖ͯͨ͠໾ׂ • ಺෦ΠςϨʔλͷϑϨʔϜϫʔΫ (framework for internal iterators) • Ϋϥεʹinclude͢Δʢmix-inʣ • ͦͷΫϥεͷeachΛ֦ு͢Δ

Slide 26

Slide 26 text

Mix-inͱͯ͠ͷݶք • includeͰ͸each͔֦͠ுͰ͖ͳ͍ʂ (Enumerable can only extend each) • each_byte΍each_keyͰ΋map΍select͍ͨ͠ • ഑ྻ(Array)Խͯ͠΍Ε͹Ͱ͖Δ͚Ͳɺͨͱ͑͹findͷΑ͏ʹ1ͭݟ͔ͭͬ ͨΒ࢒Γ͸ཁΒͳ͍ɺͱ͍͏ͱ͖͸ඇޮ཰ (Intermediate arrays require memory) • ObjectSpace.each_objectͷΑ͏ʹϞδϡʔϧϝιου͕ΠςϨʔλɺ ͱ͍͏ྫ΋͋Δ (ObjectSpace is not an enumerable object, yet provides an iterator method)

Slide 27

Slide 27 text

EachDelegatorͱ͍͏ൃ૝ Ԭా ५͞Μ࡞ͷEachDelegator (2001) ࢦఆͨ͠ΠςϨʔλϝιουΛॻ͖׵͑ɺϒϩοΫͳ͠Ͱݺͼग़͞ΕͨΒEnumerableͳΦϒ δΣΫτΛฦ͢ɺʮϒϩοΫͳ͠eachʯͷઌߦఏҊ require "eachdelegator" class String each_delegator :each_byte end "͋".each_byte.each_with_index.collect { |byte, i| [i, "%02X" % byte] } #=> [[0, "E3"], [1, "81"], [2, "82"]]

Slide 28

Slide 28 text

EnumeratorͷൃҊ • ͜ͷΞΠσΞʹײ໏Λड͚ͨࢲ͸ɺEnumeratorΛఏҊ (May 2001) • [ruby-list:29604] Importing eachdelegator.rb • [ruby-list:29624] Enumerator • [ruby-dev:13202] Re: [ruby-list:29672] Re: Enumerator • [ruby-dev:13259] Enumerator -- Round 2 • Enumerable::EnumeratorΫϥεΛઃ͚ɺ Kernel#enum_with(:each_xxx) ͰͦͷΠϯελϯεΛฦ͢ͱ͍͏಺༰ • each_xxx ϝιουΛࢧԉ͍ͨ͠

Slide 29

Slide 29 text

Enumeratorͷ࠾༻ Ruby 1.8.1ʹඪ४ϥΠϒϥϦͱͯ͠࠾༻ (Oct 2003) • ͜ͷ࣌఺Ͱ͸ɺ·ͩrequire "enumerator"͕ඞཁͳҰϥΠϒϥϦ • ૊ΈࠐΈͰ͸ͳ͍ͷͰɺඪ४ΫϥεͷeachͰEnumerator͕ฦΔͱ͍ ͏ػೳ΋ͳ͠ • enum_with / each_for ͰϝιουΛࢦఆͯ͠࢖͏ • ͜͜Ͱɺ܁Γฦ͠ॲཧҰൠΛ֦ு͢ΔػೳΛ2ͭಋೖͨ͠

Slide 30

Slide 30 text

܁Γฦ͠ͷ֦ு • ࢦఆݸ਺ͣͭͷεϥΠε (each_slice) • ࿈ଓཁૉͷ܁Γฦ͠ (each_cons)

Slide 31

Slide 31 text

ࢦఆݸ਺ͣͭͷεϥΠε each_slice(n)Ͱnཁૉͣͭ·ͱΊͯ܁Γฦ͢ # 100௨ͣͭλεΫԽ recipient_ids.each_slice(100) do |ids| MessageJob.perform_later(ids: ids) end

Slide 32

Slide 32 text

࿈ଓཁૉͷ܁Γฦ͠ each_cons(n)Ͱʮ֤ཁૉ+ޙଓͷܭnཁૉʯʹ͍ͭͯ1ͭͣͭ ͣΒ͠ͳ͕Β܁Γฦ͢ [1, 2, 3, 4, 5, 6].each_cons(3) do |es| p es end # [1, 2, 3] # [2, 3, 4] # [3, 4, 5] # [4, 5, 6]

Slide 33

Slide 33 text

࿈ଓཁૉͷ܁Γฦ͠ • nilຒΊͤͣʹ (size - n + 1) ճ܁Γฦͯ͠ऴΘͬͯ͠· ͏ͷͰɺʮίϯςΩετ෇͖܁Γฦ͠ʯͱͯ͠࢖͏ʹ͸ ͪΐͬͱ଍Γͳ͍ • ͨͱ͑͹࠷ॳʹ [nil, 1, 2]ɺ࠷ޙʹ [5, 6, nil] Λ଍ ͯ͘͠ΕΕ͹શཁૉͷલޙίϯςΩετ෇͖܁Γฦ͠ʹͳΔ ͷʹ… ! Ruby 2.6ͷchainͰٹࡁ͞Ε·͢ʂʢޙड़ʣ

Slide 34

Slide 34 text

Ruby 1.9ͷ։ൃ͕ਐΉ ෳ਺ͷେ͖ͳมߋΛؚΉRuby 1.9ͷ։ൃ͸͔ͳΓ೉ߤͨ͠ • ΠϯλϓϦλͷࠩ͠ସ͑ʢYARVʣ • ਖ਼نදݱΤϯδϯͷมߋʢَं Onigurumaʣ • CSIํࣜͷM17Nಋೖ • ৽จ๏ ({ key: value }, -> {}) etc.

Slide 35

Slide 35 text

ΠϯλϓϦλͷࠩ͠ସ͑ʢYARVʣ • VMͷಋೖ • OSͷωΠςΟϒεϨουΛ࢖͏Α͏ʹ (pthread) • ThreadΑΓܰྔͳίϧʔνϯػߏ (Fiber)

Slide 36

Slide 36 text

༨ஊ: ਖ਼نදݱΤϯδϯͷมߋ • ৽ͨʹॻ͖ى͜͞ΕͨΤϯδϯʮَंʯ(Oniguruma) by K.Kosako • ͦΕ·Ͱ͸GNU regexϥΠϒϥϦΛ(ຐ)վ଄ͯ͠࢖͍ͬͯͨ • Perl֦ுΛ͕Μ͹࣮ͬͯ૷͖͕ͯͨ͠ɺ֦ுੑʹ΋ݶք • ϥΠηϯε͕͚ͩ͜͜LGPLͩͬͨͷͰऔΓѻ͍ʹ஫ҙΛཁͨ͠ • RubyͰ͸ະ࣮૷ͩͬͨPerlޓ׵ͷ௥ՃػೳΛ΄΅͢΂ͯඋ͑ɺBSDL Ͱɺ֦ுੑɺੑೳʹ΋༏Ε͍ͯͨ • ݱࡏ(2012-)͸ޙܧͷʮَӢʯ(Onigmo)ʹͳ͍ͬͯΔ

Slide 37

Slide 37 text

༨ஊ: CSIํࣜͷM17Nಋೖ • Code Set Independentํࣜ • ݸʑͷStringΦϒδΣΫτ͕ࣗ਎ͰΤϯίʔσΟϯά৘ใΛ࣋ͪɺෳ ਺ͷΤϯίʔσΟϯάͷจࣈྻσʔλ͕ࠞࡏͰ͖Δ • ͋·ΓଞͷݴޠʹྨΛݟͳ͍ • ಺෦ΤϯίʔσΟϯά͸UTF-8ͷΈʹ౷Ұ͢Δͷ͕ʢ౰࣌Ͱ΋ʣେ੎ • ͍͍ͤͥબ΂ͯ΋1ͭͷΈ • َंͷෳ਺ΤϯίʔσΟϯάରԠ෦͕ૅͱͳ͍ͬͯΔ

Slide 38

Slide 38 text

Enumeratorͷ ૊ΈࠐΈԽͱ੒௕

Slide 39

Slide 39 text

Enumeratorͷ૊ΈࠐΈԽ • ext/enumerator ͔ΒτοϓϨϕϧʹҠಈ͠ɺσϑΥϧτͰϩʔυ͞ΕΔΑ ͏ʹ (2005) • require͕ෆཁʹ ! • ૊ΈࠐΈΫϥεʹʮϒϩοΫͳ͠eachʯ͕࣮૷͞ΕΔ • Ruby 1.9ͷFiberΛར༻ͯ͠next, next?, rewind͕࣮૷͞ΕΔ (Aug 2007) ͍ͭʹEnumerator͕֎෦ΠςϨʔλ݉༻ʹʂ (Enumerator became usable as an external iterator) • ͜ΕͰGenerator͸ແࣄҾୀ "

Slide 40

Slide 40 text

Enumeratorͷਖ਼ࣜͳ૊ΈࠐΈԽ • Ruby 1.9.0-devϦϦʔε ! (Dec 2007) • 1.8ܥʹ΋όοΫϙʔτ͞Εࢲ͕ͯ͠ɺRuby 1.8.7ϦϦʔε (Jun 2008) ΍͕ͯདྷΔ1.9.1ͱͷΪϟοϓΛݮΒ͔ͨͬͨ͠ • 1.9.1Ͱͷ҆ఆ൛ϦϦʔεΛ߇͑ɺ͞Βʹ͔͜͜ΒEnumeratorͷ࢓༷٧Ί͕ਐΉ… • ϝϞΦϒδΣΫτͷ෇Ճػೳ (Iteration with a memo object) • ΠϯσοΫεͷ෇Ճ (Iteration with an index number)

Slide 41

Slide 41 text

Iteration With A Memo Object ϧʔϓ಺ʢ͚ͩʣͰڞ༗Ͱ͖ΔΦϒδΣΫτΛ࣋ͪɺͦ͜ʹ৘ ใΛू໿ͯ݁͠Ռ஋ͱͯ͠ಘ͍ͨ result = {} records.each do |record| result[record.id] = record end p result # એݴ/ॳظԽɺૢ࡞ɺࢀরͷ3εςοϓΛ·ͱΊ͍ͨ

Slide 42

Slide 42 text

Iteration With A Memo Object inject/reduceΛ࢖͏ͱͰ͖Δ͕ɺϒϩοΫͷฦΓ஋Λҙࣝ͠ ͳ͍ͱ͍͚ͳ͍ result = records.inject({}) { |hash, record| hash[record.id] = record hash # ͋·Γ͜ΕΛॻ͖ͨ͘ͳ͍ }

Slide 43

Slide 43 text

Iteration With A Memo Object Enumerator#with_memoͷ໊લͰఏҊͨ͠ (Jun 2008) • [ruby-core:17084] Enumerable::Enumerator#with_memo • ࠷௿ݶͷهड़Ͱ࣮ݱͰ͖Δ result = records.each.with_memo({}) { |record, hash| hash[record.id] = record } • with_object, with_obj, withͳͲͷҊ΋ఴ͑ɺͦͷޙɺintroduceͱ͍͏͔͍͍ͬ͜Ҋ ΋ग़ͨ͠ • ͔͠͠ͳ͔ͳ͔ܾΊ͖Εͣɺແ೉ͳ each_with_object ͱ͍͏໊લͰೖΕͯ৸͔ͤΔ͜ͱ ʹͨ͠ ! (To be continued)

Slide 44

Slide 44 text

Iteration With An Index Number • each_with_index͸͋Δ͕ɺ։࢝஋͕0ݻఆͳͷͰɺoriginΛࢦఆ͍ͨ͠ [ruby-dev:37921] with_index_from by mame͞Μ (2009) • ࠓ·Ͱ͸ࣗ෼ͰΦϑηοτΛ଍͍ͯͨ͠ file.each_with_index do |line, i| print "#{i+1}: #{line}" end • each_with_indexʹҾ਺Λ଍͔͕ͨͬͨ͠ɺeach_with_indexʹ౉͞ΕͨҾ਺͸ͦͷ ··eachʹ౉ΔΑ͏ʹͳ͍ͬͯΔ • ͨͱ͑͹String#each͸ΦϓγϣφϧҾ਺Ͱվߦʹ୅ΘΔ۠੾ΓจࣈΛࢦఆͰ͖Δ

Slide 45

Slide 45 text

Iteration With An Index Number • each_with_index͸ͦͷ··ʹɺ Enumerator#with_index͚֦ͩு͢Δ͜ͱʹͯ͠࠾༻ (Feb 2009) file.each.with_index(1) do |line, i| print "#{i}: #{line}" end

Slide 46

Slide 46 text

Ruby 1.9ͷҰൠ޲͚ϦϦʔε ͦͯ͠ؾ͕෇͘ͱ… Ruby 1.9.1ϦϦʔε ! (Jan 2009) • एׯෆຊҙͳ͕Βɺ each_with_object / with_object ͕ͦͷ໊લͰ֬ఆ͢Δ͜ͱʹ ! • ௕͍ͳ͋ͱࢥ͏ਓ΋ଟ͍ͱࢥ͍·͕͢ɺ͜͏͍͏ࣄ৘Ͱ͠ ͨ

Slide 47

Slide 47 text

Enumeratorͷ ͞ΒͳΔൃల

Slide 48

Slide 48 text

Enumeratorͷ͞ΒͳΔൃల • ஗ԆධՁ (Lazy Iterators) • ࣗ༝ͳྻڍ (Freehand Iterators) • ΠςϨʔλͷ࿈࠯ (Chaining Iterators)

Slide 49

Slide 49 text

Lazy Iterators • find, any?, all?ͳͲɺ৚݅ʹ߹͏ʢ߹Θͳ͍ʣཁૉ͕ग़ݱͨ͠Βଧͪ੾Γɺͱ͍͏ Enumerableͷϝιου͕৭ʑ͋Δ • map΍selectΛ࿈࠯ͤ͞Δͱ͖ɺຖճ഑ྻΛ࡞Δͷ͸ۭؒޮ཰͕ѱ͍ • ू໿͍ͨ͠৔߹ɺೖΕ෺Λ༻ҙ͢Δͷ͸࠷ޙ͚ͩͰे෼ͳ͸ͣ • ͦ΋ͦ΋ɺϑΟϧλϦϯά͚͕ͩඞཁͰɺू໿ࣗମ͸ෆཁͳ͜ͱ΋ଟ͍ • [Feature #4653] Enumerable#rude_map by shyouhei (May 2011) • [Feature #4890] Enumerable#lazy by yhara (Jun 2011) • Ruby 1.9.3ʹ͸ؒʹ߹Θͣ (Oct 2011) • Ruby 2.0ͰEnumerable#lazy͓ΑͼEnumerator::Lazy͕࠾༻ (Feb 2013)

Slide 50

Slide 50 text

Freehand Iterators • ΠςϨʔλΛ࣮૷͢Δʹ͸ɺeachϝιουΛఆٛ͢Δɺ͕جຊ • ͦͷ৔ͰEnumerableͳΦϒδΣΫτΛ࡞ͬͯฦ͍ͨ͠ɺͱ͍͏ͱ͖ɺ Object.newͯ͠.extend(Enumerable) ͯ͠ಛҟϝιουeachΛੜ ΍͢ɺͱ͍͏ͷ͸͋·ΓΧδϡΞϧʹ΍Γͨ͘ͳ͍ • EnumeratorΛ࡞ͬͨͱ͖ɺEnumerableͷ֦ுधཁͷύϯυϥͷശΛ։ ͘͜ͱʹͳΔͱ༧ݟͨ͠ "# • ԿͰ΋Ͱ͖Δ΋ͷ΋ඞཁͩΖ͏…ͱ Enumerator.new {} Λ͓·͚ ͰೖΕͨ

Slide 51

Slide 51 text

Chaining Iterators Enumerator#+ ͕΄͍͠ɺͱ͍͏ཁ๬͕དྷͨͱ͖΋… • [Feature #709] Enumerator#+ (Nov 2008) by candlerb ʮ͜ΕͰҰԠͰ͖ΔΑʯ Enumerator.new { |y| collection1.each { |x| y << x } collection2.each { |x| y << x } }.each do |x| # Enumerates collection1, and then collection2 end

Slide 52

Slide 52 text

Chaining Iterators ͱ͍͏Θ͚ͰɺҎԼͷཧ༝͔ΒҰճݟૹΒͤͯ΋Βͬͨ • ԋࢉࢠϝιουΛ͋·Γ҆қʹೖΕΔͱ͋ͱͰଞͷԋࢉࢠͱ ͷ੔߹ੑͰۤ࿑ɾޙչ͢Δ • Ϣʔεέʔε͕Ͳͷ͘Β͍͋Δ͔·ͩ໌Β͔Ͱͳ͍ • ࠓ͸Enumerator.new {}Ͱखॻ͖ͯ͠Ͷ

Slide 53

Slide 53 text

Chaining Iterators, A Decate Later • ͦͯ͠े೥ޙɺࠓ౓͸chainͱ͍͏໊લͰఏҊ͕དྷͨ [Feature #15144] Enumerator#chain (Sep 2018) by zverok • ͦͷࠒʹ͸ɺࢲࣗ਎ͷܦݧ͔Β΋࿈࠯ͷϢʔεέʔε͸۩ ମతʹݟ͍͑ͯͨ !

Slide 54

Slide 54 text

Chaining Iterators, A Decate Later • ૝ఆͰ͖ΔϢʔεέʔε • ྫ: ίϚϯυϥΠϯΦϓγϣϯͰͷࢦఆɺ؀ڥม਺ͷ஋ɺઃఆϑΝΠϧ಺ͷઃఆ ஋ɺͷॱʹݕࡧύεΛฦ͢ • ྫ: ࠷৽ͷߋ৽σʔλΛAPI͔ΒҾͬுͬͯฦ͠ɺଓ͍ͯϩʔΧϧετϨʔδʹ Ωϟογϡ͞Εͨ෦෼Λฦ͠ɺ͞ΒʹͦΕҎલͷ΋ͷ͕ඞཁͳΒAPI͔ΒҾ͍ͯฦ͢ • first(3), take_while, find ͳͲͰޮՌΛൃش • ୯७ʹɺ഑ྻΛ࡞Δ͜ͱͳ͘ෳ਺ͷετϦʔϜΛॱ࣍૸͍ࠪͨ͜͠ͱ͸࣮ࡍʹଟ͍ • શ߲໨૸ࠪ͢Δ৔߹Ͱ΋ޮ཰త ✨

Slide 55

Slide 55 text

Chaining Iterators, A Decate Later • MatzΛަ͑ͨٞ࿦Ͱ΋ɺ Enumerator#+ ΛׂΓ౰ͯͯ΋໰ ୊ͳ͔Ζ͏ ! ͱͳͬͨ • chain ͸ Enumerable ʹ͋ͬͯ΋͍͍ΑͶɺͱͳΓɺ͋Θ ͤͯRuby 2.6Ͱ࠾༻ "

Slide 56

Slide 56 text

Example: chain + each_cons = Contexual Iteretion a = ["foo", "bar", "baz"] [nil].chain(a).each_cons(2) do |prev, curr| if prev.nil? puts "#{curr} comes first." else puts "#{curr} comes after #{prev}." end end # Output: foo comes first. bar comes after foo. baz comes after bar.

Slide 57

Slide 57 text

Ruby 2.7Ҏ߱ͷ ల๬ͱ՝୊

Slide 58

Slide 58 text

Ruby 2.7Ҏ߱ͷల๬ͱ՝୊ • Enumerator::Yielder#to_proc • Enumerator.generate • Multi-Value Or Array? • Lazy: Back To Eager?

Slide 59

Slide 59 text

Enumerator::Yielder# to_proc

Slide 60

Slide 60 text

Enumerator::Yielder#to_proc • [Feature #15618] Enumerator::Yielder#to_proc (Feb 2019) by knu Enumerator#to_procΛ࣮૷͢Δ͜ͱͰ enum = Enumerator.new { |y| Dir.glob("*.rb") { |file| File.open(file) { |f| f.each_line(&y) } # File.open(file) { |f| f.each_line { |line| y << line } } } } ͱॻ͚ΔΑ͏ʹ͢ΔఏҊ • Ruby 2.7Ͱ࠾༻ !

Slide 61

Slide 61 text

Enumerator.generate

Slide 62

Slide 62 text

Enumerator.generate • [Feature #14781] Enumerator.generate (May 2018) by zverok • Ұͭલͷ஋͔Β࣍ͷཁૉΛܾఆ͢Δ܁Γฦ͠ • ਺ֶͰ͍͏ʮ઴ԽࣜʯʹΑΔ܁Γฦ͠ఆٛ • ϊʔυͷ parent ΛॱʹḷΔͱ͔ • ϦτϥΠͷ଴ͪ࣌ؒΛഒʑʹ͍ͯ͘͠ͱ͔ • ݕ౼ࣄ߲ • ऴྃ৚݅ͷࢦఆํ๏ʢಛఆͷྫ֎ͰऴΘΔͷ͔ɺnilͰऴΘΔͷ͔ɺͦͷ৔߹nilΛؚΉͷ͔ʣ • 2ͭҎ্લ΋ࢀর͍ͨ͠ʁʢྫ: ϑΟϘφον਺ྻ… ͋·Γݱ࣮ʹ͸ͳ͍ʁʣ

Slide 63

Slide 63 text

Multi-Value Or Array?

Slide 64

Slide 64 text

Multi-Value Or Array? • Hash#each / map ͸ϖΞΛ1Ҿ਺Ͱ2ཁૉ഑ྻΛϒϩοΫʹ౉ͯ͘͠Δ [1] pry(main)> {foo: 1, bar: 2, baz: 3}.each{|x| p x} [:foo, 1] [:bar, 2] [:baz, 3] => {:foo=>1, :bar=>2, :baz=>3} [2] pry(main)> {foo: 1, bar: 2, baz: 3}.map{|x| p x} [:foo, 1] [:bar, 2] [:baz, 3] => [[:foo, 1], [:bar, 2], [:baz, 3]]

Slide 65

Slide 65 text

Multi-Value Or Array? • Hash#select / reject ͸ϖΞΛ2Ҿ਺ͰϒϩοΫʹ౉ͯ͘͠Δ [3] pry(main)> {foo: 1, bar: 2, baz: 3}.reject{|x| p x} :foo :bar :baz => {} [4] pry(main)> {foo: 1, bar: 2, baz: 3}.select{|x| p x} :foo :bar :baz => {:foo=>1, :bar=>2, :baz=>3}

Slide 66

Slide 66 text

Multi-Value Or Array? • ͜ͷҧ͍͸Ͳ͔͜Βʁ • Hash#each / map ͸ϖΞΛ2ཁૉ഑ྻ1ͭΛϒϩοΫʹ౉ͯ͘͠Δ (yield [key, value]) • Hash#select / reject ͸ϖΞΛ2Ҿ਺ͰϒϩοΫʹ౉ͯ͘͠Δ (yield key, value) • Hash#select / reject ͸ɺRuby 1.8·Ͱ͸ArrayΛฦ͢ϝιου͕ͩͬͨɺ1.9͔ ΒHashΛฦ͢Α͏ʹมߋ͞Εͨ • ͦͷͱ͖ʹɺҙਤ͔ͯ͠஌Β͔ͣ2Ҿ਺Ͱ౉͢Α͏ʹͳͬͨ • ࠓ͞Β௚ͤͳ͍ͱͯ͠ɺmulti-value㱻arrayͷ૬ޓม׵͸धཁ͕͋Δ͔΋

Slide 67

Slide 67 text

Multi-Value Or Array? • λϓϧͷ֤ཁૉʹରͯ͠ɺͦΕͧΕϝιουΛద༻͢Δྫ require "csv" line = "10,foo,3.14" modifiers = [:to_i, :to_s, :to_f] # "10".send(:to_i), "foo".send(:to_s), "3.14".send(:to_f) Λظ଴… p CSV.parse_line(line).zip(modifiers).map(&:send) #=> no method name given (ArgumentError) • ࣮ࡍʹ͸ ["10", :to_i].send, … ͕࣮ߦ͞Εͯ͠·͏

Slide 68

Slide 68 text

Multi-Value Or Array? ΋͠array→multi-valueʹม׵͢Δػೳ͕͋Ε͹… module Enumerable def each_splat return to_enum(__method__) unless block_given? each { |a| yield(*a) } end end

Slide 69

Slide 69 text

Multi-Value Or Array? ͏·͍͘͘ ! require "csv" line = "10,foo,3.14" modifiers = [:to_i, :to_s, :to_f] p CSV.parse_line(line).zip(modifiers).each_splat.map(&:send) #=> [10, "foo", 3.14]

Slide 70

Slide 70 text

ͪͳΈʹ… • CSVʹ͸convertersͱ͍͏͢͹Β͍͠ػೳ͕͋Γ·͢ʂ line = "10,foo,3.14" modifiers = [:to_i, :to_s, :to_f] p CSV.parse_line(line, converters: ->(value, field) { value.send(modifiers[field.index]) }) #=> [10, "foo", 3.14] • ͱ͍͏Θ͚Ͱઆಘʹ࢖͏ʹ͸ద͞ͳ͍ϢʔεέʔεͰͨ͠

Slide 71

Slide 71 text

Lazy: Back To Eager?

Slide 72

Slide 72 text

Lazy: Back To Eager? • Ұ౓lazyʹ͢Δͱɺී௨ͷ(eagerͳ)Enumeratorʹ͸໭ͤͳ͍ lazy = [1, 2, 3].lazy # Expecting #each would create a normal Enumerator... still_lazy = lazy.each # Not: Enumerator::Lazy#each is overridden to return a Lazy # Not usable as a normal Enumerator p still_lazy.map { |x| x * 2 } #=> #:map> • lazyΛۦ࢖ͯ͠࡞ͬͨEnumeratorΛɺmap͢Δͱ഑ྻ͕ฦΔΑ͏ͳ;ͭ͏ͷEnumerableΦϒδΣΫτ ͱͯ͠ฦ͍ͨ͠

Slide 73

Slide 73 text

Enumerator::Lazy#eager (Ҋ) ΋͠lazyͰͳ͍Enumeratorʹม׵͢Δػೳ͕͋Ε͹… class Enumerator::Lazy def eager Enumerator.new { |y| each { |x| y << x } } end end

Slide 74

Slide 74 text

Lazy: Back To Eager? ͏·͍͘͘ ! lazy = [1, 2, 3].lazy eager = lazy.eager # Usable as a normal enumerable object p eager.map { |x| x * 2 } #=> [2, 4, 6]

Slide 75

Slide 75 text

·ͱΊ

Slide 76

Slide 76 text

·ͱΊ • ΈΜͳେ޷͖Enumerable͸ͲΜͲΜਐԽ͖ͯ͠·ͨ͠ɻ • EnumeratorͷಋೖʹΑΓɺ७ਮʹ܁Γฦࣗ͠ମͷݚڀ͕ਐΈ·ͨ͠ɻ • ࠓ΋ਐԽ͍ͯ͠·͢ʂ • ࠓޙ΋ɺݱ࣮ͷχʔζΛ౿·͑ͯʮ΄͍͠ʂʯػೳΛ֦ॆ͍͖ͯ͠·͢ʂ • ࠷ۙ͸RubyͷϦϦʔεαΠΫϧ͕ߴ଎Խ͍ͯ͠ΔͷͰɺ͋ͳͨ΋ཁ๬Λग़ͤ͹ ೥຤ʹ͸۩ݱԽ͢Δ͔΋ʂ • ΫϦεϚεϓϨθϯτ ! • ϚνϚνͰҰॹʹಇ͘஥ؒΛืू͍ͯ͠·͢ʂ