I decided to take a "meta" approach and created a quick and dirty code
generator. I taught it some basic Ruby Identities and hen let it have
at it. With just the 5 silly identities that it currently has it can
generate never ending variations, though they get repetitive very
quickly --nevertheless there are already some unexpected solutions. I
suppose with maybe a few dozen identities it could get pretty
interesting.
Try running like so:
ruby helloword.rb 100
ruby helloword.rb test 100
ruby helloword.rb output 100
The number is the number of solutions to generate, 'test' will run it
through test/unit to make sure it all checks out and 'output' will
print a whole bunch of "Hello, World!"s :)
Oh, and yes, I know it's not all that robust. It was just a fun quick
hack. But feel free to improve it and let me know if you have any good
identities to add.
T.
---
class SimpleCodeGenerator
def self.identities
@identities ||= []
end
def self.identity(&block)
identities << block
end
attr_reader :original
attr_accessor :alternates
def initialize(original)
@original = original
@alternates = [original]
end
def generate(limit=100)
work = original.dup
while(alternates.size < limit) do
alts = alternates.dup
size = alternates.size
alts.each do |alt|
self.class.identities.each do |identity|
self.alternates |= [identity[alt]]
break if alternates.size >= limit
end
end
end
end
def show_code
alternates.each do |code|
puts code
end
end
def show_output
alternates.each do |code|
puts run(code)
end
end
def generate_tests
original_run = run(original)
runner = method(:run)
testcase = Class.new(Test::Unit::TestCase)
alternates.each_with_index do |code, index|
testcase.class_eval do
define_method("test_#{index}") do
assert_equal(original_run, runner[code])
end
end
end
end
def run(code)
so = $stdout
sio = StringIO.new
$stdout, $stderr = sio, sio
eval code, $TOPLEVEL_BINDING
result = $stdout.string
$stdout = so
result
end
# code identities
identity do |code|
code.sub(/puts ["](.*)["]/, 'print "\1\n"')
end
identity do |code|
code.sub(/puts ["](.*)["]/, 'printf "%s\n" % ["\1"]')
end
identity do |code|
code.gsub(/["](.*)["]/, '"\1".reverse.reverse')
end
identity do |code|
code.gsub(/['](.*)[']/){ $1.inspect }
end
identity do |code|
code.gsub(/['](.*)[']/){ "#{$1.split(//).inspect}.join('')" }
end
end
if __FILE__ == $0
cnt = (ARGV.find{ |a| /\d+/ =~ a } || 20).to_i
scg = SimpleCodeGenerator.new("puts 'Hello, World!'")
scg.generate(cnt)
case ARGV[0]
when 'test'
require 'test/unit'
scg.generate_tests
when 'output'
scg.show_output
else
scg.show_code
end
end