LFAãæ¸ããã¨ãã®è©±ã«ããKernel#load
ã®ç¬¬2å¼æ°ã§åå空éçãªãã®ãä½ãããã ãã©ãload
ããå
ã®ãã¡ã¤ã«ã§require
ããã¦ãããã¡ãªãã ãããã¨ãã話ã®ç¶ãããã¡ãªãã ããã¼ãã§çµãã£ã¦ããã ãã©RubyKaigi2023ã§@shioyamaããã®Multiverse Rubyãèãã¦ãããã«ä»²éããã!!! ã£ã¦ãªã£ã¦ãããã«ãã®ãã¨ãã¼ã§é£²ã¿ãªããããããããã£ã¦çãä¸ãã£ãã®ã§ããªããè²ã
èãã¦ããã
RubyKaigiã®è©±ã¯å¥éæ¸ãã¨ãã¦ããã¾ã¯ã¨ãããããã£ã¡ã
å¾åã«ããããªãã®ã欲ãããã¨ãã話ãããã³èªãã 人ã®æè¦ã欲ããã¨ãããã¨ãæ¸ãã¦ããã®ã§ããã®ãããã«ä½ãæãã¨ããããã人ã¯ãã²èªãã§ã¿ã¦ãã ãããã©ã£ã¡ãã¨ããã¨ãèªå以å¤ã®Rubyã¦ã¼ã¶ãã©ãèãã¦ããã®ãããbugsã«åºãåã«ã¾ãç¥ããããªã¨æã£ã¦ãã¾ãã
åæ©
Rubyã«ã¯ã¿ãªãããåç¥ã®éããåå空éçãªãã®ããªããã©ããªã¹ã¯ãªããã»ã©ã¤ãã©ãªã»ã¢ããªã±ã¼ã·ã§ã³ã§ããã¯ã©ã¹ã»ã¢ã¸ã¥ã¼ã«ãå®ç¾©ããã¨ããåºæ¬çã«ã¯åå空éã®ãããã¬ãã«ã«ç½®ããããããã¯æ¢åã®ã¢ã¸ã¥ã¼ã«ã»ã¯ã©ã¹ã®ä¸ã«ç½®ãããããããã«ã¯ä»¥ä¸ã«èª¬æãããããªåé¡ãããã
ååã®è¡çª
è¤æ°ã®ã©ã¤ãã©ãªãåãååã使ã£ã¦ããå ´åããã¡ãã競åãããåã種é¡(ã¯ã©ã¹orã¢ã¸ã¥ã¼ã«)ã ã£ãå ´åã¯ãäºããä¸æ¸ãããããç°ãªã種é¡ã ã£ãå ´åã«ã¯ãµãã¤ããèªã¿è¾¼ãã æç¹ã§ä¾å¤ã¨ãªãã
ã¾ãRubyã®ä¸çã§æ¯é
çãªRuby on Railsããåºæ¬çã«ã¢ããªã±ã¼ã·ã§ã³ã®ã¯ã©ã¹ã»ã¢ã¸ã¥ã¼ã«ã¯ãã¹ã¦ãããã¬ãã«ã«ç½®ããã¨ããè¦ç´ãç¨ãã¦ããã®ããã®å¶ç´ãç ´æ»
çã«ãã¦ããããããã¬ãã«ã®åå空éãè¨å¤§ãªæ°ã®ã¦ã¼ã¶ã¼å®ç¾©ã¯ã©ã¹ã«æ¶è²»ããã¦ããããããããªããããã®ãããã©ã¤ãã©ãªä½è
ãã©ã¤ãã©ãªãä½ãã¨ãã«ã¯ããããã¬ãã«ã«ã¯User
ãAccount
ãStrategy
ãGuild
ãRecipe
ã使ããªãã*1
ãããã¬ãã«ã§ååãè¡çªããã¨ããçæ¹ãã¢ããªã±ã¼ã·ã§ã³ã§ããã°ååãå¤æ´ã§ãããããããªããããµãã¤ã®ã©ã¤ãã©ãªãåãååã使ã£ã¦ããå ´åãã²ã¨ã¤ã®ã¢ããªã±ã¼ã·ã§ã³ãã両æ¹ã使ããã¨ã¯é¸æè¢ããç¡ããªããç¾ç¶ã§ããã°ãã©ã¡ããã諦ããªãã¦ã¯ãããªãã
è¤æ°ãã¼ã¸ã§ã³ã®ä½¿ç¨ä¸å¯
ã©ã¤ãã©ãªã¯ãã¼ã¸ã§ã³ã¢ãããè¡ã£ã¦ããå¤ãã®å ´åãå½ç¶åãååãç¨ããããã®ããç¾å¨ã®Rubyã§ã¯ã©ãããã°ã£ã¦ãç¹å®ã©ã¤ãã©ãªã®è¤æ°ãã¼ã¸ã§ã³ã1ããã»ã¹å ã«ã¯å ±åãããããªããããã¯ãã¢ããªã±ã¼ã·ã§ã³ãä¾åããè¤æ°ã®ã©ã¤ãã©ãª(A, B)ãåãã©ã¤ãã©ãª(C)ã«ä¾åããããããããããããã¼ã¸ã§ã³å¶ç´ãç°ãªããã¨ããç¶æ³ã解決ã§ããªããã¨ãæå³ããã
App ---> A ---> C (~> 1.4.0) | +--> B ---> C (~> 2.0)
ããã¯ã¢ããªã±ã¼ã·ã§ã³éçºè ã«ã¨ã£ã¦ã¯ããªãå³ãããä¸è¨ã®ç¶æ³ã§ããã°ã©ã¤ãã©ãªAã®éçºè ã«ä¾åé¢ä¿ãæ´æ°ãã¦ããããããé¡ããããã¨ã«ãªããAã®éçºè ã¯ä¾åé¢ä¿ãæ´æ°ãã¦ãã®ç¶æ³ã§Aã®åä½ç¢ºèªã¨ãªãªã¼ã¹ãè¡ãããã®ä¸ã§ã¢ããªã±ã¼ã·ã§ã³éçºè ãã¾ãä¾åé¢ä¿ã®æ´æ°ã¨ãã¹ããè¡ããã¨ã«ãªãã
å±éºãªã©ã¤ãã©ãªã°ãã¼ãã«
ã©ã¤ãã©ãªã«è¨å®ãè¡ããã¨ãããããããã¯ã¯ã©ã¹å¤æ°ãç¨ãã¦å®è£
ããã¦ããå¯è½æ§ããããä¾ãã°åä½ãéãããã¨ä½¿ããããã¨ãå¤ãoj
ã¯ã以ä¸ã®ããã«è¨å®ãè¡ãã
Oj.default_options[:allow_gc] #=> true Oj.default_options = {allow_gc: false} Oj.default_options[:allow_gc] #=> false
ããã¯ãã¡ããOj.parse
ããã¨ãã®åä½ãå¤æ´ãããã¤ã¾ããã©ãã(èªåã«è²¬ä»»ã®ãªã)ã¢ããªã±ã¼ã·ã§ã³ãã©ã¤ãã©ãªã®çé
ã§è¨å®ãå¤æ´ãããã¨ãããã»ã¹å
ãã¹ã¦ã«ãããã©ã¤ãã©ãªã®åä½ã«å½±é¿ãä¸ããã
åå空éã«ãã解決
ããã«æ¸ããåé¡ã¯ãåºæ¬çã«åå空éãããã°è§£æ±ºã§ãããã¨èªåã¯ä¿¡ãã¦ãããRubyã®åä½ããããªãå¤ããå¿ è¦ã¯ãªãããªãã·ã§ãã«ã«æå®ã§ããåå空éãããã°ãããã¨æã£ã¦ããã
Imã使ã£ã¦ã¿ã
åå空éãRubyã§å®ç¾ãã試ã¿(Multiverse Rubyã¨è¡¨ç¾ããã¦ãã)ã¨ãã¦@shioyamaãããä½ã£ããã®ãIm*2ã
ããã¯æ¬¡ã®ããã«ãã©ã¤ãã©ãªã®ãã¼ããä½ãããã¼ãã¯ã¢ã¯ã»ã¹ãããã¢ã¸ã¥ã¼ã«ã»ã¯ã©ã¹åããããããå®ç¾©ããã¦ãããã¡ã¤ã«åãç¹å®ãã¦ããã¼ã((å®ä½ã¯Module
ã®æ´¾çã¢ã¸ã¥ã¼ã«))èªèº«ã®ä¸é¨ã«èªã¿è¾¼ãã
require "im" loader = Im::Loader.for_gem loader.setup # ready! loader::MyGem # ãã¼ããã¹ä¸ã® 'my_gem.rb' ãç¹å®ããèªåçã«èªã¿è¾¼ã¾ãã
ãããKaigiä¸ã«è©¦ãã¦ã¿ããã ãã©ãLFAã§ã¯ä»¥ä¸ã®çç±ããã£ã¦ä½¿ããªããã¾ãgemãªã©ã®ã©ã¤ãã©ãªã«ä½¿ãã®ã«ãç¾ç¶ã ã¨å³ããã¨æãã
loader.setup
ããåã®æç¹ã§ãã¼ããã¹ã確å®ããå¿
è¦ããã
ããã¯ImãZeitwerkãforkãã¦ä½ããã¦ããããã¨ããå®è£
ä¸ã®çç±ã大ãããããããªããå
é¨çã«loader.setup
ããæç¹ã§ãã¼ããã¹ã«ããå
¨ã¦ã®ãã¡ã¤ã«ããªã¹ãã¢ãããã¦å®æ°åã¨autoloadãã対象ãã¡ã¤ã«åã®å¯¾å¿è¡¨ãä½ããããloader.setup
ããå¾ã§å¥ã®ãã£ã¬ã¯ããªã«ãããã¡ã¤ã«ããã¯ã©ã¹ã»ã¢ã¸ã¥ã¼ã«å®ç¾©ãèªã¿è¾¼ããã¨æã£ã¦ãé£ããã((unload
ãã¦ãã¼ããã¹ã追å å¾ã«setup
ããªããã°å¯è½ã ãã©ããªããªã常ç¨ã«ã¯å³ããã¨æãã))
LFAã¯ã¢ããªã±ã¼ã·ã§ã³ã®èµ·åæã«ãã¼ããã¹ã確å®ã§ããã®ã§ãã®ç¹ã¯åé¡ã§ã¯ãªãããé常ã®Rubyã«å ¥ãããã¨ããæ©è½ã¨ãã¦ã¯å³ããå¶ç´ã ã¨æãã
ãã¼ã対象ã®ã¯ã©ã¹ã»ã¢ã¸ã¥ã¼ã«åã¨ãã¡ã¤ã«åã®é¢ä¿ã«å¼·ãå¶ç´ããã
ãããZeitwerkç±æ¥ã ããã ããåç §ãããå®æ°åãããã¯ã«ãã¦èªã¿è¾¼ããã¡ã¤ã«åãç¹å®ããé¢ä¿ä¸ããµãã¼ãã§ããªããã®ãå¤ããªãã
loader::MyGem # -> my_gem loader::MessagePack # -> message_pack ã ã msgpack.rb ãèªãã§ã»ããâ¦â¦ loader::StringIO # -> requireãã対象㯠stringio ã ãã
LFAã§ã¯èªã¿è¾¼ã¿å¯¾è±¡ã®ãã¡ã¤ã«ãããã«æ¸ããã¦ããã¯ã©ã¹ã»ã¢ã¸ã¥ã¼ã«åãè¨å®ãã¡ã¤ã«ããæå®ãã*3ãããååãã¼ã¹ã§èªã¿è¾¼ã¿å¯¾è±¡ã決å®ããè¦ç´ã¯ä¸è¦ã¨ããããå¶ç´ã¨ãªã£ã¦ä½¿ç¨ã§ããªããã¾ãä¸è¬çã«ãgemã§ãé£ããã¨æããRubyæ¬ä½ã®æ¨æºæ·»ä»ã©ã¤ãã©ãªã§ããã®å½åè¦ç´ã«å¾ã£ã¦ããªããã®ã¯å¤ãã
æ¡å¼µã©ã¤ãã©ãªã«å¯¾å¿ã§ããªã
Kernel#load
ã®ç¬¬2å¼æ°ãç¨ããããããã¯pure Rubyãªã©ã¤ãã©ãªã§require
ã使ã£ã¦ããªããã®ã«ã¯ãã¾ãåããã ãã©ãããã§ãªãå ´åã«ã¯ãã¾ããããªããã¾ãrequire
ã使ããã¦ãã¦ããã®å
ãpure Rubyã³ã¼ããªããªãã¨ããªãããªã¨æã((å
·ä½çã«ã¯Kernel#require
ãä¸æ¸ããã¦load
ãwrapã¢ã¸ã¥ã¼ã«ã¨ä¸ç·ã«å¼ã¶ããã«ãã))ãã©ãæ¡å¼µã©ã¤ãã©ãªã®å ´åã«ã¯ãããã£ãæ¹æ³ã使ããªãã
欲ãããã®
èªåã欲ãããã®ã¯ä»¥ä¸ã®ããã«ä½¿ããåå空éãªãã¸ã§ã¯ãã ãå®ä½ã¨ãã¦ã¯ãæ¡å¼µãããæ©è½ã®require
ããã³load
ã¡ã½ããããã¤Module
ã®ãµãã¢ã¸ã¥ã¼ã«ã«ãªãããããå®ç¾ã§ããã°ãä¾ã«ç¤ºãããã«ããããã¬ãã«åå空éã§ã®è¡çªã®åé¿ãç°ãªããã¼ã¸ã§ã³ã®ã©ã¤ãã©ãªã®èªã¿è¾¼ã¿ãã¯ã©ã¹å¤æ°ã®ä½¿ç¨ã«ããæå³ããªãæåå¤åã®é²æ¢ãã©ãããå®ç¾ã§ããã
ãã®åå空éãå®ç¾ããã¢ã¸ã¥ã¼ã«ãã以ä¸ã®ã³ã¼ãä¾ã§ã¯ModuleBoxã¨å¼ã¶ããªã@shioyamaããã¨è©±ãã¦ããã¨ãã«ã¯ãHakoã¨å¼ã¶ã®ãããã®ã§ã¯ãã¨ãããã¨ã«ãªã£ã¦ãã*4ã
box1 = ModuleBox.new # or ModuleBox.new(load_path: $LOAD_PATH + ['...']) box2 = ModuleBox.new
åºæ¬çã«ã¯ã¤ã³ã¹ã¿ã³ã¹ãä½ãããã®åå空éå ã§ã®ã¿ä½ãããããã¨ãããã®ã¤ã³ã¹ã¿ã³ã¹ã«å¯¾ãã¦æä½ããã
é è½ãããåå空éã§ã®èªã¿è¾¼ã¿
# é è½ããã空éã§ã®ã¹ã¯ãªããã®load box1.load('my_client.rb') box1::MyClient #=> MyClient box2.require('guild') box2::Guild #=> Guild MyClient #=> NameError Guild #=> NameError box1::Guild #=> NameError box2::MyClient => NameError # import to a different name can be done MyGuild = box2::Guild MyGuild.build(...)
ç°ãªããã¼ã¸ã§ã³ã®ã©ã¤ãã©ãªã®èªã¿è¾¼ã¿
box1.require('msgpack', version: '1.6.0') box2.require('msgpack') #=> latest one msgpack1 = box1.const_get(:MessagePack) msgpack1::VERSION #=> "1.6.0" msgpack2 = box2::MessagePack msgpack2::VERSION #=> "1.7.0"
ã¯ã©ã¹å¤æ°ãç¨ããè¨å®å¤æ´ã®å½±é¿ã®å±æå
require('oj') box1.require('oj') oj1 = box1.const_get(:Oj) oj1.default_options[:allow_gc] #=> true oj1.default_options = oj1.defualt_options.merge({allow_gc: false}) oj1.default_options[:allow_gc] #=> false Oj.default_options[:allow_gc] #=> true
ãããã
èªåã®ã¢ã¤ãã¢ã¯ãã¡ãããã ã®ã¢ã¤ãã¢ãªã®ã§ãã¾ã ä½ã²ã¨ã¤å®ç¾ã§ãã¦ããªããé¢ä¿ããããªã³ã¼ãã¯èªãã§ã¿ãçµæãRubyæ¬ä½ãå¤æ´ããªãã¨å®ç¾ã§ãããã«ãªãã®ã¯ããã£ã¦ããã®ã§ãbugs.ruby-lang.orgã«Featureãåºãã¦ã¿ã¦ãèªåã®æå ã§å®è£ ã«ãã£ã¬ã³ã¸ãã¦ã¿ãããªãã¨æã£ã¦ããã
ãããèªãã 人ã«ã¯ãä¸è¨ã®ã¢ã¤ãã¢ãã©ããªããã«è¦ããããèãã¦ã¿ã¦ã»ãããå°è±¡ãèãããã ã¾ããã®æ©è½ã ãã§ã¯ä¸ååã ã¨ããAPIãæªãã¨ãããããããã£ã¼ãããã¯ãããã°ãã²æãã¦ã»ããã
*1:ãããã¬ãã«ã«ãããªã®ç½®ããªããã¨ããã®ã¯ããããã¾ãâ¦â¦ã
*2:ã¤ã ã¨èªããImportã®Imã ããã
*3:AWS Lambdaããã®ããã«ãªã£ã¦ããã®ã§ãLFAã®è¨å®ãå½ç¶ãããè¸è¥²ãã¦ãã
*4:è±èªè©±è ãããã¦ãHakoã¨ããã®ã¯é¿ããããâ¦â¦ãããã