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

Namespace on read

Namespace on read

Ruby Association Grant Project "Namespace on read" Report at Ruby Association Activity Report 2024

Satoshi Tagomori

July 21, 2024
Tweet

More Decks by Satoshi Tagomori

Other Decks in Programming

Transcript

  1. ϓϩδΣΫτৄࡉ͓Αͼ೔ఔ 2023/10 ʙ 2024/03 • 2023/10/25ɿ ϓϩδΣΫτ࠾୒௨஌
 ϝϯλʔܾఆ(·ͭ΋ͱΏ͖ͻΖ͞Μ) • 2023/10/26

    ʙ 2023/03/20ɿϓϩδΣΫτਐߦ • ػೳৄࡉͷݕ౼ • ֦ுϥΠϒϥϦͷγϯϘϧղܾ༻ C API ௥Ճ (Ruby 3.3) • ࣮૷ํ๏ͷݕ౼͓Αͼ࣮૷ • 2024/01/11ɿ தؒใࠂఏग़ • 2024/03/20ɿ ࠷ऴใࠂఏग़
  2. Namespace Separating apps/libs into isolated spaces • Load apps/libs in

    a space • Hide changes from apps/libs in a namespace to other spaces • Run methods de fi ned in a space with de fi nitions in the space
  3. Before Namespace: Global Only All classes/modules are shared in the

    entire Ruby process Ruby Process Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7)
  4. Collision: 2 versions of 1 library cause errors Ruby Process

    Library Code DB::Client (v3) 😵 Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Before Namespace: Global Only
  5. Ruby Process Namespace Load apps/libs in a space Namespace Application

    Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7)
  6. Ruby Process Namespace Hide changes from apps/libs in a namespace

    to other spaces Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Library Code DB::Client (v3) 😀
  7. Ruby Process Namespace Run methods de fi ned in a

    space with de fi nitions in the space Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Namespace Library Code DB::Client (v3) Namespace Application Code App::Func2 User Library Code ActiveSupport (v6) Application Code call call call
  8. ػೳৄࡉͷݕ౼ ݴޠػೳͱͯ͠ͷNamespaceͷઃܭ • ϝϯλʔ(·ͭ΋ͱ͞Μ)ͱٞ࿦ • Namespaceͱ͸Կ͔? ԿͰ͋Δ΂͖͔? ԿͳΒ࣮ݱՄೳ͔? • ҆қʹͰ͖ͦ͏ͳ࣮૷ҊʹҾ͖ͣΒΕͳ͍Α͏ʹ஫ҙ͢Δඞཁ͕͋ͬͨ

    • ػೳɿ Մೳੑͱ࣮ͯ͠૷Ͱ͖ͦ͏ͳػೳΛ࠷େݶϦετΞοϓ • ࣮ݱՄೳੑ͸ͦͷޙͰ୳Δ • είʔϓͱAPIɿ ࣮༻έʔεΛ૝ఆͯ͠Ͳ͏͋Δ΂͖͔Λߟ͑Δ
  9. ػೳৄࡉͷݕ౼ ࣮૷͢΂͖ػೳ • require/load .rb • require/load .so • autoload

    • eval • proc, lambda • Ϋϥε΍Ϟδϡʔϧͷఆٛ • ૊ࠐΈΫϥεͷมߋ • include/prepend • τοϓϨϕϧϝιουఆٛ • άϩʔόϧม਺ͷมߋɺ௥Ճ • ఆ਺ͷมߋɺ௥Ճ • ΫϥεΠϯελϯεม਺ͷมߋɺ௥Ճ • Ϋϥεม਺ͷมߋɺ௥Ճ • ಛҟϝιουͷ௥Ճ
  10. ػೳৄࡉͷݕ౼ είʔϓͱAPI • NamespaceఆٛͱಡΈࠐΈͷൣғ • ϑΝΠϧ୯ҐͰͷఆٛ? ϒϩοΫͳͲଞͷέʔε΋? • ݱࡏͷNamespace͸ϨΩγΧϧʹܾఆ? ΋ͬͱಈతʹ?

    • Namespaceͷఆٛํ๏ͱӅṭείʔϓ • Namespace͸਌ࢠؔ܎Λ࡞Δ? ਌ࢠؔ܎ͷؒͰ͸಺෦ఆ͕ٛࢀরͰ͖Δ? • Namespaceͷ࡞੒ͱಡΈࠐΈͷAPI • Namespace.newɺNamespace#requireɿ ௿ϨϕϧAPI? • Ϣʔβ޲͚ͷߴϨϕϧAPI͸ͲͷΑ͏ͳ΋ͷ͔?
  11. ػೳৄࡉͷݕ౼ ߴϨϕϧΠϯλʔϑΣΠεͷఏҊɿPackage API • Namespace on readΛϕʔεʹͨ͠ΑΓ޿͍Ϣʔβ޲͚API • ΑΓ୯७ͳAPIͰϝϦοτΛड͚ΒΕΔΑ͏ʹ͢Δ pkg

    = require_package('my-awesome-gem') MyAwesomeGem = pkg.export(:MyAwesomeGem) MyAwesomeGem.call_method() • Namespace on read͕Ϛʔδ͞ΕͨΒݕ౼Λܧଓ
  12. • ֦ுϥΠϒϥϦͷγϯϘϧղܾ • ಉ໊γϯϘϧΛ࣋ͭϥΠϒϥϦ͕͋Γ͏Δ • ಉϥΠϒϥϦͷҟόʔδϣϯಡΈࠐΈ • ಉҰ .so Λෳ਺ճಡΈࠐΈ

    • dlopen࣌ͷRTLD_LOCALϑϥάࢦఆ • ैདྷͱҧ͏ํ๏ͰγϯϘϧղܾ • ଞͷ֦ுϥΠϒϥϦʹ௚઀ґଘ͢Δ৔߹ͷΈ • rb_ext_resolve_symbol(fname, symname) Ruby w/ Namespace ֦ுϥΠϒϥϦͷγϯϘϧղܾ γϯϘϧղܾ༻ C API ͷ௥Ճ (Ruby 3.3) Ruby w/o Namespace db_driver_v1.so db_conn_server() query_client.so db_conn_server() db_driver_v1.so db_conn_server() query_client.so db_conn_server() db_driver_v2.so db_conn_server() ❌ rb_ext_resolve_symbol(“db_driver_v2”, “db_conn_server”)
  13. Namespaceͷ࣮૷ Namespaceͷσʔλߏ଄: Namespace ͱ rb_namespace_t • Namespace • ModuleͷαϒΫϥε •

    Namespace#require ΍ Namespace#load • rb_namespace_t (಺෦࣮૷ɺstruct) • LOAD_PATH, LOADED_FEATURES, etc ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call()
  14. Namespaceͷ࣮૷ ྫ1: Class/Moduleͷఆٛ • Namespace಺ͰͷClassఆٛ • MyAwesomeΛns::MyAwesomeʹ • .rbͷ৔߹ •

    load_wrapper() ͕ղܾ • .soͷ৔߹ # my_awesome.rb class MyAwesome; end # my_awesome.c void Init_my_awesome(void) { rb_define_class(“MyAwesome”, rb_cObject) } # app.rb ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call()
  15. (no NS) Namespaceͷ࣮૷ ྫ1: Class/Moduleͷఆٛ • Namespace಺ͰͷClassఆٛ • MyAwesomeΛns::MyAwesomeʹ •

    .rbͷ৔߹ • load_wrapper() ͕ղܾ (1) • .soͷ৔߹ (2) require(“my_awesome.rb”) class MyAwesome; end defineclass .rb C func ISeq vm_find_or_create_class_by_id() rb_define_class_id() declare_under() vm_define_class() vm_declare_class() (1) ns.require(“my_awesome.rb”) class MyAwesome; end load_wrapper() defineclass vm_find_or_create_class_by_id() rb_define_class_id() declare_under() vm_define_class() vm_declare_class() ns:: ns:: ns:: ns::
  16. Namespaceͷ࣮૷ ྫ1: Class/Moduleͷఆٛ • Namespace಺ͰͷClassఆٛ • MyAwesomeΛns::MyAwesomeʹ • .rbͷ৔߹ •

    load_wrapper() ͕ղܾ (1) • .soͷ৔߹ (2) .rb C func ISeq (2) ns.require(“my_awesome.rb”) rb_define_class() rb_define_class_id_under() (no NS) require(“my_awesome.rb”) rb_define_class() ns::
  17. ػೳৄࡉͷݕ౼ ࣮૷͢΂͖ػೳ (revisit) • require/load .rb • require/load .so •

    autoload • eval • proc, lambda • Ϋϥε΍Ϟδϡʔϧͷఆٛ • ૊ࠐΈΫϥεͷมߋ • include/prepend • τοϓϨϕϧϝιουఆٛ • άϩʔόϧม਺ͷมߋɺ௥Ճ • ఆ਺ͷมߋɺ௥Ճ • ΫϥεΠϯελϯεม਺ͷมߋɺ௥Ճ • Ϋϥεม਺ͷมߋɺ௥Ճ • ಛҟϝιουͷ௥Ճ
  18. Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ • class String ʹΑΔӨڹൣғͷݶఆ • Namespace಺ͰͷΈ༗ޮʹ͍ͨ͠ •

    Namespaceͷ֎Ͱ͸ແޮʹ͍ͨ͠ • ಛఆͷൣғͰͷΈ༗ޮͳϝιου
 → Re fi nementsͰ͸? # my_awesome.rb class String def blank?; false; end end class MyAwesome def self.call; “yay”.blank?; end end # app.rb ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() #=> false “yay”.blank? # NoMethodError
  19. Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ: Implicit Re fi nements # app.rb ns

    = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() “yay”.blank? # NoMethodError # my_awesome.rb class String def blank?; false; end end class MyAwesome def self.call = “yay”.blank? end # my_awesome.rb using ns.refiner class String def blank?; false; end end class MyAwesome def self.call = “yay”.blank? end • Namespace͸಺෦ʹϞδϡʔϧ(re fi ner)Λ΋ͬͯImplicit Re fi nementsʹ༻͍Δ • Namespace಺ͰධՁ͞ΕΔ .rb ͸·ͣ
 ҉໧ʹusing͞ΕΔ ಈ࡞͕ಁաతʹ ॻ͖׵͑ΒΕΔ෦෼
  20. Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ: Implicit Re fi nements # app.rb ns

    = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() “yay”.blank? # NoMethodError rb false; end me ll = “yay”.blank? # my_awesome.rb using ns.refiner module ns.refiner refine String do def blank?; false; end end end class MyAwesome def self.call = “yay”.blank? end # my_awesome.rb using ns.refiner class String def blank?; false; end end class MyAwesome def self.call = “yay”.blank? end • class StringΛ
 module re fi ner; re fi ne String ʹॻ͖׵͑ͯ
 Re fi nementʹͳΔΑ͏ಡΈସ͑Δ ಈ࡞͕ಁաతʹ ॻ͖׵͑ΒΕΔ෦෼
  21. Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ: Implicit Re fi nements # app.rb ns

    = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() “yay”.blank? # NoMethodError # my_awesome.rb using ns.refiner module ns.refiner refine String do def blank?; false; end end end using ns.refiner class MyAwesome def self.call = “yay”.blank? end # my_awesome.rb using ns.refiner module ns.refiner refine String do def blank?; false; end end end class MyAwesome def self.call = “yay”.blank? end y_awesome.rb ng ns.refiner ss String ef blank?; false; end ss MyAwesome ef self.call = “yay”.blank? • ߋ৽͞ΕͨRe fi nementΛ༗ޮʹ͢ΔͨΊ
 ΋͏͍ͪͲusing͢Δ ಈ࡞͕ಁաతʹ ॻ͖׵͑ΒΕΔ෦෼
  22. Namespaceͷ࣮૷ Implicit Re fi nementsʹΑΔ࣮ߦ࣌ఆٛߋ৽ • ϝιου௥Ճ → Implicit Re

    fi nementsͰ࣮ݱ • ఆ਺௥Ճ → re fi nerϞδϡʔϧʹఆ਺Λ௥Ճͯ͠ࢀরՄೳʹ • τοϓϨϕϧϝιουఆٛ → ObjectΛre fi ne͢Δ͜ͱͰରԠՄೳ
  23. ػೳৄࡉͷݕ౼ ࣮૷͢΂͖ػೳ (re-revisit) • require/load .rb • require/load .so •

    autoload • eval • proc, lambda • Ϋϥε΍Ϟδϡʔϧͷఆٛ • ૊ࠐΈΫϥεͷมߋ • include/prepend • τοϓϨϕϧϝιουఆٛ • άϩʔόϧม਺ͷมߋɺ௥Ճ • ఆ਺ͷมߋɺ௥Ճ • ΫϥεΠϯελϯεม਺ͷมߋɺ௥Ճ • Ϋϥεม਺ͷมߋɺ௥Ճ • ಛҟϝιουͷ௥Ճ ϓϩδΣΫτ಺Ͱ࣮ݱ͞Εͨػೳ
  24. Namespaceͷ࣮૷ 4݄Ҏ߱ɺRubyKaigi 2024Λӽ͑ͯ • https://speakerdeck.com/tagomoris/namespace-what-and-why • Re fi nementsϕʔεͷ࣮૷Λഁغ •

    classext copyͱ͍͏ख๏Ͱͷ࣮૷ʹํ਑Λస׵
 (RubyKaigi 2024ͷτʔΫ಺༰Λࢀর) • test-all ͕׬૸ɺ10 failures/errors ͱ͍͏͋ͨΓ·Ͱ࣮૷͞Εͭͭ͋Δ
 (2024/07/18) • Implicit Re fi nements ෦෼తʹ෮׆ͷػӡߴ·Δ
  25. Special Thanks to Matz Thank you for listening! The Ruby

    Designer & The Mentor of this project