Skip to content

Commit 64cbadb

Browse files
authored
Improvements to the documentation (#64)
This adds cross-references, examples, expands detail, and rewords for greater clarity. Some argument names are modified for more intiutive interpretation. It also enhances the manual and should turn on previews in PRs. Fixes #49.
1 parent 334ab42 commit 64cbadb

File tree

4 files changed

+105
-43
lines changed

4 files changed

+105
-43
lines changed

docs/Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
4+
[compat]
5+
Documenter = "0.25"

docs/make.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ makedocs(
99
pages = Any["Home" => "index.md"],
1010
)
1111

12-
deploydocs(repo = "github.com/JuliaGizmos/Observables.jl.git")
12+
deploydocs(repo = "github.com/JuliaGizmos/Observables.jl.git", push_preview=true)

docs/src/index.md

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
# Observables
22

3-
Observables are like `Ref`s but you can listen to changes.
3+
Observables are like `Ref`s:
44

55
```@repl manual
66
using Observables
77
88
observable = Observable(0)
99
10+
observable[]
11+
```
12+
13+
But unlike `Ref`s, but you can listen for changes:
14+
15+
```@repl manual
1016
obs_func = on(observable) do val
1117
println("Got an update: ", val)
1218
end
1319
1420
observable[] = 42
1521
```
1622

17-
To get the value of an observable index it with no arguments
18-
```@repl manual
19-
observable[]
20-
```
21-
2223
To remove a handler use `off` with the return value of `on`:
2324

2425
```@repl manual
@@ -45,36 +46,44 @@ obs_func = nothing
4546
### Async operations
4647

4748
#### Delay an update
48-
```julia
49+
50+
```@repl manual
4951
x = Observable(1)
5052
y = map(x) do val
5153
@async begin
52-
sleep(0.5)
54+
sleep(1.5)
5355
return val + 1
5456
end
5557
end
58+
tstart = time()
59+
onany(x, y) do xval, yval
60+
println("At ", time()-tstart, ", we have x = ", xval, " and y = ", yval)
61+
end
62+
sleep(3)
63+
x[] = 5
64+
sleep(3)
5665
```
5766

5867
#### Multiply updates
59-
If you want to fire several events on an update (e.g. for interpolating animations), you can use a channel:
60-
```julia
68+
69+
If you want to fire several events on an update (e.g., for interpolating animations), you can use a channel:
70+
71+
```@repl manual
6172
x = Observable(1)
6273
y = map(x) do val
6374
Channel() do channel
6475
for i in 1:10
6576
put!(channel, i + val)
6677
end
6778
end
68-
end
79+
end; on(y) do val
80+
println("updated to ", val)
81+
end; sleep(2)
6982
```
7083

71-
#### The same works for constructing observables
84+
Similarly, you can construct the Observable from a `Channel`:
7285

7386
```julia
74-
Observable(@async begin
75-
sleep(0.5)
76-
return 1 + 1
77-
end)
7887
Observable(Channel() do channel
7988
for i in 1:10
8089
put!(channel, i + 1)
@@ -97,7 +106,7 @@ Modules = [Observables]
97106
Private = false
98107
```
99108

100-
### Internal
109+
### Extensions of Base methods or internal methods
101110

102111
```@autodocs
103112
Modules = [Observables]

src/Observables.jl

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ function observe(::S) where {S<:AbstractObservable}
2525
end
2626

2727
"""
28-
Like a `Ref` but updates can be watched by adding a handler using `on`.
28+
obs = Observable(val)
29+
obs = Observable{T}(val)
30+
31+
Like a `Ref`, but updates can be watched by adding a handler using [`on`](@ref) or [`map`](@ref).
2932
"""
3033
mutable struct Observable{T} <: AbstractObservable{T}
3134
listeners::Vector{Any}
@@ -162,16 +165,33 @@ end
162165
on(f, observable::AbstractObservable; weak = false)
163166
164167
Adds function `f` as listener to `observable`. Whenever `observable`'s value
165-
is set via `observable[] = val` `f` is called with `val`.
168+
is set via `observable[] = val`, `f` is called with `val`.
166169
167-
Returns an `ObserverFunction` that wraps `f` and `observable` and allows to
170+
Returns an [`ObserverFunction`](@ref) that wraps `f` and `observable` and allows to
168171
disconnect easily by calling `off(observerfunction)` instead of `off(f, observable)`.
172+
If instead you want to compute a new `Observable` from an old one, use [`map(f, ::Observable)`](@ref).
169173
170174
If `weak = true` is set, the new connection will be removed as soon as the returned `ObserverFunction`
171175
is not referenced anywhere and is garbage collected. This is useful if some parent object
172176
makes connections to outside observables and stores the resulting `ObserverFunction` instances.
173177
Then, once that parent object is garbage collected, the weak
174178
observable connections are removed automatically.
179+
180+
# Example
181+
182+
```jldoctest; setup=:(using Observables)
183+
julia> obs = Observable(0)
184+
Observable{$Int} with 0 listeners. Value:
185+
0
186+
187+
julia> on(obs) do val
188+
println("current value is ", val)
189+
end
190+
(::Observables.ObserverFunction) (generic function with 0 methods)
191+
192+
julia> obs[] = 5;
193+
current value is 5
194+
```
175195
"""
176196
function on(@nospecialize(f), observable::AbstractObservable; weak::Bool = false)
177197
push!(listeners(observable), f)
@@ -305,7 +325,7 @@ to_value(x) = isa(x, AbstractObservable) ? x[] : x # noninferrable dispatch is
305325
"""
306326
obsid(observable::Observable)
307327
308-
Gets a unique id for an observable!
328+
Gets a unique id for an observable.
309329
"""
310330
obsid(observable::Observable) = string(objectid(observable))
311331
obsid(observable::AbstractObservable) = obsid(observe(observable))
@@ -327,6 +347,8 @@ Calls `f` on updates to any observable refs in `args`.
327347
`args` may contain any number of `Observable` objects.
328348
`f` will be passed the values contained in the refs as the respective argument.
329349
All other objects in `args` are passed as-is.
350+
351+
See also: [`on`](@ref).
330352
"""
331353
function onany(f::F, args...; weak::Bool = false) where F
332354
callback = OnUpdate(f, args)
@@ -366,6 +388,35 @@ Updates `observable` with the result of calling `f` with values extracted from a
366388
All other objects in `args` are passed as-is.
367389
368390
By default `observable` gets updated immediately, but this can be suppressed by specifying `update=false`.
391+
392+
# Example
393+
394+
We'll create an observable that can hold an arbitrary number:
395+
396+
```jldoctest map!; setup=:(using Observables)
397+
julia> obs = Observable{Number}(3)
398+
Observable{Number} with 0 listeners. Value:
399+
3
400+
```
401+
402+
Now,
403+
404+
```jldoctest map!
405+
julia> obsrt1 = map(sqrt, obs)
406+
Observable{Float64} with 0 listeners. Value:
407+
1.7320508075688772
408+
```
409+
410+
creates an `Observable{Float64}`, which will fail to update if we set `obs[] = 3+4im`.
411+
However,
412+
413+
```jldoctest map!
414+
julia> obsrt2 = map!(sqrt, Observable{Number}(), obs)
415+
Observable{Number} with 0 listeners. Value:
416+
1.7320508075688772
417+
```
418+
419+
can handle any number type for which `sqrt` is defined.
369420
"""
370421
@inline function Base.map!(f::F, observable::AbstractObservable, os...; update::Bool=true) where F
371422
# note: the @inline prevents de-specialization due to the splatting
@@ -396,15 +447,28 @@ See also [`Observables.ObservablePair`](@ref).
396447
connect!(o1::AbstractObservable, o2::AbstractObservable) = map!(identity, o1, o2)
397448

398449
"""
399-
map(f, observable::AbstractObservable, args...)
450+
obs = map(f, arg1::AbstractObservable, args...)
400451
401-
Creates a new observable ref which contains the result of `f` applied to
402-
values extracted from args. The second argument `observable` must be an observable ref for
403-
dispatch reasons. `args` may contain any number of `Observable` objects.
452+
Creates a new observable ref `obs` which contains the result of `f` applied to values
453+
extracted from `arg1` and `args` (i.e., `f(arg1[], ...)`.
454+
`arg1` must be an observable ref for dispatch reasons. `args` may contain any number of `Observable` objects.
404455
`f` will be passed the values contained in the refs as the respective argument.
405456
All other objects in `args` are passed as-is.
457+
458+
If you don't need the value of `obs`, and just want to run `f` whenever the
459+
arguments update, use [`on`](@ref) or [`onany`](@ref) instead.
460+
461+
# Example
462+
463+
```jldoctest; setup=:(using Observables)
464+
julia> obs = Observable([1,2,3]);
465+
466+
julia> map(length, obs)
467+
Observable{$Int} with 0 listeners. Value:
468+
3
469+
```
406470
"""
407-
@inline function Base.map(f::F, observable::AbstractObservable, os...; kwargs...) where F
471+
@inline function Base.map(f::F, arg1::AbstractObservable, args...; kwargs...) where F
408472
# note: the @inline prevents de-specialization due to the splatting
409473
if haskey(kwargs, :init)
410474
Base.depwarn("""
@@ -415,23 +479,9 @@ All other objects in `args` are passed as-is.
415479
`map!(f, Observable{T}(), args...)`.
416480
""", :map)
417481
dest = Observable{Any}(kwargs[:init])
418-
return map!(f, dest, observable, os...; update=false)
482+
return map!(f, dest, arg1, args...; update=false)
419483
end
420-
map!(f, Observable(f(observable[], map(to_value, os)...)), observable, os...; update=false)
421-
end
422-
423-
"""
424-
map(f, Observable{T}, args...)
425-
426-
Creates an `Observable{T}` containing the result of calling `f` with values extracted from args.
427-
`args` may contain any number of `Observable` objects.
428-
`f` will be passed the values contained in the refs as the respective argument.
429-
All other objects in `args` are passed as-is.
430-
"""
431-
@inline function Base.map(f::F, ::Type{Observable{T}}, os...) where {F, T}
432-
# note: the @inline prevents de-specialization due to the splatting
433-
dest = Observable{T}(f(map(to_value, os)...))
434-
map!(f, dest, os...; update=false)
484+
map!(f, Observable(f(arg1[], map(to_value, args)...)), arg1, args...; update=false)
435485
end
436486

437487
"""

0 commit comments

Comments
 (0)