stomp_parser 1.0.0-universal-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc2d9bd4c0e92423027543f02348d68441534536
4
+ data.tar.gz: a16e1abf7f2eda5f48932fe148e72e7e14d3f88e
5
+ SHA512:
6
+ metadata.gz: 67fb331703eb2b68e2aa70fc38f50883a09f0016c20210ff8aa5f7a9242a76162493f5535d371eb192563693215387ca3590ff7ebd6baa324e05242e6cbf223a
7
+ data.tar.gz: 59585100cab11f493bd3063905c543928e8d2abe4eb80217bd133771cfc257b0ff5c151769d7ef0718e4c135bab993e1cb02a14741d7ee166785b425f225cede
data/.gitignore ADDED
@@ -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
data/.travis.yml ADDED
@@ -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
data/Brewfile ADDED
@@ -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
data/MIT-LICENSE.txt ADDED
@@ -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.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # StompParser
2
+
3
+ [![Build Status](https://travis-ci.org/stompede/stomp_parser.png?branch=master)](https://travis-ci.org/stompede/stomp_parser)
4
+ [![Code Climate](https://codeclimate.com/github/stompede/stomp_parser.png)](https://codeclimate.com/github/stompede/stomp_parser)
5
+ [![Gem Version](https://badge.fury.io/rb/stomp_parser.png)](http://badge.fury.io/rb/stomp_parser)
6
+
7
+ Fast STOMP parser and serializer for Ruby with native extensions in C for MRI
8
+ and Rubinius and in Java for JRuby, as well as a pure Ruby parser.
9
+
10
+ ## Parsing
11
+
12
+ ``` ruby
13
+ parser = StompParser::Parser.new
14
+ parser.parse(chunk) do |frame|
15
+ puts "We received #{frame.command} frame with #{frame.body} and headers #{frame.headers}!"
16
+ end
17
+ ```
18
+
19
+ The chunks do not have to be complete STOMP frames. The callback will be called
20
+ whenever a complete frame has been parsed. Additionally, StompParser handles
21
+ escape sequences in headers and body encoding for you.
22
+
23
+ ## Serializing
24
+
25
+ ``` ruby
26
+ StompParser::Frame.new("SEND", { some: "header" }, "Hello").to_str
27
+ ```
28
+
29
+ ## Development
30
+
31
+ Development should be ez.
32
+
33
+ ``` bash
34
+ git clone git@github.com:stompede/stomp_parser.git # git, http://git-scm.com/
35
+ cd stomp_parser
36
+ brew bundle # Homebrew, http://brew.sh/
37
+ bundle install # Bundler, http://bundler.io/
38
+ rake # compile state machine, run test suite
39
+ ```
40
+
41
+ A few notes:
42
+
43
+ - Native dependencies are listed in the Brewfile.
44
+ - The stomp message parser is written in [Ragel](http://www.complang.org/ragel/), see [parser_common.rl](parser_common.rl).
45
+ - Graphviz is used to visualize the Ragel state machine.
46
+ - Most rake tasks will compile the state machine anew if needed.
47
+
48
+ ## Contributing
49
+
50
+ 1. Fork it on GitHub (<http://github.com/stompede/stomp_parser/fork>).
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
52
+ 3. Follow the [Development](#development) instructions in this README.
53
+ 4. Create your changes, please add tests.
54
+ 5. Commit your changes (`git commit -am 'Add some feature'`).
55
+ 6. Push to the branch (`git push origin my-new-feature`).
56
+ 7. Create new pull request on GitHub.
57
+
58
+ ## License
59
+
60
+ [MIT](MIT-LICENSE.txt)
data/Rakefile ADDED
@@ -0,0 +1,134 @@
1
+ def ragel(*args)
2
+ sh "ragel", "-I.", *args
3
+ end
4
+
5
+ # Build state machine before building gem.
6
+ task :build => :compile
7
+
8
+ file "parser_common.rl"
9
+
10
+ rule ".rb" => %w[.rb.rl parser_common.rl] do |t|
11
+ ragel "-F1", "-R", t.source, "-o", t.name
12
+ end
13
+
14
+ rule ".c" => %w[.c.rl parser_common.rl] do |t|
15
+ ragel "-G2", "-C", t.source, "-o", t.name
16
+ end
17
+
18
+ rule ".java" => %w[.java.rl parser_common.rl] do |t|
19
+ ragel "-T0", "-J", t.source, "-o", t.name
20
+ end
21
+
22
+ desc "ragel machines"
23
+ task :compile => %w[lib/stomp_parser/ruby_parser.rb]
24
+
25
+ # JRuby do not like C extensions to even exist.
26
+ if %w[rbx ruby].include?(RUBY_ENGINE)
27
+ require "rake/extensiontask"
28
+ task :compile => %w[ext/stomp_parser/c_parser.c]
29
+
30
+ Rake::ExtensionTask.new do |ext|
31
+ ext.name = "c_parser"
32
+ ext.ext_dir = "ext/stomp_parser"
33
+ ext.lib_dir = "lib/stomp_parser"
34
+ end
35
+ end
36
+
37
+ require "rake/javaextensiontask"
38
+ task :compile => %w[ext/java/stomp_parser/JavaParser.java]
39
+
40
+ Rake::JavaExtensionTask.new do |ext|
41
+ ext.name = "java_parser"
42
+ ext.lib_dir = "lib/stomp_parser"
43
+ end
44
+
45
+ desc "ragel machines"
46
+ task :clean do |t|
47
+ source_tasks = Rake::Task[:compile].prerequisite_tasks.grep(Rake::FileTask)
48
+ rm_f source_tasks.map(&:name)
49
+ end
50
+
51
+ namespace :ragel do
52
+ desc "Show stomp parser state machine as an image"
53
+ task :show => "lib/stomp_parser/ruby_parser.rb" do |t|
54
+ mkdir_p "tmp"
55
+ ragel "-V", "-p", t.prerequisite_tasks[0].source, "-o", "tmp/parser.dot"
56
+ sh "dot -Tpng -O tmp/parser.dot"
57
+ rm "tmp/parser.dot"
58
+ sh "open tmp/parser.dot.png"
59
+ end
60
+ end
61
+
62
+ desc "Start a pry session with the gem loaded."
63
+ task :console => :compile do
64
+ exec "pry", "-rbundler/setup", "-rstomp_parser"
65
+ end
66
+
67
+ require "rspec/core/rake_task"
68
+ RSpec::Core::RakeTask.new(:spec)
69
+ task :spec => :compile
70
+
71
+ desc "Run all benchmarks."
72
+ task :bench => :compile do
73
+ sh "ruby", "-I.", *FileList["spec/benchmarks/**/*.rb"].flat_map { |x| ["-r", x] }, "-e", "''"
74
+ end
75
+
76
+ desc "Run the profiler and show a gif, requires perftools.rb"
77
+ task :profile => :compile do
78
+ # CPUPROFILE_METHODS=0 CPUPROFILE_OBJECTS=0 CPUPROFILE_REALTIME=1
79
+ sh "CPUPROFILE_REALTIME=1 ruby spec/profile.rb"
80
+ sh "pprof.rb --text spec/profile/parser.profile"
81
+ end
82
+
83
+ desc "Build gem in preparation for release"
84
+ task :build, [:everything_compiled?] => :compile do |task, args|
85
+ unless args[:everything_compiled?] == "all_compiled"
86
+ puts "Hi there. This is a safeguard to stop you from doing mistakes."
87
+ puts
88
+ puts "Make sure that the lib/stomp_parser/java_parser.jar is up to"
89
+ puts "date by switching to JRuby and running `rake compile`. This is"
90
+ puts "because JRuby cannot build native extensions on gem installation,"
91
+ puts "so we must bundle the .jar with the gem."
92
+ puts
93
+ puts "To do this, switch to JRuby and issue `rake compile`."
94
+ puts
95
+ puts "Once you've compiled the parser, run `rake build[all_compiled]`"
96
+ puts "to build gems for all platforms!"
97
+ abort
98
+ end
99
+
100
+ require "rubygems/package"
101
+
102
+ root = File.dirname(__FILE__)
103
+ pkgs = File.join(root, "pkg/")
104
+ mkdir_p(pkgs, verbose: true)
105
+
106
+ gemspec = Gem::Specification.load("stomp_parser.gemspec")
107
+
108
+ # For all the rubies. Except JRuby.
109
+ ruby_gemspec = gemspec.dup
110
+ ruby_gemspec.platform = Gem::Platform::RUBY
111
+ ruby_gemname = Gem::Package.build(ruby_gemspec)
112
+ ruby_gempath = File.join(pkgs, File.basename(ruby_gemname))
113
+ mv(ruby_gemname, ruby_gempath, verbose: true)
114
+
115
+ # JRuby don't like C extensions.
116
+ java_gemspec = gemspec.dup
117
+ java_gemspec.files += ["lib/stomp_parser/java_parser.jar"]
118
+ java_gemspec.extensions = []
119
+ java_gemspec.platform = "universal-java"
120
+ java_gemname = Gem::Package.build(java_gemspec)
121
+ java_gempath = File.join(pkgs, File.basename(java_gemname))
122
+ mv(java_gemname, java_gempath, verbose: true)
123
+
124
+ puts
125
+ puts "Now you may push the gems:"
126
+ puts
127
+ puts " gem push #{ruby_gempath}"
128
+ puts " gem push #{java_gempath}"
129
+ puts
130
+ puts "Do not forget to tag and push the versions to GitHub!"
131
+ end
132
+
133
+
134
+ 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
+ }