Name: jaqen
Owner: Twitter, Inc.
Owner: Twitter Archive
Description: A type-safe heterogenous Map or a Named field Tuple
Created: 2014-07-16 21:33:34.0
Updated: 2018-03-31 00:56:08.0
Pushed: 2014-11-08 02:27:37.0
Size: 500
Language: Scala
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
A type-safe heterogenous Map or a Named field Tuple depending how you look at it.
“Speak the names and a man will do the rest”
The build runs in Travis CI:
https://github.com/twitter/jaqen/blob/6661c711b20cf16c242e21e9c7f38ed198841016/jaqen-ntuple/src/main/scala/com/twitter/jaqen/ntuple/NTuple.scala#L11
t NTuple[T <: NTuple[T]] {
*
returns the field named 'key' with the proper type
if key does not exist, a compilation error will occur
@param key a literal or a Symbol
example:
<code>
val tuple = t('a -> 1, 'b -> "2")
tuple('a)
=> 1 (of type Int)
tuple('b)
=> "2" (of type String)
</code>
/
f get(key: Any) = macro applyImp[T]
* @see get */
f apply(key: Any) = macro applyImp[T]
*
adds a pair key -> value to the tuple
if key already exists, a compilation error will occur
key must be a literal or a symbol.
example: <code>
val tuple = t('a -> 1, 'b -> 2)
tuple + ('c -> 3)
=> t('a -> 1, 'b -> 2, 'c -> 3)
</code>
/
f add(pair: (Any, Any)) = macro plusImpl[T]
* @see add */
f +(pair: (Any, Any)) = macro plusImpl[T]
*
concats another NTuple to this one
if a key is defined in both tuples a compilation error will occur
<code>
val tuple1 = t('a -> 1, 'b -> 2)
val tuple2 = t('c -> 3, 'd -> 4)
tuple1 ++ tuple2
=> t('a -> 1, 'b -> 2, 'c -> 3, 'd -> 4)
</code>
/
f concat[T2 <: NTuple[T2]](t: T2) = macro plusplusImpl[T,T2]
* @see concat */
f ++[T2 <: NTuple[T2]](t: T2) = macro plusplusImpl[T,T2]
*
removes a key from the tuple
if key does not exist, a compilation error will occur
<code>
val tuple = t('a -> 1, 'b -> 2)
tuple - 'a
=> t('b -> 2)
</code>
/
f remove(key: Any) = macro minusImpl[T]
* @see remove */
f -(key: Any) = macro minusImpl[T]
*
takes a key -> value pair and replaces the existing key with the given value
if key does not exist, a compilation error will occur
example:
<code>
val tuple = t('a -> 1, 'b -> 2)
tuple -+ ('a -> 3)
=> t('a -> 3, 'b -> 2)
</code>
/
f replace(pair: (Any, Any)) = macro replaceImpl[T]
* @see replace */
f -+(pair: (Any, Any)) = macro replaceImpl[T]
*
prefixes all the key names with the given prefix.
useful to concatenate 2 tuples
example:
<code>
t('a -> 1, 'b -> 2).prefix("t")
=> t('ta -> 1, 'tb -> 2)
</code>
/
f prefix(prefix: String) = macro prefixImpl[T]
*
takes a pair (inputs -> output) and a function
inputs: a tuple of the keys of the values to pass to the function
output: the key to set with the result
@returns the resulting tuple with the output key set with the result of the function
example:
<code>
val tuple = t('a -> 1, 'b -> 2)
tuple.map(('a, 'b) -> 'c) { (a: Int, b: Int) => a + b }
=> t('a -> 1, 'b -> 2, 'c -> 3)
</code>
/
f map(pair: Any)(f: Any) = macro mapImpl[T]
*
@returns a string representation of this tuple
example:
<code>
t('a -> 1, 'b -> 2).mkString
(a -> 1, b -> 2)
</code>
/
f mkString = macro mkStringImpl[T]
*
converts this tuple to a Map.
@returns an immutable Map
/
f toMap = macro toMapImpl[T]
ct NTuple {
*
creates a new NTuple from a list of key -> value pairs
the types of the values are preserved and will be returned accordingly when apply is called
if a key is defined twice a compilation error will occur
<code>
val tuple1 = t('a -> 1, 'b -> "2")
</code>
/
f t(pairs: Any*) = macro newTupleImpl
plicit def nTupleToString[T <: NTuple[T]](ntuple: T): String = macro nTupleToStringImpl[T]
plicit def listOfNTupleToRichList[T <: NTuple[T]](list: List[T]) = RichList[T](list)
clean compile
a -classpath jaqen-ntuple/target/classes
Examples:
rt com.twitter.jaqen.ntuple.NTuple._
foo = "FOO"
bar = 3
aps
map = Map("a" -> foo, "b" -> bar)
+ ("d" -> 3f)
ma: String = map("a")
mb: Int = map("b")
"c")
- "a"
uples
tuple1 = (foo, bar)
tuple1a: String = tuple1._1
tuple1b: Int = tuple1._2
r
(tuple1a, tuple1b) = tuple1
uple with named fields!
t1 = t('a -> foo, 'b -> bar)
kString
t1a: String = t1('a)
t1b: Int = t1('b)
c) // error: t1 does not contain key: "c"
- 'b).mkString
t2 = t1 + ('c -> 2)
('c -> 3) // error: t2 already contains key c
-+ ('c -> 3)).mkString
lso a tuple
1
2
(t1a, t1b) = t1.toTuple
oMap
empty = t()
notempty = empty + ("A" -> foo)
mpty("A")
class Person(val name: String, val age: Int)
input = List(Person("John", 10), Person("Jack", 5))
class PersonBirthYear(val name: String, val birthYear: Int)
t.map((in) => PersonBirthYear(in.name, 2014 - in.age)).filter(_.birthYear > 2005).map(_.name)
t.map((in) => (in.name, 2014 - in.age)).filter{ case (_, birthYear) => birthYear > 2005 }.map { case (name, _) => name }
t.map((in) => t('name -> in.name, 'birthYear -> (2014 - in.age))).filter(_('birthYear) > 2005).map(_('name))
Result:
a> com.twitter.jaqen.ntuple.NTuple._
rt com.twitter.jaqen.ntuple.NTuple._
a>
a> val foo = "FOO"
String = FOO
a> val bar = 3
Int = 3
a>
a> // maps
a> val map = Map("a" -> foo, "b" -> bar)
scala.collection.immutable.Map[String,Any] = Map(a -> FOO, b -> 3)
a> map + ("d" -> 3f)
: scala.collection.immutable.Map[String,Any] = Map(a -> FOO, b -> 3, d -> 3.0)
a> val ma: String = map("a")
sole>:13: error: type mismatch;
nd : Any
uired: String
val ma: String = map("a")
^
a> val mb: Int = map("b")
sole>:13: error: type mismatch;
nd : Any
uired: Int
val mb: Int = map("b")
^
a> map("c")
.util.NoSuchElementException: key not found: c
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:58)
at scala.collection.MapLike$class.apply(MapLike.scala:141)
at scala.collection.AbstractMap.apply(Map.scala:58)
at .<init>(<console>:14)
at .<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983)
at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568)
at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:756)
at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:801)
at scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:713)
at scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:577)
at scala.tools.nsc.interpreter.ILoop.innerLoop$1(ILoop.scala:584)
at scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:587)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply$mcZ$sp(ILoop.scala:878)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833)
at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833)
at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
at scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:833)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
a> map - "a"
: scala.collection.immutable.Map[String,Any] = Map(b -> 3)
a>
a> // tuples
a> val tuple1 = (foo, bar)
e1: (String, Int) = (FOO,3)
a>
a> val tuple1a: String = tuple1._1
e1a: String = FOO
a> val tuple1b: Int = tuple1._2
e1b: Int = 3
a> // or
a> val (tuple1a, tuple1b) = tuple1
e1a: String = FOO
e1b: Int = 3
a>
| // tuple with named fields!
a> val t1 = t('a -> foo, 'b -> bar)
com.twitter.jaqen.ntuple.NTuple2[String("a"),String,String("b"),Int] = (FOO,3)
a> t1.mkString
: String = (a -> FOO, b -> 3)
a> val t1a: String = t1('a)
String = FOO
a> val t1b: Int = t1('b)
Int = 3
a> t1('c) // error: t1 does not contain key: "c"
sole>:14: error: t1 does not contain key c
t1('c) // error: t1 does not contain key: "c"
^
a> (t1 - 'b).mkString
: String = (a -> FOO)
a> val t2 = t1 + ('c -> 2)
com.twitter.jaqen.ntuple.NTuple3[String("a"),String,String("b"),Int,String("c"),Int(2)] = (FOO,3,2)
a> t2 + ('c -> 3) // error: t2 already contains key c
sole>:15: error: t2 already contains key c
t2 + ('c -> 3) // error: t2 already contains key c
^
a> (t2 -+ ('c -> 3)).mkString
: String = (a -> FOO, b -> 3, c -> 3)
a> // also a tuple
a> t1._1
: String = FOO
a> t1._2
0: Int = 3
a> val (t1a, t1b) = t1.toTuple
String = FOO
Int = 3
a> t1.toMap
1: scala.collection.immutable.Map[Any,Any] = Map(a -> FOO, b -> 3)
a>
a> val empty = t()
y: ntuple.NTuple0 = ()
a> val notempty = empty + ("A" -> foo)
mpty: com.twitter.jaqen.ntuple.NTuple1[String("A"),String] = FOO
a> notempty("A")
2: String = FOO
a>
a> case class Person(val name: String, val age: Int)
ned class Person
a> val input = List(Person("John", 10), Person("Jack", 5))
t: List[Person] = List(Person(John,10), Person(Jack,5))
a>
a> case class PersonBirthYear(val name: String, val birthYear: Int)
ned class PersonBirthYear
a> input.map((in) => PersonBirthYear(in.name, 2014 - in.age)).filter(_.birthYear > 2005).map(_.name)
3: List[String] = List(Jack)
a>
a> input.map((in) => (in.name, 2014 - in.age)).filter{ case (_, birthYear) => birthYear > 2005 }.map { case (name, _) => name }
4: List[String] = List(Jack)
a>
a> input.map((in) => t('name -> in.name, 'birthYear -> (2014 - in.age))).filter(_('birthYear) > 2005).map(_('name))
5: List[String] = List(Jack)