Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor native extension #4

Merged

Conversation

d-unsed
Copy link

@d-unsed d-unsed commented Sep 21, 2016

  • Add Transform and TryTransform traits
  • Move Rust functions outside methods! macro
  • Change naming to match conventions


class!(CaseTransform);
trait Transform: Object {
Copy link
Author

@d-unsed d-unsed Sep 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
  • RString
  • Symbol
  • Hash
  • Array

by implementing transorm methods.

fn transformSymbol(value: Symbol, transformMethod: &Fn(AnyObject) -> AnyObject) -> Symbol {
let transformed = transformMethod(value);
Symbol::new(transformed);
trait TryTransform: Object {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try_transform<T> method:

  1. Tries to convert current AnyObject to the type T.
  2. :
    • 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 transformation

The 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)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
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) }
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we can safely unwrap in this methods, because objects are AnyObjects

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

legit

fn toSnakeCase(key: String) -> String { to_snake_case(key.unwrap()) }
class!(CaseTransform);

methods! (
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the functions which are not used directly in the CaseTransform class are moved outside methods!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes sense!

@d-unsed
Copy link
Author

d-unsed commented Sep 21, 2016

That's what I meant in d-unsed/ruru#35 :)

I hope it helps!

# Running:

....

Finished in 2.039933s, 1.9608 runs/s, 28.9225 assertions/s.


use ruru::{Class, Object, RString, Hash, Array, Symbol, AnyObject, VM};
use ruru::types::ValueType;
use inflector::cases::{camelcase, classcase, kebabcase, snakecase};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is handy!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?


class!(CaseTransform);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was this removed? I saw it one one of the example repos, though I don't know what its purpose was

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line was moved to the bottom of the file

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

methods! (
CaseTransform,
itself,
trait Transform: Object {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to read up on traits and impls

for myself:

fn transformSymbol(value: Symbol, transformMethod: &Fn(AnyObject) -> AnyObject) -> Symbol {
let transformed = transformMethod(value);
Symbol::new(transformed);
result.into_iter()
Copy link
Collaborator

@NullVoxPopuli NullVoxPopuli Sep 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arrays are iterable by default?

edit: not*

Copy link
Author

@d-unsed d-unsed Sep 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here it is!

@NullVoxPopuli
Copy link
Collaborator

@d-unseductable this helps a ton! thanks so much!

@NullVoxPopuli
Copy link
Collaborator

I have to wait till I get to my personal laptop to try this out, so I have consistent hardware for my benchmarking :-)

@d-unsed
Copy link
Author

d-unsed commented Sep 21, 2016

You're welcome! Please let me know when you get the results

@NullVoxPopuli
Copy link
Collaborator

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.

@NullVoxPopuli NullVoxPopuli merged commit 8056028 into rails-api:ruru-rust-speed-boost Sep 21, 2016
@NullVoxPopuli
Copy link
Collaborator

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!

@NullVoxPopuli
Copy link
Collaborator

I guess what could be next is seeing if fiddle is slowing me down.

@d-unsed d-unsed deleted the transform_trait branch September 22, 2016 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants