class Role
constructor: (spec, entityInterface)->
@validateSpec(spec)
@spec = spec
## dci forked from https://github.com/brokenseal/eunomia/blob/master/src/eunomia.coffee version 0.0.1
Data, Context, Interaction (DCI)
see http://en.wikipedia.org/wiki/Data,_context_and_interaction http://www.artima.com/articles/dci_vision.html https://dzone.com/articles/implementing-dci-qi4j http://www.amazon.ca/Lean-Architecture-Agile-Software-Development/dp/0470684208/ https://github.com/amolenaar/roles/blob/master/example.py https://github.com/shamus/javascript-dci/blob/master/examples/frontloading.js
##
class Role
constructor: (spec, entityInterface)->
@validateSpec(spec)
@spec = spec
entityInterface is a non mandatory interface to which entities need to comply to
@entityInterface = entityInterface
validateSpec: (spec)->
a spec represents the role’s methods, need to contain only methods and no state
for name of spec
if not (spec[name] instanceof Function)
throw new Error('Given spec is not accepted')
validateInterfaceAgainst: (entity)->
if @entityInterface
check that the given entity complies to the previously given interface
for name of @entityInterface
obj = entity[name]
klass = @entityInterface[name]
if obj instanceof klass or toString.call(obj) is "[object " + klass.name + "]"
continue
throw new Error("Given entity does not comply to the role's needed interface,
attribute missing: `" + name + "` of type " + @entityInterface[name])
applyTo: (entity)->
@validateInterfaceAgainst(entity)
return new Actor(@, entity)
class Actor
An actor is a role proxy, it exposes the same interface as the role specification but will apply its methods to the given entity. This way, the original entity object is left pristine and can easily impersonate other roles at the same time without other roles interfering with each other.
constructor: (role, entity)->
@entity = entity
@role = role
for name of @role.spec
@[name] = @role.spec[name].bind(@entity)
useCaseFactory = (roles, method)->
return (entities)->
create the actors the use case will manage
actors = {}
for name of entities
actors[name] = roles[name].applyTo(entities[name])
return method.call(null, actors)
(exports ? this).context = (roles, useCases, formurlaManager)->
validate roles
for name of roles
if not (roles[name] instanceof Role)
throw new Error("Roles can only be instances of Role")
if Object.keys(useCases).length is 0
throw new Error('Context must be able to enact at least one use case')
if formurlaManager?
roles.formurlaManager = new Role
get: () -> @ # the intention is to return the formurlaManager itself
getNoodb: () -> @noodb # the intention is to return the formurlaManager itself
getRootPanel: () -> @rootPanel
useCasesProxies = {}
for name of useCases
useCasesProxies[name] = useCaseFactory(roles, useCases[name])
return useCasesProxies
(exports ? this).role = (roleSpec, entityInterface)->
return new Role(roleSpec, entityInterface)