Skip to content

Instantly share code, notes, and snippets.

@duckinator
Last active August 29, 2015 14:00
Show Gist options
  • Save duckinator/ea6d659a625d7a898152 to your computer and use it in GitHub Desktop.
Save duckinator/ea6d659a625d7a898152 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
module EvilClass
class << self
def has_been_evil?
@@has_been_evil = false
end
def make_ruby_cry
return unless File.expand_path($0) == File.expand_path(__FILE__)
load ARGV[0]
@@has_been_evil = true
end
def load_file(filename, wrap, full_filename)
unless full_filename && File.exist?(full_filename)
raise LoadError, "cannot load such file -- #{filename}"
end
rewrite_code(filename, wrap, File.open(filename).read)
end
def rewrite_code(filename, wrap, code)
#TODO: Make wrap=true do something.
# See massive HACK comment below as to how this was kept so
# simple, despite the fact that it should technically require
# parsing partially-invalid Ruby.
code.gsub!(/^(\s*)class ([^\s<]+)\s*(<\s*([^\s]))?$/, 'const_set :"\2", Class.new(\4) do')
# TODO: Check if TOPLEVEL_BINDING is actually correct.
eval(code, TOPLEVEL_BINDING, filename)
end
end
end
# const_set/const_get/const_missing/method_missing wizardry lovingly
# stolen from @wilkie: https://gist.github.com/wilkie/10cf0cf60f371f680d30
module Kernel
def const_set(sym, value, &block)
# HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK
#
# We should be changing this:
#
# class X < Y
# ...
# end
#
# to:
#
# const_set(:"X", Class.new(const_get(:"Y")) {
# ...
# })
#
# But, instead, we change it to this, so we don't have to actually
# parse Ruby, this way (we just match a single line):
#
# const_set :"X", Class.new(const_get(:"Y")) do
# ...
# end
#
# *This is actually passing the block to const_set.*
# The following if statement makes it behave as if that were not
# the case.
#
# HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK
if block
value.class_eval(&block)
return const_set(sym, value)
end
if sym.to_s.match /^[^A-Z]/
@@__cool_constants ||= {}
@@__cool_constants[sym] = value
else
super(sym, value)
end
end
def const_get(sym)
if sym.to_s.match /^[^A-Z]/
@@__cool_constants ||= {}
if @@__cool_constants.has_key? sym
return @@__cool_constants[sym]
end
end
super(sym)
end
def const_missing(sym, *args)
@@__cool_constants ||= {}
if @@__cool_constants.has_key? sym
@@__cool_constants[sym]
else
super(sym, *args)
end
end
def method_missing(sym, *args)
# "Real" Methods have precedence over unicode-constants which have
# precedence over dynamic methods.
@@__cool_constants ||= {}
if @@__cool_constants.has_key? sym
@@__cool_constants[sym]
else
super(sym, *args)
end
end
alias_method :original_load, :load
def load(filename, wrap=false)
EvilClass.load_file(filename, wrap, filename)
end
alias_method :original_require, :require
def require(filename)
full_filename =
if File.file?(filename)
filename
else
$:.lazy.map do |directory|
%w[rb so dll].lazy.map do |extension|
potential_filename = File.join(directory, "#{filename}.#{extension}")
potential_filename if File.exist?(potential_filename)
end.reject(&:nil?).first
end.reject(&:nil?).first
end
EvilClass.load_file(filename, false, full_filename)
$LOADED_FEATURES << File.expand_path(filename)
end
end
module EvilClass
make_ruby_cry unless has_been_evil?
end
..uckinator/evilclass⚡master+ ./test.rb
YEAAAAAAAAAAAAAAAAHHHHHHHHH
..uckinator/evilclass⚡master+
#!./evilclass.rb
require './❤.rb'
class <
def w00t
puts yeah!
end
end
.new.w00t
class
def yeah!
"YEAAAAAAAAAAAAAAAAHHHHHHHHH"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment