1
0
Fork 0
mirror of https://github.com/Oreolek/raconteur.git synced 2024-06-26 03:30:47 +03:00
This commit is contained in:
Bruno Dias 2015-04-12 18:06:08 -03:00
parent bb6e302857
commit b4bf9b238e
7 changed files with 177 additions and 7 deletions

0
docs/dependencies.md Normal file
View file

View file

@ -73,6 +73,10 @@ elem.content('bar').id('bar_span')
Every ElementHelper object supplies the following methods. All of them return a new, modified ElementHelper which inherits from the ElementHelper that the method was called on. ElementHelpers are immutable to make this safe; otherwise, an ElementHelper could have its data changed by alterations to another ElementHelper further up its prototype chain.
## alt(altText) -> ElementHelper
Returns a new ElementHelper with the given string as its `_alt` property. This property is used as the element's `alt` attribute.
## class :: String -> ElementHelper
Returns a new ElementHelper with the given String as an additional class. This method is *additive,* so it adds new classes to the element. To completely change the element's classes, use ElementHelper#Classes
@ -93,6 +97,10 @@ Returns a new ElementHelper with the given id. This string is then used as the v
Returns a new ElementHelper with the given string as its `_ref` property. This property is used as the value of the element's `href` attribute.
## src(url) -> ElementHelper
Returns a new ElementHelper with the given string as its `_src` property. This property is used as the value of the element's `src` attribute.
## url :: String -> ElementHelper, situation :: String -> ElementHelper
Aliases for `ElementHelper#ref`, for code legibility.
@ -118,4 +126,30 @@ e.writer('foo') // e.type('writer').ref('foo')
e.replacer('foo') // e.type('replacer').ref('foo')
e.inserter('foo') // e.type('inserter').ref('foo')
e.action('foo') // e.type('action').ref('foo')
```
```
# Exports
`elements.js` exports the following methods:
## a(content) -> elementHelper
Returns a new `<a>` elementHelper object, with its content set to the argument.
## span(content) -> elementHelper
Returns a new `<span>` elementHelper object, with its content set to the argument.
## img(alt) -> elementHelper
Returns a new `<img>` elementHelper object, with its alt text set to the argument
## element(tag) -> elementHelper
Returns a new elementHelper object for the given tag. Usually, this can be called once to define your own custom element helpers:
```javascript
var elements = require('raconteur/elements.js');
var em = elements.element('em');
var glow = function (content) { return em.class('glow').content(content); };
```

56
docs/oneOf.md Normal file
View file

@ -0,0 +1,56 @@
# oneOf.js
This module implements a tool for generating adaptive text snippets. The syntax for using oneOf is:
```javascript
oneOf("foo", "bar", "baz").randomly()
```
## oneOf(...snippets) -> Object
Takes any number of arguments (at least one) and returns an Object with the following methods. This function is the top level export of this module.
Each one of those methods returns a closure which iterates over the arguments in some particular way. Those closures also have a special property: They supply a `toString()` method which is just equivalent ot `call()`. In practice, what this means is that you can treat them as either functions, or as values that stringify to a text snippet according to certain rules.
This means that you can use `oneOf` inline, inside strings, without parenthetising and calling it:
```coffeescript
"#{oneOf('dog', 'cat', 'alpaca').randomly()}"
"#{(oneOf('dog', 'cat', 'alpaca').randomly())()}" # Equivalent
```
However, keep in mind that this will create a new object each time, so it's only useful for randomising text; otherwise, it will behave as a totally new iterator each time.
### A note about initialisation
The methods that generate random text can optionally take an `undum.System` object as an argument. This object is passed into your code by Undum, and it contains a random number generator set up by Undum. This allows for random text to be consistently generated across different loads of the same saved game.
For this reason, text snippets with random variations should be initialised inside a function that has access to it, unless it is intentional that they should not be consistent across saves. This means that they should be created inside your `undum.game.init` function; creating them inside a situation's `content` function will not work as intended, since a new closure will be created every time the situation is entered.
# Object Methods
## cycling() -> Function
Returns a closure that iterates over the list and returns each one in order, going back to the first one when it runs out.
## stopping() -> Function
Returns a closure that iterates over the list and returns each one in order, then repeats the last item when it runs out.
## randomly(system) -> Function
Optionally takes an Undum `System` object as an argument. If one is provided, then random results will be consistent across saves.
Returns a closure that returns a random item of the list each time it's called. It will never return the same item twice in a row.
## trulyAtRandom(system) -> Function
Optionally takes an Undum `System` object as an argument. If one is provided, then random results will be consistent across saves.
Returns a closure that returns a random item of the list each time it's called. Unlike `randomly()`, this can return the same item twice in a row.
## inRandomOrder(system) -> Function
Optionally takes an Undum `System` object as an argument. If one is provided, then random results will be consistent across saves.
Returns a closure that returns the items of the list one at a time, in a random order. When it runs out, it goes back to the beginning of that random order.

39
docs/philosophy.md Normal file
View file

@ -0,0 +1,39 @@
# Design Philosophy
Raconteur is designed with the following principles in mind:
## Code should disappear when it doesn't matter
Unlike Twine, which enforces a clear separation between code and content, in an Undum story your code and content will be blended together in one file.
This is powerful: Instead of relying on macros, you always have the full power of a real programming language and its APIs to use anywhere. But it can also lead to a lot of boilerplate.
Raconteur's API is deisigned so that you can just write content. The DSL-like approach makes Raconteur source code written in CoffeeScript look like Twee or ChoiceScript files:
```coffeescript
situation 'west-of-house',
content: """
You are standing in an open field west of a [house], with a boarded up
front door. A [forest] is to the west.
"""
```
Markdown is used throughout so that your prose doesn't get lost in html. As much as possible, we try to follow the lead of systems that have been built previously to produce adaptive text or functionality in interactive fiction, such as commonly-used Twine macros and Inform 7's adaptive text functionality.
## Interfaces should start simple and become complex as necessary
Undum provides two prototypes for situations: Situation, a barebones prototype that only implements those methods which Undum expects internally; and SimpleSituation, a simplified version of that which serves the purposes of situations with some static text and a few choices.
Raconteur provides a single prototype, RaconteurSituation, which is designed to scale up as situations become more complex. Changing a situation from one with static text to one with dynamic text is easy:
```coffeescript
situation 'west-of-house',
content: () -> """
You are standing in an open field west of a [house], with a boarded up
front door. A [forest] is to the west.
#{getRoomContents(this)}
"""
```
Adding more functionality to a situation is strictly a matter of adding more properties to the situation's spec. Most writing is rewriting; Raconteur aims to make rewriting as straightforward as possible.

View file

@ -72,9 +72,15 @@ elementHelper.prototype.id = elementSetterGen("_id");
elementHelper.prototype.type = elementSetterGen("_linkType");
elementHelper.prototype.content = elementSetterGen("_content");
elementHelper.prototype.ref = elementSetterGen("_ref");
elementHelper.prototype.src = elementSetterGen("_src");
elementHelper.prototype.alt = elementSetterGen("_alt");
elementHelper.prototype.url = elementHelper.prototype.ref;
elementHelper.prototype.situation = elementHelper.prototype.ref;
elementHelper.prototype.once = () => this.class('once');
elementHelper.prototype.once = function () {
return this.class('once');
};
var linkTypeGen = function (type) {
return function (ref) {
@ -92,7 +98,9 @@ elementHelper.prototype.toString = function () {
classString = "",
idString = "",
hrefString= "",
contentString = "";
contentString = "",
srcString = "",
altString = "";
if (this._classes) {
classes += this._classes.join(' ');
@ -120,15 +128,24 @@ elementHelper.prototype.toString = function () {
}
}
if (this._src) {
srcString = `src="${this._src}"`;
}
if (this._alt) {
altString = `alt="${this._alt}"`;
}
if (this._content) {
contentString = markdown.renderInline(this._content);
}
return `<${this.element}${classString}${idString}${hrefString}>${contentString}</${this.element}>`;
return `<${this.element}${classString}${idString}${hrefString}${srcString}>${contentString}</${this.element}>`;
};
var a_proto = Object.freeze(new elementHelper("a"));
var span_proto = Object.freeze(new elementHelper("span"));
var img_proto = Object.freeze(new elementHelper("img"));
var a = function (content) {
if (content) return a_proto.content(content);
@ -140,5 +157,16 @@ var span = function (content) {
return span_proto;
};
var img = function (alt) {
if (alt) return img_proto.alt(alt);
return img_proto;
};
var element = function (tag) {
return Object.freeze(new elementHelper(tag));
};
module.exports.a = a;
module.exports.span = span;
module.exports.span = span;
module.exports.img = img;
module.exports.element = element;

View file

@ -83,6 +83,11 @@ var stringish = function (callback) {
var oneOf = function (...ary) {
if (ary.length<1) {
throw new Error(
"tried to create a oneOf iterator with a 0-length array");
}
return {
inOrder () {
var i = 0;
@ -111,6 +116,11 @@ var oneOf = function (...ary) {
randomly (system) {
var rng = (system) ? system.random : Math.random,
last;
if (ary.length<2) {
throw new Error(
"attempted to make randomly() iterator with a 1-length array");
}
return stringish(function () {
var i;
@ -134,6 +144,7 @@ var oneOf = function (...ary) {
var shuffled = ary.shuffle(system),
i = 0;
return stringish(function () {
if (i >= ary.length) i = 0;
return shuffled[i++];
});
}

View file

@ -2,5 +2,7 @@ site_name: Raconteur User Documentation
theme: readthedocs
pages:
- ['index.md', 'Introduction', 'What is Raconteur?']
- ['situation.md', 'API Documentation', 'Situation.js']
- ['elements.md', 'API Documentation', 'Elements.js']
- ['philosophy.md', 'Introduction', 'Design Philosophy']
- ['situation.md', 'API Documentation', 'situation.js']
- ['elements.md', 'API Documentation', 'elements.js']
- ['oneOf.md', 'API Documentation', 'oneOf.js']