thick 0.0.4-java → 0.0.5-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.
data/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
- ## 0.4 (xy.xz.2012)
1
+ ## 0.5 (30.11.2012)
2
+
3
+ * update Netty to 3.5.11
4
+ * get rid of Loader experiment
5
+ * update Rake gem (development)
6
+
7
+ ## 0.4 (29.3.2012)
2
8
 
3
9
  * make gem Java specific
4
10
  * copy-less request body container
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Thick is very lightweight web server for JRuby based on excellent Netty library.
4
4
 
5
+ [![Build Status](https://secure.travis-ci.org/marekjelen/thick.png?branch=master)](http://travis-ci.org/marekjelen/thick)
6
+
5
7
  ## Status
6
8
 
7
9
  Works on several Sinatra and Rails applications. No real testing, yet.
data/ROADMAP.md CHANGED
@@ -3,8 +3,7 @@
3
3
  * SSL support
4
4
  * Tests
5
5
  * Code refactorings
6
- * Optimalizations
7
- * Replace StringIO
6
+ * Optimizations
8
7
 
9
8
  ## Nice to have
10
9
 
data/bin/thick CHANGED
@@ -2,7 +2,6 @@
2
2
  require 'optparse'
3
3
 
4
4
  require 'rubygems'
5
- require 'rack'
6
5
 
7
6
  $: << File.expand_path('../../lib', __FILE__)
8
7
  require 'thick'
@@ -27,20 +26,22 @@ OptionParser.new do |opts|
27
26
  options[:port] = Integer(port)
28
27
  end
29
28
 
30
- opts.on('-E', '--env ENVIRONMENT', 'use ENVIRONMENT for defaults (default: development)') do |e|
31
- options[:environment] = e
29
+ opts.on('-f', '--file FILE', 'use FILE to load the application (default: config.ru)') do |file|
30
+ options[:file] = file
32
31
  end
33
32
 
34
- end.parse!
33
+ opts.on('-d', '--directory DIR', 'use DIR as default directory (default: cwd)') do |directory|
34
+ options[:directory] = directory
35
+ end
35
36
 
36
- options[:address] ||= '0.0.0.0'
37
- options[:port] ||= 9292
38
- options[:environment] ||= 'development'
37
+ opts.on('-E', '--env ENVIRONMENT', 'use ENVIRONMENT for defaults (default: development)') do |e|
38
+ options[:environment] = e
39
+ end
39
40
 
40
- ENV['RACK_ENV'] ||= ENV['RAILS_ENV'] ||= options[:environment]
41
+ opts.on('-C', '--controller', 'starts controller for remote monitoring and management') do |e|
42
+ options[:controller] = e
43
+ end
41
44
 
42
- puts "Loading app #{options.inspect}"
43
- app = Rack::Builder.parse_file('config.ru')
45
+ end.parse!
44
46
 
45
- puts "Starting server"
46
- Thick.start(app[0], options)
47
+ Thick.start(options)
Binary file
@@ -8,15 +8,26 @@ module Thick
8
8
  @custom = false
9
9
  @async = false
10
10
  @block = nil
11
+ @chunked = false
12
+ @content_length = nil
13
+ @closed = false
11
14
  @params = []
12
15
  end
13
16
 
14
17
  def call(chunk)
15
- @context.channel.write(Thick::Java::ChannelBuffers.copiedBuffer(chunk.to_s, Thick::Java::CharsetUtil::UTF_8))
18
+ chunk = Thick::Java::ChannelBuffers.copiedBuffer(chunk.to_s, Thick::Java::CharsetUtil::UTF_8)
19
+ chunk = Thick::Java::DefaultHttpChunk.new(chunk) if @chunked
20
+ @context.channel.write(chunk) unless closed?
16
21
  end
17
22
 
18
23
  def close
19
- @context.channel.write(Thick::Java::ChannelBuffers::EMPTY_BUFFER).addListener(Thick::Java::ChannelFutureListener::CLOSE)
24
+ if @chunked
25
+ chunk = Thick::Java::ChannelBuffers.copiedBuffer("0\r\n\r\n", Thick::Java::CharsetUtil::UTF_8)
26
+ else
27
+ chunk = Thick::Java::ChannelBuffers::EMPTY_BUFFER
28
+ end
29
+ @context.channel.write(chunk).addListener(Thick::Java::ChannelFutureListener::CLOSE) unless closed?
30
+ closed!
20
31
  end
21
32
 
22
33
  def ready!
@@ -48,6 +59,30 @@ module Thick
48
59
  @async
49
60
  end
50
61
 
62
+ def chunked!
63
+ @chunked = true
64
+ end
65
+
66
+ def chunked?
67
+ @chunked
68
+ end
69
+
70
+ def content_length!(length)
71
+ @content_length = length
72
+ end
73
+
74
+ def content_length
75
+ @content_length
76
+ end
77
+
78
+ def closed!
79
+ @closed = true
80
+ end
81
+
82
+ def closed?
83
+ @closed
84
+ end
85
+
51
86
  end
52
87
 
53
88
  end
@@ -0,0 +1,88 @@
1
+ module Thick
2
+ class Controller
3
+
4
+ def initialize(options, server)
5
+ @options = options
6
+ @server = server
7
+ @factory = Thick::Java::NioServerSocketChannelFactory.new(Thick::Java::Executors.new_cached_thread_pool, Thick::Java::Executors.new_cached_thread_pool)
8
+ @bootstrap = Thick::Java::ServerBootstrap.new(@factory)
9
+ @bootstrap.pipeline_factory = Controller::PipelineFactory.new(@options)
10
+ end
11
+
12
+ def start
13
+ @channel = @bootstrap.bind(Thick::Java::InetSocketAddress.new('127.0.0.1', 9393))
14
+ puts "* Controller started on 127.0.0.1:9393"
15
+ self
16
+ end
17
+
18
+ def stop
19
+ @channel.close
20
+ self
21
+ end
22
+
23
+ class PipelineFactory
24
+
25
+ include Thick::Java::ChannelPipelineFactory
26
+
27
+ def initialize(options)
28
+ @options = options
29
+ end
30
+
31
+ def getPipeline
32
+ pipeline = Thick::Java::Channels.pipeline
33
+ pipeline.add_last('decoder', Thick::Java::HttpRequestDecoder.new)
34
+ pipeline.add_last('aggregator', Thick::Java::HttpChunkAggregator.new(65536))
35
+ pipeline.add_last('encoder', Thick::Java::HttpResponseEncoder.new)
36
+ pipeline.add_last('handler', Controller::Handler.new(@options))
37
+ pipeline
38
+ end
39
+
40
+ end
41
+
42
+ class Handler < Thick::Java::SimpleChannelUpstreamHandler
43
+
44
+ def messageReceived(context, event)
45
+ message = event.message
46
+ case message
47
+ when Thick::Java::HttpRequest
48
+ handle_request(context, message)
49
+ when Thick::Java::WebSocketFrame
50
+ handle_websocket_frame(context, message)
51
+ end
52
+ end
53
+
54
+ def handle_request(context, request)
55
+ url = "ws://" + request.get_header(Thick::Java::HttpHeaders::Names::HOST) + '/controller'
56
+ factory = Thick::Java::WebSocketServerHandshakerFactory.new(url, nil, false)
57
+ @handshaker = factory.new_handshaker(request)
58
+ if @handshaker
59
+ @handshaker.handshake(context, request)
60
+ else
61
+ factory.send_unsupported_webSocket_version_response(context)
62
+ end
63
+ end
64
+
65
+ def handle_websocket_frame(context, frame)
66
+ case frame
67
+ when Thick::Java::CloseWebSocketFrame
68
+ @handshaker.close(context, frame)
69
+ when Thick::Java::PingWebSocketFrame
70
+ context.channel.write(Thick::Java::PongWebSocketFrame.new(frame.binary_data))
71
+ when Thick::Java::TextWebSocketFrame
72
+ handle_websocket_message(context, frame.text)
73
+ end
74
+ end
75
+
76
+ def websocket_send(context, message)
77
+ context.channel.write(Thick::Java::TextWebSocketFrame.new(message.to_s))
78
+ end
79
+
80
+ def handle_websocket_message(context, message)
81
+
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
data/lib/thick/java.rb CHANGED
@@ -8,16 +8,24 @@ module Thick
8
8
  java_import 'org.jboss.netty.buffer.ChannelBuffer'
9
9
  java_import 'org.jboss.netty.buffer.ChannelBufferInputStream'
10
10
  java_import 'org.jboss.netty.buffer.ChannelBuffers'
11
+ java_import 'org.jboss.netty.handler.codec.http.DefaultHttpChunk'
11
12
  java_import 'org.jboss.netty.handler.codec.http.DefaultHttpResponse'
12
13
  java_import 'org.jboss.netty.handler.codec.http.HttpContentDecompressor'
13
14
  java_import 'org.jboss.netty.handler.codec.http.HttpHeaders'
14
15
  java_import 'org.jboss.netty.handler.codec.http.HttpChunk'
16
+ java_import 'org.jboss.netty.handler.codec.http.HttpChunkAggregator'
15
17
  java_import 'org.jboss.netty.handler.codec.http.HttpRequest'
16
18
  java_import 'org.jboss.netty.handler.codec.http.HttpRequestDecoder'
17
19
  java_import 'org.jboss.netty.handler.codec.http.HttpResponseEncoder'
18
20
  java_import 'org.jboss.netty.handler.codec.http.HttpResponseStatus'
19
21
  java_import 'org.jboss.netty.handler.codec.http.HttpVersion'
20
22
  java_import 'org.jboss.netty.handler.codec.http.QueryStringDecoder'
23
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame'
24
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame'
25
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame'
26
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame'
27
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame'
28
+ java_import 'org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory'
21
29
  java_import 'org.jboss.netty.handler.codec.spdy.SpdyFrameDecoder'
22
30
  java_import 'org.jboss.netty.handler.codec.spdy.SpdyFrameEncoder'
23
31
  java_import 'org.jboss.netty.handler.codec.spdy.SpdySessionHandler'
@@ -36,6 +44,10 @@ module Thick
36
44
  java_import 'org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory'
37
45
  java_import 'org.jboss.netty.logging.InternalLogLevel'
38
46
  java_import 'org.jboss.netty.util.CharsetUtil'
47
+ java_import 'org.jruby.CompatVersion'
48
+ java_import 'org.jruby.embed.AttributeName'
49
+ java_import 'org.jruby.embed.LocalContextScope'
50
+ java_import 'org.jruby.embed.ScriptingContainer'
39
51
 
40
52
  end
41
53
  end
@@ -0,0 +1,20 @@
1
+ module Thick
2
+
3
+ class Loader
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ ENV['RACK_ENV'] ||= ENV['RAILS_ENV'] ||= @options[:environment]
8
+ @application = Rack::Builder.parse_file(@options[:file])[0]
9
+ end
10
+
11
+ def call(env)
12
+ @application.call(env)
13
+ rescue => e
14
+ puts e.message
15
+ puts e.backtrace
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -1,57 +1,16 @@
1
1
  module Thick
2
2
 
3
- class TimeProbe
4
-
5
- include Thick::Java::ChannelUpstreamHandler
6
- include Thick::Java::ChannelDownstreamHandler
7
-
8
- def self.setup
9
- @total = 0
10
- @count = 0
11
- end
12
-
13
- def initialize
14
- @time = Time.now.to_f
15
- end
16
-
17
- TimeProbe.setup
18
-
19
- def self.time(time)
20
- @total += time
21
- @count += 1
22
- if @count % 100 == 0
23
- puts "AVG: #{@total / @count}"
24
- setup
25
- end
26
- end
27
-
28
- def handleUpstream(context, event)
29
- context.send_upstream(event)
30
- end
31
-
32
- def handleDownstream(context, event)
33
- if event.respond_to?(:getState)
34
- stop = Time.now.to_f - @time
35
- self.class.time(stop)
36
- end
37
- context.send_downstream(event)
38
- end
39
-
40
- end
41
-
42
3
  class PipelineFactory
43
4
 
44
5
  include Thick::Java::ChannelPipelineFactory
45
6
 
46
- def initialize(application)
47
- @application = application
7
+ def initialize(options)
8
+ @options = options
48
9
  @executor = Thick::Java::ExecutionHandler.new(Thick::Java::OrderedMemoryAwareThreadPoolExecutor.new(20, 0, 0))
49
10
  end
50
11
 
51
12
  def getPipeline
52
13
  pipeline = Thick::Java::Channels.pipeline
53
-
54
- pipeline.add_last('time_probe', TimeProbe.new)
55
14
 
56
15
  pipeline.add_last('http_decoder', Thick::Java::HttpRequestDecoder.new)
57
16
  pipeline.add_last('http_encoder', Thick::Java::HttpResponseEncoder.new)
@@ -60,7 +19,7 @@ module Thick
60
19
 
61
20
  pipeline.add_last('executor', @executor)
62
21
 
63
- pipeline.add_last('handler', ServerHandler.new(@application))
22
+ pipeline.add_last('handler', ServerHandler.new(@options))
64
23
 
65
24
  pipeline
66
25
  end
data/lib/thick/server.rb CHANGED
@@ -1,29 +1,23 @@
1
1
  module Thick
2
2
 
3
- def self.start(application, options)
4
- @server = Server.new(application)
5
- @server.start(:address => options[:address], :port => options[:port])
6
- end
7
-
8
3
  class Server
9
4
 
10
- def initialize(application)
5
+ def initialize(options)
6
+ @options = options
11
7
  @factory = Thick::Java::NioServerSocketChannelFactory.new(Thick::Java::Executors.new_cached_thread_pool, Thick::Java::Executors.new_cached_thread_pool)
12
8
  @bootstrap = Thick::Java::ServerBootstrap.new(@factory)
13
- @bootstrap.pipeline_factory = PipelineFactory.new(application)
9
+ @bootstrap.pipeline_factory = PipelineFactory.new(@options)
14
10
  end
15
11
 
16
- def start(options = {})
17
- @channel = @bootstrap.bind(Thick::Java::InetSocketAddress.new(options[:address], options[:port]))
18
- puts 'Server started'
19
- loop do
20
- # ToDo: Is this hack needed?
21
- sleep(100)
22
- end
12
+ def start
13
+ @channel = @bootstrap.bind(Thick::Java::InetSocketAddress.new(@options[:address], @options[:port]))
14
+ puts "* Server started on #{@options[:address]}:#{@options[:port]}"
15
+ self
23
16
  end
24
17
 
25
18
  def stop
26
19
  @channel.close
20
+ self
27
21
  end
28
22
 
29
23
  end
@@ -1,12 +1,10 @@
1
- require 'stringio'
2
-
3
1
  module Thick
4
2
 
5
3
  class ServerHandler < Thick::Java::SimpleChannelUpstreamHandler
6
4
 
7
- def initialize(application)
5
+ def initialize(options)
8
6
  super()
9
- @application = application
7
+ @options = options
10
8
  end
11
9
 
12
10
  def channelConnected(context, event)
@@ -32,7 +30,7 @@ module Thick
32
30
  def on_request(context, request)
33
31
 
34
32
  # Serve file if exists in public directory
35
- file = File.join('public', request.uri)
33
+ file = File.join(@options[:directory], 'public', request.uri)
36
34
  return serve_file(context, file).addListener(Thick::Java::ChannelFutureListener::CLOSE) if !request.uri.index('..') && File.exists?(file) && !File.directory?(file)
37
35
 
38
36
  query_string = request.uri.split('?', 2)
@@ -53,7 +51,8 @@ module Thick
53
51
  'SERVER_NAME' => 'localhost', # ToDo: Be more precise!
54
52
  'SERVER_PORT' => '8080', # ToDo: Be more precise!
55
53
  # Thick specific
56
- 'thick.async' => AsyncResponse.new(context)
54
+ 'thick.async' => AsyncResponse.new(context),
55
+ 'thick.options' => @options
57
56
  }
58
57
 
59
58
  # Get content length if available
@@ -83,7 +82,7 @@ module Thick
83
82
  end
84
83
 
85
84
  def handle_request(context)
86
- response = @application.call(@env)
85
+ response = @options[:application].call(@env)
87
86
 
88
87
  # Let the application make the response as it wants
89
88
  if @env['thick.async'].custom?
@@ -102,6 +101,15 @@ module Thick
102
101
  Thick::Java::HttpHeaders.set_header(@response, name, value)
103
102
  end
104
103
 
104
+ if @env['thick.async'].async?
105
+ if length = @env['thick.async'].content_length
106
+ Thick::Java::HttpHeaders.set_content_length(@response, length)
107
+ else
108
+ @response.remove_header('Content-Length')
109
+ end
110
+ @response.chunked = true if @env['thick.async'].chunked?
111
+ end
112
+
105
113
  context.channel.write(@response)
106
114
 
107
115
  # Set content as requested by application
@@ -126,6 +134,7 @@ module Thick
126
134
  end
127
135
 
128
136
  def channelClosed(context, event)
137
+ @env['thick.async'].closed!
129
138
  end
130
139
 
131
140
  def exceptionCaught(context, e)
@@ -0,0 +1,29 @@
1
+ module Thick
2
+
3
+ def self.start(options)
4
+ @options = {
5
+ :address => '0.0.0.0',
6
+ :port => 9292,
7
+ :environment => 'development',
8
+ :reloader => false,
9
+ :controller => false,
10
+ :directory => Dir.getwd,
11
+ :file => 'config.ru'
12
+ }.merge(options)
13
+
14
+ puts "* Starting Thick: #{@options.inspect}"
15
+
16
+ @options[:application] = Loader.new(@options)
17
+ @server = Server.new(@options).start
18
+
19
+ if @options[:controller]
20
+ @controller = Controller.new(@options, @server)
21
+ @controller.start
22
+ end
23
+
24
+ loop do
25
+ sleep(100) # ToDo: Is this hack needed?
26
+ end
27
+ end
28
+
29
+ end
data/lib/thick/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Thick
2
- VERSION = '0.0.4' unless const_defined?(:VERSION)
2
+ VERSION = '0.0.5' unless const_defined?(:VERSION)
3
3
  end
data/lib/thick.rb CHANGED
@@ -2,12 +2,16 @@ require 'rack'
2
2
 
3
3
  require 'java'
4
4
 
5
- require File.expand_path('../jars/netty-3.4.0.Alpha2.jar', __FILE__)
5
+ require File.expand_path('../jars/netty-3.5.11.Final.jar', __FILE__)
6
6
 
7
7
  require 'thick/java'
8
+ require 'thick/thick'
8
9
  require 'thick/version'
9
10
  require 'thick/buffer'
10
11
  require 'thick/async_response'
12
+ require 'thick/loader'
11
13
  require 'thick/server_handler'
12
14
  require 'thick/pipeline_factory'
13
- require 'thick/server'
15
+ require 'thick/controller'
16
+ require 'thick/server'
17
+
metadata CHANGED
@@ -1,78 +1,113 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: thick
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.0.4
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
6
  platform: java
7
- authors:
8
- - Marek Jelen
9
- autorequire:
7
+ authors:
8
+ - Marek Jelen
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2012-03-29 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: rack
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - "="
22
- - !ruby/object:Gem::Version
23
- version: 1.4.1
24
- type: :runtime
25
- version_requirements: *id001
12
+ date: 2012-11-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 1.4.1
21
+ none: false
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.1
27
+ none: false
28
+ prerelease: false
29
+ type: :runtime
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - '='
35
+ - !ruby/object:Gem::Version
36
+ version: 2.9.0
37
+ none: false
38
+ requirement: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - '='
41
+ - !ruby/object:Gem::Version
42
+ version: 2.9.0
43
+ none: false
44
+ prerelease: false
45
+ type: :development
26
46
  description: Very lightweight web server for JRuby based on Netty library.
27
- email:
28
- - marek@jelen.biz
29
- executables:
30
- - thick
47
+ email:
48
+ - marek@jelen.biz
49
+ executables:
50
+ - thick
31
51
  extensions: []
32
-
33
52
  extra_rdoc_files: []
34
-
35
- files:
36
- - bin/thick
37
- - lib/thick.rb
38
- - lib/jars/netty-3.4.0.Alpha2.jar
39
- - lib/thick/async_response.rb
40
- - lib/thick/buffer.rb
41
- - lib/thick/java.rb
42
- - lib/thick/pipeline_factory.rb
43
- - lib/thick/server.rb
44
- - lib/thick/server_handler.rb
45
- - lib/thick/version.rb
46
- - LICENSE
47
- - README.md
48
- - ROADMAP.md
49
- - CHANGELOG.md
53
+ files:
54
+ - !binary |-
55
+ YmluL3RoaWNr
56
+ - !binary |-
57
+ bGliL3RoaWNrLnJi
58
+ - !binary |-
59
+ bGliL3RoaWNrL3BpcGVsaW5lX2ZhY3RvcnkucmI=
60
+ - !binary |-
61
+ bGliL3RoaWNrL2phdmEucmI=
62
+ - !binary |-
63
+ bGliL3RoaWNrL3RoaWNrLnJi
64
+ - !binary |-
65
+ bGliL3RoaWNrL2xvYWRlci5yYg==
66
+ - !binary |-
67
+ bGliL3RoaWNrL3ZlcnNpb24ucmI=
68
+ - !binary |-
69
+ bGliL3RoaWNrL3NlcnZlcl9oYW5kbGVyLnJi
70
+ - !binary |-
71
+ bGliL3RoaWNrL2FzeW5jX3Jlc3BvbnNlLnJi
72
+ - !binary |-
73
+ bGliL3RoaWNrL2J1ZmZlci5yYg==
74
+ - !binary |-
75
+ bGliL3RoaWNrL2NvbnRyb2xsZXIucmI=
76
+ - !binary |-
77
+ bGliL3RoaWNrL3NlcnZlci5yYg==
78
+ - !binary |-
79
+ bGliL2phcnMvbmV0dHktMy41LjExLkZpbmFsLmphcg==
80
+ - LICENSE
81
+ - README.md
82
+ - ROADMAP.md
83
+ - CHANGELOG.md
50
84
  homepage: http://github.com/marekjelen/thick
51
85
  licenses: []
52
-
53
- post_install_message:
86
+ post_install_message:
54
87
  rdoc_options: []
55
-
56
- require_paths:
57
- - lib
58
- required_ruby_version: !ruby/object:Gem::Requirement
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: !binary |-
97
+ MA==
98
+ hash: 2
59
99
  none: false
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: "0"
64
- required_rubygems_version: !ruby/object:Gem::Requirement
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: !binary |-
105
+ MA==
65
106
  none: false
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: "0"
70
107
  requirements: []
71
-
72
- rubyforge_project:
73
- rubygems_version: 1.8.15
74
- signing_key:
108
+ rubyforge_project:
109
+ rubygems_version: 1.8.24
110
+ signing_key:
75
111
  specification_version: 3
76
112
  summary: Very lightweight web server for JRuby
77
113
  test_files: []
78
-
Binary file