<commit_before>package gremlin.scala

import scala.collection.JavaConversions._
import shapeless._

trait ScalaElement[ElementType <: Element] {
  def element: ElementType

  def graph: ScalaGraph = element.graph

  def start(): GremlinScala[ElementType, HNil]

  def id[A: DefaultsToAny]: A = element.id.asInstanceOf[A]

  def label: String = element.label

  def keys: Set[Key[Any]] = element.keys.toSet.map(Key.apply[Any])

  def setProperty[A](key: Key[A], value: A): ElementType

  def removeProperty(key: Key[_]): ElementType

  def removeProperties(keys: Key[_]*): ElementType

  def property[A](key: Key[A]): Property[A] = element.property[A](key.value)

  def properties[A: DefaultsToAny]: Stream[Property[A]]

  def properties[A: DefaultsToAny](keys: String*): Stream[Property[A]]

  // note: this may throw an IllegalStateException - better use `valueOption` or `Property`
  def value[A: DefaultsToAny](key: String): A =
    element.value[A](key)

  // typesafe version of `value. have to call it `value2` because of a scala compiler bug :(
  // https://issues.scala-lang.org/browse/SI-9523
  def value2[A](key: Key[A]): A =
    element.value[A](key.value)

  def valueOption[A: DefaultsToAny](key: String): Option[A] =
    element.property[A](key).toOption

  def valueOption[A](key: Key[A]): Option[A] =
    element.property[A](key.value).toOption

  // note: this may throw an IllegalStateException - better use `Property`
  def values[A: DefaultsToAny](keys: String*): Iterator[A] =
    element.values[A](keys: _*)

  def valueMap[A: DefaultsToAny]: Map[String, A] = valueMap[A](keys.toSeq.map(_.value): _*)

  def valueMap[A: DefaultsToAny](keys: String*): Map[String, A] =
    (properties[A](keys: _*) map (p ⇒ (p.key, p.value))).toMap

  def toCC[CC <: Product: Marshallable]: CC

  def updateWith[CC <: Product: Marshallable](update: CC): ElementType = {
    val propMap = implicitly[Marshallable[CC]].fromCC(update).valueMap
    propMap foreach {case (prop, value) => element.property(prop, value)}

    element
  }

  def updateAs[CC <: Product: Marshallable](f: CC => CC): ElementType = updateWith(f(toCC[CC]))

}
<commit_msg>[Issue #166] Make ScalaElement.updateWith(x) remove properties which are None in x<commit_after>package gremlin.scala

import scala.collection.JavaConversions._
import shapeless._

trait ScalaElement[ElementType <: Element] {
  def element: ElementType

  def graph: ScalaGraph = element.graph

  def start(): GremlinScala[ElementType, HNil]

  def id[A: DefaultsToAny]: A = element.id.asInstanceOf[A]

  def label: String = element.label

  def keys: Set[Key[Any]] = element.keys.toSet.map(Key.apply[Any])

  def setProperty[A](key: Key[A], value: A): ElementType

  def removeProperty(key: Key[_]): ElementType

  def removeProperties(keys: Key[_]*): ElementType

  def property[A](key: Key[A]): Property[A] = element.property[A](key.value)

  def properties[A: DefaultsToAny]: Stream[Property[A]]

  def properties[A: DefaultsToAny](keys: String*): Stream[Property[A]]

  // note: this may throw an IllegalStateException - better use `valueOption` or `Property`
  def value[A: DefaultsToAny](key: String): A =
    element.value[A](key)

  // typesafe version of `value. have to call it `value2` because of a scala compiler bug :(
  // https://issues.scala-lang.org/browse/SI-9523
  def value2[A](key: Key[A]): A =
    element.value[A](key.value)

  def valueOption[A: DefaultsToAny](key: String): Option[A] =
    element.property[A](key).toOption

  def valueOption[A](key: Key[A]): Option[A] =
    element.property[A](key.value).toOption

  // note: this may throw an IllegalStateException - better use `Property`
  def values[A: DefaultsToAny](keys: String*): Iterator[A] =
    element.values[A](keys: _*)

  def valueMap[A: DefaultsToAny]: Map[String, A] = valueMap[A](keys.toSeq.map(_.value): _*)

  def valueMap[A: DefaultsToAny](keys: String*): Map[String, A] =
    (properties[A](keys: _*) map (p ⇒ (p.key, p.value))).toMap

  def toCC[CC <: Product: Marshallable]: CC

  def updateWith[CC <: Product: Marshallable](update: CC): ElementType = {
    val propMap = implicitly[Marshallable[CC]].fromCC(update).valueMap
    this.valueMap.keySet.diff(propMap.keySet) foreach { key =>
      val prop = element.property(key)
      if (prop.isPresent) prop.remove()
    }
    propMap foreach {case (key, value) => element.property(key, value)}

    element
  }

  def updateAs[CC <: Product: Marshallable](f: CC => CC): ElementType = updateWith(f(toCC[CC]))

}

{'fraction_non_alphanumeric': 0.15074262912879627, 'fraction_numerical': 0.0033252050543116827, 'mean_word_length': 4.6259351620947635, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 8, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '255848', 'n_tokens_mistral': 1576, 'n_tokens_neox': 1501, 'n_words': 365}