Skip to content

Instantly share code, notes, and snippets.

@s-andringa
Created December 28, 2010 15:38
Show Gist options
  • Save s-andringa/757335 to your computer and use it in GitHub Desktop.
Save s-andringa/757335 to your computer and use it in GitHub Desktop.
Deal with bitmask-form options & Safely monkey patch Ruby gems
class ConstantGardener
def self.create(*booleans)
Class.new do
def initialize(bitmask)
@bitmask = bitmask
end
booleans.each_with_index do |b, i|
const_set b.to_s.upcase, 2**i
define_method "#{b.to_s.downcase}?" do
@bitmask[i] == 1
end
end
end
end
end
require 'rubygems'
require 'constant_gardener'
module GemPatch
Strategy = ConstantGardener.create(:warn, :skip, :raise)
class << self
private
def versions_to_sentence(versions)
if versions.size == 1
"version #{versions.first}"
else
"versions " + versions[0..-2].join(', ') + " and " + versions.last.to_s
end
end
end
end
class GemPatchError < StandardError; end
module Kernel
def patch(gem_spec, strategy = GemPatch::Strategy::RAISE, &block)
name, *versions = gem_spec.split(/\s+/)
wanted_versions = versions.map{ |v| Gem::Version.new(v) }
loaded_version = Gem.loaded_specs[name] ? Gem.loaded_specs[name].version : nil
strategy = GemPatch::Strategy.new(strategy)
error = if !loaded_version
"You patched #{name} in #{caller.first} but #{name} was not loaded."
elsif wanted_versions.size > 0 && !wanted_versions.include?(loaded_version)
"You patched #{name} #{GemPatch.send(:versions_to_sentence, wanted_versions)} in #{caller.first} but version #{loaded_version} was loaded. Is your patch still applicable?"
end
raise GemPatchError, error if error && strategy.raise?
logger.warn "GemPatch warning: #{error}" if error && respond_to?(:logger) && strategy.warn?
yield unless error && strategy.skip?
end
end
require 'gem_patch'
# Raises an error if faker isn't loaded:
#
patch "faker" do
module Faker
#...
end
end
# Logs a warning if a version of faker other than 0.3.0 is loaded:
#
patch "faker 0.3.0", GemPatch::Strategy::WARN do
module Faker
#...
end
end
# Logs a warning and does not apply the patch if a version of faker other
# than 0.2.9 or 0.3.0 is loaded:
#
patch "faker 0.2.9 0.3.0", GemPatch::Strategy::WARN + GemPatch::Strategy::SKIP do
module Faker
#...
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment