Skip to content

Commit

Permalink
Parse variables from story (#89)
Browse files Browse the repository at this point in the history
* First pass of storing and using history variable

* Moved history setting so not caught in initial path walk

* Fixed ObjectDataResolverSpec for new get and set

* Removed broken tests spec

* Overriding styles to make it look nicer

* First iteration of reading variables from story

* Example includes nested variables

* Story variable parsing now recurses keeping variable nesting

* Improved logger output
  • Loading branch information
andy-brown authored Jun 4, 2018
1 parent 268008b commit bcdca71
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 110 deletions.
169 changes: 62 additions & 107 deletions demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
<meta charset="utf-8">
<title>Romper Frog Demo</title>
<link href="dist/romper.css" rel="stylesheet" type="text/css">
<link href="dist/democontent/newsround/styles.css" rel="stylesheet" type="text/css">
</head>

<body>
<div id="romper-target"></div>
<script type="application/json" id="romper-story">{
<script type="application/json" id="romper-story"> {
"asset_collections": [
{
"id": "kvw1g6r47mnzv6p99blnm2q52d",
Expand Down Expand Up @@ -404,16 +405,6 @@
"image_src": "./dist/democontent/newsround/background.png"
}
},
{
"id": "b165c26a-48b2-455d-85b8-4920c070d51b",
"description": "",
"version": "",
"name": "",
"tags": {},
"assets": {
"image_src": "./dist/democontent/newsround/Intro pane.png"
}
},
{
"id": "p2cunpcyloebz8fisqql0g2cb8",
"description": "",
Expand Down Expand Up @@ -514,41 +505,6 @@
}
],
"presentations": [
{
"id": "96hz3ctyubpl2bz4yzeuohz5fi",
"version": "0.0",
"name": "Intro frame",
"representations": [
{
"representation": {
"id": "z3f0zzm4bvnl1ksoakr46xi563",
"version": "0.0",
"name": "Representation Item",
"representation_type": "urn:x-object-based-media:representation-types:image/v1.0",
"tags": {},
"choices": [],
"asset_collection": {
"foreground": "b165c26a-48b2-455d-85b8-4920c070d51b",
"background": [],
"icon": {
"active": "",
"default": ""
}
},
"behaviours": {
"STARTED": [],
"COMPLETED": []
}
},
"condition": {
"==": [
1,
1
]
}
}
]
},
{
"id": "86hz3ctyubpl2bz4yzeuohz5fi",
"version": "0.0",
Expand All @@ -571,18 +527,7 @@
}
},
"behaviours": {
"STARTED": [
{
"type": "urn:x-object-based-media:representation-behaviour:showimage/v1.0",
"image": "b165c26a-48b2-455d-85b8-4920c070d51b"
},
{
"type": "urn:x-object-based-media:representation-behaviour:showwaitbutton/v1.0",
"button_class": "romper-start-button",
"text": "Start",
"hide_narrative_buttons": true
}
],
"STARTED": [],
"COMPLETED": []
}
},
Expand Down Expand Up @@ -1096,9 +1041,9 @@
}
},
"condition": {
"==": [
1,
1
"<": [
{ "var": "profile.age" },
18
]
}
},
Expand All @@ -1124,9 +1069,9 @@
}
},
"condition": {
"==": [
1,
1
">=": [
{ "var": "profile.age" },
18
]
}
}
Expand Down Expand Up @@ -1464,31 +1409,31 @@
}
}
],
"tags": {},
"narrative_elements": [
{
"id": "uk3czilt2nsy9flx2ybwhmu0rc",
"version": "0.0",
"name": "Intro image",
"description": "Enter description here",
"tags": {},
"presentation": {
"type": "PRESENTATION_ELEMENT",
"target": "96hz3ctyubpl2bz4yzeuohz5fi"
},
"links": [
{
"condition": {
"==": [
1,
1
]
},
"link_type": "NARRATIVE_ELEMENT",
"target": "us3czilt2nsy9flx2ybwhmu0rc"
"variables": {
"profile": {
"default_value": {
"age": {
"default_value": 18,
"description": "how old user is",
"type": "integer"
},
"location": {
"default_value": "UK",
"description": "where user is",
"type": "string"
}
]
},
"type": "integer",
"description": "profile of the user"
},
"bandwidth": {
"default_value": 3,
"description": "how much data user can consume",
"type": "integer"
}
},
"tags": {},
"narrative_elements": [
{
"id": "us3czilt2nsy9flx2ybwhmu0rc",
"version": "0.0",
Expand All @@ -1512,7 +1457,7 @@
}
]
},
{
{
"id": "ccbm3vzunrhm5p9x5mwwq0g1r0",
"version": "0.0",
"name": "Celebrities",
Expand Down Expand Up @@ -1548,9 +1493,9 @@
"links": [
{
"condition": {
"==": [
1,
1
">": [
{ "var": "profile.age" },
15
]
},
"link_type": "NARRATIVE_ELEMENT",
Expand Down Expand Up @@ -1578,9 +1523,25 @@
},
{
"condition": {
"==": [
1,
1
"or": [
{
"in": [
"oiminrzzx5u571ew39mx50qgn0",
{ "var": "romper_path_history" }
]
},
{
"in": [
"iq3a7rejmj0gg5o3pzd4w76r7y",
{ "var": "romper_path_history" }
]
},
{
"in": [
"tix7ubtivifrwp37s7wr0i4qsv",
{ "var": "romper_path_history" }
]
}
]
},
"link_type": "NARRATIVE_ELEMENT",
Expand Down Expand Up @@ -1971,8 +1932,8 @@
{
"condition": {
"==": [
1,
1
{ "var": "profile.location" },
"UK"
]
},
"link_type": "NARRATIVE_ELEMENT",
Expand Down Expand Up @@ -2123,28 +2084,22 @@
<script>
(function () {
const config = JSON.parse(document.getElementById('romper-story').textContent);
const wait = () => new Promise(resolve => setTimeout(resolve, Math.random() * 100));
let romper = window.Romper.init({
target: document.getElementById('romper-target'),
dataResolver: window.Romper.RESOLVERS.FROM_OBJECT({}),
analyticsLogger: dataObj => {
console.log('ANALYTICS:', dataObj);
},
storyFetcher: id => Promise.resolve(wait().then(() => config.story.filter(storyObject => storyObject.id === id)[
0
])),
storyFetcher: id => Promise.resolve().then(
() => config.story.filter(storyObject => storyObject.id === id)[0]
),
mediaFetcher: uri => Promise.resolve(uri).then(resolvedUri => resolvedUri ? resolvedUri : Promise.reject('cannot resolve uri')),
presentationFetcher: id => Promise.resolve(
config.presentations
.filter(presentationObject => presentationObject.id === id)[
0
]
.filter(presentationObject => presentationObject.id === id)[0]
).then(presentationObject => presentationObject ? presentationObject : Promise.reject('no such presentation object: ' + id)),
assetCollectionFetcher: id => Promise.resolve(
config.asset_collections
.filter(assetCollectionObject => assetCollectionObject.id === id)[
0
]
.filter(assetCollectionObject => assetCollectionObject.id === id)[0]
).then(assetCollectionObject => assetCollectionObject ? assetCollectionObject : Promise.reject('no such asset collection: ' + id)),
});

Expand Down
48 changes: 47 additions & 1 deletion src/StoryReasoner.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,43 @@ export default class StoryReasoner extends EventEmitter {
throw new Error('InvalidState: this story has already been');
}
this._storyStarted = true;
this._fetchVariablesFromStory();
this._chooseBeginning();
}

// Get the variables defined in this story, and store the default values in our dataresolver
_fetchVariablesFromStory() {
if (this._story.variables) {
const variableTree = this._parseVariableDefinitions(this._story.variables);
Object.keys(variableTree).forEach((storyVariableName) => {
const storyVariableValue = variableTree[storyVariableName];
this.setVariableValue(storyVariableName, storyVariableValue);
});
} else {
logger.info('No variables in story');
}
}

// extract default values from nested variable tree, preserving tree structure
_parseVariableDefinitions(variables: Object) {
const result = {};
Object.keys(variables).forEach((varName) => {
const storyVar = variables[varName];
// is this a leaf or a node?
// nodes have an object as default_value
const varDefaultValue = storyVar.default_value;
if (varDefaultValue !== null && typeof varDefaultValue === 'object') {
// recurse
const subVar = this._parseVariableDefinitions(varDefaultValue);
result[varName] = subVar;
} else {
// return value
result[varName] = varDefaultValue;
}
});
return result;
}

/**
* Move on to the next node of this story.
*
Expand Down Expand Up @@ -199,11 +233,23 @@ export default class StoryReasoner extends EventEmitter {
}
}

/**
* Store or change a variable for the reasoner to use while reasoning
*
* @param {String} name The name of the variable to set
* @param {any} value Its value
*/
setVariableValue(name: string, value: any) {
logger.info(`Setting variable ${name} to ${value}`);
logger.info(`Setting variable '${name}' to ${JSON.stringify(value)}`);
this._dataResolver.set(name, value);
}

/**
* Record the fact that a given Narrative Element has been visited
* A special case of storing a variable
*
* @param {string} narrativeElementId The id of the narrative element visited
*/
appendToHistory(narrativeElementId: string) {
logger.info(`Storing ${narrativeElementId} in history`);
this._dataResolver.get('romper_path_history')
Expand Down
5 changes: 5 additions & 0 deletions src/romper.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ module.exports = {
init: (settings: Settings): ?Controller => {
const mergedSettings = Object.assign({}, DEFAULT_SETTINGS, settings);

if (!mergedSettings.dataResolver) {
logger.info('No data resolver passed to romper - creating one');
mergedSettings.dataResolver = ObjectDataResolver({});
}

const storyReasonerFactory = StoryReasonerFactory(
mergedSettings.storyFetcher,
mergedSettings.dataResolver,
Expand Down
5 changes: 3 additions & 2 deletions src/romper.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ export type Story = {
beginnings: Array<Beginning>,
narrative_elements: Array<NarrativeElement>,
meta?: any,
variables?: Object,
};

export type DataResolver = {
get: (name: string) => Promise<any>,
export type DataResolver = {
get: (name: string) => Promise<any>,
set: (name: string, value: any) => any,
}

Expand Down

0 comments on commit bcdca71

Please sign in to comment.