Skip to content

Commit 803b258

Browse files
committed
Refactor native extension
- Add `Transform` and `TryTransform` traits - Move Rust functions outside `methods!` macro - Change naming to match conventions
1 parent 8f017c6 commit 803b258

File tree

1 file changed

+99
-53
lines changed

1 file changed

+99
-53
lines changed

ext/case_transform/src/lib.rs

+99-53
Original file line numberDiff line numberDiff line change
@@ -2,80 +2,126 @@
22
extern crate ruru;
33
extern crate inflector;
44

5-
// // dash: kebab-case
6-
use inflector::cases::kebabcase::to_kebab_case;
7-
// // underscore: snake_case
8-
use inflector::cases::snakecase::to_snake_case;
9-
// // camel_lower: camelCase
10-
use inflector::cases::camelcase::to_camel_case;
11-
// // camel: ClassCase (PascalCase)
12-
use inflector::cases::classcase::to_class_case;
13-
14-
use ruru::{Class, Object, RString, Hash, Array, Symbol, AnyObject, VM};
5+
use inflector::cases::{camelcase, classcase, kebabcase, snakecase};
6+
7+
use ruru::{Class, Object, VerifiedObject, RString, Hash, Array, Symbol, AnyObject};
158
use ruru::types::ValueType;
9+
use ruru::result::Error as RuruError;
1610

17-
class!(CaseTransform);
11+
trait Transform: Object {
12+
fn transform(&self, transform_function: &Fn(String) -> String) -> AnyObject;
13+
}
1814

19-
methods! (
20-
CaseTransform,
21-
itself,
15+
impl Transform for AnyObject {
16+
fn transform(&self, _transform_function: &Fn(String) -> String) -> AnyObject {
17+
self.clone()
18+
}
19+
}
20+
21+
impl Transform for RString {
22+
fn transform(&self, transform_function: &Fn(String) -> String) -> AnyObject {
23+
RString::new(&transform_function(self.to_string())).to_any_object()
24+
}
25+
}
26+
27+
impl Transform for Symbol {
28+
fn transform(&self, transform_function: &Fn(String) -> String) -> AnyObject {
29+
let result = transform_function(self.to_string());
30+
31+
Symbol::new(&result).to_any_object()
32+
}
33+
}
2234

23-
fn deepTransformKeys(hash: Hash, block: &Fn(String) -> String) -> Hash {
24-
let result = Hash::new();
35+
impl Transform for Hash {
36+
fn transform(&self, transform_function: &Fn(String) -> String) -> AnyObject {
37+
let mut result = Hash::new();
2538

26-
hash.unwrap().each(|key, value| {
27-
let newValue = if value.ty() == ValueType::Hash { deepTransformKeys(value, block).to_any_object() } else { value };
28-
let newKey = RString::new(block(key.unwrap().to_string()));
29-
result.store(newKey, newValue);
39+
self.each(|key, value| {
40+
let new_key = transform(key, transform_function);
41+
let new_value = match value.ty() {
42+
ValueType::Hash => transform(value, transform_function),
43+
_ => value,
44+
};
45+
46+
result.store(new_key, new_value);
3047
});
3148

32-
result
49+
result.to_any_object()
3350
}
51+
}
3452

35-
fn transformArray(value: Array, transformMethod: &Fn(AnyObject) -> AnyObject) -> Array {
36-
value.map(|item| transformMethod(item)).unwrap()
37-
}
53+
impl Transform for Array {
54+
fn transform(&self, transform_function: &Fn(String) -> String) -> AnyObject {
55+
// Temp hack to consume &self for iterator
56+
let array = unsafe { self.to_any_object().to::<Array>() };
3857

39-
fn transformHash(value: Hash, transformMethod: &Fn(AnyObject) -> AnyObject) -> Hash {
40-
deepTransformKeys(value, |key| transformMethod(key))
58+
array.into_iter()
59+
.map(|item| transform(item, transform_function))
60+
.collect::<Array>()
61+
.to_any_object()
4162
}
63+
}
4264

43-
fn transformSymbol(value: Symbol, transformMethod: &Fn(AnyObject) -> AnyObject) -> Symbol {
44-
let transformed = transformMethod(value);
45-
Symbol::new(transformed);
65+
trait TryTransform: Object {
66+
fn try_transform<T>(&self,
67+
transform_function: &Fn(String) -> String)
68+
-> Result<AnyObject, RuruError>
69+
where T: VerifiedObject + Transform
70+
{
71+
self.try_convert_to::<T>().map(|object| object.transform(transform_function))
4672
}
73+
}
74+
75+
impl TryTransform for AnyObject {}
76+
77+
fn transform(object: AnyObject, key_transform: &Fn(String) -> String) -> AnyObject {
78+
let result = object.try_transform::<RString>(key_transform)
79+
.or_else(|_| object.try_transform::<Symbol>(key_transform))
80+
.or_else(|_| object.try_transform::<Array>(key_transform))
81+
.or_else(|_| object.try_transform::<Hash>(key_transform))
82+
.or_else(|_| object.try_transform::<AnyObject>(key_transform));
4783

48-
fn transform(
49-
value: AnyObject,
50-
objectTransform: &Fn(AnyObject) -> AnyObject,
51-
keyTransform: &Fn(String) -> String
52-
) -> AnyObject {
53-
match value.unwrap().ty() {
54-
ValueType::Array => transformArray(value, objectTransform).to_any_object(),
55-
ValueType::Hash => transformHash(value, objectTransform).to_any_object(),
56-
ValueType::Symbol => transformSymbol(value, objectTransform).to_any_object(),
57-
ValueType::RString => keyTransform(value).to_any_object(),
58-
ValueType::Object => value
59-
}
84+
if result.is_err() {
85+
unreachable!()
6086
}
6187

62-
fn toPascalCase(key: String) -> String { to_class_case(to_snake_case(key.unwrap())) }
63-
fn toCamelCase(key: String) -> String { to_camel_case(to_snake_case(key.unwrap())) }
64-
fn toDashedCase(key: String) -> String { to_kebab_case(to_snake_case(key.unwrap())) }
65-
fn toSnakeCase(key: String) -> String { to_snake_case(key.unwrap()) }
88+
result.unwrap()
89+
}
90+
91+
fn to_pascal_case(key: String) -> String {
92+
classcase::to_class_case(snakecase::to_snake_case(key))
93+
}
94+
95+
fn to_camel_case(key: String) -> String {
96+
camelcase::to_camel_case(snakecase::to_snake_case(key))
97+
}
98+
99+
fn to_dashed_case(key: String) -> String {
100+
kebabcase::to_kebab_case(snakecase::to_snake_case(key))
101+
}
102+
103+
fn to_snake_case(key: String) -> String {
104+
snakecase::to_snake_case(key)
105+
}
106+
107+
class!(CaseTransform);
108+
109+
methods! (
110+
CaseTransform,
111+
_itself,
66112

67-
fn camel(value: AnyObject) -> AnyObject { transform(value.unwrap().to_any_object(), &camel, &toPascalCase) }
68-
fn camelLower(value: AnyObject) -> AnyObject { transform(value.unwrap().to_any_object(), &camelLower, &toCamelCase) }
69-
fn dash(value: AnyObject) -> AnyObject { transform(value.unwrap().to_any_object(), &dash, &toDashedCase) }
70-
fn underscore(value: AnyObject) -> AnyObject { transform(value.unwrap(), &underscore, &toSnakeCase) }
71-
fn unaltered(value: AnyObject) -> AnyObject { value.unwrap().to_any_object() }
113+
fn camel(value: AnyObject) -> AnyObject { transform(value.unwrap(), &to_pascal_case) }
114+
fn camel_lower(value: AnyObject) -> AnyObject { transform(value.unwrap(), &to_camel_case) }
115+
fn dash(value: AnyObject) -> AnyObject { transform(value.unwrap(), &to_dashed_case) }
116+
fn underscore(value: AnyObject) -> AnyObject { transform(value.unwrap(), &to_snake_case) }
117+
fn unaltered(value: AnyObject) -> AnyObject { value.unwrap() }
72118
);
73119

74120
#[no_mangle]
75-
pub extern fn initialize_case_transform() {
76-
Class::new("CaseTransform", None).define(|itself| {
121+
pub extern "C" fn initialize_case_transform() {
122+
Class::from_existing("CaseTransform").define(|itself| {
77123
itself.def_self("camel", camel);
78-
itself.def_self("camel_lower", camelLower);
124+
itself.def_self("camel_lower", camel_lower);
79125
itself.def_self("dash", dash);
80126
itself.def_self("underscore", underscore);
81127
itself.def_self("unaltered", unaltered);

0 commit comments

Comments
 (0)