$30 off During Our Annual Pro Sale. View Details »

Multiverse Ruby

Multiverse Ruby

Slides from my talk by the same name at RubyKaigi 2023, given in Japanese.

shioyama/im
shioyama/rails_on_im

Chris Salzberg

May 12, 2023
Tweet

More Decks by Chris Salzberg

Other Decks in Programming

Transcript

  1. n = 10 a, b = 0, 1 n.times do

    a, b = b, a + b end puts a
  2. module Fibonacci def self.fib(n) a, b = 0, 1 n.times

    do a, b = b, a + b end a end end
  3. module Fibonacci def self.fib(n) a, b = 0, 1 n.times

    do a, b = b, a + b end a end end code
  4. module Fibonacci def self.fib(n) a, b = 0, 1 n.times

    do a, b = b, a + b end a end end architecture
  5. // variable.c:138 static VALUE make_temporary_path(VALUE obj, VALUE klass) { VALUE

    path; switch (klass) { case Qnil: path = rb_sprintf("#<Class:%p>", (void*)obj); break; case Qfalse: path = rb_sprintf("#<Module:%p>", (void*)obj); break; default: path = rb_sprintf("#<%"PRIsVALUE":%p>", klass, (void*)obj); break; } OBJ_FREEZE(path); return path; }
  6. mod

  7. require "my_gem" # my_gem.rb require "foo" require "bar" # foo.rb

    # bar.rb require require require require require
  8. mod = import "my_gem" # my_gem.rb require "foo" require "bar"

    # foo.rb # bar.rb require require require require require load load load load load load load
  9. mod = import "my_gem" # my_gem.rb require "foo" require "bar"

    # foo.rb # bar.rb require require require require require load load load load load load load
  10. im i isolated solated m module odule autoloader autoloader i

    isolated solated m module odule autoloader autoloader
  11. Zeitwerk: Code Loader lib/my_gem.rb → MyGem lib/my_gem/foo.rb → MyGem::Foo lib/my_gem/bar_baz.rb

    → MyGem::BarBaz lib/my_gem/woo/zoo.rb → MyGem::Woo::Zoo Object:: Object:: Object:: Object::
  12. lib/my_gem.rb → MyGem lib/my_gem/foo.rb → MyGem::Foo lib/my_gem/bar_baz.rb → MyGem::BarBaz lib/my_gem/woo/zoo.rb

    → MyGem::Woo::Zoo Im: Isolated Code Loader mod:: mod:: mod:: mod:: temporary root
  13. mod = import "my_gem" mod::MyGem::Foo #=> loads "lib/my_gem/foo.rb" mod::MyGem::Foo::BarBaz #=>

    loads "lib/my_gem/foo/bar_baz.rb" mod::MyGem::Foo::Woo::Zoo #=> loads "lib/my_gem/foo/woo/zoo.rb"
  14. # lib/my_gem.rb (main file) require "zeitwerk" loader = Zeitwerk::Loader.for_gem loader.setup

    # ready! module MyGem # ... end loader.eager_load # optionally
  15. # lib/my_gem.rb (main file) require "im" loader = Im::Loader.for_gem loader.setup

    # ready! module loader::MyGem # ... end loader.eager_load # optionally define under loader, not at top-level!
  16. def require(path) filetype, feature_path = $:.resolve_feature_path(path) if (loader = Im::Registry.loader_for(path))

    # ... $LOADED_FEATURES << feature_path begin load path, loader rescue => e $LOADED_FEATURES.delete(feature_path) raise e end
  17. def require(path) filetype, feature_path = $:.resolve_feature_path(path) if (loader = Im::Registry.loader_for(path))

    # ... $LOADED_FEATURES << feature_path begin load path, loader rescue => e $LOADED_FEATURES.delete(feature_path) raise e end
  18. def require(path) filetype, feature_path = $:.resolve_feature_path(path) if (loader = Im::Registry.loader_for(path))

    # ... $LOADED_FEATURES << feature_path begin load path, loader rescue => e $LOADED_FEATURES.delete(feature_path) raise e end
  19. def require(path) filetype, feature_path = $:.resolve_feature_path(path) if (loader = Im::Registry.loader_for(path))

    # ... $LOADED_FEATURES << feature_path begin load path, loader rescue => e $LOADED_FEATURES.delete(feature_path) raise e end 🙈
  20. assert loader::A X = loader::A assert loader::A assert loader::A::B assert

    loader::A::B::C assert_equal(X::B::C, loader::A::B::C) FAIL ❌
  21. { "<#Im::Loader ...>" ⇨ ... "MyFoo" ⇨ ... "MyFoo::Bar" ⇨

    ... ... } cpath Object.const_added(:MyFoo)
  22. assert loader::A X = loader::A assert loader::A assert loader::A::B assert

    loader::A::B::C assert_equal(X::B::C, loader::A::B::C) PASS ✅