dev-to-pywrcp.txt (26200B)
1 [1]Skip to content 2 [3] DEV Community 3 [4][ ] 4 [6] 5 [7] Log in [8] Create account 6 7 DEV Community 8 9 ● Add reaction 10 [sp] Like [mu] Unicorn [ex] Exploding Head [ra] Raised Hands [fi] Fire 11 Jump to Comments Save 12 Copy link 13 Copied to Clipboard 14 [20] Share to Twitter [21] Share to LinkedIn [22] Share to Reddit [23] Share to 15 Hacker News [24] Share to Facebook [25] Share to Mastodon 16 [26]Share Post via... [27]Report Abuse 17 [28] Cover image for Decorating Ruby - Part Two - Method Added Decoration 18 [29]Brandon Weaver 19 [30]Brandon Weaver 20 21 Posted on Aug 18, 2019 • Updated on Jan 21, 2021 22 23 ● ● ● ● ● 24 25 Decorating Ruby - Part Two - Method Added Decoration 26 27 [31]#ruby 28 29 [32]Decorating Ruby (3 Part Series) 30 31 [33] 1 Decorating Ruby - Part One - Symbol Method Decoration [34] 2 Decorating 32 Ruby - Part Two - Method Added Decoration [35] 3 Decorating Ruby - Part Three - 33 Prepending Decoration 34 35 One precursor of me writing an article is if I keep forgetting how something's 36 done, causing me to write a reference to look back on for later. This is one 37 such article. 38 39 [36] What's in Store for Today? 40 41 We'll be looking at the next type of decoration, which involves intercepting 42 method_added to make a more fluent interface. 43 44 [37]The "Dark Lord" Crimson with Metaprogramming magic 45 46 Table of Contents 47 48 • [38]Part One - Symbol Method Decoration 49 • [39]Part Two - Method Added Decoration 50 • [40]Part Three - Prepending Decoration 51 52 [41]<< Previous | [42]Next >> 53 54 [43] What Does Method Added Decoration Look Like? 55 56 You've seen the Symbol Method variant: 57 58 private def something; end 59 60 Readers that were paying very close attention in the last article may have 61 noticed when I said that I preferred that style of declaring private methods in 62 Ruby, but this was after the way that can be debatably considered more popular 63 and widely used in the community: 64 65 private 66 67 def something; end 68 def something_else; end 69 70 Using private like this means that every method defined after will be 71 considered private. We know how the first one works, but what about the second? 72 There's no way it's using method names because it catches both of those methods 73 and doesn't change the definition syntax. 74 75 That's what we'll be looking into and learning today, and let me tell you it's 76 a metaprogramming trip. 77 78 [44] Making Our Own Method Added Decoration 79 80 As with the last article we're going to need to learn about a few tools before 81 we'll be ready to implement this one. 82 83 [45] Module Inclusion 84 85 Ruby uses Module inclusion as a way to extend classes with additional behavior, 86 sometimes requiring an interface to be met before it can do so. Enumerable is 87 one of the most common, and requires an each implementation to work: 88 89 class Collection 90 include Enumerable 91 92 def initialize(*items) 93 @items = items 94 end 95 96 def each(&fn) 97 return @items.to_enum unless block_given? 98 @items.each { |item| fn.call(item) } 99 end 100 end 101 102 (yield could be used here instead, but is less explicit and can be confusing to 103 teach.) 104 105 By defining that one method we've given our class the ability to do all types 106 of amazing things like map, select, and more. 107 108 Through those few lines we've added a lot of functionality to a class. Here's 109 the interesting part about Ruby: it also provides hooks to let Enumerable know 110 it was included, including what included it. 111 112 [46] Feeling Included 113 114 Let's say we have our own module, [47]Affable, which gives us a method to say 115 "hi": 116 117 module Affable 118 def greeting 119 "It's so very lovely to see you today!" 120 end 121 end 122 123 My, it is quite an [48]Affable module, now isn't it? 124 125 We could even go as far as to make a particularly Affable lemur: 126 127 class Lemur 128 include Affable 129 def initialize(name) @name = name; end 130 end 131 132 Lemur.new("Indigo").greeting 133 => "It's so very lovely to see you today!" 134 135 What a classy lemur, yes. 136 137 [49] Hook, Line, and Sinker 138 139 Let's say that we wanted to tell what particular animal was Affable. We can use 140 included to see just that: 141 142 module Affable 143 def self.included(klass) 144 puts "#{klass.name} has become extra Affable!" 145 end 146 end 147 148 If we were to re-include that module: 149 150 class Lemur 151 include Affable 152 def initialize(name) @name = name; end 153 end 154 155 # STDOUT: Lemur has become extra Affable! 156 # => :initialize 157 158 Right classy. Oh, right, speaking of classy... 159 160 [50] Extra Classy Indeed 161 162 So we can hook inclusion of a module, great! Why do we care? 163 164 What if we wanted to both include methods into a class as well as extend its 165 behavior? 166 167 With just include it will apply all the behavior to instances of a class. With 168 just extend it will apply all the behavior to the class itself. We can't do 169 both. 170 171 ...ok ok, it's Ruby, you caught me, we can totally do both. 172 173 As it turns out, include and extend are just methods on a class. We could just 174 Lemur.extend(ExtraBehavior) if we wanted to, or we could use our fun little 175 hooks from earlier. 176 177 A common convention for using this technique is a sub-module called 178 ClassMethods, like so: 179 180 module Affable 181 def self.included(klass) 182 klass.extend(ClassMethods) 183 end 184 185 module ClassMethods 186 def affable? 187 true 188 end 189 end 190 end 191 192 This allows us to inject behavior directly into the class as well as other 193 behavior we want to include in instances. 194 195 Part of me thinks this is so I don't have to remember the difference between 196 include and extend, but I always remember that and don't have to spend 20 197 minutes flipping between the two and prepend to see which one actually works, 198 absolutely not. 199 200 Now remember the title about Method Added being the technique for today? Oh 201 yes, there's a hook for that as well, but first we need to indicate that 202 something needs to be hooked in the first place. 203 204 [51] Raise Your Flag 205 206 We can intercept a method being added, but how do we know which method should 207 be intercepted? We'd need to add a flag to let that hook know it's time to 208 start intercepting in full force. 209 210 module Affable 211 def self.included(klass) 212 klass.extend(ClassMethods) 213 end 214 215 module ClassMethods 216 def extra_affable 217 @extra_affable = true 218 end 219 end 220 end 221 222 If you remember private, this could be the flag to indicate that every method 223 afterwards should be private: 224 225 private 226 227 def something; end 228 def something_else; end 229 230 Same idea here, and once a flag is raised it can also be taken down to make 231 sure later methods aren't impacted as well. We keep hinting at hooking method 232 added, so let's go ahead and do just that. 233 234 [52] Method Added 235 236 Now that we have our flag, we have enough to hook into method_added: 237 238 module Affable 239 def self.included(klass) 240 klass.extend(ClassMethods) 241 end 242 243 module ClassMethods 244 def extra_affable 245 @extra_affable = true 246 end 247 248 def method_added(method_name) 249 return unless @extra_affable 250 251 @extra_affable = false 252 # ... 253 end 254 end 255 end 256 257 We can use our flag to ignore method_added unless said flag is set. After we 258 check that, we can take down the flag to make sure additional methods defined 259 after aren't affected as well. For private this doesn't happen, but we want to 260 be polite. It is and Affable module after all. 261 262 [53] Politely Aliasing 263 264 Speaking of politeness, it's not precisely kind to just overwrite a method 265 without giving a way to call it as it was. We can use alias_method to get a new 266 name to the method before we overwrite it: 267 268 def method_added(method_name) 269 return unless @extra_affable 270 271 @extra_affable = false 272 273 original_method_name = "#{method_name}_without_affability".to_sym 274 alias_method original_method_name, method_name 275 end 276 277 This means that we can access the original method through this name. 278 279 [54] Wrap Battle 280 281 So we have the original method aliased, our hook in place, let's get to 282 overwriting that method then! As with the last tutorial we can use 283 define_method to do this: 284 285 module Affable 286 def self.included(klass) 287 klass.extend(ClassMethods) 288 end 289 290 module ClassMethods 291 def extra_affable 292 @extra_affable = true 293 end 294 295 def method_added(method_name) 296 return unless @extra_affable 297 298 @extra_affable = false 299 300 original_method_name = "#{method_name}_without_affability".to_sym 301 alias_method original_method_name, method_name 302 303 define_method(method_name) do |*args, &fn| 304 original_result = send(original_method_name, *args, &fn) 305 306 "#{original_result} Very lovely indeed!" 307 end 308 end 309 end 310 end 311 312 Overwriting our original class again: 313 314 class Lemur 315 include Affable 316 317 def initialize(name) @name = name; end 318 319 extra_affable 320 321 def farewell 322 "Farewell! It was lovely to chat." 323 end 324 end 325 326 We can give it a try: 327 328 Lemur.new("Indigo").farewell 329 => "Farewell! It was lovely to chat. Very lovely indeed!" 330 331 [55] send Help! 332 333 Wait wait wait wait, send? Didn't we use method last time? 334 335 We did, but remember that method_added is a class method that does not have the 336 context of an instance of the class, or in other words it has no idea where the 337 farewell method is located. 338 339 send lets us treat this as an instance again by sending the method name 340 directly. Now we could use method inside of here as well, but that can be a bit 341 more expensive. 342 343 Only the contents inside define_method's block are executed in the context of 344 the instance. 345 346 [56] executive Functions 347 348 If we wanted to, we could have our special method take blocks which execute in 349 the context of an instance as well, and this is an extra special bonus trick 350 for this post. 351 352 Say that we made extra_affable also take a block that allows us to manipulate 353 the original value and still execute in the context of the instance: 354 355 class Lemur 356 include Affable 357 358 def initialize(name) @name = name; end 359 360 extra_affable { |original| 361 "#{@name}: #{original} Very lovely indeed!" 362 } 363 364 def farewell 365 "Farewell! It was lovely to chat." 366 end 367 end 368 369 With normal blocks, this will evaluate in the context of the class, but we want 370 it to evaluate in the context of the instance instead. That's what we have 371 instance_exec for: 372 373 module Affable 374 def self.included(klass) 375 klass.extend(ClassMethods) 376 end 377 378 module ClassMethods 379 def extra_affable(&fn) 380 @extra_affable = true 381 @extra_affable_fn = fn 382 end 383 384 def method_added(method_name) 385 return unless @extra_affable 386 387 @extra_affable = false 388 extra_affable_fn = @extra_affable_fn 389 390 original_method_name = "#{method_name}_without_affability".to_sym 391 alias_method original_method_name, method_name 392 393 define_method(method_name) do |*args, &fn| 394 original_result = send(original_method_name, *args, &fn) 395 instance_exec(original_result, &extra_affable_fn) 396 end 397 end 398 end 399 end 400 401 Running that gives us this: 402 403 Lemur.new("Indigo").farewell 404 # => "Indigo: Farewell! It was lovely to chat. Very lovely indeed!" 405 406 Now pay very close attention to this line: 407 408 extra_affable_fn = @extra_affable_fn 409 410 We need to use this because inside define_method's block is inside the 411 instance, which has no clue what @extra_affable_fn is. That said, it can still 412 see outside to the context where the block was called, meaning it can see that 413 local version of extra_affable_fn sitting right there, allowing us to call it: 414 415 instance_exec(original_result, &extra_affable_fn) 416 417 [57] instance_eval vs instance_exec? 418 419 Why not use instance_eval? instance_exec allows us to pass along arguments as 420 well, otherwise instance_eval would make a lot of sense to evaluate something 421 in an instance. Instead, we need to execute something in the context of an 422 instance, so we use instance_exec here. 423 424 [58] Wrapping Up 425 426 So that was quite a lot of magic, and it took me a fair bit to really 427 understand what some of it was doing and why. That's perfectly ok, if I 428 understood everything the first time I'd be worried because that means I'm not 429 really learning anything! 430 431 One issue I think this will have later is I wonder how poorly having multiple 432 hooks to method_added will work. If it turns out it makes things go boom in a 433 spectacularly pretty and confounding way there'll be a part three. If not, this 434 paragraph will disappear and I'll pretend to not know what you're talking about 435 if you ask me about it. 436 437 There's a lot of potential here for some really interesting things, but there's 438 also a lot of potential for abuse. Be sure to not abuse such magic, because for 439 every layer of redefinition code can become increasingly harder to reason about 440 and test later. 441 442 In most cases I would instead advocate for SimpleDelegate, Forwardable, or 443 simple inheritance with super to extend behavior of classes. Don't use a 444 chainsaw where hedge trimmers will do, but on occasion it's nice to know a 445 chainsaw is there for those particularly gnarly problems. 446 447 Discretion is the name of the game. 448 449 Table of Contents 450 451 • [59]Part One - Symbol Method Decoration 452 • [60]Part Two - Method Added Decoration 453 • [61]Part Three - Prepending Decoration 454 455 [62]<< Previous | [63]Next >> 456 457 [64]Decorating Ruby (3 Part Series) 458 459 [65] 1 Decorating Ruby - Part One - Symbol Method Decoration [66] 2 Decorating 460 Ruby - Part Two - Method Added Decoration [67] 3 Decorating Ruby - Part Three - 461 Prepending Decoration 462 463 Top comments (2) 464 465 Subscribe 466 pic 467 [ ] 468 Personal Trusted User 469 [75] Create template 470 471 Templates let you quickly answer FAQs or store snippets for re-use. 472 473 Submit Preview [78]Dismiss 474 475 [79] edisonywh profile image 476 [80] Edison Yap 477 Edison Yap 478 [82] [https] Edison Yap 479 Follow 480 An aspiring software engineer from the tiny city of Kuala Lumpur. 481 482 • Location 483 Stockholm, Sweden 484 • Education 485 RMIT University, Melbourne 486 • Work 487 Software Engineer at Klarna 488 • Joined 489 Jul 25, 2018 490 491 • [84] Aug 18 '19 • Edited on Aug 18 • Edited 492 493 • [86]Copy link 494 • 495 • Hide 496 • 497 • 498 • 499 500 Wow this is really cool, thanks for sharing Brandon! 501 502 Is there a way to hook onto the last method_added? For example I'd like to 503 execute something after all methods are added 504 505 EDIT: also quick search online seems to say that method_added only works for 506 instance methods, but there's singleton_method_added hook for class methods 507 too! 508 509 1 like Like [89] Reply 510 511 [90] baweaver profile image 512 [91] Brandon Weaver 513 Brandon Weaver 514 [93] [https] Brandon Weaver 515 Follow 516 Principal Ruby Engineer at Gusto on Payroll Services. Autistic / ADHD, He / 517 Him. I'm the Lemur guy. 518 519 • Location 520 San Francisco, CA 521 • Work 522 Principal Engineer - Payroll Services at Gusto 523 • Joined 524 Jan 16, 2019 525 526 • [95] Aug 18 '19 • Edited on Aug 18 • Edited 527 528 • [97]Copy link 529 • 530 • Hide 531 • 532 • 533 • 534 535 Technically in Ruby there's never a point in which methods are no longer added, 536 so it's a bit hard to hook that. One potential is to use TracePoint to hook the 537 ending of a class definition and retaining a class of "infected" classes, but 538 that'd be slow. 539 540 Look for "Class End Event" in this article: [99]medium.com/@baweaver/ 541 exploring-tra... 542 543 EDIT - ...though now I'm curious if one could use such things to freeze a class 544 from modifications. 545 546 1 like Like [101] Reply 547 [102]Code of Conduct • [103]Report abuse 548 549 Are you sure you want to hide this comment? It will become hidden in your post, 550 but will still be visible via the comment's [107]permalink. 551 552 [109][ ] 553 554 Hide child comments as well 555 556 Confirm 557 558 For further actions, you may consider blocking this person and/or [111] 559 reporting abuse 560 561 Read next 562 563 [112] 564 cherryramatis profile image 565 566 Bringing more sweetness to Ruby with Sorbet types 🍦 567 568 Cherry Ramatis - Sep 18 '23 569 570 [113] 571 hungle00 profile image 572 573 Ruby's main object 574 575 hungle00 - Oct 1 '23 576 577 [114] 578 braindeaf profile image 579 580 Making a YouTube Short 581 582 RobL - Sep 28 '23 583 584 [115] 585 iberianpig profile image 586 587 Enhance Your Touchpad Experience on Linux with ThumbSense! 588 589 Kohei Yamada - Sep 27 '23 590 591 [116] [https] Brandon Weaver 592 Follow 593 Principal Ruby Engineer at Gusto on Payroll Services. Autistic / ADHD, He / 594 Him. I'm the Lemur guy. 595 596 • Location 597 San Francisco, CA 598 • Work 599 Principal Engineer - Payroll Services at Gusto 600 • Joined 601 Jan 16, 2019 602 603 More from [118]Brandon Weaver 604 605 [119] Understanding Ruby - Memoization 606 #ruby #beginners 607 [120] In Favor of Ruby Central Memberships 608 #ruby #community 609 [121] Pattern Matching Interfaces in Ruby 610 #ruby #rails #functional 611 612 Once suspended, baweaver will not be able to comment or publish posts until 613 their suspension is removed. 614 615 [ ] 616 [ ] 617 [ ] 618 Note: [ ] 619 620 Submit & Suspend 621 622 Once unsuspended, baweaver will be able to comment and publish posts again. 623 624 [ ] 625 [ ] 626 [ ] 627 Note: [ ] 628 629 Submit & Unsuspend 630 631 Once unpublished, all posts by baweaver will become hidden and only accessible 632 to themselves. 633 634 If baweaver is not suspended, they can still re-publish their posts from their 635 dashboard. 636 637 Note:[ ] 638 639 Unpublish all posts 640 641 Once unpublished, this post will become invisible to the public and only 642 accessible to Brandon Weaver. 643 644 They can still re-publish the post if they are not suspended. 645 646 Unpublish Post 647 648 Thanks for keeping DEV Community safe. Here is what you can do to flag 649 baweaver: 650 651 [129]( ) Make all posts by baweaver less visible 652 653 baweaver consistently posts content that violates DEV Community's code of 654 conduct because it is harassing, offensive or spammy. 655 656 [130] Report other inappropriate conduct 657 658 Confirm Flag 659 660 Unflagging baweaver will restore default visibility to their posts. 661 662 Confirm Unflag 663 664 [133]DEV Community — A constructive and inclusive social network for software 665 developers. With you every step of your journey. 666 667 • [134] Home 668 • [135] Podcasts 669 • [136] Videos 670 • [137] Tags 671 • [138] FAQ 672 • [139] Forem Shop 673 • [140] Advertise on DEV 674 • [141] About 675 • [142] Contact 676 • [143] Guides 677 • [144] Software comparisons 678 679 • [145] Code of Conduct 680 • [146] Privacy Policy 681 • [147] Terms of use 682 683 Built on [148]Forem — the [149]open source software that powers [150]DEV and 684 other inclusive communities. 685 686 Made with love and [151]Ruby on Rails. DEV Community © 2016 - 2024. 687 688 DEV Community 689 690 We're a place where coders share, stay up-to-date and grow their careers. 691 692 [152] Log in [153] Create account 693 ● ● ● ● ● 694 695 References: 696 697 [1] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#main-content 698 [3] https://dev.to/ 699 [6] https://dev.to/search 700 [7] https://dev.to/enter 701 [8] https://dev.to/enter?state=new-user 702 [20] https://twitter.com/intent/tweet?text=%22Decorating%20Ruby%20-%20Part%20Two%20-%20Method%20Added%20Decoration%22%20by%20%40keystonelemur%20%23DEVCommunity%20https%3A%2F%2Fdev.to%2Fbaweaver%2Fdecorating-ruby-part-two-method-added-decoration-48mj 703 [21] https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fdev.to%2Fbaweaver%2Fdecorating-ruby-part-two-method-added-decoration-48mj&title=Decorating%20Ruby%20-%20Part%20Two%20-%20Method%20Added%20Decoration&summary=How%20various%20forms%20of%20method%20decoration%20work%20in%20Ruby&source=DEV%20Community 704 [22] https://www.reddit.com/submit?url=https%3A%2F%2Fdev.to%2Fbaweaver%2Fdecorating-ruby-part-two-method-added-decoration-48mj&title=Decorating%20Ruby%20-%20Part%20Two%20-%20Method%20Added%20Decoration 705 [23] https://news.ycombinator.com/submitlink?u=https%3A%2F%2Fdev.to%2Fbaweaver%2Fdecorating-ruby-part-two-method-added-decoration-48mj&t=Decorating%20Ruby%20-%20Part%20Two%20-%20Method%20Added%20Decoration 706 [24] https://www.facebook.com/sharer.php?u=https%3A%2F%2Fdev.to%2Fbaweaver%2Fdecorating-ruby-part-two-method-added-decoration-48mj 707 [25] https://toot.kytta.dev/?text=https%3A%2F%2Fdev.to%2Fbaweaver%2Fdecorating-ruby-part-two-method-added-decoration-48mj 708 [26] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj# 709 [27] https://dev.to/report-abuse 710 [28] https://res.cloudinary.com/practicaldev/image/fetch/s--UjPHgJnM--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://thepracticaldev.s3.amazonaws.com/i/rdvh6fph3zoga5f9pw98.png 711 [29] https://dev.to/baweaver 712 [30] https://dev.to/baweaver 713 [31] https://dev.to/t/ruby 714 [32] https://dev.to/baweaver/series/10894 715 [33] https://dev.to/baweaver/decorating-ruby-part-1-symbol-method-decoration-4po2 716 [34] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj 717 [35] https://dev.to/baweaver/decorating-ruby-part-three-prepending-decoration-1ehc 718 [36] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#whats-in-store-for-today 719 [37] https://res.cloudinary.com/practicaldev/image/fetch/s--L5_TPTzS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/5pzy2brl5apjtt4edgrm.png 720 [38] https://dev.to/baweaver/decorating-ruby-part-1-symbol-method-decoration-4po2 721 [39] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj 722 [40] https://dev.to/baweaver/decorating-ruby-part-three-prepending-decoration-1ehc 723 [41] https://dev.to/baweaver/decorating-ruby-part-1-symbol-method-decoration-4po2 724 [42] https://dev.to/baweaver/decorating-ruby-part-three-prepending-decoration-1ehc 725 [43] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#what-does-method-added-decoration-look-like 726 [44] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#making-our-own-method-added-decoration 727 [45] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#module-inclusion 728 [46] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#feeling-included 729 [47] https://www.merriam-webster.com/dictionary/affable 730 [48] https://www.merriam-webster.com/dictionary/affable 731 [49] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#hook-line-and-sinker 732 [50] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#extra-classy-indeed 733 [51] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#raise-your-flag 734 [52] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#method-added 735 [53] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#politely-aliasing 736 [54] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#wrap-battle 737 [55] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#-raw-send-endraw-help 738 [56] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#-raw-exec-endraw-utive-functions 739 [57] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#-raw-instanceeval-endraw-vs-raw-instanceexec-endraw- 740 [58] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#wrapping-up 741 [59] https://dev.to/baweaver/decorating-ruby-part-1-symbol-method-decoration-4po2 742 [60] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj 743 [61] https://dev.to/baweaver/decorating-ruby-part-three-prepending-decoration-1ehc 744 [62] https://dev.to/baweaver/decorating-ruby-part-1-symbol-method-decoration-4po2 745 [63] https://dev.to/baweaver/decorating-ruby-part-three-prepending-decoration-1ehc 746 [64] https://dev.to/baweaver/series/10894 747 [65] https://dev.to/baweaver/decorating-ruby-part-1-symbol-method-decoration-4po2 748 [66] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj 749 [67] https://dev.to/baweaver/decorating-ruby-part-three-prepending-decoration-1ehc 750 [75] https://dev.to/settings/response-templates 751 [78] https://dev.to/404.html 752 [79] https://dev.to/edisonywh 753 [80] https://dev.to/edisonywh 754 [82] https://dev.to/edisonywh 755 [84] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#comment-e96o 756 [86] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#comment-e96o 757 [89] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#/baweaver/decorating-ruby-part-two-method-added-decoration-48mj/comments/new/e96o 758 [90] https://dev.to/baweaver 759 [91] https://dev.to/baweaver 760 [93] https://dev.to/baweaver 761 [95] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#comment-e9g0 762 [97] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#comment-e9g0 763 [99] https://medium.com/@baweaver/exploring-tracepoint-in-ruby-part-two-events-f4fd291992f5 764 [101] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj#/baweaver/decorating-ruby-part-two-method-added-decoration-48mj/comments/new/e9g0 765 [102] https://dev.to/code-of-conduct 766 [103] https://dev.to/report-abuse 767 [107] https://dev.to/baweaver/decorating-ruby-part-two-method-added-decoration-48mj# 768 [111] https://dev.to/report-abuse 769 [112] https://dev.to/cherryramatis/bringing-more-sweetness-to-ruby-with-sorbet-types-13jp 770 [113] https://dev.to/hungle00/rubys-main-object-5hni 771 [114] https://dev.to/braindeaf/making-a-youtube-short-5gih 772 [115] https://dev.to/iberianpig/enhance-your-touchpad-experience-on-linux-with-thumbsense-391n 773 [116] https://dev.to/baweaver 774 [118] https://dev.to/baweaver 775 [119] https://dev.to/baweaver/understanding-ruby-memoization-2be5 776 [120] https://dev.to/baweaver/in-favor-of-ruby-central-memberships-15gl 777 [121] https://dev.to/baweaver/pattern-matching-interfaces-in-ruby-1b15 778 [130] javascript:void(0); 779 [133] https://dev.to/ 780 [134] https://dev.to/ 781 [135] https://dev.to/pod 782 [136] https://dev.to/videos 783 [137] https://dev.to/tags 784 [138] https://dev.to/faq 785 [139] https://shop.forem.com/ 786 [140] https://dev.to/advertise 787 [141] https://dev.to/about 788 [142] https://dev.to/contact 789 [143] https://dev.to/guides 790 [144] https://dev.to/software-comparisons 791 [145] https://dev.to/code-of-conduct 792 [146] https://dev.to/privacy 793 [147] https://dev.to/terms 794 [148] https://www.forem.com/ 795 [149] https://dev.to/t/opensource 796 [150] https://dev.to/ 797 [151] https://dev.to/t/rails 798 [152] https://dev.to/enter 799 [153] https://dev.to/enter?state=new-user