-
Notifications
You must be signed in to change notification settings - Fork 55
Module structure
SOCRAT
is designed to be highly scalable. According to large-scale architecture principles, each module implements standard structure. You can add a new module to SOCRAT
in a few easy steps:
Each module is represented by a collection of files, one file per AngularJs
component, such as module, controller, directive, or service.
These components are implemented as CoffeeScript classes in CommonJs module format.
SOCRAT
provides base classes for different types of components, which can be used to create custom implementations.
Let's create new analysis module, that will appear in main menu under Tools
drop-down.
Empty template
We can start by creating a new directory MyModule
under scripts/analysis/tools
and create MyModule.module.coffee
file inside:
'use strict'
# import module class
Module = require 'scripts/BaseClasses/BaseModule.coffee'
# export instance of new module
module.exports = myModule = new Module
# module id for registration
id: 'socrat_analysis_mymodule'
# module components
components:
services:
'socrat_analysis_mymodule_initService': require 'scripts/analysis/tools/MyModule/MyModuleInit.service.coffee'
'socrat_analysis_mymodule_msgService': require 'scripts/analysis/tools/MyModule/MyModuleMsgService.service.coffee'
'socrat_analysis_mymodule_dataService': require 'scripts/analysis/tools/MyModule/MyModuleDataService.service.coffee'
'socrat_analysis_mymodule_myService': require 'scripts/analysis/tools/MyModule/MyModuleMyService.service.coffee'
controllers:
'mymoduleMainCtrl': require 'scripts/analysis/tools/MyModule/MyModuleMainCtrl.ctrl.coffee'
'mymoduleSidebarCtrl': require 'scripts/analysis/tools/MyModule/MyModuleSidebarCtrl.ctrl.coffee'
directives:
'socratMyModuleDir': require 'scripts/analysis/tools/MyModule/MyModuleDir.directive.coffee'
# module state config
state:
# module name to show in UI
name: 'My Awesome Module'
url: '/tools/mymodule'
mainTemplate: require 'partials/analysis/tools/MyModule/main.jade'
sidebarTemplate: require 'partials/analysis/tools/MyModule/sidebar.jade'
Here we can see that module instance contains few key components. id
is a string that makes it addressable by SOCRAT
. components
enlists all services, controllers, and directives of current module referring to their implementations via require
statement. state
is used to add a new state to routing system, identified by corresponding url
and providing Jade templates with module UI.
First 2 services are required for any module to initialize. Let's take a closer look on their implementation.
Init Service
Create MyModuleInit.service.coffee
:
'use strict'
# import base service class
BaseModuleInitService = require 'scripts/BaseClasses/BaseModuleInitService.coffee'
# export custom service class
module.exports = class MyModuleInitService extends BaseModuleInitService
# requires message service as a dependency
@inject 'socrat_analysis_mymodule_msgService'
# entry point function:
initialize: ->
# this renaming is required for initialization!
@msgService = @socrat_analysis_mymodule_msgService
# required method call to initiate module messaging interface
@setMsgList()
As you can see it's easy to create Init Service based on already existing class that hides all necessary functions. Only thing we need to do is to provide a link to messaging service, which is a required dependency. Note, that whatever you name your module messaging service, it has to be renamed in the initialize
method to @msgService
.
As a next step we can look how to implement messaging service which will allow our module to interact with SOCRAT
.
Every module have it's own config
block which is started at the stage of module initialization. Services, providers from ng
module (such as $http
, $resource
) can be injected in config
. Note, that services, providers in this module cannot be injected in the config
block, because it's run before their initialization.
.config([
() ->
console.log "config block of myModule module"
])
Event Manager
This is another essential module component. Every module has to have a MODULE_NAMEEventMngr()
service which provides messaging with core
.service('myModuleEventMngr', [
() ->
sb = null
msgList =
outcome: ['outcomeMsg']
income: ['incomeMsg']
scope: ['myModule']
eventManager = (msg, data) ->
# here goes implementation of inner listener
setSb: (_sb) ->
return false if _sb is undefined
sb = _sb
getMsgList: () ->
msgList
listenToIncomeEvents: () ->
console.log 'subscribed for ' + msgList.income[0]
sb.subscribe
msg: msgList.income[0]
listener: eventManager
msgScope: msgList.scope
sum: sum
])
Factory
Module initialization is handled by the Core module of the Framework by invoking the Angular factory of the same name. For example, app.myModule
module has to have myModule
factory. Factory takes Sandbox object sb
as a parameter. Factory returns an object containing methods init()
and destroy()
and message list msgList
. In the init()
method module subscribes for messages from it's own components (communication within the module).
.factory('myModule', [
# Factory has Event Manager as a dependency
'myModuleEventMngr'
(myModuleEventMngr) ->
# Sandbox is used in Event Manager for communications
(sb) ->
# List of messages is retrieved from Event Manager
msgList = myModuleEventMngr.getMsgList()
myModuleEventMngr.setSb sb unless !sb?
# This method invoked on module initialization
init: (opt) ->
console.log 'myModule init invoked'
myModuleEventMngr.listenToIncomeEvents()
# This method invoked on module destruction
destroy: () ->
# Return list of messages to Core
msgList: msgList
])