1
0
Fork 0
mirror of https://github.com/Oreolek/raconteur.git synced 2024-05-17 00:08:16 +03:00

Separate qualities and element helper into modules

This commit is contained in:
Bruno Dias 2015-04-11 02:08:16 -03:00
parent ac4baabb42
commit b3568bc5cf
6 changed files with 226 additions and 208 deletions

View file

@ -35,7 +35,8 @@ var bundle = function () {
.pipe(buffer())
.pipe(sourcemaps.init({
loadMaps: true,
includeContent: true
includeContent: true,
debug: true
}))
.on('error', gutil.log.bind(gutil, 'Sourcemaps Error'))
.pipe(sourcemaps.write('./'))

View file

@ -1,11 +1,12 @@
var situation = require('raconteur/situation.js'),
$ = require('jquery'),
undum = require('undum-commonjs'),
tools = require('raconteur/tools.js');
tools = require('raconteur/tools.js'),
elements = require('raconteur/elements.js'),
qualities = require('raconteur/qualities.js');
var a = situation.a,
span = situation.span,
qualities = situation.qualities;
var a = elements.a,
span = elements.span;
undum.game.id = "my_game_id";
undum.game.version = "1.0";

144
lib/elements.js Normal file
View file

@ -0,0 +1,144 @@
/* Element Helpers */
/*
While you can write HTML elements by hand, those helpers make it easier to
place anchors (especially with special purpose) and spans.
They define a monadic interface:
a.id('my-link').content('link').writer('my-ref')
-> <a id="my-link" href="./_writer_my-ref">link</a>
span -> <span></span>
The object supplies a toString() method that outputs the tag. Element
helpers are immutable, so theoretically this should be safe from side
effects. This interface allows the safe definition of templates which
can be used and modified at will, for instance:
let mySpanClass = span.class('myclass'); // -> <span class="myclass"></span>
mySpanClass.content("Hello!"); // -> <span class="myclass">Hello!</span>
Methods on an elementHelper return a new elementHelper that inherits from
itself. Since those objects (should be) immutable by being frozen when they
are created, this is semantically equivalent to returning a copy but more
efficient in terms
Methods:
class :: String -> elementHelper
Returns a new elementHelper with the given class added.
classes :: [String] -> elementHelper
Returns a new elementHelper with the given classes.
id :: String -> elementHelper
Returns a new elementHelper with the given id.
*/
var md = require('markdown-it');
var markdown = new md({
typographer: true,
html: true
});
var elementHelper = function (element) {
this.element = element;
this._classes = [];
};
var elementSetterGen = function (prop) {
return function (value) {
return Object.freeze(Object.create(this, {
[prop]: {value}
}));
};
};
elementHelper.prototype.classes = function (newClasses) {
return Object.freeze(Object.create(this, {
_classes: {
value: newClasses
}
}));
};
elementHelper.prototype.class = function (newClass) {
return this.classes(this._classes.concat(newClass));
};
elementHelper.prototype.id = elementSetterGen("_id");
elementHelper.prototype.type = elementSetterGen("_linkType");
elementHelper.prototype.content = elementSetterGen("_content");
elementHelper.prototype.ref = elementSetterGen("_ref");
elementHelper.prototype.url = elementHelper.prototype.ref;
elementHelper.prototype.situation = elementHelper.prototype.ref;
elementHelper.prototype.once = () => this.class('once');
var linkTypeGen = function (type) {
return function (ref) {
return this.type(type).ref(ref);
}
};
elementHelper.prototype.writer = linkTypeGen("writer");
elementHelper.prototype.replacer = linkTypeGen("replacer");
elementHelper.prototype.inserter = linkTypeGen("inserter");
elementHelper.prototype.action = linkTypeGen("action");
elementHelper.prototype.toString = function () {
var classes = "",
classString = "",
idString = "",
hrefString= "",
contentString = "";
if (this._classes) {
classes += this._classes.join(' ');
}
if (this._linkType) {
classes += (' ' + this._linkType);
}
if (classes) {
classString = ` class="${classes}"`;
}
if (this._id) {
idString = ` id="${this._id}"`;
}
if (this.element === "a") {
if (this._linkType) {
if (this._linkType === "action") {
hrefString = ` href="./${this._ref}"`;
} else {
hrefString = ` href="./_${this._linkType}_${this._ref}"`;
}
} else {
hrefString = ` href="${this._ref}"`;
}
}
if (this._content) {
contentString = markdown.renderInline(this._content);
}
return `<${this.element}${classString}${idString}${hrefString}>${contentString}</${this.element}>`;
};
var a_proto = Object.freeze(new elementHelper("a"));
var span_proto = Object.freeze(new elementHelper("span"));
var a = function (content) {
if (content) return a_proto.content(content);
return a_proto;
};
var span = function (content) {
if (content) return span_proto.content(content);
return span_proto;
};
module.exports.a = a;
module.exports.span = span;

54
lib/qualities.js Normal file
View file

@ -0,0 +1,54 @@
/*
Quality definition function
Meant to be called only once in the main story source file, this definition
is passed a spec to define qualities. The spec is an object containing quality
groups as objects, which contain qualities that themselves hold definitions.
*/
var undum = require('undum-commonjs');
var qualities = function (spec) {
Object.keys(spec).forEach(function(group) {
/* The special "name" and "options" properties are passed on. */
var groupName = (spec[group].name === undefined) ? null : spec[group].name;
var groupOpts = (spec[group].options === undefined) ? {} : spec[group].options;
undum.game.qualityGroups[group] = new undum.QualityGroup(groupName, groupOpts);
Object.keys(spec[group]).forEach(function(quality) {
if (quality === "name" || quality === "options") return;
undum.game.qualities[quality] = spec[group][quality](group);
});
});
};
var qualityShim = {
integer: "IntegerQuality",
nonZeroInteger: "NonZeroIntegerQuality",
numeric: "NumericQuality",
fudgeAdjectives: "FudgeAdjectivesQuality",
onOff: "OnOffQuality",
yesNo: "YesNoQuality"
};
Object.keys(qualityShim).forEach(function (key) {
qualities[key] = function (title, spec={}) {
return function (group) {
spec.group = group;
return new undum[qualityShim[key]](title, spec);
};
};
});
/*
WordScaleQuality has a different interface (naughty!) so it has to be
defined by hand.
*/
qualities.wordScale = function (title, words, spec={}) {
return function (group) {
spec.group = group;
return new undum.WordScaleQuality(title, words, spec);
};
};
module.exports = qualities;

View file

@ -3,7 +3,7 @@ var undum = require('undum-commonjs'),
$ = require('jquery');
/* ---------------------------------------------------------------------------
Undularity is a rethought API for Undum, featuring more usable interfaces
Raconteur is a rethought API for Undum, featuring more usable interfaces
which coalesce as a DSL for defining Undum stories.
----------------------------------------------------------------------------*/
@ -27,7 +27,7 @@ String.prototype.normaliseTabs = function () {
/* Agnostic Call */
/*
Many properties in Undularity can be either a String, or a function that
Many properties in Raconteur can be either a String, or a function that
takes some objects from the game state (character, system, and the current
situation) and returns a String. Or in Haskell terms:
String | (CharacterObject -> SystemObject -> SituationString -> String)
@ -69,8 +69,8 @@ String.prototype.fade = function () {
/* Situations ----------------------------------------------------------------
The prototype UndularitySituation is the basic spec for situations
created with Undularity. It should be able to handle any use case for Undum.
The prototype RaconteurSituation is the basic spec for situations
created with Raconteur. It should be able to handle any use case for Undum.
Properties:
@ -116,7 +116,7 @@ String.prototype.fade = function () {
*/
var UndularitySituation = function (spec) {
var RaconteurSituation = function (spec) {
undum.Situation.call(this, spec);
// Add all properties of the spec to the object, indiscriminately.
@ -130,7 +130,7 @@ var UndularitySituation = function (spec) {
};
UndularitySituation.inherits(undum.Situation);
RaconteurSituation.inherits(undum.Situation);
/*
Undum calls Situation.enter every time a situation is entered, and
@ -138,10 +138,10 @@ UndularitySituation.inherits(undum.Situation);
and a string referencing the previous situation, or null if there is
none (ie, for the starting situation).
Undularity's version of enter is set up to fulfill most use cases.
Raconteur's version of enter is set up to fulfill most use cases.
*/
UndularitySituation.prototype.enter = function (character, system, f) {
RaconteurSituation.prototype.enter = function (character, system, f) {
this.visited++;
@ -167,13 +167,13 @@ UndularitySituation.prototype.enter = function (character, system, f) {
(Ie, a link that doesn't point at another situation or an external URL) is
clicked.
Undularity's version of act() is set up to implement commonly used
Raconteur's version of act() is set up to implement commonly used
functionality: "writer" links, "replacer" links, "inserter" links, and
generic "action" links that call functions which access the underlying
Undum API.
*/
UndularitySituation.prototype.act = function (character, system, action) {
RaconteurSituation.prototype.act = function (character, system, action) {
var actionClass,
self = this;
@ -219,199 +219,8 @@ UndularitySituation.prototype.act = function (character, system, action) {
};
/* Element Helpers */
/*
While you can write HTML elements by hand, those helpers make it easier to
place anchors (especially with special purpose) and spans.
They define a monadic interface:
a.id('my-link').content('link').writer('my-ref')
-> <a id="my-link" href="./_writer_my-ref">link</a>
span -> <span></span>
The object supplies a toString() method that outputs the tag. Element
helpers are immutable, so theoretically this should be safe from side
effects. This interface allows the safe definition of templates which
can be used and modified at will, for instance:
let mySpanClass = span.class('myclass'); // -> <span class="myclass"></span>
mySpanClass.content("Hello!"); // -> <span class="myclass">Hello!</span>
Methods on an elementHelper return a new elementHelper that inherits from
itself. Since those objects (should be) immutable by being frozen when they
are created, this is semantically equivalent to returning a copy but more
efficient in terms
Methods:
class :: String -> elementHelper
Returns a new elementHelper with the given class added.
classes :: [String] -> elementHelper
Returns a new elementHelper with the given classes.
id :: String -> elementHelper
Returns a new elementHelper with the given id.
*/
var elementHelper = function (element) {
this.element = element;
this._classes = [];
};
var elementSetterGen = function (prop) {
return function (value) {
return Object.freeze(Object.create(this, {
[prop]: {value}
}));
};
};
elementHelper.prototype.classes = function (newClasses) {
return Object.freeze(Object.create(this, {
_classes: {
value: newClasses
}
}));
};
elementHelper.prototype.class = function (newClass) {
return this.classes(this._classes.concat(newClass));
};
elementHelper.prototype.id = elementSetterGen("_id");
elementHelper.prototype.type = elementSetterGen("_linkType");
elementHelper.prototype.content = elementSetterGen("_content");
elementHelper.prototype.ref = elementSetterGen("_ref");
elementHelper.prototype.url = elementHelper.prototype.ref;
elementHelper.prototype.situation = elementHelper.prototype.ref;
elementHelper.prototype.once = () => this.class('once');
var linkTypeGen = function (type) {
return function (ref) {
return this.type(type).ref(ref);
}
};
elementHelper.prototype.writer = linkTypeGen("writer");
elementHelper.prototype.replacer = linkTypeGen("replacer");
elementHelper.prototype.inserter = linkTypeGen("inserter");
elementHelper.prototype.action = linkTypeGen("action");
elementHelper.prototype.toString = function () {
var classes = "",
classString = "",
idString = "",
hrefString= "",
contentString = "";
if (this._classes) {
classes += this._classes.join(' ');
}
if (this._linkType) {
classes += (' ' + this._linkType);
}
if (classes) {
classString = ` class="${classes}"`;
}
if (this._id) {
idString = ` id="${this._id}"`;
}
if (this.element === "a") {
if (this._linkType) {
if (this._linkType === "action") {
hrefString = ` href="./${this._ref}"`;
} else {
hrefString = ` href="./_${this._linkType}_${this._ref}"`;
}
} else {
hrefString = ` href="${this._ref}"`;
}
}
if (this._content) {
contentString = markdown.renderInline(this._content);
}
return `<${this.element}${classString}${idString}${hrefString}>${contentString}</${this.element}>`;
};
var a_proto = Object.freeze(new elementHelper("a"));
var span_proto = Object.freeze(new elementHelper("span"));
var a = function (content) {
if (content) return a_proto.content(content);
return a_proto;
};
var span = function (content) {
if (content) return span_proto.content(content);
return span_proto;
};
/*
Quality definition function
Meant to be called only once in the main story source file, this definition
is passed a spec to define qualities. The spec is an object containing quality
groups as objects, which contain qualities that themselves hold definitions.
*/
var qualities = function (spec) {
Object.keys(spec).forEach(function(group) {
/* The special "name" and "options" properties are passed on. */
var groupName = (spec[group].name === undefined) ? null : spec[group].name;
var groupOpts = (spec[group].options === undefined) ? {} : spec[group].options;
undum.game.qualityGroups[group] = new undum.QualityGroup(groupName, groupOpts);
Object.keys(spec[group]).forEach(function(quality) {
if (quality === "name" || quality === "options") return;
undum.game.qualities[quality] = spec[group][quality](group);
});
});
};
var qualityShim = {
integer: "IntegerQuality",
nonZeroInteger: "NonZeroIntegerQuality",
numeric: "NumericQuality",
fudgeAdjectives: "FudgeAdjectivesQuality",
onOff: "OnOffQuality",
yesNo: "YesNoQuality"
};
Object.keys(qualityShim).forEach(function (key) {
qualities[key] = function (title, spec={}) {
return function (group) {
spec.group = group;
return new undum[qualityShim[key]](title, spec);
};
};
});
/*
WordScaleQuality has a different interface (naughty!) so it has to be
defined by hand.
*/
qualities.wordScale = function (title, words, spec={}) {
return function (group) {
spec.group = group;
return new undum.WordScaleQuality(title, words, spec);
};
};
module.exports = function (name, spec) {
spec.name = name;
undum.game.situations[name] = new UndularitySituation(spec);
};
module.exports.a = a;
module.exports.span = span;
module.exports.qualities = qualities;
undum.game.situations[name] = new RaconteurSituation(spec);
};

View file

@ -0,0 +1,9 @@
{
"folders":
[
{
"path": ".",
"folder_exclude_patterns": ["node_modules", "devel/build"]
}
]
}