disnet / contracts.coffee

Contracts for CoffeeScript
http://disnet.github.io/contracts.coffee/
MIT License
216 stars 6 forks source link

CoffeeScript classes supported? #26

Open TobiaszCudnik opened 12 years ago

TobiaszCudnik commented 12 years ago

Are CoffeeScript classes supported? I didn't have any luck while trying to put a contract on a class in various ways. Maybe i'm doing something wrong?

Contract for a whole class:

NodeAddr = ? {
    port: Num
    host: Str
}
Node :: (NodeAddr, Any, Any) -> {
    address: (NodeAddr) -> Any
}
Node = class
    constructor: (address, services, next) ->
    address: (addr) ->

Results in

TypeError: Object.getOwnPropertyDescriptor called on non-object
    at Function.getOwnPropertyDescriptor (native)
    at Object.getPropertyDescriptor (...node_modules/contracts.js/lib/contracts.js:410:23)
    at Contract.handler (...node_modules/contracts.js/lib/contracts.js:853:25)
    at Contract.check (...node_modules/contracts.js/lib/contracts.js:597:21)
    at ...node_modules/contracts.js/lib/contracts.js:742:29
    at <error: illegal access>
    at <error: illegal access>
    at Object.<anonymous> (...prototypes/contracts/foo.coffee:71:9)
    at Object.<anonymous> (...prototypes/contracts/foo.coffee:86:4)
    at Object.<anonymous> (...prototypes/contracts/foo.coffee:87:4)

Contract for a specific method:

NodeAddr = ? {
    port: Num
    host: Str
}
class Node
    constructor :: (NodeAddr, Any, Any) -> Any
    constructor: (address, services, next) -> yes
    address: (addr) ->

Results in "Error: In foo.coffee, Parse error on line 29: Unexpected 'OUTDENT'".

disnet commented 12 years ago

An unfortunate and glaring omission, we don't have explicit grammar support for putting contracts on classes yet. I really should have added them before, it's now at the top of my stack.

Interestingly enough, your first example of putting a whole contract on the class should have worked since Node compiles to a normal constructor and contracts work fine on them. Not sure yet what is causing the problem but I'll look into it.

TobiaszCudnik commented 12 years ago

Thats a pity as my app is OO and classes was first place where i wanted to put the contracts. I'll be looking forward for them.

Thanks for a great library and idea. It'll be really powerful once used.

BTW tested on node 0.7.0 and 0.5.10, same results.

TobiaszCudnik commented 12 years ago

After deeper checking there an issue with two things here:

  1. The -> wont work for classes, ==> need to be used.
  2. The following line:
address: (NodeAddr) -> Any

Changing NodeAddr to Any makes it all passing and class is initialized correctly.

disnet commented 12 years ago

Interesting...

  1. The -> wont work for classes, ==> need to be used.

This is definitely a bug. The ==> contract is supposed to restrict the function it is guarding to only be used with new but -> should work for both new and non-new calls.

TobiaszCudnik commented 12 years ago

I needed to use ==> because -> doens't trigger options.newSafe, thanks to which proxy returns new instance instead of a return value of the constructor.

Additionally, to have a class contracted fully, you have to do 2 things:

  1. Apply contract in the same file.
  2. Divide class contract to 2 custom ones: constructor and the instance body (object).
  3. Apply all instance body contracts onto the prototype, possibly using the following code:
# TServer is a contract
# Server is a class
for prop, Tcontr of TServer.oc
    continue if not Server::[prop] or
        prop is 'constructor'
    Server::[prop] :: Tcontr
    Server::[prop] = Server::[prop]
rimmington commented 11 years ago

Has there been any movement on this issue?

disnet commented 11 years ago

Sorry, no. Haven't had time to work on this project in a while.

benrudolph commented 10 years ago

+1 for this

DominikGuzei commented 9 years ago

:+1: for class suppport!