Skip to content

Instantly share code, notes, and snippets.

@okunishinishi
Last active February 13, 2017 04:25
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 okunishinishi/60ec3f8a610afdd8d3b8cd39d5b59659 to your computer and use it in GitHub Desktop.
Save okunishinishi/60ec3f8a610afdd8d3b8cd39d5b59659 to your computer and use it in GitHub Desktop.
[SUGOS] チュートリアル04 - Moduleをnpmパッケージ化する ref: http://qiita.com/okunishinishi@github/items/2c5f4f5fbd57fbb7c3e2
# Install as global module
npm install -g sugo-scaffold
# Show version to check if the installation succeeded
sugo-scaffold --version
# Create a module project
sugo-scaffold module "sugos-tutorial-04"
cd sugos-tutorial-04
npm install
npm test
// Example JavasScript, after ES2015
function doSomething (src, dest, options = {}) {
let {
force = false,
mkdirp = true
} = options
console.log('Do something with args: ', src, dest, force)
}
doSomething('foo.txt', 'bar.txt', { force: false, mkdirp: false })
// Example JavasScript, before ES2015
function doSomething (src, dest, options) {
if(typeof options === 'undefined') {
options = {}
}
var force = typeof options.force === 'undefined' ? false : options.force
var mkdirp = typeof options.mkdirp === 'undefined' ? true : options.mkdirp
console.log('Do something with args: ', src, dest, force)
}
doSomething('foo.txt', 'bar.txt', { force: false, mkdirp: false })
/**
* KeyValueStore class
* @class KeyValueStore
* @augments Module
* @param {Object} config - Configuration
*/
'use strict'
const { Module } = require('sugo-module-base')
const { name, version, description } = require('../package.json')
const co = require('co')
const { hasBin } = require('sg-check')
const debug = require('debug')('sugo:module:demo-module')
/** @lends KeyValueStore */
class KeyValueStore extends Module {
constructor (config = {}) {
debug('Config: ', config)
super(config)
}
/**
* Ping a message.
* @param {string} pong
* @returns {Promise.<string>} - Pong message
*/
ping (pong = 'pong') {
return co(function * pingAck () {
return pong // Return result to a remote caller.
})
}
/**
* Assert actor system requirements.
* @throws {Error} - System requirements failed error
* @returns {Promise.<boolean>} - Asserted state
*/
assert () {
const bins = [ 'node' ] // Required commands
return co(function * assertAck () {
yield hasBin.assertAll(bins)
return true
})
}
/**
* Module specification
* @see https://github.com/realglobe-Inc/sg-schemas/blob/master/lib/module_spec.json
*/
get $spec () {
return {
name,
version,
desc: description,
methods: {
ping: {
desc: 'Test the reachability of a module.',
params: [
{ name: 'pong', type: 'string', desc: 'Pong message to return' }
],
return: {
type: 'string',
desc: 'Pong message'
}
},
assert: {
desc: 'Test if the actor fulfills system requirements',
params: [],
throws: [ {
type: 'Error',
desc: 'System requirements failed'
} ],
return: {
type: 'boolean',
desc: 'System is OK'
}
}
},
events: null
}
}
}
module.exports = KeyValueStore
/** ... */
'use strict'
const { Module } = require('sugo-module-base')
const { name, version, description } = require('../package.json')
const co = require('co')
const fs = require('fs')
const { hasBin } = require('sg-check')
const debug = require('debug')('sugo:module:demo-module')
/** @lends KeyValueStore */
class KeyValueStore extends Module {
// Add "filename" parameter on constructor
constructor (config = {}) {
let { filename = 'kv.json' } = config
debug('Config: ', config)
super(config)
const s = this
s.filename = filename
}
/** ... */
ping (pong = 'pong') { /* ... */ }
/** ... */
assert () { /* ... */ }
// Define methods for Key-vale store
set (key, value) {
const s = this
return co(function * () {
let data = yield s._read().catch(() => ({}))
data[ key ] = value
return yield s._write(data)
})
}
get (key) {
const s = this
return co(function * () {
let data = yield s._read()
return data[ key ]
})
}
del (key) {
const s = this
return co(function * () {
let data = yield s._read()
delete data[ key ]
return yield s._write(data)
})
}
// Private function to read data file
// Methods with "_" is not exposed to remote caller
_read () {
let { filename } = this
return new Promise((resolve, reject) =>
fs.readFile((filename), (err, content) => err ? reject(err) : resolve(content))
).then(JSON.parse)
}
// Private function to write data file
// Methods with "_" is not exposed to remote caller
_write (data) {
let { filename } = this
return new Promise((resolve, reject) =>
fs.writeFile(filename, JSON.stringify(data), (err) => err ? reject(err) : resolve())
)
}
/** ... */
get $spec () { /* ... */ }
}
module.exports = KeyValueStore
/** ... */
'use strict'
const { Module } = require('sugo-module-base')
const { name, version, description } = require('../package.json')
const co = require('co')
const fs = require('fs')
const { hasBin } = require('sg-check')
const debug = require('debug')('sugo:module:demo-module')
/** @lends KeyValueStore */
class KeyValueStore extends Module {
constructor (config = {}) { /* ... */ }
/** ... */
ping (pong = 'pong') { /* ... */ }
/** ... */
assert () { /* ... */ }
set (key, value) { /* ... */ }
get (key) { /* ... */ }
del (key) { /* ... */ }
// Private function to read data file
// Methods with "_" is not exposed to remote caller
_read () { /* ... */ }
// Private function to write data file
// Methods with "_" is not exposed to remote caller
_write (data) { /* ... */ }
/**
* Module specification
* @see https://github.com/realglobe-Inc/sg-schemas/blob/master/lib/module_spec.json
*/
get $spec () {
return {
name,
version,
desc: description,
methods: {
ping: { /* ... */ },
assert: { /* ... */ },
set: {
desc: 'Set key value',
params: [
{ name: 'key', type: 'string', desc: 'Key to set' },
{ name: 'value', type: 'string', desc: 'value to set' }
]
},
get: {
desc: 'Get by key ',
params: [
{ name: 'key', type: 'string', desc: 'Key to set' }
],
return: { type: 'string', desc: 'Found value' }
},
del: {
desc: 'Delete by key ',
params: [
{ name: 'key', type: 'string', desc: 'Key to set' }
]
}
},
events: null
}
}
}
module.exports = KeyValueStore
/**
* Test case for demoModule.
* Runs with mocha.
*/
'use strict'
const KeyValueStore = require('../lib/key_value_store.js')
const assert = require('assert')
const co = require('co')
const { EventEmitter } = require('events')
const sgSchemas = require('sg-schemas')
const sgValidator = require('sg-validator')
describe('demo-module', function () {
this.timeout(3000)
before(() => co(function * () {
}))
after(() => co(function * () {
}))
it('Get module spec', () => co(function * () {
let module = new KeyValueStore({ $emitter: new EventEmitter() })
assert.ok(module)
let { $spec } = module
let specError = sgValidator(sgSchemas.moduleSpec).validate($spec)
assert.ok(!specError)
}))
it('Try ping-pong', () => co(function * () {
let module = new KeyValueStore({ $emitter: new EventEmitter() })
let pong = yield module.ping('pong')
assert.equal(pong, 'pong')
}))
it('Do assert', () => co(function * () {
let module = new KeyValueStore({ $emitter: new EventEmitter() })
let caught
try {
yield module.assert({})
} catch (err) {
caught = err
}
assert.ok(!caught)
}))
it('Compare methods with spec', () => co(function * () {
let module = new KeyValueStore({ $emitter: new EventEmitter() })
let { $spec } = module
let implemented = Object.getOwnPropertyNames(KeyValueStore.prototype)
.filter((name) => !/^[\$_]/.test(name))
.filter((name) => !~[ 'constructor' ].indexOf(name))
let described = Object.keys($spec.methods).filter((name) => !/^[\$_]/.test(name))
for (let name of implemented) {
assert.ok(!!~described.indexOf(name), `${name} method should be described in spec`)
}
for (let name of described) {
assert.ok(!!~implemented.indexOf(name), `${name} method should be implemented`)
}
}))
})
/* global describe, before, after, it */
/**
* Test case for demoModule.
* Runs with mocha.
*/
'use strict'
const KeyValueStore = require('../lib/key_value_store.js')
const assert = require('assert')
const co = require('co')
const { EventEmitter } = require('events')
const sgSchemas = require('sg-schemas')
const sgValidator = require('sg-validator')
describe('demo-module', function () {
this.timeout(3000)
before(() => co(function * () {
}))
after(() => co(function * () {
}))
it('Get module spec', () => co(function * () { /* ... */ }))
it('Try ping-pong', () => co(function * () { /* ... */ }))
it('Do assert', () => co(function * () { /* ... */ }))
it('Compare methods with spec', () => co(function * () { /* ... */ }))
it('Do get/set/del', () => co(function * () {
let module = new KeyValueStore({
filename: `${__dirname}/../testing-store.json`,
$emitter: new EventEmitter()
})
yield module.set('foo', 'This is foo')
{
let foo = yield module.get('foo')
assert.equal(foo, 'This is foo')
}
yield module.del('foo')
{
let foo = yield module.get('foo')
assert.equal(foo, undefined)
}
}))
})
/* global describe, before, after, it */
#!/usr/bin/env node
/**
* Example usage to register module on actor
* @see https://github.com/realglobe-Inc/sugo-actor
*/
'use strict'
const { KeyValueStore } = require('sugos-tutorial-04')
const sugoActor = require('sugo-actor')
const co = require('co')
co(function * () {
let actor = sugoActor('http://my-sugo-cloud.example.com/actors', {
key: 'my-actor-01',
modules: {
// Register the module
kvs: new KeyValueStore({
filename: 'kv.json'
})
}
})
yield actor.connect()
}).catch((err) => console.error(err))
# Keyword-arguments example of Python
def do_something(src, dest, **keywords):
force = keywords.pop('force', false)
mkdirp = keywords.pop('mkdirp', true)
print('Do something with args: ', src, dest, force)
do_something('foo.txt', 'bar.txt', force=false, mkdirp=false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment