Refactor native extension#4
Conversation
803b258 to
86b302e
Compare
| use ruru::result::Error as RuruError; | ||
|
|
||
| class!(CaseTransform); | ||
| trait Transform: Object { |
There was a problem hiding this comment.
Transform describes an interface for transformation. It can be implemented only to Ruby objects due to Object constraint.
Then we make type-specific implementations for
AnyObject(no-op)RStringSymbolHashArray
by implementing transorm methods.
| fn transformSymbol(value: Symbol, transformMethod: &Fn(AnyObject) -> AnyObject) -> Symbol { | ||
| let transformed = transformMethod(value); | ||
| Symbol::new(transformed); | ||
| trait TryTransform: Object { |
There was a problem hiding this comment.
TryTransform trait itself is needed only to define try_transform method on AnyObject. Rust does not allow to change the implementation of types that is not owned by current crate.
| let transformed = transformMethod(value); | ||
| Symbol::new(transformed); | ||
| trait TryTransform: Object { | ||
| fn try_transform<T>(&self, |
There was a problem hiding this comment.
try_transform<T> method:
- Tries to convert current
AnyObjectto the typeT. - :
- If the conversion is successful it performs a transformation.
- otherwise, returns an error from
try_convert_to.
An example of usage of try_transform is
object.try_transform::<Hash>(key_transform) // if the object is a hash, try to do a hash transformationThe interesting part here is the constraints for T type: where T: VerifiedObject + Transform.
| ValueType::Object => value | ||
| } | ||
| fn transform(object: AnyObject, key_transform: &Fn(String) -> String) -> AnyObject { | ||
| let result = object.try_transform::<RString>(key_transform) |
There was a problem hiding this comment.
Try to transform the object as a RString
Otherwise try to transform the object as a Symbol
...
Otherwise try to transform the object as a AnyObject (it is any unkown class, do nothing)
| fn toCamelCase(key: String) -> String { to_camel_case(to_snake_case(key.unwrap())) } | ||
| fn toDashedCase(key: String) -> String { to_kebab_case(to_snake_case(key.unwrap())) } | ||
| fn toSnakeCase(key: String) -> String { to_snake_case(key.unwrap()) } | ||
| result.unwrap() |
There was a problem hiding this comment.
We can safely unwrap here, because result has AnyObject type
- Add `Transform` and `TryTransform` traits - Move Rust functions outside `methods!` macro - Change naming to match conventions
86b302e to
f7dc641
Compare
| fn dash(value: AnyObject) -> AnyObject { transform(value.unwrap().to_any_object(), &dash, &toDashedCase) } | ||
| fn underscore(value: AnyObject) -> AnyObject { transform(value.unwrap(), &underscore, &toSnakeCase) } | ||
| fn unaltered(value: AnyObject) -> AnyObject { value.unwrap().to_any_object() } | ||
| fn camel(object: AnyObject) -> AnyObject { transform(value.unwrap(), &to_pascal_case) } |
There was a problem hiding this comment.
And we can safely unwrap in this methods, because objects are AnyObjects
| fn toSnakeCase(key: String) -> String { to_snake_case(key.unwrap()) } | ||
| class!(CaseTransform); | ||
|
|
||
| methods! ( |
There was a problem hiding this comment.
All the functions which are not used directly in the CaseTransform class are moved outside methods!
|
That's what I meant in d-unsed/ruru#35 :) I hope it helps! |
|
|
||
| use ruru::{Class, Object, RString, Hash, Array, Symbol, AnyObject, VM}; | ||
| use ruru::types::ValueType; | ||
| use inflector::cases::{camelcase, classcase, kebabcase, snakecase}; |
There was a problem hiding this comment.
is there a way to import the methods into the 'global' namespace of the file? so you don't have to do classcase::to_class_case?
| use ruru::types::ValueType; | ||
| use inflector::cases::{camelcase, classcase, kebabcase, snakecase}; | ||
|
|
||
| class!(CaseTransform); |
There was a problem hiding this comment.
why was this removed? I saw it one one of the example repos, though I don't know what its purpose was
There was a problem hiding this comment.
The line was moved to the bottom of the file
| methods! ( | ||
| CaseTransform, | ||
| itself, | ||
| trait Transform: Object { |
There was a problem hiding this comment.
I need to read up on traits and impls
for myself:
- https://doc.rust-lang.org/book/traits.html
- https://doc.rust-lang.org/book/generics.html looks like impl's are just implementations of a generic struct?
| fn transformSymbol(value: Symbol, transformMethod: &Fn(AnyObject) -> AnyObject) -> Symbol { | ||
| let transformed = transformMethod(value); | ||
| Symbol::new(transformed); | ||
| result.into_iter() |
There was a problem hiding this comment.
arrays are iterable by default?
edit: not*
There was a problem hiding this comment.
They kinda are iterable, but after explicit conversion to iterators :) Same for slices, vectors etc
| fn toCamelCase(key: String) -> String { to_camel_case(to_snake_case(key.unwrap())) } | ||
| fn toDashedCase(key: String) -> String { to_kebab_case(to_snake_case(key.unwrap())) } | ||
| fn toSnakeCase(key: String) -> String { to_snake_case(key.unwrap()) } | ||
| class!(CaseTransform); |
|
@d-unseductable this helps a ton! thanks so much! |
|
I have to wait till I get to my personal laptop to try this out, so I have consistent hardware for my benchmarking :-) |
|
You're welcome! Please let me know when you get the results |
|
Just for some background here is the comparison between pure ruby, and my last successful compile: rails-api/active_model_serializers#1928 (comment) It actually significantly hurt performance. haha. |
|
rails-api/active_model_serializers#1928 (comment) So, slightly faster... but still am not sure what the deal is with the slowness. Still, I appreciate you teaching me rust! |
|
I guess what could be next is seeing if fiddle is slowing me down. |
TransformandTryTransformtraitsmethods!macro