This works:
myfunc = () ->
id: 3
name: 'myname'
But I want to be explicit about returning object.
myfunc = () ->
return
id: 3
name: 'myname'
But I get "Unexpected 'INDENT'" error. What's wrong with the above code?
myFunc = ->
return {
id : 3
name : 'myname'
}
myFunc = ->
return {} =
id : 3
name : 'myname'
myFunc = ->
# return
id : 3
name : 'myname'
you should put the return value on the same line or wrap it in () :
myFunc = () ->
return id:3, name:'myname'
myFunc = () ->
return (
id: 3
name: 'myname'
)
I think the best way is
myFunc = ->
return (
id: 3
name: 'myname'
)
because it fits the philosophy of functional programming.
The previous answers are all correct. This works too:
myFunc = () ->
{
id: 3
name: 'myname'
}
Related
I would like to do the following, but macros in that position don’t seem to work (I get error: expected `:`, found `!`. How can I pattern-match individual struct members and attach attributes to them based on the match?
use serde_derive::Serialize;
macro_rules! optional_param {
($name:ident : Option<$type:ty>) => { #[serde(skip_serializing_if = "Option::is_none")] pub $name: Option<$ty> };
($name:ident : Vec <$type:ty>) => { #[serde(skip_serializing_if = "Vec::is_empty" )] pub $name: Vec <$ty> };
($name:ident : bool ) => { #[serde(skip_serializing_if = "bool::not" )] pub $name: bool };
}
macro_rules! impl_extra {
( $name:ident { $( $param:ident : $type:ty ),* $(,)* } ) => (
#[derive(Default,Debug,Serialize)]
pub struct $name {
$( optional_param!($param : $type), )*
}
);
}
impl_extra!(MyStruct { member: Option<String> });
Link to the playground
Indeed, macro invocations are not valid in the middle of a struct definition. However, we can use metavariables there. The trick is to parse the parameters incrementally, building the tokens for the field definitions along the way, and when there's no more input to process, emit a struct definition with the field definitions coming from a metavariable.
As a first step, let's see what a macro that doesn't handle field types specifically looks like:
macro_rules! impl_extra {
( # $name:ident { } -> ($($result:tt)*) ) => (
#[derive(Default, Debug, Serialize)]
pub struct $name {
$($result)*
}
);
( # $name:ident { $param:ident : $type:ty, $($rest:tt)* } -> ($($result:tt)*) ) => (
impl_extra!(# $name { $($rest)* } -> (
$($result)*
pub $param : $type,
));
);
( $name:ident { $( $param:ident : $type:ty ),* $(,)* } ) => (
impl_extra!(# $name { $($param : $type,)* } -> ());
);
}
The only thing this macro does is add pub on each field and define a pub struct with a #[derive] attribute. The first rule handles the terminal case, i.e. when there are no more fields to process. The second rule handles the recursive case, and the third rule handles the macro's "public" syntax and transforms it into the "processing" syntax.
Note that I'm using an # as the initial token for internal rules to distinguish them from "public" rules. If this macro is not meant to be exported to other crates, then you could also move the internal rules to a different macro. If the macro is exported though, then the separate macro for the internal rules might have to be exported too.
Now, let's handle the various field types:
macro_rules! impl_extra {
( # $name:ident { } -> ($($result:tt)*) ) => (
#[derive(Default, Debug, Serialize)]
pub struct $name {
$($result)*
}
);
( # $name:ident { $param:ident : Option<$type:ty>, $($rest:tt)* } -> ($($result:tt)*) ) => (
impl_extra!(# $name { $($rest)* } -> (
$($result)*
#[serde(skip_serializing_if = "Option::is_none")]
pub $param : Option<$type>,
));
);
( # $name:ident { $param:ident : Vec<$type:ty>, $($rest:tt)* } -> ($($result:tt)*) ) => (
impl_extra!(# $name { $($rest)* } -> (
$($result)*
#[serde(skip_serializing_if = "Vec::is_empty")]
pub $param : Vec<$type>,
));
);
( # $name:ident { $param:ident : bool, $($rest:tt)* } -> ($($result:tt)*) ) => (
impl_extra!(# $name { $($rest)* } -> (
$($result)*
#[serde(skip_serializing_if = "bool::not")]
pub $param : bool,
));
);
( $name:ident { $( $param:ident : $($type:tt)* ),* $(,)* } ) => (
impl_extra!(# $name { $($param : $($type)*,)* } -> ());
);
}
Note that there's a difference in the last rule: instead of matching on a ty, we now match on a sequence of tt. That's because once the macro has parsed a ty, it can't be broken down, so when we make a recursive macro call, a ty cannot possibly match something like Option<$type:ty>.
Below is my coffee Script .Its giving "Unexpected Indentation" error.
Any one can guess whats the errror is?
evaluateContainerRules: ( rules, containerType ) ->
deferred = Ext.create( 'Deft.promise.Deferred' )
searchCriteria = []
for rule in rules
if rule.searchTerms? and rule.searchTerms.length > 0
searchCriteria.push( rule )
console.log 'rule'
console.log 'searchCriteria'
if searchCriteria.length <= 0
emptyRules =
[
{
searchOption: 'EMPTY_RULE'
searchTerms: true
}
]
console.log 'emptyRules'
searchCriteria.push( emptyRules )
searchCriteria.push["Hello"]
console.log 'searchCriteria'
store = Ext.create( 'Traverse.core.store.admin.container.ContainerMemberSummarySearchStore',
params:
searchCriterias: searchCriteria
traverseTypeEnums: if containerType is 'device' then [ Traverse.core.enumeration.TraverseType.DEVICE ] else [ Traverse.core.enumeration.TraverseType.TEST ]
)
complete = false
store.on(
'load'
( records, operation, success ) ->
# NOTE: callback is fired multiple times for a paging store, only execute logic during the first call
if complete
return
complete = true
if success
deferred.resolve( store )
else
store.destroyStore()
#showError( operation.getError() )
deferred.reject( operation.getError() )
return
scope: #
)
store.load()
return deferred.promise
Its
This seems a reasonable re-indentation of your code that compiles
evaluateContainerRules: ( rules, containerType ) ->
deferred = Ext.create( 'Deft.promise.Deferred' )
searchCriteria = []
for rule in rules
if rule.searchTerms? and rule.searchTerms.length > 0
searchCriteria.push( rule )
console.log 'rule'
console.log 'searchCriteria'
if searchCriteria.length <= 0
emptyRules =
[{
searchOption: 'EMPTY_RULE'
searchTerms: true
}]
console.log 'emptyRules'
searchCriteria.push( emptyRules )
searchCriteria.push["Hello"]
console.log 'searchCriteria'
store = Ext.create( 'Traverse.core.store.admin.container.ContainerMemberSummarySearchStore',
params:
searchCriterias: searchCriteria
traverseTypeEnums: if containerType is 'device' then [ Traverse.core.enumeration.TraverseType.DEVICE ] else [ Traverse.core.enumeration.TraverseType.TEST ]
)
complete = false
store.on(
'load'
( records, operation, success ) ->
# NOTE: callback is fired multiple times for a paging store, only execute logic during the first call
if complete
return
complete = true
if success
deferred.resolve( store )
else
store.destroyStore()
#showError( operation.getError() )
deferred.reject( operation.getError() )
return
scope: #
)
store.load()
Hope this helps
I would like to create an array in a macro to transform something like:
let array = create_array!(
fn test() -> i32 { }
fn test1() { }
);
into
let array = [test, test1];
I tried this:
macro_rules! create_array {
() => {
};
(fn $func_name:ident () -> $return_type:ty $block:block $($rest:tt)*) => {
$func_name,
create_array!($($rest)*);
};
(fn $func_name:ident () $block:block $($rest:tt)*) => {
$func_name,
create_array!($($rest)*);
};
}
but it fails with the following error:
error: macro expansion ignores token `,` and any following
--> src/main.rs:11:19
|
11 | $func_name,
| ^
|
note: caused by the macro expansion here; the usage of `create_array!` is likely invalid in expression context
--> src/main.rs:27:18
|
27 | let array = [create_array!(
|
I also tried this:
macro_rules! create_array {
($(fn $func_name:ident () $( -> $return_type:ty )* $block:block)*) => {
[$($func_name),*]
};
}
but it fails with:
error: local ambiguity: multiple parsing options: built-in NTs block ('block') or 1 other option.
--> src/main.rs:22:19
|
22 | fn test() -> i32 { }
|
So how can I create an array in such a case?
The parsing ambiguity of -> vs $:block has been resolved as of Rust 1.20, so the second version you tried will now work as intended.
macro_rules! create_array {
($(fn $func_name:ident () $(-> $return_type:ty)* $block:block)*) => {
[$($func_name),*]
};
}
fn main() {
let test = "TEST";
let test1 = "TEST1";
let array = create_array! {
fn test() -> i32 {}
fn test1() {}
};
println!("{:?}", array);
}
Here is a simplified version of a macro I am trying to implement for an RPC library I am working on:
#[macro_export]
macro_rules! msgpack_rpc {
(
$(
rpc $name:ident ( $( $arg:ident : $arg_ty:ty ),* ) -> $ret_ty:ty | $err_ty:ty;
)+
) => (
pub trait Service {
$(
fn $name ( &self, $( $arg : $arg_ty ),* ) -> Result<$ret_ty, $err_ty>;
)+
}
pub struct Server;
impl Server {
pub fn listen<S>(handle: &(), address: (), service: S)
-> ::std::io::Result<()>
where S: Service + Send + Sync + 'static {
let service = move |msg: &str| {
let result = match msg {
$(
stringify!($name) => {
service.$name($( $arg ),*)
.map(String::from)
.map_err(String::from)
}
),+,
_ => String::from("method not supported".into()),
};
};
Ok(())
}
}
)
}
msgpack_rpc! {
rpc echo(arg: i64) -> i64 | ();
}
The macro expansion fails to compile with this error:
error: unresolved name `arg` [--explain E0425]
--> <anon>:40:17
|>
40 |> rpc echo(arg: i64) -> i64 | ();
|> ^
<anon>:39:1: 41:2: note: in this expansion of msgpack_rpc! (defined in <anon>)
From reading similar questions, I know that macro_rules sometimes has problems expanding statements. However, I am confused as to why it is having trouble expanding items in this case.
Is there a workaround to fix the expansion?
You don't have any variable named arg in the context in which you call the function. This is the "unresolved arg" the compiler is complaining about.
stringify!($name) => {
$( let $arg = Default::default(); )*
service.$name($( $arg ),*)
.map(String::from)
.map_err(String::from)
}
I am attempting to generate methods on a coffeescript class, like so:
class Test
log: (msg...) ->
for m in msg
console.log(m)
for alias in ['one', 'two', 'three', 'four', 'five']
Test::[alias] = (v...) ->
o = {}
o[alias] = v[0]
Test::log.apply(#, [o].concat(v.slice(1)))
t = new Test()
t.one(1)
t.two(3)
For reasons that fully escape me, this prints out
{ five: 1 }
{ five: 2 }
rather than what I had expected, being:
{ one: 1 }
{ two: 2 }
What am I missing here?
The problem is that you're binding alias variable to the new value on each iteration of the for loop. So, when t.one(1) method is called alias variable is bound to 'five'.
There are two ways of fixing this problem.
First solution is to use Array.prototype.forEach():
['one', 'two', 'three', 'four', 'five'].forEach (alias) ->
Test::[alias] = (v...) ->
// ..
Second solution is to use coffee-script do statement to create a closure:
for alias in ['one', 'two', 'three', 'four', 'five']
Test::[alias] = do (alias) -> (v...) ->
// ..