Skip to content

Instantly share code, notes, and snippets.

@Asmod4n
Last active August 29, 2015 14:27

Revisions

  1. Asmod4n revised this gist Aug 19, 2015. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions zproto_codec_mruby.gsl
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,7 @@
    .gsl from "zproto_codec_c.gsl"

    // zproto_codec_mruby.gsl
    // Generates a codec for a protocol specification.

    .gsl from "zproto_codec_c.gsl"
    .output "$(class.source_dir)/mrb_$(class.name)_body.h"
    /* =========================================================================
    $(class.name) - $(class.title:)
    @@ -336,7 +335,7 @@ mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    zlist_t *$(name)s = $(class.name)_$(name) (self);

    int ai = mrb_gc_arena_save (mrb);
    mrb_value $(name) = mrb_ary_new_capa (mrb, zlist_size ($(name)s);
    mrb_value $(name) = mrb_ary_new_capa (mrb, zlist_size ($(name)s));
    char *item = (char *) zlist_first ($(name)s);
    while (item) {
    mrb_value item_obj = mrb_str_new_static (mrb, item, strlen (item));
    @@ -589,7 +588,7 @@ mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    .output "$(class.source_dir)/mrb_$(class.name)_gem_init.h"
    struct RClass *$(class.name)_class;

    $(class.name)_class = mrb_define_class (mrb, "$(class.name:camel)", mrb->object_class);
    $(class.name)_class = mrb_define_class (mrb, "$(class.name:Neat,Camel)", mrb->object_class);
    MRB_SET_INSTANCE_TT($(class.name)_class, MRB_TT_DATA);
    int ai = mrb_gc_arena_save (mrb);
    .for define
  2. Asmod4n revised this gist Aug 19, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions zproto_codec_mruby.gsl
    Original file line number Diff line number Diff line change
    @@ -305,7 +305,7 @@ mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)

    const char *$(name) = $(class.name)_$(name) (self);

    return mrb_str_new_static(mrb, $(name), strlen ($(name)));
    return mrb_str_new_static (mrb, $(name), strlen ($(name)));
    }

    // Set the $(name) field
    @@ -593,7 +593,7 @@ mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    MRB_SET_INSTANCE_TT($(class.name)_class, MRB_TT_DATA);
    int ai = mrb_gc_arena_save (mrb);
    .for define
    mrb_define_const (mrb, $(class.name)_class, "$(DEFINE.NAME)", mrb_str_new_static (mrb, "$(value:)"), strlen ("$(value:)"));
    mrb_define_const (mrb, $(class.name)_class, "$(DEFINE.NAME)", mrb_str_new_static (mrb, "$(value:)", strlen ("$(value:)"));
    mrb_gc_arena_restore (mrb, ai);
    .endfor
    .for message
  3. Asmod4n revised this gist Aug 19, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions zproto_codec_mruby.gsl
    Original file line number Diff line number Diff line change
    @@ -40,6 +40,7 @@
    #include <mruby/error.h>
    #include <mruby/hash.h>
    #include <mruby/string.h>
    #include <mruby/throw.h>

    static void
    mrb_$(class.name)_destroy (mrb_state *mrb, void *p)
  4. Asmod4n revised this gist Aug 19, 2015. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions zproto_codec_mruby.gsl
    Original file line number Diff line number Diff line change
    @@ -35,6 +35,7 @@
    #include <errno.h>
    #include <mruby.h>
    #include <mruby/array.h>
    #include <mruby/class.h>
    #include <mruby/data.h>
    #include <mruby/error.h>
    #include <mruby/hash.h>
    @@ -145,7 +146,7 @@ mrb_$(class.name)_print (mrb_state *mrb, mrb_value mrb_self)
    }

    // --------------------------------------------------------------------------
    // Get/set the message routing_id
    // Get the message routing_id

    static mrb_value
    mrb_$(class.name)_routing_id (mrb_state *mrb, mrb_value mrb_self)
    @@ -157,6 +158,8 @@ mrb_$(class.name)_routing_id (mrb_state *mrb, mrb_value mrb_self)
    return mrb_str_new_static (mrb, zframe_data (routing_id), zframe_size (routing_id));
    }

    // Set the message routing_id

    static mrb_value
    mrb_$(class.name)_set_routing_id (mrb_state *mrb, mrb_value mrb_self)
    {
    @@ -569,11 +572,11 @@ mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    int ai = mrb_gc_arena_save (mrb);
    for (;$(name)s < $(name)s_end ; $(name)s++) {
    mrb_value s = mrb_str_to_str (mrb, *$(name)s);
    mrb_gc_arena_restore (mrb, ai);
    if (zmsg_addmem ($(name), RSTRING_PTR (s), RSTRING_LEN (s)) == -1) {
    zmsg_destroy (&$(name));
    mrb_sys_fail (mrb, "zmsg_addmem");
    }
    mrb_gc_arena_restore (mrb, ai);
    }

    $(class.name)_set_$(name) (self, &$(name));
  5. Asmod4n created this gist Aug 19, 2015.
    623 changes: 623 additions & 0 deletions zproto_codec_mruby.gsl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,623 @@
    .gsl from "zproto_codec_c.gsl"

    // zproto_codec_mruby.gsl
    // Generates a codec for a protocol specification.

    .output "$(class.source_dir)/mrb_$(class.name)_body.h"
    /* =========================================================================
    $(class.name) - $(class.title:)

    Codec class for $(class.name).

    ** WARNING *************************************************************
    THIS SOURCE FILE IS 100% GENERATED. If you edit this file, you will lose
    your changes at the next build cycle. This is great for temporary printf
    statements. DO NOT MAKE ANY CHANGES YOU WISH TO KEEP. The correct places
    for commits are:

    * The XML model used for this code generation: $(filename), or
    * The code generation script that built this file: $(script)
    ************************************************************************
    . for class.license
    $(string.trim (license.):block )
    . endfor
    =========================================================================
    */

    /*
    @header
    $(class.name) - $(class.title:)
    @discuss
    @end
    */

    #include "$(class.package_dir)/$(class.name).h"
    #include <errno.h>
    #include <mruby.h>
    #include <mruby/array.h>
    #include <mruby/data.h>
    #include <mruby/error.h>
    #include <mruby/hash.h>
    #include <mruby/string.h>

    static void
    mrb_$(class.name)_destroy (mrb_state *mrb, void *p)
    {
    $(class.name)_destroy (($(class.name)_t **) &p);
    }

    static const struct mrb_data_type mrb_$(class.name)_type = {
    "i_$(class.name)_type", mrb_$(class.name)_destroy
    };

    // --------------------------------------------------------------------------
    // Create a new $(class.name)

    static mrb_value
    mrb_$(class.name)_initialize (mrb_state *mrb, mrb_value mrb_self)
    {
    errno = 0;
    $(class.name)_t *self = $(class.name)_new ();
    if (self == NULL) {
    mrb_sys_fail (mrb, "$(class.name)_new");
    }

    mrb_data_init (mrb_self, self, &mrb_$(class.name)_type);

    return mrb_self;
    }

    // --------------------------------------------------------------------------
    // Receive a $(class.name) from the socket. Returns self if OK, else raises an exception.
    // Blocks if there is no message waiting.

    static mrb_value
    mrb_$(class.name)_recv (mrb_state *mrb, mrb_value mrb_self)
    {
    errno = 0;
    mrb_value input_obj;

    mrb_get_args (mrb, "o", &input_obj);

    if (mrb_type (input_obj) != MRB_TT_DATA)
    mrb_raise(mrb, E_ARGUMENT_ERROR, "input is not a data type");

    .if class.virtual ?= 1
    mrb_assert (zmsg_is (DATA_PTR (input_obj)));
    zmsg_t *input = (zmsg_t *) DATA_PTR (input_obj);
    .else
    mrb_assert (zsock_is (DATA_PTR (input_obj)));
    zsock_t *input = (zsock_t *) DATA_PTR (input_obj);
    .endif

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    if ($(class.name)_recv (self, input) == -1) {
    mrb_sys_fail (mrb, "$(class.name)_recv");
    }

    return mrb_self;
    }

    // --------------------------------------------------------------------------
    // Send the $(class.name) to the socket. Does not destroy it. Returns self if
    // OK, else raises an exception.

    static mrb_value
    mrb_$(class.name)_send (mrb_state *mrb, mrb_value mrb_self)
    {
    errno = 0;
    mrb_value output_obj;

    mrb_get_args (mrb, "o", &output_obj);

    if (mrb_type (output_obj) != MRB_TT_DATA)
    mrb_raise(mrb, E_ARGUMENT_ERROR, "output is not a data type");

    .if class.virtual ?= 1
    mrb_assert (zmsg_is (DATA_PTR (output_obj)));
    zmsg_t *output = (zmsg_t *) DATA_PTR (output_obj);
    .else
    mrb_assert (zsock_is (DATA_PTR (output_obj)));
    zsock_t *output = (zsock_t *) DATA_PTR (output_obj);
    .endif

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    if ($(class.name)_send (self, output) == -1) {
    mrb_sys_fail (mrb, "$(class.name)_send");
    }

    return mrb_self;
    }

    // --------------------------------------------------------------------------
    // Print contents of message to stdout

    static mrb_value
    mrb_$(class.name)_print (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    $(class.name)_print (self);

    return mrb_self;
    }

    // --------------------------------------------------------------------------
    // Get/set the message routing_id

    static mrb_value
    mrb_$(class.name)_routing_id (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zframe_t *routing_id = $(class.name)_routing_id (self);

    return mrb_str_new_static (mrb, zframe_data (routing_id), zframe_size (routing_id));
    }

    static mrb_value
    mrb_$(class.name)_set_routing_id (mrb_state *mrb, mrb_value mrb_self)
    {
    char *routing_id_str;
    mrb_int routing_id_len;

    mrb_get_args (mrb, "s", &routing_id_str, &routing_id_len);

    if (routing_id_len > 256) {
    mrb_raise (mrb, E_RANGE_ERROR, "routing_id is too large");
    }

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zframe_t *routing_id = zframe_new (routing_id_str, routing_id_len);

    $(class.name)_set_routing_id (self, routing_id);

    zframe_destroy (&routing_id);

    return mrb_self;
    }

    // --------------------------------------------------------------------------
    // Get the $(class.name) id

    static mrb_value
    mrb_$(class.name)_id (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    // TODO: add bounds checking

    return mrb_fixnum_value ($(class.name)_id (self));
    }

    // Set the $(class.name) id

    static mrb_value
    mrb_$(class.name)_set_id (mrb_state *mrb, mrb_value mrb_self)
    {
    mrb_int id;

    mrb_get_args (mrb, "i", &id);

    if (id < INT_MIN || id > INT_MAX)
    mrb_raise (mrb, E_RANGE_ERROR, "id is out of range");

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    $(class.name)_set_id (self, id);

    return mrb_self;
    }

    // --------------------------------------------------------------------------
    // Return a printable command string

    static mrb_value
    mrb_$(class.name)_command (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    const char *command = $(class.name)_command (self);

    return mrb_str_new_static (mrb, command, strlen (command));
    }

    .for class.field where !defined (value)
    . if type = "number"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    // TODO: add bounds checking

    return mrb_fixnum_value ($(class.name)_$(name) (self));
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    mrb_int $(name);

    mrb_get_args (mrb, "i", &$(name));

    // TODO: add bounds checking

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    $(class.name)_set_$(name) (self, $(name));

    return mrb_self;
    }

    . elsif type = "octets"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    return mrb_str_new_static (mrb, $(class.name)_$(name) (self), $(size));
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    byte *$(name);
    mrb_int $(name)_len;

    mrb_get_args (mrb, "s", &$(name), $(name)_len);

    if ($(name)_len != $(size))
    mrb_raise (mrb, E_ARGUMENT_ERROR, "$(name) must be $(size) bytes long");

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    $(class.name)_set_$(name) (self, $(name));

    return mrb_self;
    }

    . elsif type = "string" | type = "longstr"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    const char *$(name) = $(class.name)_$(name) (self);

    return mrb_str_new_static(mrb, $(name), strlen ($(name)));
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    char *$(name);

    mrb_get_args (mrb, "z", &$(name));

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    $(class.name)_set_$(name) (self, $(name));

    return mrb_self;
    }

    . elsif type = "strings"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zlist_t *$(name)s = $(class.name)_$(name) (self);

    int ai = mrb_gc_arena_save (mrb);
    mrb_value $(name) = mrb_ary_new_capa (mrb, zlist_size ($(name)s);
    char *item = (char *) zlist_first ($(name)s);
    while (item) {
    mrb_value item_obj = mrb_str_new_static (mrb, item, strlen (item));
    mrb_ary_push (mrb, $(name), item_obj);
    mrb_gc_arena_restore (mrb, ai);
    item = (char *) zlist_next ($(name)s);
    }

    return $(name);
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    errno = 0;
    mrb_value *$(name)s;
    mrb_int $(name)_len;

    mrb_get_args (mrb, "a", &$(name)s, &$(name)_len);

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    mrb_value *$(name)s_end = $(name)s + $(name)_len;

    zlist_t *$(name) = zlist_new ();
    if ($(name) == NULL) {
    mrb_sys_fail (mrb, "zlist_new");
    }

    int ai = mrb_gc_arena_save (mrb);
    for (;$(name)s < $(name)_end ; $(name)s++) {
    const char *item = mrb_string_value_cstr (mrb, &*$(name)s);
    mrb_gc_arena_restore (mrb, ai);
    if (zlist_append ($(name), item) == -1) {
    zlist_destroy (&$(name));
    mrb_sys_fail (mrb, "zlist_append");
    }
    }

    $(class.name)_set_$(name) (self, &$(name));

    return mrb_self;
    }

    . elsif type = "hash"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zhash_t *$(name)s = $(class.name)_$(name) (self);

    int ai = mrb_gc_arena_save (mrb);
    mrb_value $(name) = mrb_hash_new_capa (mrb, zhash_size ($(name)s));
    char *item = (char *) zhash_first ($(name)s);
    while (item) {
    const char *key = zhash_cursor ($(name)s);
    mrb_value key_obj = mrb_str_new_static (mrb, key, strlen (key));
    mrb_value item_obj = mrb_str_new_static (mrb, item, strlen (item));
    mrb_hash_set (mrb, $(name), key_obj, item_obj);
    mrb_gc_arena_restore (mrb, ai);
    item = (char *) zhash_next ($(name)s);
    }

    return $(name);
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    errno = 0;
    mrb_value $(name)s;

    mrb_get_args (mrb, "H", &$(name)s);

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zhash_t *$(name) = zhash_new ();
    if ($(name) == NULL) {
    mrb_sys_fail (mrb, "zhash_new");
    }

    int ai = mrb_gc_arena_save (mrb);
    mrb_value keys = mrb_hash_keys (mrb, $(name)s);
    for (mrb_int i = 0; i != RARRAY_LEN(keys); i++) {
    mrb_value key_obj = mrb_ary_ref(mrb, keys, i);
    const char *key = mrb_string_value_cstr (mrb, &key_obj);
    mrb_value item_obj = mrb_hash_get (mrb, $(name)s, key_obj);
    const char *item = mrb_string_value_cstr (mrb, &item_obj);
    mrb_gc_arena_restore (mrb, ai);
    if (zhash_insert ($(name), key, item) == -1) {
    mrb_sys_fail (mrb, "zhash_insert");
    }
    }

    $(class.name)_set_$(name) (self, &$(name));

    return mrb_self;
    }

    . elsif type = "uuid"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zuuid_t *$(name) = $(class.name)_$(name) (self);

    return mrb_str_new_static (mrb, zuuid_data ($(name)), zuuid_size ($(name)));
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    char *$(name)_str;
    mrb_int $(name)_len;

    mrb_get_args (mrb, "s", &$(name)_str, &$(name)_len);

    if ($(name)_len != ZUUID_LEN)
    mrb_raisef (mrb, E_ARGUMENT_ERROR, "uuid must be %S bytes long", mrb_fixnum_value (ZUUID_LEN));

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zuuid_t *$(name) = zuuid_new_from ($(name)_str);
    $(class.name)_set_$(name) (self, $(name));
    zuuid_destroy (&$(name));

    return mrb_self;
    }

    // Create a $(name)

    static mrb_value
    mrb_$(class.name)_create_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zuuid_t *$(name) = zuuid_new ();
    $(class.name)_set_$(name) (self, $(name));
    zuuid_destroy (&$(name));

    return mrb_self;
    }

    . elsif type = "chunk" | type = "frame"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    z$(type)_t *$(name) = $(class.name)_$(name) (self);

    return mrb_str_new_static (mrb, z$(type)_data ($(name)), z$(type)_size ($(name)));
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    char *$(name)_str;
    mrb_int $(name)_len;

    mrb_get_args (mrb, "s", &$(name)_str, &$(name)_len);

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    z$(type)_t *$(name) = z$(type)_new ($(name)_str, $(name)_len);

    $(class.name)_set_$(name) (self, &$(name));

    return mrb_self;
    }

    . elsif type = "msg"
    // --------------------------------------------------------------------------
    // Get the $(name) field

    static mrb_value
    mrb_$(class.name)_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zmsg_t *$(name)s = $(class.name)_$(name) (self);

    int ai = mrb_gc_arena_save(mrb);
    mrb_value $(name) = mrb_ary_new_capa (mrb, zmsg_size ($(name)s));
    zframe_t *item = zmsg_first ($(name));
    while (item) {
    mrb_value $(name)_str = mrb_str_new_static (mrb, zframe_data (item), zframe_size (item));
    mrb_ary_push (mrb, $(name), $(name)_str);
    mrb_gc_arena_restore (mrb, ai);
    item = zmsg_next ($(name)s);
    }

    return $(name);
    }

    // Set the $(name) field

    static mrb_value
    mrb_$(class.name)_set_$(name) (mrb_state *mrb, mrb_value mrb_self)
    {
    errno = 0;
    mrb_value *$(name)s;
    mrb_int $(name)_len;

    mrb_get_args (mrb, "a", &$(name)s, &$(name)_len);

    $(class.name)_t *self = ($(class.name)_t *) DATA_PTR (mrb_self);

    zmsg_t *$(name) = zmsg_new ();
    if ($(name) == NULL) {
    mrb_sys_fail (mrb, "zmsg_new");
    }

    mrb_value *$(name)s_end = $(name)s + $(name)_len;
    int ai = mrb_gc_arena_save (mrb);
    for (;$(name)s < $(name)s_end ; $(name)s++) {
    mrb_value s = mrb_str_to_str (mrb, *$(name)s);
    if (zmsg_addmem ($(name), RSTRING_PTR (s), RSTRING_LEN (s)) == -1) {
    zmsg_destroy (&$(name));
    mrb_sys_fail (mrb, "zmsg_addmem");
    }
    mrb_gc_arena_restore (mrb, ai);
    }

    $(class.name)_set_$(name) (self, &$(name));

    return mrb_self;
    }
    . endif
    .endfor
    .output "$(class.source_dir)/mrb_$(class.name)_gem_init.h"
    struct RClass *$(class.name)_class;

    $(class.name)_class = mrb_define_class (mrb, "$(class.name:camel)", mrb->object_class);
    MRB_SET_INSTANCE_TT($(class.name)_class, MRB_TT_DATA);
    int ai = mrb_gc_arena_save (mrb);
    .for define
    mrb_define_const (mrb, $(class.name)_class, "$(DEFINE.NAME)", mrb_str_new_static (mrb, "$(value:)"), strlen ("$(value:)"));
    mrb_gc_arena_restore (mrb, ai);
    .endfor
    .for message
    mrb_define_const (mrb, $(class.name)_class, "$(MESSAGE.NAME)", mrb_fixnum_value ($(id)));
    mrb_gc_arena_restore (mrb, ai);
    .endfor
    .for class.field where type = "octets"
    mrb_define_const (mrb, $(class.name)_class, "$(FIELD.NAME)_SIZE", mrb_fixnum_value ($(size)));
    mrb_gc_arena_restore (mrb, ai);
    .endfor
    mrb_define_method (mrb, $(class.name)_class, "initialize", mrb_$(class.name)_initialize, MRB_ARGS_NONE());
    mrb_define_method (mrb, $(class.name)_class, "recv", mrb_$(class.name)_recv, MRB_ARGS_REQ(1));
    mrb_define_method (mrb, $(class.name)_class, "send", mrb_$(class.name)_send, MRB_ARGS_REQ(1));
    mrb_define_method (mrb, $(class.name)_class, "print", mrb_$(class.name)_print, MRB_ARGS_NONE());
    mrb_define_method (mrb, $(class.name)_class, "routing_id", mrb_$(class.name)_routing_id, MRB_ARGS_NONE());
    mrb_define_method (mrb, $(class.name)_class, "routing_id=", mrb_$(class.name)_set_routing_id, MRB_ARGS_REQ(1));
    mrb_define_method (mrb, $(class.name)_class, "id", mrb_$(class.name)_id, MRB_ARGS_NONE());
    mrb_define_method (mrb, $(class.name)_class, "id=", mrb_$(class.name)_set_id, MRB_ARGS_REQ(1));
    mrb_define_method (mrb, $(class.name)_class, "command", mrb_$(class.name)_command, MRB_ARGS_REQ(1));
    .for class.field where !defined (value)
    . if type = "number" | type = "octets" | type = "string" | type = "longstr" | type = "strings" | type = "hash" | type = "chunk" | type = "frame" | type = "msg"
    mrb_define_method (mrb, $(class.name)_class, "$(name)", mrb_$(class.name)_$(name), MRB_ARGS_NONE());
    mrb_define_method (mrb, $(class.name)_class, "$(name)=", mrb_$(class.name)_set_$(name), MRB_ARGS_REQ(1));
    . elsif type = "uuid"
    mrb_define_method (mrb, $(class.name)_class, "$(name)", mrb_$(class.name)_$(name), MRB_ARGS_NONE());
    mrb_define_method (mrb, $(class.name)_class, "$(name)=", mrb_$(class.name)_set_$(name), MRB_ARGS_REQ(1));
    mrb_define_method (mrb, $(class.name)_class, "create_$(name)", mrb_$(class.name)_create_$(name), MRB_ARGS_NONE());
    . else
    . echo "E: unknown type '$(type)' for field '$(name)'"
    . endif
    .endfor