gserver 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac2ef003f2e6a480149eacf3fc3af0ad854d1d23
4
+ data.tar.gz: 89528c80a5bb9ec990abd98454de7bbe8fe11c7b
5
+ SHA512:
6
+ metadata.gz: 03cfeb39d1a7dea2643af0411c898c889f4d204ef7dee078fa6fa51422d0e33f9d60aa0ada165761411d8272b7e05e72144f727d2042f9034bd642dcb3abd087
7
+ data.tar.gz: c2fe1aae9435dcd7210306b0dc9587870c90e62dfabb390497637d2fd0ef260d3bf418e738d4d01fc644af24e2c5838c030b93a8db7c0dd574d7d4854b965abe
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gserver.gemspec
4
+ gemspec
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a) distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
@@ -0,0 +1,71 @@
1
+ # Gserver
2
+
3
+ GServer implements a generic server, featuring thread pool management,
4
+ simple logging, and multi-server management. See HttpServer in
5
+ <tt>sample/xmlrpc.rb</tt> in the Ruby standard library for an example of
6
+ GServer in action.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'gserver'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install gserver
23
+
24
+ ## Usage
25
+
26
+ Using GServer is simple. Below we implement a simple time server, run it,
27
+ query it, and shut it down. Try this code in +irb+:
28
+
29
+ require 'gserver'
30
+
31
+ #
32
+ # A server that returns the time in seconds since 1970.
33
+ #
34
+ class TimeServer < GServer
35
+ def initialize(port=10001, *args)
36
+ super(port, *args)
37
+ end
38
+ def serve(io)
39
+ io.puts(Time.now.to_i)
40
+ end
41
+ end
42
+
43
+ # Run the server with logging enabled (it's a separate thread).
44
+ server = TimeServer.new
45
+ server.audit = true # Turn logging on.
46
+ server.start
47
+
48
+ # *** Now point your browser to http://localhost:10001 to see it working ***
49
+
50
+ # See if it's still running.
51
+ GServer.in_service?(10001) # -> true
52
+ server.stopped? # -> false
53
+
54
+ # Shut the server down gracefully.
55
+ server.shutdown
56
+
57
+ # Alternatively, stop it immediately.
58
+ GServer.stop(10001)
59
+ # or, of course, "server.stop".
60
+
61
+ All the business of accepting connections and exception handling is taken
62
+ care of. All we have to do is implement the method that actually serves the
63
+ client.
64
+
65
+ ## Contributing
66
+
67
+ 1. Fork it ( https://github.com/[my-github-username]/gserver/fork )
68
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
69
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
70
+ 4. Push to the branch (`git push origin my-new-feature`)
71
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gserver/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gserver"
8
+ spec.version = Gserver::VERSION
9
+ spec.authors = ["John W. Small", "SHIBATA Hiroshi"]
10
+ spec.email = ["hsbt@ruby-lang.org"]
11
+ spec.summary = %q{GServer implements a generic server}
12
+ spec.description = %q{GServer implements a generic server}
13
+ spec.homepage = ""
14
+ spec.license = "Ruby"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,310 @@
1
+ #
2
+ # Copyright (C) 2001 John W. Small All Rights Reserved
3
+ #
4
+ # Author:: John W. Small
5
+ # Documentation:: Gavin Sinclair
6
+ # Licence:: Ruby License
7
+
8
+ require "socket"
9
+ require "thread"
10
+
11
+ #
12
+ # GServer implements a generic server, featuring thread pool management,
13
+ # simple logging, and multi-server management. See HttpServer in
14
+ # <tt>xmlrpc/httpserver.rb</tt> in the Ruby standard library for an example of
15
+ # GServer in action.
16
+ #
17
+ # Any kind of application-level server can be implemented using this class.
18
+ # It accepts multiple simultaneous connections from clients, up to an optional
19
+ # maximum number. Several _services_ (i.e. one service per TCP port) can be
20
+ # run simultaneously, and stopped at any time through the class method
21
+ # <tt>GServer.stop(port)</tt>. All the threading issues are handled, saving
22
+ # you the effort. All events are optionally logged, but you can provide your
23
+ # own event handlers if you wish.
24
+ #
25
+ # == Example
26
+ #
27
+ # Using GServer is simple. Below we implement a simple time server, run it,
28
+ # query it, and shut it down. Try this code in +irb+:
29
+ #
30
+ # require 'gserver'
31
+ #
32
+ # #
33
+ # # A server that returns the time in seconds since 1970.
34
+ # #
35
+ # class TimeServer < GServer
36
+ # def initialize(port=10001, *args)
37
+ # super(port, *args)
38
+ # end
39
+ # def serve(io)
40
+ # io.puts(Time.now.to_i)
41
+ # end
42
+ # end
43
+ #
44
+ # # Run the server with logging enabled (it's a separate thread).
45
+ # server = TimeServer.new
46
+ # server.audit = true # Turn logging on.
47
+ # server.start
48
+ #
49
+ # # *** Now point your browser to http://localhost:10001 to see it working ***
50
+ #
51
+ # # See if it's still running.
52
+ # GServer.in_service?(10001) # -> true
53
+ # server.stopped? # -> false
54
+ #
55
+ # # Shut the server down gracefully.
56
+ # server.shutdown
57
+ #
58
+ # # Alternatively, stop it immediately.
59
+ # GServer.stop(10001)
60
+ # # or, of course, "server.stop".
61
+ #
62
+ # All the business of accepting connections and exception handling is taken
63
+ # care of. All we have to do is implement the method that actually serves the
64
+ # client.
65
+ #
66
+ # === Advanced
67
+ #
68
+ # As the example above shows, the way to use GServer is to subclass it to
69
+ # create a specific server, overriding the +serve+ method. You can override
70
+ # other methods as well if you wish, perhaps to collect statistics, or emit
71
+ # more detailed logging.
72
+ #
73
+ # * #connecting
74
+ # * #disconnecting
75
+ # * #starting
76
+ # * #stopping
77
+ #
78
+ # The above methods are only called if auditing is enabled, via #audit=.
79
+ #
80
+ # You can also override #log and #error if, for example, you wish to use a
81
+ # more sophisticated logging system.
82
+ #
83
+ class GServer
84
+
85
+ DEFAULT_HOST = "127.0.0.1"
86
+
87
+ def serve(io)
88
+ end
89
+
90
+ @@services = {} # Hash of opened ports, i.e. services
91
+ @@servicesMutex = Mutex.new
92
+
93
+ # Stop the server running on the given port, bound to the given host
94
+ #
95
+ # +port+:: port, as a Fixnum, of the server to stop
96
+ # +host+:: host on which to find the server to stop
97
+ def GServer.stop(port, host = DEFAULT_HOST)
98
+ @@servicesMutex.synchronize {
99
+ @@services[host][port].stop
100
+ }
101
+ end
102
+
103
+ # Check if a server is running on the given port and host
104
+ #
105
+ # +port+:: port, as a Fixnum, of the server to check
106
+ # +host+:: host on which to find the server to check
107
+ #
108
+ # Returns true if a server is running on that port and host.
109
+ def GServer.in_service?(port, host = DEFAULT_HOST)
110
+ @@services.has_key?(host) and
111
+ @@services[host].has_key?(port)
112
+ end
113
+
114
+ # Stop the server
115
+ def stop
116
+ @connectionsMutex.synchronize {
117
+ if @tcpServerThread
118
+ @tcpServerThread.raise "stop"
119
+ end
120
+ }
121
+ end
122
+
123
+ # Returns true if the server has stopped.
124
+ def stopped?
125
+ @tcpServerThread == nil
126
+ end
127
+
128
+ # Schedule a shutdown for the server
129
+ def shutdown
130
+ @shutdown = true
131
+ end
132
+
133
+ # Return the current number of connected clients
134
+ def connections
135
+ @connections.size
136
+ end
137
+
138
+ # Join with the server thread
139
+ def join
140
+ @tcpServerThread.join if @tcpServerThread
141
+ end
142
+
143
+ # Port on which to listen, as a Fixnum
144
+ attr_reader :port
145
+ # Host on which to bind, as a String
146
+ attr_reader :host
147
+ # Maximum number of connections to accept at a time, as a Fixnum
148
+ attr_reader :maxConnections
149
+ # IO Device on which log messages should be written
150
+ attr_accessor :stdlog
151
+ # Set to true to cause the callbacks #connecting, #disconnecting, #starting,
152
+ # and #stopping to be called during the server's lifecycle
153
+ attr_accessor :audit
154
+ # Set to true to show more detailed logging
155
+ attr_accessor :debug
156
+
157
+ # Called when a client connects, if auditing is enabled.
158
+ #
159
+ # +client+:: a TCPSocket instance representing the client that connected
160
+ #
161
+ # Return true to allow this client to connect, false to prevent it.
162
+ def connecting(client)
163
+ addr = client.peeraddr
164
+ log("#{self.class} #{@host}:#{@port} client:#{addr[1]} " +
165
+ "#{addr[2]}<#{addr[3]}> connect")
166
+ true
167
+ end
168
+
169
+
170
+ # Called when a client disconnects, if audition is enabled.
171
+ #
172
+ # +clientPort+:: the port of the client that is connecting
173
+ def disconnecting(clientPort)
174
+ log("#{self.class} #{@host}:#{@port} " +
175
+ "client:#{clientPort} disconnect")
176
+ end
177
+
178
+ protected :connecting, :disconnecting
179
+
180
+ # Called when the server is starting up, if auditing is enabled.
181
+ def starting()
182
+ log("#{self.class} #{@host}:#{@port} start")
183
+ end
184
+
185
+ # Called when the server is shutting down, if auditing is enabled.
186
+ def stopping()
187
+ log("#{self.class} #{@host}:#{@port} stop")
188
+ end
189
+
190
+ protected :starting, :stopping
191
+
192
+ # Called if #debug is true whenever an unhandled exception is raised.
193
+ # This implementation simply logs the backtrace.
194
+ #
195
+ # +detail+:: the Exception that was caught
196
+ def error(detail)
197
+ log(detail.backtrace.join("\n"))
198
+ end
199
+
200
+ # Log a message to #stdlog, if it's defined. This implementation
201
+ # outputs the timestamp and message to the log.
202
+ #
203
+ # +msg+:: the message to log
204
+ def log(msg)
205
+ if @stdlog
206
+ @stdlog.puts("[#{Time.new.ctime}] %s" % msg)
207
+ @stdlog.flush
208
+ end
209
+ end
210
+
211
+ protected :error, :log
212
+
213
+ # Create a new server
214
+ #
215
+ # +port+:: the port, as a Fixnum, on which to listen
216
+ # +host+:: the host to bind to
217
+ # +maxConnections+:: the maximum number of simultaneous connections to
218
+ # accept
219
+ # +stdlog+:: IO device on which to log messages
220
+ # +audit+:: if true, lifecycle callbacks will be called. See #audit
221
+ # +debug+:: if true, error messages are logged. See #debug
222
+ def initialize(port, host = DEFAULT_HOST, maxConnections = 4,
223
+ stdlog = $stderr, audit = false, debug = false)
224
+ @tcpServerThread = nil
225
+ @port = port
226
+ @host = host
227
+ @maxConnections = maxConnections
228
+ @connections = []
229
+ @connectionsMutex = Mutex.new
230
+ @connectionsCV = ConditionVariable.new
231
+ @stdlog = stdlog
232
+ @audit = audit
233
+ @debug = debug
234
+ end
235
+
236
+ # Start the server if it isn't already running
237
+ #
238
+ # +maxConnections+::
239
+ # override +maxConnections+ given to the constructor. A negative
240
+ # value indicates that the value from the constructor should be used.
241
+ def start(maxConnections = -1)
242
+ raise "server is already running" if !stopped?
243
+ @shutdown = false
244
+ @maxConnections = maxConnections if maxConnections > 0
245
+ @@servicesMutex.synchronize {
246
+ if GServer.in_service?(@port,@host)
247
+ raise "Port already in use: #{host}:#{@port}!"
248
+ end
249
+ @tcpServer = TCPServer.new(@host,@port)
250
+ @port = @tcpServer.addr[1]
251
+ @@services[@host] = {} unless @@services.has_key?(@host)
252
+ @@services[@host][@port] = self;
253
+ }
254
+ @tcpServerThread = Thread.new {
255
+ begin
256
+ starting if @audit
257
+ while !@shutdown
258
+ @connectionsMutex.synchronize {
259
+ while @connections.size >= @maxConnections
260
+ @connectionsCV.wait(@connectionsMutex)
261
+ end
262
+ }
263
+ client = @tcpServer.accept
264
+ Thread.new(client) { |myClient|
265
+ @connections << Thread.current
266
+ begin
267
+ myPort = myClient.peeraddr[1]
268
+ serve(myClient) if !@audit or connecting(myClient)
269
+ rescue => detail
270
+ error(detail) if @debug
271
+ ensure
272
+ begin
273
+ myClient.close
274
+ rescue
275
+ end
276
+ @connectionsMutex.synchronize {
277
+ @connections.delete(Thread.current)
278
+ @connectionsCV.signal
279
+ }
280
+ disconnecting(myPort) if @audit
281
+ end
282
+ }
283
+ end
284
+ rescue => detail
285
+ error(detail) if @debug
286
+ ensure
287
+ begin
288
+ @tcpServer.close
289
+ rescue
290
+ end
291
+ if @shutdown
292
+ @connectionsMutex.synchronize {
293
+ while @connections.size > 0
294
+ @connectionsCV.wait(@connectionsMutex)
295
+ end
296
+ }
297
+ else
298
+ @connections.each { |c| c.raise "stop" }
299
+ end
300
+ @tcpServerThread = nil
301
+ @@servicesMutex.synchronize {
302
+ @@services[@host].delete(@port)
303
+ }
304
+ stopping if @audit
305
+ end
306
+ }
307
+ self
308
+ end
309
+
310
+ end
@@ -0,0 +1,3 @@
1
+ module Gserver
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,173 @@
1
+ # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
2
+ #
3
+ # $Id$
4
+ #
5
+
6
+
7
+ require "gserver"
8
+
9
+ # Implements a simple HTTP-server by using John W. Small's (jsmall@laser.net)
10
+ # ruby-generic-server: GServer.
11
+ class HttpServer < GServer
12
+
13
+ ##
14
+ # +handle_obj+ specifies the object, that receives calls from +request_handler+
15
+ # and +ip_auth_handler+
16
+ def initialize(handle_obj, port = 8080, host = DEFAULT_HOST, maxConnections = 4,
17
+ stdlog = $stdout, audit = true, debug = true)
18
+ @handler = handle_obj
19
+ super(port, host, maxConnections, stdlog, audit, debug)
20
+ end
21
+
22
+ private
23
+
24
+ CRLF = "\r\n"
25
+ HTTP_PROTO = "HTTP/1.0"
26
+ SERVER_NAME = "HttpServer (Ruby #{RUBY_VERSION})"
27
+
28
+ # Default header for the server name
29
+ DEFAULT_HEADER = {
30
+ "Server" => SERVER_NAME
31
+ }
32
+
33
+ # Mapping of status codes and error messages
34
+ StatusCodeMapping = {
35
+ 200 => "OK",
36
+ 400 => "Bad Request",
37
+ 403 => "Forbidden",
38
+ 405 => "Method Not Allowed",
39
+ 411 => "Length Required",
40
+ 500 => "Internal Server Error"
41
+ }
42
+
43
+ class Request
44
+ attr_reader :data, :header, :method, :path, :proto
45
+
46
+ def initialize(data, method=nil, path=nil, proto=nil)
47
+ @header, @data = Table.new, data
48
+ @method, @path, @proto = method, path, proto
49
+ end
50
+
51
+ def content_length
52
+ len = @header['Content-Length']
53
+ return nil if len.nil?
54
+ return len.to_i
55
+ end
56
+
57
+ end
58
+
59
+ class Response
60
+ attr_reader :header
61
+ attr_accessor :body, :status, :status_message
62
+
63
+ def initialize(status=200)
64
+ @status = status
65
+ @status_message = nil
66
+ @header = Table.new
67
+ end
68
+ end
69
+
70
+ # A case-insensitive Hash class for HTTP header
71
+ class Table
72
+ include Enumerable
73
+
74
+ def initialize(hash={})
75
+ @hash = hash
76
+ update(hash)
77
+ end
78
+
79
+ def [](key)
80
+ @hash[key.to_s.capitalize]
81
+ end
82
+
83
+ def []=(key, value)
84
+ @hash[key.to_s.capitalize] = value
85
+ end
86
+
87
+ def update(hash)
88
+ hash.each {|k,v| self[k] = v}
89
+ self
90
+ end
91
+
92
+ def each
93
+ @hash.each {|k,v| yield k.capitalize, v }
94
+ end
95
+
96
+ # Output the Hash table for the HTTP header
97
+ def writeTo(port)
98
+ each { |k,v| port << "#{k}: #{v}" << CRLF }
99
+ end
100
+ end # class Table
101
+
102
+
103
+ # Generates a Hash with the HTTP headers
104
+ def http_header(header=nil) # :doc:
105
+ new_header = Table.new(DEFAULT_HEADER)
106
+ new_header.update(header) unless header.nil?
107
+
108
+ new_header["Connection"] = "close"
109
+ new_header["Date"] = http_date(Time.now)
110
+
111
+ new_header
112
+ end
113
+
114
+ # Returns a string which represents the time as rfc1123-date of HTTP-date
115
+ def http_date( aTime ) # :doc:
116
+ aTime.gmtime.strftime( "%a, %d %b %Y %H:%M:%S GMT" )
117
+ end
118
+
119
+ # Returns a string which includes the status code message as,
120
+ # http headers, and body for the response.
121
+ def http_resp(status_code, status_message=nil, header=nil, body=nil) # :doc:
122
+ status_message ||= StatusCodeMapping[status_code]
123
+
124
+ str = ""
125
+ str << "#{HTTP_PROTO} #{status_code} #{status_message}" << CRLF
126
+ http_header(header).writeTo(str)
127
+ str << CRLF
128
+ str << body unless body.nil?
129
+ str
130
+ end
131
+
132
+ # Handles the HTTP request and writes the response back to the client, +io+.
133
+ #
134
+ # If an Exception is raised while handling the request, the client will receive
135
+ # a 500 "Internal Server Error" message.
136
+ def serve(io) # :doc:
137
+ # perform IP authentication
138
+ unless @handler.ip_auth_handler(io)
139
+ io << http_resp(403, "Forbidden")
140
+ return
141
+ end
142
+
143
+ # parse first line
144
+ if io.gets =~ /^(\S+)\s+(\S+)\s+(\S+)/
145
+ request = Request.new(io, $1, $2, $3)
146
+ else
147
+ io << http_resp(400, "Bad Request")
148
+ return
149
+ end
150
+
151
+ # parse HTTP headers
152
+ while (line=io.gets) !~ /^(\n|\r)/
153
+ if line =~ /^([\w-]+):\s*(.*)$/
154
+ request.header[$1] = $2.strip
155
+ end
156
+ end
157
+
158
+ io.binmode
159
+ response = Response.new
160
+
161
+ # execute request handler
162
+ @handler.request_handler(request, response)
163
+
164
+ # write response back to the client
165
+ io << http_resp(response.status, response.status_message,
166
+ response.header, response.body)
167
+
168
+ rescue Exception
169
+ io << http_resp(500, "Internal Server Error")
170
+ end
171
+
172
+ end # class HttpServer
173
+
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gserver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - John W. Small
8
+ - SHIBATA Hiroshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-08-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.7'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.7'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ description: GServer implements a generic server
43
+ email:
44
+ - hsbt@ruby-lang.org
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - gserver.gemspec
55
+ - lib/gserver.rb
56
+ - lib/gserver/version.rb
57
+ - sample/xmlrpc.rb
58
+ homepage: ''
59
+ licenses:
60
+ - Ruby
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.4.1
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: GServer implements a generic server
82
+ test_files: []
83
+ has_rdoc: