vhskit 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e430d0d0e31a503a95c60b807545dc1a3a94fc5e
4
+ data.tar.gz: 7a6a6ecc2b83794d50d64564fcb3bf29a3bc85df
5
+ SHA512:
6
+ metadata.gz: c9289b1c0329abe97406c8d8f63afcbf47cedb9494933b7d9c69a96979542ac7937bad712873ee0b52c08f627fafa51b85c5ed4bda1aad9034ee6d7bcf8f158c
7
+ data.tar.gz: 4021bc6ad57ccb61caec90c20b39706a7a2280b76927e9cccbdbfb991b5a5936ad51379be92967f44051d5344475cd9bfd0b7da81db48ae297c3a0a201e96124
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+ # vim: set sw=2 et:
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # VHSKit
2
+
3
+ VHSKit is a server that speaks like a real Postgres server.
4
+
5
+ See [example](example) for a sample.
6
+
7
+ `cert` (and its `key`) is a self-signed SSL certificate for 127.0.0.1, for your
8
+ convenience.
9
+
10
+ ## license
11
+
12
+ MIT.
13
+
14
+ ## copyright
15
+
16
+ © Amelia Cuss, 2013.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/core/rake_task'
4
+ require 'bundler/gem_tasks'
5
+
6
+ task :default => :spec
7
+
8
+ RSpec::Core::RakeTask.new
9
+
10
+ # vim: set sw=2 et:
data/cert ADDED
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDOzCCAiOgAwIBAgIJALKaTzk+J1xAMA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
3
+ BAYTAkFVMREwDwYDVQQIDAhWaWN0b3JpYTESMBAGA1UEAwwJMTI3LjAuMC4xMB4X
4
+ DTEzMTAwMTAyNDU0NVoXDTEzMTAzMTAyNDU0NVowNDELMAkGA1UEBhMCQVUxETAP
5
+ BgNVBAgMCFZpY3RvcmlhMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3
6
+ DQEBAQUAA4IBDwAwggEKAoIBAQDDBfIIsdVepCbi/sB+EP747kBS4YLLJBhPvV3W
7
+ zpBn45nSjikfEJmxGKE8oqVZSHfxMESWfdAJCwRQ+UhwiXIyiveZ8Dg0PsMDMLws
8
+ QljK0Qlmc8ZzBFKfqIT6wBVGks0u8RjE8KI0SA9QcKLSHBpmBktoaRQETnwYU222
9
+ oo3Z8cmYaIWmL/Zw0Hj3mGG3+nqFZEktk1xFo/COJ3gVGPJl7Gs9ESy60HWqEV1F
10
+ eTuGAak+5R3pmnyLrkV7UWKatWbWxGcIQ88G/BRsrR605OTH9HGZMj3ZtwDl60DF
11
+ /LDwRa9rA5X36L4Y/hUXXn/DAC5Qa2CAz2yQri8loLOXp0ExAgMBAAGjUDBOMB0G
12
+ A1UdDgQWBBQV2qgcTkj9NTGKpTBbK63D4IE62zAfBgNVHSMEGDAWgBQV2qgcTkj9
13
+ NTGKpTBbK63D4IE62zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCy
14
+ 9WcFT6WUspF1t4SHNG2i6Xhbv9i8KeAhgwYakANmx10iJse4Ssn5+i9/Hx34cYlt
15
+ dLmhxF8pGBeQtuh5kBQtLVQHkdJYmfjKSf4Ny2daF2kRpDSbh8jhwmu1FxPOO/T2
16
+ 86PyyBRRlEnfdTRrmz4UvHGVc8AWenJUcVHWqwiFwrOV6qE7sNwwXbXA9w16RnOg
17
+ M5jH+knVxqJT9ZNo2dmvM9b4jsmvtPDTElkWJ2D6ttPeHI0A8WtVU4Bf5mVlgq3O
18
+ n/n08+/Q1Z3hYUhibTfW1sKq9U3OKKo9zx6Whia3C3H+dbGkgO0J/jyiSc5Ns9/1
19
+ 54qrouInAjWJe5Ki8tbb
20
+ -----END CERTIFICATE-----
data/example ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ $: << "./lib"
5
+
6
+ require 'vhskit'
7
+
8
+ VHSKit.run(port: 15432) do
9
+ =begin
10
+ on_auth do |user, database|
11
+ puts "auth got user #{user}, database #{database}"
12
+ # return the password for this user, or nil if none
13
+ "hello"
14
+ end
15
+ =end
16
+
17
+ on_query do |user, database, query|
18
+ puts "user #{user}, database #{database}, query #{query}"
19
+
20
+ if query =~ /^insert /i
21
+ {insert: 4}
22
+ elsif query =~ /^delete /i
23
+ {delete: 4}
24
+ elsif query =~ /^update /i
25
+ {update: 4}
26
+ elsif query =~ /^select /i
27
+ {select:
28
+ {columns: ["id", "int4",
29
+ "name", "text"],
30
+ rows: ["1", "Joanne",
31
+ "2", "Yorick"]}}
32
+ else
33
+ nil
34
+ end
35
+ end
36
+ end
37
+
38
+ # vim: set sw=2 et:
data/key ADDED
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEAwwXyCLHVXqQm4v7AfhD++O5AUuGCyyQYT71d1s6QZ+OZ0o4p
3
+ HxCZsRihPKKlWUh38TBEln3QCQsEUPlIcIlyMor3mfA4ND7DAzC8LEJYytEJZnPG
4
+ cwRSn6iE+sAVRpLNLvEYxPCiNEgPUHCi0hwaZgZLaGkUBE58GFNttqKN2fHJmGiF
5
+ pi/2cNB495hht/p6hWRJLZNcRaPwjid4FRjyZexrPREsutB1qhFdRXk7hgGpPuUd
6
+ 6Zp8i65Fe1FimrVm1sRnCEPPBvwUbK0etOTkx/RxmTI92bcA5etAxfyw8EWvawOV
7
+ 9+i+GP4VF15/wwAuUGtggM9skK4vJaCzl6dBMQIDAQABAoIBAH3knqNiOPzJNpke
8
+ HqDC0/VZx4g5Lzd3a4I+Gg+KdMm7sRas0nrNOomJ/runutlx4It/vybuvJa51+V1
9
+ pn+PGnrqHn/vBDklsrmigjaH9c2nN0w9vIOO7M9H99/uk01lgrKkzHqFZBAf3FLv
10
+ AwxjO99UfOU/v74v9Ae4A4D8WlmvjFKCGzQJh+NywECnonU6YJzH+CNo2j//6lv5
11
+ LCvMSNooCffDoEdkwakFGyglha8xf0SaiaUsB7YFx4Yp0e5RQeSRC7ubtqK3QjRJ
12
+ WeESWyQPJMbpHps0NfFei5dgmGlqIqFncbQwHrHtQNsagM1eFWF+GoTp9xxrU4I5
13
+ PGKxi+ECgYEA8ISAsrGMsa5eex9CDBIclefLt7NrFlFaE2JEkwa0zE/DqfbUQJ28
14
+ 6NRcO5gLrIRA7uAnbstNVeTSNqiMkWbQhSAw9dhH4FiAEw0e/ZSsyZRFWFa6/W7T
15
+ ck6WI45Cn/QBavq5xkejMBFwGBIHtarzirw0sC4OP0FikeN+LU6fXyUCgYEAz5O9
16
+ VajcXiHU7gG6USozTMkD+HvPMLWlYR+eDlTPzpJ3+dRhySG6v8luYWN0X4yk0TsQ
17
+ hdbTv1iiJrB8qabMWVuMgXYJHDtnfIRWNzv0yr5HH2tcMZ1NWS+sXazNqUfdzxj1
18
+ KTxYRY+GOd57fwxgnMF90F0vENSo++asWp7fch0CgYEA1sEo/OUlv/z2pa7aVVbS
19
+ qVMIBiWwp4PKDua+Xh0t0AQkrB0VlgCCDc6X8Copukd4hxIkg3wJuHkQ7fb/VFDe
20
+ PQ/qR4lvXDUJXnlnw3o98dtvM5p1ahbLvBPJYUQD3ziLD4+B0zZh0mivkv5+Xcqf
21
+ nK/Bx9HHrNlf/u2G20OJb/UCgYAL5+5xLllNcOVUrXaxVxlQKyt2IivVIGYW9whK
22
+ zCSLNa15/+uH7M5YV8ZkAZ9YJ6oAckHVW2gTzpKmY3MTDAUmjvC1MD7/hoy+AJ0t
23
+ V9wHkPhlXfQQyHP6TJi3WsUFE6EuUsElF1f8zWmmghNVSzFzbEm6HM4pSflTUXzL
24
+ SdeJJQKBgQDcVB1n29fOX3icpADox3u9IMFNh0vPASa6MVbGhPq5NkDT7xHFRGVn
25
+ ECsS8H1MlLa4WG3UHsiUptk8K2hS71BqFlVUa2hbwY+NfthIFp2VDq33hAdLak2f
26
+ 3DdPDrVgJNPAPtyBIOw4YN6/96w6u/GEDjAy27MgOOK8T2bXj0W4JQ==
27
+ -----END RSA PRIVATE KEY-----
data/lib/vhskit.rb ADDED
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module VHSKit
4
+ require 'vhskit/server'
5
+
6
+ def self.run(opts, &block)
7
+ port = opts.delete(:port) || 5432
8
+
9
+ if opts.length > 0
10
+ raise ArgumentError.new("Unknown options: #{opts.keys.join ", "}")
11
+ end
12
+
13
+ conf = VHSKit::Configurator.new
14
+ if block
15
+ conf.instance_exec(&block)
16
+ end
17
+
18
+ VHSKit::Server.new(port, conf).run
19
+ end
20
+ end
21
+
22
+ # vim: set sw=2 et:
@@ -0,0 +1,255 @@
1
+ # encoding: utf-8
2
+
3
+ # References:
4
+ # http://www.postgresql.org/docs/9.1/static/protocol-flow.html
5
+ # http://www.postgresql.org/docs/9.1/static/protocol-message-formats.html
6
+ # http://www.postgresql.org/docs/9.1/static/catalog-pg-type.html
7
+ # http://www.postgresql.org/docs/9.1/static/catalog-pg-attribute.html
8
+ # http://ruby-doc.org/core-2.0.0/Array.html#method-i-pack
9
+ # http://www.postgresql.org/docs/9.1/static/protocol-error-fields.html
10
+ # http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
11
+
12
+ require 'openssl'
13
+ require 'vhskit/oid'
14
+
15
+ class VHSKit::Handler
16
+ def initialize(sock, conf)
17
+ @sock = sock
18
+ @conf = conf.fns
19
+ end
20
+
21
+ def run
22
+ start
23
+ @sock.close rescue false
24
+ rescue Exception => e
25
+ STDERR.puts "error in VHSKit::Handler: #{e}"
26
+ STDERR.puts e.backtrace
27
+ @sock.close rescue false
28
+ end
29
+
30
+ private
31
+
32
+ def start
33
+ startup = read_msg()
34
+ ver = startup.unpack('L>')[0]
35
+
36
+ if ver == 80877103 && startup.length == 4
37
+ @sock.write 'S' # accept the request
38
+
39
+ ctx = OpenSSL::SSL::SSLContext.new(:SSLv23_server)
40
+ ctx.cert = OpenSSL::X509::Certificate.new(File.read('cert'))
41
+ ctx.key = OpenSSL::PKey::RSA.new(File.read('key'))
42
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
43
+ @sock = OpenSSL::SSL::SSLSocket.new(@sock.to_io, ctx)
44
+ @sock.accept
45
+
46
+ startup = read_msg()
47
+ ver = startup.unpack('L>')[0]
48
+ end
49
+
50
+ if ver != 196608
51
+ STDERR.puts "unknown version #{ver}; bye"
52
+ return
53
+ end
54
+
55
+ handle_opts(startup[4..-1])
56
+ end
57
+
58
+ def handle_opts(opts)
59
+ hash = {}
60
+ while opts.length > 1
61
+ key, val, opts = opts.unpack('Z*Z*a*')
62
+ hash[key] = val
63
+ end
64
+
65
+ if opts != "\0"
66
+ STDERR.puts "options terminated poorly; bye"
67
+ return
68
+ end
69
+
70
+ if !hash["user"]
71
+ STDERR.puts "no user specified; bye"
72
+ return
73
+ end
74
+
75
+ @user = hash["user"]
76
+ @database = hash["database"] || @user
77
+
78
+ if @conf[:on_auth]
79
+ pwd = @conf[:on_auth].call(@user, @database)
80
+
81
+ salt = Random::DEFAULT.bytes(4)
82
+ STDERR.puts salt.bytes.length
83
+ write_msg 'R', [5, salt].pack('L>a*') # AuthenticationMD5
84
+ tag = read_tag
85
+
86
+ if tag != 'p'
87
+ STDERR.puts "expected 'p', got #{tag}; bye"
88
+ return
89
+ end
90
+
91
+ enc = read_msg().unpack('Z*')[0]
92
+
93
+ if !pwd
94
+ comp = nil
95
+ else
96
+ comp = 'md5' + Digest::MD5.hexdigest(
97
+ Digest::MD5.hexdigest(pwd + @user) + salt)
98
+ end
99
+
100
+ if enc != comp
101
+ write_msg 'E', notice_error_body(
102
+ 'S' => 'FATAL',
103
+ 'C' => '28P01',
104
+ 'M' => "password authentication failed for user \"#@user\"")
105
+ return
106
+ end
107
+ end
108
+
109
+ write_msg 'R', [0].pack('L>') # AuthenticationOk
110
+
111
+ mainloop
112
+ end
113
+
114
+ def mainloop
115
+ @abort = false
116
+ while !@abort
117
+ main
118
+ end
119
+ end
120
+
121
+ def main
122
+ # ReadyForQuery
123
+ write_msg 'Z', (!@transaction ? 'I' : 'T') # 'E' for failed txn block
124
+
125
+ kind = @sock.read(1)
126
+
127
+ case kind
128
+ when 'Q'
129
+ query
130
+ when 'X'
131
+ puts "client terminated"
132
+ @abort = true
133
+ else
134
+ STDERR.puts "unknown kind #{kind}"
135
+ @abort = true
136
+ end
137
+ end
138
+
139
+ def query
140
+ query = read_msg()
141
+ on_query = @conf[:on_query]
142
+ if !on_query
143
+ write_msg 'E', notice_error_body(
144
+ 'S' => 'ERROR',
145
+ 'C' => 'XX000',
146
+ 'M' => 'Internal error: no query handler available')
147
+ return
148
+ end
149
+
150
+ each_query(query.strip, on_query)
151
+ end
152
+
153
+ def each_query(query, on_query)
154
+ result = on_query.call(@user, @database, query)
155
+ if !result || result.keys.length != 1
156
+ STDERR.puts "result.keys not unary for #{query.inspect}: #{result.inspect}"
157
+ write_msg 'E', notice_error_body(
158
+ 'S' => 'ERROR',
159
+ 'C' => 'XX000',
160
+ 'M' => "Internal error: query handler didn't return sensible data")
161
+ return
162
+ end
163
+
164
+ key, value = result.to_a[0]
165
+
166
+ case key
167
+ when :insert
168
+ # CommandComplete
169
+ write_msg 'C', ["INSERT 0 #{value}"].pack('Z*')
170
+ when :delete
171
+ # CommandComplete
172
+ write_msg 'C', ["DELETE #{value}"].pack('Z*')
173
+ when :update
174
+ # CommandComplete
175
+ write_msg 'C', ["UPDATE #{value}"].pack('Z*')
176
+ when :select
177
+ rows = value[:columns].each_slice(2).map {|name, type|
178
+ [name, 0, 0, VHSKit::OID.by_name(type),
179
+ 4, # XXX this is wrong
180
+ -1, 0]}
181
+ # RowDescription
182
+ write_msg 'T', row_descriptions(rows)
183
+
184
+ count = 0
185
+ value[:rows].each_slice(rows.length).each do |row|
186
+ # DataRow
187
+ write_msg 'D', data_row(row)
188
+ count += 1
189
+ end
190
+
191
+ # CommandComplete
192
+ write_msg 'C', ["SELECT #{count}"].pack('Z*')
193
+ # when :move
194
+ # when :fetch
195
+ # when :copy
196
+ else
197
+ raise StandardError.new("unknown key #{key.inspect}")
198
+ end
199
+ end
200
+
201
+ def read_tag()
202
+ r = @sock.read(1)
203
+ if !r || r.length < 1
204
+ raise EOFError
205
+ end
206
+ r
207
+ end
208
+
209
+ def read_msg()
210
+ len = @sock.read(4).unpack('L>')[0]
211
+ r = @sock.read(len - 4)
212
+ if !r || r.length < len - 4
213
+ raise EOFError
214
+ end
215
+ r
216
+ end
217
+
218
+ def write_msg(tag, data)
219
+ @sock.write tag
220
+ @sock.write [data.length + 4].pack('L>')
221
+ @sock.write data
222
+ @sock.flush
223
+ end
224
+
225
+ def notice_error_body(pairs)
226
+ pairs.map do |k,v|
227
+ if k.length != 1
228
+ raise ArgumentError.new("notice_error_body got key #{k.inspect}")
229
+ end
230
+
231
+ [k, v].pack('aZ*')
232
+ end.join.force_encoding('US-ASCII') + "\00"
233
+ end
234
+
235
+ # rows should be an Array of Arrays of:
236
+ # - field name (String)
237
+ # - table OID or zero (Integer)
238
+ # - column OID or zero (Integer)
239
+ # - data type OID (Integer)
240
+ # - data type size (Integer)
241
+ # - type modifier (Integer)
242
+ # - format code (Integer: 0 text, 1 binary)
243
+ def row_descriptions(rows)
244
+ [rows.length,
245
+ rows.map {|e| e.pack('Z*L>S>L>S>L>S>')}.join].pack('S>a*')
246
+ end
247
+
248
+ # columns should be an Array of Strings
249
+ def data_row(columns)
250
+ [columns.length,
251
+ columns.map {|e| [e.length + 1, e].pack('L>Z*')}.join].pack('S>a*')
252
+ end
253
+ end
254
+
255
+ # vim: set sw=2 et:
data/lib/vhskit/oid.rb ADDED
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+
3
+ # Source for OIDs:
4
+ # http://jdbc.postgresql.org/development/privateapi/constant-values.html#org.postgresql.core.Oid.INT4
5
+
6
+ module VHSKit::OID
7
+ BIT = 1560
8
+ BIT_ARRAY = 1561
9
+ BOOL = 16
10
+ BOOL_ARRAY = 1000
11
+ BPCHAR = 1042
12
+ BPCHAR_ARRAY = 1014
13
+ BYTEA = 17
14
+ BYTEA_ARRAY = 1001
15
+ CHAR = 18
16
+ CHAR_ARRAY = 1002
17
+ DATE = 1082
18
+ DATE_ARRAY = 1182
19
+ FLOAT4 = 700
20
+ FLOAT4_ARRAY = 1021
21
+ FLOAT8 = 701
22
+ FLOAT8_ARRAY = 1022
23
+ INT2 = 21
24
+ INT2_ARRAY = 1005
25
+ INT4 = 23
26
+ INT4_ARRAY = 1007
27
+ INT8 = 20
28
+ INT8_ARRAY = 1016
29
+ INTERVAL = 1186
30
+ INTERVAL_ARRAY = 1187
31
+ MONEY = 790
32
+ MONEY_ARRAY = 791
33
+ NAME = 19
34
+ NAME_ARRAY = 1003
35
+ NUMERIC = 1700
36
+ NUMERIC_ARRAY = 1231
37
+ OID = 26
38
+ OID_ARRAY = 1028
39
+ TEXT = 25
40
+ TEXT_ARRAY = 1009
41
+ TIME = 1083
42
+ TIME_ARRAY = 1183
43
+ TIMESTAMP = 1114
44
+ TIMESTAMP_ARRAY = 1115
45
+ TIMESTAMPTZ = 1184
46
+ TIMESTAMPTZ_ARRAY = 1185
47
+ TIMETZ = 1266
48
+ TIMETZ_ARRAY = 1270
49
+ UNSPECIFIED = 0
50
+ UUID = 2950
51
+ UUID_ARRAY = 2951
52
+ VARBIT = 1562
53
+ VARBIT_ARRAY = 1563
54
+ VARCHAR = 1043
55
+ VARCHAR_ARRAY = 1015
56
+ VOID = 2278
57
+ XML = 142
58
+ XML_ARRAY = 143
59
+
60
+ def self.by_name(name)
61
+ name = name.upcase
62
+
63
+ array = false
64
+ if name =~ /^(.+)\[\]$/
65
+ name = $1
66
+ array = true
67
+ end
68
+
69
+ if name =~ /^(.+) WITHOUT TIME ZONE$/
70
+ name = $1
71
+ end
72
+
73
+ if name =~ /^(.+) WITH TIME ZONE$/
74
+ name = "#{$1}TZ"
75
+ end
76
+
77
+ if array
78
+ name << "_ARRAY"
79
+ end
80
+
81
+ const_get name
82
+ end
83
+ end
84
+
85
+ # vim: set sw=2 et:
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'socket'
4
+ require 'vhskit/handler'
5
+
6
+ class VHSKit::Server
7
+ def initialize(port, conf)
8
+ @serv = TCPServer.new port
9
+ @conf = conf
10
+ end
11
+
12
+ def run
13
+ while true
14
+ sock = @serv.accept
15
+ Thread.start do
16
+ VHSKit::Handler.new(sock, @conf).run
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class VHSKit::Configurator
23
+ def initialize
24
+ @fns = {}
25
+ end
26
+
27
+ attr_reader :fns
28
+
29
+ FNS = [:on_auth, :on_query]
30
+
31
+ FNS.each do |fn|
32
+ define_method(fn) do |&block|
33
+ @fns[fn] = block
34
+ end
35
+ end
36
+ end
37
+
38
+ # vim: set sw=2 et:
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ module VHSKit
4
+ VERSION = "0.0.1"
5
+ end
6
+
7
+ # vim: set sw=2 et:
data/vhskit.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../lib/vhskit/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ["Amelia Cuss"]
7
+ gem.email = ["amelia@kivikakk.ee"]
8
+ gem.description = %q{Just like a Postgres server, only fake}
9
+ gem.summary = %q{A Postgres server protocol implementation you can configure with a DSL.}
10
+ gem.homepage = "https://github.com/kivikakk/vhskit"
11
+
12
+ gem.add_development_dependency('rake')
13
+ gem.add_development_dependency('rspec')
14
+
15
+ gem.files = `git ls-files`.split($\)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.name = "vhskit"
19
+ gem.require_paths = ["lib"]
20
+ gem.version = VHSKit::VERSION
21
+ end
22
+
23
+ # vim: set sw=2 et:
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vhskit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Amelia Cuss
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Just like a Postgres server, only fake
42
+ email:
43
+ - amelia@kivikakk.ee
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .rspec
50
+ - .travis.yml
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - cert
55
+ - example
56
+ - key
57
+ - lib/vhskit.rb
58
+ - lib/vhskit/handler.rb
59
+ - lib/vhskit/oid.rb
60
+ - lib/vhskit/server.rb
61
+ - lib/vhskit/version.rb
62
+ - vhskit.gemspec
63
+ homepage: https://github.com/kivikakk/vhskit
64
+ licenses: []
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.0.3
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: A Postgres server protocol implementation you can configure with a DSL.
86
+ test_files: []