Functional Patterns for Ruby

by Arne Brasseur / plexus

JRubyConf EU 2013 Lightning talk

Immutability

FREEZE ALL THE THINGS!

class Foo
  def initialize(a,b)
    @a, @b = a.freeze, b.freeze
  end
end

Immutability

IceNine!

IceNice.deep_freeze(foo)

Function Classes

def MyCalculation
  def self.call ; self.new.call ; end

  def initialize(param_x = 7)
    @param_x = param_x.freeze
  end

  def call(in_value) ; out_value ; end

  def intermediate
    @intermediate ||= @param_x * @param_x
  end
end

Function Classes

Callable like a lambda

@calc = MyCalculation
new_value = @calc.(new_value)

Pipelining

class ValueClass
  # ...snip...

  def |(callable)
    callable.call(self)
  end

  def process(callables)
    callables.empty? ? self :
      callables.first.(self).process(callables.drop(1))
  end
end

Pipelining

new_value = value | MyCalculation \
  | MyCalculation.new(5) | ->(v) { v.foo }
new_value = value.process(
  MyCalculation,
  MyCalculation.new(5),
  ->(v) { v.foo }
)

API design

What about operators that look like they modify the object?

# This does not work
h << foo
h << bla
# This does... but ugly backslash
h = h << foo \
      << bla

API design

(Re)discovered <<=

h = foo
h <<= H[:title, "Web Linguistics"]
h <<= H[:link, rel: 'stylesheet', href: 'stylesheets/stylesheet.css']
h <<= H[:script, src: file_uri_relative('javascripts/highlight.pack.js')]

Name your blocks

def do_x
  ->(_) { ... }
end

def only_y
  ->(_) { ... }
end

foo.map(&do_x).filter(&only_y)

FIN

Twitter / Github : @plexus