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