-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathREADME.markdown.in
95 lines (78 loc) · 3.31 KB
/
README.markdown.in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# simple-arm
`simple-arm` is based on the `Managed` typeclass, which opens and
closes resources. There are three ways to use it: for-comprehensions,
the `using` function, and `ResourceScope`s:
```scala
import com.rojoma.simplearm.util._
val linesCopied = for {
in <- managed(new java.io.FileReader(inName))
out <- managed(new java.io.FileWriter(outName))
} {
copyLines(in, out)
}
val linesCopied = using(new java.io.FileReader(inName), new java.io.FileWriter(outName)) { (in, out) =>
copyLines(in, out)
}
// return an iterator which is managed by the given ResourceScope.
// Closing the iterator through the scope will also ensure the
// underlying Source is closed.
def fileAsIterator(in: File, rs: ResourceScope): Iterator[String] = {
val source = rs.open(Source.fromFile(in))
rs.openUnmanaged(source.getLines(), transitiveClose = List(source))
}
```
The first two are almost completely equivalent; the
`for`-comprehension requires using `managed` but the `using` function
separates the resource from its name. In a `for`-comprehension,
earlier resources are available at the time later ones are
initialized, of course.
`Managed` is a monad; invoking `flatMap` or `map` on it will produce a
new `Managed`. To actually cause the effects to occur, `run` or
`foreach` must be used. This is a change from simple-arm 1, where
`Managed` supported the for-comprehension syntactic sugar without
actually being a monad. `foreach` and `run` are synonyms; in
particular, `foreach` will return the result of the function it is
passed:
```scala
val x = for(r <- managed(...)) yield 5 // x is Managed[Int]
val y = for(r <- managed(...)) 5 // y is Int
```
## Getting it
SBT:
```scala
libraryDependencies += "com.rojoma" %% "simple-arm-v2" % "%VERSION%"
```
While for Maven, the pom snippets are:
```xml
<dependencies>
<dependency>
<groupId>com.rojoma</groupId>
<artifactId>simple-arm-v2_${scala.version}</artifactId>
<version>%VERSION%</version>
</dependency>
</dependencies>
```
## Details
Resource-management is defined as follows:
1. Create the resouce by evaluating the by-name parameter passed to `managed` or `using`.
2. Open the resource by calling the `openPreTry` method on the
typeclass instance with it. By default, this is a no-op. If the
open returns normally, the resource is considered to be under
management and will be closed.
3. Open the resource by calling the `openPostTry` method on the
typeclass instance. By default, this is a no-op.
3. Do whatever is required with this resource.
4. If the "whatever" returns normally ("normally" includes via
`ControlThrowable`), invoke `close` on the typeclass instance with
it. Otherwise, invoke `closeAbormally` with both the resource
object and the exception. By default, this simply defers to
`close`. If `closeAbnormally` throws a non-`ControlThrowable`
exception, it is added to the original exception's suppressed
list.
Resources in `using` are acquired in left-to-right order and released
in the opposite order. `ResourceScope` will, unless resources are
explicitly closed early, also close resources in the opposite order
from which they were added. Note that transferring resources between
`ResourceScopes` may not preserve the exact order. Instead, it uses
_some_ order consistent with the DAG produced by resources'
`transitiveClose` parameters.