Skip to content

Commit

Permalink
[Feature] Add FunctionalObject mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
Drenmi committed Mar 8, 2021
1 parent b9064bf commit 2630109
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 2 deletions.
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,44 @@
# Stimpack
# Stimpack 💉

Supporting libraries for NydusNetwork.
Supporting libraries for NydusNetwork. Stimpack consists of a number of well
tested building blocks which can be used independently, or be combined at the
application level to build systems with consistent, well-defined interfaces
and behaviour.

## Table of Contents

- [FunctionalObject](#functionalobject)

## FunctionalObject

A simple mixin that provides a shorthand notation for instantiating and
invoking `#call` on an object.

**Example:**

Given this class definition:

```ruby
class Foo
include FunctionalObject

def initialize(bar:)
@bar = bar
end

def call
puts bar
end

private

attr_reader :bar
end
```

we can now initialize and invoke an instance of `Foo` by calling:

```ruby
Foo.(bar: "Hello world!")
#=> "Hello world!"
```
28 changes: 28 additions & 0 deletions lib/stimpack/functional_object.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module Stimpack
module FunctionalObject
module ClassMethods
# Instantiates an object and proxies arguments to the `#call` method.
# This allows for shorthand invocation, e.g.:
#
# AccruePoints.(user: user, amount: amount)
#
# which shortens code and aids in stubbing responses.
#
def call(...)
new(...).()
end
end

def self.included(klass)
klass.extend(ClassMethods)
end

# This is the main entry point to be implemented by each concrete class.
#
def call
raise NotImplementedError
end
end
end
43 changes: 43 additions & 0 deletions spec/stimpack/functional_object_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

require "stimpack/functional_object"

RSpec.describe Stimpack::FunctionalObject do
subject(:service) { klass }

describe ".call" do
context "when service does not implement #call" do
let(:klass) do
Class.new do
include Stimpack::FunctionalObject
end
end

it { expect { klass.() }.to raise_error(NotImplementedError) }
end

context "when service implements #call" do
let(:klass) do
Class.new do
include Stimpack::FunctionalObject

def initialize(foo, bar:, &block)
@foo = foo
@bar = bar
@baz = block.()
end

attr_reader :foo, :bar, :baz

def call
[foo, bar, baz]
end
end
end

it "delegates arguments, options, and block" do
expect(klass.("foo", bar: "bar") { "baz" }).to eq(%w[foo bar baz])
end
end
end
end

0 comments on commit 2630109

Please sign in to comment.