Python Decorators in Ruby

This past week, I had a pretty long discussion on StackOverflow about Ruby and Python, that was touched off by question about whether there was anything special about Ruby that made it more amenable for Rails.

My initial response covered blocks (as a self-hosting way to improve the language) and the ability to define new “class keywords” because of the fact that class bodies are just normal executable code. The strongest argument against this was that Python decorators are as powerful as Ruby’s executable class bodies, and therefore can be used to achieve anything that Ruby can achieve.

Python decorators do in fact provide a certain amount of additional power and elegance over the Python before decorators. However, this power is simply a subset of the available Ruby functionality. This is because Ruby has always had the ability to add features like decorators to the language without needing language changes.

In other words, while Python has added a new hardcoded feature in order to achieve some of the power of Ruby, adding such a feature to Ruby would be unnecessary because of the underlying structure of the Ruby language.

To show this clearly, I have implemented a port of Python function decorators in under 70 lines of Ruby. I wrote the code test-first, porting the necessary functionality from two Python Decorator tutorials written by Bruce Eckel in October 2008.

The list of features supported:

  • Decorate any object that responds to call via: decorate SomeKlass or decorate some_lambda
  • A simpler syntax for class names that can be used as decorators: SomeKlass(arg)
  • The ability to give the decorator a name that could be used instead of the class name, if desired

Some examples:

class MyDecorator
  def initialize(klass, method)
    @method = method
  end
 
  def call(this, *args)
    puts "Before MyDecorator with #{args.inspect}"
    @method.bind(this).call(*args)
    puts "After MyDecorator with #{args.inspect}"
  end
end
 
class WithDecorator
  # we could trivially add these to all classes, but we'll keep it isolated
  extend MethodDecorators
 
  MyDecorator() # equivalent to decorate MyDecorator
  def my_function(*args)
    puts "Inside my_function with #{args.inspect}"
  end
end
 
WithDecorator.new.my_function(1)

When MyDecorator() is called inside the WithDecorator class, it registers a decorator for the next method that is defined. This is roughly equivalent to Python’s function decoration. Some other examples:

class MyDecorator < Decorator
  decorator_name :surround
 
  def initialize(klass, method, *args)
    @method, @args = method, args
  end
 
  def call(this, *args)
    puts "Before MyDecorator(#{@args.inspect}) with #{args.inspect}"
    @method.bind(this).call(*args)
    puts "After MyDecorator(#{@args.inspect}) with #{args.inspect}"
  end
end
 
class Class
  include MethodDecorators
end
 
class WithDecorator
  surround(1, 2)
  def function(*args)
    p args
  end
end
 
WithDecorator.new.function(1)

In this case, I’ve inherited from the Decorator class, which allows me to add a decorator name, which can then be used in a class with MethodDecorators mixed in. In this example, I’ve mixed MethodDecorators into Class, which makes decorators available for all classes. Again, I could have made this the default, but I like to try to make new behaviors global if I can avoid it.

This is of course a first pass and I’m sure there are subtle inconsistencies between Python’s decorator implementation and what I have here. My point is just that the feature that was added to Python to add flexibility is merely a subset of the functionality available to Ruby, because Rubyists can implement new declarative features without needing help from the language implementors, and have always been able to.

API | Rails Fire

API

AppSumo: A Discount Bundle of Webapp Credits Suited to Ruby Developers

AppSumo is an intriguing "bad ass developer bundle" that brings together $1543 of credit for ten different Web app development related resources (most are Ruby focused or have Ruby APIs) for a mere $47 purchase.
The services include:

Wesley Beary and fog Promoted to the Engine Yard Open Source Program

There's a lot of muscle under the hood of the Engine Yard AppCloud and xCloud offerings providing Rails/Ruby automation, management and support. I am ecstatic to announce that a critical layer of our automation -- fog, the Ruby library for cloud computing and provisioning, along with its creator Wesley Beary -- are being promoted to the Engine Yard Open Source Program!

Ruby 1.9.2 Released

Yuki (Yugui) Sonoda has just announced the release of the stable version of Ruby 1.9.2!
Ruby 1.9.2 has been released. This is the newest release of Ruby 1.9 series. Ruby 1.9.2 is mostly compatible with 1.9.1, except the following changes:

Fog: A Powerful “Cloud Services” Gem

fog is a Ruby gem by Wesley Beary to control a variety of cloud services through a unified API. It deals with both server cloud and storage based services and supports Amazon S3 and Rackspace Files; as well as servers and on Amazon EC2, Rackspace Servers, Terremark vCloud and Slicehost. Support is also available for Amazon ELB and SimpleDB.

Interesting Ruby and Rails Tidbits #31

The latest installment of our series of roundup posts, covering some of our latest findings in the world of all things Ruby (or not). These items wouldn't make it in as separate posts, but they should be of enough interest to Rubyists generally to make it a worthwhile browse for most readers.

Pusher: WebSocket-powered Realtime Browser Push Service for Rubyists

Pusher is a new Web service from New Bamboo that makes it easy to push data to users of your web applications "live", outside of the request response cycle. They've embraced Web Sockets technology and built a REST API to which you can post events.

RDropbox: A Ruby Client Library for Dropbox

Dropbox is a popular file hosting service (4m+ users) that provides synced backup and file hosting to OS X, Windows, and Linux users. You get up to 2GB of space for free.

Paul Barry Winner RPCFN #8

In this brief interview, Satish Talim of RubyLearning talks to Paul Barry of USA, winner of the eighth Ruby Programming Challenge For Newbies.

Nestful: A Simple Ruby HTTP/REST Client Library

Nestful is a simple HTTP/REST client library for Ruby, developed by Alex MacCaw (of Juggernaut) fame. Nestful allows you to consume basic Web services easily, usually in a single line of code.

Facebook Rails Integration with OAuth2

This is simply awesome.  Facebook launches a new API using OAuth2, making it much easier to integrate with Facebook from your Rails app, and Michael Bleigh quickly churns out a new oauth2 gem.

Syndicate content