Documentation
¶
Overview ¶
Package observer is a pure-Go (CGO=0) implementation of the core state behind Ruby's Observable mixin — the observer registry and the "changed" flag — as specified by MRI Ruby's lib/observer.rb (verified against the reference interpreter, Ruby 4.0.5).
A Registry backs one object that includes Observable. It owns the ordered set of observers (insertion order, as MRI's Hash-keyed store), the changed-flag lifecycle, and the notify decision/reset. It deliberately does not invoke observers: NotifyObservers returns the ordered (observer, method, args) tuples to call, and the actual method dispatch onto each observer stays in the caller (in go-embedded-ruby, the interpreter). Likewise responsiveness (Ruby's respond_to?) is delegated to a caller-supplied callback, so this package has no dependency on any interpreter.
The MRI mapping is:
add_observer(obj, func=:update) -> Registry.AddObserver delete_observer(obj) -> Registry.DeleteObserver delete_observers -> Registry.DeleteObservers count_observers -> Registry.CountObservers changed(state=true) -> Registry.Changed changed? -> Registry.ChangedQ notify_observers(*args) -> Registry.NotifyObservers
add_observer raises NoMethodError when the observer does not respond to the method (reproduced as *NotRespondingError); notify_observers is a no-op returning nil when changed? is false, and otherwise notifies each observer in insertion order and then resets changed? to false.
Index ¶
- Constants
- type Entry
- type NotRespondingError
- type Observer
- type Registry
- func (r *Registry) AddObserver(observer Observer, fn string, respondTo RespondTo) error
- func (r *Registry) Changed(state bool)
- func (r *Registry) ChangedQ() bool
- func (r *Registry) CountObservers() int
- func (r *Registry) DeleteObserver(observer Observer)
- func (r *Registry) DeleteObservers()
- func (r *Registry) NotifyObservers(args ...any) (entries []Entry, notifyArgs []any, ok bool)
- type RespondTo
Constants ¶
const DefaultFunc = "update"
DefaultFunc is the method name Observable#add_observer uses when the caller does not pass an explicit one, matching MRI's default (`:update`).
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Entry ¶
type Entry struct {
// Observer is the registered observer object.
Observer Observer
// Func is the name of the method to call on Observer (the value passed to
// AddObserver, or DefaultFunc).
Func string
}
Entry is a registered (observer, method) pair as returned by Registry.NotifyObservers. The caller (rbgo) performs the actual dispatch by invoking Func on Observer with the notification arguments.
type NotRespondingError ¶
type NotRespondingError struct {
// Func is the method name the observer failed to respond to.
Func string
}
NotRespondingError is returned by Registry.AddObserver when the observer does not respond to the requested method. It mirrors the NoMethodError MRI's Observable#add_observer raises; rbgo translates it back into a Ruby NoMethodError. Its Error string matches MRI's message verbatim:
observer does not respond to `update'
func (*NotRespondingError) Error ¶
func (e *NotRespondingError) Error() string
type Observer ¶
type Observer = any
Observer is one registered observer together with the name of the method to invoke on it. Observer is an opaque interface value supplied by the caller (in go-embedded-ruby it is the underlying Ruby object); this package never inspects it beyond identity, so it is used as a map key and must therefore be comparable.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is the state backing one object that includes Ruby's Observable mixin: the ordered set of observers and the "changed" flag. A zero Registry is ready to use and has no observers with changed? == false.
Registry owns the observer set, insertion ordering, the changed-flag lifecycle, and the notify decision/reset; it does not invoke observers. The method dispatch onto each observer stays in the caller (rbgo), which acts on the Entry list [NotifyObservers] returns.
Registry is not safe for concurrent use; callers must synchronise, matching MRI's Observable (which is likewise not thread-safe).
func (*Registry) AddObserver ¶
AddObserver registers observer, recording func name as the method to invoke on notification. fn is the method name (use DefaultFunc for MRI's default of :update). respondTo, when non-nil, is consulted to verify observer responds to fn; if it does not, observer is not registered and a *NotRespondingError is returned, mirroring MRI's NoMethodError. A nil respondTo skips the check (the caller is then responsible for responsiveness).
Re-adding an already-registered observer updates its method name and leaves its position in the order unchanged, matching MRI's Hash-keyed store.
func (*Registry) Changed ¶
Changed sets the changed flag to state, matching MRI's Observable#changed (whose argument defaults to true). Pass true to mark the state changed, false to clear it.
func (*Registry) ChangedQ ¶
ChangedQ reports whether the changed flag is set, matching MRI's Observable#changed?.
func (*Registry) CountObservers ¶
CountObservers returns the number of registered observers.
func (*Registry) DeleteObserver ¶
DeleteObserver removes observer from the set. Removing an observer that is not registered is a no-op, matching MRI's Hash#delete.
func (*Registry) DeleteObservers ¶
func (r *Registry) DeleteObservers()
DeleteObservers removes every observer from the set.
func (*Registry) NotifyObservers ¶
NotifyObservers decides whether observers should be notified, following MRI's Observable#notify_observers exactly:
- When changed? is false it is a no-op: it returns a nil Entry list and leaves the changed flag false. (ok reports false in this case.)
- When changed? is true it returns the registered observers in insertion order, each paired with its method name, then clears the changed flag. (ok reports true.)
args are the notification arguments; they are not used by this package and are returned to the caller unchanged so it can forward them to each observer's method. The caller (rbgo) performs the dispatch — it invokes each Entry.Func on each Entry.Observer with args — which is why the args are echoed here rather than acted upon.
ok mirrors MRI's truthiness: MRI returns nil when not changed and the result of changed(false) (i.e. false) when it did notify; callers that need the notify decision should use ok rather than len(entries).
type RespondTo ¶
RespondTo reports whether observer responds to the method named name. The caller supplies this because responsiveness is an interpreter concept (Ruby's respond_to?); this package is interpreter-agnostic. AddObserver consults it to reproduce MRI's behaviour of raising NoMethodError for an observer that does not respond to the requested method.
