diff --git a/.gitignore b/.gitignore index f30e625..5292519 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -logs/ -.idea/ \ No newline at end of file +logs/ \ No newline at end of file diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..949ba36 --- /dev/null +++ b/example/main.go @@ -0,0 +1,117 @@ +package main + +import ( + "log/slog" + + "ron" +) + +type SomethingElements struct { + Name string + Description string +} + +var elements = []SomethingElements{ + {"element 1", "description 1"}, + {"element 2", "description 2"}, + {"element 3", "description 3"}, + {"element 4", "description 4"}, + {"element 5", "description 5"}, + {"element 6", "description 6"}, + {"element 7", "description 7"}, + {"element 8", "description 8"}, + {"element 9", "description 9"}, + {"element 10", "description 10"}, + {"element 11", "description 11"}, + {"element 12", "description 12"}, + {"element 13", "description 13"}, + {"element 14", "description 14"}, + {"element 15", "description 15"}, + {"element 16", "description 16"}, + {"element 17", "description 17"}, + {"element 18", "description 18"}, + {"element 19", "description 19"}, + {"element 20", "description 20"}, + {"element 21", "description 21"}, + {"element 22", "description 22"}, + {"element 23", "description 23"}, + {"element 24", "description 24"}, + {"element 25", "description 25"}, + {"element 26", "description 26"}, + {"element 27", "description 27"}, + {"element 28", "description 28"}, + {"element 29", "description 29"}, + {"element 30", "description 30"}, + {"element 31", "description 31"}, + {"element 32", "description 32"}, + {"element 33", "description 33"}, + {"element 34", "description 34"}, + {"element 35", "description 35"}, + {"element 36", "description 36"}, + {"element 37", "description 37"}, + {"element 38", "description 38"}, + {"element 39", "description 39"}, + {"element 40", "description 40"}, + {"element 41", "description 41"}, + {"element 42", "description 42"}, + {"element 43", "description 43"}, + {"element 44", "description 44"}, + {"element 45", "description 45"}, + {"element 46", "description 46"}, + {"element 47", "description 47"}, + {"element 48", "description 48"}, + {"element 49", "description 49"}, +} + +func main() { + r := ron.New(func(e *ron.Engine) { + e.LogLevel = slog.LevelDebug + }) + + htmlRender := ron.NewHTMLRender() + r.Render = htmlRender + + r.Static("static", "static") + + r.GET("/json", helloWorldJSON) + r.POST("/another", anotherHelloWorld) + r.GET("/html", helloWorldHTML) + r.GET("/component", componentHTML) + + r.Run(":8080") +} + +func helloWorld(c *ron.Context) { + slog.Info("Dummy info message") + c.W.Write([]byte("hello world")) +} + +func anotherHelloWorld(c *ron.Context) { + c.W.Write([]byte("another hello world")) +} + +func helloWorldJSON(c *ron.Context) { + c.JSON(200, ron.Data{"message": "hello world"}) +} + +func helloWorldHTML(c *ron.Context) { + + pages := ron.Pages{ + TotalElements: len(elements), + ElementsPerPage: 5, + } + + pages.PaginationParams(c.R) + elementsPaginated := pages.PaginateArray(elements) + + td := &ron.TemplateData{ + Data: ron.Data{"title": "hello world", "message": "hello world from html", "elements": elementsPaginated}, + Pages: pages, + } + + c.HTML(200, "page.index.gohtml", td) +} + +func componentHTML(c *ron.Context) { + c.HTML(200, "component.list.gohtml", nil) +} diff --git a/example/static/img/dummy.png b/example/static/img/dummy.png new file mode 100644 index 0000000..885878c Binary files /dev/null and b/example/static/img/dummy.png differ diff --git a/example/templates/component.list.gohtml b/example/templates/component.list.gohtml new file mode 100644 index 0000000..342f35f --- /dev/null +++ b/example/templates/component.list.gohtml @@ -0,0 +1,4 @@ + diff --git a/example/templates/page.index.gohtml b/example/templates/page.index.gohtml new file mode 100644 index 0000000..f1eef8a --- /dev/null +++ b/example/templates/page.index.gohtml @@ -0,0 +1,52 @@ + + + + + + {{ .Data.title }} + + + + + + +{{ .Data.message }} + +{{ range .Data.elements }} + + +{{ end }} + +{{ if not .Pages.HasPrevious }} +primera página +{{ else }} +primera +anterior +{{ end }} + +{{ range .Pages.PageRange 5 }} +{{ if .Active }} +{{ .Number }} +{{ else }} +{{ .Number }} +{{ end }} +{{ end }} + +{{ if not .Pages.HasNext }} +última página +{{ else }} +siguiente +última +{{ end }} + + + + + + \ No newline at end of file diff --git a/ron.go b/ron.go index 75fcb78..aeea964 100644 --- a/ron.go +++ b/ron.go @@ -24,27 +24,10 @@ type ( E *Engine } - router struct { - path string - method string - handler func(*Context) - group *routerGroup - } - - routerGroup struct { - prefix string - middlewares middlewareChain - engine *Engine - } - - middlewareChain []func(http.Handler) http.Handler - Engine struct { - LogLevel slog.Level - Render *Render - mux *http.ServeMux - middlewares middlewareChain - router []router + mux *http.ServeMux + LogLevel slog.Level + Render *Render } ) @@ -70,32 +53,8 @@ func (e *Engine) apply(opts ...EngineOptions) *Engine { return e } -func (e *Engine) applyMiddlewares(handler http.Handler) http.Handler { - for i := len(e.middlewares) - 1; i >= 0; i-- { - handler = e.middlewares[i](handler) - } - return handler -} - func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) { - handler := e.applyMiddlewares(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - for _, route := range e.router { - if strings.HasPrefix(r.URL.Path, route.path) && r.Method == route.method { - groupHandler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - route.handler(&Context{W: w, R: r, E: e}) - })) - if route.group != nil { - for i := len(route.group.middlewares) - 1; i >= 0; i-- { - groupHandler = route.group.middlewares[i](groupHandler) - } - } - groupHandler.ServeHTTP(w, r) - return - } - } - http.NotFound(w, r) - })) - handler.ServeHTTP(w, r) + e.handleRequest(w, r) } func (e *Engine) Run(addr string) error { @@ -107,35 +66,24 @@ func (e *Engine) handleRequest(w http.ResponseWriter, r *http.Request) { e.mux.ServeHTTP(w, r) } -func (e *Engine) USE(middleware ...func(http.Handler) http.Handler) { - e.middlewares = append(e.middlewares, middleware...) -} - func (e *Engine) GET(path string, handler func(*Context)) { - e.router = append(e.router, router{path: path, method: http.MethodGet, handler: handler}) + e.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + return + } + handler(&Context{W: w, R: r, E: e}) + }) } func (e *Engine) POST(path string, handler func(*Context)) { - e.router = append(e.router, router{path: path, method: http.MethodPost, handler: handler}) -} - -func (e *Engine) GROUP(prefix string) *routerGroup { - return &routerGroup{ - prefix: prefix, - engine: e, - } -} - -func (rg *routerGroup) USE(middleware ...func(http.Handler) http.Handler) { - rg.middlewares = append(rg.middlewares, middleware...) -} - -func (rg *routerGroup) GET(path string, handler func(*Context)) { - rg.engine.router = append(rg.engine.router, router{path: rg.prefix + path, method: http.MethodGet, handler: handler, group: rg}) -} - -func (rg *routerGroup) POST(path string, handler func(*Context)) { - rg.engine.router = append(rg.engine.router, router{path: rg.prefix + path, method: http.MethodPost, handler: handler, group: rg}) + e.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + return + } + handler(&Context{W: w, R: r, E: e}) + }) } // Static serves static files from a specified directory, accessible through a defined URL path. @@ -159,9 +107,7 @@ func (e *Engine) Static(path, dir string) { } fs := http.FileServer(http.Dir(dir)) - e.GET(path, func(c *Context) { - http.StripPrefix(path, fs).ServeHTTP(c.W, c.R) - }) + e.mux.Handle(path, http.StripPrefix(path, fs)) slog.Info("Static files served", "path", path, "dir", dir) } diff --git a/ron_test.go b/ron_test.go index 7b25e30..05593f1 100644 --- a/ron_test.go +++ b/ron_test.go @@ -10,14 +10,14 @@ import ( func Test_defaultEngine(t *testing.T) { e := defaultEngine() if e == nil { - t.Error("Expected engine, Actual: nil") + t.Error("Expected Engine, Actual: nil") } } func Test_New(t *testing.T) { e := New() if e == nil { - t.Error("Expected engine, Actual: nil") + t.Error("Expected Engine, Actual: nil") } if e.Render != nil { t.Error("No expected Renderer, Actual: Renderer") @@ -88,96 +88,6 @@ func Test_POST(t *testing.T) { } } -func Test_USE(t *testing.T) { - e := New() - e.USE(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("MIDDLEWARE")) - next.ServeHTTP(w, r) - }) - }) - e.GET("/", func(c *Context) { - c.W.WriteHeader(http.StatusOK) - c.W.Write([]byte("GET")) - }) - - rr := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) - e.ServeHTTP(rr, req) - - if status := rr.Code; status != http.StatusOK { - t.Errorf("Expected status code: %d, Actual: %d", http.StatusOK, status) - } - - if rr.Body.String() != "MIDDLEWAREGET" { - t.Errorf("Expected: MIDDLEWAREGET, Actual: %s", rr.Body.String()) - } -} - -func Test_GROUP(t *testing.T) { - tests := []struct { - method string - path string - expectedCode int - expectedBody string - }{ - {"GET", "/group/", http.StatusOK, "GET"}, - {"POST", "/group/", http.StatusOK, "POST"}, - } - - e := New() - g := e.GROUP("/group") - g.GET("/", func(c *Context) { - c.W.WriteHeader(http.StatusOK) - c.W.Write([]byte("GET")) - }) - g.POST("/", func(c *Context) { - c.W.WriteHeader(http.StatusOK) - c.W.Write([]byte("POST")) - }) - - for _, tt := range tests { - rr := httptest.NewRecorder() - req, _ := http.NewRequest(tt.method, tt.path, nil) - e.ServeHTTP(rr, req) - - if status := rr.Code; status != tt.expectedCode { - t.Errorf("Expected status code: %d, Actual: %d", tt.expectedCode, status) - } - - if rr.Body.String() != tt.expectedBody { - t.Errorf("Expected: %s, Actual: %s", tt.expectedBody, rr.Body.String()) - } - } -} - -func Test_GROUPUSE(t *testing.T) { - e := New() - g := e.GROUP("/group") - g.USE(func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("MIDDLEWARE")) - next.ServeHTTP(w, r) - }) - }) - g.GET("/", func(c *Context) { - c.W.WriteHeader(http.StatusOK) - c.W.Write([]byte("GET")) - }) - - rr := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/group/", nil) - e.ServeHTTP(rr, req) - - if status := rr.Code; status != http.StatusOK { - t.Errorf("Expected status code: %d, Actual: %d", http.StatusOK, status) - } - - if rr.Body.String() != "MIDDLEWAREGET" { - t.Errorf("Expected: MIDDLEWAREGET, Actual: %s", rr.Body.String()) - } -} - func Test_Static(t *testing.T) { os.Mkdir("assets", os.ModePerm) f, _ := os.Create("assets/style.css")