Skip to content
This repository has been archived by the owner on Jul 19, 2020. It is now read-only.

Commit

Permalink
Add a feature gate for service (#204)
Browse files Browse the repository at this point in the history
* Add a feature gate for service

* fix minimal readme

* remove yew as a dependency when compiling with no features

* add todo to remove unit_state

* implement Switch generically

* fix permissive in router_component example

* fix tests

* add method for creating a route with its default state

* other merged

* cleanup dead code, move formatting route code to service
  • Loading branch information
hgzimmerman authored Dec 17, 2019
1 parent 7837f76 commit 0deb2e1
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 162 deletions.
18 changes: 10 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ repository = "https://github.com/yewstack/yew_router"
[features]
default = ["core", "unit_alias"]

core = ["router", "components"]
core = ["router", "components"] # Most everything

# TODO remove this
unit_alias = []

router = ["agent"]
components = ["agent" ]
agent = []
router = ["agent"] # The Router component
components = ["agent" ] # The button and anchor
agent = ["service"] # The RouteAgent
service = ["stdweb", "yew"] # The RouteService


[dependencies]
log = "0.4.8"
serde = "1.0.103"
serde_derive = "1.0.103"
serde = {version = "1.0.103", features = ["derive"]}
#yew = "0.10.0"
yew = {git = "https://github.com/yewstack/yew", branch = "master"}
stdweb = "0.4.20"
yew = {git = "https://github.com/yewstack/yew", branch = "master", optional = true}
stdweb = {version = "0.4.20", optional = true}

yew-router-route-parser = {path = "crates/yew_router_route_parser", version = "0.8.0"}
yew-router-macro = {path = "crates/yew_router_macro", version = "0.8.0"}
Expand Down
2 changes: 1 addition & 1 deletion crates/yew_router_macro/src/switch/enum_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn generate_enum_impl(
let token_stream = quote! {
#impl_line
{
fn from_route_part<__T: ::yew_router::route::RouteState>(route: String, mut state: Option<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {
fn from_route_part<__T>(route: String, mut state: Option<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {
let route_string = route;
#(#variant_matchers)*

Expand Down
2 changes: 1 addition & 1 deletion crates/yew_router_macro/src/switch/struct_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn generate_struct_impl(item: SwitchItem, generics: Generics) -> TokenStream
let token_stream = quote! {
#impl_line
{
fn from_route_part<__T: ::yew_router::route::RouteState>(route: String, mut state: Option<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {
fn from_route_part<__T>(route: String, mut state: Option<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {

#matcher
let route_string = route;
Expand Down
2 changes: 1 addition & 1 deletion examples/minimal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2018"
[dependencies]
#yew = "0.10.0"
yew = {git = "https://github.com/yewstack/yew", branch = "master"}
yew-router = {path = "../../", default-features=false}
yew-router = {path = "../../", default-features=false, features = ["service"]}
web_logger = "0.1"
log = "0.4.8"
wee_alloc = "0.4.5"
4 changes: 2 additions & 2 deletions examples/minimal/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Minimal Example

This example shows how to use this library without any of the features turned on.
Without any features, you lack the `Router` component and `RouteAgent` and its associated bridges and dispatchers.
This example shows how to use this library with only the "service" feature turned on.
Without most of the features, you lack the `Router` component and `RouteAgent` and its associated bridges and dispatchers.
This means that you must use the `RouteService` to interface with the browser to handle route changes.

Removing the `Router` component means that you have to deal with the `RouteService` directly and propagate change route messages up to the component that contains the `RouteService`.
Expand Down
10 changes: 5 additions & 5 deletions examples/router_component/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
c_component::CModel,
};
use yew::virtual_dom::VNode;
use yew_router::switch::AllowMissing;
use yew_router::switch::{AllowMissing, Permissive};

#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
Expand Down Expand Up @@ -62,12 +62,12 @@ impl Component for Model {
},
AppRoute::C => html!{<CModel />},
AppRoute::E(string) => html!{format!("hello {}", string)},
AppRoute::PageNotFound(None) => html!{"Page not found"},
AppRoute::PageNotFound(Some(missed_route)) => html!{format!("Page '{}' not found", missed_route)}
AppRoute::PageNotFound(Permissive(None)) => html!{"Page not found"},
AppRoute::PageNotFound(Permissive(Some(missed_route))) => html!{format!("Page '{}' not found", missed_route)}
}
})
redirect = Router::redirect(|route: Route| {
AppRoute::PageNotFound(Some(route.route))
AppRoute::PageNotFound(Permissive(Some(route.route)))
})
/>
</div>
Expand All @@ -87,7 +87,7 @@ pub enum AppRoute {
#[to = "/e/{string}"]
E(String),
#[to = "/page-not-found"]
PageNotFound(Option<String>),
PageNotFound(Permissive<String>),
}

#[derive(Debug, Switch, PartialEq, Clone, Copy)]
Expand Down
2 changes: 1 addition & 1 deletion examples/switch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
yew-router = {path = "../../"}
yew-router = {path = "../../", default-features=false}
25 changes: 13 additions & 12 deletions examples/switch/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
use yew_router::{route::Route, Switch};
use yew_router::switch::Permissive;

fn main() {
let route = Route::<()>::from("/some/route");
let route = Route::new_no_state("/some/route");
let app_route = AppRoute::switch(route);
dbg!(app_route);

let route = Route::<()>::from("/some/thing/other");
let route = Route::new_no_state("/some/thing/other");
let app_route = AppRoute::switch(route);
dbg!(app_route);

let route = Route::<()>::from("/another/other");
let route = Route::new_no_state("/another/other");
let app_route = AppRoute::switch(route);
dbg!(app_route);

let route = Route::<()>::from("/inner/left");
let route = Route::new_no_state("/inner/left");
let app_route = AppRoute::switch(route);
dbg!(app_route);

let route = Route::<()>::from("/yeet"); // should not match
let route = Route::new_no_state("/yeet"); // should not match
let app_route = AppRoute::switch(route);
dbg!(app_route);

let route = Route::<()>::from("/single/32");
let route = Route::new_no_state("/single/32");
let app_route = AppRoute::switch(route);
dbg!(app_route);

let route = Route::<()>::from("/othersingle/472");
let route = Route::new_no_state("/othersingle/472");
let app_route = AppRoute::switch(route);
dbg!(app_route);

let route = Route::<()>::from("/option/test");
let route = Route::new_no_state("/option/test");
let app_route = AppRoute::switch(route);
dbg!(app_route);

Expand Down Expand Up @@ -69,12 +70,12 @@ pub enum AppRoute {
Single(Single),
#[rest]
OtherSingle(OtherSingle),
/// Because this is an option, the inner item doesn't have to match.
/// Because this is permissive, the inner item doesn't have to match.
#[to = "/option/{}"]
Optional(Option<String>),
/// Because this is an option, a corresponding capture group doesn't need to exist
Optional(Permissive<String>),
/// Because this is permissive, a corresponding capture group doesn't need to exist
#[to = "/missing/capture"]
MissingCapture(Option<String>),
MissingCapture(Permissive<String>),
}

#[derive(Switch, Debug, Clone)]
Expand Down
20 changes: 15 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ pub use yew_router_route_parser;

#[macro_use]
mod alias;

#[cfg(feature = "service")]
pub mod service;

#[cfg(feature = "agent")]
Expand All @@ -72,6 +74,7 @@ pub mod components;
#[cfg(feature = "router")]
pub mod router;

/// TODO remove this
/// Contains aliases and functions for working with this library using a state of type `()`.
#[cfg(feature = "unit_alias")]
pub mod unit_state {
Expand All @@ -83,26 +86,32 @@ pub mod unit_state {
pub mod prelude {
pub use super::matcher::Captures;

#[cfg(feature = "service")]
pub use crate::service::RouteService;
#[cfg(feature = "service")]
pub use crate::route::RouteState;

#[cfg(feature = "agent")]
pub use crate::agent::RouteAgent;
#[cfg(feature = "agent")]
pub use crate::agent::RouteAgentBridge;
#[cfg(feature = "agent")]
pub use crate::agent::RouteAgentDispatcher;

#[cfg(feature = "components")]
pub use crate::components::RouterAnchor;
#[cfg(feature = "components")]
pub use crate::components::RouterButton;

#[cfg(feature = "router")]
pub use crate::router::Router;
pub use crate::{route::Route, service::RouteService};

pub use crate::switch::{Switch, Routable};
pub use yew_router_macro::Switch;
// State restrictions
pub use crate::route::RouteState;
#[cfg(feature = "router")]
pub use crate::router::RouterState;

pub use crate::route::Route;
pub use crate::switch::{Switch, Routable};
pub use yew_router_macro::Switch;
}

pub use alias::*;
Expand All @@ -111,6 +120,7 @@ pub mod matcher;

pub use matcher::Captures;

#[cfg(feature = "service")]
pub use crate::route::RouteState;
#[cfg(feature = "router")]
pub use crate::router::RouterState;
Expand Down
47 changes: 26 additions & 21 deletions src/route.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
//! Wrapper around route url string, and associated history state.
#[cfg(feature = "service")]
use stdweb::{unstable::TryFrom, Value};
#[cfg(feature = "service")]
use serde::de::DeserializeOwned;

use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref};
use stdweb::{unstable::TryFrom, Value};
use std::fmt::Debug;
use serde::de::DeserializeOwned;

/// Any state that can be used in the router agent must meet the criteria of this trait.
#[cfg(feature = "service")]
pub trait RouteState: Serialize + DeserializeOwned + Debug + Clone + Default + TryFrom<Value> + 'static {}
#[cfg(feature = "service")]
impl<T> RouteState for T where T: Serialize + DeserializeOwned + Debug + Clone + Default + TryFrom<Value> + 'static {}

/// The representation of a route, segmented into different sections for easy access.
Expand All @@ -18,35 +23,35 @@ pub struct Route<T = ()> {
pub state: T,
}

/// Formats a path, query, and fragment into a string.
///
/// # Note
/// This expects that all three already have their expected separators (?, #, etc)
pub(crate) fn format_route_string(path: &str, query: &str, fragment: &str) -> String {
format!(
"{path}{query}{fragment}",
path = path,
query = query,
fragment = fragment
)
}

impl<T> fmt::Display for Route<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
std::fmt::Display::fmt(&self.route, f)
impl Route<()> {
/// Creates a new route with no state out of a string.
///
/// This Route will have `()` for its state.
pub fn new_no_state<T: AsRef<str>>(route: T) -> Self {
Route {
route: route.as_ref().to_string(),
state: (),
}
}
}

// This is getting removed anyway
impl<T: Default> From<&str> for Route<T> {
fn from(string: &str) -> Route<T> {
impl <T: Default> Route<T> {
/// Creates a new route out of a string, setting the state to its default value.
pub fn new_default_state<U: AsRef<str>>(route: U) -> Self {
Route {
route: string.to_string(),
route: route.as_ref().to_string(),
state: T::default(),
}
}
}

impl<T> fmt::Display for Route<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
std::fmt::Display::fmt(&self.route, f)
}
}

impl<T> Deref for Route<T> {
type Target = String;

Expand Down
17 changes: 16 additions & 1 deletion src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl<T> RouteService<T> {
let path = location.pathname().unwrap();
let query = location.search().unwrap();
let fragment = location.hash().unwrap();
crate::route::format_route_string(&path, &query, &fragment)
format_route_string(&path, &query, &fragment)
}


Expand Down Expand Up @@ -144,6 +144,21 @@ where
}
}


/// Formats a path, query, and fragment into a string.
///
/// # Note
/// This expects that all three already have their expected separators (?, #, etc)
pub(crate) fn format_route_string(path: &str, query: &str, fragment: &str) -> String {
format!(
"{path}{query}{fragment}",
path = path,
query = query,
fragment = fragment
)
}


fn get_state(history: &History) -> Value {
js!(
return @{history}.state;
Expand Down
Loading

0 comments on commit 0deb2e1

Please sign in to comment.