Skip to content

Instantly share code, notes, and snippets.

@JimPanic
Last active December 25, 2015 10:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JimPanic/6959920 to your computer and use it in GitHub Desktop.
Save JimPanic/6959920 to your computer and use it in GitHub Desktop.
EnsureType .. enforced ducktyping in javascript
# Ensure given object implements methods and has properties according to the
# given interface.
#
# An interface may look as follows:
#
# DuckType = {
# getFoo: 'function', # Expect function foo
# setFoo: [ 'function', 3 ], # Expect function bar, taking at least 3 arguments
# bar: 'property',
# boo: [ 'property', 'string' ]
# }
EnsureType = (object, duck) ->
errors = []
unless typeof object in [ 'function', 'object' ]
errors.push "Given argument to test is not actually an object, but a #{typeof object}."
unless typeof duck is 'object'
errors.push "Given type to test the object against is not an object, but a #{typeof object}."
unless errors.length
property_names = Object.getOwnPropertyNames object
for name of duck
parameter = undefined
type = duck[name]
[type, parameter] = duck[name] if typeof duck[name] is 'object'
console.log name, type, parameter, typeof object[name]
if type == 'function'
unless name in property_names
errors.push function_not_implemented(object, name, parameter)
unless is_function object, name
errors.push function_wrong_type(object, name, parameter)
if parameter? and object[name].length != parameter
errors.push function_wrong_arguments(object, name, parameter)
if type == 'property'
unless name in property_names
errors.push property_not_implemented(object, name, parameter)
unless is_property object, name
errors.push property_wrong_type(object, name, parameter)
if parameter? and typeof object[name] isnt parameter
errors.push property_wrong_type(object, name, parameter)
if errors.length > 1
throw " - #{errors.join "\n - "}"
if errors.length > 0
throw errors[0]
object
is_function = (object, name) -> 'function' is typeof object[name]
function_not_implemented = (object, name, expected = null) ->
str = "Function '#{name}' is not implemented."
if expected?
str += " Expected a function taking at least #{expected} arguments."
str
function_wrong_type = (object, name, expected = null) ->
str = "Expected '#{name}' to be a function, but it is of type #{typeof object[name]}."
if expected?
str += " Expected a function taking at least #{expected} arguments."
str
function_wrong_arguments = (object, name, expected) ->
"Expected function '#{name}' to take at least #{expected} arguments, but it only takes #{object[name].length}."
is_property = (object, name) -> 'function' isnt typeof object[name]
property_not_implemented = (object, name, expected = null) ->
str = "Property '#{name}' is not present."
if expected?
str += "Expected it to hold a value of type #{expected}."
str
property_wrong_type = (object, name, expected = null) ->
str = "Expected '#{name}' to be a property"
if expected?
str += " holding a value of type #{expected}"
"#{str}, but it is of type #{typeof object[name]}."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment