From 78bd9af7631918d41ef51528b5965377c04ab832 Mon Sep 17 00:00:00 2001
From: kirbylife <gabriel13m@gmail.com>
Date: Sun, 17 Jan 2021 20:01:06 -0600
Subject: [PATCH] add the selector and the request base

---
 Cargo.toml      |  7 ++++++-
 src/lib.rs      | 31 +++++++++++++++++++++++++++++--
 src/request.rs  | 36 ++++++++++++++++++++++++++++++++++++
 src/response.rs | 16 ++++++++++++++++
 src/selector.rs | 42 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 129 insertions(+), 3 deletions(-)
 create mode 100644 src/request.rs
 create mode 100644 src/response.rs
 create mode 100644 src/selector.rs

diff --git a/Cargo.toml b/Cargo.toml
index 7960f8d..f3d9d23 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,14 @@
 [package]
 name = "raspa"
 version = "0.1.0"
-authors = ["kirbylife <gabriel13m@gmail.com>"]
+authors = ["kirbylife <kirbylife@protonmail.com>"]
 edition = "2018"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+reqwest = { version = "0.10", features = ["blocking", "json"] }
+tokio = { version = "0.2", features = ["full"] }
+url = "2.1"
+http = "0.2"
+nipper = "0.1.8"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 31e1bb2..2cdd4d2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,34 @@
+pub mod request;
+pub mod response;
+pub mod selector;
+
 #[cfg(test)]
 mod tests {
+    use crate::request::{Request, RequestBase};
+    use crate::selector::{Selector, SelectorBase};
+    use http::StatusCode;
+
     #[test]
-    fn it_works() {
-        assert_eq!(2 + 2, 4);
+    fn plain_text_selector() {
+        let html = "
+<html>
+  <body>
+    <h1>hello world</h1>
+    <p id='text'>good bye</p>
+  </body>
+</html>
+";
+        let sel = Selector::from_html(html);
+        println!("{:?}", sel.css("h1"));
+        assert_eq!(sel.css("h1")[0].html(), "<h1>hello world</h1>");
+        assert_eq!(sel.css("#text")[0].content(), "good bye");
+    }
+
+    #[test]
+    fn simple_request() {
+        let req: Request = RequestBase::new("https://httpbin.org/");
+        let resp = req.launch();
+        assert_eq!(resp.status_code, StatusCode::OK);
+        assert!(resp.css("h2")[0].html().contains("httpbin.org"));
     }
 }
diff --git a/src/request.rs b/src/request.rs
new file mode 100644
index 0000000..324603b
--- /dev/null
+++ b/src/request.rs
@@ -0,0 +1,36 @@
+use crate::response;
+use http::status::StatusCode;
+use url::Url;
+
+pub trait RequestBase {
+    fn new(url: &'static str) -> Self;
+    fn launch(&self) -> response::Response;
+}
+
+#[derive(Debug)]
+pub struct Request {
+    pub url: url::Url,
+}
+
+impl RequestBase for Request {
+    fn new(url: &'static str) -> Request {
+        Request {
+            url: Url::parse(url).unwrap(),
+        }
+    }
+
+    fn launch(&self) -> response::Response {
+        let resp = reqwest::blocking::get(self.url.as_str()).unwrap();
+
+        let text: String = resp.text().unwrap();
+        let status = StatusCode::OK;
+
+        let url = self.url.clone();
+
+        response::Response {
+            text: text,
+            status_code: status,
+            url: url,
+        }
+    }
+}
diff --git a/src/response.rs b/src/response.rs
new file mode 100644
index 0000000..0bfc9d2
--- /dev/null
+++ b/src/response.rs
@@ -0,0 +1,16 @@
+use crate::selector::SelectorBase;
+use http::StatusCode;
+use url::Url;
+
+#[derive(Debug)]
+pub struct Response {
+    pub text: String,
+    pub status_code: StatusCode,
+    pub url: Url,
+}
+
+impl SelectorBase for Response {
+    fn html(&self) -> &str {
+        self.text.as_str()
+    }
+}
diff --git a/src/selector.rs b/src/selector.rs
new file mode 100644
index 0000000..94ec37c
--- /dev/null
+++ b/src/selector.rs
@@ -0,0 +1,42 @@
+pub trait SelectorBase {
+    fn html(&self) -> &str;
+
+    fn css(&self, css_selector: &'static str) -> Vec<Selector> {
+        let html = nipper::Document::from(self.html());
+        html.select(css_selector)
+            .iter()
+            .map(|element| Selector {
+                text: element.html().to_string(),
+            })
+            .into_iter()
+            .collect::<Vec<_>>()
+    }
+
+    fn content(&self) -> String {
+        let html = nipper::Document::from(self.html());
+        html.select("*")
+            .iter()
+            .map(|element| element.text().to_string())
+            .last()
+            .unwrap()
+    }
+}
+
+#[derive(Debug)]
+pub struct Selector {
+    text: String,
+}
+
+impl SelectorBase for Selector {
+    fn html(&self) -> &str {
+        self.text.as_str()
+    }
+}
+
+impl Selector {
+    pub fn from_html(html: &'static str) -> Self {
+        Selector {
+            text: html.to_string(),
+        }
+    }
+}