{"id":13472132,"url":"https://github.com/gobuffalo/plush","last_synced_at":"2025-05-13T20:22:31.446Z","repository":{"id":18430291,"uuid":"83604525","full_name":"gobuffalo/plush","owner":"gobuffalo","description":"The powerful template system that Go needs","archived":false,"fork":false,"pushed_at":"2025-04-17T16:03:26.000Z","size":536,"stargazers_count":948,"open_issues_count":3,"forks_count":57,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-04-28T11:56:42.675Z","etag":null,"topics":["go","gobuffalo","golang","plush","templating"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gobuffalo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"markbates","patreon":"buffalo"}},"created_at":"2017-03-01T21:40:32.000Z","updated_at":"2025-04-24T10:51:42.000Z","dependencies_parsed_at":"2024-06-18T12:17:29.637Z","dependency_job_id":"5d7a8b26-a6ae-4019-8279-e0cf7fb7839d","html_url":"https://github.com/gobuffalo/plush","commit_stats":{"total_commits":290,"total_committers":24,"mean_commits":"12.083333333333334","dds":"0.44482758620689655","last_synced_commit":"f6aa62427ac64da25082b2bca8bd8748403a8d4a"},"previous_names":[],"tags_count":94,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobuffalo%2Fplush","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobuffalo%2Fplush/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobuffalo%2Fplush/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gobuffalo%2Fplush/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gobuffalo","download_url":"https://codeload.github.com/gobuffalo/plush/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251311332,"owners_count":21569008,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","gobuffalo","golang","plush","templating"],"created_at":"2024-07-31T16:00:52.191Z","updated_at":"2025-04-28T11:56:49.038Z","avatar_url":"https://github.com/gobuffalo.png","language":"Go","funding_links":["https://github.com/sponsors/markbates","https://patreon.com/buffalo"],"categories":["开源类库","Go","HTML template engines","Open source library"],"sub_categories":["模板引擎","Template Engine"],"readme":"# Plush\n\n[![Standard Test](https://github.com/gobuffalo/plush/actions/workflows/standard-go-test.yml/badge.svg)](https://github.com/gobuffalo/plush/actions/workflows/standard-go-test.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/gobuffalo/plush/v5.svg)](https://pkg.go.dev/github.com/gobuffalo/plush/v5)\n\nPlush is the templating system that [Go](http://golang.org) both needs _and_ deserves. Powerful, flexible, and extendable, Plush is there to make writing your templates that much easier.\n\n**[Introduction Video](https://blog.gobuffalo.io/introduction-to-plush-82a8a12cf98a#.y9t0g4xq2)**\n\n## Installation\n\n```text\n$ go get -u github.com/gobuffalo/plush\n```\n\n## Usage\n\nPlush allows for the embedding of dynamic code inside of your templates. Take the following example:\n\n```erb\n\u003c!-- input --\u003e\n\u003cp\u003e\u003c%= \"plush is great\" %\u003e\u003c/p\u003e\n\n\u003c!-- output --\u003e\n\u003cp\u003eplush is great\u003c/p\u003e\n```\n\n### Controlling Output\n\nBy using the `\u003c%= %\u003e` tags we tell Plush to dynamically render the inner content, in this case the string `plush is great`, into the template between the `\u003cp\u003e\u003c/p\u003e` tags.\n\nIf we were to change the example to use `\u003c% %\u003e` tags instead the inner content will be evaluated and executed, but not injected into the template:\n\n```erb\n\u003c!-- input --\u003e\n\u003cp\u003e\u003c% \"plush is great\" %\u003e\u003c/p\u003e\n\n\u003c!-- output --\u003e\n\u003cp\u003e\u003c/p\u003e\n```\n\nBy using the `\u003c% %\u003e` tags we can create variables (and functions!) inside of templates to use later:\n\n```erb\n\u003c!-- does not print output --\u003e\n\u003c%\nlet h = {name: \"mark\"}\nlet greet = fn(n) {\n  return \"hi \" + n\n}\n%\u003e\n\u003c!-- prints output --\u003e\n\u003ch1\u003e\u003c%= greet(h[\"name\"]) %\u003e\u003c/h1\u003e\n```\n\n#### Full Example:\n\n```go\nhtml := `\u003chtml\u003e\n\u003c%= if (names \u0026\u0026 len(names) \u003e 0) { %\u003e\n\t\u003cul\u003e\n\t\t\u003c%= for (n) in names { %\u003e\n\t\t\t\u003cli\u003e\u003c%= capitalize(n) %\u003e\u003c/li\u003e\n\t\t\u003c% } %\u003e\n\t\u003c/ul\u003e\n\u003c% } else { %\u003e\n\t\u003ch1\u003eSorry, no names. :(\u003c/h1\u003e\n\u003c% } %\u003e\n\u003c/html\u003e`\n\nctx := plush.NewContext()\nctx.Set(\"names\", []string{\"john\", \"paul\", \"george\", \"ringo\"})\n\ns, err := plush.Render(html, ctx)\nif err != nil {\n  log.Fatal(err)\n}\n\nfmt.Print(s)\n// output: \u003chtml\u003e\n// \u003cul\u003e\n// \t\t\u003cli\u003eJohn\u003c/li\u003e\n// \t\t\u003cli\u003ePaul\u003c/li\u003e\n// \t\t\u003cli\u003eGeorge\u003c/li\u003e\n// \t\t\u003cli\u003eRingo\u003c/li\u003e\n// \t\t\u003c/ul\u003e\n// \u003c/html\u003e\n```\n## Comments\n\nYou can add comments like this:\n\n```erb\n\u003c%# This is a comment %\u003e\n```\n\nYou can also add line comments within a code section\n\n```erb\n\u003c%\n# this is a comment\nnot_a_comment()\n%\u003e\n```\n\n## If/Else Statements\n\nThe basic syntax of `if/else if/else` statements is as follows:\n\n```erb\n\u003c%\nif (true) {\n  # do something\n} else if (false) {\n  # do something\n} else {\n  # do something else\n}\n%\u003e\n```\n\nWhen using `if/else` statements to control output, remember to use the `\u003c%= %\u003e` tag to output the result of the statement:\n\n```erb\n\u003c%= if (true) { %\u003e\n  \u003c!-- some html here --\u003e\n\u003c% } else { %\u003e\n  \u003c!-- some other html here --\u003e\n\u003c% } %\u003e\n```\n\n### Operators\n\nComplex `if` statements can be built in Plush using \"common\" operators:\n\n* `==` - checks equality of two expressions\n* `!=` - checks that the two expressions are not equal\n* `~=` - checks a string against a regular expression (`foo ~= \"^fo\"`)\n* `\u003c` - checks the left expression is less than the right expression\n* `\u003c=` - checks the left expression is less than or equal to the right expression\n* `\u003e` - checks the left expression is greater than the right expression\n* `\u003e=` - checks the left expression is greater than or equal to the right expression\n* `\u0026\u0026` - requires both the left **and** right expression to be true\n* `||` - requires either the left **or** right expression to be true\n\n### Grouped Expressions\n\n```erb\n\u003c%= if ((1 \u003c 2) \u0026\u0026 (someFunc() == \"hi\")) { %\u003e\n  \u003c!-- some html here --\u003e\n\u003c% } else { %\u003e\n  \u003c!-- some other html here --\u003e\n\u003c% } %\u003e\n```\n\n## Maps\n\nMaps in Plush will get translated to the Go type `map[string]interface{}` when used. Creating, and using maps in Plush is not too different than in JSON:\n\n```erb\n\u003c% let h = {key: \"value\", \"a number\": 1, bool: true} %\u003e\n```\n\nWould become the following in Go:\n\n```go\nmap[string]interface{}{\n  \"key\": \"value\",\n  \"a number\": 1,\n  \"bool\": true,\n}\n```\n\nAccessing maps is just like access a JSON object:\n\n```erb\n\u003c%= h[\"key\"] %\u003e\n```\n\nUsing maps as options to functions in Plush is incredibly powerful. See the sections on Functions and Helpers to see more examples.\n\n## Arrays\n\nArrays in Plush will get translated to the Go type `[]interface{}` when used.\n\n```erb\n\u003c% let a = [1, 2, \"three\", \"four\", h] %\u003e\n```\n\n```go\n[]interface{}{ 1, 2, \"three\", \"four\", h }\n```\n\nArrays in plush can be appended using the following format:\n\n```erb\n\u003c% let a = [1, 2, \"three\", \"four\", h] %\u003e \u003c% a = a + \"hello world\"%\u003e\n```\n\nIf the array passed to plush is not of type `[]interface{}` and an attempt is made to append a value with a data type that does not match the underlying array type, an error will be returned. \n\n## For Loops\n\nThere are three different types that can be looped over: maps, arrays/slices, and iterators. The format for them all looks the same:\n\n```erb\n\u003c%= for (key, value) in expression { %\u003e\n  \u003c%= key %\u003e \u003c%= value %\u003e\n\u003c% } %\u003e\n```\n\nYou can also  `continue` to the next iteration of the loop:\n```erb\nfor (i,v) in [1, 2, 3,4,5,6,7,8,9,10] {\n  if (i \u003e 0) {\n    continue\n  }\n  return v\n}\n```\n\nYou can terminate the for loop with `break`:\n```erb\nfor (i,v) in [1, 2, 3,4,5,6,7,8,9,10] {\n  if (i \u003e 5) {\n    break\n  }\n  return v\n}\n```\n\nThe values inside the `()` part of the statement are the names you wish to give to the key (or index) and the value of the expression. The `expression` can be an array, map, or iterator type.\n\n### Arrays\n\n#### Using Index and Value\n\n```erb\n\u003c%= for (i, x) in someArray { %\u003e\n  \u003c%= i %\u003e \u003c%= x %\u003e\n\u003c% } %\u003e\n```\n\n#### Using Just the Value\n\n```erb\n\u003c%= for (val) in someArray { %\u003e\n  \u003c%= val %\u003e\n\u003c% } %\u003e\n```\n\n### Maps\n\n#### Using Index and Value\n\n```erb\n\u003c%= for (k, v) in someMap { %\u003e\n  \u003c%= k %\u003e \u003c%= v %\u003e\n\u003c% } %\u003e\n```\n\n#### Using Just the Value\n\n```erb\n\u003c%= for (v) in someMap { %\u003e\n  \u003c%= v %\u003e\n\u003c% } %\u003e\n```\n\n### Iterators\n\n```go\ntype ranger struct {\n\tpos int\n\tend int\n}\n\nfunc (r *ranger) Next() interface{} {\n\tif r.pos \u003c r.end {\n\t\tr.pos++\n\t\treturn r.pos\n\t}\n\treturn nil\n}\n\nfunc betweenHelper(a, b int) Iterator {\n\treturn \u0026ranger{pos: a, end: b - 1}\n}\n```\n\n```go\nhtml := `\u003c%= for (v) in between(3,6) { return v } %\u003e`\n\nctx := plush.NewContext()\nctx.Set(\"between\", betweenHelper)\n\ns, err := plush.Render(html, ctx)\nif err != nil {\n  log.Fatal(err)\n}\nfmt.Print(s)\n// output: 45\n```\n\n## Default helpers\n\nPlush ships with a comprehensive list of helpers to make your life easier. For more info check the helpers package.\n\n### Custom Helpers\n\n```go\nhtml := `\u003cp\u003e\u003c%= one() %\u003e\u003c/p\u003e\n\u003cp\u003e\u003c%= greet(\"mark\")%\u003e\u003c/p\u003e\n\u003c%= can(\"update\") { %\u003e\n\u003cp\u003ei can update\u003c/p\u003e\n\u003c% } %\u003e\n\u003c%= can(\"destroy\") { %\u003e\n\u003cp\u003ei can destroy\u003c/p\u003e\n\u003c% } %\u003e\n`\n\nctx := NewContext()\n\n// one() #=\u003e 1\nctx.Set(\"one\", func() int {\n  return 1\n})\n\n// greet(\"mark\") #=\u003e \"Hi mark\"\nctx.Set(\"greet\", func(s string) string {\n  return fmt.Sprintf(\"Hi %s\", s)\n})\n\n// can(\"update\") #=\u003e returns the block associated with it\n// can(\"adsf\") #=\u003e \"\"\nctx.Set(\"can\", func(s string, help HelperContext) (template.HTML, error) {\n  if s == \"update\" {\n    h, err := help.Block()\n    return template.HTML(h), err\n  }\n  return \"\", nil\n})\n\ns, err := Render(html, ctx)\nif err != nil {\n  log.Fatal(err)\n}\nfmt.Print(s)\n// output: \u003cp\u003e1\u003c/p\u003e\n// \u003cp\u003eHi mark\u003c/p\u003e\n// \u003cp\u003ei can update\u003c/p\u003e\n```\n\n### Special Thanks\n\nThis package absolutely 100% could not have been written without the help of Thorsten Ball's incredible book, [Writing an Interpreter in Go](https://interpreterbook.com).\n\nNot only did the book make understanding the process of writing lexers, parsers, and asts, but it also provided the basis for the syntax of Plush itself.\n\nIf you have yet to read Thorsten's book, I can't recommend it enough. Please go and buy it!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgobuffalo%2Fplush","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgobuffalo%2Fplush","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgobuffalo%2Fplush/lists"}