Bring a bit of Clojure/Racket to Ruby!

I made a new gem based on some exploration I did, but to tell the story, let's talk about a possible use case.

Let's say you're writing some Ruby code where you need to call a sequence of methods on some initial value. (This is a contrived example, so bear with me)

class FileChecker  
  def report(file)
    # need to produce summary after running checks
  end

  # add error strings to an instance variable if check fails
  def check_columns(input); end
  def check_blanks(input); end
  def check_constraints(input); end

  # selects error strings and other info to return
  def summarize(input); end
end  

There are probably several ways to approach this. You could, for instance, make the input in those check methods and that summary method not an argument but an instance variable that is implicitly provided, allowing you to do this in #report:

# along with changes to all those check methods and to summarize to not take arguments...
def report(file)  
  @contents = File.read(file)
  check_columns
  check_blanks
  check_constraints
  summarize
end  

This could be a totally workable option, but what if you could enhance the testability and make the arguments more explicit for each helper method without using a bunch of tedious assignments to local variables in #report? What if you could get the benefits of working with ActiveRecord::Relation, where you can just chain where and joins and select and so on all in a row?

I experimented with this idea in the newly released pipeable gem. Here's what you could do with that gem:

require 'pipeable'  
class FileChecker  
  include Pipeable

  def report(file)
    contents = File.read(file)
    output = 
      Pipeable(contents) | 
        :check_columns | 
        :check_blanks |
        :check_constraints |
        :summarize
     output.value
  end

  ...
end  

Now, you can write pretty simple specs for those check methods; just pass the appropriate value in (no need to check if it's a Pipeable or to 'unwrap' it at all, just use the value directly). It allows you to arbitrarily break down functionality into smaller and smaller methods without losing out on composability. There's a reason -> in Clojure pops up everywhere (more on this later)!

Basically, you can wrap any value and then 'pipe' it through methods or stabby lambdas or Procs or even instances of Method. At the end, you can see the value by calling .value on the result.

Another benefit: if your methods take and return Pipeable objects, you can further streamline your API and easily chain private methods or switch them around as needed.

This gem is ~34 lines of code and has 0 dependencies, and it doesn't muffle errors. Also, it doesn't monkey patch or use any meta programming. So, it should be fairly easy to ensure correctness of the behavior.

Here's the gem on github! Check it out, fork, do whatever! It's under a permissive MIT license.

Similar Stuff That Exists in Other Languages

Clojure has this useful macro called the 'thread' macro. Here's an example:

(-> 1 (+ 1) (* 2))
; evaluates to `4`

So, -> takes the first argument, 1, and 'threads' it into the (+ 1) form as the first argument, and so on for all other forms that follow. Here's a doc with more examples.

Racket has a similar threading macro called ~>, and here's docs about it.