glottis 0.3.0 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4738a04eaf3d36ff79c3b8b18e9408d825729e40a2314f76049aeb848e9fb23
4
- data.tar.gz: 3bc4629dfdb5dbc0b9d55b78369fb4f5be2dc9032a0ac1b5b2f922fdff4b7a6d
3
+ metadata.gz: b19cc9121495467f570a8989b7cbd66aba5069f70bfa7044e36541ae8d407483
4
+ data.tar.gz: a854ee9fe9e2cfa2b0969e495b9853884738d202e7a1b21ccae2f8b36bc7f9e6
5
5
  SHA512:
6
- metadata.gz: 8b36bbc01a00d869a1bd91f58ccc31348332244896e6bca5b6c2c2ba96ce8c1cdb8a16254a50fe4a4c005cc6b3d79a97f789bae8b4c01d6e084aa497f9bb4081
7
- data.tar.gz: 74dcce5991937a677eddbe3ebd51de4f792cd0c47ecff50f4d606288fe12c880ef36b9e9c280de8c7f269bf1e82a50248b0d894e38c34b2be2924ad4de3b6070
6
+ metadata.gz: dc5f81d11d5ab1a4fee50a7e1384534799abb05d24ea34c47460d8c05d07834f3ce3a5684a945f824315d8e9df83e11fe67df1511b0dee8d08000b486eb090e6
7
+ data.tar.gz: 2de12c2620eda6634c55775794408f6569aaab040cfaa64de49639f17e7434d8dce573582b5e5cc7cd6f6fecca794a12aec10559c63f8a45d87f153fc9525269
data/CHANGELOG.md CHANGED
@@ -5,15 +5,24 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semmle.com/semver/1.0.0/).
7
7
 
8
- ## [0.3.0] - 2026-07-24
8
+ ## [0.4.0] - 2026-07-24
9
+
10
+ ### Changed
11
+ - Minor version release for full Ruby 3.4+ compatibility and modernized dependency stack.
12
+ - Enhanced `RemoteInputHandler` with Server-Sent Events (SSE) stream parsing (`data: {...}`).
13
+ - Enhanced `RemoteOutputHandler` with automatic session cookie forwarding (`SID`) and strict JSON payload formatting (`{"to": "*", "body": "..."}`).
14
+ - Verified live end-to-end message streaming against the modernized Valyx server.
15
+
16
+ ## [0.3.1] - 2026-07-24
9
17
 
10
18
  ### Changed
11
19
  - Bumped required Ruby version to `>= 3.0.0`.
12
20
  - Removed `rb-readline` dependency in favor of Ruby standard library `reline`/`readline`.
13
21
  - Updated `slop` runtime dependency to `~> 4.10`.
22
+ - Explicitly set `Content-Type: application/json` headers on outgoing HTTP request posts.
14
23
  - Modernized gemspec metadata and file list configuration.
15
24
  - Updated RuboCop configuration for Ruby 3.0+ compatibility (`Layout/LineLength`).
16
25
  - Migrated CI from Travis CI to GitHub Actions (`.github/workflows/ci.yml`).
17
26
 
18
27
  ### Added
19
- - Comprehensive RSpec test suite covering core client and handlers.
28
+ - Comprehensive RSpec test suite covering core client, handlers, and live HTTP mock server integration.
data/README.md CHANGED
@@ -17,7 +17,7 @@ Install the gem by executing:
17
17
 
18
18
  Or add it to your application's Gemfile:
19
19
 
20
- $ gem 'glottis', '~> 0.3'
20
+ $ gem 'glottis', '~> 0.4'
21
21
 
22
22
  ## Usage
23
23
 
data/Rakefile CHANGED
@@ -1,11 +1,10 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rubocop/rake_task'
5
- require 'rspec/core/rake_task'
6
-
7
- RuboCop::RakeTask.new(:rubocop)
8
- RSpec::Core::RakeTask.new(:spec)
9
-
10
- task default: %i[rubocop spec]
11
-
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rubocop/rake_task'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RuboCop::RakeTask.new(:rubocop)
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: %i[rubocop spec]
data/exe/glottis CHANGED
@@ -1,24 +1,23 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'slop'
5
- require 'glottis'
6
-
7
- opts = Slop.parse do |o|
8
- o.string '--host', 'a hostname', default: 'localhost'
9
- o.integer '--port', 'TCP port', default: 8080
10
- o.bool '-v', '--verbose', 'enable verbose mode'
11
- o.on '-V', '--version', 'print the version' do
12
- puts "glottis #{Glottis::VERSION}"
13
- exit
14
- end
15
- o.on '-h', '--help' do
16
- puts o
17
- exit
18
- end
19
- end
20
-
21
- Glottis::Client.new(opts[:host],
22
- opts[:port],
23
- verbose: opts[:verbose]).run
24
-
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'slop'
5
+ require 'glottis'
6
+
7
+ opts = Slop.parse do |o|
8
+ o.string '--host', 'a hostname', default: 'localhost'
9
+ o.integer '--port', 'TCP port', default: 8080
10
+ o.bool '-v', '--verbose', 'enable verbose mode'
11
+ o.on '-V', '--version', 'print the version' do
12
+ puts "glottis #{Glottis::VERSION}"
13
+ exit
14
+ end
15
+ o.on '-h', '--help' do
16
+ puts o
17
+ exit
18
+ end
19
+ end
20
+
21
+ Glottis::Client.new(opts[:host],
22
+ opts[:port],
23
+ verbose: opts[:verbose]).run
data/glottis.gemspec CHANGED
@@ -20,19 +20,18 @@ Gem::Specification.new do |spec|
20
20
  spec.metadata['bug_tracker_uri'] = 'https://github.com/maxdeliso/glottis/issues'
21
21
  spec.metadata['rubygems_mfa_required'] = 'true'
22
22
 
23
- spec.files = Dir.glob('{exe,lib}/**/*') + %w[Rakefile README.md CHANGELOG.md glottis.gemspec]
24
- spec.files = spec.files.select { |f| File.file?(f) }
23
+ spec.files = Dir.glob('{exe,lib}/**/*').select { |f| File.file?(f) } +
24
+ %w[Rakefile README.md CHANGELOG.md glottis.gemspec]
25
25
 
26
26
  spec.bindir = 'exe'
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
- spec.add_runtime_dependency 'slop', '~> 4.10'
30
+ spec.add_dependency 'slop', '~> 4.10'
31
31
 
32
- spec.add_development_dependency 'bundler', '~> 2.0'
32
+ spec.add_development_dependency 'bundler', '>= 2.0'
33
33
  spec.add_development_dependency 'rake', '~> 13.0'
34
34
  spec.add_development_dependency 'rspec', '~> 3.0'
35
35
  spec.add_development_dependency 'rubocop', '~> 1.0'
36
+ spec.add_development_dependency 'webrick', '~> 1.8'
36
37
  end
37
-
38
-
@@ -25,32 +25,42 @@ module Glottis
25
25
  def run
26
26
  Client.logger.info('starting...')
27
27
 
28
- @handlers = [
29
- Handlers::ConsoleInputHandler.new(@outgoing),
30
- Handlers::ConsoleOutputHandler.new(@incoming),
31
- Handlers::RemoteInputHandler.new(@incoming, @host, @port),
32
- Handlers::RemoteOutputHandler.new(@outgoing, @host, @port)
33
- ]
34
-
35
- @handlers.each(&:start)
28
+ start_handlers
36
29
  @handlers.each(&:join)
37
30
  rescue Glottis::Exceptions::UserExitedException
38
31
  Client.logger.info('User exited.')
39
32
  rescue Interrupt
40
33
  Client.logger.info('Received interrupt signal. Exiting...')
41
- rescue Errno::ECONNREFUSED => conn_ref
42
- Client.logger.error("Failed to connect to host: #{conn_ref.message}")
43
- rescue StandardError => ex
44
- Client.logger.warn("Shutting down due to error: #{ex.message}")
34
+ rescue Errno::ECONNREFUSED => e
35
+ Client.logger.error("Failed to connect to host: #{e.message}")
36
+ rescue StandardError => e
37
+ Client.logger.warn("Shutting down due to error: #{e.message}")
45
38
  ensure
46
39
  stop_handlers
47
40
  end
48
41
 
49
42
  private
50
43
 
44
+ def start_handlers
45
+ remote_output = Handlers::RemoteOutputHandler.new(@outgoing, @host, @port)
46
+ remote_output.start
47
+
48
+ sleep 0.1 until remote_output.cookie || remote_output.sid
49
+
50
+ cookie = remote_output.cookie
51
+ remote_input = Handlers::RemoteInputHandler.new(@incoming, @host, @port, cookie)
52
+ remote_input.start
53
+
54
+ @handlers = [
55
+ Handlers::ConsoleInputHandler.new(@outgoing).start,
56
+ Handlers::ConsoleOutputHandler.new(@incoming).start,
57
+ remote_input,
58
+ remote_output
59
+ ]
60
+ end
61
+
51
62
  def stop_handlers
52
63
  @handlers.each(&:cleanup)
53
64
  end
54
65
  end
55
66
  end
56
-
@@ -1,9 +1,8 @@
1
- # frozen_string_literal: true
2
-
3
- module Glottis
4
- module Exceptions
5
- class GlottisException < StandardError
6
- end
7
- end
8
- end
9
-
1
+ # frozen_string_literal: true
2
+
3
+ module Glottis
4
+ module Exceptions
5
+ class GlottisException < StandardError
6
+ end
7
+ end
8
+ end
@@ -1,11 +1,10 @@
1
- # frozen_string_literal: true
2
-
3
- require 'glottis/exceptions/glottis_exception'
4
-
5
- module Glottis
6
- module Exceptions
7
- class UserExitedException < GlottisException
8
- end
9
- end
10
- end
11
-
1
+ # frozen_string_literal: true
2
+
3
+ require 'glottis/exceptions/glottis_exception'
4
+
5
+ module Glottis
6
+ module Exceptions
7
+ class UserExitedException < GlottisException
8
+ end
9
+ end
10
+ end
@@ -1,50 +1,52 @@
1
- # frozen_string_literal: true
2
-
3
- require 'glottis/exceptions/user_exited_exception'
4
- require 'readline'
5
-
6
- module Glottis
7
- module Handlers
8
- # Holds a reference to the outgoing message queue and posts console input.
9
- class ConsoleInputHandler
10
- USER_PROMPT = '> '
11
-
12
- def initialize(outgoing)
13
- @outgoing = outgoing
14
- @running = false
15
- @thread = nil
16
- end
17
-
18
- def start
19
- @running = true
20
- @thread = Thread.new { run_loop }
21
- self
22
- end
23
-
24
- def join
25
- @thread&.join
26
- end
27
-
28
- def cleanup
29
- @running = false
30
- @thread&.kill if @thread&.alive?
31
- end
32
-
33
- private
34
-
35
- def run_loop
36
- while @running
37
- user_input = Readline.readline(USER_PROMPT, true)
38
-
39
- raise Glottis::Exceptions::UserExitedException, 'User exited readline stream' if user_input.nil?
40
-
41
- @outgoing.push(user_input)
42
- end
43
- rescue Glottis::Exceptions::UserExitedException => ex
44
- Client.logger.info("Console input ended: #{ex.message}")
45
- raise ex
46
- end
47
- end
48
- end
49
- end
50
-
1
+ # frozen_string_literal: true
2
+
3
+ require 'glottis/exceptions/user_exited_exception'
4
+ require 'readline'
5
+
6
+ module Glottis
7
+ module Handlers
8
+ # Holds a reference to the outgoing message queue and posts console input.
9
+ class ConsoleInputHandler
10
+ USER_PROMPT = '> '
11
+
12
+ def initialize(outgoing)
13
+ @outgoing = outgoing
14
+ @running = false
15
+ @thread = nil
16
+ end
17
+
18
+ def start
19
+ @running = true
20
+ @thread = Thread.new { run_loop }
21
+ self
22
+ end
23
+
24
+ def join
25
+ @thread&.join
26
+ end
27
+
28
+ def cleanup
29
+ @running = false
30
+ @thread&.kill if @thread&.alive?
31
+ end
32
+
33
+ private
34
+
35
+ def run_loop
36
+ while @running
37
+ user_input = Readline.readline(USER_PROMPT, true)
38
+
39
+ if user_input.nil?
40
+ raise Glottis::Exceptions::UserExitedException,
41
+ 'User exited readline stream'
42
+ end
43
+
44
+ @outgoing.push(user_input)
45
+ end
46
+ rescue Glottis::Exceptions::UserExitedException => e
47
+ Client.logger.info("Console input ended: #{e.message}")
48
+ raise e
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,41 +1,40 @@
1
- # frozen_string_literal: true
2
-
3
- module Glottis
4
- module Handlers
5
- # Holds a reference to incoming message queue and prints messages to stdout.
6
- class ConsoleOutputHandler
7
- def initialize(incoming)
8
- @incoming = incoming
9
- @running = false
10
- @thread = nil
11
- end
12
-
13
- def start
14
- @running = true
15
- @thread = Thread.new { run_loop }
16
- self
17
- end
18
-
19
- def join
20
- @thread&.join
21
- end
22
-
23
- def cleanup
24
- @running = false
25
- @thread&.kill if @thread&.alive?
26
- end
27
-
28
- private
29
-
30
- def run_loop
31
- while @running
32
- new_msg = @incoming.pop
33
- break if new_msg.nil? || new_msg == :shutdown
34
-
35
- puts "#{new_msg['from']}, #{new_msg['to']}, #{new_msg['msg']}"
36
- end
37
- end
38
- end
39
- end
40
- end
41
-
1
+ # frozen_string_literal: true
2
+
3
+ module Glottis
4
+ module Handlers
5
+ # Holds a reference to incoming message queue and prints messages to stdout.
6
+ class ConsoleOutputHandler
7
+ def initialize(incoming)
8
+ @incoming = incoming
9
+ @running = false
10
+ @thread = nil
11
+ end
12
+
13
+ def start
14
+ @running = true
15
+ @thread = Thread.new { run_loop }
16
+ self
17
+ end
18
+
19
+ def join
20
+ @thread&.join
21
+ end
22
+
23
+ def cleanup
24
+ @running = false
25
+ @thread&.kill if @thread&.alive?
26
+ end
27
+
28
+ private
29
+
30
+ def run_loop
31
+ while @running
32
+ new_msg = @incoming.pop
33
+ break if new_msg.nil? || new_msg == :shutdown
34
+
35
+ puts "#{new_msg['from']}, #{new_msg['to']}, #{new_msg['msg']}"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -13,13 +13,15 @@ module Glottis
13
13
  STREAM_DELIMITER = "\0"
14
14
  READ_TIMEOUT = 3600
15
15
  REMOTE_PATHS = {
16
- get_message_stream: '/api/messages/stream'
16
+ get_message_stream: '/api/v1/messages/stream',
17
+ legacy_message_stream: '/api/messages/stream'
17
18
  }.freeze
18
19
 
19
- def initialize(incoming, host, port)
20
+ def initialize(incoming, host, port, cookie = nil)
20
21
  @incoming = incoming
21
22
  @host = host
22
23
  @port = port
24
+ @cookie = cookie
23
25
  @running = false
24
26
  @thread = nil
25
27
  @buffer = String.new
@@ -49,39 +51,67 @@ module Glottis
49
51
 
50
52
  def setup_http
51
53
  @http = Net::HTTP.new(@host, @port)
52
- @http.open_timeout = 1
54
+ @http.open_timeout = 2
53
55
  @http.read_timeout = READ_TIMEOUT
54
56
  end
55
57
 
56
58
  def read_loop
57
59
  Client.logger.info('reading stream...')
58
- @http.get(REMOTE_PATHS.fetch(:get_message_stream)) do |chunk|
60
+ headers = @cookie ? { 'Cookie' => @cookie } : {}
61
+
62
+ stream_request(headers) do |chunk|
59
63
  break unless @running
60
64
 
61
- Client.logger.debug("got chunk of length: #{chunk.length}")
62
65
  process_chunk(chunk)
63
66
  end
64
- rescue StandardError => ex
65
- Client.logger.error("Error reading message stream: #{ex.message}") if @running
67
+ rescue StandardError => e
68
+ Client.logger.error("Error reading message stream: #{e.message}") if @running
69
+ end
70
+
71
+ def stream_request(headers, &block)
72
+ req = Net::HTTP::Get.new(REMOTE_PATHS.fetch(:get_message_stream), headers)
73
+
74
+ @http.request(req) do |response|
75
+ if Integer(response.code) == 404
76
+ legacy_req = Net::HTTP::Get.new(REMOTE_PATHS.fetch(:legacy_message_stream), headers)
77
+ @http.request(legacy_req) { |legacy_resp| legacy_resp.read_body(&block) }
78
+ else
79
+ response.read_body(&block)
80
+ end
81
+ end
66
82
  end
67
83
 
68
84
  def process_chunk(chunk)
69
85
  @buffer << chunk
70
86
 
87
+ # Process SSE format ("data: {...}\n\n")
88
+ while (line_end = @buffer.index("\n"))
89
+ line = @buffer.slice!(0..line_end).strip
90
+ next if line.empty? || line.start_with?(':')
91
+
92
+ if line.start_with?('data:')
93
+ json_str = line.sub(/^data:\s*/, '').chomp
94
+ parse_and_push(json_str)
95
+ end
96
+ end
97
+
98
+ # Process null-delimited format
71
99
  while (delimiter_index = @buffer.index(STREAM_DELIMITER))
72
100
  msg_raw = @buffer.slice!(0..delimiter_index)
73
101
  msg_data = msg_raw.chomp(STREAM_DELIMITER)
74
- next if msg_data.empty?
75
-
76
- begin
77
- parsed_msg = JSON.parse(msg_data)
78
- @incoming.push(parsed_msg)
79
- rescue JSON::ParserError => err
80
- Client.logger.warn("Failed to parse JSON payload: #{err.message}")
81
- end
102
+ parse_and_push(msg_data)
82
103
  end
83
104
  end
105
+
106
+ def parse_and_push(raw)
107
+ return if raw.empty?
108
+
109
+ parsed_msg = JSON.parse(raw)
110
+ parsed_msg['msg'] ||= parsed_msg['body']
111
+ @incoming.push(parsed_msg)
112
+ rescue JSON::ParserError => e
113
+ Client.logger.warn("Failed to parse JSON payload: #{e.message}")
114
+ end
84
115
  end
85
116
  end
86
117
  end
87
-
@@ -13,10 +13,14 @@ module Glottis
13
13
  PROTOCOL = 'http'
14
14
 
15
15
  REMOTE_PATHS = {
16
- get_session: '/api/session',
17
- post_message: '/api/message'
16
+ get_session: '/api/v1/session',
17
+ legacy_session: '/api/session',
18
+ post_message: '/api/v1/messages',
19
+ legacy_post_message: '/api/message'
18
20
  }.freeze
19
21
 
22
+ attr_reader :cookie, :sid
23
+
20
24
  def initialize(outgoing, host, port)
21
25
  @outgoing = outgoing
22
26
  @host = host
@@ -24,6 +28,7 @@ module Glottis
24
28
  @running = false
25
29
  @thread = nil
26
30
  @sid = nil
31
+ @cookie = nil
27
32
  setup_http
28
33
  end
29
34
 
@@ -33,9 +38,7 @@ module Glottis
33
38
  @http.start
34
39
  request_session
35
40
 
36
- while @running
37
- send_queued
38
- end
41
+ send_queued while @running
39
42
  end
40
43
  self
41
44
  end
@@ -54,26 +57,47 @@ module Glottis
54
57
 
55
58
  def setup_http
56
59
  @http = Net::HTTP.new(@host, @port)
57
- @http.open_timeout = 1
58
- @http.read_timeout = 1
60
+ @http.open_timeout = 2
61
+ @http.read_timeout = 2
59
62
  end
60
63
 
61
64
  def request_session
62
65
  Client.logger.info('making initial request for session...')
63
66
 
64
- session_req = @http.get(REMOTE_PATHS.fetch(:get_session))
65
- response = JSON.parse(session_req.body)
67
+ headers = { 'Content-Type' => 'application/json' }
68
+ session_req = fetch_session(headers)
69
+
70
+ code = Integer(session_req.code)
71
+ raise "failed to retrieve session: #{session_req.body}" unless [200, 201].include?(code)
72
+
73
+ parse_session_response(session_req)
74
+ end
75
+
76
+ def fetch_session(headers)
77
+ req = @http.post(REMOTE_PATHS.fetch(:get_session), '', headers)
78
+ return req if Integer(req.code) != 404
79
+
80
+ @http.get(REMOTE_PATHS.fetch(:legacy_session))
81
+ end
82
+
83
+ def parse_session_response(session_req)
84
+ if session_req['set-cookie']
85
+ raw_cookie = session_req['set-cookie']
86
+ @cookie = raw_cookie.split(';').first
87
+ end
66
88
 
67
- if Integer(session_req.code) != 201
68
- raise "failed to retrieve session: #{response}"
89
+ response = begin
90
+ JSON.parse(session_req.body)
91
+ rescue StandardError
92
+ {}
69
93
  end
70
94
 
71
- @sid = response['sid']
95
+ @sid = response['username'] || response['sid'] || @cookie
72
96
  Client.logger.info("current session id: #{@sid}")
73
97
  end
74
98
 
75
- def if_not_ok(http_req, ok_code = 200)
76
- yield http_req.body if Integer(http_req.code) != ok_code
99
+ def if_not_ok(http_req, ok_codes = [200, 201])
100
+ yield http_req.body unless ok_codes.include?(Integer(http_req.code))
77
101
  end
78
102
 
79
103
  def send_queued
@@ -82,19 +106,21 @@ module Glottis
82
106
 
83
107
  Client.logger.info("processing message with #{@outgoing.size} messages outgoing")
84
108
 
85
- message_data = {
86
- from: @sid,
87
- to: '*',
88
- msg: raw_msg
89
- }.to_json
109
+ headers = { 'Content-Type' => 'application/json' }
110
+ headers['Cookie'] = @cookie if @cookie
90
111
 
91
- post_req = @http.post(REMOTE_PATHS.fetch(:post_message), message_data)
112
+ modern_data = { to: '*', body: raw_msg }.to_json
113
+ post_req = @http.post(REMOTE_PATHS.fetch(:post_message), modern_data, headers)
114
+
115
+ if Integer(post_req.code) == 404
116
+ legacy_data = { from: @sid, to: '*', msg: raw_msg }.to_json
117
+ post_req = @http.post(REMOTE_PATHS.fetch(:legacy_post_message), legacy_data, headers)
118
+ end
92
119
 
93
120
  if_not_ok(post_req) do |err|
94
- Client.logger.warn("failed to post message: #{message_data} #{err}")
121
+ Client.logger.warn("failed to post message: #{raw_msg} #{err}")
95
122
  end
96
123
  end
97
124
  end
98
125
  end
99
126
  end
100
-
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Glottis
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/glottis.rb CHANGED
@@ -1,5 +1,4 @@
1
- # frozen_string_literal: true
2
-
3
- require 'glottis/version'
4
- require 'glottis/client'
5
-
1
+ # frozen_string_literal: true
2
+
3
+ require 'glottis/version'
4
+ require 'glottis/client'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glottis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max DeLiso
@@ -27,14 +27,14 @@ dependencies:
27
27
  name: bundler
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2.0'
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '2.0'
40
40
  - !ruby/object:Gem::Dependency
@@ -79,6 +79,20 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '1.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: webrick
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.8'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.8'
82
96
  email:
83
97
  - maxdeliso@gmail.com
84
98
  executables:
@@ -123,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
125
139
  requirements: []
126
- rubygems_version: 3.6.7
140
+ rubygems_version: 3.6.9
127
141
  specification_version: 4
128
142
  summary: simple http messaging client
129
143
  test_files: []