rexpro 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rexpro.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Philotic, Inc.
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,40 @@
1
+ # Rexpro
2
+
3
+ *This is an early release and should not be considered stable!*
4
+
5
+ https://github.com/tinkerpop/rexster/wiki/RexPro
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'rexpro'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install rexpro
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'rexpro'
25
+
26
+ client = Rexpro::Client.new(host: 'localhost', port: 8184) # defaults
27
+
28
+ response = client.execute('g.v(2)', graph_name: 'tinkergraph')
29
+
30
+ response.results
31
+ => {"_id"=>"2", "_type"=>"vertex", "_properties"=>{"name"=>"vadas", "age"=>27}}
32
+ ```
33
+
34
+ ## Contributing
35
+
36
+ 1. Fork it
37
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
38
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
39
+ 4. Push to the branch (`git push origin my-new-feature`)
40
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ task :default => :basic_tests
6
+
7
+ desc 'Run basic (non-integration) tests'
8
+ Rake::TestTask.new(:basic_tests) do |test|
9
+ test.verbose = true
10
+ test.test_files = ['spec/*_spec.rb']
11
+ end
12
+
13
+ desc 'Run integration tests'
14
+ Rake::TestTask.new(:integration_tests) do |test|
15
+ test.verbose = true
16
+ test.test_files = ['spec/integration/*_spec.rb']
17
+ end
18
+
19
+ desc 'Run all tests'
20
+ Rake::TestTask.new do |test|
21
+ test.verbose = true
22
+ test.test_files = ['spec/**/*_spec.rb']
23
+ end
@@ -0,0 +1,52 @@
1
+ require 'socket'
2
+
3
+ require_relative './session'
4
+
5
+ module Rexpro
6
+ class Client
7
+ DEFAULT_HOST = 'localhost'
8
+ DEFAULT_PORT = 8184
9
+
10
+ attr_reader :host, :port, :socket
11
+
12
+ def initialize(opts = {})
13
+ @host = opts[:host] || DEFAULT_HOST
14
+ @port = opts[:port] || DEFAULT_PORT
15
+ reconnect
16
+ end
17
+
18
+ def reconnect
19
+ @socket.close if @socket && !@socket.closed?
20
+ @socket = TCPSocket.new @host, @port
21
+ end
22
+
23
+ def new_session(*args)
24
+ req = Rexpro::Message::SessionRequest.new(*args)
25
+ resp = request(req)
26
+ Rexpro::Session.new(self, resp.session_uuid, req.channel, resp.languages)
27
+ end
28
+
29
+ def request(req)
30
+ req.write_to(@socket)
31
+
32
+ Rexpro::Message.read_from(@socket).tap do |resp|
33
+ if resp.request_uuid.bytes.to_a != req.request_uuid.bytes.to_a
34
+ raise Rexpro::RexproException,
35
+ "request uuid of response didn't match request"
36
+ end
37
+
38
+ if resp.is_a? Rexpro::Message::Error
39
+ err_msg = resp.error_message
40
+ err_msg << " [flag=#{resp.flag}]" if resp.flag
41
+ raise Rexpro::RexproError.new(err_msg)
42
+ end
43
+ end
44
+ end
45
+
46
+ def execute(script, attrs = {})
47
+ attrs = attrs.merge(script: script)
48
+ msg = Rexpro::Message::ScriptRequest.new(attrs)
49
+ request(msg)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,199 @@
1
+ require 'msgpack'
2
+ require 'uuid'
3
+
4
+ # https://github.com/tinkerpop/rexster/wiki/RexPro-Messages
5
+
6
+ module Rexpro
7
+ module Message
8
+ PROTOCOL_VERSION = 0
9
+
10
+ ZERO_UUID = [0, 0, 0, 0].pack('NNNN')
11
+
12
+ TYPE_ERROR = 0
13
+ TYPE_SESSION_REQUEST = 1
14
+ TYPE_SESSION_RESPONSE = 2
15
+ TYPE_SCRIPT_REQUEST = 3
16
+ TYPE_CONSOLE_SCRIPT_RESPONSE = 4
17
+ TYPE_MSGPACK_SCRIPT_RESPONSE = 5
18
+ TYPE_GRAPHSON_SCRIPT_RESPONSE = 6
19
+
20
+ CHANNEL_CONSOLE = 1
21
+ CHANNEL_MSGPACK = 2
22
+ CHANNEL_GRAPHSON = 3
23
+
24
+ class << self
25
+ def generate_uuid
26
+ @uuid ||= UUID.new
27
+ hex = @uuid.generate(:compact)
28
+ ints = hex.each_char.each_slice(8).map { |h| Integer(h.join, 16) }
29
+ ints.pack('NNNN')
30
+ end
31
+
32
+ def types
33
+ @types ||= {}
34
+ end
35
+
36
+ def read_from(io)
37
+ version = io.readbyte
38
+ if version != PROTOCOL_VERSION
39
+ raise RexproException, "Unknown protocol version #{version}"
40
+ end
41
+
42
+ header = io.read(5)
43
+ if header.nil? || header.size < 5
44
+ raise RexproException, "Unexpected EOF: #{header.inspect}"
45
+ end
46
+
47
+ type, size = header.unpack('CN')
48
+ type_class = types[type]
49
+ unless type_class
50
+ raise RexproException, "Unknown message type #{type}"
51
+ end
52
+ fields = type_class.fields
53
+
54
+ unpacker = MessagePack::Unpacker.new(io)
55
+ array_size = unpacker.read_array_header
56
+ if array_size != fields.length
57
+ raise RexproException,
58
+ "Expected #{fields.length} fields, got #{array_size}"
59
+ end
60
+
61
+ values = unpacker.read
62
+
63
+ attrs = fields.zip(values).inject({}) do |memo, (field, value)|
64
+ memo[field] = value
65
+ memo
66
+ end
67
+
68
+ type_class.new(attrs)
69
+ end
70
+ end
71
+
72
+ module Base
73
+ def self.included(klass)
74
+ klass.extend ClassMethods
75
+ klass.define_fields session_uuid: :to_s, request_uuid: :to_s,
76
+ meta: :to_hash
77
+ end
78
+
79
+ module ClassMethods
80
+ attr_reader :type
81
+
82
+ def type=(type)
83
+ @type = type
84
+ Message.types[type] = self
85
+ end
86
+
87
+ def fields
88
+ @fields ||= []
89
+ end
90
+
91
+ def field_methods
92
+ @field_methods ||= {}
93
+ end
94
+
95
+ def define_fields(hsh)
96
+ hsh.each do |name, method|
97
+ fields << name
98
+ field_methods[name] = method
99
+ attr_accessor(name)
100
+ end
101
+ end
102
+
103
+ def define_meta_fields(*names)
104
+ names.each do |name|
105
+ # RexPro uses mixedCase keys in meta
106
+ name_parts = name.to_s.split('_')
107
+ name_parts[1..-1].each(&:capitalize!)
108
+ rexpro_name = name_parts.join
109
+
110
+ define_method(name) { meta[rexpro_name] }
111
+ define_method("#{name}=") { |value| meta[rexpro_name] = value }
112
+ end
113
+ end
114
+ end
115
+
116
+ def initialize(attrs = {})
117
+ self.meta ||= {}
118
+ attrs.each { |k, v| send("#{k}=", v) }
119
+ self.session_uuid ||= ZERO_UUID
120
+ self.request_uuid ||= Message.generate_uuid
121
+ end
122
+
123
+ def to_msgpack(*args)
124
+ self.class.fields.map do |field|
125
+ value = send(field)
126
+ field_method = self.class.field_methods[field]
127
+ value = value.send(field_method) if field_method
128
+ value
129
+ end.to_msgpack(*args)
130
+ end
131
+
132
+ def write_to(io)
133
+ body = to_msgpack
134
+ header = [PROTOCOL_VERSION, self.class.type, body.size].pack('CCN')
135
+ io.write(header)
136
+ io.write(body)
137
+ end
138
+ end
139
+
140
+ class Error
141
+ include Base
142
+ self.type = TYPE_ERROR
143
+ define_fields error_message: :to_s
144
+ define_meta_fields :flag
145
+ end
146
+
147
+ class SessionRequest
148
+ include Base
149
+ self.type = TYPE_SESSION_REQUEST
150
+ define_fields channel: :to_i, username: :to_s, password: :to_s
151
+ define_meta_fields :graph_name, :graph_obj_name, :kill_session
152
+
153
+ def initialize(*_)
154
+ super
155
+ self.channel ||= CHANNEL_MSGPACK
156
+ end
157
+ end
158
+
159
+ class SessionResponse
160
+ include Base
161
+ self.type = TYPE_SESSION_RESPONSE
162
+ define_fields languages: :to_a
163
+ define_meta_fields :graph_name, :graph_obj_name, :kill_session
164
+ end
165
+
166
+ class ScriptRequest
167
+ include Base
168
+ self.type = TYPE_SCRIPT_REQUEST
169
+ define_fields language_name: :to_s, script: :to_s, bindings: :to_hash
170
+ define_meta_fields :channel, :in_session, :isolate, :transaction,
171
+ :graph_name, :graph_obj_name
172
+
173
+ def initialize(*_)
174
+ super
175
+ self.language_name ||= 'groovy'
176
+ self.bindings ||= {}
177
+ self.channel ||= CHANNEL_MSGPACK
178
+ end
179
+ end
180
+
181
+ class ConsoleScriptResponse
182
+ include Base
183
+ self.type = TYPE_CONSOLE_SCRIPT_RESPONSE
184
+ define_fields console_lines: :to_a, bindings: :to_hash
185
+ end
186
+
187
+ class MsgpackScriptResponse
188
+ include Base
189
+ self.type = TYPE_MSGPACK_SCRIPT_RESPONSE
190
+ define_fields results: nil, bindings: :to_hash
191
+ end
192
+
193
+ class GraphsonScriptResponse
194
+ include Base
195
+ self.type = TYPE_GRAPHSON_SCRIPT_RESPONSE
196
+ define_fields results: :to_s, bindings: :to_hash
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,22 @@
1
+ require 'rexpro'
2
+
3
+ class Rexpro::Session
4
+ attr_reader :client, :uuid, :channel, :languages
5
+
6
+ def initialize(client, uuid, channel, languages = nil)
7
+ @client, @uuid, @channel, @languages = client, uuid, channel, languages
8
+ end
9
+
10
+ def kill
11
+ attrs = {session_uuid: uuid, kill_session: true}
12
+ msg = Rexpro::Message::SessionRequest.new(attrs)
13
+ client.request(msg)
14
+ end
15
+
16
+ def execute(script, attrs = {})
17
+ attrs = attrs.merge(
18
+ session_uuid: uuid, channel: channel, in_session: true, script: script)
19
+ msg = Rexpro::Message::ScriptRequest.new(attrs)
20
+ client.request(msg)
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Rexpro
2
+ VERSION = "0.0.1"
3
+ end
data/lib/rexpro.rb ADDED
@@ -0,0 +1,8 @@
1
+ require_relative "./rexpro/version"
2
+ require_relative "./rexpro/client"
3
+ require_relative "./rexpro/message"
4
+
5
+ module Rexpro
6
+ class RexproException < StandardError; end
7
+ class RexproError < RexproException; end
8
+ end
data/rexpro.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rexpro/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rexpro"
8
+ spec.version = Rexpro::VERSION
9
+ spec.authors = ["Lann Martin"]
10
+ spec.email = ["lann@causes.com"]
11
+ spec.description = %q{RexPro, a binary protocol for Rexster}
12
+ spec.summary = <<DESC
13
+ RexPro is a binary protocol for Rexster that can be used to send Gremlin
14
+ scripts to a remote Rexster instance.
15
+ DESC
16
+ spec.homepage = ""
17
+ spec.license = "MIT"
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.test_files = spec.files.grep(%r{^spec/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "msgpack", "~> 0.5.4"
24
+ spec.add_dependency "uuid", "~> 2.3.7"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.3"
27
+ spec.add_development_dependency "rake"
28
+ end
@@ -0,0 +1,13 @@
1
+ ## Integration tests
2
+
3
+ The specs in this directory expect a working Rexster server. The easiest way
4
+ to get one is to download rexster from
5
+ https://github.com/tinkerpop/rexster/wiki/Downloads
6
+ and run a local server with `bin/rexster.sh -s`.
7
+
8
+ If you would rather run against an existing server you can do so by setting the
9
+ `REXPRO_HOST` and/or `REXPRO_PORT` env vars, e.g.:
10
+
11
+ ```
12
+ REXPRO_HOST=rexster-server bundle exec rake integration_tests
13
+ ```
@@ -0,0 +1,35 @@
1
+ require 'minitest/autorun'
2
+ require_relative './integration_helper'
3
+ require 'rexpro'
4
+
5
+ describe Rexpro::Client do
6
+ include IntegrationHelper
7
+
8
+ subject { Rexpro::Client.new(client_opts) }
9
+
10
+ it 'connects' do
11
+ with_connect_notice do
12
+ subject.socket.closed?.must_equal false
13
+ end
14
+ end
15
+
16
+ describe '#new_session' do
17
+ it 'opens a new session' do
18
+ session = subject.new_session
19
+ session.uuid.bytesize.must_equal 16
20
+ end
21
+ end
22
+
23
+ describe '#execute' do
24
+ it 'executes a script' do
25
+ resp = subject.execute('1')
26
+ resp.results.must_equal 1
27
+ end
28
+
29
+ it 'raises errors' do
30
+ proc do
31
+ subject.execute(']invalid script[')
32
+ end.must_raise Rexpro::RexproError
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ module IntegrationHelper
2
+ def client_opts
3
+ %w[host port].inject({}) do |memo, key|
4
+ value = ENV["REXPRO_#{key.upcase}"]
5
+ memo[key.to_sym] = value if value
6
+ memo
7
+ end
8
+ end
9
+
10
+ @@notice_shown = false
11
+
12
+ def with_connect_notice(&blk)
13
+ yield
14
+ rescue SocketError, Errno::ECONNREFUSED
15
+ unless @@notice_shown
16
+ puts '!' * 65,
17
+ 'It looks like the client failed to connect. Make sure a server is',
18
+ 'running and that REXPRO_HOST and REXPRO_PORT are set if needed.',
19
+ '!' * 65
20
+ @notice_shown = true
21
+ end
22
+ raise
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ require 'minitest/autorun'
2
+ require_relative './integration_helper'
3
+ require 'rexpro'
4
+
5
+ describe Rexpro::Session do
6
+ include IntegrationHelper
7
+
8
+ subject { Rexpro::Client.new(client_opts).new_session }
9
+
10
+ it 'is a session' do
11
+ with_connect_notice do
12
+ subject.must_be_instance_of Rexpro::Session
13
+ end
14
+ end
15
+
16
+ describe '#execute' do
17
+ it 'executes a script in the session' do
18
+ resp = subject.execute('1')
19
+ resp.session_uuid.must_equal subject.uuid
20
+ end
21
+ end
22
+
23
+ describe '#kill' do
24
+ it 'ends the session' do
25
+ resp = subject.kill
26
+ resp.session_uuid.must_equal Rexpro::Message::ZERO_UUID
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ require 'minitest/autorun'
4
+ require 'stringio'
5
+
6
+ require 'rexpro'
7
+
8
+ describe Rexpro::Message do
9
+ describe '.generate_uuid' do
10
+ let(:uuid) { Rexpro::Message.generate_uuid }
11
+
12
+ it 'generates 16 byte strings' do
13
+ uuid.bytesize.must_equal 16
14
+ end
15
+
16
+ it 'generates unique strings' do
17
+ uuid.wont_equal Rexpro::Message.generate_uuid
18
+ end
19
+ end
20
+
21
+ describe '.read_from' do
22
+ let(:data) { "\x00\x00\x00\x00\x00/\x94\xB01234567812345678" +
23
+ "\xB0abcdefghijklmnop\x81\xA4flag\a\xA4boom" }
24
+ let(:io) { StringIO.new data }
25
+ let(:msg) { Rexpro::Message.read_from(io) }
26
+
27
+ it 'correctly parses data' do
28
+ msg.must_be_instance_of Rexpro::Message::Error
29
+ msg.session_uuid.must_equal '1234567812345678'
30
+ msg.request_uuid.must_equal 'abcdefghijklmnop'
31
+ msg.error_message.must_equal 'boom'
32
+ msg.flag.must_equal 7
33
+ end
34
+
35
+ it 'is symmetrical with #write_to' do
36
+ out = StringIO.new ''
37
+ msg.write_to(out)
38
+ out.string.must_equal data
39
+ end
40
+ end
41
+ end
42
+
43
+ describe Rexpro::Message::SessionRequest do
44
+ let(:request_uuid) { '1234567812345678' }
45
+ subject { Rexpro::Message::SessionRequest.new request_uuid: request_uuid }
46
+
47
+ describe '#write_to' do
48
+ let(:io) { StringIO.new '' }
49
+
50
+ it 'correctly writes to the io object' do
51
+ subject.session_uuid = 'abcdefghijklmnop'
52
+ subject.write_to(io)
53
+ io.string.must_equal "\x00\x01\x00\x00\x00'\x96\xB0abcdefghijklmnop" +
54
+ "\xB01234567812345678\x80\x02\xA0\xA0"
55
+ end
56
+
57
+ it 'is symmetrical with .read_from' do
58
+ subject.write_to(io)
59
+ io.rewind
60
+ msg = Rexpro::Message.read_from(io)
61
+ msg.must_be_instance_of Rexpro::Message::SessionRequest
62
+ msg.request_uuid.must_equal subject.request_uuid
63
+ end
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rexpro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Lann Martin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: msgpack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.5.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.5.4
30
+ - !ruby/object:Gem::Dependency
31
+ name: uuid
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 2.3.7
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 2.3.7
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: RexPro, a binary protocol for Rexster
79
+ email:
80
+ - lann@causes.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - lib/rexpro.rb
91
+ - lib/rexpro/client.rb
92
+ - lib/rexpro/message.rb
93
+ - lib/rexpro/session.rb
94
+ - lib/rexpro/version.rb
95
+ - rexpro.gemspec
96
+ - spec/integration/README.md
97
+ - spec/integration/client_spec.rb
98
+ - spec/integration/integration_helper.rb
99
+ - spec/integration/session_spec.rb
100
+ - spec/message_spec.rb
101
+ homepage: ''
102
+ licenses:
103
+ - MIT
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.23
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: RexPro is a binary protocol for Rexster that can be used to send Gremlin
126
+ scripts to a remote Rexster instance.
127
+ test_files:
128
+ - spec/integration/README.md
129
+ - spec/integration/client_spec.rb
130
+ - spec/integration/integration_helper.rb
131
+ - spec/integration/session_spec.rb
132
+ - spec/message_spec.rb