{"id":16445853,"url":"https://github.com/mslinn/pfview","last_synced_at":"2025-10-27T05:32:04.000Z","repository":{"id":25909060,"uuid":"29349852","full_name":"mslinn/PFView","owner":"mslinn","description":"Drop-in replacement for Play Framework's Twirl","archived":true,"fork":false,"pushed_at":"2020-04-23T11:41:57.000Z","size":1700,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-10T02:13:26.684Z","etag":null,"topics":["play-framework","scala","template-language","twirl"],"latest_commit_sha":null,"homepage":"","language":"Scala","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/mslinn.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}},"created_at":"2015-01-16T13:37:47.000Z","updated_at":"2023-08-14T17:04:01.000Z","dependencies_parsed_at":"2022-08-24T06:20:29.420Z","dependency_job_id":null,"html_url":"https://github.com/mslinn/PFView","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2FPFView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2FPFView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2FPFView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mslinn%2FPFView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mslinn","download_url":"https://codeload.github.com/mslinn/PFView/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238445876,"owners_count":19473826,"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":["play-framework","scala","template-language","twirl"],"created_at":"2024-10-11T09:45:37.939Z","updated_at":"2025-10-27T05:31:58.720Z","avatar_url":"https://github.com/mslinn.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"![PFView logo](https://raw.githubusercontent.com/mslinn/PFView/master/images/pfview_355x148.png \"PFView Logo\")\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Build Status](https://travis-ci.org/mslinn/PFView.svg?branch=master)](https://travis-ci.org/mslinn/PFView)\n[ ![Download](https://api.bintray.com/packages/micronautics/play/pfview/images/download.svg) ](https://bintray.com/micronautics/play/pfview/_latestVersion)\n\nThis project is sponsored by [Micronautics Research Corporation](http://www.micronauticsresearch.com/),\nthe company that delivers online Scala and Play training via [ScalaCourses.com](http://www.ScalaCourses.com).\nYou can learn exactly how this project works by taking the [Introduction to Scala](http://www.ScalaCourses.com/showCourse/40),\n[Intermediate Scala](http://www.ScalaCourses.com/showCourse/45) and [Introduction to Play](http://www.ScalaCourses.com/showCourse/39) courses.\n\n`PFView` is a drop-in replacement for Play Framework's [Twirl template language](https://github.com/playframework/twirlhttps://github.com/playframework/twirl).\nTwirl is good for simple view templates because for simple pages, the HTML structure is left mostly intact.\nFor more complex pages, `PFView` is:\n\n * Simpler to write\n * Faster, because conversions between XML elements, `Html` and `String` can be eliminated. The job of a view is to generate a `String` that is sent to a client.\n * Testable\n * Debuggable\n * Optimizable, by defining portions as `lazy val`s which are evaluated only once instead of every time a page is parsed.\n * 100% Scala, so IDEs know how to refactor views defined by PFView\n\nThe job of a view is to work with data passed from a controller, as well as global state, and render output.\nNo business logic should exist in a view, however traversing data structures requires an expressive computing language.\n\n`PFView` was created to overcome `Twirl`'s shortcomings. Twirl:\n * Generates Scala code which is an unreadable mess, and is horrible to debug\n * Cannot be refactored by an IDE\n * Components must be stored in separate files, instead of merely defining a class or method\n * DSL is less expressive than Scala, and is not a successful functional language.\n * All of a web page's contents are created dynamically; no portion can be designated as being immutable\n\nAs a result, a non-trivial `Twirl` template becomes an unholy mess that is difficult to maintain.\n\nAs well, `Twirl` has an awkward syntax and limited capabilities compared to other view templating languages, such as ASP, JSP, JSP EL, etc.\nPFView is 100% Scala. It could be made to work to with Play for Java projects, but no work has been done to document how to do this.\n\nWhen Adobe Flex was popular, it was common to initially write view templates in [MXML](http://en.wikipedia.org/wiki/MXML),\nthen rewrite them in [ActionScript](http://en.wikipedia.org/wiki/ActionScript) as complexity increased.\nMXML is to Twirl as ActionScript is to PFView.\n\n## Installing ##\n\nAdd two lines to `build.sbt`.\n\n * Add the `pfview` dependency:\n````\n\"com.micronautics\" %% \"pfview\" % \"0.0.7\" withSources()\n````\n\n * Add this to the `resolvers`:\n````\n\"micronautics/play on bintray\" at \"http://dl.bintray.com/micronautics/play\"\n````\n\nThis library has been built against Scala 2.12.1 / Play 2.6.0-M4, Scala 2.11.8 / Play 2.5.14 and Scala 2.10.6 / Play 2.2.6.\n\n## Working with PFView ##\n### Creating an Instance ###\nCreate an `PFView` instance and invoke the `++` method to provide content to be appended to the PFView's instance's internal `StringBuilder` buffer.\nWhen the PFView instance has been created, it returns the contents of the buffer as a `String` \u0026ndash; just send that `String` to the web client.\nThat's all there is to it!\n\nThere are several ways of creating `PFView` instances. Examples of all of these are provided in the unit tests.\n\n 1) To define a Twirl-compatible dynamic view, define an injected `class` that accepts an instance of `Environment`.\n  Pass the `PFView` constructor the `Environment` instance.\n   The `class` would normally define a method called `apply` that returns `Html`.\n````\nimport javax.inject.Inject\nimport play.api.Environment\n\nclass dynamicView @Inject() (env: Environment) {\n  def apply(suffix: String): Html = new PFView(env) {\n    ++(s\"Feeling $suffix?\")\n  }.toHtml\n}\n````\nOf course, `apply` can be defined to have as many arguments and argument lists as required, including typical play signatures such as:\n\n    def apply(suffix: String)(implicit request: RequestHeader): Html\n\n 2) Define a method that creates an anonymous subclass of `PFView`, which is then implicitly converted to `String`.\n   This is useful for complex, dynamic content.\n\n````\nimport play.api.Environment\n\nval env: Environment = ???\n\ndef simple = new PFView(env) {\n  ++(\"simple\")\n}\n````\n\n 3) `PFView` instances can be recursively nested:\n````\nimport javax.inject.Inject\nimport play.api.Environment\n\nclass nestedViews @Inject() (env: Environment) {\n  def apply(msg: String=\"\") = new PFView(env) {\n    def repeatContent(msg: String): String = new PFView(env) {\n      ++(msg * 2)\n    }.toString\n\n    val repeatedContent = repeatContent(msg)\n    ++(repeatedContent)\n  }\n}\n````\n\n 4) To define a static view, define an `object` that extends `PFView`.\n This should only be done when assigning the result to a lazy val.\n````\nimport play.api.Environment\n\nval env: Environment = ???\n\nobject staticView extends PFView(env) {\n  ++(\"\u003ch1\u003eThis is a test\u003c/h1\u003e\")\n  ++{s\"\"\"\u003cp\u003eThe time is now ${new java.util.Date}\n        |This is another line\u003c/p\u003e\n        |${ unIf (6==9) { \"Somehow 6 equals 9\" } }\"\"\".stripMargin}\n}\n````\n\n### Methods ###\nThe following methods are provided by `PFView`:\n\n * `++` - appends content to the buffer\n * `If` - a convenience method for conditionally appending content to the buffer.\n`If (condition) { thenClause }` is equivalent to `if (condition) thenClause else \"\"`.\nThis method is useful within string interpolation. Unlike Twirl's `@if` expression, spaces can exist anywhere in an `If` expression.\n * `includeFile` - append the contents of a local file into the buffer; localized versions of files are searched for,\naccording to standard [i18n](http://en.wikipedia.org/wiki/Internationalization_and_localization) behavior using the value of the implicit\n[Lang](https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.i18n.Lang) parameter.\nFor example, if `filePath` is specified as `blah.html` and `lang` has the value `en-US` then the file `blah_en-US.html` is searched for,\nthen if not found `blah_en.html` is searched for and finally `blah.html` is searched for.\n````\nincludeFile(\"blah.html\")\n````\nYou can also specify the `lang` argument explicitly:\n````\nincludeFile(\"blah.html\")(Lang(\"fr\"))\n````\nBy default, files are searched for in the `public` directory. You can override this by specifying a value for `baseDir`; the value can be relative or absolute.\n````\nincludeFile(\"blah.html\", \"/var/tmp\")\n````\nalso:\n````\nincludeFile(\"blah.html\", \"/var/tmp\")(Lang(\"de\"))\n````\n * `includeUrl` - append the contents of the web page pointed to by a URL into the buffer.\nRelative URLs are not supported. The default [encoding](https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.mvc.Codec) is UTF-8.\nFor example, include this `README.md` file from its GitHub repo like this:\n````\nincludeUrl(\"https://raw.githubusercontent.com/mslinn/PFView/master/README.md\")\n````\nYou can specify an alternative encoding like this:\n````\nincludeUrl(\"https://raw.githubusercontent.com/mslinn/PFView/master/README.md\", \"iso-8859-1\")\n````\n\n## Scaladoc\n[Here](http://blog.mslinn.com/PFView/latest/api/views/index.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmslinn%2Fpfview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmslinn%2Fpfview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmslinn%2Fpfview/lists"}