jeremyevans/ruby-refrigerator: Freeze all core ruby classes
December 31, 2024

jeremyevans/ruby-refrigerator: Freeze all core ruby classes

Refrigerator provides a simple way to freeze all Ruby core classes and modules. It is designed for use in production and testing to ensure that no code makes unintended changes to core classes or modules at runtime.

gem install refrigerator

The source code is available on GitHub: github.com/jeremyevans/ruby-refrigerator

After all of your application’s code is loaded, you can call freeze_core Ways to freeze all core categories:

require 'refrigerator'
Refrigerator.freeze_core

This will freeze all core classes so modifications to them at runtime will throw exceptions.

In a rack-based application, a good place to call “freeze_core” is at the end of the “config.ru” file.

You can also pass the :except option to freeze_core With an array of category names that is not frozen:

Refrigerator.freeze_core(:except=>['BasicObject'])

One reason to exclude certain categories is because you know they will be modified at runtime.

A refrigerator is also provided check_require Method to check if the library has made modifications to core classes. It allows you to easily see what’s failing when you try to require a library with frozen cores, and provides some options you can use to try to get the requirements to not throw exceptions. This allows you to view changes made to core categories by the library. This is a basic usage example:

Refrigerator.check_require('open3', :modules=>[:Open3])

this check_require The method takes the following options:

:module

Defines the given mod name before freezing the core (array of symbols)

:course

Define the given category name before freezing the core (symbol array or two element array with category name symbol and supercategory name symbol)

:exclude

Exclude the given category/mod name from freezing (array of strings)

:depending on

Any dependencies needed before freezing the core (array of strings)

Without any choice, check_require May throw an exception as it freezes the core before requesting, failing if the required archive attempts to add a class or module to the global namespace. The presence of the :modules and :classes options allows you to predefine classes so that the required files will reopen existing classes instead of defining new ones.

The :depends option can be easily used to load all dependencies of a required file before freezing the core. This is also necessary in most cases, especially when using stdlib, since many stdlib files modify core classes in ways other than adding modules or classes. The :exclude option is basically a last resort where you can disable freezing of required libraries if you know they modify some core classes.

Here is an example using Sequel, a ruby ​​library toolkit:

Refrigerator.check_require 'sequel',
  :depends=>%w'bigdecimal date thread time uri',
  :modules=>[:Sequel]

Here’s another example using Roda, a Ruby web toolkit:

Refrigerator.check_require 'roda',
  :depends=>%w'rack uri fileutils set tmpdir tempfile thread date time',
  :classes=>[:Roda]

Note that many stdlib libraries will fail check_require Unless you use the :exclude option, for example, date:

Refrigerator.check_require 'date',
  :classes=>[:Date, [:DateTime, :Date]]
# Fails due to Time#to_date addition

Refrigerator.check_require 'date',
  :classes=>[:Date, [:DateTime, :Date]],
  :exclude=>['Time']
# => true

The refrigerator is shipped with check_require Binary file that provides access rights Refrigerator.check_require from the command line. This is the usage:

$ bin/check_require
Usage: check_require [options] path

Options:
  -m, --modules [Module1,Module2]  define given modules under Object before freezing core classes
  -c [Class1,Class2/SuperclassOfClass2],
      --classes                    define given classes under Object before freezing core classes
  -r, --require [foo,bar/baz]      require given libraries before freezing core classes
  -e, --exclude [Object,Array]     exclude given core classes from freezing
  -h, -?, --help                   Show this message

You can use this to easily check if there is an issue with the ruby ​​library when needed. For example, let’s try open3:

$ bin/check_require open3
Traceback (most recent call last):
        4: from bin/check_require:42:in `
' 3: from /home/billg/ruby-refrigerator/lib/refrigerator.rb:35:in `check_require' 2: from /usr/local/lib/ruby/2.5/rubygems/core_ext/kernel_require.rb:59:in `require' 1: from /usr/local/lib/ruby/2.5/rubygems/core_ext/kernel_require.rb:59:in `require' /usr/local/lib/ruby/2.5/open3.rb:32:in `': can't modify frozen #

As shown above, except for the definition Open3 Mods.

let’s try it date:

$ bin/check_require date
Traceback (most recent call last):
        6: from bin/check_require:42:in `
' 5: from /home/billg/ruby-refrigerator/lib/refrigerator.rb:35:in `check_require' 4: from /usr/local/lib/ruby/2.5/rubygems/core_ext/kernel_require.rb:59:in `require' 3: from /usr/local/lib/ruby/2.5/rubygems/core_ext/kernel_require.rb:59:in `require' 2: from /usr/local/lib/ruby/2.5/date.rb:4:in `' 1: from /usr/local/lib/ruby/2.5/rubygems/core_ext/kernel_require.rb:59:in `require' /usr/local/lib/ruby/2.5/rubygems/core_ext/kernel_require.rb:59:in `require': can't modify frozen #

The first failure was because date defined Date and DateTime classes, so you must first define these classes and use a slash to separate DateTime from the superclass Date. Note that it still fails in this case, but it doesn’t even tell you why. It turns out that the reason is this date also added to_date and other methods Timeso you need to exclude freezing Time as well as.

Here are some more examples using Sequel and Roda:

bin/check_require -m Sequel -r bigdecimal,date,thread,time,uri sequel
bin/check_require -c Roda -r rack,uri,fileutils,set,tmpdir,tempfile,thread,date,time roda

Support new ruby ​​minor versions

constant list freeze_core Freezes will be stored in module_names/*.txt files in the repository, with a separate file for each ruby ​​minor version. When a new Ruby minor version is released, module_names The rake task can be run with the new Ruby minor version and it will produce the corresponding archive.

Skip courses and mods

Internal, deprecated and private classes and mods are not frozen in the freezer.

and

Jeremy Evans

2024-12-28 19:17:26

Leave a Reply

Your email address will not be published. Required fields are marked *