Conditional class opening in Ruby
resolv-replace library monkey-patches the SOCKSSocket class under specific conditions.
In this article, we’re going to explore the following topics:
- How to enable
SOCKSSocketat Ruby interpreter compilation
- how the
resolv-replacelibrary check if Ruby has been compiled with
Before to start
I’m thrilled to share with you our latest project: Fun Facts about Ruby — Volume 1
Please feel free to spread the word and share this link! 🙏
Fun Facts about Ruby — Volume 1
Fun Facts about Ruby — Volume 1 is a collection of cards..
Thank you for your time!
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
SOCKSSocket is an optional feature of Ruby
irb> require "socket"
irb> defined? SOCKSSocket
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
?> ./configure --enable-socks
?> make && make install
2.7.1 :001> require "socket"
2.7.1 :002> defined? SOCKSSocket
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
SOCKSSocketis not loaded you must probably add this option to your
enable_option_checking=nobefore 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
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
So, as the
class keyword is only a syntactic sugar for class definition and class opening, then you can call a modifier-if to execute this code (or not).
Opening a class only if this class is already defined isn’t a common pattern. But when you deal with external library and the optional features provided by the Ruby interpreter, you need to ensure that the class is defined before any modification.