Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

on the fly state extension #6

Closed
ghost opened this issue Sep 7, 2015 · 2 comments
Closed

on the fly state extension #6

ghost opened this issue Sep 7, 2015 · 2 comments

Comments

@ghost
Copy link

ghost commented Sep 7, 2015

I have a feature request to reinstate an older functionality of possum: extending an instance's states via composition. Previously we could use some internals to reach into a possum's .router() and extendStates(). These concepts no longer apply, so I came up with a couple solutions...

let extender = stampit()
    .props({
        states: {
            extended: {
                extendedHandler: function () {
                    console.log('heyo')
                }
            }
        }
    })

let base = possum.compose(extender)

let impl = base
    .config({
        initialState: 'a'
    })
    .states({
        a: {
            goToExtended: function () {
                this.transition('extended')
            }
        }
    })

let it = impl()
it.goToExtended()
it.extendedHandler() // "heyo"

This works sort-of well, due to the recursive merging of stampit.props()... however, it's a source for silent errors if an implementer wants to have their own extended state. Due to the invocation order of .init blocks, I can't protect the implementer via the following...

let extender = stampit()
    .init(function () {
        // won't work due to the order of init blocks
        if (this.states.extended) {
            console.warn('careful: "extended" is a built in state, pick another name.')
        }

        this.states.extended = {
            extendedHandler: function () {

            }
        }
    })

This won't work because possum's init() blocks are triggered first - which is where states are set/sealed and closed to further extension. I can change the composition ordering, I suppose, like this:

let base = extender
    .compose(possum)

// extender's .init() is triggered before possums.init(), so there's time to 
// create and modify the this.states object...
let it = base()

However, digging into the props() .states object just feels wrong. What are your thoughts on this?

@mnichols
Copy link
Owner

mnichols commented Sep 7, 2015

I intentionally pulled that out, considering it the burden of the caller to merge the states object before constructing their instance. Possum would get too involved in guessing what the user intends for things like duplicates and so on.
I'd suggest you simply have an explicit composition object that brings together your state handlers and then pass that into possum.states; eg

var handlers1 = {
    a: { 
        b: function(){... }
   }
}

var handlers2 = {
   c: {
      d: function(){ ... }
   }
}

var merged = Object.assign({}, handlers1, handlers2)
possum.config(...).states(merged).create()

@ghost
Copy link
Author

ghost commented Sep 7, 2015

Noted. Thanks for the tip.

@ghost ghost closed this as completed Sep 7, 2015
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant