Links
Tags
apache
armenia
books
bsd
c
c++
chips
cinema
concurrency
cooking
database
dragonfly
erlang
filesystem
freebsd
fun
hardware
java
javascript
json
languages
linux
lyric
mac_osx
mail
math
misc
music
personal
poems
presentation
programming
python
references
ruby
rubyjs
scm
software
spiking_neural_net
study
sysadm
sysarch
technology
testing
travel
virtualization
web
wee
windows
require 'openssl'
require 'xmlrpc/client'
def hmac(key, msg) OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('md5'), key, msg) end
passwd = "abc"
url = "http://127.0.0.1:3001"
p XMLRPC::Client.new2(url).call("f", hmac(passwd, url), 0, [])
It should query a tinyp2p.py server started with:
python tinyp2p.py abc server 127.0.0.1 3001
But it failed for some unknown reason. So I stopped at this point.
Today, Florian Gross posted a 6 lines P2P program in Ruby which is shown below:
# Server: ruby p2p.rb password server server-uri merge-servers
# Sample: ruby p2p.rb foobar server druby://localhost:1337 druby://foo.bar:1337
# Client: ruby p2p.rb password client server-uri download-pattern
# Sample: ruby p2p.rb foobar client druby://localhost:1337 *.rb
require'drb';F,D,C,P,M,U,*O=File,Class,Dir,*ARGV;def s(p)F.split(p[/[^|].*/])[-1
]end;def c(u);DRbObject.new((),u)end;def x(u)[P,u].hash;end;M=="client"&&c(U).f(
x(U)).each{|n|p,c=x(n),c(n);(c.f(p,O[0],0).map{|f|s f}-D["*"]).each{|f|F.open(f,
"w"){|o|o<<c.f(p,f,1)}}}||(DRb.start_service U,C.new{def f(c,a=[],t=2)c==x(U)&&(
t==0&&D[s(a)]||t==1&&F.read(s(a))||p(a))end;def y()(p(U)+p).each{|u|c(u).f(x(u),
p(U))rescue()};self;end;private;def p(x=[]);O.push(*x).uniq!;O;end}.new.y;sleep)
I think I would understand this code better than the Python code, but I will not try it ;-)
The examples are taken from the article Decorate this.
Wrapping
Let me show the Python example first.
def wrapwith(obj):
def decorator(f):
def _wrapper(*args, **kwargs):
print "##", obj
return f(*args, **kwargs)
return _wrapper
return decorator
@wrapwith(42)
def f(x): return x*2
# let's use it
print f(4)
Now the same example in Ruby (with my single-line patch applied):
def wrapwith(obj, method_id)
old_method = method(method_id)
new_method = proc {|*args|
print "##", obj, "\n"
old_method.call(*args)
}
self.class.send(:define_method, method_id, new_method)
end
wrapwith 42,
def f(x) x*2 end
# let's use it
print f(4)
For me, the Python example is harder to understand, as three nested function definitions are involved. Now, the Ruby example is just fine, but in Ruby 2.0 we can even do better:
def f(x) x*2 end
def wrap:f(x)
print "##", 42, "\n"
super # calls "f"
end
print f(4)
For all examples, the output will be:
## 42
8
Prototype-based OO
Below, I only show how to apply prototype-based OO with Decorators in Python, not how to implement it. For the complete Python example see Decorate this.
class Foo:
def __init__(self):
self.x = 42
foo = Foo()
@addto(foo)
def print_x(self):
print self.x
foo.print_x() # => 42
The same in Ruby:
class Foo
def initialize
@x = 42
end
end
foo = Foo.new
def foo.print_x
print @x
end
foo.print_x # => 42
Note that the Ruby example is complete whereas in the Python example the implementation of @addto is missing. But what if you want to add a whole bunch of methods to an object? In Ruby it’s as easy:
foo = Foo.new
class << foo
def m1
1
end
def m2
2
end
end
foo.m1 # => 1
foo.m2 # => 2
The Ruby language instead is pretty constant since it’s very beginnings (version 1.0 of December 1996). There are no visible changes in the language (but in the library!) except the introduction of class-variables in 1.4 (or was it 1.6?).
Decorators in Python
Instead of:
def f(...)
...
f = synchronize(f)
you can now write:
@synchronize
def f(...)
...
The part after the at-sign is simply a function (synchronize is our case).
Decorators in Ruby
def f
...
end
synchronize :f
That’s pretty the same as the first Python example shown above. But can we simulate the second Python example in Ruby? Yes we can! We could do this in pure Ruby, but that would be a bit more advanced. Therefore I’ll show you how to do it with a minor change to the Ruby interpreter. Minor means that the change does not break any existing code and that only one line needs to be changed:
--- eval.c 2 Aug 2004 08:52:53 -0000 1.686
+++ eval.c 16 Aug 2004 12:52:28 -0000
@@ -3701,7 +3701,7 @@
rb_add_method(rb_singleton_class(ruby_class),
node->nd_mid, defn, NOEX_PUBLIC);
}
- result = Qnil;
+ result = ID2SYM(node->nd_mid);
}
break;
With this patch applied, a method definition will return the method name as symbol. Let’s try this:
x =
def f
end
p x # => :f
Now we can "simulate" the second Python example in Ruby:
synchronize def f
...
end
# or with the decorator on a separate line
synchronize \
def f
...
end
Note that the backslash after the synchronize in the second part of the example is neccessary! This tells Ruby that the argument is on the next line.
And we can even cascade "decorators":
private memoize synchronize \
def f
...
end
Of course this only works if each involved "decorator" method passes the method-id through.