Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rubyの拡張をCrystalで書いてみる

 Rubyの拡張をCrystalで書いてみる

Tokyo Crystal Meetup #3 (2016-01-22)

E3d8c68398580685ee7ef4ec2cc1cfc2?s=128

Hirofumi Wakasugi

January 22, 2016
Tweet

Transcript

  1. 3VCZͷ֦ுΛ $SZTUBMͰॻ͍ͯΈΔ Writing Ruby extension with Crystal Hirofumi Wakasugi (@5t111111)

  2. /BUJWF&YUFOTJPO Fetching: nokogiri-1.6.7.1.gem (100%) Building native extensions. This could take

    a while... w ಛʹ࣮ߦ଎౓͕ॏཁͳॲཧΛ$Ͱॻ͘͜ͱ͕Ͱ͖Δ w طଘͷ$ϥΠϒϥϦΛར༻͢Δ͜ͱ͕Ͱ͖Δ 3VCZ͸$ݴޠͰ֦ுϥΠϒϥϦΛॻ͘͜ͱ͕Ͱ͖Δ
  3. $SZTUBM$-JCSBSZ#JOEJOHT lib LibC fun pow(x: Float64, y: Float64) : Float64

    fun sqrt(val: Float64) : Float64 end puts(LibC.pow(10, 10)) puts(LibC.sqrt(4)) end $SZTUBMͰ$ͷόΠϯσΟϯάΛॻ͘ͷ͸ͱͯ΋؆୯
  4. ͏ΜɺͦΕͳΒ $SZTUBMͰ3VCZͷ֦ுॻ͚ͦ͏ʂ

  5. def fibonacci(n) return n if n <= 1 fibonacci(n -

    1) + fibonacci(n - 2) end ·ͣɺ͜ͷ୯७ͳϑΟϘφον਺ྻͷؔ਺Λ 3VCZ֦ுϥΠϒϥϦͱͯ͠$SZTUBMͰॻ͖·͢ &YBNQMF
  6. lib LibRuby type VALUE = Void* $rb_cObject : VALUE fun

    rb_define_global_function(name : UInt8*, func : VALUE, VALUE -> VALUE, argc : Int32) fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE end def fibonacci_cr(self : LibRuby::VALUE, value : LibRuby::VALUE) int_value = LibRuby.rb_num2int(value) LibRuby.rb_int2inum(fibonacci_cr2(int_value)) end def fibonacci_cr2(n) return n if n <= 1 fibonacci_cr2(n - 1) + fibonacci_cr2(n - 2) end fun init = Init_extension_with_crystal GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) LibRuby.rb_define_global_function("fibonacci_cr", ->fibonacci_cr, 1); end &YBNQMFpCPCBDDJ@DS
  7. user system total real fibonacci (ruby) 16.760000 0.040000 16.800000 (

    16.963310) fibonacci (crystal) 0.830000 0.010000 0.840000 ( 0.827128) ͏Μɺ଎͍ &YBNQMF
  8. class Takeuchi def self.tarai(x, y, z) if y < x

    tarai( tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y) ) else y end end end ͨΒ͍ճؔ͠਺΋ॻ͍ͯΈ·͢ &YBNQMF
  9. lib LibRuby type VALUE = Void* $rb_cObject : VALUE fun

    rb_define_class(name : UInt8*, super : VALUE) : VALUE fun rb_define_module_function(klass : VALUE, name : UInt8*, func : VALUE, VALUE, VALUE, VALUE -> VALUE, argc : Int32) fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE end def tarai(self : LibRuby::VALUE, x : LibRuby::VALUE, y : LibRuby::VALUE, z : LibRuby::VALUE) int_x = LibRuby.rb_num2int(x) int_y = LibRuby.rb_num2int(y) int_z = LibRuby.rb_num2int(z) LibRuby.rb_int2inum(tarai2(int_x, int_y, int_z)) end def tarai2(x, y, z) if y < x tarai2( tarai2(x - 1, y, z), tarai2(y - 1, z, x), tarai2(z - 1, x, y) ) else y end end fun init = Init_extension_with_crystal GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) rb_class_takeuchi = LibRuby.rb_define_class("TakeuchiCr", LibRuby.rb_cObject) LibRuby.rb_define_module_function(rb_class_takeuchi, "tarai", ->tarai, 3); end &YBNQMF5BLFVDIJ$SUBSBJ
  10. user system total real tarai (ruby) 19.810000 0.050000 19.860000 (

    20.248620) tarai (crystal) 0.970000 0.000000 0.970000 ( 0.998764) ͏Μɺ଎͍ &YBNQMF
  11. ͋͞ɺͭΒ͍ͷ͸͔͜͜Β

  12. 5TVSBNJ person = LibRuby.rb_define_class("Person", LibRuby.rb_cObject) LibRuby.rb_define_method(person, "Hello", ->hello, 1); w

    $SZTUBMͷදݱྗΛ׆༻͢Δ͜ͱ͕೉͍͠ w ن໛͕େ͖͘ͳͬͯ͘Δͱ͔ͳΓݟ௨͕͠ѱ͘ͳΔ ݁ہɺී௨ʹ࢖͏ͱ$"1*ͷόΠϯσΟϯάͰ͔͠ͳ͍
  13. 5TVSBNJ #define RB_FIX2LONG(x) ((long)RSHIFT((SIGNED_VALUE)(x),1)) #define StringValuePtr(v) rb_string_value_ptr(&(v)) w $͔ΒѻΘͳ͍৔߹γϯϘϧΛએݴ͢Δͷ͕େม w

    ຖճʮSVCZIʯͱ͔Λ͕Μ͹ͬͯಡΉ͜ͱʹͳΔ 3VCZ$"1*Ͱ͸ϚΫϩ͕ଟ༻͞ΕΔ
  14. 5TVSBNJ fun rb_define_method(klass : VALUE, name : UInt8*, func :

    VALUE, VALUE -> VALUE, argc : Int32) w ؔ਺ͷܕΛࢦఆ͢Δඞཁ͕͋Δ w ͜ΕҎ֎ͷܕͷؔ਺Λ౉͢ͱίϯύΠϧΤϥʔ 3VCZ$"1*ؔ਺ͷҾ਺͕ؔ਺ϙΠϯλͷͱ͖ʜ
  15. DSZTUBM@SVCZ 8SJUF3VCZFYUFOTJPOTJO$SZTUBM IUUQTHJUIVCDPNNBOBTUFDIDSZTUBM@SVCZ w ެࣜʹΑΔʮ1SPPGPG$PODFQUʯ w ҙࣝߴ͍ w ࠷৽ͷ$SZTUBMͰ͸ಈ͔͢ͷʹͪΐͬͱमਖ਼͕ཁΔ

  16. 1SPPGPG$PODFQU 1P$ ruby_extension "test_ruby", class Foo def foo(a) "From Crystal!!

    #{a}" end end SVCZ@FYUFOTJPOϚΫϩͰίʔυ จࣈྻ Λॲཧ ϚΫϩʹ౉͞Εͨίʔυ͸1BSTFSͰύʔε͞ΕΔ
  17. 1SPPGPG$PODFQU 1P$ class MyVisitor < Visitor … def visit(node :

    ClassDef) @str << %(_class = Ruby::Class.new "#{node.name}"\n) end def visit(node : Def) @str << %(_class.def "#{node.name}", #{node.args.size}, ) @str << %[->(self : LibRuby::VALUE, ] node.args.each do |arg| @str << %(_#{arg.name} : LibRuby::VALUE, ) … end … end "45ϊʔυ͸7JTJUPSΛܧঝͨ͠ΫϥεͰॲཧ͞ΕΔ ؔ਺ϙΠϯλ͸ܕΛ7PJE Ͱఆ͓͍ٛͯͯ͠ɺ͜͜Ͱ۩ମతͳܕͱͯ͠ઃఆ͞ΕΔ
  18. ·ͱ΋ʹಈ͔ͳ͍͚Ͳҙࣝߴ͍1P$

  19. .BUPNF w 3VCZͷ֦ுΛ$SZTUBMͰॻ͚Δɺ͕ී௨ʹॻ͘ͱͭΒ͍ w Ͱ΋ɺ$SZTUBMͰ֦ுΛॻ͘ར఺͸େ͖͍ ‣ ΍ͬͺΓ଎͍ ‣ 3VCZͷγϯλοΫεͱඇৗʹ͍ۙ w

    ެ͕ࣜ3VCZͷ֦ுʹରͯ͠ੵۃత
  20. ޚ੩ௌ ༗೉͏ޚ࠲͍·ͨ͠ ຊεϥΠυதͷαϯϓϧίʔυ ͓Αͼͦͷग़ྗ಺༰͸ ͢΂ͯ$SZTUBMͰ֬ೝ͍ͯ͠·͢ LIVE FOREVER