Slide 1

Slide 1 text

Rubyʹܕ͕͋Δͱ ศ ར ͔ ೋʓҰ࿡೥ ޒ݄ೋेീ೔ ౦ژRubyձٞ11 ksss

Slide 2

Slide 2 text

p self Yuki Kurihara ! ksss " @_ksss_ RubyKaja 2014 (Asakusa.rb) Ұࣇͷύύ

Slide 3

Slide 3 text

spicelife

Slide 4

Slide 4 text

झຯ == Hacking ! ksss/AsciiPack ! ksss/digest-murmurhash ! ksss/rgot ! ksss/mruby-file-stat ! ksss/active_tsv

Slide 5

Slide 5 text

ܕ

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

ܕͱݴͬͯ΋͍Ζ͍Ζ͋Δ

Slide 8

Slide 8 text

Rubyʹܕ͕͋Δͱศར͔ RubyͰclassνΣοΫ͢Δͱ w w w w w w w w w w w ศར͔

Slide 9

Slide 9 text

RubyͰclassνΣοΫ

Slide 10

Slide 10 text

String === "hello" #=> true String === 123 #=> false String === nil #=> false RubyͰClassνΣοΫ

Slide 11

Slide 11 text

͜Ε·ͰͷRubyͰͷ࣮૷ྫ ! gogotanaka/Rubype ! egonSchiele/contracts.ruby def sum(x, y) x + y end typesig :sum, [Numeric, Numeric] => Numeric

Slide 12

Slide 12 text

TypeStruct ! ksss/type_struct

Slide 13

Slide 13 text

First Issue σʔλͷմ͚ͩΛද͢class͕΄͔ͬͨ͠ ͍͍࣮ͪͪ૷͢Δͷ͕ΊΜͲ͍͘͞ ݁ߏ௕ੜ͖͢Δ ·͕ͪͬͯ࢖ΘΕΔͱࠔΔ Keyword argument͕࢖͑ΔStruct

Slide 14

Slide 14 text

TypeStruct Α͏͸ΦϨΦϨStruct `new`ͰKeyword argument͕࢖͑Δ C΍GolangͷΑ͏ͳܕه๏

Slide 15

Slide 15 text

Struct͓͞Β͍ User = Struct.new( :name, :age, :type, ) user = User.new( "ksss", 29, "normal", ) user.name #=> "ksss"

Slide 16

Slide 16 text

TypeStruct User = TypeStruct.new( name: String, age: Integer, type: /\A(genius|normal)\z/ ) user = User.new( name: "ksss", age: 29, type: "normal" ) user.name #=> "ksss"

Slide 17

Slide 17 text

TypeStruct name: String, name: "ksss", String === "ksss" #=> true

Slide 18

Slide 18 text

TypeStruct age: Integer, age: 29, Integer === 29 #=> true

Slide 19

Slide 19 text

TypeStruct type: /\A(genius|normal)\z/ type: "normal" /\A(genius|normal)\z/ === "normal" #=> true

Slide 20

Slide 20 text

TypeStruct νΣοΫ͸஋͕มΘΔ͚࣌ͩ νΣοΫ͕௨Βͳ͔ͬͨΒଈ࠲ʹΤϥʔ User = TypeStruct.new( name: String, age: Integer, ) User.new(name: "ksss", age: "30") #=> TypeError user.age = "30" #=> TypeError

Slide 21

Slide 21 text

Kernel#===ศར Rubyͷ΄ͱΜͲͷObjectͰΑ΂Δ (BasicObjectҎ֎) Rubyͷclassܧঝߏ଄͕࢖͑Δ Numeric === 1(Integer) or 1.23(Float) ͳΜͰ΋Α͚Ε͹ `Object`

Slide 22

Slide 22 text

TypeStruct ਖ਼௚͜Ε͚ͩͰ͸ࣗ෼Ͱ΋࢖Θͳ͔ͬͨ ͋·Γ࢖͍Έ͕ͪͳ͍ ͜Ε͚ͩͷͨΊʹgemΛೖΕͳͯ͘΋

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

Second Issue JSONΛѻ͏ϓϩάϥϜΛॻ͘ͷ͕ΊΜͲ͘ ͍͞

Slide 25

Slide 25 text

Second Issue { "object": { "object_id" 123, "contents": [ { "content_id": 234, "items": [ { "type": "image", "image_id": 10, "position": { "x": 100, "y": 200, } }, { "type": "text", "font_id": 20, "position": { "x": 300, "y": 400, } "option": {} }]}]}}

Slide 26

Slide 26 text

Second Issue json["object"]["contents"].each do |content| content["items"].each do |item| case item["type"] when "image" image_id = item["image_id"] x = item["position"]["x"] # ... when "text" # ... end end end

Slide 27

Slide 27 text

Second Issue json.fetch("object").fetch("contents").each do |content| content.fetch("items").each do |item| case item.fetch("type") when "image" image_id = item.fetch("image_id") x = item.fetch("position").fetch("x") # ... when "text" # ... end end end

Slide 28

Slide 28 text

Second Issue

Slide 29

Slide 29 text

Second Issue typo͕͜Θ͍ ίʔυ͕ಡΈʹ͍͘ Ͳ͏͍͏ϝιου͕࢖͑Δͷ͔Θ͔Βͳ͍ nil͸͋Γ͑Δͷ͔ͳͲ͕Θ͔Βͳ͍ ଞͷݴޠ͸Ͳ͏ͯ͠Δʁ

Slide 30

Slide 30 text

Golang JSON type Point struct { X int `json:"x"` Y int `json:"y"` } type Line struct { P1 Point `json:"p1"` P2 Point `json:"p2"` } func main() { const input = `{"p1":{"x":10,"y":20},"p2":{"x":30,"y":40}}` var line Line json.NewDecoder(strings.NewReader(input)).Decode(&line) fmt.Println(line.P2.Y) //=> 40 }

Slide 31

Slide 31 text

Crystal JSON class Point JSON.mapping({ x: Int64, y: Int64, }) end class Line JSON.mapping({ p1: Point, p2: Point, }) end input = %({"p1":{"x":10,"y":20},"p2":{"x":30,"y":40}}) line = Line.from_json(input) puts line.p2.y #=> 40

Slide 32

Slide 32 text

Second Issue RubyͰJSON(Hash)ΛStructԽ͢Δ JSON.parse(json, object_class: Foo)ͩͱɺ࠶ ؼతʹॻ͘ͷ͕໘౗ ͳΜ͔͖ͬ͞ͷه๏ɺ࠷ۙݟͨͧ……ʁ TypeStructʹػೳ௥Ճͯ͠ΈΕ͹͍͍ͷͰ͸ʂ

Slide 33

Slide 33 text

Second Issue

Slide 34

Slide 34 text

TypeStruct.from_hash Point = TypeStruct.new( x: Integer, y: Integer, ) Line = TypeStruct.new( p1: Point, p2: Point, ) input = %({"p1":{"x":10,"y":20}, "p2":{"x":30,"y":40}}) line = Line.from_hash(JSON(input)) puts line.p2.y #=> 40

Slide 35

Slide 35 text

{ "object": { "object_id" 123, "contents": [ { "content_id": 234, "items": [ { "type": "image", "image_id": 10, "position": { "x": 100, "y": 200, } }, { "type": "text", "font_id": 20, "position": { "x": 300, "y": 400, } "option": {} }]}]}} TypeStruct

Slide 36

Slide 36 text

TypeStruct Position = TypeStruct.new( x: Numeric, y: Numeric, ) Text = TypeStruct.new( font_id: Integer, position: Position, option: Option, ) Image = TypeStruct.new( image_id: Integer, position: Position, ) Content = TypeStruct.new( content_id: Integer, items: ArrayOf(Image | Text), ) Obj = TypeStruct.new( object_id: Integer, contents: ArrayOf(Content), )

Slide 37

Slide 37 text

TypeStruct json.object.contents.each do |content| content.items.each do |item| case item when Image image_id = item.image_id x = item.position.x # ... when Text # ... end end end

Slide 38

Slide 38 text

TypeStruct ΈͨΊΑ͠ ҆৺ײ͕͋Δ શͯͷJSONίʔυΛTypeStructʹ͓͖͔͑ ΕΔͷͰ͸ʁ ͍͔ͭ͘ͷ໰୊఺

Slide 39

Slide 39 text

~4ͭͷissueͱ4ͭͷclass~ TypeStruct

Slide 40

Slide 40 text

[ {"slime": "A"}, {"slime": "B"}, {"slime": "C"} ] Arrayがあらわれた!

Slide 41

Slide 41 text

Array? Slime = TypeStruct.new( slime: String ) Encount = TypeStruct.new( enemies: Array # []Slime )

Slide 42

Slide 42 text

Golang & Crystal class Encount JSON.mapping({ enemies: Array(Slime) }) end type Encount struct { Enemies []Slime }

Slide 43

Slide 43 text

ArrayOf

Slide 44

Slide 44 text

ArrayOf Encount = TypeStruct.new( enemies: ArrayOf(Slime) ) encount = Encount.from_hash( enemies: [ {"slime": "A"}, {"slime": "B"}, {"slime": "C"} ] ) encount.enemies #=> [#, #, #]

Slide 45

Slide 45 text

ArrayOf class ArrayOf def initialize(type) @type = type end def ===(ary) ary.all? { |o| @type === o } end end

Slide 46

Slide 46 text

ArrayOf ͘͠Έ͸୯७ ʮ***ͷArrayʯΛදݱͰ͖Δ ͜Ε͚ͩͰ΋࢖͑Δ͔΋ʁ case ary when ArrayOf(String) # ... when ArrayOf(Regexp)

Slide 47

Slide 47 text

{ "1": {"slime": "A"}, "2": {"slime": "B"}, "3": {"slime": "C"} } Hashがあらわれた!

Slide 48

Slide 48 text

Hash? Encount = TypeStruct.new( enemies: Hash )

Slide 49

Slide 49 text

Golang & Crystal class Encount JSON.mapping({ enemies: Hash(String, Slime) }) end type Encount struct { Enemies map[string]Slime }

Slide 50

Slide 50 text

HashOf

Slide 51

Slide 51 text

HashOf Encount = TypeStruct.new( enemies: HashOf(String, Slime) ) encount = Encount.from_hash( enemies: { "1" => {"slime": "A"}, "2" => {"slime": "B"}, "3" => {"slime": "C"} } ) encount.enemies.each do |index, slime|

Slide 52

Slide 52 text

HashOf class HashOf def initialize(key_type, value_type) @key_type = key_type @value_type = value_type end def ===(h) h.all? do |k, v| @key_type === k && @value_type === v end end end

Slide 53

Slide 53 text

Booleanがあらわれた! Nullがあらわれた! [ true, false, null ]

Slide 54

Slide 54 text

Golang & Crystal type Figure struct { Show bool } class Figure JSON.mapping({ show: Bool }) end

Slide 55

Slide 55 text

include Boolean? module Boolean end class TrueClass include Boolean end class FalseClass include Boolean end Boolean === true #=> true Boolean === false #=> true Boolean === Object.new #=> false

Slide 56

Slide 56 text

Null type Canvas struct { item: Item } class Canvas item: { type: Item, nilable: true } end

Slide 57

Slide 57 text

Slimeがあらわれた! [ {"slime": "A"}, {"name": "drakee"}, {"hp": 100, "type": "Golem"} ] Drakeeがあらわれた! Golemがあらわれた!

Slide 58

Slide 58 text

Slide 59

Slide 59 text

Union

Slide 60

Slide 60 text

Union class Union def initialize(*classes) @classes = classes end def ===(obj) @classes.any? { |c| c === obj } end end

Slide 61

Slide 61 text

Union module Ext refine Class do def |(other) Union.new(self, other) end end end using Ext

Slide 62

Slide 62 text

Union Integer | String # 123 or "hi" TrueClass | FalseClass # true or false ArrayOf(Item) | NilClass # [Item] or nil ArrayOf(Slime | Drakee | Golem) # [Slime or Drakee or Golem]

Slide 63

Slide 63 text

Union Crystalͷจ๏͔Βഈआ `Class#|`Λఆٛ͢ΔͱͦΕͬΆ͘ͳΔ ޙʹ໰୊ࣇͱͳΔ

Slide 64

Slide 64 text

ダックタイピングがあらわれた!

Slide 65

Slide 65 text

Interface

Slide 66

Slide 66 text

Interface class Interface def initialize(*methods) @methods = methods end def ===(other) @methods.all? do |m| other.respond_to?(m) end end end

Slide 67

Slide 67 text

Interface Reader = Interface.new(:read) Writer = Interface.new(:write) Stream = TypeStruct.new( input: Reader, output: Writer, ) Stream.new(input: $stdin, output: StringIO.new)

Slide 68

Slide 68 text

Interface μοΫλΠϐϯά༻ golangͷΑ͏ʹclassͱͷґଘΛͳ͍ͨ͘͠ ϝιου͕ఆٛ͞Ε͍ͯΔ͔͚ͩΛνΣοΫ ࡞ͬͯΈ͚ͨͲͦΜͳʹ࢖͏৔໘͕ࢥ͍ු͔͹ͳ ͍(·͓ͩͨͤͯͳ͍) ར༻γʔϯΛ໛ࡧத

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

TypeStructͷϝϦοτ JSONΛTypeStructʹ౰ͯ͸ΊΔ͜ͱ͕Ͱ͖Δ StructͷϝϦοτ͸ͦͷ··ڗड typoରࡦ, ίʔυͷݟͨ໨, σόοάͷ͠΍ ͢͞ ୯७ͳ࡞ΓͳͷͰɺগͣͭ͠ಋೖ΋Ͱ͖Δ

Slide 71

Slide 71 text

TypeStructͷϝϦοτ ಈ࡞͢ΔυΩϡϝϯτͱͯ͠ศར هԱʹཔΒͳ͍͍ͯ͘ ৽ਓ͔Βͷʮ͜ͷJSONͬͯͲ͏͍͏ߏ଄͕͋ Γ͑ΔΜͰ͔͢ʁʯͱ͍͏࣭໰ʹଈ౴Ͱ͖Δɻ PRͰܕͷมߋ఺Λٞ࿦Ͱ͖Δ

Slide 72

Slide 72 text

TypeStructͷσϝϦοτ Union͸ॾਕͷ݋ σόοά͕͠ʹ͘͘ͳΔ ͍͋·͍͕͞࢈·ΕΔ ܕΛॻ͘ͷ͕ΊΜͲ͍͘͞ ͪΐͬͱͨ͠΋ͷΑΓɺෳ਺ਓͰͷ։ൃ޲͖

Slide 73

Slide 73 text

TypeStruct·ͱΊ ݱঢ়͸JSONΛclassνΣοΫͭͭ͠Objectʹ ͢Δ΋ͷͱͯ͠࢖͍ͬͯΔ ෳ਺ਓͰΧονϦͱ࡞ΔͷʹΉ͍ͯΔ Scope͕޿͍৔߹ʹศར

Slide 74

Slide 74 text

࣮૷Ͱ໎ͬͨॴ nilΛڐՄ͢΂͖͔ɺͤ͟Δ΂͖͔ UnionΛڐ͢΂͖͔ ࣮૷ଆ΋࢖͏ଆ΋ෳࡶʹͳΔ crystal΍golangͰ͸ɺJSONม׵ʹ͸࢖͑ͳ͘ͳ͍ͬͯΔ nilͱBoolean͑͞ͳΜͱ͔ͳΕ͹ɺ͍Βͳ͍͔΋ ҉໧ͷม׵Λ͢΂͖͔

Slide 75

Slide 75 text

Rubyʹܕ͕͋Δͱ ศར͔ʁ

Slide 76

Slide 76 text

ศར

Slide 77

Slide 77 text

Ruby3

Slide 78

Slide 78 text

Ruby3 http://www.slideshare.net/yukihiro_matz/ feeding-the-sharks/143 http://www.atdot.net/~ko1/activities/ 2016_RubyConfLT_pub.pdf

Slide 79

Slide 79 text

※ Ruby3ͷܕ͸ ࠓճͷൃදͷΑ͏ͳ΋ͷͱ͸ શ͘ҧ͍·͢

Slide 80

Slide 80 text

Ruby3(ͷల๬Λฉ͍ͨ࿩) ੩తνΣοΫ => method͕ݺ΂Δ͔ͷࣄલcheck RubyϨϕϧͰ͸AnnotationΛॻ͔ͳ͍ => def meth(arg : Foo)Έ͍ͨͳ͜ͱ͸͠ͳ͍ CϨϕϧͷmethod͸શ෦AnnotationΛॻ͘ => େมͦ͏ɻɻɻ

Slide 81

Slide 81 text

͜Ε͔Β ੩తղੳ͸௅ઓͯ͠Έ͍ͨ TAPLಡΉͷ͕Μ͹Δ Rubyͷ͘͠ΈΛֶͿ ଞͷݴޠʹ΋৮Ε͍ͯ͘

Slide 82

Slide 82 text

͓ΘΓ