Skip to content

Commit

Permalink
Simplified presenters
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Evans committed Mar 27, 2012
1 parent bee1110 commit c32982b
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 51 deletions.
39 changes: 18 additions & 21 deletions src/presenter.coffee
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
class egg.Presenter extends egg.Base

@init (opts)->
@presentedItems = opts.present || throw("#{@constructor.name} needs a 'present' option")
@createReaderMethods()
@objects = opts.objects || throw("#{@constructor.name} needs an 'objects' option")
@onFirstSubscribe ->
for name, item of @presentedItems
for name, item of @objects
@subscribe item, '*', (params, event) => @emit("#{name}:#{event.name}", params)

@decorate: (className, methodLists...)->
@jsonGenerators()[className] = (obj)->
Object.extend(obj.toJSON(), methodLists...)
@decorators()[className] = Object.extend({}, methodLists...)

@jsonFor: (className, jsonGenerator)->
@jsonGenerators()[className] = jsonGenerator

@jsonGenerators: ->
@classInstanceVars().jsonGenerators ?= {}
@decorators: ->
@classInstanceVars().decorators ?= {}

jsonGeneratorFor: (obj)->
@constructor.jsonGenerators()[obj.constructor.name]
decoratorFor: (obj)->
@constructor.decorators()[obj.constructor.name]

toJSON: ->
json = {}
for name, item of @presentedItems
json[name] = @present(item)
for name, object of @objects
json[name] = @present(object)
json

present: (obj)->
Expand All @@ -33,9 +28,12 @@ class egg.Presenter extends egg.Base
@presentObject(obj)

presentObject: (obj)->
@jsonGeneratorFor(obj)?(obj) ||
obj.toJSON?() ||
Object.extend({}, obj)
hash = obj.toJSON?() || Object.extend({}, obj)
decorator = @decoratorFor(obj)
if decorator
for key, value of decorator
hash[key] = (if @isFunction(value) then value.call(obj) else value)
hash

presentEnumerable: (obj)->
json = []
Expand All @@ -44,7 +42,6 @@ class egg.Presenter extends egg.Base

isEnumerable: (obj)->
!!obj.forEach

createReaderMethods: ->
for name, item of @presentedItems
@[name] = -> @present(item)

isFunction: (value)->
typeof value == 'function'
59 changes: 29 additions & 30 deletions test/src/presenter.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ describe 'egg.Presenter', ->
}

@decorate 'Knee',
thighBone: -> @hipBone * 2

@jsonFor 'Monkey', (monkey)->
{super: "#{monkey.get('hungry')}duper"}
thighBone: -> @get('hipBone') * 2

class Elbow extends egg.Model
class Knee extends egg.Model
Expand All @@ -25,50 +22,52 @@ describe 'egg.Presenter', ->

describe 'toJSON', ->
it "should return the items to present", ->
presenter = TestPresenter.create(present: {chicken: {big: 'beak'}})
presenter = TestPresenter.create(objects: {chicken: {big: 'beak'}})
expect( presenter.toJSON() ).toEqual chicken: {big: 'beak'}

it "should use toJSON if it's present", ->
presenter = TestPresenter.create(present: {chicken: {toJSON: -> ['d', {a: 2}]}})
presenter = TestPresenter.create(objects: {chicken: {toJSON: -> ['d', {a: 2}]}})
expect( presenter.toJSON() ).toEqual chicken: ['d', {a: 2}]

it "should create a method for each presented item", ->
presenter = TestPresenter.create(present: {chicken: {toJSON: -> ['d', {a: 2}]}})
expect( presenter.chicken() ).toEqual ['d', {a: 2}]

it "should loop over anything that responds to forEach", ->
array = [{toJSON: -> 'blah'}, {toJSON: -> 'gurd'}]
chickens = {forEach: (callback) -> callback(item) for item in array }
presenter = TestPresenter.create(present: {chickens: chickens})
presenter = TestPresenter.create(objects: {chickens: chickens})
expect( presenter.toJSON() ).toEqual chickens: ['blah', 'gurd']

it "should decorate any specified objects", ->
elbow = Elbow.create attrs: {doobie: 'doo'}
presenter = TestPresenter.create(present: {elbow: elbow})
presenter = TestPresenter.create(objects: {elbow: elbow})
expect( presenter.toJSON() ).toEqual elbow: {doobie: 'doo', shards: 'blaggard'}

it "should allow giving multiple decoration method lists", ->
shiny = Shiny.create attrs: {doobie: 'doo'}
presenter = TestPresenter.create(present: {shiny: shiny})
presenter = TestPresenter.create(objects: {shiny: shiny})
expect( presenter.toJSON() ).toEqual shiny: {doobie: 'doo', smurf: 'poo', dongle: 'trousers'}

it "should allow for custom toJSON overrides", ->
monkey = Monkey.create attrs: {hungry: 'yes'}
presenter = TestPresenter.create(present: {monkey: monkey})
expect( presenter.toJSON() ).toEqual monkey: {super: 'yesduper'}
it "should call any decoration methods", ->
knee = Knee.create attrs: {hipBone: 4}
presenter = TestPresenter.create(objects: {knee: knee})
expect( presenter.toJSON() ).toEqual knee: {hipBone: 4, thighBone: 8}

it "should allow getting json for a specific model", ->
knee = Knee.create attrs: {hipBone: 4}
presenter = TestPresenter.create(objects: {knee: knee})
expect( presenter.present(knee) ).toEqual {hipBone: 4, thighBone: 8}

it "should forward events", ->
monkey = Monkey.create attrs: {hungry: 'yes'}
presenter = TestPresenter.create(present: {monkey: monkey})
spyOn(presenter, 'emit')
presenter.on 'anything', ->
monkey.set('hungry', 'pig')
expect( presenter.emit ).toHaveBeenCalledWith('monkey:change.hungry', instance: monkey, from: 'yes', to: 'pig')
describe "events", ->
it "should forward events", ->
monkey = Monkey.create attrs: {hungry: 'yes'}
presenter = TestPresenter.create(objects: {monkey: monkey})
spyOn(presenter, 'emit')
presenter.on 'anything', ->
monkey.set('hungry', 'pig')
expect( presenter.emit ).toHaveBeenCalledWith('monkey:change.hungry', instance: monkey, from: 'yes', to: 'pig')

it "should not forward events if nothing has yet subscribed to it", ->
monkey = Monkey.create attrs: {hungry: 'yes'}
presenter = TestPresenter.create(present: {monkey: monkey})
spyOn(presenter, 'emit')
monkey.set('hungry', 'pig')
expect( presenter.emit ).not.toHaveBeenCalled()
it "should not forward events if nothing has yet subscribed to it", ->
monkey = Monkey.create attrs: {hungry: 'yes'}
presenter = TestPresenter.create(objects: {monkey: monkey})
spyOn(presenter, 'emit')
monkey.set('hungry', 'pig')
expect( presenter.emit ).not.toHaveBeenCalled()

0 comments on commit c32982b

Please sign in to comment.