stomp_parser 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5a04a9e96b78143103517610d026fe12603b2ebe
4
+ data.tar.gz: 660c92162ef6ad5cdc05f321ced1f36ce52999ab
5
+ SHA512:
6
+ metadata.gz: f20b1607fbba7e6f3a6be6a736c0bf5a63e90ef4e2f76d086cc617a3f564166b0b61523bdecb7d5a5748bfef0f164d1ccb8fbddd0c744da9991bf9e51c3a1096
7
+ data.tar.gz: c4f7189b20e941cb84547c970d9a3d4b8c3e118d15539ef3387c8bbda60ebd6cc98f7a1efab3560f65f624cf778e9b30515bb435f564818ceb74258bd1c3d3c3
@@ -0,0 +1,33 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/profile
19
+
20
+ # C extension
21
+ *.o
22
+ *.bundle
23
+ mkmf.log
24
+ Makefile
25
+ tmp/
26
+ spec/spec.log
27
+
28
+ # Ragel
29
+ lib/stomp_parser/ruby_parser.rb
30
+ lib/stomp_parser/c_parser.rb
31
+ ext/stomp_parser/c_parser.c
32
+ ext/java/stomp_parser/JavaParser.java
33
+ lib/stomp_parser/java_parser.jar
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -r spec_helper
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - rbx-2
7
+ - jruby
@@ -0,0 +1,2 @@
1
+ install ragel
2
+ install graphviz
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem "perftools.rb", platform: :mri
6
+ gem "benchmark-ips"
7
+
8
+ platforms :rbx do
9
+ gem "rb-readline"
10
+ gem "rubysl-singleton"
11
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Kim Burgestrand, Jonas Nicklas
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,59 @@
1
+ # StompParser
2
+
3
+ [![Build Status](https://travis-ci.org/stompede/stomp_parser.png?branch=master)](https://travis-ci.org/stompede/stomp_parser)
4
+ [![Gem Version](https://badge.fury.io/rb/stomp_parser.png)](http://badge.fury.io/rb/stomp_parser)
5
+
6
+ Fast STOMP parser and serializer for Ruby with native extensions in C for MRI
7
+ and Rubinius and in Java for JRuby, as well as a pure Ruby parser.
8
+
9
+ ## Parsing
10
+
11
+ ``` ruby
12
+ parser = StompParser::Parser.new
13
+ parser.parse(chunk) do |frame|
14
+ puts "We received #{frame.command} frame with #{frame.body} and headers #{frame.headers}!"
15
+ end
16
+ ```
17
+
18
+ The chunks do not have to be complete STOMP frames. The callback will be called
19
+ whenever a complete frame has been parsed. Additionally, StompParser handles
20
+ escape sequences in headers and body encoding for you.
21
+
22
+ ## Serializing
23
+
24
+ ``` ruby
25
+ StompParser::Frame.new("SEND", { some: "header" }, "Hello").to_str
26
+ ```
27
+
28
+ ## Development
29
+
30
+ Development should be ez.
31
+
32
+ ``` bash
33
+ git clone git@github.com:stompede/stomp_parser.git # git, http://git-scm.com/
34
+ cd stomp_parser
35
+ brew bundle # Homebrew, http://brew.sh/
36
+ bundle install # Bundler, http://bundler.io/
37
+ rake # compile state machine, run test suite
38
+ ```
39
+
40
+ A few notes:
41
+
42
+ - Native dependencies are listed in the Brewfile.
43
+ - The stomp message parser is written in [Ragel](http://www.complang.org/ragel/), see [parser_common.rl](parser_common.rl).
44
+ - Graphviz is used to visualize the Ragel state machine.
45
+ - Most rake tasks will compile the state machine anew if needed.
46
+
47
+ ## Contributing
48
+
49
+ 1. Fork it on GitHub (<http://github.com/stompede/stomp_parser/fork>).
50
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
51
+ 3. Follow the [Development](#development) instructions in this README.
52
+ 4. Create your changes, please add tests.
53
+ 5. Commit your changes (`git commit -am 'Add some feature'`).
54
+ 6. Push to the branch (`git push origin my-new-feature`).
55
+ 7. Create new pull request on GitHub.
56
+
57
+ ## License
58
+
59
+ [MIT](MIT-LICENSE.txt)
@@ -0,0 +1,85 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ def ragel(*args)
4
+ sh "ragel", "-I.", *args
5
+ end
6
+
7
+ # Build state machine before building gem.
8
+ task :build => :compile
9
+
10
+ file "parser_common.rl"
11
+
12
+ rule ".rb" => %w[.rb.rl parser_common.rl] do |t|
13
+ ragel "-F1", "-R", t.source, "-o", t.name
14
+ end
15
+
16
+ rule ".c" => %w[.c.rl parser_common.rl] do |t|
17
+ ragel "-G2", "-C", t.source, "-o", t.name
18
+ end
19
+
20
+ rule ".java" => %w[.java.rl parser_common.rl] do |t|
21
+ ragel "-T0", "-J", t.source, "-o", t.name
22
+ end
23
+
24
+ desc "ragel machines"
25
+ task :compile => %w[lib/stomp_parser/ruby_parser.rb]
26
+
27
+ case RUBY_ENGINE
28
+ when "rbx", "ruby"
29
+ require "rake/extensiontask"
30
+ task :compile => %w[ext/stomp_parser/c_parser.c]
31
+
32
+ Rake::ExtensionTask.new do |ext|
33
+ ext.name = "c_parser"
34
+ ext.ext_dir = "ext/stomp_parser"
35
+ ext.lib_dir = "lib/stomp_parser"
36
+ end
37
+ when "jruby"
38
+ require "rake/javaextensiontask"
39
+ task :compile => %w[ext/java/stomp_parser/JavaParser.java]
40
+
41
+ Rake::JavaExtensionTask.new do |ext|
42
+ ext.name = "java_parser"
43
+ ext.lib_dir = "lib/stomp_parser"
44
+ end
45
+ end
46
+
47
+ desc "ragel machines"
48
+ task :clean do |t|
49
+ source_tasks = Rake::Task[:compile].prerequisite_tasks.grep(Rake::FileTask)
50
+ rm_f source_tasks.map(&:name)
51
+ end
52
+
53
+ namespace :ragel do
54
+ desc "Show stomp parser state machine as an image"
55
+ task :show => "lib/stomp_parser/ruby_parser.rb" do |t|
56
+ mkdir_p "tmp"
57
+ ragel "-V", "-p", t.prerequisite_tasks[0].source, "-o", "tmp/parser.dot"
58
+ sh "dot -Tpng -O tmp/parser.dot"
59
+ rm "tmp/parser.dot"
60
+ sh "open tmp/parser.dot.png"
61
+ end
62
+ end
63
+
64
+ desc "Start a pry session with the gem loaded."
65
+ task :console => :compile do
66
+ exec "pry", "-rbundler/setup", "-rstomp_parser"
67
+ end
68
+
69
+ require "rspec/core/rake_task"
70
+ RSpec::Core::RakeTask.new(:spec)
71
+ task :spec => :compile
72
+
73
+ desc "Run all benchmarks."
74
+ task :bench => :compile do
75
+ sh "ruby", "-I.", *FileList["spec/benchmarks/**/*.rb"].flat_map { |x| ["-r", x] }, "-e", "''"
76
+ end
77
+
78
+ desc "Run the profiler and show a gif, requires perftools.rb"
79
+ task :profile => :compile do
80
+ # CPUPROFILE_METHODS=0 CPUPROFILE_OBJECTS=0 CPUPROFILE_REALTIME=1
81
+ sh "CPUPROFILE_REALTIME=1 ruby spec/profile.rb"
82
+ sh "pprof.rb --text spec/profile/parser.profile"
83
+ end
84
+
85
+ task :default => :spec
@@ -0,0 +1,179 @@
1
+ package stomp_parser;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyModule;
5
+ import org.jruby.RubyClass;
6
+ import org.jruby.RubyObject;
7
+ import org.jruby.RubyFixnum;
8
+ import org.jruby.RubyString;
9
+ import org.jruby.RubyNumeric;
10
+ import org.jruby.RubyException;
11
+ import org.jruby.exceptions.RaiseException;
12
+
13
+ import org.jruby.runtime.ThreadContext;
14
+ import org.jruby.runtime.builtin.IRubyObject;
15
+ import org.jruby.runtime.Block;
16
+
17
+ import org.jruby.anno.JRubyClass;
18
+ import org.jruby.anno.JRubyMethod;
19
+
20
+ %%{
21
+ machine frame;
22
+ alphtype byte;
23
+
24
+ action mark {
25
+ mark = p;
26
+ }
27
+
28
+ action mark_frame {
29
+ mark_frame = context.runtime.getClassFromPath("StompParser::Frame").callMethod("new", context.nil, context.nil);
30
+ mark_frame_size = 0;
31
+ }
32
+
33
+ action write_command {
34
+ mark_frame.callMethod(context, "write_command", RubyString.newString(context.runtime, data, mark, p - mark));
35
+ mark = -1;
36
+ }
37
+
38
+ action mark_key {
39
+ mark_key = RubyString.newString(context.runtime, data, mark, p - mark);
40
+ mark = -1;
41
+ }
42
+
43
+ action write_header {
44
+ IRubyObject args[] = { mark_key, RubyString.newString(context.runtime, data, mark, p - mark) };
45
+ mark_frame.callMethod(context, "write_header", args);
46
+ mark_key = null;
47
+ mark = -1;
48
+ }
49
+
50
+ action finish_headers {
51
+ IRubyObject content_length = mark_frame.callMethod(context, "content_length");
52
+
53
+ if ( ! content_length.isNil()) {
54
+ mark_content_length = RubyNumeric.num2int(content_length);
55
+ } else {
56
+ mark_content_length = -1;
57
+ }
58
+ }
59
+
60
+ action write_body {
61
+ mark_frame.callMethod(context, "write_body", RubyString.newString(context.runtime, data, mark, p - mark));
62
+ mark = -1;
63
+ }
64
+
65
+ action consume_null {
66
+ ((mark_content_length != -1) && ((p - mark) < mark_content_length))
67
+ }
68
+
69
+ action consume_octet {
70
+ ((mark_content_length == -1) || ((p - mark) < mark_content_length))
71
+ }
72
+
73
+ action check_frame_size {
74
+ mark_frame_size += 1;
75
+ if (mark_frame_size > maxFrameSize) {
76
+ RubyModule frameSizeExceeded = context.runtime.getClassFromPath("StompParser::FrameSizeExceeded");
77
+ RubyException error = (RubyException) frameSizeExceeded.callMethod("new");
78
+ throw new RaiseException(error);
79
+ }
80
+ }
81
+
82
+ action finish_frame {
83
+ block.yield(context, mark_frame);
84
+ mark_frame = null;
85
+ }
86
+
87
+ include frame_common "parser_common.rl";
88
+ }%%
89
+
90
+ @JRubyClass(name="JavaParser", parent="Object")
91
+ public class JavaParser extends RubyObject {
92
+ %% write data noprefix;
93
+
94
+ private class State {
95
+ public int cs = JavaParser.start;
96
+ public byte[] chunk;
97
+ public int mark = -1;
98
+ public RubyString mark_key;
99
+ public IRubyObject mark_frame;
100
+ public int mark_frame_size = -1;
101
+ public int mark_content_length = -1;
102
+ }
103
+
104
+ private RubyException parseError;
105
+ private long maxFrameSize;
106
+ private State state;
107
+
108
+ public JavaParser(Ruby runtime, RubyClass klass) {
109
+ super(runtime, klass);
110
+ state = new State();
111
+ parseError = null;
112
+ }
113
+
114
+ @JRubyMethod
115
+ public IRubyObject initialize(ThreadContext context) {
116
+ RubyModule mStompParser = context.runtime.getClassFromPath("StompParser");
117
+ return initialize(context, mStompParser.callMethod("max_frame_size"));
118
+ }
119
+
120
+ @JRubyMethod(argTypes = {RubyFixnum.class})
121
+ public IRubyObject initialize(ThreadContext context, IRubyObject maxFrameSize) {
122
+ this.maxFrameSize = ((RubyFixnum) maxFrameSize).getLongValue();
123
+ return context.nil;
124
+ }
125
+
126
+ @JRubyMethod(argTypes = {RubyString.class})
127
+ public IRubyObject parse(ThreadContext context, IRubyObject chunk, Block block) {
128
+ if (parseError == null) {
129
+ int p;
130
+ byte data[] = null;
131
+ byte bytes[] = ((RubyString) chunk).getBytes();
132
+
133
+ if (state.chunk != null) {
134
+ p = state.chunk.length;
135
+ data = new byte[state.chunk.length + bytes.length];
136
+ System.arraycopy(state.chunk, 0, data, 0, state.chunk.length);
137
+ System.arraycopy(bytes, 0, data, state.chunk.length, bytes.length);
138
+ } else {
139
+ p = 0;
140
+ data = bytes;
141
+ }
142
+
143
+ int pe = data.length;
144
+
145
+ int cs = state.cs;
146
+ int mark = state.mark;
147
+ RubyString mark_key = state.mark_key;
148
+ IRubyObject mark_frame = state.mark_frame;
149
+ int mark_frame_size = state.mark_frame_size;
150
+ int mark_content_length = state.mark_content_length;
151
+
152
+ %% write exec;
153
+
154
+ if (mark != -1) {
155
+ state.chunk = data;
156
+ } else {
157
+ state.chunk = null;
158
+ }
159
+
160
+ state.cs = cs;
161
+ state.mark = mark;
162
+ state.mark_key = mark_key;
163
+ state.mark_frame = mark_frame;
164
+ state.mark_frame_size = mark_frame_size;
165
+ state.mark_content_length = mark_content_length;
166
+
167
+ if (cs == error) {
168
+ IRubyObject args[] = { RubyString.newString(context.runtime, data), RubyFixnum.newFixnum(context.runtime, (long) p) };
169
+ parseError = (RubyException) context.runtime.getClassFromPath("StompParser").callMethod(context, "build_parse_error", args);
170
+ }
171
+ }
172
+
173
+ if (parseError != null) {
174
+ throw new RaiseException(parseError);
175
+ }
176
+
177
+ return context.nil;
178
+ }
179
+ }
@@ -0,0 +1,23 @@
1
+ package stomp_parser;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.RubyModule;
6
+ import org.jruby.runtime.load.BasicLibraryService;
7
+ import org.jruby.runtime.builtin.IRubyObject;
8
+ import org.jruby.runtime.ObjectAllocator;
9
+
10
+ public class JavaParserService implements BasicLibraryService {
11
+ public boolean basicLoad(Ruby ruby) {
12
+ RubyModule mStomp = ruby.getClassFromPath("StompParser");
13
+ RubyClass cJavaParser = ruby.defineClassUnder("JavaParser", ruby.getObject(), JAVA_PARSER_ALLOCATOR, mStomp);
14
+ cJavaParser.defineAnnotatedMethods(JavaParser.class);
15
+ return true;
16
+ }
17
+
18
+ private static final ObjectAllocator JAVA_PARSER_ALLOCATOR = new ObjectAllocator() {
19
+ public IRubyObject allocate(Ruby ruby, RubyClass klass) {
20
+ return new JavaParser(ruby, klass);
21
+ }
22
+ };
23
+ }
@@ -0,0 +1,225 @@
1
+ #include <ruby.h>
2
+
3
+ #if DEBUG_H
4
+ # define DEBUG(fmt, ...) do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); } while(0)
5
+ #else
6
+ # define DEBUG(...)
7
+ #endif
8
+
9
+ #define UNUSED(x) (void)(x)
10
+ #define MARK_LEN (p - mark)
11
+ #define MARK_STR_NEW() rb_str_new(mark, MARK_LEN)
12
+
13
+ #define true 1
14
+ #define false 0
15
+
16
+ typedef struct {
17
+ VALUE error;
18
+ long max_frame_size;
19
+
20
+ VALUE chunk;
21
+ const char *p;
22
+ int cs;
23
+ const char *mark;
24
+ VALUE mark_key;
25
+ VALUE mark_frame;
26
+ long mark_frame_size;
27
+ long mark_content_length;
28
+ } parser_state_t;
29
+
30
+ VALUE mStompParser = Qnil;
31
+ VALUE cFrame = Qnil;
32
+ VALUE eFrameSizeExceeded = Qnil;
33
+ ID g_new;
34
+ ID g_write_command;
35
+ ID g_write_header;
36
+ ID g_write_body;
37
+ ID g_content_length;
38
+ ID g_build_parse_error;
39
+ ID g_max_frame_size;
40
+
41
+ %%{
42
+ machine frame;
43
+
44
+ action mark {
45
+ mark = p;
46
+ }
47
+
48
+ action mark_frame {
49
+ mark_frame = rb_funcall(cFrame, g_new, 2, Qnil, Qnil);
50
+ mark_frame_size = 0;
51
+ }
52
+
53
+ action write_command {
54
+ rb_funcall(mark_frame, g_write_command, 1, MARK_STR_NEW());
55
+ mark = NULL;
56
+ }
57
+
58
+ action mark_key {
59
+ mark_key = MARK_STR_NEW();
60
+ mark = NULL;
61
+ }
62
+
63
+ action write_header {
64
+ rb_funcall(mark_frame, g_write_header, 2, mark_key, MARK_STR_NEW());
65
+ mark_key = Qnil;
66
+ mark = NULL;
67
+ }
68
+
69
+ action finish_headers {
70
+ VALUE length = rb_funcall(mark_frame, g_content_length, 0);
71
+ if ( ! NIL_P(length)) {
72
+ mark_content_length = NUM2LONG(length);
73
+ } else {
74
+ mark_content_length = -1;
75
+ }
76
+ }
77
+
78
+ action write_body {
79
+ rb_funcall(mark_frame, g_write_body, 1, MARK_STR_NEW());
80
+ mark = NULL;
81
+ }
82
+
83
+ action consume_null {
84
+ ((mark_content_length != -1) && (MARK_LEN < mark_content_length))
85
+ }
86
+
87
+ action consume_octet {
88
+ ((mark_content_length == -1) || (MARK_LEN < mark_content_length))
89
+ }
90
+
91
+ action check_frame_size {
92
+ mark_frame_size += 1;
93
+ if (mark_frame_size > max_frame_size) {
94
+ rb_raise(eFrameSizeExceeded, "");
95
+ }
96
+ }
97
+
98
+ action finish_frame {
99
+ rb_yield(mark_frame);
100
+ mark_frame = Qnil;
101
+ }
102
+
103
+ include frame_common "parser_common.rl";
104
+
105
+ write data noprefix;
106
+ }%%
107
+
108
+ static void parser_free(parser_state_t *state) {
109
+ // TODO: free memory inside struct!
110
+ xfree(state);
111
+ }
112
+
113
+ static void parser_mark(parser_state_t *state) {
114
+ rb_gc_mark(state->error);
115
+ rb_gc_mark(state->mark_key);
116
+ rb_gc_mark(state->mark_frame);
117
+ rb_gc_mark(state->chunk);
118
+ }
119
+
120
+ static VALUE parser_alloc(VALUE klass) {
121
+ parser_state_t *state = ALLOC(parser_state_t);
122
+ return Data_Wrap_Struct(klass, parser_mark, parser_free, state);
123
+ }
124
+
125
+ static VALUE parser_initialize(int argc, VALUE *argv, VALUE self) {
126
+ parser_state_t *state;
127
+ Data_Get_Struct(self, parser_state_t, state);
128
+
129
+ VALUE max_frame_size;
130
+ rb_scan_args(argc, argv, "01", &max_frame_size);
131
+
132
+ if (max_frame_size == Qnil) {
133
+ max_frame_size = rb_funcall(mStompParser, g_max_frame_size, 0);
134
+ }
135
+
136
+ state->error = Qnil;
137
+ state->max_frame_size = FIX2LONG(max_frame_size);
138
+ state->chunk = Qnil;
139
+ state->cs = start;
140
+ state->mark = NULL;
141
+ state->mark_key = Qnil;
142
+ state->mark_frame = Qnil;
143
+ state->mark_frame_size = 0;
144
+ state->mark_content_length = 0;
145
+
146
+ return self;
147
+ }
148
+
149
+ static VALUE parser_parse(VALUE self, VALUE new_chunk) {
150
+ parser_state_t *state;
151
+ Data_Get_Struct(self, parser_state_t, state);
152
+
153
+ if (NIL_P(state->error)) {
154
+ VALUE chunk = Qnil;
155
+ const char *p = NULL;
156
+ const char *mark = NULL;
157
+
158
+ if ( ! NIL_P(state->chunk)) {
159
+ long offset = RSTRING_LEN(state->chunk);
160
+ long mark_offset = state->mark - RSTRING_PTR(state->chunk);
161
+
162
+ chunk = rb_str_append(state->chunk, new_chunk);
163
+ p = RSTRING_PTR(chunk) + offset;
164
+ mark = RSTRING_PTR(chunk) + mark_offset;
165
+ } else {
166
+ chunk = new_chunk;
167
+ p = RSTRING_PTR(chunk);
168
+ }
169
+
170
+ const char *pe = RSTRING_END(chunk);
171
+ long max_frame_size = state->max_frame_size;
172
+
173
+ int cs = state->cs;
174
+ VALUE mark_key = state->mark_key;
175
+ VALUE mark_frame = state->mark_frame;
176
+ long mark_frame_size = state->mark_frame_size;
177
+ long mark_content_length = state->mark_content_length;
178
+
179
+ %% write exec;
180
+
181
+ if (mark != NULL) {
182
+ state->chunk = chunk;
183
+ } else {
184
+ state->chunk = Qnil;
185
+ }
186
+
187
+ state->cs = cs;
188
+ state->mark = mark;
189
+ state->mark_key = mark_key;
190
+ state->mark_frame = mark_frame;
191
+ state->mark_frame_size = mark_frame_size;
192
+ state->mark_content_length = mark_content_length;
193
+
194
+ if (cs == error) {
195
+ long index = p - RSTRING_PTR(chunk);
196
+ state->error = rb_funcall(mStompParser, g_build_parse_error, 2, chunk, LONG2NUM(index));
197
+ }
198
+ }
199
+
200
+ if ( ! NIL_P(state->error)) {
201
+ rb_exc_raise(state->error);
202
+ }
203
+
204
+ return Qnil;
205
+ }
206
+
207
+ void Init_c_parser(void) {
208
+ mStompParser = rb_const_get(rb_cObject, rb_intern("StompParser"));
209
+ cFrame = rb_const_get(mStompParser, rb_intern("Frame"));
210
+ eFrameSizeExceeded = rb_const_get(mStompParser, rb_intern("FrameSizeExceeded"));
211
+
212
+ g_new = rb_intern("new");
213
+ g_write_command = rb_intern("write_command");
214
+ g_write_header = rb_intern("write_header");
215
+ g_write_body = rb_intern("write_body");
216
+ g_content_length = rb_intern("content_length");
217
+ g_build_parse_error = rb_intern("build_parse_error");
218
+ g_max_frame_size = rb_intern("max_frame_size");
219
+
220
+ VALUE cParser = rb_define_class_under(mStompParser, "CParser", rb_cObject);
221
+ rb_define_alloc_func(cParser, parser_alloc);
222
+
223
+ rb_define_method(cParser, "initialize", parser_initialize, -1);
224
+ rb_define_method(cParser, "parse", parser_parse, 1);
225
+ }