IOC
Maestro has a build in IOC framework.
It is simple, and tailored specifically to roku memory management and performance, as well as easy debugging using RALE tool.
Using maestro IOC
Create your IOC container
Early on in your application, create your container and set instances as follows:
function initializeIOC()
m.log.info("initializing the IOD container")
'note this is done in the boostrap sequence in my apps
mioc.createContainer()
fontManager = createObject("roSGNode", "mv_FontManager")
mioc.setInstance("fontManager", fontManager)
styleManager = createObject("roSGNode", "mv_StyleManager")
mioc.setInstance("styleManager", styleManager)
end function
Get instances
To retrieve an instance, use mioc.getInstance("instance_name")
Get paths
To retrieve an instance, use mioc.getInstance("instance_name", "path.to.some.data")
, which will return the data on instance_name.path.to.some.data
Set instances
You can override instances at any point with mioc.setInstance
Use @inject annotation
You can inject ioc instances directly into your class fields, e.g.
class ButtonView extends mv.BaseView
@inject("styleManager")
private styleManager
@inject("user", "credentials.isLoggedIn")
private isLoggedIn
Unit testing
Maestro is all about testability, for this reason all the main base classes (e.g. NodeClass
, BaseView
, BaseViewModel
, etc) have wrappers for mioc.setInstance
and mioc.getInstance
making them very easy to stub in a unit test. e.g.
extract from LoginScreenVM.spec.bs
private function onRefreshComplete(result)
m.log.method("onRefreshComplete", result)
m.isLoading = false
m.isMainGroupVisible = true
if m.getInstance("user").isLoggedIn
m.dismiss("success")
else
m.signalAppLaunchDialog(false)
m.isRefreshing = false
end if
end function
extract from LoginScreenVM.bs
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@describe("onRefreshComplete")
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@it("dismisses on successful refresh")
function _()
user = { "id": "user", isLoggedIn: true }
m.expectOnce(m.vm, "getInstance", ["user"], user)
m.expectOnce(m.vm, "dismiss", ["success"])
m.vm.isLoading = true
m.vm.isRefreshing = true
m.vm.onRefreshComplete({})
end function