December 6, 2006
My Ruby Slum
Post by Peter Cooper
I have a special folder on my computer called rubyslum. It's literally a slum where ugly snatches of Ruby code live. Whenever I want to try out an idea, implement something bizarre, or just mess around with some metaprogramming, that's where I play.
I often stumble across code in there I forget ever writing, which makes me cringe with embarrassment, or stuff that reignites ideas in my brain. In the spirit of sharing, here are several of the highlights from my "Ruby Slum". I hope this encourages other people to share scrappy bits of code of their own. I think there's a lot to learn from some of the weird techniques you try out in private.
Slum Inhabitants
class TrueClass; def =~(a); a[:ifTrue].call; end; end class FalseClass; def =~(a); a[:ifFalse].call; end; end def _(&a); lambda &a; end (1 + 1 == 2) =~ { :ifTrue => _{ puts "True" }, :ifFalse => _{ puts "False" }, }
class TrueClass def =~(a) a[:ifTrue].call end def >(a) a[:ifTrue].call end end class FalseClass def =~(a) a[:ifFalse].call end end def _(&a) lambda &a end (1 + 1 == 2) > { :ifTrue => _{ puts "True" }, :ifFalse => _{ puts "False" }, } puts case (1 + 1 == 32) when true: "True" when false: "False" end
require 'rubygems' require 'hpricot' require 'open-uri' doc = Hpricot(open("index.rdf")) doc.search("item").each do |i| puts i.search("link").inner_html puts "\n\n" end
require 'gserver' require 'socket' class SMTPProxy < GServer def serve(io) @@c ||= 0 @@c += 1 data = '' puts "#{@@c} go" smtp = TCPSocket.new("127.0.0.1", 25) loop do if IO.select([io], nil, nil, 0.1) x = io.readpartial(4096) smtp.print x smtp.flush elsif IO.select([smtp], nil, nil, 0.1) x = smtp.readpartial(4096) io.print x io.flush end break if io.closed? || smtp.closed? end io.close end end a = SMTPProxy.new(1234) a.start a.join
require 'rubygems' require 'inline' require 'benchmark' class CFactorial class << self inline do |b| b.c %q{ long factorial(int value) { int result = 1, i = 1; for (i = 1; i <= value; i++) { result *= i; } return result; } } end end end class Fixnum def factorial (1..self).inject { |a, b| a * b } end end Benchmark.bm do |bm| bm.report('ruby:') do 100000.times { 8.factorial } end bm.report('c:') do 100000.times { CFactorial.factorial(8) } end end
q = %w{11011001110001110100111001110110000111101110111000011000111000011011110000111100111110001111001} q.each do |a| a.scan(/[01]{8}/).each { |b| puts b.to_i(2).chr } end
class PX; def self.method_missing(m, *args); m = m.to_s; eval $c.join if m == '-@'; m.scan(/(\w)(\w)/).each { |t| ($c ||= []) << (((t[0][0] - 97) * 26) + (t[1][0] - 97)).chr }; end; end
#x = { "a" => "b", "k1" => { "x" => "c", "k2" => { "y" => "z" }}, "f" => "x" } h = {"a"=>"b", "c"=>"d", 1=>{2=>{"e"=>"f", 3=>{4=>"value"}}}} class Hash def extract_keys keys = [] self.each { |key, value| if value.class == Hash keys << value.extract_keys else keys << key end } keys.flatten end end puts h.extract_keys.inspect
class OrderedHash < Hash alias_method :store, :[]= alias_method :each_pair, :each def initialize @keys = [] end def []=(key, val) @keys << key super end def delete(key) @keys.delete(key) super end def each @keys.each { |k| yield k, self[k] } end def each_key @keys.each { |k| yield k } end def each_value @keys.each { |k| yield self[k] } end end x = OrderedHash.new x[:y] = 10 x[:z] = 50 x.each { |k| puts k }
^^^ I eventually figured how stupid the above was, but it was an early attempt!
# Yet Another Ruby Text Adventure! # By Peter Cooper class Item attr_accessor :name, :description def initialize(params) @name = params[:name] @description = params[:description] end end class Location attr_accessor :name, :description, :west, :east, :south, :north, :items def initialize(params) @name = params[:name] @description = params[:description] @items = [] end # We have to create our own setter methods to do the mirrored east/west north/south relationships def west=(loc) @west = loc @west.east = self unless @west.east end def east=(loc) @east = loc @east.west = self unless @east.west end def south=(loc) @south = loc @south.north = self unless @south.north end def north=(loc) @north = loc @north.south = self unless @north.south end def exits exits = [] exits << "west" if self.west exits << "east" if self.east exits << "south" if self.south exits << "north" if self.north exits end def contains_items? self.items && self.items.length > 0 end end class Player attr_accessor :inventory, :location end class World attr_accessor :main_location end def prepare_world(world) # Create a location main_room = Location.new( :name => "Central Room" ) world.main_location = main_room main_room.west = Location.new( :name => "West Room" ) main_room.east = Location.new( :name => "East Room" ) main_room.west.north = Location.new( :name => "The North of the West Room" ) main_room.west.north.north = Location.new( :name => "The Really Far North Room" ) # Create a lamp lamp = Item.new( :name => "Magic Lamp", :description => "a golden lamp with magical powers" ) # Add the lamp to the west room main_room.west.items << lamp end # Now the game logic really begins! world = World.new player = Player.new prepare_world(world) player.location = world.main_location inventory = [] catch :end_of_game do loop do puts "You are in #{player.location.name}." puts "Items here: #{player.location.items.collect{|item| item.name }.join(", ")} " if player.location.contains_items? puts "Exits are to the #{player.location.exits.join(", ")}." puts "Which direction next?" instruction = gets case instruction.chomp.downcase when "north" next_room = player.location.north || false when "south" next_room = player.location.south || false when "west" next_room = player.location.west || false when "east" next_room = player.location.east || false when "exit" throw :end_of_game when /^take (.+)$/ puts "Taking #{$1}" inventory << player.location.items.find {|item| item.name.downcase == $1 } player.location.items.delete_if {|item| item.name.downcase == $1 } when /^drop (.+)$/ puts "Dropping #{$1}" player.location.items << inventory.find {|item| item.name.downcase == $1 } end if next_room == false puts "No!" elsif next_room player.location = next_room end end end puts "Bye bye!"
^^^ Horribly inefficient technique for changing room. You can do a lot better than this with some cute meta methods.
ARGV[1].to_i.upto(ARGV[2].to_i) {|x| puts x if (TCPSocket.new(ARGV[0],x) rescue false) }
class Hash def method_missing(meth, *args) if meth.to_s =~ /\=$/ self[meth.to_s[0...-1].to_sym] = args.first else return self[meth.to_sym] end end end x = {} x.test = 10 puts x.test
^^^ Before I discovered OpenStruct..