howl.util.moon.PropertyObject
allows specifying a getter and setter using get and set
value = 'hello'
class Test extends PropertyObject
  @property foo:
    get: => value
    set: (v) => value = v
o = Test!
assert.equal o.foo, 'hello'
o.foo = 'world'
assert.equal o.foo, 'world'
assigning a property with only a getter raises a read-only error
class Test extends PropertyObject
  @property foo: get: => 'foo'
o = Test!
assert.raises 'read%-only', -> o.foo = 'bar'
assert.equal o.foo, 'foo'
class Test extends PropertyObject
  @property foo: get: => 'foo'
assert.equal getmetatable(Test!), getmetatable(Test!)
class Test1 extends PropertyObject
  @property foo: get: => 'foo'
class Test2 extends PropertyObject
  @property foo: get: => 'foo'
assert.is_not.equal getmetatable(Test1!), getmetatable(Test2!)
class Test extends PropertyObject
  @meta __add: (o1, o2) -> 3 + o2
assert.equal 5, Test! + 2
inheritance
properties defined in any part of the chain works
class Parent extends PropertyObject
  new: (foo) =>
    super!
    @_foo = foo
  @property foo:
    get: => @_foo or 'wrong'
    set: (v) => @_foo = v .. @foo
class SubClass extends Parent
  new: (text) => super text
  @property bar:
    get: => @_bar
    set: (v) => @_bar = v
parent = Parent 'parent'
assert.equal parent.foo, 'parent'
parent.foo = 'hello '
assert.equal parent.foo, 'hello parent'
s = SubClass 'editor'
assert.equal s.foo, 'editor'
s.foo = 'hello'
assert.equal s.foo, 'helloeditor'
s.bar = 'world'
assert.equal s.bar, 'world'
overriding methods work
class Parent extends PropertyObject
  foo: => 'parent'
class SubClass extends Parent
  foo: => 'sub'
assert.equal SubClass!\foo!, 'sub'
write to read-only properties are detected
class Parent extends PropertyObject
  @property foo: get: => 1
class SubClass extends Parent
  true
assert.raises 'read%-only', -> SubClass!.foo = 'bar'
class Parent extends PropertyObject
  @meta __add: (o1, o2) -> 3 + o2
class SubClass extends Parent
  @meta __div: (o1, o2) -> 'div'
o = SubClass!
assert.equal 5, o + 2
assert.equal 'div', o / 2
 
delegation
allows delegating to a default object passed in the constructor
target = {
  foo: 'bar'
  func: spy.new -> 'return'
}
class Delegating extends PropertyObject
  new: => super target
  @property frob: get: => 'nic'
o = Delegating!
assert.equals 'nic',  o.frob
assert.equals 'bar',  o.foo
assert.equals 'return',  o\func!
assert.spy(target.func).was.called_with match.is_ref(target)