Last active
December 25, 2015 10:09
-
-
Save JimPanic/6959920 to your computer and use it in GitHub Desktop.
EnsureType .. enforced ducktyping in javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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