Commit 8e4de87d authored by Leon Arnott's avatar Leon Arnott
Browse files

Added a string-specific shorthand of (repeated:) called (str-repeated:).

This will be followed by a number of other str- macros in the coming days.

Additionally, the (text:) macro now has another alias, (str:). This alias will now be the preferred name for this macro in the documentation, mainly due to the arrival of other string macros that begin with "str-", and additionally to avoid semantic conflict with the various "text-" changer macros like (text-style:).
parent 3bd0aa67f513
......@@ -2,6 +2,16 @@
Rough documentation is at http://twine2.neocities.org/. See below for compilation instructions.
###2.1.1 changes:
####Alterations
* The `(text:)` macro now has another alias, `(str:)`. This alias will now be the preferred name for this macro in the documentation, mainly due to the arrival of other string macros that begin with "str-", and additionally to avoid semantic conflict with the various "text-" changer macros like `(text-style:)`.
####Additions
* Added a string-specific shorthand of `(repeated:)` called `(str-repeated:)` (and aliased as `(string-repeated:)`). `(str: ...(repeated: 14, "-+*+"))` is the same as `(str-repeated: 14, "-+*+")`.
###2.1.0 changes:
####Bugfixes
......@@ -41,7 +51,7 @@ Rough documentation is at http://twine2.neocities.org/. See below for compilatio
* Fixed a bug where subtracting non-subtractable values (such as booleans) wouldn't produce an error, instead implicitly converting the values to numbers, and potentially producing the Javascript value `NaN`.
* Fixed a bug where subtracting arrays and datasets wouldn't correctly compare contained data structures - for instance, `(a:(a:1)) - (a:(a:1))` wouldn't work correctly.
* Fixed a bug where the `(dataset:)` macro, and adding datasets, wouldn't correctly compare data structures - for instance, `(dataset: (a:),(a:))` would contain both identical arrays, as would `(dataset: (a:)) + (dataset: (a:))`.
* Additionally fixed a bug where data structures were storied in datasets by reference, allowing two variables to reference (and remotely alter) the same data.
* Additionally fixed a bug where data structures were stored in datasets by reference, allowing two variables to reference (and remotely alter) the same data.
* Fixed a bug where using `(move:)` to move a subarray or substring (such as `(move: $a's (a:2,3) to $b))` wouldn't work.
* Fixed a bug where using `(set:)` to set a substring, when the given array of positions contained "length" (such as `(set: $a's (a:1,"length")) to "foo")`), wouldn't produce an error.
* Fixed a bug where the `(count:)` macro would give the wrong result when the data to count (the second value) was an empty string.
......
......@@ -106,7 +106,7 @@ define(['requestAnimationFrame', 'macros', 'utils', 'state', 'passages', 'engine
`(print: $var + "s")`
Details:
It is capable of printing things which (text:) cannot convert to a string,
It is capable of printing things which (str:) cannot convert to a string,
such as changer commands - but these will usually become bare descriptive
text like `[A (font: ) command]`. You may find this useful for debugging purposes.
......@@ -124,7 +124,7 @@ define(['requestAnimationFrame', 'macros', 'utils', 'state', 'passages', 'engine
compared to just setting `$p` to a string, but is available nonetheless.
See also:
(text:), (display:)
(str:), (display:)
#basics 4
*/
......
......@@ -582,7 +582,7 @@ define([
and so forth.
Incidentally... you can also use this macro to rotate a string's characters, by doing
something like this: `(string: ...(rotated: 1, ...$str))`
something like this: `(str: ...(rotated: 1, ...$str))`
Details:
To ensure that it's being used correctly, this macro requires three or more items -
......@@ -679,8 +679,8 @@ define([
However, (interlaced:) can also be of use alongside macros which accept a sequence: you
can use it to cleanly insert values between each item. For instance, one can pair
an array with another array of spaces, and then convert them to a string with (text:).
`(text: ...(interlaced: $arr, (repeated: $arr's length, ' '))` will create a string containing
an array with another array of spaces, and then convert them to a string with (str:).
`(str: ...(interlaced: $arr, (repeated: $arr's length, ' '))` will create a string containing
each element of $arr, followed by a space.
Details:
......
......@@ -53,34 +53,34 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
| `of` | Obtaining the character at the left numeric position. | `1st of "YO"` (is "Y")<br>`(2) of "PS"` (is "S")<br>`(a: 2,3) of "ear"` (is "ar")
*/
/*d:
(text: ...[Number or String or Boolean or Array]) -> String
Also known as: (string:)
(str: ...[Number or String or Boolean or Array]) -> String
Also known as: (string:), (text:)
(text:) accepts any amount of expressions and tries to convert them all
(str:) accepts any amount of expressions and tries to convert them all
to a single String.
Example usages:
* `(text: $cash + 200)`
* `(if: (text: $cash)'s length > 3)[Phew! Over four digits!]`
* `(text: ...$arr)`
* `(str: $cash + 200)`
* `(if: (str: $cash)'s length > 3)[Phew! Over four digits!]`
* `(str: ...$arr)`
Rationale:
Unlike in Twine 1 and SugarCube, Twine 2 will only convert numbers into strings, or strings
into numbers, if you explictly ask it to. This extra carefulness decreases
the likelihood of unusual bugs creeping into stories (such as adding 1 and "22"
and getting "122"). The (text:) macro (along with (num:)) is how you can convert
and getting "122"). The (str:) macro (along with (num:)) is how you can convert
non-string values to a string.
Details:
This macro can also be used much like the (print:) macro - as it evaluates to a
string, and strings can be placed in the story source freely,
If you give an array to (text:), it will attempt to convert every element
If you give an array to (str:), it will attempt to convert every element
contained in the array to a String, and then join them up with commas. So,
`(text: (a: 2, "Hot", 4, "U"))` will result in the string "2,Hot,4,U".
`(str: (a: 2, "Hot", 4, "U"))` will result in the string "2,Hot,4,U".
If you'd rather this not occur, you can also pass the array's individual
elements using the `...` operator - this will join them with nothing in between.
So, `(text: ...(a: 2, "Hot", 4, "U"))` will result in the string "2Hot4U".
So, `(str: ...(a: 2, "Hot", 4, "U"))` will result in the string "2Hot4U".
See also:
(num:)
......@@ -94,7 +94,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
to do anything more than join() the array.
*/
(_, ...args) => args.join(''),
// (text: accepts a lot of any primitive)
// (str: accepts a lot of any primitive)
[zeroOrMore(Macros.TypeSignature.either(String, Number, Boolean, Array))])
/*d:
......@@ -260,6 +260,39 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
*/
("words", (_, string) => string.split(new RegExp(realWhitespace + "+")).filter(Boolean),
[String])
/*d:
(str-repeated: Number, String) -> String
Also known as: (string-repeated:)
A special shorthand combination of the (str:) and (repeated:) macros, this accepts a single string
and duplicates it the given number of times.
Example usage:
* `(str-repeated: 5, "Fool! ")` produces `"Fool! Fool! Fool! Fool! Fool! "`
Rationale:
This macro is a shorthand form of nesting (repeated:) inside (str:). This example:
`(str: ...(repeated: 14, "-+*+"))` is the same as `(str-repeated: 14, "-+*+")`.
Details:
An error will, of course, be produced if the number given is 0 or less, or contains a fraction.
See also:
(repeated:), (str-rotated:)
#string
*/
(["str-repeated", "string-repeated"], (_, number, string) => {
if (number <= 0) {
return TwineError.create("macrocall",
"I can't repeat this string " + number + " times.");
}
if (string.length === 0) {
return TwineError.create("macrocall", "I can't repeat an empty string.");
}
return string.repeat(number);
},
[parseInt, String])
/*d:
Number data
......@@ -289,7 +322,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
You can only perform these operations (apart from `is`) on two pieces of data if they're both numbers. Adding the
string "5" to the number 2 would produce an error, and not the number 7 nor the string "52". You must
convert one side or the other using the (num:) or (text:) macros.
convert one side or the other using the (num:) or (str:) macros.
*/
/*d:
(num: String) -> Number
......@@ -314,7 +347,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
this macro will be necessary.
See also:
(text:)
(str:)
#number
*/
......
......@@ -371,7 +371,7 @@ function processTextTerms(text, name, allow) {
}
if (typeNamesLinked.indexOf(matchName) === -1) {
typeNamesLinked.push(matchName);
return preceding + linkFn(matchName, "type");
return preceding + linkFn(matchName, "type", matchName + plural);
}
return text;
})
......
......@@ -163,6 +163,8 @@ describe("data structure macros", function () {
it("returns an array containing arguments 1+, rotated by the number", function() {
runPassage("(set: $a to (rotated:1,1,2,3,4))");
expect("(print: $a)").markupToPrint("4,1,2,3");
runPassage("(set: $a to (rotated:-2,1,2,3,4))");
expect("(print: $a)").markupToPrint("3,4,1,2");
});
it("produces an error if the number is greater than the quantity of items", function() {
expect("(rotated:5,1,2,3,4))").markupToError();
......
......@@ -158,4 +158,28 @@ describe("primitive value macros", function() {
expect("(print: (words: 'Golly')'s 1st is 'Golly')").markupToPrint('true');
});
});
describe("the (string-repeated:) macro", function() {
it("accepts 1 integer and 1 string", function() {
expect("(string-repeated:)").markupToError();
expect("(string-repeated:1)").markupToError();
expect("(string-repeated:1,1)").markupToError();
expect("(string-repeated:'A')").markupToError();
expect("(string-repeated:'A',2)").markupToError();
expect("(string-repeated:1,true)").markupToError();
expect("(string-repeated:1.1,'X')").markupToError();
});
it("returns the passed string repeated the given number of times", function() {
runPassage("(set: $a to (string-repeated:4,'garply'))");
expect("(print: $a)").markupToPrint("garplygarplygarplygarply");
runPassage("(set: $b to (string-repeated:8,'x'))");
expect("(print: $b)").markupToPrint("xxxxxxxx");
});
it("produces an error if the number is smaller than 1", function() {
expect("(string-repeated:-2,'grault'))").markupToError();
expect("(string-repeated:0,'grault'))").markupToError();
});
it("produces an error if the string is empty", function() {
expect("(string-repeated:2,'')").markupToError();
});
});
});
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment