Polyfill

Build

Polyfill implements newer Ruby features into older versions. If the Ruby version already supports the polyfill then calling it does nothing. This is designed to allow gem maintainers to use newer methods and gain their advantages while retaining backwards compatibility. It can also be used for code that would like newer features but is not completely ready to upgrade Ruby versions. The polyfills are built using refinements so there is no monkey patching that may cause issues outside of your use.

Right now the only update is from 2.3 to 2.4 however the goal is to go all the way back to 2.0 (when refinements were introduced). Additionally, core methods are being focused on but stdlib will eventually be added.

Caveat Emptor

Not all features can be perfectly implemented. This is a best effort implementation but it's best to always test thoroughly across versions. This project is also currently pre-1.0. Breaking changes may occur on any release. Once a stable API is built it will be moved to 1.0.0.

See the implementation table for specifics about what has been implemented.

Installation

Add it to your Gemfile:

gem 'polyfill', '0.5.0'

Or install it manually:

$ gem install polyfill

This project uses Semantic Versioning.

Goals

  1. Features should ideally mimic the true behavior (including bugs).
  2. Features should not significantly burden the runtime.
  3. Keep everything modular so users can be specific or broad in their usage.

Usage

To use all updates:

using Polyfill

To specify methods from a particular object use it's class name and pass an array of strings containing the methods you'd like to use. Instance methods need to start with "#" and class methods need to start with ".".

using Polyfill(
  Array: %w[#concat],
  Dir: %w[.empty?],
  Hash: %w[#compact! #transform_values],
)

If you want all of the methods for a particular class you can use :all.

using Polyfill(Numeric: :all)

Updates can be stopped at a specific version by pass it via :version. The version selected must be formatted as "MAJOR.MINOR".

using Polyfill(version: '2.3', Numeric: :all)

Methods can be included in the same way. Prior to Ruby 2.4, refinements did not work on modules. In order to get methods you'll need to include them after the module. Calling using on a module will add it to all core Ruby classes that include it. The methods will only be included if they are needed by the Ruby version running the code.

class Foo
  include Comparable
  include Polyfill(Comparable: %w[#clamp])
end

Implementation Table

2.3 to 2.4

Object Method Implemented Notes
Array #concat Yes
#max No This method already existed but was inherited from Enumerable. It was optimized on Array so redefining Enumerable#max no longer affects this.
#min No This method already existed but was inherited from Enumerable. It was optimized on Array so redefining Enumerable#min no longer affects this.
#pack No
#sum Yes
Binding #irb No
Comparable #clamp Yes
CSV #new No
Dir .empty? Yes
Enumerable #chunk Yes
#sum Yes
#uniq Yes
Enumerator::Lazy #chunk_while Yes
#uniq Yes
File .empty? Yes
FileTest .empty? No
Float #ceil Yes
#floor Yes
#round No
#truncate Yes
Hash #compact Yes
#compact! Yes
#transform_values Yes
#transform_values! Yes
Integer #ceil Yes
#digits Yes
#floor Yes
#round Yes
#truncate Yes
IO #each_line Yes
.foreach Yes
#gets Yes
#lines Yes
#readline Yes
#readlines Yes
.readlines Yes
IPAddr #== Yes
#<=> Yes
Logger #new No
MatchData #named_captures Yes
#values_at Yes
Module #refine No
.used_modules No
Net::HTTP #post No
Net::FTP #new No
#status No
Numeric #clone Yes
#dup Yes
#finite? Yes
#infinite? Yes
Object #clone Yes
OptionParser #order No
#order! No
#parse No
#parse! No
#permute No
#permute! No
Pathname #empty? Yes
Readline #quoting_detection_proc No
#quoting_detection_proc= No
REXML::Element #[] No
Rational #round No
Regexp #match? Yes
Set #compare_by_identity No
#compare_by_identity? No
String #capitalize No
#capitalize! No
#casecmp? Partial Does not support Unicode characters.
#concat Yes
#downcase No
#downcase! No
#each_line Yes
#lines Yes
#match? Yes
.new Partial Allows :capacity option to pass but does nothing.
#prepend Yes
#swapcase No
#swapcase! No
#unpack1 Yes
#upcase No
#upcase! No
StringIO #each_line Yes
#gets Yes
#readline Yes
#readlines Yes
Symbol #capitalize No
#capitalize! No
#casecmp? Partial Does not support Unicode characters.
#downcase No
#downcase! No
#match Yes
#match? Yes
#swapcase No
#swapcase! No
#upcase No
#upcase! No
Thread #report_on_exception No
.report_on_exception No
TracePoint #callee_id No
Warning #warn No

2.2 to 2.3

Object Method Implemented Notes
ARGF #read_nonblock No
Array #bsearch_index No
#dig No
Comparable #== No
Enumerable #chunk No
#chunk_while Yes
#grep_v No
#slice_before No
Enumerator::Lazy #grep_v No
File .mkfifo No
Hash #< No
#<= No
#> No
#>= No
#dig No
#fetch_values No
#to_proc No
IO #advise No
Kernel #loop No
Module #deprecate_constant No
NameError #receiver No
Numeric #negative? No
#positive? No
Queue #close No
String #+@ No
#-@ No
.new Yes
Struct #dig No
Thread #name No
#name= No

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/AaronLasseigne/polyfill. Please read the contributing file prior to pull requests.

Credits

Polyfill is licensed under the MIT License.