Skip to content

Commit 9d115e5

Browse files
orenmnerojnape
authored andcommitted
Adding AutoBracket, an AutoClosable constrained Bracket
1 parent ade8610 commit 9d115e5

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn2;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.functions.Fn2;
5+
import com.jnape.palatable.lambda.functions.builtin.fn3.Bracket;
6+
import com.jnape.palatable.lambda.io.IO;
7+
8+
import static com.jnape.palatable.lambda.functions.builtin.fn3.Bracket.bracket;
9+
import static com.jnape.palatable.lambda.io.IO.io;
10+
11+
/**
12+
* Given an {@link IO} yielding some {@link AutoCloseable} type <code>A</code> and a kleisli arrow from that type to a
13+
* new {@link IO} of type <code>B</code>, attempt to provision the <code>A</code>, applying the body operation if
14+
* provisioning was successful and ensuring that {@link AutoCloseable#close} is called regardless of whether the body
15+
* succeeds or fails.
16+
* <p>
17+
* This is the canonical {@link Bracket bracketing} operation for {@link AutoCloseable AutoCloseables}.
18+
*
19+
* @param <A> the initial {@link AutoCloseable} value type to map and clean up
20+
* @param <B> the resulting type
21+
* @see Bracket
22+
*/
23+
public final class AutoBracket<A extends AutoCloseable, B> implements
24+
Fn2<IO<A>, Fn1<? super A, ? extends IO<B>>, IO<B>> {
25+
26+
private static final AutoBracket<?, ?> INSTANCE = new AutoBracket<>();
27+
28+
private AutoBracket() {
29+
}
30+
31+
@Override
32+
public IO<B> checkedApply(IO<A> io, Fn1<? super A, ? extends IO<B>> bodyIO) {
33+
return bracket(io, a -> io(a::close), bodyIO);
34+
}
35+
36+
@SuppressWarnings("unchecked")
37+
public static <A extends AutoCloseable, B> AutoBracket<A, B> autoBracket() {
38+
return (AutoBracket<A, B>) INSTANCE;
39+
}
40+
41+
public static <A extends AutoCloseable, B> Fn1<Fn1<? super A, ? extends IO<B>>, IO<B>> autoBracket(IO<A> io) {
42+
return AutoBracket.<A, B>autoBracket().apply(io);
43+
}
44+
45+
public static <A extends AutoCloseable, B> IO<B> autoBracket(IO<A> io, Fn1<? super A, ? extends IO<B>> bodyIO) {
46+
return AutoBracket.<A, B>autoBracket(io).apply(bodyIO);
47+
}
48+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn2;
2+
3+
import com.jnape.palatable.lambda.adt.Unit;
4+
import com.jnape.palatable.lambda.io.IO;
5+
import org.junit.Before;
6+
import org.junit.Test;
7+
8+
import java.util.concurrent.atomic.AtomicInteger;
9+
10+
import static com.jnape.palatable.lambda.functions.builtin.fn2.AutoBracket.autoBracket;
11+
import static com.jnape.palatable.lambda.io.IO.io;
12+
import static org.hamcrest.CoreMatchers.equalTo;
13+
import static org.junit.Assert.assertEquals;
14+
import static org.junit.Assert.assertThat;
15+
import static testsupport.matchers.IOMatcher.throwsException;
16+
import static testsupport.matchers.IOMatcher.yieldsValue;
17+
18+
public class AutoBracketTest {
19+
20+
private AtomicInteger closedCounter;
21+
private AutoCloseable autoCloseable;
22+
23+
@Before
24+
public void setUp() {
25+
closedCounter = new AtomicInteger(0);
26+
autoCloseable = closedCounter::incrementAndGet;
27+
}
28+
29+
@Test
30+
public void closeWhenDone() {
31+
IO<Integer> bracketed = autoBracket(io(autoCloseable), closeable -> io(1));
32+
33+
assertEquals(0, closedCounter.get());
34+
assertThat(bracketed, yieldsValue(equalTo(1)));
35+
assertEquals(1, closedCounter.get());
36+
}
37+
38+
@Test
39+
public void closeOnException() {
40+
RuntimeException cause = new RuntimeException();
41+
42+
IO<Unit> bracketed = autoBracket(io(autoCloseable), closeable -> IO.throwing(cause));
43+
44+
assertEquals(0, closedCounter.get());
45+
assertThat(bracketed, throwsException(equalTo(cause)));
46+
assertEquals(1, closedCounter.get());
47+
}
48+
}

0 commit comments

Comments
 (0)