1#![warn(missing_docs)]
2
3use proc_macro::TokenStream;
9use quote::quote;
10use syn;
11
12#[proc_macro]
16pub fn example_macro(_input: TokenStream) -> TokenStream {
17 let expanded = quote! {
19 println!("Hello from ruby-macros!");
20 };
21
22 TokenStream::from(expanded)
23}
24
25#[proc_macro_derive(ExampleDerive)]
29pub fn example_derive(input: TokenStream) -> TokenStream {
30 let ast: syn::DeriveInput = syn::parse(input).unwrap();
32
33 let generated = quote! {
35 impl ExampleDerive for #ast {
36 fn example_method(&self) {
37 println!("Example derive macro implemented!");
38 }
39 }
40 };
41
42 TokenStream::from(generated)
43}
44
45#[proc_macro_attribute]
49pub fn example_attribute(_attr: TokenStream, item: TokenStream) -> TokenStream {
50 item
53}
54
55#[proc_macro_derive(RubyClass)]
60pub fn ruby_class_derive(input: TokenStream) -> TokenStream {
61 let ast: syn::DeriveInput = syn::parse(input).unwrap();
63
64 impl_ruby_class(&ast)
66}
67
68fn impl_ruby_class(ast: &syn::DeriveInput) -> TokenStream {
70 let struct_name = &ast.ident;
72 let class_name = struct_name.to_string();
73
74 let fields = if let syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(ref fields), .. }) = ast.data {
76 fields
77 }
78 else {
79 panic!("RubyClass can only be derived for structs with named fields");
80 };
81
82 let field_names: Vec<_> = fields
84 .named
85 .iter()
86 .map(|f| {
87 let name = &f.ident;
88 let name_str = name.as_ref().unwrap().to_string();
89 quote! { #name_str }
90 })
91 .collect();
92
93 let field_ids: Vec<_> = fields
94 .named
95 .iter()
96 .map(|f| {
97 let name = &f.ident;
98 quote! { #name }
99 })
100 .collect();
101
102 let expanded = quote! {
104 impl #struct_name {
105 pub fn to_ruby_value(&self) -> ::ruby_types::RubyValue {
107 use ::ruby_types::RubyValue;
108
109 let mut fields = std::collections::HashMap::new();
110 #(fields.insert(#field_names.to_string(), self.#field_ids.to_ruby_value());)*
111
112 RubyValue::Object(#class_name.to_string(), fields)
113 }
114
115 pub fn define_ruby_class(ruby: &mut ::ruby::Ruby) -> Result<(), Box<dyn std::error::Error>> {
117 ruby.define_class(#class_name)?;
118 Ok(())
119 }
120 }
121
122 impl ::ruby::ToRubyValue for #struct_name {
123 fn to_ruby_value(&self) -> ::ruby_types::RubyValue {
124 self.to_ruby_value()
125 }
126 }
127 };
128
129 TokenStream::from(expanded)
130}