Last active
August 29, 2015 14:10
-
-
Save ChetHarrison/c610d4fe4a5e9f9280a2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var EventEmitter = require('events').EventEmitter, | |
globalChannel = new EventEmitter(), | |
Rx = require('rx'), | |
nutrients = require('./food-objects/nutrients'), | |
nutrients, | |
defaultHandlers = { | |
onError: function (err) { | |
console.log('Error: ' + err); | |
}, | |
onComplete: function () { | |
console.log('Completed'); | |
} | |
}, | |
globalChannelDestroyEvent = Rx.Observable.fromEvent( globalChannel, 'destroy').take(1), | |
// declaration | |
//----------------------------------------- | |
frenchFryNutrition = Object.create( nutrients ); // using delegation pattern | |
// lazy instantiation | |
//----------------------------------------- | |
frenchFryNutrition.initNutrition({ | |
state: { | |
salt: 100, | |
sugar: 95, | |
calories: 50 | |
}, | |
init: function() { | |
console.log('init was called on this stateContainer'); | |
} | |
}); | |
// events | |
//----------------------------------------- | |
// create observables | |
Rx.Observable.fromEvent( globalChannel, 'nutrientRequest', | |
function( eventArgs ) { | |
return frenchFryNutrition.getState()[ eventArgs[0] ]; | |
}). | |
takeUntil(globalChannelDestroyEvent). | |
subscribe( | |
function( response ) { globalChannel.emit( 'nutrientResponse', response ); }, | |
defaultHandlers.onError, | |
defaultHandlers.onComplete | |
); | |
Rx.Observable.fromEvent( globalChannel, 'nutrientResponse' ). | |
takeUntil(globalChannelDestroyEvent). | |
subscribe( | |
function( response ) { console.log( response ); }, | |
defaultHandlers.onError, | |
defaultHandlers.onComplete | |
); | |
//----------------------------------------- | |
// main | |
//----------------------------------------- | |
console.log(frenchFryNutrition.getNutrients()); // { salt: 100, sugar: 95, calories: 50 } | |
// test that we got a value not reference | |
nutrients = frenchFryNutrition.getNutrients(); | |
nutrients.salt = 25; // this does not work because getNutrients() returns a shallow copy not a reference | |
console.log(frenchFryNutrition.getNutrients()); // { salt: 100, sugar: 95, calories: 50 } | |
// test modification of ingredient | |
frenchFryNutrition.setNutrients({ salt: 5 }); | |
console.log(frenchFryNutrition.getNutrients()); // { salt: 5, sugar: 95, calories: 50 } | |
// test events | |
globalChannel.emit('nutrientRequest', 'salt'); // 5 | |
globalChannel.emit('nutrientRequest', 'sugar'); // 95 | |
globalChannel.emit('nutrientRequest', 'calories'); // 50 | |
globalChannel.emit('destroy'); // Completed\nCompleted | |
// output | |
//----------------------------------------- | |
// $ node index.js | |
// init was called on this stateContainer | |
// { salt: 100, sugar: 95, calories: 50 } | |
// { salt: 100, sugar: 95, calories: 50 } | |
// { salt: 5, sugar: 95, calories: 50 } | |
// 5 | |
// 95 | |
// 50 | |
// Completed | |
// Completed |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var nutrient = Object.create( require('../base-objects/state-container') ); | |
nutrient.initNutrition = function( options ) { | |
this.initStateContainer( options ); | |
}; | |
nutrient.getNutrients = function() { | |
return this.getState(); | |
}; | |
nutrient.setNutrients = function( nutrients ) { | |
// only change the ones in the arg | |
var keys = Object.keys( nutrients ), | |
state = this.state; | |
keys.forEach(function(key) { | |
state[key] = nutrients[key]; | |
}); | |
}; | |
module.exports = nutrient; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var util = require('./utilities'); | |
module.exports = { | |
initStateContainer: function( options ) { | |
// can send events | |
options = options || {}; | |
this.setState( options.state ); | |
this.observables = options.observables || []; | |
this.init = options.init || util.noop; | |
this.init(); | |
}, | |
setState: function( state ) { | |
this.state = state || {}; | |
}, | |
getState: function() { | |
return util.shallowCopy( this.state ); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
module.exports = { | |
noArg: function fatal(name) { | |
throw new Error('Missing required parameter: ' + name); | |
}, | |
noop: function(){}, | |
shallowCopy: function( obj ) { | |
var keys = Object.keys( obj ), | |
copy = {}; | |
keys.forEach(function(key) { | |
copy[key] = obj[key]; | |
}); | |
return copy; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This was an experiment to see if I could replicate Radio's functionality in RxJs and also play with Kyle Simpson's delegate pattern.
Radio
https://gist.github.com/ChetHarrison/c610d4fe4a5e9f9280a2#file-index-js-L43-L52 sets up an observable that takes a Node.js EventEmitter as a "channel" and listens for a "nutrientRequest" and takes an arg. the
takeUntil()
call sets the terms of disposal and RxJs takes 3 handlers: onNext, onError, and onComplete, onNext === success.https://gist.github.com/ChetHarrison/c610d4fe4a5e9f9280a2#file-index-js-L54-L60 sets up an observable on the same "channel" to wait for responses from our request. So it achieves bidirectional eventing with payloads.
Delegation
Look mom, no constructors!. Kyle's argument is that JS is not a classical OO language. Trying to dress it up as one (as we all do) just adds to your brain damage. It is a much simpler paradigm to think in terms of just linking objects. All instance state hangs off
this
.Because context is determined by the "call site"
Object.create()
is great way to establish the links. The context is right. I'm not thinking about binding.In this example
var nutrient = Object.create( require('../base-objects/state-container') );
links a nutrient object to a base object calledstateContainer
andfrenchFryNutrition = Object.create( nutrients );
linksfrenchFryNutrition
tonutrient
. So I can callgetState()
instateContainer
fromfrenchFryNutrition
with out having to figure out if it is hanging off a prototype because all of these objects are just objects, no constructor.So how do you add instance attributes to your instance without a constructor? Add an init function to your object https://gist.github.com/ChetHarrison/c610d4fe4a5e9f9280a2#file-state-container-js-L6-L13