2009-11-17

qng and qif: self-reproducing images

qng image

http://dame.dyndns.org/misc/misc/qng.png

The above image is qng, a png image that prints a Ruby script that generates the image itself.

$ cat qng.rb
eval s=%q(require"zlib";include Zlib;f=Inflate.inflate(*"eNq
1VomxQyEIpAP675IOiAjqIvqS/INh3hh1dTkN0c+FOfR5j6r4Nh98cT6xSIf
Yl4WEfi92mn1Q7WCOxRijCiXWjUfjo/Y9MBLTZqkP3sh2chfDfiKSrxxUcRg
Wa6dsfMUHbSZxkAAGHFYd202KM5EerlI9uQHU4i499MPXy0yJA0/YdR1Vzp3
DbjIVe/mEhclA8rdpJU/hexb33qch/hNxK71Uh+3AJ2ZwUHw1UyNHwX6P1LI
SJTQL4yslc+qq0OleFggW1F9QlTlGLN3zmVS2ZbTXrZCezjKsy45MqoWVsmk
I+rktkSxh05qTU3O2Y4xuvppRSL6q8d185X7mUw2uJoZaonDkvCb9gajY6Yn
yiEyg5+3GOV1XWK3OIHu/Yt37eqiu4K7nIP3oe07glFr/KR4g1lQLkIdYFBW
7ShhyI+ZYMYJS7x2FBtj2jnt3zy49YrHZsp45S04Ow16yLq4p4dD0pvek8qY
3wCynAi5tWBmrVEr3vnA+2EsP2FnIOUbJV+mBV2sgF8oRX8+Q1L1Heq8Alfj
m+j2vrhKuq1DCdRVL+N29pfOMEl49lqGlY/bzpTuDv/b9cvjbcJMXSB2OYQ=
=".unpack("m"));z="\0";s="IDAT"+Deflate.deflate(z*561+%(eva\
l s=%q(#{s})).scan(/.+/).map{|l|(0..9).map{|i|[z*4,l.bytes .
map{|c|f[c*30+i*3-960,3]},z*3]}*""}*(z*187)+z*561);print ["\
\x89PNG\r\n\x1a\n","\rIHDR",372,192,4,0,4107545177,s.size-4,
s,Zlib.crc32(s),0,"IEND\xAEB\x60\x82"].pack"a11A*NNCN3A*NNA*
"############## qng.rb (c) Yusuke Endoh 2009 ##############)

$ ruby qng.rb > qng.png

qif image

http://dame.dyndns.org/misc/misc/qif.gif

The above image is qif, a gif image that prints a Ruby script that generates the image itself.

$ cat qif.rb
Y,E=%q~260|0!e0*h0($0j0($"!e0($"f0e0($0!e0*p;4f4#.q9!&8*%"1(
}+0!,e4|8,e<.%}e6#g4*};!(4*%})2!e09$"u91&(#6}f0(%+#u0)6"1(7,
v0.,*%"<8{9!(4+2}!(4*%90}<.'#<(}$"!e0($")n48$6!(0($".!e0($"$
e0w0($")k0r4*%"<8$"!9!&8*%"<0|0($"#&0()0i;f=87$};!(4+6"!e0j;
f0(',}91(4+3e0($j;!.8)2}}}}}}},4"!e0($"!2i2!i0)e0e0(#$0($"!e
0(,0}}o0(%2"1(4~,%~y;0('&!e=8}}q9!($"!"<0}}}}}}y0g4f0+2}441$
!}g;0&<}h2$11!{0!q0}h0m0|20!&8*%9s9!(7$%"<0p0!e4"g3.q9!(7&!(
(0o9!(3&!e=8o0(&>#01(t9!(2$$"<0o;0*"$$"<0o9e0($")e0o9!(4.%"<
0n4"g0*!h0(o0}}k;0{0!}}g0+."!}f0?$'!t0!($"!e0e2i0e2!e0($f4}t
0($k=!-%%!040r70&8!;}%3#,0/,"r8->#!78}z8,&s0g0($"!g~;eval$s=
%q(h=eval"0b"+(Y+"}"*39+E).bytes.map{|x|x<95?("%05b".%x-32if
32<x):"0"*(x-96)}*"";z=[2,128].pack"vC";print [71,73,70,"89\
a",372,192,736,0,0,65535,11519,0,0,372,192,768,z*372,%(Y,E=\
%q~#{Y}~,%~#{E}~;eval$s=\n%q(#$s)).scan(/.+/).map{|l|(0..9).
map{|i|[z*2,l.bytes.map{|c|[4,17&n=h>>60*c-1980+i*6,17&n>>1,
n[2]+n[3]*16,136].pack "C*"},z*2]}*""}*(z*124),z*372,"\0;"].
pack"C3a3v12"+"a*"*4 #### qif.rb (c) Yusuke Endoh 2009 ####)

$ ruby qif.rb > qif.gif

COPYRIGHTS

The two images contain Proggy Programming Fonts:

Copyright (c) 2004, 2005 Tristan Grimmer

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

translated from mamememo in Japanese (2009-07-23) and (2009-11-16).

2009-11-15

_ : a library that allows you to write Ruby script by using only _

I published one of my darling libraries into gemcutter, named _. By using _, you can write Ruby script that consist only of _.

Getting started

$ gem install _

Source code: http://github.com/mame/_

Gem info: http://gemcutter.org/gems/_

Example

This is "Hello, world!" __script__ written in Ruby:

require "_"
____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______
_____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _
____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____
__ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____

This is nothing but normal Ruby __script__. Works on Ruby 1.8 and 1.9. You can rearrenge line breaks but can not change the order of _s.

$ ruby18 -rubygems __hello__.rb
Hello, world!

$ ruby19 __hello__.rb
Hello, world!

If you mind the first `require' line, the option `-r_' can be used in Ruby 1.9.

$ ruby19 -r_ -e '____ _ _____ ____ __ ____ ____ __ ___ ____ __
__ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _
____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____
____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
'
Hello, world!

And, you can translate your own script into __script__ by __script__ method.

$ echo -n 'puts"Hello, world!"' | ruby19 -r_ -e 'puts __script__($<.read)'
require "_"
____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______
_____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _
____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____
__ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____

translated from mamememo in Japanese (2009-04-02) and (2009-11-15).

2009-11-11

enumerabler.rb: Enumerable lazy-version method library

When you want to gather first ten even numbers from an integer array, what do you do?

ary.select {|x| x.even? }.take(10)

The above program is very simple. But it may cause a lot of unnecessary checks when array is big. Also, `select' creates intermediate array.

ret = []
ary.each do |x|
  ret << x if x.even?
  break if ret.size == 10
end

This will stop the loop when enough even numbers is found, and create no unnecessary array. But, it has trouble with readability and maintainability because it is very dirty, cumbersome, tricky, too long and too primitive. We live in the age of Ruby 1.9. We need more elegance.

"We can use Enumerator and `to_enum' in Ruby 1.9!"

It's a good idea, but you are unfortunate.

(1..50).to_enum(:select) {|x| x.even? }.take(10)
  #=> [1,2,3,4,5,6,7,8,9,10]  # never selected!

Please think yourself the reason why it does not work. `to_enum' is too difficult for me, to explain in English :-p

No matter how you combine `to_enum' and `select', it will never work, I guess. You can (must) use Enumerator.new without using Enumearble#select:

module Enumerable
  def selector(&blk)
    Enumerator.new do |e|
      each do |x|
        e << x if blk[x]
      end
    end
  end
end

Also troublesome...

proposed `enumerabler.rb'

I wrote a library, named enumerabler.rb, which is a collection of the above method definitions.

require "enumerabler"

ary.selector {|x| x.even? }.take(10)

You use `selector' instead of `select.' While `select' returns an array, `selector' returns an Enumerator corresponding the array. Because of Enumerator, the evaluation is delayed. So, the above program using `selector' is not only simple but also effective, which will stop its loop as soon as ten even numbers is found. No intermediate array.

enumerabler.rb defines:

  • Enumerable#grepper
  • Enumerable#finder_all (alias: all_finder, selector)
  • Enumerable#rejecter
  • Enumerable#collector (alias: mapper)
  • Enumerable#flat_mapper (alias: concat_collector)
  • Enumerable#zipper
  • Enumerable#taker
  • Enumerable#taker_while
  • Enumerable#dropper
  • Enumerable#dropper_while

All of them returns corresponding Enumerator. In an aside, I cannot distinguish -er and -or without a dictionary.

"Does it use a Fiber? Isn't it slow?"

No, enumerabler.rb does neither generate nor yield a Fiber. Trust me. If you worry, please read and check the source code of Ruby!

However, it is actually slow because it calls Proc frequently. `selector' is about two or three times slower than the original `select', but it is faster than a Fiber, and actually reduces memory usage.

Examples

p ary.selector {|x| x.even? }.taker(100).take_while {|x| x >= 0 }

gathers first 100 even numbers, however terminates before the negative element, without unnecessary check and intermediate array.

require "enumerabler"

def sieve(e, &blk)
  yield n = e.first
  sieve(e.rejecter {|x| x % n == 0 }, &blk)
end

sieve(2..(1.0/0.0)) {|x| p x } #=> 2, 3, 5, 7, 11, 13, 17, 19, 23, ...

Sieve of Eratosthenes using `rejecter.'

require "enumerabler"

def fibonacci
  Enumerator.new do |e|
    e << 1
    e << 1
    fibonacci.zip(fibonacci.dropper(1)) {|x, y| e << x + y }
  end
end

fibonacci.each {|x| p x } #=> 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

Fibonacci numbers. `dropper' can drop an infinite sequence. Note that this is very slow because of call-by-name evaluation and because `zip' internally uses a Fiber.

how to install

$ gem install enumerabler

http://github.com/mame/enumerabler

translated from mamememo in Japanese (2009-11-11).