You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
2.4 KiB
126 lines
2.4 KiB
2 years ago
|
package engine
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
|
||
|
"gitoa.ru/go-4devs/mime"
|
||
|
"gitoa.ru/go-4devs/templating/loader"
|
||
|
"gitoa.ru/go-4devs/templating/render"
|
||
|
)
|
||
|
|
||
|
var _ render.Engine = (*Engine)(nil)
|
||
|
|
||
|
var (
|
||
|
ErrNotSupport = errors.New("not support")
|
||
|
ErrDuplicate = errors.New("duplicate")
|
||
|
ErrNotFound = errors.New("not found")
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
Option func(*Engine)
|
||
|
Parse func(loader.Source) (Template, error)
|
||
|
)
|
||
|
|
||
|
type Cache interface {
|
||
|
Set(ctx context.Context, tpl Template) error
|
||
|
Get(ctx context.Context, name string) (Template, error)
|
||
|
List(_ context.Context) []Template
|
||
|
}
|
||
|
|
||
|
func WithTemplates(tpls ...Template) Option {
|
||
|
ctx := context.Background()
|
||
|
|
||
|
return func(l *Engine) {
|
||
|
for _, tpl := range tpls {
|
||
|
_ = l.tpls.Set(ctx, tpl)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithLoader(load loader.Loader) Option {
|
||
|
return func(l *Engine) {
|
||
|
l.load = load
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithFormats(formats ...mime.Ext) Option {
|
||
|
return func(e *Engine) {
|
||
|
e.formats = formats
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func New(name string, parse Parse, opts ...Option) *Engine {
|
||
|
engine := Engine{
|
||
|
name: name,
|
||
|
parce: parse,
|
||
|
tpls: NewTemplates(),
|
||
|
load: loader.Empty(),
|
||
|
}
|
||
|
|
||
|
for _, opt := range opts {
|
||
|
opt(&engine)
|
||
|
}
|
||
|
|
||
|
return &engine
|
||
|
}
|
||
|
|
||
|
type Engine struct {
|
||
|
name string
|
||
|
formats []mime.Ext
|
||
|
tpls Cache
|
||
|
load loader.Loader
|
||
|
parce Parse
|
||
|
}
|
||
|
|
||
|
func (l Engine) WithLoader(load loader.Loader) *Engine {
|
||
|
return New(l.name, l.parce, WithTemplates(l.tpls.List(context.Background())...), WithLoader(load))
|
||
|
}
|
||
|
|
||
|
func (l Engine) Add(ctx context.Context, tpls ...Template) error {
|
||
|
for idx, tpl := range tpls {
|
||
|
if err := l.tpls.Set(ctx, tpl); err != nil {
|
||
|
return fmt.Errorf("engine add template[%d] with name %s: %w", idx, tpl.Name(), err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (l Engine) Support(ctx context.Context, tpl render.Reference) bool {
|
||
|
return Support(tpl, l.name, l.formats...)
|
||
|
}
|
||
|
|
||
|
func (l Engine) Load(ctx context.Context, reference render.Reference) (render.Execute, error) {
|
||
|
var (
|
||
|
tpl Template
|
||
|
err error
|
||
|
)
|
||
|
|
||
|
tpl, err = l.tpls.Get(ctx, reference.Name())
|
||
|
if err == nil {
|
||
|
return tpl.Execute, nil
|
||
|
}
|
||
|
|
||
|
if !errors.Is(err, ErrNotFound) {
|
||
|
return nil, fmt.Errorf("load get:%w", err)
|
||
|
}
|
||
|
|
||
|
source, err := l.load.Load(ctx, reference)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("load source:%w", err)
|
||
|
}
|
||
|
|
||
|
tpl, err = l.parce(source)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("load parce:%w", err)
|
||
|
}
|
||
|
|
||
|
if err := l.tpls.Set(ctx, tpl); err != nil {
|
||
|
return nil, fmt.Errorf("load set:%w", err)
|
||
|
}
|
||
|
|
||
|
return tpl.Execute, nil
|
||
|
}
|