Skip to content

Commit

Permalink
Merge pull request #54 from linkdata/bind-split
Browse files Browse the repository at this point in the history
Bind split
  • Loading branch information
linkdata authored Dec 17, 2024
2 parents 502d1c8 + 79469b4 commit a260b31
Show file tree
Hide file tree
Showing 23 changed files with 207 additions and 611 deletions.
4 changes: 2 additions & 2 deletions bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
// The pointer will be used as the UI tag.
func Bind[T comparable](l sync.Locker, p *T) Binder[T] {
if rl, ok := l.(RWLocker); ok {
return binding[T]{lock: rl, ptr: p}
return binding[T]{RWLocker: rl, ptr: p}
}
return binding[T]{lock: rwlocker{l}, ptr: p}
return binding[T]{RWLocker: rwlocker{l}, ptr: p}
}
45 changes: 45 additions & 0 deletions bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,48 @@ func TestBindFunc_Time(t *testing.T) {
testBind_TimeSetter(t, Bind(&mu, &val))
testBind_TimeSetter(t, Bind(&mu, &val).Success(func() {}))
}

func TestBindFormat(t *testing.T) {
var mu sync.Mutex
val := 12

bind1 := Bind(&mu, &val)
if s := bind1.JawsGetHTML(nil); s != "12" {
t.Errorf("%q", s)
}

bind2 := bind1.Format("%3v")
if s := bind2.JawsGetHTML(nil); s != " 12" {
t.Errorf("%q", s)
}

bind3 := bind2.Success(func() {})
if s := bind3.JawsGetHTML(nil); s != " 12" {
t.Errorf("%q", s)
}

bind4 := bind3.Format("%4v")
if s := bind4.JawsGetHTML(nil); s != " 12" {
t.Errorf("%q", s)
}
}

func TestBindFormatHTML(t *testing.T) {
var mu sync.Mutex
val := "<span>"

bind1 := Bind(&mu, &val)
if s := bind1.JawsGetHTML(nil); s != "&lt;span&gt;" {
t.Errorf("%q", s)
}

bind2 := bind1.FormatHTML("%v")
if s := bind2.JawsGetHTML(nil); s != "<span>" {
t.Errorf("%q", s)
}

bind3 := bind2.FormatHTML("<p>%v</p>")
if s := bind3.JawsGetHTML(nil); s != "<p><span></p>" {
t.Errorf("%q", s)
}
}
15 changes: 14 additions & 1 deletion binder.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package jaws

import "html/template"

// BindSetHook is a function that replaces JawsSetLocked for a Binder.
//
// The lock will be held before calling the function, preferring RLock over Lock, if available.
Expand Down Expand Up @@ -27,11 +29,14 @@ type BindGetHook[T comparable] func(bind Binder[T], elem *Element) (value T)
// no more success hooks are called.
type BindSuccessHook func(*Element) (err error)

type BindFormatHook[T comparable] func(value T, elem *Element) (tmpl template.HTML)

type Binder[T comparable] interface {
RWLocker
Setter[T]
AnySetter
JawsGetTag(*Request) any
HTMLGetter
TagGetter

JawsBinderPrev() Binder[T] // returns the previous Binder in the chain, or nil
JawsGetLocked(elem *Element) (value T)
Expand Down Expand Up @@ -65,4 +70,12 @@ type Binder[T comparable] interface {
// * func(*Element)
// * func(*Element) error
Success(fn any) (newbind Binder[T])

// Format returns a Binder[T] that will implement JawsGetHTML(elem)
// using html.EscapeString(fmt.Sprintf(f, JawsGet[T](elem)))
Format(f string) (newbind Binder[T])

// FormatHTML returns a Binder[T] that will implement JawsGetHTML(elem)
// using fmt.Sprintf(f, JawsGet[T](elem))
FormatHTML(f string) (newbind Binder[T])
}
75 changes: 46 additions & 29 deletions binding.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package jaws

import (
"fmt"
"html"
"html/template"
)

type binding[T comparable] struct {
lock RWLocker
ptr *T
RWLocker
ptr *T
}

func (bind binding[T]) JawsBinderPrev() Binder[T] {
Expand All @@ -14,9 +20,9 @@ func (bind binding[T]) JawsGetLocked(*Element) T {
}

func (bind binding[T]) JawsGet(elem *Element) (value T) {
bind.lock.RLock()
bind.RWLocker.RLock()
value = bind.JawsGetLocked(elem)
bind.lock.RUnlock()
bind.RWLocker.RUnlock()
return
}

Expand All @@ -33,9 +39,9 @@ func (bind binding[T]) JawsSetLocked(elem *Element, value T) (err error) {
}

func (bind binding[T]) JawsSet(elem *Element, value T) (err error) {
bind.lock.Lock()
bind.RWLocker.Lock()
err = bind.JawsSetLocked(elem, value)
bind.lock.Unlock()
bind.RWLocker.Unlock()
return
}

Expand All @@ -47,20 +53,8 @@ func (bind binding[T]) JawsGetTag(*Request) any {
return bind.ptr
}

func (bind binding[T]) Lock() {
bind.lock.Lock()
}

func (bind binding[T]) Unlock() {
bind.lock.Unlock()
}

func (bind binding[T]) RLock() {
bind.lock.RLock()
}

func (bind binding[T]) RUnlock() {
bind.lock.RUnlock()
func (bind binding[T]) JawsGetHTML(elem *Element) (tmpl template.HTML) {
return template.HTML( /*#nosec G203*/ html.EscapeString(fmt.Sprint(bind.JawsGet(elem))))
}

// SetLocked returns a Binder[T] that will call fn instead of JawsSetLocked.
Expand All @@ -71,9 +65,9 @@ func (bind binding[T]) RUnlock() {
// The bind argument to the function is the previous Binder in the chain,
// and you probably want to call it's JawsSetLocked first.
func (bind binding[T]) SetLocked(fn BindSetHook[T]) Binder[T] {
return &BindingHook[T]{
Binder: bind,
BindSetHook: fn,
return bindingHook[T]{
Binder: bind,
hook: fn,
}
}

Expand All @@ -85,9 +79,9 @@ func (bind binding[T]) SetLocked(fn BindSetHook[T]) Binder[T] {
// The bind argument to the function is the previous Binder in the chain,
// and you probably want to call it's JawsGetLocked first.
func (bind binding[T]) GetLocked(fn BindGetHook[T]) Binder[T] {
return &BindingHook[T]{
Binder: bind,
BindGetHook: fn,
return bindingHook[T]{
Binder: bind,
hook: fn,
}
}

Expand All @@ -101,12 +95,35 @@ func (bind binding[T]) GetLocked(fn BindGetHook[T]) Binder[T] {
// - func(*Element)
// - func(*Element) error
func (bind binding[T]) Success(fn any) Binder[T] {
return &BindingHook[T]{
Binder: bind,
BindSuccessHook: wrapSuccessHook(fn),
return bindingHook[T]{
Binder: bind,
hook: wrapSuccessHook(fn),
}
}

// Format returns a Binder[T] that will implement JawsGetString(elem)
// using fmt.Sprintf(f, JawsGet[T](elem))
func (bind binding[T]) Format(f string) (newbind Binder[T]) {
return bindingHook[T]{
Binder: bind,
hook: BindFormatHook[T](func(value T, elem *Element) (tmpl template.HTML) {
return template.HTML( /*#nosec G203*/ html.EscapeString(fmt.Sprintf(f, value)))
}),
}
}

// FormatHTML returns a Binder[T] that will implement JawsGetHTML(elem)
// using fmt.Sprintf(f, JawsGet[T](elem))
func (bind binding[T]) FormatHTML(f string) (newbind Binder[T]) {
return bindingHook[T]{
Binder: bind,
hook: BindFormatHook[T](func(value T, elem *Element) (tmpl template.HTML) {
return template.HTML( /*#nosec G203*/ fmt.Sprintf(f, value))
}),
}

}

func wrapSuccessHook(fn any) (hook BindSuccessHook) {
switch fn := fn.(type) {
case func():
Expand Down
Loading

0 comments on commit a260b31

Please sign in to comment.