APIs

Posts tagged with "APIs."
  • 11

    MAY
    2012

    Delaying Decisions

    I love playing with Ruby's Hash. I think it has a neat API and experimenting with it can actually help you understand how to write good Ruby. Let's dig into this idea to see what I mean.

    The nil Problem

    In Destroy All Software #9 Gary chooses to show an example in Python because, unlike Ruby's Hash, it will raise an error for a non-existent key. Ruby just returns nil, he explains.

    What Gary said isn't really true, but I'm guessing he just didn't know that at the time. He was in the process of switching to Ruby from Python and I'm guessing he just didn't have a deep enough understanding of Ruby's Hash yet. I bet he does know how it works now.

    But assume he was right. What's he saying and why does it matter? Consider some code like this:

    class SearchesController < ApplicationController
      def show
        terms = params[:terms]
        SomeModel.search(terms)
        # ...
      end
    end
    

    This is what Gary doesn't like, and rightfully so. Because I indexed into params here with the []() method, I will indeed get a nil if the :terms key wasn't in params.

    Read more…

  • 9

    OCT
    2008

    Dual Interface Modules

    I'm guessing we've all seen Ruby's Math Module. I'm sure you know that you can call methods in it as "module (or class) methods:"

    Math.sqrt(4)  # => 2.0
    

    That's just one way to use the Math Module though. Another is to treat it as a mixin and call the same methods as instance methods:

    module MyMathyThing
      extend Math
    
      def self.my_sqrt(*args)
        sqrt(*args)
      end
    end
    
    MyMathyThing.my_sqrt(4)  # => 2.0
    

    Ruby ships with a few Modules that work like this, including the mighty Kernel.

    How is this dual interface accomplished? With the seldom seen module_function() method. You use this much like you would private(), to affect all following method definitions:

    module Greeter
      module_function
    
      def hello
        "Hello!"
      end
    end
    
    module MyGreeter
      extend Greeter
    
      def self.my_hello
        hello
      end
    end
    
    Greeter.hello       # => "Hello!"
    MyGreeter.my_hello  # => "Hello!"
    

    As you can see, it magically gives us the dual interface for the methods beneath it. You can also affect specific methods by name, just as you could with private(). This is equivalent to my definition above:

    Read more…

    In: Ruby Voodoo | Tags: APIs | 2 Comments
  • 8

    OCT
    2008

    Readable Booleans

    There's a great little trick you can do to improve the readability of your code. A common problem is dealing with methods that have a boolean flag arguments. Here's an example I ran into just today in a Rails application:

    def rating_stars(..., clickable = false)
      # ...
    end
    

    The problem with this is that you typically see calls like this scattered around the application:

    <%= rating_stars(..., true) %>
    

    Would you know what true did there if I hadn't shown you the name of the variable first? I didn't. I had to go hunting for that method definition.

    Ironically the opposite problem, a magical dangling false, is much more rare in my experience. That's typically the default for these kind of arguments and it just makes more sense and reads better to leave it out.

    Anyway, the point is that we can typically improve the ease of understanding the common case. Remember that in Ruby false and nil are false while everything else is true. That means that truth is very loosely defined and we can pass a lot of things for our boolean flag value. For example, after looking up the method and understanding what was needed, I chose to call it like this:

    Read more…

    In: Ruby Voodoo | Tags: APIs & Style | 2 Comments
  • 6

    OCT
    2008

    Conversion Methods

    I want to take a step back from all the syntax I've been covering lately and just talk about some simple methods in Ruby's core. Ruby ships with so many great helpers, it's often hard to keep track of what everything can do. Specifically, let's talk about the type conversion methods.

    I assume we all make calls to to_s() and to_i() regularly:

    255.to_s    # => "255"
    "255".to_i  # => 255
    

    There shouldn't be any surprises there. Even these two simple methods can do more though. They make it possible to convert to and from various numeric bases. For example, here are the same conversions into and out of base 16 (hexadecimal):

    255.to_s(16)   # => "ff"
    "ff".to_i(16)  # => 255
    

    Ruby has other ways to do these same conversions. Here are two unusual methods (beginning with capital letters) that are similar:

    String(255)     # => "255"
    Integer("255")  # => 255
    

    I'll be honest and tell you that I don't really find String() useful as it just calls to_s() for you, but Integer() is a different story. First of all, to_i() is very lenient about what it converts while Integer() is more strict:

    Read more…

    In: Ruby Voodoo | Tags: APIs | 0 Comments
  • 25

    JUN
    2008

    The One Method Config

    I've used this technique a couple of times now for dirt-simple configurations. The idea is to provide a trivial way to read and write configuration values with just a single method. Let me show you what I mean:

    module Configurable
      module_function
    
      def config(new_config = nil)
        if new_config.nil?
          @config ||= { }
        else
          config.merge!(new_config)
        end
      end
    end
    
    include Configurable
    
    config                    # => {}
    
    config :a => 1, :b => 2
    config                    # => {:a=>1, :b=>2}
    config[:a]                # => 1
    
    config :a => -1, :c => 3
    config                    # => {:a=>-1, :b=>2, :c=>3}
    
    config.clear
    config                    # => {}
    

    There's no deep magic here, obviously. The method has two function: read and write for the configuration. Read is handled with what I like refer to as Ruby's "caching operator" (||=). The first time that line is triggered, it will cache an empty Hash in the variable. Thereafter, the same call is just a cache hit to get the same Hash back.

    Read more…