Source: unsplash.com

Conditional class opening in Ruby

Why the resolv-replace library monkey-patches the SOCKSSocket class under specific conditions.

Tech - RubyCademy
RubyCademy
Published in
3 min readSep 13, 2020

--

In this article, we’re going to explore the following topics:

  • How to enable SOCKSSocket at Ruby interpreter compilation
  • how the resolv-replace library check if Ruby has been compiled with SOCKSSocket

SOCKS Sockets

SOCKS is an Internet protocol that exchanges network packets between a client and server through a proxy server.

Ruby provides an interface to the SOCKS protocol through SOCKSSocket class. This class directly inherits from TCPSocket. SOCKSSocket is an optional feature of Ruby

irb> require "socket"
=> true
irb> defined? SOCKSSocket
=> nil

Here we can see that SOCKSSocket is not defined within Ruby 2.7.1 by default.

To add this feature to your Ruby interpreter, you must recompile Ruby with the --enable-socks flag

?> ./configure --enable-socks
...
?> make && make install
..
?> irb
2.7.1 :001> require "socket"
=> true
2.7.1 :002> defined? SOCKSSocket

=> "constant"

In the above example, we recompile our Ruby interpreter by adding --enable-socks. This flag provides the SOCKS C Macro that is used to enable the loading of the SOCKSSocket class at runtime.

Note that if SOCKSSocket is not loaded you must probably add this option to your configure file: enable_option_checking=no before to restart the compilation process.

Now that we’re more familiar with the fact that the default compiled Ruby interpreter doesn’t load all the classes provided by Ruby and that you must recompile your Ruby interpreter to explicitly add these classes, let’s see how the resolv-replace library — available in the Ruby Standard Library — handles the case of monkey-patching (or not) the SOCKSSocket class.

resolv-replace and SOCKSSocket

This library simply monkey-patches (IP|TCP|UDP|SOCKS)Socket classes provided by the socket library to use the Resolv DNS resolver.

In the case of SOCKSSocket, the monkey-patching only intervenes when the Ruby interpreter is compiled with the --enable-socks flag. So let’s see how the resolv-replace library handles this tricky case

Notice the modifier-if line 10. Indeed, to choose to monkey-patch this class or not, the resolv-replace library simply checks if the SOCKSSocket constant is defined using the defined? keyword. Indeed, as seen in the previous section, SOCKSSocket is only defined if the Ruby interpreter is compiled using the --enable-flag.

So, as the class keyword is only syntactic sugar for class definition and class opening, then you can call a modifier-if to execute this code (or not).

Conclusion

Opening a class only if this class is already defined isn’t a common pattern. But when you deal with an external library and the optional features provided by the Ruby interpreter, you need to ensure that the class is defined before any modification.

Ruby Mastery

We’re currently finalizing our first online course: Ruby Mastery.

Join the list for an exclusive release alert! 🔔

🔗 Ruby Mastery by RubyCademy

Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.

💚

--

--