Read about our upcoming Code of Conduct on this issue

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 @@ ...@@ -2,6 +2,16 @@
Rough documentation is at http://twine2.neocities.org/. See below for compilation instructions. 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: ###2.1.0 changes:
####Bugfixes ####Bugfixes
...@@ -41,7 +51,7 @@ Rough documentation is at http://twine2.neocities.org/. See below for compilatio ...@@ -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 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 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:))`. * 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 `(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 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. * 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 ...@@ -106,7 +106,7 @@ define(['requestAnimationFrame', 'macros', 'utils', 'state', 'passages', 'engine
`(print: $var + "s")` `(print: $var + "s")`
Details: 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 such as changer commands - but these will usually become bare descriptive
text like `[A (font: ) command]`. You may find this useful for debugging purposes. text like `[A (font: ) command]`. You may find this useful for debugging purposes.
...@@ -124,7 +124,7 @@ define(['requestAnimationFrame', 'macros', 'utils', 'state', 'passages', 'engine ...@@ -124,7 +124,7 @@ define(['requestAnimationFrame', 'macros', 'utils', 'state', 'passages', 'engine
compared to just setting `$p` to a string, but is available nonetheless. compared to just setting `$p` to a string, but is available nonetheless.
See also: See also:
(text:), (display:) (str:), (display:)
#basics 4 #basics 4
*/ */
......
...@@ -582,7 +582,7 @@ define([ ...@@ -582,7 +582,7 @@ define([
and so forth. and so forth.
Incidentally... you can also use this macro to rotate a string's characters, by doing 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: Details:
To ensure that it's being used correctly, this macro requires three or more items - To ensure that it's being used correctly, this macro requires three or more items -
...@@ -679,8 +679,8 @@ define([ ...@@ -679,8 +679,8 @@ define([
However, (interlaced:) can also be of use alongside macros which accept a sequence: you 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 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:). an array with another array of spaces, and then convert them to a string with (str:).
`(text: ...(interlaced: $arr, (repeated: $arr's length, ' '))` will create a string containing `(str: ...(interlaced: $arr, (repeated: $arr's length, ' '))` will create a string containing
each element of $arr, followed by a space. each element of $arr, followed by a space.
Details: Details:
......
...@@ -53,34 +53,34 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal ...@@ -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") | `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: /*d:
(text: ...[Number or String or Boolean or Array]) -> String (str: ...[Number or String or Boolean or Array]) -> String
Also known as: (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. to a single String.
Example usages: Example usages:
* `(text: $cash + 200)` * `(str: $cash + 200)`
* `(if: (text: $cash)'s length > 3)[Phew! Over four digits!]` * `(if: (str: $cash)'s length > 3)[Phew! Over four digits!]`
* `(text: ...$arr)` * `(str: ...$arr)`
Rationale: Rationale:
Unlike in Twine 1 and SugarCube, Twine 2 will only convert numbers into strings, or strings 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 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" 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. non-string values to a string.
Details: Details:
This macro can also be used much like the (print:) macro - as it evaluates to a 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, 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, 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 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. 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: See also:
(num:) (num:)
...@@ -94,7 +94,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal ...@@ -94,7 +94,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
to do anything more than join() the array. to do anything more than join() the array.
*/ */
(_, ...args) => args.join(''), (_, ...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))]) [zeroOrMore(Macros.TypeSignature.either(String, Number, Boolean, Array))])
/*d: /*d:
...@@ -260,6 +260,39 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal ...@@ -260,6 +260,39 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
*/ */
("words", (_, string) => string.split(new RegExp(realWhitespace + "+")).filter(Boolean), ("words", (_, string) => string.split(new RegExp(realWhitespace + "+")).filter(Boolean),
[String]) [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: /*d:
Number data Number data
...@@ -289,7 +322,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal ...@@ -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 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 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: /*d:
(num: String) -> Number (num: String) -> Number
...@@ -314,7 +347,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal ...@@ -314,7 +347,7 @@ define(['macros', 'utils', 'utils/operationutils', 'datatypes/colour', 'internal
this macro will be necessary. this macro will be necessary.
See also: See also:
(text:) (str:)
#number #number
*/ */
......
...@@ -371,7 +371,7 @@ function processTextTerms(text, name, allow) { ...@@ -371,7 +371,7 @@ function processTextTerms(text, name, allow) {
} }
if (typeNamesLinked.indexOf(matchName) === -1) { if (typeNamesLinked.indexOf(matchName) === -1) {
typeNamesLinked.push(matchName); typeNamesLinked.push(matchName);
return preceding + linkFn(matchName, "type"); return preceding + linkFn(matchName, "type", matchName + plural);
} }
return text; return text;
}) })
......
...@@ -163,6 +163,8 @@ describe("data structure macros", function () { ...@@ -163,6 +163,8 @@ describe("data structure macros", function () {
it("returns an array containing arguments 1+, rotated by the number", function() { it("returns an array containing arguments 1+, rotated by the number", function() {
runPassage("(set: $a to (rotated:1,1,2,3,4))"); runPassage("(set: $a to (rotated:1,1,2,3,4))");
expect("(print: $a)").markupToPrint("4,1,2,3"); 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() { it("produces an error if the number is greater than the quantity of items", function() {
expect("(rotated:5,1,2,3,4))").markupToError(); expect("(rotated:5,1,2,3,4))").markupToError();
......
...@@ -158,4 +158,28 @@ describe("primitive value macros", function() { ...@@ -158,4 +158,28 @@ describe("primitive value macros", function() {
expect("(print: (words: 'Golly')'s 1st is 'Golly')").markupToPrint('true'); 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