|
2 years ago | |
---|---|---|
filters | 2 years ago | |
LICENSE | 3 years ago | |
README.md | 2 years ago | |
changelog.md | 2 years ago | |
rasyen.js | 2 years ago | |
rasyen.min.js | 3 years ago | |
tests.html | 2 years ago |
__________ _________ ___________
\______ \_____ / _____/__.__.\_ _____/ ____
| _/\__ \ \_____ < | | | __)_ / \
| | \ / __ \_/ \___ | | \ | \
|____|_ /(____ /_______ / ____|/_______ /___| /
\/ \/ \/\/ \/ \/
Rasyen (pronounced /ˈɹeɪzn/ like the dried grape) uses a list of options to select a string randomly from an object or array and a template to do the replacements on. This effectively separates the data from template allowing you to store lists of data and leave the random parsing to a simple template.
Contents:
The most basic usage of RaSyEn could look like this.
Rasyen.list_load("flowers", "violets roses forget-me-nots".split(" "));
alert(Rasyen.parse("Daisy likes %flowers%."));
// → "Daisy likes violets."
And here is an example combining random words to generate a name.
// Load (list name, Array or Object)
Rasyen.lists_load({
"first" : [
"Ae","Ara","Bal","Ylla","Zin","Zyl"
],
"second" : [
"balar","can","yra","zorwyn","zumin"
]
});
// Templates use tags like %list-name% to produce random output.
var template = "Your elf name is %first%%second%.";
// Parse the template
var out = Rasyen.parse(template);
// → "Your elf name is Arayra."
Or consider this other example:
// Load a "story list"
Rasyen.lists_load("story", {
"name" : [
"Ben",
"Jasper",
"John"
],
"action" : [
"was hunting",
"went fishing",
"was dozing off",
],
"result" : [
"when he saw an old abandoned cabin",
"and then suddenly it all made sense",
"when he received a mysterious call"
]
});
// Parse three tags
var out = Rasyen.parse("%story@name% %story@action% %story@result%.");
The value of out
could be...
“Ben went fishing and then suddenly it all made sense."
... Or any number of other combinations.
You can see RaSyEn in action in the online demo here.
For a more complex demo that uses AJAX and a simple cache system for the lists see this implementation.
Here you will find a brief description of all methods, containers, callbacks and filters in RaSyEn.
Templates are strings fed into the parser, who will look for tags, parts of the string with surrounding percent symbols, and proceed from there. Here is a basic description of a tags symbology.
%
to open and close a tag.@
to separate categories.|
to to merge different lists.=
to separate different filters.With that in mind you can create templates with tags such as:
%list%
That returns a random string from list
, or you can modify the output using a filter named filter
, like this:
%list=filter%
.
Easy-peasy. You could also descend into a category
of the list and then modify the result with a filter:
%list@category=filter%
.
What if you want a random result from two lists? Try this:
%list-a|list-b%
.
... Or combine list-a
with a category from list-b
and then pass the result through filter-1
and filter-2
.
%list-a|list-b@category=filter-1=filter-2%
.
It gets better, you can save a category name and apply it to another list, or you can create lists which contain templates to further randomize things.
The methods built in Rasyen are:
Rasyen.random_range(min, max)
Rasyen.rai(array)
Rasyen.roi(object)
Rasyen.rok(object)
Rasyen.random_str(object_or_array)
Rasyen.navigate_obj(object, array)
Rasyen.extend_obj(old_obj, new_obj, newer_obj, etc)
Rasyen.replace_in_obj(old_obj, replace_arr, path_arr)
Rasyen.list_save_item(result, name)
Rasyen.list_remove_item(name, str, path_array)
Rasyen.list_load(name, object_or_array)
Rasyen.lists_load(object_of_lists)
Rasyen.list_remove(name)
Rasyen.list_get(name)
Rasyen.parse_tag(string)
Rasyen.parse_template(string)
Rasyen.parse(string)
There are actually more public methods in Rasyen, but these are the methods most people will use.
RaSyEn contains several containers you can access directly if needed:
Rasyen.lists
object
Rasyen.filters
object
Rasyen.saved_keys
array
=save-result
filter are saved in this array.Rasyen.removed_items
array
=remove-result
filter are saved here.Rasyen.options
object
Rasyen.options.max_recusrion
number
Rasyen.options.use_window_crypto
boolean
You can also use these callback functions to edit core functionalities.
Rasyen.callback
object
Rasyen.callback.parse_template(data)
function
Rasyen.callback.parse_tag(data)
function
Rasyen.callback.parse_list(data)
function
Rasyen.callback.parse_filters(data)
function
Rasyen.callback.on_error(error)
function
Filters are an expansible tool that can be used inside the template tags to do something with the output.
Pre-built filters are:
=to-lower
=to-upper
=first-to-lower
=first-to-upper
=words
=random-category
=range
=save-result
=category
=remove-result
=meta
=inline
=quiet
English Filters:
These filters are located in the filters/en_US-filters.js
file. It is not included by default.
=a-or-an
=pronoun-swap
=to-plural
=to-singular
=number-to-words
There is an ever-growing test file where you can see every filter in action.
You can use filters on lists to do a specific thing with the randomly returned result.
A filter is usually prefixed by a list name it applies to, so if your list is named “fruit” containing a single item “banana", its tag in the template would be “%fruit%", and to apply the “=to-upper” filter you would add it to the tag resulting in %fruit=to-upper%
which would produce “BANANA".
// Add a list called "insect"
Rasyen.list_load("insect", [
"MOTH",
"MANTIS"
]);
// Parse
var template = "%insect=first-to-upper% and %insect=to-lower%.";
var out = Rasyen.parse(template);
// → "Moth and moth."
// Combining filters
out = Rasyen.parse("%insect=to-lower=first-to-upper%.");
// → "Mantis." || "Moth."
Remember, filter order matters and they will be applied from left to right, so:
// Load a list called "title" with two items
Rasyen.list_load("title", [
"Mrs",
"Miss"
]);
var out = Rasyen.parse("%title=to-lower=to-upper% Parker");
// → "MISS Parker" || "MRS Parker"
Or use filters to do grammatical prefixing:
// Load a list called "animal"
Rasyen.list_load("animal", [
"tiger",
"ostrich"
]);
// Parse
var out = Rasyen.parse("%animal=a-or-an%"); // → "a tiger" or "an ostrich"
Some filters accept parameters or even use other filters, like =words
:
// Load a list called "animal"
Rasyen.list_load("kung-fu", [
"angry tiger style",
"spinning ostrich kick"
]);
var out = Rasyen.parse("%kung-fu=words=first-to-upper%"); // → "Angry Tiger Style" ...
Complex lists can be accessed by use of categories, (the object property name) prefixed with the @
character.
And lists can be combined in the same tag by using the |
symbol and filtered with built in or custom filters.
// Load lists as json object
Rasyen.lists_load({
// The "adjective" list contains categories "good" and "bad"
"adjective" : {
"good" : [
"happy",
"calm",
"nice"
],
"bad" : [
"lazy",
"tired"
]
},
// The "name" list
"name" : {
"male" : {
"hobbit" : [
"Bilbo",
"Frodo",
"Sam"
],
"other" : [
"Gandalf",
"Tom Bombadil",
"Aragorn"
]
},
"female" : [
"Galadriel",
"Goldberry"
]
}
});
// Parse
var template = "%name@male% was feeling %adjective%.";
var out = Rasyen.parse(template);
// → "Gandalf was feeling happy." || "Tom Bombadil was feeling lazy." || ...
// Combine male hobbit names and female using the "|" pipe character
out = Rasyen.parse("%name@male@hobbit|name@female% feels %adjective@good%.");
The =save-result
and =remove-result
let you save and remove an item from a list, let say you are making a plot, you can save the name of your character and use it later again, or you can remove an item from a list so the template will never use the item twice.
// We add our lists
Rasyen.lists_load({
"feeling" : [
"sad",
"happy"
],
"title" : [
"she",
"he"
]
});
// Save title to "t1" and feeling to "f1" and use them later
var template = "%title=save-result=t1% was %feeling=save-result=f1%, %t1% was always %f1%";
var out = Rasyen.parse(template);
// → "she was sad, she was always sad"
// You can also remove items so they don't show up twice
template = "%title=remove-result% knew %title% would do it";
out = Rasyen.parse(template);
// → "she knew he would do it"
// Or mix two lists and save the result
template = "%feeling|title|=save-result=new-result% is %new-result%.";
out = Rasyen.parse(template);
// → "sad is sad." || "she is she" || ...
The property name in a javascript object is used as a category in RaSyEn. You can use =random-category
to get a category as a result and apply it using the =category
filter.
// Load the "object" list with categories by room
Rasyen.list_load("house", {
"lounge" : [
"radio",
"lamp"
],
"kitchen" : [
"toaster",
"microwave"
]
});
// Parse
var template = [
"In the %house=random-category=save-result=room%",
"there was a brave little %house=category=room%"
];
var out = Rasyen.parse(template.join(" "));
// → "In the kitchen there was a brave little toaster" || ...
In the example above by saving the category name you can use it to select the pertinent list item further down the road.
Here is an advanced example that tries to show how powerful these filters can be, lets say we want to produce a story where we can keep track of a set of characters, and use them later on in the same template. For example to produce a text similar to this.
“He, Lancelot loveth she, Guinevere, but Guinevere loveth Arthur. Lancelot grew jealous of Arthur, and plotted with Morgana to forsake him."
We would have to do:
// Some basic syntax lists
Rasyen.lists_load({
"title" : [
"he",
"she"
],
"preposition" : {
"he" : "him",
"she" : "her"
},
"name" : {
"he" : [
"Lancelot",
"Arthur",
"Tam Lin"
],
"she" : [
"Guinevere",
"Morgana",
"Janet"
]
}
});
// Now the template...
var template = [
"%title=remove-result=save-result=t1=first-to-upper%,",
// → "He,"
"%name=category=t1=remove-result=save-result=n1%",
// → "Lancelot"
"loveth %title=remove-result=save-result=t2%,",
// → "loveth she,"
"%name=category=t2=remove-result=save-result=n2%,",
// → "Guinevere,"
"but %n2% loveth %name=category=t1=save-result=n3%.",
// → "but Guinevere loveth Arthur."
"%n1% grew jealous of %n3%,",
// → "Lancelot grew jealous of Arthur,"
"and plotted with %name=category=t2=save-result=n4%",
// → "and plotted with Morgana"
"to forsake %preposition=category=t1%."
// → "to forsake him."
];
// Parse
var out = Rasyen.parse(template.join(" "));
In essence you now have four characters n1
, n2
, n3
and n4
, which you can use to add continuity to the narration. n1
and n3
are the same gender, and n2
and n4
are plotting against n1
What if you want to use lists in your lists?
The =meta
filter can be useful for making combined syntax.
// Load (list name, Array or Object)
Rasyen.list_load("elf", {
"a" : [
"Ae",
"Ara",
"Bal",
"Ylla",
"Zin",
"Zyl"
],
"b" : [
"balar",
"can",
"yra",
"zorwyn",
"zumin"
],
"name" : "%elf@a%%elf@b%" // For use with the =meta filter
});
var template = "Your elf name is %elf@name=meta%.";
// → "Your elf name is Arayra."
// Or store the name as %elf-name%
template = "This elf is called %elf@name=meta=save-result=elf-name%.";
var out = Rasyen.parse(template);
// → "This elf is called Arayra."
This looks like the first example, with a key difference, now that you are using only one tag you can save it using the =save-result
filter.
Another cool thing are custom filters, which can be built easily enough using the following technique.
// Load a list called happy
Rasyen.list_load("happy", [
"happy",
"joyful",
"gay"
]);
// The %happy=smile% filter adds a smile to the selected word.
Rasyen.filters['smile'] = function(list){
list.replace = list.replace+' ^_^';
return list;
};
var out = Rasyen.parse("be %happy=smile%");
Or if you want to always filter a list you can just name the filter the same way as the list and it will be done automatically.
// Add a list with a strange layout
Rasyen.list_load("color", {
"crayola" : [
["almond", "#efdecd"],
["antique brass", "#cd9575"],
["apricot", "#fdd9b5"]
]
});
// Always filter this list in the following way:
Rasyen.filters['color'] = function(list){
if(typeof Rasyen.lists['color'] !== 'undefined'){
// Get the full list apply categories and select an array
var color_list = Rasyen.lists['color'];
var color_cat = Rasyen.roi(color_list);
if(list.categories){
// search color_list with list.categories for the color category
color_cat = Rasyen.navigate_obj(color_list, list.categories);
}
// Get a random array item from color_cat
var col = Rasyen.rai(color_cat);
// Add the color to the word.
list.replace = '<span style="color:'+col[1]+'">'+col[0]+'</span>';
}
return list;
};
// Now every time this list is called the function above will run.
var out = Rasyen.parse("%color%");
Filters don't necessarily have to come after a list name, you can also have a tag with a filter and no list. For example:
// A filter to include a smile
Rasyen.filters['smile'] = function(list){
list.replace = '^_^';
return list;
};
// And then:
var out = Rasyen.parse("%=smile% a wild smile appears!");
// → "^_^ a wild smile appears!"
Callbacks allow you to manipulate information in different parts of the parsing process. The callback functions are also extremely useful when debugging.
Rasyen.callback.parse_tag = function(parsed){
// For debugging
console.log(parsed);
return parsed;
};
Check out these projects that use RaSyEn: