gohttp 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6970bde6a9b5abb0c5dba6d1d24dd8d45e6d5f03
4
+ data.tar.gz: a49d93842ba8fbb32e5daf62c2cadfc406013d24
5
+ SHA512:
6
+ metadata.gz: 76290ca49818def17d3d107273b84811511d668539c3cecd01a79250d39ac50e52ad421ea6721177438c07936b7376024422950998e3cc45e44e6df22b181387
7
+ data.tar.gz: 37f5738e18ce5210bcca7afc3a13860138eb23021178cb5783537b2969d11bc53f07da103bc9710f73f6c4019510c8c5a3d679fa07a49409026f498334418828
@@ -0,0 +1,17 @@
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
+ *.swp
13
+ *.o
14
+ *.a
15
+ mkmf.log
16
+ gohttp.h
17
+ gohttp.so
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (C) 2015 NARUSE, Yui. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,35 @@
1
+ # Gohttp
2
+
3
+ A demo to implement a extension library with Go.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'gohttp'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install gohttp
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'gohttp'
25
+ r = Gohttp.get('https://example.com/index.html')
26
+ puts r.body.read
27
+ ```
28
+
29
+ ## Contributing
30
+
31
+ 1. Fork it ( https://github.com/nurse/gohttp/fork )
32
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
33
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
34
+ 4. Push to the branch (`git push origin my-new-feature`)
35
+ 5. Create a new Pull Request
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+ require 'rspec/core/rake_task'
4
+ require 'rake/extensiontask'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ task :default => [:compile, :spec]
8
+
9
+ spec = eval File.read('gohttp.gemspec')
10
+ Rake::ExtensionTask.new('gohttp', spec) do |ext|
11
+ ext.ext_dir = 'ext/gohttp'
12
+ ext.lib_dir = File.join(*['lib', 'gohttp', ENV['FAT_DIR']].compact)
13
+ ext.source_pattern = "*.{c,cpp,go}"
14
+ end
15
+
16
+ RSpec::Core::RakeTask.new :spec do |spec|
17
+ spec.pattern = 'spec/**/*_spec.rb'
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'mkmf'
2
+ find_executable('go')
3
+ $objs = []
4
+ def $objs.empty?; false ;end
5
+ create_makefile("gohttp/gohttp")
6
+ case `#{CONFIG['CC']} --version`
7
+ when /Free Software Foundation/
8
+ ldflags = '-Wl,--unresolved-symbols=ignore-all'
9
+ when /clang/
10
+ ldflags = '-undefined dynamic_lookup'
11
+ end
12
+ File.open('Makefile', 'a') do |f|
13
+ f.write <<eom.gsub(/^ {8}/, "\t")
14
+ $(DLLIB): Makefile $(srcdir)/gohttp.go $(srcdir)/wrapper.go
15
+ CGO_CFLAGS='$(INCFLAGS)' CGO_LDFLAGS='#{ldflags}' \
16
+ go build -p 4 -buildmode=c-shared -o $(DLLIB) $(srcdir)/gohttp.go $(srcdir)/wrapper.go
17
+ eom
18
+ end
@@ -0,0 +1,362 @@
1
+ package main
2
+
3
+ /*
4
+ #include <ruby/ruby.h>
5
+
6
+ VALUE NewGoStruct(VALUE klass, void *p);
7
+ void *GetGoStruct(VALUE obj);
8
+
9
+ VALUE gohttp_hello(VALUE);
10
+ VALUE gohttpGet(VALUE,VALUE);
11
+ VALUE gohttpHead(VALUE,VALUE);
12
+ int hash_of_ary_of_str2values_i(VALUE,VALUE,VALUE);
13
+ VALUE gohttpPostForm(VALUE,VALUE,VALUE);
14
+ VALUE gohttp_get_url(VALUE,VALUE);
15
+ VALUE gourlQueryEscape(VALUE,VALUE);
16
+ VALUE gourlQueryUnescape(VALUE,VALUE);
17
+
18
+ VALUE goio_to_s(VALUE);
19
+ VALUE goioRead(VALUE);
20
+ VALUE goioClose(VALUE);
21
+
22
+ VALUE reqMethod(VALUE);
23
+ VALUE reqURL(VALUE);
24
+ VALUE reqProto(VALUE);
25
+ VALUE reqHeader(VALUE);
26
+ VALUE reqBody(VALUE);
27
+ VALUE reqContentLength(VALUE);
28
+ VALUE reqTransferEncoding(VALUE);
29
+ VALUE reqHost(VALUE);
30
+ VALUE reqForm(VALUE);
31
+ VALUE reqForm(VALUE);
32
+ VALUE reqForm(VALUE);
33
+ VALUE reqForm(VALUE);
34
+ VALUE reqRemoteAddr(VALUE);
35
+ VALUE reqRequestURI(VALUE);
36
+
37
+ VALUE respContentLength(VALUE);
38
+ VALUE respStatus(VALUE);
39
+ VALUE respStatusCode(VALUE);
40
+ VALUE respProto(VALUE);
41
+ VALUE respTransferEncoding(VALUE);
42
+ VALUE respHeader(VALUE);
43
+ VALUE respBody(VALUE);
44
+ VALUE respRequest(VALUE);
45
+ */
46
+ import "C"
47
+
48
+ import "fmt"
49
+ import "io"
50
+ import "io/ioutil"
51
+ import "net/http"
52
+ import "net/url"
53
+ import "reflect"
54
+ import "unsafe"
55
+
56
+ func main() {
57
+ }
58
+
59
+ var rb_cGoIO C.VALUE
60
+ var rb_cGohttp C.VALUE
61
+ var rb_cGourl C.VALUE
62
+ var rb_cRequest C.VALUE
63
+ var rb_cResponse C.VALUE
64
+
65
+ //export goobj_retain
66
+ func goobj_retain(obj unsafe.Pointer) {
67
+ objects[obj] = true
68
+ }
69
+
70
+ //export goobj_free
71
+ func goobj_free(obj unsafe.Pointer) {
72
+ delete(objects, obj)
73
+ }
74
+
75
+ func goioNew(klass C.VALUE, r interface{}) C.VALUE {
76
+ v := reflect.ValueOf(r)
77
+ return C.NewGoStruct(klass, unsafe.Pointer(&v))
78
+ }
79
+
80
+ //export goio_to_s
81
+ func goio_to_s(self C.VALUE) C.VALUE {
82
+ v := (*reflect.Value)(C.GetGoStruct(self))
83
+ switch v.Kind() {
84
+ case reflect.Struct:
85
+ return RbString(fmt.Sprintf("#<GoIO:%s>", v.Type().String()))
86
+ case reflect.Chan, reflect.Map, reflect.Ptr, reflect.UnsafePointer:
87
+ return RbString(fmt.Sprintf("#<GoIO:%s:0x%X>", v.Type().String(), v.Pointer()))
88
+ default:
89
+ return RbString(fmt.Sprintf("#<GoIO:%s>", v.Type().String()))
90
+ }
91
+ }
92
+
93
+ //export goioRead
94
+ func goioRead(self C.VALUE) C.VALUE {
95
+ v := (*reflect.Value)(C.GetGoStruct(self))
96
+ r := v.Interface().(io.Reader)
97
+ body, err := ioutil.ReadAll(r)
98
+ if err != nil {
99
+ rb_raise(C.rb_eArgError, "'%s'", err)
100
+ }
101
+ return RbBytes(body)
102
+ }
103
+
104
+ //export goioClose
105
+ func goioClose(self C.VALUE) C.VALUE {
106
+ v := (*reflect.Value)(C.GetGoStruct(self))
107
+ if c, ok := v.Interface().(io.Closer); ok {
108
+ c.Close()
109
+ return C.Qtrue
110
+ }
111
+ return C.Qfalse
112
+ }
113
+
114
+ func reqNew(klass C.VALUE, r *http.Request) C.VALUE {
115
+ return C.NewGoStruct(klass, unsafe.Pointer(r))
116
+ }
117
+
118
+ //export reqMethod
119
+ func reqMethod(self C.VALUE) C.VALUE {
120
+ req := (*http.Request)(C.GetGoStruct(self))
121
+ return RbString(req.Method)
122
+ }
123
+
124
+ //export reqProto
125
+ func reqProto(self C.VALUE) C.VALUE {
126
+ req := (*http.Request)(C.GetGoStruct(self))
127
+ return RbString(req.Proto)
128
+ }
129
+
130
+ //export reqHeader
131
+ func reqHeader(self C.VALUE) C.VALUE {
132
+ req := (*http.Request)(C.GetGoStruct(self))
133
+ h := C.rb_hash_new()
134
+ for key, value := range req.Header {
135
+ C.rb_hash_aset(h, RbString(key), StrSlice2RbArray(value))
136
+ }
137
+ return h
138
+ }
139
+
140
+ //export reqBody
141
+ func reqBody(self C.VALUE) C.VALUE {
142
+ req := (*http.Request)(C.GetGoStruct(self))
143
+ if req.Body == nil {
144
+ return C.Qnil
145
+ }
146
+ return goioNew(rb_cGoIO, req.Body)
147
+ }
148
+
149
+ //export reqContentLength
150
+ func reqContentLength(self C.VALUE) C.VALUE {
151
+ req := (*http.Request)(C.GetGoStruct(self))
152
+ return INT64toNUM(req.ContentLength)
153
+ }
154
+
155
+ //export reqTransferEncoding
156
+ func reqTransferEncoding(self C.VALUE) C.VALUE {
157
+ req := (*http.Request)(C.GetGoStruct(self))
158
+ return StrSlice2RbArray(req.TransferEncoding)
159
+ }
160
+
161
+ //export reqHost
162
+ func reqHost(self C.VALUE) C.VALUE {
163
+ req := (*http.Request)(C.GetGoStruct(self))
164
+ return RbString(req.Host)
165
+ }
166
+
167
+ //export reqRemoteAddr
168
+ func reqRemoteAddr(self C.VALUE) C.VALUE {
169
+ req := (*http.Request)(C.GetGoStruct(self))
170
+ return RbString(req.RemoteAddr)
171
+ }
172
+
173
+ //export reqRequestURI
174
+ func reqRequestURI(self C.VALUE) C.VALUE {
175
+ req := (*http.Request)(C.GetGoStruct(self))
176
+ return RbString(req.RequestURI)
177
+ }
178
+
179
+ func respNew(klass C.VALUE, r *http.Response) C.VALUE {
180
+ return C.NewGoStruct(klass, unsafe.Pointer(r))
181
+ }
182
+
183
+ //export respContentLength
184
+ func respContentLength(self C.VALUE) C.VALUE {
185
+ resp := (*http.Response)(C.GetGoStruct(self))
186
+ return INT64toNUM(resp.ContentLength)
187
+ }
188
+
189
+ //export respHeader
190
+ func respHeader(self C.VALUE) C.VALUE {
191
+ resp := (*http.Response)(C.GetGoStruct(self))
192
+ h := C.rb_hash_new()
193
+ for key, value := range resp.Header {
194
+ C.rb_hash_aset(h, RbString(key), StrSlice2RbArray(value))
195
+ }
196
+ return h
197
+ }
198
+
199
+ //export respStatus
200
+ func respStatus(self C.VALUE) C.VALUE {
201
+ resp := (*http.Response)(C.GetGoStruct(self))
202
+ return RbString(resp.Status)
203
+ }
204
+
205
+ //export respStatusCode
206
+ func respStatusCode(self C.VALUE) C.VALUE {
207
+ resp := (*http.Response)(C.GetGoStruct(self))
208
+ return INT2NUM(resp.StatusCode)
209
+ }
210
+
211
+ //export respProto
212
+ func respProto(self C.VALUE) C.VALUE {
213
+ resp := (*http.Response)(C.GetGoStruct(self))
214
+ return RbString(resp.Proto)
215
+ }
216
+
217
+ //export respTransferEncoding
218
+ func respTransferEncoding(self C.VALUE) C.VALUE {
219
+ resp := (*http.Response)(C.GetGoStruct(self))
220
+ return StrSlice2RbArray(resp.TransferEncoding)
221
+ }
222
+
223
+ //export respBody
224
+ func respBody(self C.VALUE) C.VALUE {
225
+ resp := (*http.Response)(C.GetGoStruct(self))
226
+ if resp.Body == nil {
227
+ return C.Qnil
228
+ }
229
+ return goioNew(rb_cGoIO, resp.Body)
230
+ }
231
+
232
+ //export respRequest
233
+ func respRequest(self C.VALUE) C.VALUE {
234
+ resp := (*http.Response)(C.GetGoStruct(self))
235
+ return reqNew(rb_cRequest, resp.Request)
236
+ }
237
+
238
+ //export gohttp_hello
239
+ func gohttp_hello(dummy C.VALUE) C.VALUE {
240
+ fmt.Printf("hello, world\n")
241
+ return C.Qnil
242
+ }
243
+
244
+ //export gohttpGet
245
+ func gohttpGet(dummy C.VALUE, urlstr C.VALUE) C.VALUE {
246
+ str := RbGoString(urlstr)
247
+ resp, err := http.Get(str)
248
+ if err != nil {
249
+ rb_raise(C.rb_eArgError, "'%s'", err)
250
+ }
251
+ return respNew(rb_cResponse, resp)
252
+ }
253
+
254
+ //export gohttpHead
255
+ func gohttpHead(dummy C.VALUE, urlstr C.VALUE) C.VALUE {
256
+ str := RbGoString(urlstr)
257
+ resp, err := http.Head(str)
258
+ if err != nil {
259
+ rb_raise(C.rb_eArgError, "'%s'", err)
260
+ }
261
+ return respNew(rb_cResponse, resp)
262
+ }
263
+
264
+ //export hash_of_ary_of_str2values_i
265
+ func hash_of_ary_of_str2values_i(key C.VALUE, ary C.VALUE, arg C.VALUE) C.int {
266
+ values := (*url.Values)(unsafe.Pointer(uintptr(arg)))
267
+ values.Add(RbGoString(key), RbGoString(ary))
268
+ return C.ST_CONTINUE
269
+ }
270
+
271
+ //export gohttpPostForm
272
+ func gohttpPostForm(dummy C.VALUE, urlstr C.VALUE, data C.VALUE) C.VALUE {
273
+ str := RbGoString(urlstr)
274
+ val := url.Values{}
275
+ C.rb_hash_foreach(data, (*[0]byte)(C.hash_of_ary_of_str2values_i), C.VALUE(uintptr(unsafe.Pointer(&val))))
276
+ resp, err := http.PostForm(str, val)
277
+ if err != nil {
278
+ rb_raise(C.rb_eArgError, "'%s'", err)
279
+ }
280
+ return respNew(rb_cResponse, resp)
281
+ }
282
+
283
+ //export gohttp_get_url
284
+ func gohttp_get_url(dummy C.VALUE, urlstr C.VALUE) C.VALUE {
285
+ u, err := url.Parse(RbGoString(urlstr))
286
+ if err != nil {
287
+ return C.Qnil
288
+ }
289
+ return RbString(u.String())
290
+ }
291
+
292
+ //export gourlQueryEscape
293
+ func gourlQueryEscape(dummy C.VALUE, s C.VALUE) C.VALUE {
294
+ return RbString(url.QueryEscape(RbGoString(s)))
295
+ }
296
+
297
+ //export gourlQueryUnescape
298
+ func gourlQueryUnescape(dummy C.VALUE, s C.VALUE) C.VALUE {
299
+ src := RbGoString(s)
300
+ str, err := url.QueryUnescape(src)
301
+ if err != nil {
302
+ rb_raise(C.rb_eArgError, "'%s' is not valid pct-encoded", src)
303
+ }
304
+ return RbString(str)
305
+ }
306
+
307
+ //export Init_gohttp
308
+ func Init_gohttp() {
309
+ sNew := "new"
310
+ str_new := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&sNew)))[0]))
311
+
312
+ rb_cGoIO = rb_define_class("GoIO", C.rb_cIO)
313
+ C.rb_undef_alloc_func(rb_cGoIO)
314
+ C.rb_undef_method(C.rb_class_of(rb_cGoIO), str_new)
315
+ rb_define_method(rb_cGoIO, "to_s", C.goio_to_s, 0)
316
+ rb_define_method(rb_cGoIO, "inspect", C.goio_to_s, 0)
317
+ rb_define_method(rb_cGoIO, "read", C.goioRead, 0)
318
+ rb_define_method(rb_cGoIO, "close", C.goioClose, 0)
319
+
320
+ rb_cRequest = rb_define_class("Request", C.rb_cObject)
321
+ C.rb_undef_alloc_func(rb_cRequest)
322
+ C.rb_undef_method(C.rb_class_of(rb_cRequest), str_new)
323
+ rb_define_method(rb_cRequest, "method", C.reqMethod, 0)
324
+ //rb_define_method(rb_cRequest, "url", C.reqURL, 0)
325
+ rb_define_method(rb_cRequest, "proto", C.reqProto, 0)
326
+ rb_define_method(rb_cRequest, "header", C.reqHeader, 0)
327
+ rb_define_method(rb_cRequest, "body", C.reqBody, 0)
328
+ rb_define_method(rb_cRequest, "content_length", C.reqContentLength, 0)
329
+ rb_define_method(rb_cRequest, "transfer_encoding", C.reqTransferEncoding, 0)
330
+ rb_define_method(rb_cRequest, "host", C.reqHost, 0)
331
+ //rb_define_method(rb_cRequest, "form", C.reqForm, 0)
332
+ //rb_define_method(rb_cRequest, "post_form", C.reqForm, 0)
333
+ //rb_define_method(rb_cRequest, "multipart_form", C.reqForm, 0)
334
+ //rb_define_method(rb_cRequest, "trailer", C.reqForm, 0)
335
+ rb_define_method(rb_cRequest, "remote_addr", C.reqRemoteAddr, 0)
336
+ rb_define_method(rb_cRequest, "request_uri", C.reqRequestURI, 0)
337
+
338
+ rb_cResponse = rb_define_class("Response", C.rb_cObject)
339
+ C.rb_undef_alloc_func(rb_cResponse)
340
+ C.rb_undef_method(C.rb_class_of(rb_cResponse), str_new)
341
+ rb_define_method(rb_cResponse, "size", C.respContentLength, 0)
342
+ rb_define_method(rb_cResponse, "status", C.respStatus, 0)
343
+ rb_define_method(rb_cResponse, "status_code", C.respStatusCode, 0)
344
+ rb_define_method(rb_cResponse, "proto", C.respProto, 0)
345
+ rb_define_method(rb_cResponse, "transfer_encoding", C.respTransferEncoding, 0)
346
+ rb_define_method(rb_cResponse, "header", C.respHeader, 0)
347
+ rb_define_method(rb_cResponse, "body", C.respBody, 0)
348
+ rb_define_method(rb_cResponse, "request", C.respRequest, 0)
349
+
350
+ rb_cGohttp = rb_define_class("Gohttp", C.rb_cObject)
351
+ rb_define_singleton_method(rb_cGohttp, "hello", C.gohttp_hello, 0)
352
+ rb_define_singleton_method(rb_cGohttp, "get", C.gohttpGet, 1)
353
+ rb_define_singleton_method(rb_cGohttp, "head", C.gohttpHead, 1)
354
+ //rb_define_singleton_method(rb_cGohttp, "post", C.gohttpPost, 1)
355
+ rb_define_singleton_method(rb_cGohttp, "post_form", C.gohttpPostForm, 2)
356
+ //rb_define_method(rb_cGohttp, "initialize", C.gohttp_initialize, 1)
357
+ rb_define_method(rb_cGohttp, "get_url", C.gohttp_get_url, 1)
358
+
359
+ rb_cGourl = rb_define_class("Gourl", C.rb_cObject)
360
+ rb_define_singleton_method(rb_cGourl, "query_escape", C.gourlQueryEscape, 1)
361
+ rb_define_singleton_method(rb_cGourl, "query_unescape", C.gourlQueryUnescape, 1)
362
+ }
@@ -0,0 +1,105 @@
1
+ package main
2
+
3
+ /*
4
+ #include <ruby/ruby.h>
5
+
6
+ const char *
7
+ rstring_ptr(VALUE str) {
8
+ return RSTRING_PTR(str);
9
+ }
10
+ int
11
+ rstring_len(VALUE str) {
12
+ return RSTRING_LENINT(str);
13
+ }
14
+ void
15
+ rb_raise2(VALUE exc, const char *str) {
16
+ rb_raise(exc, "%s", str);
17
+ }
18
+
19
+ void goobj_retain(void *);
20
+ void goobj_free(void *);
21
+
22
+ static const rb_data_type_t go_type = {
23
+ "GoStruct",
24
+ {NULL, goobj_free, NULL},
25
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
26
+ };
27
+
28
+ VALUE
29
+ NewGoStruct(VALUE klass, void *p)
30
+ {
31
+ goobj_retain(p);
32
+ return TypedData_Wrap_Struct((klass), &go_type, p);
33
+ }
34
+
35
+ void *
36
+ GetGoStruct(VALUE obj)
37
+ {
38
+ void *val;
39
+ return TypedData_Get_Struct((obj), void *, &go_type, (val));
40
+ }
41
+ */
42
+ import "C"
43
+ import "unsafe"
44
+ import "fmt"
45
+
46
+ var objects = make(map[interface{}]bool)
47
+
48
+ func rb_define_method(klass C.VALUE, name string, fun unsafe.Pointer, args int) {
49
+ cname := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&name)))[0]))
50
+ C.rb_define_method(klass, cname, (*[0]byte)(fun), C.int(args))
51
+ }
52
+
53
+ func rb_define_singleton_method(klass C.VALUE, name string, fun unsafe.Pointer, args int) {
54
+ cname := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&name)))[0]))
55
+ C.rb_define_singleton_method(klass, cname, (*[0]byte)(fun), C.int(args))
56
+ }
57
+
58
+ func RbGoString(str C.VALUE) string {
59
+ C.rb_string_value(&str)
60
+ return C.GoStringN(C.rstring_ptr(str), C.rstring_len(str))
61
+ }
62
+
63
+ func RbBytes(bytes []byte) C.VALUE {
64
+ if len(bytes) == 0 {
65
+ return C.rb_str_new(nil, C.long(0))
66
+ }
67
+ cstr := (*C.char)(unsafe.Pointer(&bytes[0]))
68
+ return C.rb_str_new(cstr, C.long(len(bytes)))
69
+ }
70
+
71
+ func RbString(str string) C.VALUE {
72
+ if len(str) == 0 {
73
+ return C.rb_utf8_str_new(nil, C.long(0))
74
+ }
75
+ cstr := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&str)))[0]))
76
+ return C.rb_utf8_str_new(cstr, C.long(len(str)))
77
+ }
78
+
79
+ func rb_define_class(name string, parent C.VALUE) C.VALUE {
80
+ cname := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&name)))[0]))
81
+ v := C.rb_define_class(cname, parent)
82
+ return v
83
+ }
84
+
85
+ func rb_raise(exc C.VALUE, format string, a ...interface{}) {
86
+ str := fmt.Sprintf(format, a...)
87
+ cstr := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&str)))[0]))
88
+ C.rb_raise2(exc, cstr)
89
+ }
90
+
91
+ func INT2NUM(n int) C.VALUE {
92
+ return C.rb_int2inum(C.long(n))
93
+ }
94
+
95
+ func INT64toNUM(n int64) C.VALUE {
96
+ return C.rb_ll2inum(C.longlong(n))
97
+ }
98
+
99
+ func StrSlice2RbArray(slice []string) C.VALUE {
100
+ ary := C.rb_ary_new_capa(C.long(len(slice)))
101
+ for _, val := range slice {
102
+ C.rb_ary_push(ary, RbString(val))
103
+ }
104
+ return ary
105
+ }
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gohttp/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gohttp"
8
+ spec.version = Strptime::VERSION
9
+ spec.authors = ["NARUSE, Yui"]
10
+ spec.email = ["naruse@airemix.jp"]
11
+
12
+ spec.summary = %q{an http library with go.}
13
+ spec.description = %q{an http library with go.}
14
+ spec.homepage = "https://github.com/nurse/gohttp"
15
+ spec.license = "BSD-2-Clause"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+ spec.extensions = ["ext/gohttp/extconf.rb"]
22
+ spec.required_ruby_version = '~> 2.0'
23
+
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rake-compiler"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency 'yard'
29
+ end
@@ -0,0 +1,10 @@
1
+ require "gohttp/version"
2
+ begin
3
+ require "gohttp/#{RUBY_VERSION[/\d+\.\d+/]}/gohttp"
4
+ rescue LoadError
5
+ require "gohttp/gohttp"
6
+ end
7
+
8
+ class Gohttp
9
+ # Your code goes here...
10
+ end
@@ -0,0 +1,3 @@
1
+ class Strptime
2
+ VERSION = "0.1.0"
3
+ end
data/test.rb ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gohttp'
4
+ require 'minitest/autorun'
5
+
6
+ class TestGohttp < Minitest::Test
7
+ def test_hello
8
+ assert_output("hello, world\n") do
9
+ Gohttp.hello
10
+ end
11
+ end
12
+
13
+ def test_hello
14
+ o = Object.new
15
+ def o.to_str; "https://例え.テスト/ファイル.html"; end
16
+ g = Gohttp.new
17
+ assert_equal "https://%E4%BE%8B%E3%81%88.%E3%83%86%E3%82%B9%E3%83%88/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.html", g.get_url(o)
18
+ end
19
+
20
+ def test_get
21
+ r = Gohttp.get('https://example.com/index.html')
22
+ assert_kind_of Response, r
23
+ assert_equal '200 OK', r.status
24
+ assert_equal 200, r.status_code
25
+ assert_equal 'HTTP/1.1', r.proto
26
+ assert_equal 1270, r.size
27
+ assert_equal [], r.transfer_encoding
28
+ hdr = r.header
29
+ assert_kind_of Hash, hdr
30
+ assert_equal %w[max-age=604800], hdr["Cache-Control"]
31
+ assert_equal %w[text/html], hdr["Content-Type"]
32
+ b = r.body
33
+ assert_match /\A#<GoIO:\*http.bodyEOFSignal:0x\h+>/, b.to_s
34
+ assert_match /Example Domain/, b.read
35
+ assert_equal true, b.close
36
+ req = r.request
37
+ assert_equal 'GET', req.method
38
+ assert_equal 'HTTP/1.1', req.proto
39
+ assert_equal Hash[], req.header
40
+ assert_nil req.body
41
+ assert_equal 0, req.content_length
42
+ assert_equal [], req.transfer_encoding
43
+ assert_equal 'example.com', req.host
44
+ assert_equal '', req.remote_addr
45
+ assert_equal '', req.request_uri
46
+ end
47
+
48
+ def test_head
49
+ r = Gohttp.head('https://example.com/index.html')
50
+ assert_kind_of Response, r
51
+ assert_equal '200 OK', r.status
52
+ assert_equal 200, r.status_code
53
+ assert_equal 'HTTP/1.1', r.proto
54
+ assert_equal 1270, r.size
55
+ assert_equal [], r.transfer_encoding
56
+ hdr = r.header
57
+ assert_kind_of Hash, hdr
58
+ assert_equal %w[max-age=604800], hdr["Cache-Control"]
59
+ assert_equal %w[text/html], hdr["Content-Type"]
60
+ b = r.body
61
+ assert_match /\A#<GoIO:\*http.bodyEOFSignal>/, b.to_s
62
+ assert_match '', b.read
63
+ assert_equal true, b.close
64
+ req = r.request
65
+ assert_equal 'HEAD', req.method
66
+ assert_equal 'HTTP/1.1', req.proto
67
+ assert_equal Hash[], req.header
68
+ assert_nil req.body
69
+ assert_equal 0, req.content_length
70
+ assert_equal [], req.transfer_encoding
71
+ assert_equal 'example.com', req.host
72
+ assert_equal '', req.remote_addr
73
+ assert_equal '', req.request_uri
74
+ end
75
+
76
+ def test_head
77
+ r = Gohttp.post_form('http://nalsh.jp/env.cgi', {'foo' => 'bar'})
78
+ assert_kind_of Response, r
79
+ assert_equal '200 OK', r.status
80
+ assert_equal 200, r.status_code
81
+ assert_equal 'HTTP/1.1', r.proto
82
+ assert_equal -1, r.size
83
+ assert_equal %w[chunked], r.transfer_encoding
84
+ hdr = r.header
85
+ assert_kind_of Hash, hdr
86
+ assert_equal nil, hdr["Cache-Control"]
87
+ assert_equal %w[text/html], hdr["Content-Type"]
88
+ b = r.body
89
+ assert_match /\A#<GoIO:\*http.bodyEOFSignal:0x\h+>/, b.to_s
90
+ assert_match '', b.read
91
+ assert_equal true, b.close
92
+ req = r.request
93
+ assert_equal 'POST', req.method
94
+ assert_equal 'HTTP/1.1', req.proto
95
+ assert_equal Hash["Content-Type"=>["application/x-www-form-urlencoded"]], req.header
96
+ assert_match /\A#<GoIO:ioutil.nopCloser>\z/, req.body.to_s
97
+ assert_equal 7, req.content_length
98
+ assert_equal [], req.transfer_encoding
99
+ assert_equal 'nalsh.jp', req.host
100
+ assert_equal '', req.remote_addr
101
+ assert_equal '', req.request_uri
102
+ end
103
+ end
104
+
105
+ class TestGourl < Minitest::Test
106
+ def test_escape
107
+ assert_equal '%E3%81%82+%2B', Gourl.query_escape('あ +')
108
+ end
109
+
110
+ def test_escape
111
+ assert_equal 'あ ', Gourl.query_unescape('%E3%81%82%20+')
112
+ assert_raises(ArgumentError){ Gourl.query_unescape('%%81%82%20+') }
113
+ end
114
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gohttp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - NARUSE, Yui
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
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: rake
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
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: an http library with go.
84
+ email:
85
+ - naruse@airemix.jp
86
+ executables: []
87
+ extensions:
88
+ - ext/gohttp/extconf.rb
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - ext/gohttp/extconf.rb
97
+ - ext/gohttp/gohttp.go
98
+ - ext/gohttp/wrapper.go
99
+ - gohttp.gemspec
100
+ - lib/gohttp.rb
101
+ - lib/gohttp/version.rb
102
+ - test.rb
103
+ homepage: https://github.com/nurse/gohttp
104
+ licenses:
105
+ - BSD-2-Clause
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '2.0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.4.5
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: an http library with go.
127
+ test_files: []
128
+ has_rdoc: