-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feature] Add FunctionalObject mixin
- Loading branch information
Showing
3 changed files
with
114 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |