Skip to content

jasondelaat/enumerated_types

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Enumerated Types for Javascript

Full featured, extensible enumerations for javascript.

Getting Started

Installing

Node

npm install enumerated_types

Browser

Download the package from here.

The js folder contains two files: enumerated_types.js and enumerated_module.js.

To use enumerated_types.js load it from an HTML script tag:

<script type='text/javascript' src='/js/enumerated_types.js'></script>

To use enumerated_module.js import the required objects/functions:

import * as enumeration from '/js/enumerated_module.js'
import {Enum} from '/js/enumerated_module.js'

Usage

The enumeration package provides a base object, EnumerationBase, on which to base enumerated types.

The following methods are available on all enumerated types:

MethodDescriptionDefault Implementation
first()Returns the first value in the enumerationno
fromInt(i)Returns an enumeration given an integerno
isEqualTo(other)Tests two enumerations for equalityyes
isGreater(other)Test if one enumeration is greater than anotheryes
isGreaterOrEqualTo(other)Test if one enumeration is greater than or equal to anotheryes
isLess(other)Test if one enumeration is less than anotheryes
isLessOrEqualTo(other)Test if one enumeration is less than or equal to anotheryes
iterator(from, to)Gives an iterator between the (optional) given enumeration valuesyes
last()Returns the last value of the enumerationno
methods(methods_object)Adds additional methods to the enumerated typeyes
next()Returns the next enumeration value in the sequenceyes
previous()Returns the previous enumeration value in the sequenceyes
toInt()Converts an enumeration value to its integer representationno
toString()Converts an enumeration value to a string representationno

When creating your own enumerated types, the methods marks “no” under ‘Default Implementation’ must be implemented. All other methods may be overridden if required.

Enumerated constants with Enum

Use the Enum function to create a set of constants:

Color = Enum(
    'RED',
    'ORANGE',
    'YELLOW',
    'GREEN',
    'BLUE',
    'INDIGO',
    'VIOLET'
)

Constants can be converted to and from their interger equivalents:

Color.fromInt(3)    // Color.GREEN
Color.GREEN.toInt() // 3

And you can also get the string representation:

Color.RED.toString()    // 'RED'
Color.VIOLET.toString() // 'VIOLET'

This allows you to use the constants as if they were object keys.

someObj = {
    Color.RED : 'Something having to do with red.',
    Color.BLUE : 'Something to do with blue.',
}

In the above example the actual keys are the strings RED and BLUE because javascript calls toString() automatically when an object is used as a key.

You can navigate forwards and backwards through the sequence using next() and previous(). Going past the end of the sequence throws and error:

Color.RED.next()        // Color.ORANGE
Color.INDIGO.previous() // Color.BLUE
Color.RED.previous()    // Error!
Color.VIOLET.next()     // Error!

To get around that you can get an iterator() and loop through the values with a for loop or with forEach.

// Prints all the colors to the console.
for (let color of Color.iterator()) {
    ; console.log(color.toString()) 
}

// Also prints all the colors to the console.
Color.iterator().forEach(color => console.log(color.toString()))

The iterator() method takes two parameters from and to, both optional, so you can iterate though a subset of the values.

Color.iterator(Color.GREEN, Color.INDIGO)
    .forEach(color => console.log(color.toString()))

And can even be used to iterate though the values in reverse order if desired.

Color.iterator(Color.last(), Color.first())
    .forEach(color => console.log(color.toString()))

The constants can be compared in a number of ways.

Color.RED.isLess(Color.BLUE)                // true
Color.VIOLET.isLess(Color.BLUE)             // false
Color.VIOLET.isGreater(Color.BLUE)          // true
Color.VIOLET.isGreater(Color.VIOLET)        // false
Color.VIOLET.isGreaterOrEqual(Color.VIOLET) // true
Color.RED.isEqual(Color.GREEN)              // false
Color.RED.isEqual(Color.RED)                // true
Color.RED === Color.GREEN                   // false
Color.RED === Color.RED                     // true

Finally, the type can be extended with addtional methods:

Answers = Enum('YES', 'NO', 'MAYBE').methods({
    toLowerCase() {
	return this.toString().toLowerCase();
    },
    capitalize() {
	const as_string = this.toString();
	const first = as_string[0];
	const rest = as_string.substring(1).toLowerCase();
	return `${first}${rest}`;
    }
})

console.log(Answers.YES.toLowerCase());  // yes
console.log(Answers.Maybe.capitalize()); // Maybe

You can call methods at most once. After that the prototype object is frozen and can’t be modified further.

Enumerated constants with EnumObjects

The EnumObjects function works in much the same way as Enum but instead of a list of strings it takes an object as input. Each key becomes a constant and, unlike Enum each contant can have its own additional properties and methods.

   Animal = E.EnumObjects({
	  DOG : {
	      speak() {
		  console.log('woof!');
	      }
	  },
	  CAT : {
	      speak() {
		  console.log('meow!');
	      }
	  },
	  GIRAFFE : {}
   }).methods({
	  speak() {
	      console.log('...');
	  }
   })

   Animal.DOG.speak()     // woof!
   Animal.CAT.speak()     // meow!
   Animal.GIRAFFE.speak() // ...
   Animal.iterator().forEach(a => a.speak())

In particular, notice that we can use methods to define default methods which will apply to all constants that don’t specifically override it: DOG and CAT use their own behaviour while GIRAFFE uses the default.

Binary options with Flags

Flags are like enumerated constants except, instead of being sequential, each flag’s value is a power of 2.

Options = Flags('A', 'B', 'C', 'D')
Options.A.toInt() // 1
Options.B.toInt() // 2
Options.C.toInt() // 4
Options.D.toInt() // 8

This means you can combine multiple flags into a single integer value using the bitwise OR (|) operator:

Options.A | Options.B | Options.D;  // 11

Flag types have an additional method, listFromInt(), which returns a list of all options represented by a given integer.

Options.listFromInt(Options.A | Options.B | Options.D);  // [Options.A, Options.B, Options.D]
Options.listFromInt(12)                                  // [Options.C, Options.D]
Options.listFromInt(0)                                   // []
Options.listFromInt(16)                                  // Error! Out of range.

Constrained values with EnumeratedRange

Another type of enumeration are values constrained to a particular range: values between 1 and 10, for instance. In this case it’s actually the number we’re interested in not a symbolic name and there are, generally, too many possible values to create them as contants. Instead we can create an EnumeratedRange.

SmallNum = EnumeratedRange(1, 10, 'SmallNum')

The resulting value, SmallNum in this example, can then be used to construct values in this range. The third parameter is optional and is only relevant when calling toString(). Trying to create a value outside of the allowed range throws an error.

x = SmallNum(1)
y = SmallNum(5)
z = SmallNum(10)
error1 = SmallNum(0)  // Error!
error2 = SmallNum(11) // Error!

Even though the values don’t exist as constants you can still get an iterator over all the possible values:

// Prints all SmallNum values from 1 to 10
SmallNum.iterator().forEach(n => console.log(n))

About

Full featured, extensible enumerations for javascript.

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published