they’re rotated or tilted), and you can rotate and tweak the colors a bit, and you end up with a great looking photo, without the hassle of a big flatbed scanner and desktop scanning software.
my parents and grandparents have used ShoeBox to scan some of our family’s old photos. This is my grand-grandmother who I grew up calling Ninna, but a few weeks ago I learn that her real name is...
# original_filename if the # file is over 20k def image.original_filename @uri.path.split('/').last end image end Or to monkey patching a library that doesn’t quite work as we need it to.
add new features to Ruby itself, features that other languages’ core teams had to endlessly debate and eventually code directly into the language’s compiler or runtime. But with Ruby, we can just use Ruby itself to extend the language, thus, extending Ruby with Ruby.
a little bit of syntactic sugar for adding commonly reused tidbits of functionality to methods and functions. I’m going to take a few minutes to show some examples that demonstrate what decorators are and why they would be useful in Ruby. I used to do a lot of Python coding, and function decorators are something that I definitely miss from those day, and thing are something that can help almost all of us make our Ruby code cleaner.
from.save! to.save! end And then save both of the accounts. But, there’s a couple things that are wrong with this, the most notable of which is the lack of a transaction. (If `from.save!` succeeds, but `to.save!` fails, money will vanish into thin air).
+= amount from.save! to.save! end end Luckily, ActiveRecord (or however else you’re using your database, hopefully) makes this easy. We just throw this transaction block around our code, and we are guaranteed that everything in it succeeds, or everything in it fails.
+= amount from.save() to.save() db.commit_transaction() except: db.rollback_transaction() raise Once we add the transaction though, things get ugly. There are 10 lines of code in this method...
+= amount from.save() to.save() db.commit_transaction() except: db.rollback_transaction() raise The other 6 are all boilerplate for running the main logic inside a transaction. Worse than this being ugly and verbose though, is that every time you need to use a transaction, you have to remember all 6 of these lines, including the proper error handling and rollback semantics. This is exactly what Rich Hickey talked about on Monday. This is a great example of complecting things together. So how can we make this prettier and more DRY? Python doesn’t have blocks, so what we did with Ruby isn’t really an option.
from.save() to.save() send_money = transactional(send_money) What python does provide us though, is the ability to pass around and reassign methods easily. So, what we can do is write a function called `transactional` that takes a function as an argument, and returns the same function, but wrapped in the transaction boilerplate.
raise return transactional_fn And inside of the boilerplate, it calls the original function that was passed in, with the args that were passed in to the new function
from.save() to.save() send_money = transactional(send_money) So, we pass the function `send_money` to the `transactional` function we just defined, and returns a new function that does everything `send_money` does, except wrapped inside of a transaction, and then we assign this new function to `send_money`, overriding its original value. Now, whenever we call `send_money`, the version with the transaction will get executed.
amount from.save() to.save() And here’s what all of this has been leading up to. This idiom is so common in Python that special syntax got added to support it. This is a function decorator. And this is pretty much how you make something transactional with the Django ORM.
that this decorator mumbo jumbo solves the same problems that blocks solve. Why would we want this in Ruby.” Well, let’s look at a case where blocks are inelegant.
1) * fib(n - 2) end end So we have a very naive method to calculate the value of the nth element in the fibonacci sequence. This is slow, so we want to memoize it.
1 1 else fib(n - 1) * fib(n - 2) end end The common way to do this is to shove this `||=` stuff all over the place, which suffers from the same problem as the first example of transactions: we’ve mixed our core algorithm and some additional behavior we want to surround it.
= if n <= 1 1 else fib(n - 1) * fib(n - 2) end end We’ve also forgotten a few things, like the fact that `nil` and `false` can’t be memoized this way. More boilerplate that we have to remember and type ourselves.
else fib(n - 1) * fib(n - 2) end end end So, we could solve this with a block, but blocks don’t have access to their calling method’s name or arguments, so we have to pass them in manually.
if n <= 1 1 else fib(n - 1) * fib(n - 2) end end end end end We keep retyping the name of the method and it’s arguments over and over. This is quite brittle and will break once we change the method’s signature in any way.
= memoize(fib) Which should remind you of what we saw in Python, when the modification to the method came after the method itself. Why did the Python community not like this? A few reasons: 1) You can no longer trace the execution of your code from top to bottom 2) It’s too easy to move a method around and forget to bring the code that comes after it
else fib(n - 1) * fib(n - 2) end end So, I’m going to take the next 10 minutes to show you how we get this in Ruby. (using + instead of @, and starting with a capital letter). And what’s really cool, is that we can add this decorator syntax that is very close to Python’s, to Ruby with, with only about 15 lines of code.
orig.call(*args, &blk) end end end It has one method `call`, that will get called in place of the original method. It takes the method it’s wrapping, and the args and block that are being passed to that method in it’s current invocation.
orig.call(*args, &blk) end end end And then we call the original method, inside of the transaction block. You’ll notice this getup is a little different than how Python’s decorators work. Instead of the decorator generating a function that’s receives the arguments, our ruby decorators will receive the method and it’s arguments on each invocation. We have to do this due to Ruby’s method binding semantics, which we’ll talk about a bit more in a second.
@@decorator end def self.clear_decorator @@decorator = nil end end So what’s in Decorator? This `[email protected]` thing is the unary plus operator, so this method will be called when we call +DecoratorName, like we did with +Transactional a few slides back.
-= amount to.balance += amount from.save! to.save! end end A class that wants to have decorated methods needs to extend MethodDecorators. extend is similar to include, but instead of the methods on the module becoming instance methods of the class they’re extended onto, they become methods on the class itself. We could’ve extended MethodDecorators directly onto `Class`, but I think it’s a best practice to leave a decision like that up to the end user.
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end method_added is a private instance_method on class that is called whenever a method is define, giving us a nice way to hook into a method’s creation.
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end Call super. It’s easy to forget to this in when you’re overriding a method like method_added, method_missing, or respond_to?, but when you don’t do this, you break other libraries and
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end We get the current decorator, returning if there isn’t one, and then we clear it out. It’s important to clear it out early, because we redefine the method below, which then triggers method_added again.
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end We extract the original version of the method
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end And then redefine it
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end instance_method above actually returns an UnboundMethod, which is a method that doesn’t know what object it belongs to, so we have to rebind it to the current object.
decorator Decorator.clear_decorator orig_method = instance_method(name) define_method(name) do |*args, &blk| m = orig_method.bind(self) decorator.call(m, *args, &blk) end end end And then we call the decorator with the original method and the arguments that were passed to the new version.
I showed that we could pass a value to a decorator. We want to be able to construct individual instances of decorators however we want and use them to decorate our methods
corner cases, added a thorough test suite, and rolled all of this into a gem. `gem install method_decorators`, or check the code out on github. Use this, as I think it can make a bunch of your code cleaner and more easily read and maintained.
ruby or python is better, you can point out that we can add features from python to ruby, but ruby features cannot be added to python. So I think we can now definitively say that ruby is better than python.
Partial application is a general functional programming technique that’s in a bunch of languages, but Scala’s support and syntax for it is particularly elegant.
all, and instead just use an _, and it fills it in with the argument passed to the function. I find this to be much more readable/easy to explain that our Symbol#to_proc equivalent.
[1,2,3].reduce(& _ + _ * 2) [1,2,3].map(& 1 + _ ) We can do this in Ruby with just an added ampersand (+ some magic code), but this only works if the _ is the first thing in function that you’re writing. There’s also a bunch of cases where the code I’ve written for this doesn’t really work, so I’m not going to waste your time showing how’ve I’ve done this.
3 }) [1,2,3].reduce(&_{ _ + _ * 2 }) [1,2,3].map(&_{ 1 + _ }) But, with a little bit of added ugliness, we can get things to work exactly like they do in Scala. This has definitely crossed the threshold into “bad idea” territory where it’s not generally useful, but I think the “how” behind this is interesting enough to look into.
the _ method, which we added to Object. (Don’t do this. If you’re adding a method to Object, you should reevaluate things a bit.) It returns a new instance of PartialApplication. So what’s a PartialApplication?
lambda do |*args| Execution.new(args, @blk.binding). instance_eval(&@blk) end end end that builds a new `Execution` with the arguments that the block is given, and the binding of the block. A block’s binding is the environment that the block was defined in, so we’ll us it later to pull some things out of.
lambda do |*args| Execution.new(args, @blk.binding). instance_eval(&@blk) end end end Finally, we instance_eval the block on the Execution. So what’s an execution?
name == :_ @args.shift else @binding.instance_eval do method(name) end.call(*args, &blk) end end end And remember that we instance_evaled that block on this method, and obviously there’s not really anything defined in here, so every method call should go to method_missing instead.
name == :_ @args.shift else @binding.instance_eval do method(name) end.call(*args, &blk) end end end Hitting the else branch first, we find the method that was trying to be called in the original binding, and then we call it.
name == :_ @args.shift else @binding.instance_eval do method(name) end.call(*args, &blk) end end end But, when the name of the method is _, we instead pop the first element off of the args that were passed in in the invocation of the PartialEvaluation lambda.
to_proc on that instance of PartialApplication, and it returns a lambda that gets called with each item we’re mapping over and passes those args to a new instance of Execution.
= “I'm lazy" main = putStrLn (rails_conf (simpleHTTP (getRequest “http://haskell.org/"))) So, this is some dummy Haskell code to quickly demonstrate this concept, and I promise this is the only slide of Haskell in the deck.
response = “I'm lazy" main = putStrLn (rails_conf (simpleHTTP (getRequest “http://haskell.org/"))) This declares a function called rails_conf, and says that its argument is going to be of type IO (Network.Stream.Result (Response String)), which is Haskellese for “the result of a network request”, and returns a String.
= “I'm lazy" main = putStrLn (rails_conf (simpleHTTP (getRequest “http://haskell.org/"))) Here we define the body of that function, calling the argument we get passed `response`, and then returning the string “I’m lazy”
= “I'm lazy" main = putStrLn (rails_conf (simpleHTTP (getRequest “http://haskell.org/"))) We define the main function, which is the function that gets called when we run this file, and tell it to print out the result of calling the rails_conf function
Either Haskell doesn’t need a network to make HTTP requests, which would be pretty cool, or something else is going. The something else is lazy evaluation: Haskell doesn’t actually execute the http request until the result is needed from it.
end puts rails_conf( get(“http://ruby-lang.org”)) Same thing in Ruby. And of course we all know that if we ran this without an internet connection, it would blow up.
end end puts rails_conf( get(“http://ruby-lang.org”)) But, we can wrap this in a Lazy, which we’re about to define, and then this method won’t actually evaluate as its result is unused. And so this version of the program will run fine without a network connection.
def method_missing(method, *args, &blk) @result ||= @block.call @result.send(method, *args, &blk) end end Lazy is incredibly simple. It stores the block that’s passed to it.
def method_missing(method, *args, &blk) @result ||= @block.call @result.send(method, *args, &blk) end end And then when any methods are called on it, it evaluates the block once, stores the result, and then sends that method on to the result of the block. All future methods called on the lazy are then delegated to the cached result.
if ... #some exceptions im = k.instance_method(m) k.send(:define_method, m) do |*args| Lazy.new do im.bind(self).call(*args)} end end end end We loop over every method in every module and class (with a couple of exceptions), and redefine them to be lazy. Now, every method in Ruby is completely lazy, à la Haskell, and if you program in a functional style where you don’t rely on side effects from your methods, this completely works, and I’ve written some simple programs with this change made.
<% @tweets.each do |tweet| %> <%= tweet.author_name %>: <%= tweet.text %> <% end %> But the laziness stuff can actually be useful in your day to day work as a rails programmer. This is some fairly simple rails code to fetch some tweets from the twitter API and print them out.
end # View <% @tweets.each do |tweet| %> <%= tweet.author_name %>: <%= tweet.text %> <% end %> But if you’re taking advantage of rails’s streaming response stuff, it’s essential to get the header of you page down to client as quickly as possible so the browser can start fetching the CSS and JS. If we make the request to twitter lazy,
“Tail-call recursive would make this code so much cleaner" So whenever you hear your coworker say “I really wish we could use Java style annotations here”,
“Tail-call recursion would make this code so much cleaner.” Or “Tail-call recursion would make this code so much cleaner”, realize that you can build these things into Ruby yourself.