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

On-the-fly Suggestions of Rewriting Method Depr...

On-the-fly Suggestions of Rewriting Method Deprecations

Masato Ohba

April 19, 2025
Tweet

More Decks by Masato Ohba

Other Decks in Programming

Transcript

  1.  5IF%FQSFDBUJPO1SPCMFN0WFSWJFX w "TPGUXBSFEFWFMPQNFOUQSBDUJDFUPQIBTFPVUPMEGFBUVSFT w *UTFSWFTBTBUSBOTJUJPOQFSJPECFUXFFOTVQQPSUJOHMFHBDZDPEFBOE SFNPWJOHJU w ,FZQVSQPTFT w

    4JHOBMJOHQMBOOFESFNPWBMPGBGFBUVSF w &ODPVSBHJOHNJHSBUJPOUPOFXFSBMUFSOBUJWFT w "MMPXJOHHSBEVBMDPEFCBTFVQEBUFT 8IBUJTEFQSFDBUJPO
  2.  5IF%FQSFDBUJPO1SPCMFN0WFSWJFX 5SBEJUJPOBMNFUIPEEFQSFDBUJPOUJNFMJOF W W W -JCSBSZ6TFS *NQMFNFOU old_method "EEnew_method

    %FQSFDBUFold_method 3FNPWF old_method 6TF old_method 4FFXBSOJOHTXIJMF VTJOHold_method $PEFCSFBLTVOMFTT VTJOHnew_method -JWFXJUI new_method W -JCSBSZ"VUIPS 5SBOTJUJPOQFSJPE 1BJOPGNBOVBMDPEFVQEBUFT -JCSBSZBVUIPSTJODMVEFJUTMBOHVBHFEFWFMPQFST
  3.  5IF%FQSFDBUJPO1SPCMFN0WFSWJFX 4UBUJD%ZOBNJDBOBMZTJT 3 w 3VCP$PQ w "VUPDPSSFDUTEFQSFDBUJPOT w %FQSFDBUJPO5PPMLJU

    w 3FDPSETEFQSFDBUJPOXBSOJOHT BUSVOUJNF IUUQTEPDTSVCPDPQPSHSVCPDPQDPQT@MJOUIUNMMJOUEFQSFDBUFEDMBTTNFUIPET IUUQTHJUIVCDPN4IPQJGZEFQSFDBUJPO@UPPMLJU
  4.  -FBSOJOHGSPN0UIFS-BOHVBHFT %J ff FSFOUQSPHSBNNJOHMBOHVBHFTIBOEMFEFQSFDBUJPOJOVOJRVFXBZT w warningsNPEVMF w EPDVNFOUBUJPO w

    TUBUJDBOBMZTJTUPPMT 1ZUIPO w @deprecatedUBH w DPNQJMFUJNFXBSOJOHT w DPEFNPET +4BTXFMM 5ZQF4DSJQU w @DeprecatedBOOPUBUJPO w +BWBEPD w *%&JOUFHSBUJPO +BWB w [Obsolete]BUUSJCVUF w 3PTMZOBOBMZ[FST w "VUP fi YFTJO*%& $ w  #[ deprecated]BUUSJCVUF w cargo fix GPSBVUPNBUFE VQEBUFT 3VTU #[ deprecated(since = "1.0.0", note = "U pub fn old_function() { println!("This function is deprecat } @Deprecated public void oldMeth System.out.prin } [Obsolete("Use NewMethod instead")] public Task<T?> OldMethod<T>(string s) { } import warnings def old_method(): warnings.warn( "Use new_method", DeprecationWarning, stacklevel=2 ) return "oops"
  5.  -FBSOJOHGSPN0UIFS-BOHVBHFT &WPMVUJPOPGEFQSFDBUJPOIBOEMJOH 1 2 3 4 5 %PDVNFOUBUJPOPOMZ $PNNFOUT

    DIBOHFMPHTBOEHVJEFT 3VOUJNFXBSOJOHT 8BSOXIFODPEFSVOT 4UBUJDBOBMZTJT 'JOEJTTVFTXJUIUPPMT JODMVEJOHUZQFDIFDL *%&JOUFHSBUJPO 7JTVBMDVFTBOETVHHFTUFE fi YFT "VUPNBUFE fi Y "VUPNBUJDBMMZUSBOTGPSNTDPEF ? 'VUVSF 0OUIF fl Z DPEFSFXSJUJOH 5IFQPTJUJPOTPGFBDIMPHPBSFGPSJMMVTUSBUJPOQVSQPTFTPOMZBOENBZOPUBDDVSBUFMZSF fl FDUUIFBDUVBMTJUVBUJPO
  6.  -FBSOJOHGSPN0UIFS-BOHVBHFT 1IBSPT%FQSFXSJUFS "VUPNBUJDBMMZSFXSJUFTDBMMFSTPGEFQSFDBUFENFUIPETBUSVOUJNF  CBTFEPOUSBOTGPSNBUJPOSVMFTEF fi OFECZMJCSBSZBVUIPST Logger >>

    log: aMessage [ "The deprecation definition" self deprecated: 'use #log:level: instead' transformWith: '`@rec log: `@argument' - > '`@rec log: `@argument level: #info'. "The body of the method" ^ self log: aMessage level: #info ]
  7.  -FBSOJOHGSPN0UIFS-BOHVBHFT )PX1IBSPT%FQSFXSJUFSXPSLT "OOPUBUJPO 1 5IFEFQSFDBUFENFUIPEJTNBSLFEXJUI EFQSFDBUJPOBOEJUTSVOUJNF USBOTGPSNBUJPO &YFDVUJPO 2

    %VSJOHQSPHSBNFYFDVUJPO UIF FYFDVUJPOPGUIFEFQSFDBUFENFUIPE SBJTFTBOFYDFQUJPO &YDFQUJPOIBOEMJOH 3 *UDBQUVSFTUIFFYDFQUJPO $BMMFSSFXSJUJOH 4 *UJEFOUJ fi FTDBMMTJUFTJOUIFDBMMJOH NFUIPEBOEJUSFXSJUFTUIFNFUIPEXJUI USBOTGPSNBUJPOSVMFT &YFDVUJPODPOUJOVFT 5 5IFIBMUFENFUIPEFYFDVUJPOJTSFTVNFE 5IFCPEZPGUIFEFQSFDBUFENFUIPEJT SFXSJUUFOJONPTUDBTFT 5IF fi HVSFXBTDSFBUFECBTFEPOSFGFSFODFTGSPNUIFQBQFSIUUQTJOSJBIBMTDJFODFIBMEPDVNFOU -JCSBSZ6TFS -JCSBSZ"VUIPS
  8.  -FBSOJOHGSPN0UIFS-BOHVBHFT 8IZBUSVOUJNF OPUTUBUJDBOBMZTJT 5IPTFFYBNQMFTBSFEFTDSJCFEJOUIFQBQFS $IBSBDUFSJTUJDTPG EZOBNJDUZQFEMBOHVBHF 4UBUJDBOBMZTJTUPPMTDBVTFFYDFTTJWFPSJOTV ff i

    DJFOU SFXSJUJOHDBOEJEBUFT &YJTUFODFPG )PNPOZNPVT.FUIPET *GCPUIMPHHJOHNBUIMJCSBSJFTIBWFMPHNFUIPE TUBUJD BOBMZTJTDPVMEOUEFUFSNJOFJGBQBSUJDVMBSMPHDBMM .FUIPE0WFSSJEJOH 5IFFYBNQMFPGJT/JMJO1IBSP XIJDIJTTFOUUJNFT BOEJNQMFNFOUFEJODMBTTFT
  9.  -FBSOJOHGSPN0UIFS-BOHVBHFT class Legacy def old_method(arg) # do old thing

    end def new_method(arg) # do new thing end end w .BJOUBJOTLegacyDMBTT w "EETnew_method w %FQSFDBUFTold_method -JCSBSZ"VUIPS -FUTTBZBMJCSBSZBVUIPS
  10.  -FBSOJOHGSPN0UIFS-BOHVBHFT -JCSBSZ"VUIPS $VSSFOUBQQSPBDIFT Gem :: Deprecate class Legacy #

    @deprecated Use {#new_method} def old_method(arg) warn "Use #new_method instead" # do old thing end def new_method(arg) # do new thing end end class Legacy def old_method(arg) # do old thing end def new_method(arg) # do new thing end extend Gem : : Deprecate deprewrite :old_method, :new_method, 2025, 4 end :"3% warn
  11. class Legacy def old_method(arg) # do old thing end def

    new_method(arg) # do new thing end extend Deprewriter deprewrite :old_method, to: "new_method( {{ arguments } } )" end  -FBSOJOHGSPN0UIFS-BOHVBHFT w %FDMBSFUBSHFUUPSFXSJUF w %FDMBSFUSBOTGPSNBUJPOSVMF -JCSBSZ"VUIPS 6TF%FQSFXSJUFS 💡
  12. --- ./script.rb +++ ./script.rb @@ -37,6 +37,6 @@ legecy =

    Legacy.new -legecy.old_method(arg) +legecy.new_method(arg)  -FBSOJOHGSPN0UIFS-BOHVBHFT legacy = Legacy.new legacy.old_method(arg) -JCSBSZ6TFS 3VOVTFSDPEF UIFOHFU fi YFTPSTVHHFTUJPOT MPHHJOH EJ ff  fi MFT BQQMZJNNFEJBUFMZ %FQSFXSJUFSJEFOUJ fi FTDPEFUPCFSFXSJUUFOBUSVOUJNFBOESFXSJUFT PSPVUQVUTTVHHFTUJPOTUPSFXSJUF
  13.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT )PXUPJNQMFNFOUB%FQSFXSJUFSJO3VCZ "OOPUBUJPO 1 &YFDVUJPO 2 &YDFQUJPOIBOEMJOH 3 -JCSBSZ6TFS

    $BMMFSSFXSJUJOH &YFDVUJPODPOUJOVFT 5 4 "VUIPSTOFFEUPBEE JUUPEFQFOEFODZ 3VCZQSPWJEFTNFUIPEJOUFSDFQUJPO XBZXJUIPVUFYDFQUJPO /FFEUP fi OEDBMMFSMPDBUJPOXJUISPX OVNCFSIPSJ[POUBMQPTJUJPO -JCSBSZ"VUIPS
  14. "OOPUBUF USBOTGPSNBUJPOSVMFT 2  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT %FQSFXSJUFSTDPNQMFUFXPSL fl PXJO3VCZ -JCSBSZ"VUIPS -JCSBSZ6TFS

    "EE%FQSFXSJUFSUP EFQFOEFODZ 1     DBOCFEPOFCZMJCSBSZVTFST*UTJEFBMUPEF fi OFCZBVUIPST 🤔)PXUPXSJUFUSBOTGPSNBUJPOSVMFT 🤔*TSFXSJUJOHDPEFBUSVOUJNFTBGF 🤔8JMMUIF3VCZFDPTZTUFNBEPQUJU 🤔)PXUPUSBOTGPSNDPEF &YFDVUFVTFSDPEF FOBCMJOH%FQSFXSJUFS 3 %FQSFDBUFENFUIPEDBMM USJHHFSTJOUFSDFQUJPO 4 'JOEFYBDUDBMMFS MPDBUJPO 4 5SBOTGPSNDBMMFSDPEF CBTFEPOSVMFT 5 $IBOHFTBSFSFQPSUFE BQQMJFE 6 0SJHJOBMNFUIPE FYFDVUJPODPOUJOVFT 7
  15.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $IBMMFOHFTPG%FQSFXSJUFS 1 2 3 4 )PXUPXSJUFUSBOTGPSNBUJPOSVMFT  )PXUPUSBOTGPSNDPEF

     *TSFXSJUJOHDPEFBUSVOUJNFTBGF  8JMMUIF3VCZFDPTZTUFNBEPQUJU *NQMFNFOUBUJPO$PODFSOT &DPTZTUFNXJEF$PODFSOT
  16.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $IBMMFOHFTPG%FQSFXSJUFS 1 2 3 4 )PXUPXSJUFUSBOTGPSNBUJPOSVMFT  )PXUPUSBOTGPSNDPEF

     *TSFXSJUJOHDPEFBUSVOUJNFTBGF  8JMMUIF3VCZFDPTZTUFNBEPQUJU 🤔 *NQMFNFOUBUJPO$PODFSOT &DPTZTUFNXJEF$PODFSOT
  17.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT # @param method_name [Symbol] The name of the

    method to deprecate # @param from [String, nil] Pattern to match for transformation # @param to [String] Pattern to transform to def deprewrite: (Symbol method_name, to: String, ?from: String?) -> void Deprewriter.deprewriteTJHOBUVSF deprewrite :old_method, from: ".call_node[name=old_method]", to: "new_method( {{ arguments } } )" &YBNQMF fromJTBOPQUJPOBMBSHVNFOUUPTUSJDUMZ fi MUFSBDBMMOPEF )PXUPXSJUFUSBOTGPSNBUJPOSVMFT 1
  18.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT w "45CBTFE3VCZDPEFUSBOTGPSNBUJPOUPPM w 1SPWJEFTQBSTFSPQUJPOT JODMVEJOH1SJTN w &YUSBDUTJUTJOUFSOBMJNQMFNFOUBUJPOJOUPTFQBSBUFHFNT w

    IUUQTHJUIVCDPNTZOWFSUIROPEFRVFSZSVCZ w IUUQTHJUIVCDPNTZOWFSUIROPEFNVUBUJPOSVCZ 4ZOWFSU *EFDJEFEUPBEPQU4ZOWFSUTZOUBYBTUSBOTGPSNBUJPOSVMF from, to )PXUPXSJUFUSBOTGPSNBUJPOSVMFT 1
  19.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT NodeMutation :: PrismAdapterFYBNQMF adapter = NodeMutation :: PrismAdapter.new

    replacement = "new_method( {{ arguments.arguments.0 }} :, {{ arguments.arguments.1 }} :)" original_code = "old_method(arg1, arg2)" call_node = Prism.parse(original_code).value.statements.body.first new_code = adapter.rewritten_source(call_node, replacement) # => "new_method(arg1:, arg2:)" )PXUPXSJUFUSBOTGPSNBUJPOSVMFT 1
  20.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT NodeMutation :: PrismAdapterFYBNQMF adapter = NodeMutation :: PrismAdapter.new

    replacement = "new_method( {{ arguments.arguments.0 }} :, {{ arguments.arguments.1 }} :)" original_code = "old_method(arg1, arg2)" call_node = Prism.parse(original_code).value.statements.body.first new_code = adapter.rewritten_source(call_node, replacement) # => "new_method(arg1:, arg2:)" $PEFUSBOTGPSNBUJPOJTQPTTJCMFJGXFQBTTBO"45OPEF )PXUPXSJUFUSBOTGPSNBUJPOSVMFT 1
  21.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $IBMMFOHFTPG%FQSFXSJUFS 1 2 3 4 )PXUPXSJUFUSBOTGPSNBUJPOSVMFT  )PXUPUSBOTGPSNDPEF

     *TSFXSJUJOHDPEFBUSVOUJNFTBGF  8JMMUIF3VCZFDPTZTUFNBEPQUJU ✅ 🤔 *NQMFNFOUBUJPO$PODFSOT &DPTZTUFNXJEF$PODFSOT
  22.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT class Legacy def old_method(arg) # do old thing

    end def new_method(arg) # do new thing end extend Deprewriter deprewrite :old_method, to: "new_method( {{ arguments }} )" end 8IBUIBQQFOTPOVTJOHdeprewrite )PXUPUSBOTGPSNDPEF 2
  23.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT def deprewrite(method_name, to:, from: nil) class_eval do old

    = "_deprecated_ #{ method_name}" alias_method old, method_name define_method method_name do |*args, &block| # Transformation logic here send old, *args, &block end end end .FUIPEDBMMJOUFSDFQUJPO w 4BNFUFDIOJRVFBT Gem :: Deprecate. deprecate w 1SFTFSWFPSJHJOBM NFUIPECFIBWJPSUP SFTVNFMBUFS IUUQTEPDTSVCZMBOHPSHFONBTUFS(FN%FQSFDBUFIUNM )PXUPUSBOTGPSNDPEF 2
  24. def deprewrite(method_name, to:, from: nil) class_eval do old = "_deprecated_

    #{ method_name}" alias_method old, method_name define_method method_name do |*args, &block| filepath, line = Gem.location_of_caller source = File.read(filepath) # Transformation logic here send old, *args, &block end end end  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT (FU fi MFQBUIBOESFBEUIF fi MFUPEFUFDUBDBMMTJUF )PXUPUSBOTGPSNDPEF 2
  25.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT (FUPrism :: CallNodeXJUIDBMMFSsourceUPCFUSBOTGPSNFE IUUQTEPDTSVCZMBOHPSHFONBTUFS1SJTN7JTJUPSIUNM class CallSiteFinder < Prism

    :: Visitor def initialize(method_name, line, from: nil) # Set instance variables end # @param source [String] source code to search def find(source) parsed_result = Prism.parse(source) parsed_result.value.statements.accept(self) @node # @return [Prism :: CallNode] end def visit_call_node(node) # Find call node here end end )PXUPUSBOTGPSNDPEF 2
  26.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT Prism :: CallNode IUUQTEPDTSVCZMBOHPSHFONBTUFS1SJTN$BMM/PEFIUNM legacy = Legacy.new result

    = legacy.old_method(1, 2) do |a| # block arg end do_something(with: result) DBMMOPEFPG #old_method )PXUPUSBOTGPSNDPEF 2
  27. class CallSiteFinder < Prism :: Visitor def initialize(method_name, line, from:

    nil) @node_query = from ? NodeQuery.new(from, adapter: :prism) : nil end def visit_call_node(node) if @node_query matched = @node_query.query_nodes(node) @node = matched.first if matched.any? else @node = node end end end  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT IUUQTHJUIVCDPNTZOWFSUIROPEFRVFSZSVCZ 6UJMJ[FOPEFRVFSZSVCZUPTUSJDUMZ fi OEDBMMOPEF deprewrite :old_method, from: ".call_node[name=old_method]", to: "new_method( {{ arguments }} )" %FUFDUJOHNFUIPEDBMMTJUFT )PXUPUSBOTGPSNDPEF 2
  28.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $PEFUSBOTGPSNBUJPO class Transformer def initialize(source, node, transform_with) #

    Set instance variables end def transform # @return [String] return @source if @node.nil? before_node = @source[0 . .. @node.location.start_offset] new_code = transform_call_node after_node = @source[@node.location.end_offset .. ] before_node + new_code + after_node end end )PXUPUSBOTGPSNDPEF 2
  29.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $PEFUSBOTGPSNBUJPO class Transformer def initialize(source, node, transform_ #

    Set instance variables end def transform return @source if @node.nil? before_node = @source[0 .. . @node.locat new_code = transform_call_node after_node = @source[@node.location.e .. before_node + new_code + after_node end end legacy = Legacy.new result = legacy.old_method(1, 2) do |a| # block arg end do_something(with: result) *UUSBOTGPSNTPOMZDBMMOPEF  BOEQSFTFSWFTTVSSPVOEJOHDPEFDPOUFYU )PXUPUSBOTGPSNDPEF 2
  30.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $PEFUSBOTGPSNBUJPO IUUQTHJUIVCDPNTZOWFSUIROPEFNVUBUJPOSVCZ class Transformer def transform_call_node adapter =

    NodeMutation :: PrismAdapter.new receiver_code = @node.receiver ? " #{ @node.receiver.slice}." : "" call_node = Prism.parse(@node.slice.gsub(receiver_code, "")). value.statements.body.first receiver_code + adapter.rewritten_source(call_node, @transform_with) end end 6UJMJ[FOPEFNVUBUJPOSVCZUPUSBOTGPSNDBMMOPEF deprewrite :old_method, from: ".call_node[name=old_method]", to: "new_method( {{ arguments }} )" 4FUBT@transform_with )PXUPUSBOTGPSNDPEF 2
  31.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $PEFUSBOTGPSNBUJPO legacy = Legacy.new result = legacy.old_method(1, 2)

    do |a| # block arg end do_something(with: result) legacy = Legacy.new result = legacy.new_method(1, 2) do |a| # block arg end do_something(with: result) 5IJT NFUIPESFOBNJOH JTUIFTJNQMFTUEFQSFDBUJPOQBUUFSO )PXUPUSBOTGPSNDPEF 2
  32.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT .BKPSEFQSFDBUJPOTDFOBSJPT 3FOBNFNFUIPE 5IFNPTUDPNNPOSFGBDUPSJOHPQFSBUJPO ✅ "EEBSHVNFOU T "EEJOHOFXQBSBNFUFSTUPBNFUIPE ✅

    3FNPWFBSHVNFOU T 3FNPWJOHQBSBNFUFSTUIBUBSFOPMPOHFSOFFEFE ✅ $IBOHFBSH T UZQF $POWFSUJOHBSHUZQFTXJUIPVUDIBOHJOHNFUIPEOBNF ❌ $IBOHFSFDFJWFS .PWJOHNFUIPEGSPNPOFPCKFDUUPBOPUIFSPCKFDU ❌ %FMFUFNFUIPE 8JUIPVUBOZSFQMBDFNFOU ❌ *NQMFNFOUBUJPO 4UBUVT )PXUPUSBOTGPSNDPEF 2 'FBUVSFGVODUJPOBMJUZEFQSFDBUJPOBMTPFYJTUT5IJTJTPVUPGTDPQFGPSUIJTQSFTFOUBUJPO
  33.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $IBMMFOHFTPG%FQSFXSJUFS 1 2 3 4 )PXUPXSJUFUSBOTGPSNBUJPOSVMFT  )PXUPUSBOTGPSNDPEF

     *TSFXSJUJOHDPEFBUSVOUJNFTBGF  8JMMUIF3VCZFDPTZTUFNBEPQUJU ✅ ✅ 🤔 *NQMFNFOUBUJPO$PODFSOT &DPTZTUFNXJEF$PODFSOT
  34.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT w *UIPVHIUPGUXPBQQSPBDIFT w 3FXSJUFUIFDBMMFS fi MFEJSFDUMZBOEMPBEUIF fi MF

    w 3FEF fi OFUIFDBMMFSNFUIPEXJUIBNPOLFZQBUDI w #VU XIPXBOUTUPSFXSJUFDPEFPOQSPEVDUJPOBUSVOUJNF  w %FQSFXSJUFSJTTVQQPTFEUPCFBDUJWBUFEJOUFTUPSMPDBM FOWJSPONFOU 3FXSJUJOHDPEFBUSVOUJNFNBZCFOPUTBGF *TSFXSJUJOHDPEFBUSVOUJNFTBGF 3
  35. --- ./script.rb +++ ./script.rb @@ -37,6 +37,6 @@ legecy =

    Legacy.new -legecy.old_method +legecy.new_method  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT 1SPWJEFNPEFTUPIBOEMFSFXSJUUFODPEF -PH.PEF 4IPXXBSOJOHTXJUI TVHHFTUFEDIBOHFT %J ff .PEF (FOFSBUFQBUDI fi MFTUPCF BQQMJFE 3FXSJUF.PEF "VUPNBUJDBMMZVQEBUF TPVSDF fi MFT *TSFXSJUJOHDPEFBUSVOUJNFTBGF 3
  36.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT &YQFDUFEVTBHF NPEF EFTDSJQUJPO FOWJSPONFOU -PH 4IPXXBSOJOHTXJUITVHHFTUFEDIBOHFT TUBHJOH %J

    f (FOFSBUFQBUDI fi MFTGPSSFWJFX MPDBM UFTU 3FXSJUF "VUPNBUJDBMMZVQEBUFTPVSDF fi MFT MPDBM UFTU *TSFXSJUJOHDPEFBUSVOUJNFTBGF 3
  37.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT )PXUPHFOFSBUFEJ ff GPSMPHEJ ff NPEFT class Deprewriter ::

    Diff def to_s original_diff = Diffy :: Diff.new( @source, @rewritten_source, include_diff_info: true, diff: "-u").to_s formatted_timestamp = @timestamp.strftime("%Y-%m-%d %H:%M:%S.%N %z") header = [ " - -- #{ @filepath}\t #{ formatted_timestamp}", " + ++ #{ @filepath}\t #{ formatted_timestamp}" ].join("\n") [header, original_diff.lines[2 .. ].join].join("\n") end end IUUQTHJUIVCDPNTBNHEJ ff Z --- ./script.rb +++ ./script.rb @@ -37,6 +37,6 @@ legecy = Legacy.new -legecy.old_method +legecy.new_method (FOFSBUFEJ ff  *TSFXSJUJOHDPEFBUSVOUJNFTBGF 3
  38.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $IBMMFOHFTPG%FQSFXSJUFS 1 2 3 4 )PXUPXSJUFUSBOTGPSNBUJPOSVMFT  )PXUPUSBOTGPSNDPEF

     *TSFXSJUJOHDPEFBUSVOUJNFTBGF  8JMMUIF3VCZFDPTZTUFNBEPQUJU ✅ ✅ ✅ 🤔 *NQMFNFOUBUJPO$PODFSOT &DPTZTUFNXJEF$PODFSOT
  39. "OOPUBUF USBOTGPSNBUJPOSVMFT 2  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT -JCSBSZ"VUIPS -JCSBSZ6TFS "EE%FQSFXSJUFSUP EFQFOEFODZ 1

    &YFDVUFVTFSDPEF FOBCMJOH%FQSFXSJUFS 3 %FQSFDBUFENFUIPEDBMM USJHHFSTJOUFSDFQUJPO 4 'JOEFYBDUDBMMFS MPDBUJPO 4 5SBOTGPSNDBMMFSDPEF CBTFEPOSVMFT 5 $IBOHFTBSFSFQPSUFE BQQMJFE 6 0SJHJOBMNFUIPE FYFDVUJPODPOUJOVFT 7 5PSFDBQ%FQSFXSJUFSTDPNQMFUFXPSL fl PX 8JMMUIF3VCZFDPTZTUFNBEPQUJU 4 5IJTQBSUJTIBSE
  40. 6TFSDPEF -JCSBSZDPEF  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT *EFBM fl PX -JCSBSZ6TFST -JCSBSZ"VUIPS %FQSFDBUJPOXJUI

    USBOTGPSNBUJPOSVMFT "VUPNBUJDBMMZVQEBUFDPEFXJUI USBOTGPSNBUJPOSVMFT 4IJQHFNTJODMVEJOH%FQSFXSJUFS BOEJUTUSBOTGPSNBUJPOSVMFT 6TFSDPEF 6TFSDPEF 6TF 8JMMUIF3VCZFDPTZTUFNBEPQUJU 4
  41. -JCSBSZDPEF  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $PNQSPNJTFE fl PX -JCSBSZ"VUIPS 4IJQHFNTXJUIPVU%FQSFXSJUFS 6TFSDPEF -JCSBSZ6TFST

    "VUPNBUJDBMMZVQEBUFDPEFXJUI USBOTGPSNBUJPOSVMFT 6TFSDPEF 6TFSDPEF &BDIVTFSJOTUBMM%FQSFXSJUFS BOEXSJUFTUSBOTGPSNBUJPOSVMFT 💦 💦 💦 6TF 8JMMUIF3VCZFDPTZTUFNBEPQUJU 4
  42. 6TFSDPEFXJUI%FQSFXSJUFS 8SJUFBSVMFXJUIBNPOLFZQBUDI -JCSBSZDPEFXJUIPVU%FQSFXSJUFS /PUIJOHDIBOHFT  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $PNQSPNJTFE fl PX class

    Legacy def old_method(arg) # do old thing end def new_method(arg) # do new thing end end require "deprewriter" class Legacy extend Deprewriter deprewrite :old_method, to: "new_method( {{ arguments } } )" end 8JMMUIF3VCZFDPTZTUFNBEPQUJU 4
  43.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT w %FQSFXSJUFSJTKVTUBUIJSEQBSUZHFN OPUBMBOHVBHFCVJMUJO GFBUVSF w *UTOPUSFBMJTUJDUPGPSDFBMMMJCSBSZBVUIPSTUPVTFJU w "UUIJTTUBHF

    NPTUVTFDBTFTXJMMCFGPSVTFSTUPJOTUBMMUIF EFQSFXSJUFSUIFNTFMWFTBOEXSJUFUIFJSPXOUSBOTGPSNBUJPO SVMFT 8JMMUIF3VCZFDPTZTUFNBEPQUJU 8JMMUIF3VCZFDPTZTUFNBEPQUJU 4
  44.  %FQSFXSJUFS3VCZ*NQMFNFOUBUJPO%FUBJMT $IBMMFOHFTPG%FQSFXSJUFS 1 2 3 4 )PXUPXSJUFUSBOTGPSNBUJPOSVMFT  )PXUPUSBOTGPSNDPEF

     *TSFXSJUJOHDPEFBUSVOUJNFTBGF  8JMMUIF3VCZFDPTZTUFNBEPQUJU ✅ ✅ ✅ ❌ *NQMFNFOUBUJPO$PODFSOT &DPTZTUFNXJEF$PODFSOT
  45.  'VUVSF1PTTJCJMJUJFT w $BOUSFXSJUFDPNQMFYNFUIPE DBMMT NFUBQSPHSBNNJOHFUD  w /PUF ffi

    DJFOU3FXSJUJOHSVOT FWFSZUJNFXIFOBEFQSFDBUFE NFUIPEJTDBMMFE w /PUTUBOEBMPOF EFQFOETPO OPOTUBOEBSE3VCZMJCSBSJFT $VSSFOUMJNJUBUJPOT 5IFQBUIGPSXBSE w )BOEMFNPSFDPNQMFYNFUIPE DBMMT w 0QUJNJ[FCZTLJQQJOH QSPDFTTJOHPOTVCTFRVFOU NFUIPEDBMMTBGUFSUIF fi STUDBMM w #FTUBOEBMPOFCZSFEVDJOH EFQFOEFODJFT ➡
  46.  "QQFOEJY w %FQSFXSJUFSJO3VCZ w IUUQTHJUIVCDPNPICBSZFEFQSFXSJUFSSVCZ w 1IBSP w IUUQTQIBSPPSH

    w %FQSFXSJUFS0OUIF fl ZSFXSJUJOHNFUIPEEFQSFDBUJPOT   w IUUQTJOSJBIBMTDJFODFIBMEPDVNFOU w %FQ.JOFS"VUPNBUJD3FDPNNFOEBUJPOPG5SBOTGPSNBUJPO3VMFTGPS.FUIPE %FQSFDBUJPO   w IUUQTSNPE fi MFTMJMMFJOSJBGS5FBN5FYUT1BQFST;BJUB*$43%FQSFXSJUFSQEG
  47.  "QQFOEJY w 4ZOWFSU w IUUQTTZOWFSUOFU w IUUQTHJUIVCDPNTZOWFSUIROPEFRVFSZSVCZ w IUUQTHJUIVCDPNTZOWFSUIROPEFNVUBUJPOSVCZ

    w IUUQTSVCZLBJHJPSHQSFTFOUBUJPO43JDIBSE)VBOH w %J ff Z w IUUQTHJUIVCDPNTBNHEJ ff Z w )PXXFBVUPNBUJDBMMZ fi YFEUIPVTBOETPG3VCZEFQSFDBUJPOXBSOJOHT   w IUUQTBCPVUHJUMBCDPNCMPHIPXXFBVUPNBUJDBMMZ fi YFEIVOESFETPGSVCZEFQSFDBUJPOXBSOJOHT w %FQSFDBUJPO5PPMLJU w IUUQTHJUIVCDPNTIPQJGZEFQSFDBUJPO@UPPMLJU w IUUQTTIPQJGZFOHJOFFSJOHJOUSPEVDJOHUIFEFQSFDBUJPOUPPMLJU w 5IF$PNQMFUF(VJEFGPS%FQSFDBUJPO8BSOJOHTJO3BJMT   w IUUQTXXXGBTUSVCZJPCMPHSBJMTVQHSBEFTEFQSFDBUJPOXBSOJOHTSBJMTHVJEFIUNM