[QUIZ] Code Cleaning (#26)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

···

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

I'm always very vocal about how Ruby Quiz isn't interested in golf and
obfuscation. It's my own private fight for clean code.

To be fair though, you can really learn a lot from practices like golf and
obfuscation. It'll teach you a surprising number of details about the inner
workings of your language of choice. Still principals are principals and if I
bend, word will quickly get out that I've given up the fight. Can't allow that!

Here's my compromise.

This week's challenge is to utterly clean some famous examples of compressed
Ruby code. Refactor the code until it's as readable as possible, whatever that
means to you.

For those that faint at the sight of dense code, I offer a an "easier"
challenge. Try this code by Mauricio Fernández:

  #!/usr/bin/ruby -rcgi
  H,B=%w'HomePage w7.cgi?n=%s';c=CGI.new'html4';n,d=c['n']!=''?c['n']:H,c['d'];t=`
  cat #{n}`;d!=''&&`echo #{t=CGI.escapeHTML(d)} >#{n}`;c.instance_eval{out{h1{n}+
  a(B%H){H}+pre{t.gsub(/([A-Z]\w+){2}/){a(B%$&){$&}}}+form("get"){textarea('d'){t
  }+hidden('n',n)+submit}}}

If you prefer a "trickier" challenge, I offer this famous code from Florian
Gross:

  #!/usr/bin/ruby
  # Server: ruby p2p.rb password server public-uri private-uri merge-servers
  # Sample: ruby p2p.rb foobar server druby://123.123.123.123:1337
  # druby://:1337 druby://foo.bar:1337
  # Client: ruby p2p.rb password client server-uri download-pattern [list-only]
  # Sample: ruby p2p.rb foobar client druby://localhost:1337 *.rb
  ################################################################################
  # You are not allowed to use this application for anything illegal unless you
  # live inside a sane place. Insane places currently include California (see
  # link) and might soon include the complete USA. People using this software are
  # responsible for themselves. I can't prevent them from doing illegal stuff for
  # obvious reasons. So have fun and do whatever you can get away with for now.
  #
  # http://info.sen.ca.gov/pub/bill/sen/sb_0051-0100/sb_96_bill_20050114_introduced.html
  ################################################################################
  require'drb';F=File;def c(u)DRbObject.new((),u)end;def x(u)[P,u].hash;end;def s(
  p)F.basename p[/[^|]+/]end;P,M,U,V,*O=$*;M["s"]?(DRb.start_service V,Class.new{
  def p(z=O)O.push(*z).uniq;end;new.methods.map{|m|m[/_[_t]/]||private(m)};def y;(
  p(U)+p).map{|u|u!=U&&c(u).f(x(u),p(U))};self;end;def f(c,a=O,t=2)x(U)==c&&t<1?
  Dir[s(a)]:t<2?[*open(s(a),"rb")]:p(a)end}.new.y;sleep):c(U).f(x(U)).map{|n|c(n).
  f(x(n),V,0).map{|f|s f}.map{|f|O[0]?p(f):open(f,"wb")<<c(n).f(x(n),f,1)}}

This is a little different from the traditional Ruby Quiz, but I encourage all
to play and learn. I promise to go back to normal challenges next week...

Hi --

···

On Fri, 1 Apr 2005, Ruby Quiz wrote:

I'm always very vocal about how Ruby Quiz isn't interested in golf and
obfuscation. It's my own private fight for clean code.

It's not private -- see the earlier mentions of the idea of a
Deobfuscation (or Code Amelioration) Contest, going back to 2001 and
revived at my suggestion this year. Many of us are more enthralled
with the easy beauty than the hard-won ugliness of Ruby code :slight_smile:

David

--
David A. Black
dblack@wobblini.net

Help!

I would find if handy to know how to use Mauricio Fernández's code.
When I run it, I get:

    (offline mode: enter name=value pairs on standard input)

What am I supposed to do with it then?

-- Timothy

Here's my solution to the first script. See Thursday's summary for how it came about...

James Edward Gray II

#!/usr/local/bin/ruby

# wiki.cgi

require 'cgi'

HOME = 'HomePage'
LINK = 'wiki.cgi?name=%s'

query = CGI.new 'html4'

# fetch query data
page_name = if query['name'] == '' then HOME else query['name'] end
page_changes = query['changes']

# fetch file content for this page, unless it's a new page
content = File.read(page_name) rescue content = ''

# save page changes, if needed
unless page_changes == ''
  content = CGI.escapeHTML(page_changes)
  File.open(page_name, 'w') { |f| f.write content }
end

# output requested page
query.instance_eval do
  out do
    h1 { page_name } +
    a(LINK % HOME) { HOME } +
    pre do # content area
      content.gsub(/([A-Z]\w+){2}/) do |match|
        a(LINK % match) { match }
      end
    end +
    form('get') do # update from
      textarea('changes') { content } +
      hidden('name', page_name) +
      submit
    end
  end
end

To be fair, I did enter the IORCC, as is now known. That was my first obfuscation attempt and I do have a whole new appreciation for that craft. I doubt I would do it again, at least anytime in the near future, but I did learn a lot from the experience. Have to try it once so you know what you're missing, right? :wink:

Then I carefully arranged this quiz for the day after that contest ended. <laughs>

James Edward Gray II

···

On Apr 1, 2005, at 8:13 AM, David A. Black wrote:

Many of us are more enthralled with the easy beauty than the hard-won ugliness of Ruby code :slight_smile:

I have not looked at the code, but it sure sounds like a CGI script

···

On Apr 1, 2005 8:14 PM, Timothy Byrd <byrd.timothy@gmail.com> wrote:

Help!

I would find if handy to know how to use Mauricio Fernández's code.
When I run it, I get:

    (offline mode: enter name=value pairs on standard input)

What am I supposed to do with it then?

-- Timothy

I'm guessing you're running on Win, if I'm guessing right... type
something in, hit Ctrl-z, then Enter.
You'll also want to change "cat" to "type".

···

On Apr 1, 2005 8:14 PM, Timothy Byrd <byrd.timothy@gmail.com> wrote:

Help!

I would find if handy to know how to use Mauricio Fernández's code.
When I run it, I get:

    (offline mode: enter name=value pairs on standard input)

What am I supposed to do with it then?

--
Bill Guindon (aka aGorilla)

There are multiple ways to find this out. That's one of the steps of Code Reading/Code Archeology, eh? :wink:

The "-rcgi" on the first line of that one is a big hint, as others have pointed out. Get it behind a Web server and play a little. Use Ruby's included web server, WEBrick, if needed.

That's only one way to find out though. Both programs chosen are semi-famous... :wink:

Good luck!

James Edward Gray II

P.S. "Code Reading: The Open Source Perspective" is a challenging but sensational read on this very topic, for geeks like me that think this exercise is fun.

···

On Apr 1, 2005, at 7:14 PM, Timothy Byrd wrote:

Help!

I would find if handy to know how to use Mauricio Fernández's code.

And here's my best attempt at the trickier second one.

James Edward Gray II

#!/usr/local/bin/ruby

# p2p.rb

# Server: ruby p2p.rb password server public-uri private-uri merge-servers
# Sample: ruby p2p.rb foobar server druby://123.123.123.123:1337
# druby://:1337 druby://foo.bar:1337
# Client: ruby p2p.rb password client server-uri download-pattern [list-only]
# Sample: ruby p2p.rb foobar client druby://localhost:1337 *.rb

···

On Apr 5, 2005, at 2:23 PM, James Edward Gray II wrote:

Here's my solution to the first script. See Thursday's summary for how it came about...

################################################################################
# You are not allowed to use this application for anything illegal unless you
# live inside a sane place. Insane places currently include California (see
# link) and might soon include the complete USA. People using this software are
# responsible for themselves. I can't prevent them from doing illegal stuff for
# obvious reasons. So have fun and do whatever you can get away with for now.
#
# http://info.sen.ca.gov/pub/bill/sen/sb_0051-0100/sb_96_bill_20050114_introduced.html
################################################################################

require'drb'

# define utility methods
def create_drb_object( uri )
  DRbObject.new(nil, uri)
end

def encode( uri )
  [PASSWORD, uri].hash
end

def make_safe( path )
  File.basename(path[/[^|]+/])
end

# parse command-line options
PASSWORD, MODE, URI, VAR, *OPTIONS = ARGV

# define server operation
class Server
  new.methods.map{ |method| private(method) unless method[/_[_t]/] }

  def initialize
    @servers = OPTIONS.dup
    add(URI)
    @servers.each do |u|
      create_drb_object(u).add(URI) unless u == URI
    end
  end
  
  attr_reader :servers

  def add( z = OPTIONS )
    @servers.push(*z).uniq!
    @servers
  end
  
  def list( code, pattern )
    if encode(URI) == code
      Dir[make_safe(pattern)]
    else
      @servers
    end
  end
  
  def read( file )
    open(make_safe(file), "rb").read
  end
end

if MODE["s"] # server
  DRb.start_service(VAR, Server.new)
  sleep
else # client
  servers = create_drb_object(URI).servers
  servers.each do |server|
    files = create_drb_object(server).list(encode(server), VAR).map do |f|
      make_safe f
    end
    files.each do |file|
      if OPTIONS[0]
        p(file)
      else
        open(file, "wb") do |f|
          f << create_drb_object(server).read(file)
        end
      end
    end
  end
end

Perhaps, I should rephrase.

Yes, I'd already gotten as far as the replies so far. But to go into
detail on how for I've gotten would be a spoiler. I guess I'm like a
method actor asking "What's my motivation here?"

-- Timothy

I doubt I can answer that for you, but mine was:

* To practice my refactoring skills.
* To learn more about Wikis and Peer-to-Peer servers.
* To learn more about tools like WEBrick and DRb.
* To increase my understanding of shortcut language constructs.

Hope that helps.

James Edward Gray II

···

On Apr 2, 2005, at 2:44 PM, Timothy Byrd wrote:

I guess I'm like a method actor asking "What's my motivation here?"