Giter Club home page Giter Club logo

scalasti's Introduction

Scalasti: A Scala interface to the Java StringTemplate Library

Build Status Maven Central

Introduction

This is Scalasti, a Scala interface to the StringTemplate Java template library.

Scalasti provides a (useful) subset of the StringTemplate API's features, with a more Scala-friendly syntax.

Scalasti's additional features include:

  • Immutability. As of version 3.0.0, Scalasti objects are immutable, unlike the StringTemplate objects. Modifier methods always create new objects; they never modify objects in place. Immutability is more functional and more idiomatic to Scala, and an immutable Scalasti API was long overdue.

  • Error-handling. Where possible, Scalasti propagates errors via scala.util.Try objects, instead of via a StringTemplate listener. This approach is also more idiomatic to Scala.

  • Scala object support. Scalasti supports Scala objects, meaning you don't have to use @BeanProperty on your Scala classes before you can pass them into a template. This feature also allows you to use instances of third-party Scala classes directly with Scalasti.

  • Stronger type safety. You should never need to cast objects you receive from the Scalast API.

  • Mapped aggregates provide the ability to add maps (which can be nested) as template attributes, which you can then deference within the template via dot-notation.

For complete information, see the Scalasti home page.

Copyright and license

Scalasti is copyright © 2010-2018 Brian M. Clapper and is released under a BSD license. See the accompanying license file for details.

scalasti's People

Contributors

bmc avatar jalaziz avatar sethtisue avatar xuwei-k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

scalasti's Issues

Print case class values from a List

Is it possible to access of getters of case classes while iterating through a list?

import org.clapper.scalasti.ST

case class Data(one:Int, two:Int)

object Test extends App{

  val templateString =
    """
      |<data.one>
      |<data.two>
      |-----------------------
      |<dataList:{data|<data.one>}>
      |-----------------------
      |<dataList:{data|<data>}>
    """.stripMargin

  val datalist =  List(Data(1,2),Data(1,2))

  val template = ST(templateString)
  template.add("data", datalist(0))
  template.add("dataList",datalist)

  println(template.render())
}

Output is

1
2
-----------------------
-----------------------
Data(1,2)Data(1,2)

Expected Output:

1
2
-----------------------
11
-----------------------
Data(1,2)Data(1,2)

Add support for accessing Scala fields

Scalasti should permit access to public Scala fields, via the generated accessors. For example, if an instance of the following case class were stuffed into a template:

case class Person(val firstName, val lastName)

it should be possible for a template to access the fields as:

$person.firstName$
$person.lastName$

This could be accomplished by generating a Java bean on the fly, much the way Scalasti's mapped aggregates are supported.

Nested Lists still not working

I tried following:

  case class Hobby(name:String)
  case class Person(name:String, hobbies:List[Hobby])

  val templateString =
    """
      |foo(people) ::= <<
      |<people:{person|<person.name>:  <person.hobbies:{hobby|<hobby.name>}>
      |}>
      |>>
    """.stripMargin

  val tgroup = STGroupString(templateString)
  tgroup.instanceOf("foo").map { template =>
    println( template.add ("people", List(Person("John",List(Hobby("swimming"))))).render())

  }
    .recover {
      case e: Exception => e.printStackTrace()// handle error
    }

with this I receive following exception:

Failure(java.lang.Exception: context [anonymous] 1:0 internal error: java.lang.Exception: context [anonymous /_sub5] 1:32 internal error: java.lang.Exception: context [anonymous /_sub5 /_sub6] 1:56 internal error: java.lang.Exception: context [anonymous /_sub5 /_sub6] 1:56 no such property or can't access: com.sun.proxy.$Proxy1.name
Caused by: org.stringtemplate.v4.misc.STNoSuchPropertyException: no such property: com.sun.proxy.$Proxy1.name

Switching back from List to Array results in the Problem that the case classes will also require @BeanProperties.

(sorry for the 'still' in the title, this may sound negative, which was not intended)

Problem with setAttribute and makeBeanAttribute

Attached code fails.

import org.clapper.scalasti.StringTemplate

object ScalastiBug {
  class SampleUser {
    var firstName:String = null
    var lastName:String = null

    override def toString = firstName + " " + lastName
  }

  def main(args: Array[String]) {
    val u1 = new SampleUser
    u1.firstName = "Elvis"
    u1.lastName = "Presley"

    val u2 = new SampleUser
    u2.firstName = "Frank"
    u2.lastName = "Sinatra"

    val users = u1 :: u2 :: Nil
    println(users.getClass)

    val t1 = "Hi $user.firstName$ $user.lastName$!"
    System.out.println("T1: " + new StringTemplate(t1).makeBeanAttribute("user", u1).toString())

    val t2 = """
    $users:{
       Hi $it.firstName$ $it.lastName$
     }$
    """

    System.out.println("Users: " + users)

    try_one("Test 1") {
      val st = new StringTemplate(t2)
      st.makeBeanAttribute("users", users: _*)
      System.out.println("T2: " + st.toString)
    }

    // try_one("Test 2") {
    //   val st = new StringTemplate(t2)
    //   st.setAttribute("users", users)
    //   System.out.println("T2: " + st.toString)
    // }
  }

  def try_one(label: String)(code: => Unit) {
    val prefix = ("*" * 10) + " " + label + ": "
    println()
    println(prefix + "Running")
    println()
    code
    println()
  }
}

Empty, notDefined attributes produces an exception

Hi,
I am using your wrapper and found a behavior that is strange to me. If I have an attribute in my template like $data$ or $data.name$ and I will not add this to ST with add I will get an exception like this:

Failure(java.lang.Exception: context [anonymous] 19:1 internal error: java.lang.Exception: context [anonymous] 19:1 attribute grussFormel isn't defined
	at org.clapper.scalasti.ThrowExceptionErrorListener.runTimeError(ThrowExceptionErrorListener.scala:14)
	at org.stringtemplate.v4.misc.ErrorManager.runTimeError(ErrorManager.java:133)
	at org.stringtemplate.v4.Interpreter._exec(Interpreter.java:193)
	at org.stringtemplate.v4.Interpreter.exec(Interpreter.java:145)
	at org.stringtemplate.v4.ST.write(ST.java:427)
	at org.stringtemplate.v4.ST.render(ST.java:497)
	at org.clapper.scalasti.ST.$anonfun$render$1(ST.scala:310)
	at scala.util.Try$.apply(Try.scala:209)
	at org.clapper.scalasti.ST.render(ST.scala:310)
	at AntlrTest.$anonfun$new$1(AntlrTest.scala:58)
	at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
	at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
	at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
	at org.scalatest.Transformer.apply(Transformer.scala:22)
	at org.scalatest.Transformer.apply(Transformer.scala:20)
	at org.scalatest.FlatSpecLike$$anon$1.apply(FlatSpecLike.scala:1682)
	at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
	at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
	at org.scalatest.FlatSpec.withFixture(FlatSpec.scala:1685)
	at org.scalatest.FlatSpecLike.invokeWithFixture$1(FlatSpecLike.scala:1680)
	at org.scalatest.FlatSpecLike.$anonfun$runTest$1(FlatSpecLike.scala:1692)
	at org.scalatest.SuperEngine.runTestImpl(Engine.scala:289)
	at org.scalatest.FlatSpecLike.runTest(FlatSpecLike.scala:1692)
	at org.scalatest.FlatSpecLike.runTest$(FlatSpecLike.scala:1674)
	at org.scalatest.FlatSpec.runTest(FlatSpec.scala:1685)
	at org.scalatest.FlatSpecLike.$anonfun$runTests$1(FlatSpecLike.scala:1750)
	at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:396)
	at scala.collection.immutable.List.foreach(List.scala:378)
	at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
	at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:373)
	at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:410)
	at scala.collection.immutable.List.foreach(List.scala:378)
	at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
	at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:379)
	at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:461)
	at org.scalatest.FlatSpecLike.runTests(FlatSpecLike.scala:1750)
	at org.scalatest.FlatSpecLike.runTests$(FlatSpecLike.scala:1749)
	at org.scalatest.FlatSpec.runTests(FlatSpec.scala:1685)
	at org.scalatest.Suite.run(Suite.scala:1147)
	at org.scalatest.Suite.run$(Suite.scala:1129)
	at org.scalatest.FlatSpec.org$scalatest$FlatSpecLike$$super$run(FlatSpec.scala:1685)
	at org.scalatest.FlatSpecLike.$anonfun$run$1(FlatSpecLike.scala:1795)
	at org.scalatest.SuperEngine.runImpl(Engine.scala:521)
	at org.scalatest.FlatSpecLike.run(FlatSpecLike.scala:1795)
	at org.scalatest.FlatSpecLike.run$(FlatSpecLike.scala:1793)
	at org.scalatest.FlatSpec.run(FlatSpec.scala:1685)
	at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45)
	at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13(Runner.scala:1340)
	at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13$adapted(Runner.scala:1334)
	at scala.collection.immutable.List.foreach(List.scala:378)
	at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1334)
	at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24(Runner.scala:1031)
	at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24$adapted(Runner.scala:1010)
	at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1500)
	at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:1010)
	at org.scalatest.tools.Runner$.run(Runner.scala:850)
	at org.scalatest.tools.Runner.run(Runner.scala)
	at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.runScalaTest2(ScalaTestRunner.java:138)
	at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.main(ScalaTestRunner.java:28)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
)

But I understand the normal behavior of StringTemplate to set it to an empty String.
Am I wrong with this meaning?

3.0.1 produces empty text

I tried to migrate to 3.0.1 , however I have now problems with the rendering.
Following Example produces an empty String:

scalaVersion := "2.11.8"

import org.clapper.scalasti.{STGroupFile, STGroupString}
...

  val templateString =
    """
      |foo(firstName, lastName) ::= <<
      |This is a test template. It spans multiple lines, and it interpolates
      |a first name (<firstName>) and a last name (<lastName>).
    """.stripMargin

  val tgroup = STGroupString(templateString)
  tgroup.instanceOf("foo").map { template =>
    template set ("firstName", "john")
    template set ("lasttName", "doe")
    println(template.render())
    println(template.render.get)
  }
    .recover {
      case e: Exception => // handle error
    }

Handle Option and nulls?

It seems that Scalasti doesn't apply treatment to Option or nulls.

Option results in Some(x) or None being printed and nulls result in scala.MatchError: null.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.