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

New plugin: tangorin #3

Merged
merged 11 commits into from Oct 12, 2016

Conversation

Projects
None yet
2 participants
@alfateam123
Copy link
Contributor

alfateam123 commented Oct 7, 2016

This is a (possible) implementation for the tangorin plugin that is already present in Descartes but not in Gauss.

I didn't write lots of Rust until now, so if you spot something that is not idiomatic, or could be done better, or just mistakes I overlooked, I'll be more than happy to fix them.

Fixes #2

impl Tangorin {
fn grep_kanji(&self, msg: &str) -> Option<String> {
match RE.captures(msg) {
Some(captures) => {

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

Some(captures) => captures.at(1).map(|e| e.to_owned())

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

done


fn retrieve_from_selector(&self, doc: &kuchiki::NodeRef, selector: &str) -> Option<String> {
if let Some(match_) = doc.select(selector).unwrap().next() {
let node = match_.as_node().first_child().unwrap();

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

check the indentation here, it looks quite weird

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

ssh on spotty connections is suffering and makes me miss this kind of errors. fixed.

if let Some(match_) = doc.select(selector).unwrap().next() {
let node = match_.as_node().first_child().unwrap();
let borrowed_text = node.as_text().unwrap().borrow();
let mut retrieved_text = borrowed_text.clone();

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

I think this doesn't need to be mutable as you should be able to do everything in a single line, right?

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

now this not mutable anymore. Originally, I had some problems with borrowed_text lifetimes: to fix it I put each change to its own line, but didn't recompose things back.


Some(retrieved_text)
}
else{

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

I don't like much this line. What about an early return on the very top of the function?

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

refactored the whole thing, so early returns are not necessary anymore.

if let Some(match_) = doc.select("span[class=eng]").unwrap().next() {
let node = match_.as_node();
let children = node.children();
let mut meaning = "".to_string();

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

String::new() in place of "".to_string()

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

fixed

};

if let Ok(doc) = kuchiki::parse_html().from_http(&url) {
let romaji = match self.retrieve_from_selector(&doc, "rt"){

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

What if we make a macro to reduce this redundant lines?

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

implemented a simple macro called get_text!. it definitely cuts the noise down.

let info : String = match self.retrieve_info(&doc) {
Some(retrieved) => {
let sanitized = retrieved.replace("\u{2014}", "").replace(".", "").to_lowercase();
(" (".to_string()+sanitized.as_str()+")").to_string()

This comment has been minimized.

@RoxasShadow

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

i felt there was a better way to do that, but didn't look at the docs. fixed.

let sanitized = retrieved.replace("\u{2014}", "").replace(".", "").to_lowercase();
(" (".to_string()+sanitized.as_str()+")").to_string()
},
None => "".to_string()

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

String::new

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

fixed.

None => "".to_string()
};

return server.send_privmsg(target, &format!("[Tangorin] {} ({} - {}): {}{}", &*kanji, &*kana, &*romaji, &*meaning, &*info))

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

I'm pretty sure that filling a proper struct with these data and using the ToString trait would work great

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

I don't really think so. Creating an useless struct just to use .to_string is not as readable as a format!, especially considering that the retrieved information is not shared with other plugins or stored in any way.

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

At least let's try to format that string properly (splitting the vars in multiple lines just work fine) as right now that's. struct as very lightweight btw :)

assert_eq!("PRIVMSG test :[Tangorin] 頑な (かたくな - katakuna): obstinate (usually written using kana alone)\r\n",
&*get_server_value(&server));
}

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 8, 2016

Owner

useless line here, one is enough

This comment has been minimized.

@alfateam123

alfateam123 Oct 9, 2016

Author Contributor

should be fixed

alfateam123 added some commits Oct 9, 2016

plugins/tangorin: refactor text retrieval code
in `retrieve_*` function, use matches instead
of `if let ... else` to make code smaller
and more readable
Some(match_) => {
let node = match_.as_node().first_child().unwrap();
let borrowed_text = node.as_text().unwrap().borrow();
Some(borrowed_text.clone().trim().to_string())

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

to_owned() is better than clone() as it is an its specialisation

static ref RE: Regex = Regex::new(r"!tangorin (\S+)").unwrap();
}

macro_rules! get_text {

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

try_option to be more similar to try?

This comment has been minimized.

@alfateam123

alfateam123 Oct 11, 2016

Author Contributor

done.


fn retrieve_meaning(&self, doc: &kuchiki::NodeRef) -> Option<String> {
match doc.select("span[class=eng]").unwrap().next() {
None => None,

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

Can you think a way to avoid this None => None in many places? like an early return or so

This comment has been minimized.

@alfateam123

alfateam123 Oct 11, 2016

Author Contributor

as discussed privately, I've switched to Options.map when the conversion is easy and meaningful.

if let Some(text) = child.as_text() {
meaning.push_str(text.borrow().as_str());
}
else{

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

put a space after else please

This comment has been minimized.

@alfateam123

alfateam123 Oct 11, 2016

Author Contributor

fixed

let following_siblings = node.following_siblings();

match following_siblings.select("i[class=d-info]") {
Err(()) => None,

This comment has been minimized.

@RoxasShadow

This comment has been minimized.

@alfateam123

alfateam123 Oct 11, 2016

Author Contributor

fixed


match following_siblings.select("i[class=d-info]") {
Err(()) => None,
Ok(mut info_sibs) => {

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

you can avoid {...} as using direct => match is enough

This comment has been minimized.

@alfateam123

alfateam123 Oct 11, 2016

Author Contributor

good catch

match following_siblings.select("i[class=d-info]") {
Err(()) => None,
Ok(mut info_sibs) => {
match info_sibs.next() {

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

info_sibs.next().map(|n| ...)

This comment has been minimized.

@alfateam123

alfateam123 Oct 11, 2016

Author Contributor

done

match root.first_child(){
None => None,
Some(match_) => {
match match_.as_text() {

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 9, 2016

Owner

match_.as_text().map(|n| ...)

This comment has been minimized.

@alfateam123

alfateam123 Oct 11, 2016

Author Contributor

done

@@ -30,36 +30,30 @@ impl Tangorin {
}

fn retrieve_from_selector(&self, doc: &kuchiki::NodeRef, selector: &str) -> Option<String> {
match doc.select(selector).unwrap().next() {
Some(match_) => {
doc.select(selector).unwrap().next().map(|match_| {
let node = match_.as_node().first_child().unwrap();

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 12, 2016

Owner

there's an indentation problem here maybe?

This comment has been minimized.

@alfateam123

alfateam123 Oct 12, 2016

Author Contributor

fixed

if let Some(text) = child.as_text() {
meaning.push_str(text.borrow().as_str());
}
else {

This comment has been minimized.

@RoxasShadow

This comment has been minimized.

@alfateam123

alfateam123 Oct 12, 2016

Author Contributor

fixed


fn retrieve_from_selector(&self, doc: &kuchiki::NodeRef, selector: &str) -> Option<String> {
doc.select(selector).unwrap().next().map(|match_| {
let node = match_.as_node().first_child().unwrap();

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 12, 2016

Owner

indentation problem here

This comment has been minimized.

@alfateam123

alfateam123 Oct 12, 2016

Author Contributor

forgot to fix it in the previous patch :V

}

fn inner_text(&self, root: &kuchiki::NodeRef) -> Option<String> {
match root.first_child(){

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 12, 2016

Owner

put a space before the {

This comment has been minimized.

@alfateam123

alfateam123 Oct 12, 2016

Author Contributor

fixed

let kana = try_option!(self.retrieve_from_selector(&doc, "rb"));
let kanji = try_option!(self.retrieve_from_selector(&doc, "span[class=writing]"));
let meaning = try_option!(self.retrieve_meaning(&doc));
let info : String = match self.retrieve_info(&doc) {

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 12, 2016

Owner

don't put any space before the : (i.e. let info: String =)

This comment has been minimized.

@alfateam123

alfateam123 Oct 12, 2016

Author Contributor

ops :///:

let kanji = try_option!(self.retrieve_from_selector(&doc, "span[class=writing]"));
let meaning = try_option!(self.retrieve_meaning(&doc));
let info : String = match self.retrieve_info(&doc) {
Some(retrieved) => format!(" ({})", retrieved.replace("\u{2014}", "").replace(".", "").to_lowercase()),

This comment has been minimized.

@RoxasShadow

RoxasShadow Oct 12, 2016

Owner

WDYT about String::remove here?

This comment has been minimized.

@alfateam123

alfateam123 Oct 12, 2016

Author Contributor

unfortunately String::remove does not do what we thought it does:
Removes a char from this String at a byte position and returns it..
String::replace is still the only method to do that.

@RoxasShadow

This comment has been minimized.

Copy link
Owner

RoxasShadow commented Oct 12, 2016

This is cool, just a couple of request changes and we can merge this – thanks a lot 👍

@RoxasShadow RoxasShadow merged commit 363645f into RoxasShadow:master Oct 12, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.