Skip to content

Instantly share code, notes, and snippets.

@maca

maca/Spine.Scope Secret

Last active August 29, 2015 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maca/206fdce951e50c6f4ef8 to your computer and use it in GitHub Desktop.
Save maca/206fdce951e50c6f4ef8 to your computer and use it in GitHub Desktop.
class Scope extends Spine.Module
constructor: (@parent, Negate, @positive, @lambda, @params) ->
@not = new Negate(@)
all: ->
keep = (record) =>
result = @lambda.apply(record, @params)
if @positive then result else not result
record for record in @parent.all() when keep(record)
class Negate extends Spine.Module
constructor: (@parent) ->
Spine.Model.extend
scopes: (scopes) ->
ScopeSub = @Scope or= Scope.sub()
NegateSub = @Negate or= Negate.sub()
@not = {}
for key, lambda of scopes
do (lambda) =>
@[key] = ScopeSub::[key] = -> new ScopeSub(@, NegateSub, true, lambda, arguments)
@not[key] = => new ScopeSub(@, NegateSub, false, lambda, arguments)
NegateSub::[key] = -> new ScopeSub(@parent, NegateSub, false, lambda, arguments)
sorts: (sorts) ->
ScopeSub = @Scope or= Scope.sub()
for key, lambda of sorts
do (lambda) =>
@[key] = ScopeSub::[key] = -> @.all().sort(lambda)
class Person extends Spine.Model
@configure 'Person', 'name'
@scopes
startsWith: (char) -> @name[0] is char
endsWith: (char) -> @name[@name.length - 1] is char
@sorts
byName: (a, b) ->
if a.name > b.name then 1 else -1
class Dummy extends Spine.Model
@configure 'Dummy'
@scopes dummy: -> true
describe 'Scopes', ->
afterEach ->
Person.destroyAll()
beforeEach ->
@matias = Person.create(name: 'Matías')
@beto = Person.create(name: 'Beto')
@macario = Person.create(name: 'Macario')
it 'generates scope functions', ->
expect(typeof Person.startsWith).toBe 'function'
expect(typeof Person.endsWith).toBe 'function'
it 'scopes', ->
scope = Person.startsWith('M')
names = ( person.name for person in scope.all() )
expect( names.length ).toBe 2
expect( names.indexOf('Macario') ).toBeGreaterThan -1
expect( names.indexOf('Matías') ).toBeGreaterThan -1
scope = Person.endsWith('o')
names = ( person.name for person in scope.all() )
expect( names.length ).toBe 2
expect( names.indexOf('Macario') ).toBeGreaterThan -1
expect( names.indexOf('Beto') ).toBeGreaterThan -1
it 'extends model scope class', ->
scope = Person.startsWith()
expect(typeof scope.startsWith).toBe 'function'
expect(typeof scope.endsWith).toBe 'function'
scope = Person.endsWith()
expect(typeof scope.startsWith).toBe 'function'
expect(typeof scope.endsWith).toBe 'function'
it 'doesnt contaminate other model scopes', ->
scope = Dummy.dummy()
expect(scope.startsWith).toBe undefined
expect(Dummy.startsWith).toBe undefined
it 'concatenates scopes', ->
scope = Person.startsWith('M').endsWith('o')
names = ( person.name for person in scope.all() )
expect( names.length ).toBe 1
expect( names.indexOf('Macario') ).toBeGreaterThan -1
it 'negates scope', ->
scope = Person.not.startsWith('M')
names = ( person.name for person in scope.all() )
expect( names.length ).toBe 1
expect( names.indexOf('Beto') ).toBeGreaterThan -1
it 'negates concatenated scopes', ->
scope = Person.startsWith('M').not.endsWith('o')
names = ( person.name for person in scope.all() )
expect( names.length ).toBe 1
expect( names.indexOf('Matías') ).toBeGreaterThan -1
it 'double negates concatenated scopes', ->
scope = Person.not.startsWith('B').not.endsWith('o')
names = ( person.name for person in scope.all() )
expect( names.length ).toBe 1
expect( names.indexOf('Matías') ).toBeGreaterThan -1
it 'doesnt contaminate other Negate classes', ->
scope = Dummy.dummy()
expect(scope.not.startsWith).toBe undefined
expect(Dummy.not.startsWith).toBe undefined
it 'sorts', ->
names = ( person.name for person in Person.byName() )
expect( names ).toEqual ['Beto', 'Macario', 'Matías']
it 'sorts when scoped', ->
scope = Person.startsWith('M')
names = ( person.name for person in scope.byName() )
expect( names ).toEqual ['Macario', 'Matías']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment