decasify 0.10.2__tar.gz → 0.11.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {decasify-0.10.2 → decasify-0.11.0}/Cargo.lock +2 -2
- {decasify-0.10.2 → decasify-0.11.0}/Cargo.toml +4 -3
- {decasify-0.10.2 → decasify-0.11.0}/PKG-INFO +1 -1
- {decasify-0.10.2 → decasify-0.11.0}/README.md +4 -4
- {decasify-0.10.2 → decasify-0.11.0}/src/bin/decasify.rs +24 -50
- {decasify-0.10.2 → decasify-0.11.0}/src/content.rs +1 -19
- {decasify-0.10.2 → decasify-0.11.0}/src/lib.rs +64 -33
- decasify-0.11.0/src/lua.rs +190 -0
- {decasify-0.10.2 → decasify-0.11.0}/src/python.rs +11 -5
- {decasify-0.10.2 → decasify-0.11.0}/src/types.rs +103 -57
- {decasify-0.10.2 → decasify-0.11.0}/src/wasm.rs +5 -5
- {decasify-0.10.2 → decasify-0.11.0}/tests/lib.rs +13 -12
- decasify-0.10.2/src/lua.rs +0 -122
- {decasify-0.10.2 → decasify-0.11.0}/build-aux/build.rs +0 -0
- {decasify-0.10.2 → decasify-0.11.0}/pyproject.toml +0 -0
- {decasify-0.10.2 → decasify-0.11.0}/src/cli.rs +0 -0
- {decasify-0.10.2 → decasify-0.11.0}/src/en.rs +0 -0
- {decasify-0.10.2 → decasify-0.11.0}/src/tr.rs +0 -0
- {decasify-0.10.2 → decasify-0.11.0}/src/traits.rs +0 -0
- {decasify-0.10.2 → decasify-0.11.0}/tests/cli.rs +0 -0
|
@@ -307,7 +307,7 @@ dependencies = [
|
|
|
307
307
|
|
|
308
308
|
[[package]]
|
|
309
309
|
name = "decasify"
|
|
310
|
-
version = "0.
|
|
310
|
+
version = "0.11.0"
|
|
311
311
|
dependencies = [
|
|
312
312
|
"anyhow",
|
|
313
313
|
"assert_cmd",
|
|
@@ -1977,7 +1977,7 @@ dependencies = [
|
|
|
1977
1977
|
|
|
1978
1978
|
[[package]]
|
|
1979
1979
|
name = "typst"
|
|
1980
|
-
version = "0.
|
|
1980
|
+
version = "0.11.0"
|
|
1981
1981
|
dependencies = [
|
|
1982
1982
|
"anyhow",
|
|
1983
1983
|
"decasify",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "decasify"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.11.0"
|
|
4
4
|
description = "A CLI utility and library to cast strings to title-case according to locale specific style guides including Turkish support"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
build = "build-aux/build.rs"
|
|
@@ -13,7 +13,7 @@ repository.workspace = true
|
|
|
13
13
|
license.workspace = true
|
|
14
14
|
|
|
15
15
|
[workspace.package]
|
|
16
|
-
version = "0.
|
|
16
|
+
version = "0.11.0"
|
|
17
17
|
authors = ["Caleb Maclennan <caleb@alerque.com>"]
|
|
18
18
|
homepage = "https://github.com/alerque/decasify"
|
|
19
19
|
repository = "https://github.com/alerque/decasify"
|
|
@@ -64,7 +64,7 @@ wasm = ["dep:wasm-bindgen"]
|
|
|
64
64
|
|
|
65
65
|
[workspace.dependencies.decasify]
|
|
66
66
|
path = "."
|
|
67
|
-
version = "0.
|
|
67
|
+
version = "0.11.0"
|
|
68
68
|
|
|
69
69
|
[dependencies]
|
|
70
70
|
regex = "1.11"
|
|
@@ -167,6 +167,7 @@ extend-ignore-identifiers-re = ["[bB][aA][zZ]"]
|
|
|
167
167
|
|
|
168
168
|
[package.metadata.typos.default.extend-words]
|
|
169
169
|
runing = "running"
|
|
170
|
+
walm = "wasm"
|
|
170
171
|
|
|
171
172
|
[package.metadata.typos.files]
|
|
172
173
|
ignore-hidden = false
|
|
@@ -92,7 +92,7 @@ In your `Cargo.toml` file.
|
|
|
92
92
|
|
|
93
93
|
```toml
|
|
94
94
|
[dependencies]
|
|
95
|
-
decasify = "0.
|
|
95
|
+
decasify = "0.11"
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
Then use the crate functions and types in your project something like this:
|
|
@@ -103,10 +103,10 @@ use decasify::{Locale, StyleGuide, StyleOptions};
|
|
|
103
103
|
|
|
104
104
|
fn demo() {
|
|
105
105
|
let input = "ILIK SU VE İTEN RÜZGARLAR";
|
|
106
|
-
let output = titlecase(input, Locale::TR, StyleGuide::LanguageDefault, StyleOptions::default());
|
|
106
|
+
let output = titlecase(input, Locale::TR, StyleGuide::LanguageDefault, StyleOptions::default()).unwrap();
|
|
107
107
|
eprintln! {"{output}"};
|
|
108
108
|
let input = "title with a twist: a colon";
|
|
109
|
-
let output = titlecase(input, Locale::EN, StyleGuide::DaringFireball, StyleOptions::default());
|
|
109
|
+
let output = titlecase(input, Locale::EN, StyleGuide::DaringFireball, StyleOptions::default()).unwrap();
|
|
110
110
|
eprintln! {"{output}"};
|
|
111
111
|
}
|
|
112
112
|
```
|
|
@@ -259,7 +259,7 @@ The [decasify](https://typst.app/universe/package/decasify) package can be added
|
|
|
259
259
|
The exact version must be specified explicitly:
|
|
260
260
|
|
|
261
261
|
```typst
|
|
262
|
-
#import "@preview/decasify:0.
|
|
262
|
+
#import "@preview/decasify:0.11.0": *
|
|
263
263
|
```
|
|
264
264
|
|
|
265
265
|
Specific functions for each case should be available throughout the document.
|
|
@@ -1,53 +1,30 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <caleb@alerque.com>
|
|
2
2
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
3
3
|
|
|
4
|
-
use decasify::cli::Cli;
|
|
5
|
-
use decasify::{lowercase, sentencecase, titlecase, uppercase};
|
|
6
|
-
use decasify::{Case, Locale, StyleGuide, StyleOptions, StyleOptionsBuilder};
|
|
7
|
-
|
|
8
|
-
use snafu::prelude::*;
|
|
9
|
-
|
|
10
4
|
use clap::CommandFactory;
|
|
11
5
|
use std::io;
|
|
12
6
|
use std::io::BufRead;
|
|
13
7
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#[snafu(display("Failed to resolve a known locale"))]
|
|
20
|
-
Locale {},
|
|
21
|
-
|
|
22
|
-
#[snafu(display("Failed to resolve a known case"))]
|
|
23
|
-
Case {},
|
|
24
|
-
|
|
25
|
-
#[snafu(display("Failed to resolve a known style guide"))]
|
|
26
|
-
StyleGuide {},
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Clap CLI errors are reported using the Debug trait, but Snafu sets up the Display trait.
|
|
30
|
-
// So we delegate. c.f. https://github.com/shepmaster/snafu/issues/110
|
|
31
|
-
impl std::fmt::Debug for Error {
|
|
32
|
-
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
33
|
-
std::fmt::Display::fmt(self, fmt)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
type Result<T, E = Error> = std::result::Result<T, E>;
|
|
8
|
+
use decasify::cli::Cli;
|
|
9
|
+
use decasify::types::Result;
|
|
10
|
+
use decasify::{lowercase, sentencecase, titlecase, uppercase};
|
|
11
|
+
use decasify::{Case, Locale, StyleGuide, StyleOptions, StyleOptionsBuilder};
|
|
38
12
|
|
|
39
13
|
fn main() -> Result<()> {
|
|
40
14
|
let version = option_env!("VERGEN_GIT_DESCRIBE").unwrap_or_else(|| env!("CARGO_PKG_VERSION"));
|
|
41
15
|
let app = Cli::command().version(version);
|
|
42
16
|
let matches = app.get_matches();
|
|
43
|
-
let locale = matches
|
|
17
|
+
let locale = matches
|
|
18
|
+
.get_one::<Locale>("locale")
|
|
19
|
+
.unwrap_or(&Locale::default())
|
|
20
|
+
.to_owned();
|
|
44
21
|
let case = matches
|
|
45
22
|
.get_one::<Case>("case")
|
|
46
|
-
.
|
|
23
|
+
.unwrap_or(&Case::default())
|
|
47
24
|
.to_owned();
|
|
48
25
|
let style = matches
|
|
49
26
|
.get_one::<StyleGuide>("style")
|
|
50
|
-
.
|
|
27
|
+
.unwrap_or(&StyleGuide::default())
|
|
51
28
|
.to_owned();
|
|
52
29
|
let opts = if let Some(overrides) = matches.get_many::<String>("overrides") {
|
|
53
30
|
StyleOptionsBuilder::new()
|
|
@@ -60,27 +37,23 @@ fn main() -> Result<()> {
|
|
|
60
37
|
true => {
|
|
61
38
|
let input: Vec<String> = matches
|
|
62
39
|
.get_many::<String>("input")
|
|
63
|
-
.
|
|
40
|
+
.unwrap()
|
|
64
41
|
.cloned()
|
|
65
42
|
.collect();
|
|
66
43
|
let input: Vec<String> = vec![input.join(" ")];
|
|
67
44
|
process(
|
|
68
45
|
input.iter().map(|ln| ln.to_string()),
|
|
69
|
-
|
|
46
|
+
locale,
|
|
70
47
|
case,
|
|
71
48
|
style,
|
|
72
49
|
opts,
|
|
73
|
-
)
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
false => {
|
|
53
|
+
let stdin = io::stdin().lock().lines().map(|ln| ln.unwrap());
|
|
54
|
+
process(stdin, locale, case, style, opts)
|
|
74
55
|
}
|
|
75
|
-
false => process(
|
|
76
|
-
io::stdin().lock().lines().map(|ln| ln.unwrap()),
|
|
77
|
-
*locale,
|
|
78
|
-
case,
|
|
79
|
-
style,
|
|
80
|
-
opts,
|
|
81
|
-
),
|
|
82
56
|
}
|
|
83
|
-
Ok(())
|
|
84
57
|
}
|
|
85
58
|
|
|
86
59
|
fn process<I: IntoIterator<Item = String>>(
|
|
@@ -89,15 +62,16 @@ fn process<I: IntoIterator<Item = String>>(
|
|
|
89
62
|
case: Case,
|
|
90
63
|
style: StyleGuide,
|
|
91
64
|
opts: StyleOptions,
|
|
92
|
-
) {
|
|
65
|
+
) -> Result<()> {
|
|
93
66
|
for string in strings {
|
|
94
67
|
let output = match case {
|
|
95
|
-
Case::Title => titlecase(string, locale, style.clone(), opts.clone())
|
|
96
|
-
Case::Lower => lowercase(string, locale)
|
|
97
|
-
Case::Upper => uppercase(string, locale)
|
|
98
|
-
Case::Sentence => sentencecase(string, locale)
|
|
68
|
+
Case::Title => titlecase(string, locale, style.clone(), opts.clone())?,
|
|
69
|
+
Case::Lower => lowercase(string, locale)?,
|
|
70
|
+
Case::Upper => uppercase(string, locale)?,
|
|
71
|
+
Case::Sentence => sentencecase(string, locale)?,
|
|
99
72
|
_ => unreachable!(),
|
|
100
73
|
};
|
|
101
|
-
println!("{output}")
|
|
74
|
+
println!("{output}");
|
|
102
75
|
}
|
|
76
|
+
Ok(())
|
|
103
77
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <caleb@alerque.com>
|
|
2
2
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
3
3
|
|
|
4
|
-
pub use crate::types::Word;
|
|
5
|
-
|
|
6
4
|
use regex::Regex;
|
|
7
5
|
use std::{borrow::Cow, fmt, fmt::Display, str::FromStr};
|
|
8
6
|
use unicode_titlecase::StrTitleCase;
|
|
9
7
|
|
|
10
|
-
use
|
|
8
|
+
use crate::types::{Error, Result, Word};
|
|
11
9
|
|
|
12
10
|
#[derive(Clone, Debug)]
|
|
13
11
|
#[non_exhaustive]
|
|
@@ -22,22 +20,6 @@ pub enum Segment {
|
|
|
22
20
|
Word(Word),
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
#[derive(Snafu)]
|
|
26
|
-
pub enum Error {
|
|
27
|
-
#[snafu(display("Unable to cast str to Chunk"))]
|
|
28
|
-
StrToChunk {},
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Clap CLI errors are reported using the Debug trait, but Snafu sets up the Display trait.
|
|
32
|
-
// So we delegate. c.f. https://github.com/shepmaster/snafu/issues/110
|
|
33
|
-
impl std::fmt::Debug for Error {
|
|
34
|
-
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
35
|
-
std::fmt::Display::fmt(self, fmt)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
|
40
|
-
|
|
41
23
|
fn split_chunk(s: &str) -> Chunk {
|
|
42
24
|
let mut segments: Vec<Segment> = Vec::new();
|
|
43
25
|
let captures = Regex::new(r"(?<separator>\p{Whitespace}+)|(?<word>\P{Whitespace}+)").unwrap();
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
mod content;
|
|
8
8
|
mod traits;
|
|
9
|
-
mod types;
|
|
9
|
+
pub mod types;
|
|
10
10
|
|
|
11
11
|
pub use content::Chunk;
|
|
12
12
|
#[cfg(feature = "unstable-trait")]
|
|
13
13
|
pub use traits::Decasify;
|
|
14
14
|
pub use types::{Case, Locale, StyleGuide, StyleOptions, StyleOptionsBuilder, Word};
|
|
15
|
+
pub use types::{Error, Result};
|
|
15
16
|
|
|
16
17
|
#[cfg(feature = "cli")]
|
|
17
18
|
#[doc(hidden)]
|
|
@@ -33,18 +34,28 @@ mod en;
|
|
|
33
34
|
mod tr;
|
|
34
35
|
|
|
35
36
|
/// Convert a string to a specific case following typesetting conventions for a target locale
|
|
36
|
-
pub fn case(
|
|
37
|
+
pub fn case<TC, TL, TS, TO>(
|
|
37
38
|
chunk: impl Into<Chunk>,
|
|
38
|
-
case:
|
|
39
|
-
locale:
|
|
40
|
-
style:
|
|
41
|
-
opts:
|
|
42
|
-
) -> String
|
|
39
|
+
case: TC,
|
|
40
|
+
locale: TL,
|
|
41
|
+
style: TS,
|
|
42
|
+
opts: TO,
|
|
43
|
+
) -> Result<String>
|
|
44
|
+
where
|
|
45
|
+
TC: TryInto<Case>,
|
|
46
|
+
TL: TryInto<Locale>,
|
|
47
|
+
TS: TryInto<StyleGuide>,
|
|
48
|
+
TO: TryInto<StyleOptions>,
|
|
49
|
+
Error: From<TC::Error>,
|
|
50
|
+
Error: From<TL::Error>,
|
|
51
|
+
Error: From<TS::Error>,
|
|
52
|
+
Error: From<TO::Error>,
|
|
53
|
+
{
|
|
43
54
|
let chunk: Chunk = chunk.into();
|
|
44
|
-
let case: Case = case.
|
|
45
|
-
let locale: Locale = locale.
|
|
46
|
-
let style: StyleGuide = style.
|
|
47
|
-
let opts: StyleOptions = opts.
|
|
55
|
+
let case: Case = case.try_into()?;
|
|
56
|
+
let locale: Locale = locale.try_into()?;
|
|
57
|
+
let style: StyleGuide = style.try_into()?;
|
|
58
|
+
let opts: StyleOptions = opts.try_into()?;
|
|
48
59
|
match case {
|
|
49
60
|
Case::Lower => lowercase(chunk, locale),
|
|
50
61
|
Case::Upper => uppercase(chunk, locale),
|
|
@@ -54,50 +65,70 @@ pub fn case(
|
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
/// Convert a string to title case following typesetting conventions for a target locale
|
|
57
|
-
pub fn titlecase(
|
|
68
|
+
pub fn titlecase<TL, TS, TO>(
|
|
58
69
|
chunk: impl Into<Chunk>,
|
|
59
|
-
locale:
|
|
60
|
-
style:
|
|
61
|
-
opts:
|
|
62
|
-
) -> String
|
|
70
|
+
locale: TL,
|
|
71
|
+
style: TS,
|
|
72
|
+
opts: TO,
|
|
73
|
+
) -> Result<String>
|
|
74
|
+
where
|
|
75
|
+
TL: TryInto<Locale>,
|
|
76
|
+
TS: TryInto<StyleGuide>,
|
|
77
|
+
TO: TryInto<StyleOptions>,
|
|
78
|
+
Error: From<TL::Error>,
|
|
79
|
+
Error: From<TS::Error>,
|
|
80
|
+
Error: From<TO::Error>,
|
|
81
|
+
{
|
|
63
82
|
let chunk: Chunk = chunk.into();
|
|
64
|
-
let locale: Locale = locale.
|
|
65
|
-
let style: StyleGuide = style.
|
|
66
|
-
let opts: StyleOptions = opts.
|
|
67
|
-
match locale {
|
|
83
|
+
let locale: Locale = locale.try_into()?;
|
|
84
|
+
let style: StyleGuide = style.try_into()?;
|
|
85
|
+
let opts: StyleOptions = opts.try_into()?;
|
|
86
|
+
Ok(match locale {
|
|
68
87
|
Locale::EN => en::titlecase(chunk, style, opts),
|
|
69
88
|
Locale::TR => tr::titlecase(chunk, style, opts),
|
|
70
|
-
}
|
|
89
|
+
})
|
|
71
90
|
}
|
|
72
91
|
|
|
73
92
|
/// Convert a string to lower case following typesetting conventions for a target locale
|
|
74
|
-
pub fn lowercase(chunk: impl Into<Chunk>, locale:
|
|
93
|
+
pub fn lowercase<TL>(chunk: impl Into<Chunk>, locale: TL) -> Result<String>
|
|
94
|
+
where
|
|
95
|
+
TL: TryInto<Locale>,
|
|
96
|
+
Error: From<TL::Error>,
|
|
97
|
+
{
|
|
75
98
|
let chunk: Chunk = chunk.into();
|
|
76
|
-
let locale: Locale = locale.
|
|
77
|
-
match locale {
|
|
99
|
+
let locale: Locale = locale.try_into()?;
|
|
100
|
+
Ok(match locale {
|
|
78
101
|
Locale::EN => en::lowercase(chunk),
|
|
79
102
|
Locale::TR => tr::lowercase(chunk),
|
|
80
|
-
}
|
|
103
|
+
})
|
|
81
104
|
}
|
|
82
105
|
|
|
83
106
|
/// Convert a string to upper case following typesetting conventions for a target locale
|
|
84
|
-
pub fn uppercase(chunk: impl Into<Chunk>, locale:
|
|
107
|
+
pub fn uppercase<TL>(chunk: impl Into<Chunk>, locale: TL) -> Result<String>
|
|
108
|
+
where
|
|
109
|
+
TL: TryInto<Locale>,
|
|
110
|
+
Error: From<TL::Error>,
|
|
111
|
+
{
|
|
85
112
|
let chunk: Chunk = chunk.into();
|
|
86
|
-
let locale: Locale = locale.
|
|
87
|
-
match locale {
|
|
113
|
+
let locale: Locale = locale.try_into()?;
|
|
114
|
+
Ok(match locale {
|
|
88
115
|
Locale::EN => en::uppercase(chunk),
|
|
89
116
|
Locale::TR => tr::uppercase(chunk),
|
|
90
|
-
}
|
|
117
|
+
})
|
|
91
118
|
}
|
|
92
119
|
|
|
93
120
|
/// Convert a string to sentence case following typesetting conventions for a target locale
|
|
94
|
-
pub fn sentencecase(chunk: impl Into<Chunk>, locale:
|
|
121
|
+
pub fn sentencecase<TL>(chunk: impl Into<Chunk>, locale: TL) -> Result<String>
|
|
122
|
+
where
|
|
123
|
+
TL: TryInto<Locale>,
|
|
124
|
+
Error: From<TL::Error>,
|
|
125
|
+
{
|
|
95
126
|
let chunk: Chunk = chunk.into();
|
|
96
|
-
let locale: Locale = locale.
|
|
97
|
-
match locale {
|
|
127
|
+
let locale: Locale = locale.try_into()?;
|
|
128
|
+
Ok(match locale {
|
|
98
129
|
Locale::EN => en::sentencecase(chunk),
|
|
99
130
|
Locale::TR => tr::sentencecase(chunk),
|
|
100
|
-
}
|
|
131
|
+
})
|
|
101
132
|
}
|
|
102
133
|
|
|
103
134
|
fn get_override<F>(word: &Word, overrides: &Option<Vec<Word>>, case_fn: F) -> Option<Word>
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <caleb@alerque.com>
|
|
2
|
+
// SPDX-License-Identifier: LGPL-3.0-only
|
|
3
|
+
|
|
4
|
+
use crate::*;
|
|
5
|
+
use mlua::prelude::*;
|
|
6
|
+
|
|
7
|
+
use crate::types::{Error, Result};
|
|
8
|
+
|
|
9
|
+
macro_rules! impl_into_luaresult {
|
|
10
|
+
($($t:ty),*) => {
|
|
11
|
+
$(
|
|
12
|
+
impl Into<LuaResult<$t>> for $t {
|
|
13
|
+
fn into(self) -> LuaResult<$t> {
|
|
14
|
+
Ok(self)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
)*
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl_into_luaresult!(Locale, Case, StyleGuide, StyleOptions);
|
|
22
|
+
|
|
23
|
+
impl From<Error> for LuaError {
|
|
24
|
+
fn from(err: Error) -> LuaError {
|
|
25
|
+
LuaError::RuntimeError(err.to_string())
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
impl TryFrom<LuaString> for Locale {
|
|
30
|
+
type Error = Error;
|
|
31
|
+
fn try_from(s: LuaString) -> Result<Self> {
|
|
32
|
+
s.to_string_lossy().try_into()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
impl TryFrom<LuaString> for Case {
|
|
37
|
+
type Error = Error;
|
|
38
|
+
fn try_from(s: LuaString) -> Result<Self> {
|
|
39
|
+
s.to_string_lossy().try_into()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
impl TryFrom<LuaString> for StyleGuide {
|
|
44
|
+
type Error = Error;
|
|
45
|
+
fn try_from(s: LuaString) -> Result<Self> {
|
|
46
|
+
s.to_string_lossy().try_into()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[mlua::lua_module]
|
|
51
|
+
fn decasify(lua: &Lua) -> LuaResult<LuaTable> {
|
|
52
|
+
let exports = lua.create_table()?;
|
|
53
|
+
exports.set(
|
|
54
|
+
"case",
|
|
55
|
+
lua.create_function(
|
|
56
|
+
|_,
|
|
57
|
+
(chunk, case_, locale, styleguide, styleoptions): (
|
|
58
|
+
Chunk,
|
|
59
|
+
Case,
|
|
60
|
+
Locale,
|
|
61
|
+
StyleGuide,
|
|
62
|
+
StyleOptions,
|
|
63
|
+
)| { Ok(case(chunk, case_, locale, styleguide, styleoptions)?) },
|
|
64
|
+
)?,
|
|
65
|
+
)?;
|
|
66
|
+
exports.set(
|
|
67
|
+
"titlecase",
|
|
68
|
+
lua.create_function(
|
|
69
|
+
|_,
|
|
70
|
+
(chunk, locale, styleguide, styleoptions): (
|
|
71
|
+
Chunk,
|
|
72
|
+
Locale,
|
|
73
|
+
StyleGuide,
|
|
74
|
+
StyleOptions,
|
|
75
|
+
)| { Ok(titlecase(chunk, locale, styleguide, styleoptions)?) },
|
|
76
|
+
)?,
|
|
77
|
+
)?;
|
|
78
|
+
exports.set(
|
|
79
|
+
"lowercase",
|
|
80
|
+
lua.create_function(|_, (chunk, locale): (Chunk, Locale)| Ok(lowercase(chunk, locale)?))?,
|
|
81
|
+
)?;
|
|
82
|
+
exports.set(
|
|
83
|
+
"uppercase",
|
|
84
|
+
lua.create_function(|_, (chunk, locale): (Chunk, Locale)| Ok(uppercase(chunk, locale)?))?,
|
|
85
|
+
)?;
|
|
86
|
+
exports.set(
|
|
87
|
+
"sentencecase",
|
|
88
|
+
lua.create_function(|_, (chunk, locale): (Chunk, Locale)| {
|
|
89
|
+
Ok(sentencecase(chunk, locale)?)
|
|
90
|
+
})?,
|
|
91
|
+
)?;
|
|
92
|
+
let mt = lua.create_table()?;
|
|
93
|
+
let decasify = lua.create_function(
|
|
94
|
+
move |_,
|
|
95
|
+
(_, chunk, case_, locale, styleguide, styleoptions): (
|
|
96
|
+
LuaTable,
|
|
97
|
+
Chunk,
|
|
98
|
+
Case,
|
|
99
|
+
Locale,
|
|
100
|
+
StyleGuide,
|
|
101
|
+
Option<StyleOptions>,
|
|
102
|
+
)| {
|
|
103
|
+
Ok(case(
|
|
104
|
+
chunk,
|
|
105
|
+
case_,
|
|
106
|
+
locale,
|
|
107
|
+
styleguide,
|
|
108
|
+
styleoptions.unwrap_or_default(),
|
|
109
|
+
)?)
|
|
110
|
+
},
|
|
111
|
+
)?;
|
|
112
|
+
mt.set("__call", decasify)?;
|
|
113
|
+
exports.set_metatable(Some(mt))?;
|
|
114
|
+
let version = option_env!("VERGEN_GIT_DESCRIBE").unwrap_or_else(|| env!("CARGO_PKG_VERSION"));
|
|
115
|
+
let version = lua.create_string(version)?;
|
|
116
|
+
exports.set("version", version)?;
|
|
117
|
+
Ok(exports)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
121
|
+
impl FromLua for Chunk {
|
|
122
|
+
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
123
|
+
let chunk = match value {
|
|
124
|
+
LuaValue::String(s) => s.to_string_lossy(),
|
|
125
|
+
_ => String::from(""),
|
|
126
|
+
}
|
|
127
|
+
.into();
|
|
128
|
+
Ok(chunk)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
133
|
+
impl FromLua for Locale {
|
|
134
|
+
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
135
|
+
match value {
|
|
136
|
+
LuaValue::String(s) => s.try_into()?,
|
|
137
|
+
LuaValue::Nil => Self::default(),
|
|
138
|
+
_ => value.to_string().unwrap_or_default().try_into()?,
|
|
139
|
+
}
|
|
140
|
+
.into()
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
145
|
+
impl FromLua for Case {
|
|
146
|
+
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
147
|
+
match value {
|
|
148
|
+
LuaValue::String(s) => s.try_into()?,
|
|
149
|
+
LuaValue::Nil => Self::default(),
|
|
150
|
+
_ => value.to_string().unwrap_or_default().try_into()?,
|
|
151
|
+
}
|
|
152
|
+
.into()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
157
|
+
impl FromLua for StyleGuide {
|
|
158
|
+
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
159
|
+
match value {
|
|
160
|
+
LuaValue::String(s) => s.try_into()?,
|
|
161
|
+
LuaValue::Nil => Self::default(),
|
|
162
|
+
_ => value.to_string().unwrap_or_default().try_into()?,
|
|
163
|
+
}
|
|
164
|
+
.into()
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
169
|
+
impl FromLua for StyleOptions {
|
|
170
|
+
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
171
|
+
match value {
|
|
172
|
+
LuaValue::Table(t) => {
|
|
173
|
+
let mut builder = StyleOptionsBuilder::new();
|
|
174
|
+
if let Ok(overrides_table) = t.get::<LuaTable>("overrides") {
|
|
175
|
+
let overrides: Vec<Word> = overrides_table
|
|
176
|
+
.sequence_values::<String>()
|
|
177
|
+
.collect::<LuaResult<Vec<_>>>()?
|
|
178
|
+
.into_iter()
|
|
179
|
+
.map(|s| s.into())
|
|
180
|
+
.collect();
|
|
181
|
+
builder = builder.overrides(overrides);
|
|
182
|
+
}
|
|
183
|
+
builder.build()
|
|
184
|
+
}
|
|
185
|
+
LuaValue::Nil => Self::default(),
|
|
186
|
+
_ => value.to_string().unwrap_or_default().try_into()?,
|
|
187
|
+
}
|
|
188
|
+
.into()
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
use crate::types::*;
|
|
5
5
|
use pyo3::prelude::*;
|
|
6
6
|
|
|
7
|
+
impl From<crate::types::Error> for PyErr {
|
|
8
|
+
fn from(err: crate::types::Error) -> Self {
|
|
9
|
+
pyo3::exceptions::PyValueError::new_err(err.to_string())
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
#[pymodule]
|
|
8
14
|
fn decasify(module: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
9
15
|
module.add_class::<Case>()?;
|
|
@@ -33,7 +39,7 @@ fn case(
|
|
|
33
39
|
Some(words) => StyleOptionsBuilder::new().overrides(words).build(),
|
|
34
40
|
None => StyleOptions::default(),
|
|
35
41
|
};
|
|
36
|
-
Ok(crate::case(&input, case, locale, style, opts))
|
|
42
|
+
Ok(crate::case(&input, case, locale, style, opts)?)
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
#[pyfunction]
|
|
@@ -48,23 +54,23 @@ fn titlecase(
|
|
|
48
54
|
Some(words) => StyleOptionsBuilder::new().overrides(words).build(),
|
|
49
55
|
None => StyleOptions::default(),
|
|
50
56
|
};
|
|
51
|
-
Ok(crate::titlecase(&input, locale, style, opts))
|
|
57
|
+
Ok(crate::titlecase(&input, locale, style, opts)?)
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
#[pyfunction]
|
|
55
61
|
#[pyo3(signature = (input, locale))]
|
|
56
62
|
fn lowercase(input: String, locale: Locale) -> PyResult<String> {
|
|
57
|
-
Ok(crate::lowercase(&input, locale))
|
|
63
|
+
Ok(crate::lowercase(&input, locale)?)
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
#[pyfunction]
|
|
61
67
|
#[pyo3(signature = (input, locale))]
|
|
62
68
|
fn uppercase(input: String, locale: Locale) -> PyResult<String> {
|
|
63
|
-
Ok(crate::uppercase(&input, locale))
|
|
69
|
+
Ok(crate::uppercase(&input, locale)?)
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
#[pyfunction]
|
|
67
73
|
#[pyo3(signature = (input, locale))]
|
|
68
74
|
fn sentencecase(input: String, locale: Locale) -> PyResult<String> {
|
|
69
|
-
Ok(crate::sentencecase(&input, locale))
|
|
75
|
+
Ok(crate::sentencecase(&input, locale)?)
|
|
70
76
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <caleb@alerque.com>
|
|
2
2
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
3
3
|
|
|
4
|
+
use snafu::prelude::*;
|
|
5
|
+
use std::convert::{Infallible, TryFrom};
|
|
6
|
+
use std::fmt::{Debug, Display, Formatter};
|
|
4
7
|
use std::str::FromStr;
|
|
5
8
|
use strum_macros::{Display, VariantNames};
|
|
6
9
|
|
|
7
|
-
use snafu::prelude::*;
|
|
8
|
-
|
|
9
10
|
#[cfg(feature = "pythonmodule")]
|
|
10
11
|
use pyo3::prelude::*;
|
|
11
12
|
|
|
@@ -13,25 +14,32 @@ use pyo3::prelude::*;
|
|
|
13
14
|
use wasm_bindgen::prelude::*;
|
|
14
15
|
|
|
15
16
|
#[derive(Snafu)]
|
|
17
|
+
#[snafu(visibility(pub))]
|
|
16
18
|
pub enum Error {
|
|
17
|
-
#[snafu(display("Invalid input language {}"
|
|
19
|
+
#[snafu(display("Invalid input language '{input}'"))]
|
|
18
20
|
Locale { input: String },
|
|
19
21
|
|
|
20
|
-
#[snafu(display("Invalid target case {}"
|
|
22
|
+
#[snafu(display("Invalid target case '{input}'"))]
|
|
21
23
|
Case { input: String },
|
|
22
24
|
|
|
23
|
-
#[snafu(display("Invalid preferred style guide {}"
|
|
25
|
+
#[snafu(display("Invalid preferred style guide '{input}'"))]
|
|
24
26
|
StyleGuide { input: String },
|
|
25
27
|
|
|
26
|
-
#[snafu(display("Invalid style options {}"
|
|
28
|
+
#[snafu(display("Invalid style options '{input}'"))]
|
|
27
29
|
StyleOptions { input: String },
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
// Clap CLI errors are reported using the Debug trait, but Snafu sets up the Display trait.
|
|
31
33
|
// So we delegate. c.f. https://github.com/shepmaster/snafu/issues/110
|
|
32
|
-
impl
|
|
33
|
-
fn fmt(&self, fmt: &mut
|
|
34
|
-
|
|
34
|
+
impl Debug for Error {
|
|
35
|
+
fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
|
|
36
|
+
Display::fmt(self, fmt)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
impl From<Infallible> for Error {
|
|
41
|
+
fn from(_: Infallible) -> Self {
|
|
42
|
+
unreachable!()
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
45
|
|
|
@@ -99,12 +107,6 @@ pub struct StyleOptions {
|
|
|
99
107
|
pub overrides: Option<Vec<Word>>,
|
|
100
108
|
}
|
|
101
109
|
|
|
102
|
-
impl From<&str> for StyleOptions {
|
|
103
|
-
fn from(s: &str) -> Self {
|
|
104
|
-
Self::from_str(s).unwrap()
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
110
|
impl FromStr for StyleOptions {
|
|
109
111
|
type Err = Error;
|
|
110
112
|
fn from_str(s: &str) -> Result<Self> {
|
|
@@ -115,6 +117,35 @@ impl FromStr for StyleOptions {
|
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
impl TryFrom<&str> for StyleOptions {
|
|
121
|
+
type Error = Error;
|
|
122
|
+
fn try_from(s: &str) -> Result<Self> {
|
|
123
|
+
Self::from_str(s)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
impl TryFrom<String> for StyleOptions {
|
|
128
|
+
type Error = Error;
|
|
129
|
+
fn try_from(s: String) -> Result<Self> {
|
|
130
|
+
Self::from_str(&s)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
impl TryFrom<&String> for StyleOptions {
|
|
135
|
+
type Error = Error;
|
|
136
|
+
fn try_from(s: &String) -> Result<Self> {
|
|
137
|
+
Self::from_str(s)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
impl TryFrom<&[u8]> for StyleOptions {
|
|
142
|
+
type Error = Error;
|
|
143
|
+
fn try_from(s: &[u8]) -> Result<Self> {
|
|
144
|
+
let s = String::from_utf8_lossy(s);
|
|
145
|
+
Self::from_str(&s)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
118
149
|
#[derive(Debug)]
|
|
119
150
|
pub struct StyleOptionsBuilder {
|
|
120
151
|
overrides: Option<Vec<Word>>,
|
|
@@ -155,28 +186,33 @@ impl FromStr for Locale {
|
|
|
155
186
|
}
|
|
156
187
|
}
|
|
157
188
|
|
|
158
|
-
impl
|
|
159
|
-
|
|
160
|
-
|
|
189
|
+
impl TryFrom<&str> for Locale {
|
|
190
|
+
type Error = Error;
|
|
191
|
+
fn try_from(s: &str) -> Result<Self> {
|
|
192
|
+
Self::from_str(s)
|
|
161
193
|
}
|
|
162
194
|
}
|
|
163
195
|
|
|
164
|
-
impl
|
|
165
|
-
|
|
166
|
-
|
|
196
|
+
impl TryFrom<String> for Locale {
|
|
197
|
+
type Error = Error;
|
|
198
|
+
fn try_from(s: String) -> Result<Self> {
|
|
199
|
+
Self::from_str(&s)
|
|
167
200
|
}
|
|
168
201
|
}
|
|
169
202
|
|
|
170
|
-
impl
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
impl TryFrom<&String> for Locale {
|
|
204
|
+
type Error = Error;
|
|
205
|
+
fn try_from(s: &String) -> Result<Self> {
|
|
206
|
+
Self::from_str(s)
|
|
173
207
|
}
|
|
174
208
|
}
|
|
175
209
|
|
|
176
|
-
impl
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
210
|
+
impl TryFrom<&[u8]> for Locale {
|
|
211
|
+
type Error = Error;
|
|
212
|
+
|
|
213
|
+
fn try_from(s: &[u8]) -> Result<Self> {
|
|
214
|
+
let s = String::from_utf8_lossy(s);
|
|
215
|
+
Self::from_str(&s)
|
|
180
216
|
}
|
|
181
217
|
}
|
|
182
218
|
|
|
@@ -193,28 +229,33 @@ impl FromStr for Case {
|
|
|
193
229
|
}
|
|
194
230
|
}
|
|
195
231
|
|
|
196
|
-
impl
|
|
197
|
-
|
|
198
|
-
|
|
232
|
+
impl TryFrom<&str> for Case {
|
|
233
|
+
type Error = Error;
|
|
234
|
+
fn try_from(s: &str) -> Result<Self> {
|
|
235
|
+
Self::from_str(s)
|
|
199
236
|
}
|
|
200
237
|
}
|
|
201
238
|
|
|
202
|
-
impl
|
|
203
|
-
|
|
204
|
-
|
|
239
|
+
impl TryFrom<String> for Case {
|
|
240
|
+
type Error = Error;
|
|
241
|
+
fn try_from(s: String) -> Result<Self> {
|
|
242
|
+
Self::from_str(&s)
|
|
205
243
|
}
|
|
206
244
|
}
|
|
207
245
|
|
|
208
|
-
impl
|
|
209
|
-
|
|
210
|
-
|
|
246
|
+
impl TryFrom<&String> for Case {
|
|
247
|
+
type Error = Error;
|
|
248
|
+
fn try_from(s: &String) -> Result<Self> {
|
|
249
|
+
Self::from_str(s)
|
|
211
250
|
}
|
|
212
251
|
}
|
|
213
252
|
|
|
214
|
-
impl
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
253
|
+
impl TryFrom<&[u8]> for Case {
|
|
254
|
+
type Error = Error;
|
|
255
|
+
|
|
256
|
+
fn try_from(s: &[u8]) -> Result<Self> {
|
|
257
|
+
let s = String::from_utf8_lossy(s);
|
|
258
|
+
Self::from_str(&s)
|
|
218
259
|
}
|
|
219
260
|
}
|
|
220
261
|
|
|
@@ -234,28 +275,24 @@ impl FromStr for StyleGuide {
|
|
|
234
275
|
}
|
|
235
276
|
}
|
|
236
277
|
|
|
237
|
-
impl
|
|
238
|
-
|
|
239
|
-
|
|
278
|
+
impl TryFrom<&str> for StyleGuide {
|
|
279
|
+
type Error = Error;
|
|
280
|
+
fn try_from(s: &str) -> Result<Self> {
|
|
281
|
+
Self::from_str(s)
|
|
240
282
|
}
|
|
241
283
|
}
|
|
242
284
|
|
|
243
|
-
impl
|
|
244
|
-
|
|
245
|
-
|
|
285
|
+
impl TryFrom<String> for StyleGuide {
|
|
286
|
+
type Error = Error;
|
|
287
|
+
fn try_from(s: String) -> Result<Self> {
|
|
288
|
+
Self::from_str(&s)
|
|
246
289
|
}
|
|
247
290
|
}
|
|
248
291
|
|
|
249
|
-
impl
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
impl From<&[u8]> for StyleGuide {
|
|
256
|
-
fn from(s: &[u8]) -> Self {
|
|
257
|
-
let s = String::from_utf8(s.to_vec()).unwrap();
|
|
258
|
-
Self::from_str(s.as_ref()).unwrap()
|
|
292
|
+
impl TryFrom<&String> for StyleGuide {
|
|
293
|
+
type Error = Error;
|
|
294
|
+
fn try_from(s: &String) -> Result<Self> {
|
|
295
|
+
Self::from_str(s)
|
|
259
296
|
}
|
|
260
297
|
}
|
|
261
298
|
|
|
@@ -267,3 +304,12 @@ impl From<Option<StyleGuide>> for StyleGuide {
|
|
|
267
304
|
}
|
|
268
305
|
}
|
|
269
306
|
}
|
|
307
|
+
|
|
308
|
+
impl TryFrom<&[u8]> for StyleGuide {
|
|
309
|
+
type Error = Error;
|
|
310
|
+
|
|
311
|
+
fn try_from(s: &[u8]) -> Result<Self> {
|
|
312
|
+
let s = String::from_utf8_lossy(s);
|
|
313
|
+
Self::from_str(&s)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -15,7 +15,7 @@ pub fn case(
|
|
|
15
15
|
opts: Option<StyleOptions>,
|
|
16
16
|
) -> Result<String, JsError> {
|
|
17
17
|
let opts = opts.unwrap_or_default();
|
|
18
|
-
Ok(crate::case(input, case, locale, style, opts))
|
|
18
|
+
Ok(crate::case(input, case, locale, style, opts)?)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
#[wasm_bindgen]
|
|
@@ -26,20 +26,20 @@ pub fn titlecase(
|
|
|
26
26
|
opts: Option<StyleOptions>,
|
|
27
27
|
) -> Result<String, JsError> {
|
|
28
28
|
let opts = opts.unwrap_or_default();
|
|
29
|
-
Ok(crate::titlecase(input, locale, style, opts))
|
|
29
|
+
Ok(crate::titlecase(input, locale, style, opts)?)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
#[wasm_bindgen]
|
|
33
33
|
pub fn lowercase(input: &str, locale: Locale) -> Result<String, JsError> {
|
|
34
|
-
Ok(crate::lowercase(input, locale))
|
|
34
|
+
Ok(crate::lowercase(input, locale)?)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
#[wasm_bindgen]
|
|
38
38
|
pub fn uppercase(input: &str, locale: Locale) -> Result<String, JsError> {
|
|
39
|
-
Ok(crate::uppercase(input, locale))
|
|
39
|
+
Ok(crate::uppercase(input, locale)?)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
#[wasm_bindgen]
|
|
43
43
|
pub fn sentencecase(input: &str, locale: Locale) -> Result<String, JsError> {
|
|
44
|
-
Ok(crate::sentencecase(input, locale))
|
|
44
|
+
Ok(crate::sentencecase(input, locale)?)
|
|
45
45
|
}
|
|
@@ -5,11 +5,11 @@ use decasify::*;
|
|
|
5
5
|
|
|
6
6
|
#[test]
|
|
7
7
|
fn cast_from_str() {
|
|
8
|
-
let res = titlecase("FIST", "en", "gruber", "default");
|
|
8
|
+
let res = titlecase("FIST", "en", "gruber", "default").unwrap();
|
|
9
9
|
assert_eq!(res, "Fist");
|
|
10
|
-
let res = titlecase("FIST", "tr", "", "default");
|
|
10
|
+
let res = titlecase("FIST", "tr", "", "default").unwrap();
|
|
11
11
|
assert_eq!(res, "Fıst");
|
|
12
|
-
let res = titlecase("FIST", "tr", "default", "default");
|
|
12
|
+
let res = titlecase("FIST", "tr", "default", "default").unwrap();
|
|
13
13
|
assert_eq!(res, "Fıst");
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -20,23 +20,24 @@ fn cast_from_legacy_option() {
|
|
|
20
20
|
"en",
|
|
21
21
|
Some(StyleGuide::DaringFireball),
|
|
22
22
|
StyleOptions::default(),
|
|
23
|
-
)
|
|
23
|
+
)
|
|
24
|
+
.unwrap();
|
|
24
25
|
assert_eq!(res, "Fist");
|
|
25
|
-
let res = titlecase("FIST", "en", None, StyleOptions::default());
|
|
26
|
+
let res = titlecase("FIST", "en", None, StyleOptions::default()).unwrap();
|
|
26
27
|
assert_eq!(res, "Fist");
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
#[test]
|
|
30
31
|
fn custom_style_guide() {
|
|
31
32
|
let options: StyleOptions = StyleOptionsBuilder::new().overrides(vec!["fOO"]).build();
|
|
32
|
-
let res = titlecase("foo bar", "tr", StyleGuide::LanguageDefault, options);
|
|
33
|
+
let res = titlecase("foo bar", "tr", StyleGuide::LanguageDefault, options).unwrap();
|
|
33
34
|
assert_eq!(res, "fOO Bar");
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
#[cfg(feature = "unstable-trait")]
|
|
37
38
|
#[test]
|
|
38
39
|
fn trait_chery() {
|
|
39
|
-
use
|
|
40
|
+
use Decasify::Decasify;
|
|
40
41
|
let s = "WHY THE LONG FACE?";
|
|
41
42
|
assert_eq!(s.to_case("sentence", "en", None), "Why the long face?");
|
|
42
43
|
assert_eq!(
|
|
@@ -53,7 +54,7 @@ macro_rules! case {
|
|
|
53
54
|
($name:ident, $case:expr, $locale:expr, $style:expr, $opts:expr, $input:expr, $expected:expr) => {
|
|
54
55
|
#[test]
|
|
55
56
|
fn $name() {
|
|
56
|
-
let actual = case($input, $case, $locale, $style, $opts);
|
|
57
|
+
let actual = case($input, $case, $locale, $style, $opts).unwrap();
|
|
57
58
|
assert_eq!(actual, $expected);
|
|
58
59
|
}
|
|
59
60
|
};
|
|
@@ -103,7 +104,7 @@ macro_rules! titlecase {
|
|
|
103
104
|
($name:ident, $locale:expr, $style:expr, $opts:expr, $input:expr, $expected:expr) => {
|
|
104
105
|
#[test]
|
|
105
106
|
fn $name() {
|
|
106
|
-
let actual = titlecase($input, $locale, $style, $opts);
|
|
107
|
+
let actual = titlecase($input, $locale, $style, $opts).unwrap();
|
|
107
108
|
assert_eq!(actual, $expected);
|
|
108
109
|
}
|
|
109
110
|
};
|
|
@@ -247,7 +248,7 @@ macro_rules! lowercase {
|
|
|
247
248
|
($name:ident, $locale:expr, $input:expr, $expected:expr) => {
|
|
248
249
|
#[test]
|
|
249
250
|
fn $name() {
|
|
250
|
-
let actual = lowercase($input, $locale);
|
|
251
|
+
let actual = lowercase($input, $locale).unwrap();
|
|
251
252
|
assert_eq!(actual, $expected);
|
|
252
253
|
}
|
|
253
254
|
};
|
|
@@ -266,7 +267,7 @@ macro_rules! uppercase {
|
|
|
266
267
|
($name:ident, $locale:expr, $input:expr, $expected:expr) => {
|
|
267
268
|
#[test]
|
|
268
269
|
fn $name() {
|
|
269
|
-
let actual = uppercase($input, $locale);
|
|
270
|
+
let actual = uppercase($input, $locale).unwrap();
|
|
270
271
|
assert_eq!(actual, $expected);
|
|
271
272
|
}
|
|
272
273
|
};
|
|
@@ -285,7 +286,7 @@ macro_rules! sentencecase {
|
|
|
285
286
|
($name:ident, $locale:expr, $input:expr, $expected:expr) => {
|
|
286
287
|
#[test]
|
|
287
288
|
fn $name() {
|
|
288
|
-
let actual = sentencecase($input, $locale);
|
|
289
|
+
let actual = sentencecase($input, $locale).unwrap();
|
|
289
290
|
assert_eq!(actual, $expected);
|
|
290
291
|
}
|
|
291
292
|
};
|
decasify-0.10.2/src/lua.rs
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <caleb@alerque.com>
|
|
2
|
-
// SPDX-License-Identifier: LGPL-3.0-only
|
|
3
|
-
|
|
4
|
-
use crate::*;
|
|
5
|
-
use mlua::prelude::*;
|
|
6
|
-
|
|
7
|
-
#[mlua::lua_module]
|
|
8
|
-
fn decasify(lua: &Lua) -> LuaResult<LuaTable> {
|
|
9
|
-
let exports = lua.create_table()?;
|
|
10
|
-
exports.set(
|
|
11
|
-
"case",
|
|
12
|
-
LuaFunction::wrap_raw::<_, (Chunk, Case, Locale, StyleGuide, StyleOptions)>(case),
|
|
13
|
-
)?;
|
|
14
|
-
exports.set(
|
|
15
|
-
"titlecase",
|
|
16
|
-
LuaFunction::wrap_raw::<_, (Chunk, Locale, StyleGuide, StyleOptions)>(titlecase),
|
|
17
|
-
)?;
|
|
18
|
-
exports.set(
|
|
19
|
-
"lowercase",
|
|
20
|
-
LuaFunction::wrap_raw::<_, (Chunk, Locale)>(lowercase),
|
|
21
|
-
)?;
|
|
22
|
-
exports.set(
|
|
23
|
-
"uppercase",
|
|
24
|
-
LuaFunction::wrap_raw::<_, (Chunk, Locale)>(uppercase),
|
|
25
|
-
)?;
|
|
26
|
-
exports.set(
|
|
27
|
-
"sentencecase",
|
|
28
|
-
LuaFunction::wrap_raw::<_, (Chunk, Locale)>(sentencecase),
|
|
29
|
-
)?;
|
|
30
|
-
let mt = lua.create_table()?;
|
|
31
|
-
let decasify = lua.create_function(
|
|
32
|
-
move |_,
|
|
33
|
-
(_, chunk, case_, locale, styleguide, opts): (
|
|
34
|
-
LuaTable,
|
|
35
|
-
Chunk,
|
|
36
|
-
Case,
|
|
37
|
-
Locale,
|
|
38
|
-
StyleGuide,
|
|
39
|
-
Option<StyleOptions>,
|
|
40
|
-
)| {
|
|
41
|
-
Ok(case(
|
|
42
|
-
chunk,
|
|
43
|
-
case_,
|
|
44
|
-
locale,
|
|
45
|
-
styleguide,
|
|
46
|
-
opts.unwrap_or_default(),
|
|
47
|
-
))
|
|
48
|
-
},
|
|
49
|
-
)?;
|
|
50
|
-
mt.set("__call", decasify)?;
|
|
51
|
-
exports.set_metatable(Some(mt))?;
|
|
52
|
-
let version = option_env!("VERGEN_GIT_DESCRIBE").unwrap_or_else(|| env!("CARGO_PKG_VERSION"));
|
|
53
|
-
let version = lua.create_string(version)?;
|
|
54
|
-
exports.set("version", version)?;
|
|
55
|
-
Ok(exports)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
59
|
-
impl FromLua for Chunk {
|
|
60
|
-
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
61
|
-
match value {
|
|
62
|
-
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
|
|
63
|
-
_ => Ok("".into()),
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
69
|
-
impl FromLua for Locale {
|
|
70
|
-
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
71
|
-
match value {
|
|
72
|
-
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
|
|
73
|
-
LuaValue::Nil => Ok(Self::default()),
|
|
74
|
-
_ => unimplemented!(),
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
80
|
-
impl FromLua for Case {
|
|
81
|
-
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
82
|
-
match value {
|
|
83
|
-
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
|
|
84
|
-
LuaValue::Nil => Ok(Self::default()),
|
|
85
|
-
_ => unimplemented!(),
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
91
|
-
impl FromLua for StyleGuide {
|
|
92
|
-
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
93
|
-
match value {
|
|
94
|
-
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
|
|
95
|
-
LuaValue::Nil => Ok(Self::default()),
|
|
96
|
-
_ => unimplemented!(),
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
#[cfg_attr(docsrs, doc(cfg(feature = "luamodule")))]
|
|
102
|
-
impl FromLua for StyleOptions {
|
|
103
|
-
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
|
|
104
|
-
match value {
|
|
105
|
-
LuaValue::Table(t) => {
|
|
106
|
-
let mut builder = StyleOptionsBuilder::new();
|
|
107
|
-
if let Ok(overrides_table) = t.get::<LuaTable>("overrides") {
|
|
108
|
-
let overrides: Vec<Word> = overrides_table
|
|
109
|
-
.sequence_values::<String>()
|
|
110
|
-
.collect::<LuaResult<Vec<_>>>()?
|
|
111
|
-
.into_iter()
|
|
112
|
-
.map(|s| s.into())
|
|
113
|
-
.collect();
|
|
114
|
-
builder = builder.overrides(overrides);
|
|
115
|
-
}
|
|
116
|
-
Ok(builder.build())
|
|
117
|
-
}
|
|
118
|
-
LuaValue::Nil => Ok(Self::default()),
|
|
119
|
-
_ => unimplemented!(),
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|