summaryrefslogtreecommitdiff
path: root/examples/scala-js/library/src/main/scala/scala/scalajs/js/Dictionary.scala
blob: fa68d08a7328d43cb6121e24086d8e0860645eed (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*                     __                                               *\
**     ________ ___   / /  ___      __ ____  Scala.js API               **
**    / __/ __// _ | / /  / _ | __ / // __/  (c) 2013, LAMP/EPFL        **
**  __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \    http://scala-lang.org/     **
** /____/\___/_/ |_/____/_/ | |__/ /____/                               **
**                          |/____/                                     **
\*                                                                      */


/**
 * All doc-comments marked as "MDN" are by Mozilla Contributors,
 * distributed under the Creative Commons Attribution-ShareAlike license from
 * https://developer.mozilla.org/en-US/docs/Web/Reference/API
 */
package scala.scalajs.js

import annotation.JSBracketAccess

/** Dictionary "view" of a JavaScript value.
 *
 *  Using objects as dictionaries (maps from strings to values) through their
 *  properties is a common idiom in JavaScript. This trait lets you treat an
 *  object as such a dictionary.
 *
 *  To use it, cast your object, say `x`, into a [[Dictionary]] using
 *  {{{
 *  val xDict = x.asInstanceOf[js.Dictionary[Int]]
 *  }}}
 *  then use it as
 *  {{{
 *  xDict("prop") = 5
 *  println(xDict("prop")) // displays 5
 *  xDict.delete("prop")   // removes the property "prop"
 *  println(xDict("prop")) // displays undefined
 *  }}}
 *
 *  To enumerate all the keys of a dictionary, use [[js.Object.keys]], which
 *  returns a [[js.Array]] of the properties. It can be used in a for
 *  comprehension like this:
 *  {{{
 *  for (prop <- js.Object.keys(xDict)) {
 *    val value = xDict(prop)
 *    println(prop + " -> " + value)
 *  }
 *  }}}
 */
sealed trait Dictionary[A] extends Object {
  /** Reads a field of this object by its name.
   *
   *  This will fail with a ClassCastException if the key doesn't exist and
   *  the return type doesn't allow js.undefined as value. If the return type
   *  does allow js.undefined, applying with a non-existent key will return
   *  js.undefined.
   */
  @JSBracketAccess
  def apply(key: String): A = native

  /** Reads a field of this object by its name.
   *
   *  This will return undefined if the key doesn't exist. It will also return
   *  undefined if the value associated with the key is undefined. To truly
   *  check for the existence of a property, use [[js.Object.hasOwnProperty]].
   */
  @JSBracketAccess
  def get(key: String): UndefOr[A] = native

  /** Writes a field of this object by its name. */
  @JSBracketAccess
  def update(key: String, value: A): Unit = native

  /** Deletes a property of this object by its name.
   *  The property must be configurable.
   *  This method is equivalent to the "delete" keyword in JavaScript.
   *
   *  Since we are using strict mode, this throws an exception, if the property
   *  isn't configurable.
   */
  def delete(key: String): Unit = sys.error("stub")
}

/** Factory for [[Dictionary]] instances. */
object Dictionary {
  /** Returns a new empty dictionary */
  def empty[A]: Dictionary[A] = (new Object).asInstanceOf[Dictionary[A]]

  def apply[A](properties: (String, A)*): Dictionary[A] = {
    val result = empty[A]
    for ((key, value) <- properties)
      result(key) = value
    result
  }
}