grom_native 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Matt Rayner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,40 @@
1
+ .PHONY: build-and-test build install install-go install-ruby test test-go test-ruby check-built proto setup
2
+
3
+ build-and-test: install setup test
4
+
5
+ build:
6
+ @echo "-- Building library"
7
+ go build -buildmode=c-shared -o ./ext/gromnative.so ./ext/gromnative.go
8
+
9
+ install: install-go install-ruby
10
+
11
+ install-go:
12
+ @echo "-- Installing Go Dependencies"
13
+ dep ensure
14
+
15
+ install-ruby:
16
+ @echo "-- Install Ruby Dependencies"
17
+ bundle install
18
+
19
+ test: test-go test-ruby
20
+
21
+ test-go:
22
+ @echo "-- Testing library"
23
+ ginkgo ./ext/...
24
+
25
+ test-ruby: check-built
26
+ @echo "-- Testing gem"
27
+ bundle exec rake
28
+
29
+ check-built:
30
+ @echo "-- Checking for built library"
31
+ @[ -f ./ext/gromnative.so ] && echo "Lib found, not building" || make build
32
+
33
+ proto:
34
+ @echo "-- Building Protobuf files"
35
+ protowrap -I. --go_out `go env GOPATH`/src ./**/**/*.proto
36
+
37
+ setup:
38
+ @echo "-- Installing testing framework"
39
+ go get -u github.com/onsi/ginkgo/ginkgo
40
+ go get -u github.com/onsi/gomega/...
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # GromNative
2
+
3
+ ## Quick Start
4
+ ```bash
5
+ brew install protobuf ginkgo
6
+ make install
7
+ make test
8
+ ```
9
+
10
+
11
+ TODO: Delete this and the text above, and describe your gem
12
+
13
+ ## Installation
14
+
15
+ [![Go Report Card](https://goreportcard.com/badge/github.com/ukparliament/gromnative)](https://goreportcard.com/report/github.com/ukparliament/gromnative)
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'grom_native'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install GromNative
30
+
31
+ ## Usage
32
+
33
+ TODO: Write usage instructions here
34
+
35
+ ## Development
36
+
37
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
38
+
39
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
40
+
41
+ ## Contributing
42
+
43
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/GromNative. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
44
+
45
+ ## License
46
+
47
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
48
+
49
+ ## Code of Conduct
50
+
51
+ Everyone interacting in the GromNative project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/GromNative/blob/master/CODE_OF_CONDUCT.md).
52
+
53
+ ```bash
54
+ ./bin/console
55
+ require 'parliament/grom/decorator'; n = GromNative.fetch(uri: 'http://api.parliament.uk/query/person_by_id.nt?person_id=43RHonMf', filter: ['https://id.parliament.uk/schema/Person'], decorators: Parliament::Grom::Decorator).first
56
+ ```
57
+
58
+ ```bash
59
+ require 'parliament/grom/decorator'
60
+ require 'benchmark'
61
+
62
+ puts Benchmark.measure {
63
+ 10.times do
64
+ GromNative.fetch(uri: 'http://api.parliament.uk/query/person_by_id.nt?person_id=43RHonMf', filter: ['https://id.parliament.uk/schema/Person'], decorators: Parliament::Grom::Decorator).first
65
+ end
66
+ }
67
+
68
+ puts Benchmark.measure {
69
+ GromNative.fetch(uri: 'http://api.parliament.uk/query/person_index', filter: ['https://id.parliament.uk/schema/Person'], decorators: Parliament::Grom::Decorator)
70
+ }
71
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "grom_native"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/ext/gromnative.go ADDED
@@ -0,0 +1,82 @@
1
+ package main
2
+
3
+ import (
4
+ "C"
5
+ "encoding/json"
6
+ "fmt"
7
+ "github.com/ukparliament/gromnative/ext/net"
8
+ "github.com/ukparliament/gromnative/ext/processor"
9
+ . "github.com/ukparliament/gromnative/ext/types/net"
10
+ "log"
11
+ )
12
+
13
+ type Response struct {
14
+ StatementsBySubject map[string][]processor.Triple `json:"statementsBySubject"`
15
+ EdgesBySubject map[string]map[string][]string `json:"edgesBySubject"`
16
+ StatusCode int32 `json:"statusCode"`
17
+ Uri string `json:"uri"`
18
+ Err string `json:"error"`
19
+ }
20
+
21
+ func GetandProcess(uri string) (Response, error) {
22
+ // Placeholder response object
23
+ response := Response{ Uri: uri }
24
+
25
+ log.Printf("Requesting: %v\n", uri)
26
+
27
+ requestResponse, err := net.Get(&GetInput{Uri: uri})
28
+ if requestResponse.StatusCode != 0 {
29
+ response.StatusCode = requestResponse.StatusCode
30
+ }
31
+
32
+ if err != nil {
33
+ log.Printf("Error getting: %v\n", err)
34
+ response.Err = requestResponse.Error
35
+ return response, err
36
+ }
37
+
38
+ processedData, err := processor.Process(&processor.ProcessorInput{Body: requestResponse.Body})
39
+ if err != nil {
40
+ log.Printf("Error processing: %v\n", err)
41
+ response.Err = processedData.Error
42
+ return response, err
43
+ }
44
+
45
+ response.StatementsBySubject = processedData.StatementsBySubject
46
+ response.EdgesBySubject = processedData.EdgesBySubject
47
+
48
+ log.Println("Done")
49
+
50
+ return response, nil
51
+ }
52
+
53
+ func cStringConversion(response *Response) *C.char {
54
+ json, err := json.Marshal(response)
55
+ if err != nil {
56
+ return C.CString("{\"error\": \"error creating json for ruby\"}")
57
+ }
58
+
59
+ return C.CString(string(json))
60
+ }
61
+
62
+ //export get
63
+ func get(data *C.char) *C.char {
64
+ uri := C.GoString(data)
65
+ response, err := GetandProcess(uri)
66
+ if err != nil {
67
+ errorResponse := &Response{ Err: fmt.Sprintf("Error getting data: %v\n", err) }
68
+ log.Println(errorResponse.Err)
69
+ return cStringConversion(errorResponse)
70
+ }
71
+
72
+ responseJson, err := json.Marshal(response)
73
+ if err != nil {
74
+ errorResponse := &Response{ Err: fmt.Sprintf("Error marshalling data: %v\n", err) }
75
+ log.Println(errorResponse.Err)
76
+ return cStringConversion(errorResponse)
77
+ }
78
+
79
+ return C.CString(string(responseJson))
80
+ }
81
+
82
+ func main() {}
@@ -0,0 +1,150 @@
1
+ package main
2
+
3
+ import (
4
+ . "github.com/onsi/ginkgo"
5
+ . "github.com/onsi/gomega"
6
+ "github.com/ukparliament/gromnative/ext/processor"
7
+ "gopkg.in/jarcoal/httpmock.v1"
8
+ "io/ioutil"
9
+ "log"
10
+ "testing"
11
+ )
12
+
13
+ func TestProcessor(t *testing.T) {
14
+ log.SetOutput(ioutil.Discard)
15
+ RegisterFailHandler(Fail)
16
+ RunSpecs(t, "gromnative Suite")
17
+ }
18
+
19
+ var _ = BeforeSuite(func() {
20
+ // block all HTTP requests
21
+ httpmock.Activate()
22
+ })
23
+
24
+ var _ = BeforeEach(func() {
25
+ // remove any mocks
26
+ httpmock.Reset()
27
+ })
28
+
29
+ var _ = AfterSuite(func() {
30
+ httpmock.DeactivateAndReset()
31
+ })
32
+
33
+ var _ = Describe("gromnative", func() {
34
+ Describe("GetandProcess", func() {
35
+ Context("with expected data", func() {
36
+ BeforeEach(func() {
37
+ fixture, _ := ioutil.ReadFile("../spec/fixtures/one_edge.nt")
38
+
39
+ httpmock.RegisterResponder("GET", "https://api.parliament.uk/query/person_by_id?person_id=43RHonMf",
40
+ httpmock.NewStringResponder(200, string(fixture)))
41
+ })
42
+
43
+ It("returns the expected data", func() {
44
+ statementsBySubject := make(map[string][]processor.Triple)
45
+ statementsBySubject["https://id.parliament.uk/43RHonMf"] = append(
46
+ statementsBySubject["https://id.parliament.uk/43RHonMf"],
47
+ processor.Triple {
48
+ Subject: "https://id.parliament.uk/43RHonMf",
49
+ Predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
50
+ Object: "<https://id.parliament.uk/schema/Person>",
51
+ },
52
+ processor.Triple {
53
+ Subject: "https://id.parliament.uk/43RHonMf",
54
+ Predicate: "https://id.parliament.uk/schema/personGivenName",
55
+ Object: "\"Diane\"^^<xsd:string>",
56
+ },
57
+ processor.Triple {
58
+ Subject: "https://id.parliament.uk/43RHonMf",
59
+ Predicate: "https://id.parliament.uk/schema/personOtherNames",
60
+ Object: "\"Julie\"^^<xsd:string>",
61
+ },
62
+ processor.Triple {
63
+ Subject: "https://id.parliament.uk/43RHonMf",
64
+ Predicate: "https://id.parliament.uk/schema/personFamilyName",
65
+ Object: "\"Abbott\"^^<xsd:string>",
66
+ },
67
+ processor.Triple {
68
+ Subject: "https://id.parliament.uk/43RHonMf",
69
+ Predicate: "http://example.com/F31CBD81AD8343898B49DC65743F0BDF",
70
+ Object: "\"Ms Diane Abbott\"^^<xsd:string>",
71
+ },
72
+ processor.Triple {
73
+ Subject: "https://id.parliament.uk/43RHonMf",
74
+ Predicate: "http://example.com/D79B0BAC513C4A9A87C9D5AFF1FC632F",
75
+ Object: "\"Rt Hon Diane Abbott MP\"^^<xsd:string>",
76
+ },
77
+ processor.Triple {
78
+ Subject: "https://id.parliament.uk/43RHonMf",
79
+ Predicate: "https://id.parliament.uk/schema/Test",
80
+ Object: "<https://id.parliament.uk/12345678>",
81
+ })
82
+ edgesBySubject := make(map[string]map[string][]string)
83
+ edgesBySubject["https://id.parliament.uk/43RHonMf"] = make(map[string][]string)
84
+ edgesBySubject["https://id.parliament.uk/43RHonMf"]["Test"] = append(
85
+ edgesBySubject["https://id.parliament.uk/43RHonMf"]["Test"],
86
+ "https://id.parliament.uk/12345678")
87
+
88
+ expected := Response{
89
+ StatementsBySubject: statementsBySubject,
90
+ EdgesBySubject: edgesBySubject,
91
+ StatusCode: 200,
92
+ Uri: "https://api.parliament.uk/query/person_by_id?person_id=43RHonMf",
93
+ Err: "",
94
+ }
95
+
96
+ res, err := GetandProcess("https://api.parliament.uk/query/person_by_id?person_id=43RHonMf")
97
+
98
+ Expect(res).To(Equal(expected))
99
+ Expect(err).NotTo(HaveOccurred())
100
+ })
101
+ })
102
+
103
+ Context("with an error getting", func() {
104
+ BeforeEach(func() {
105
+ httpmock.DeactivateAndReset()
106
+ })
107
+
108
+ AfterEach(func() {
109
+ httpmock.Activate()
110
+ })
111
+
112
+ It("returns the expected data", func() {
113
+ expected := Response{
114
+ StatementsBySubject: nil,
115
+ EdgesBySubject: nil,
116
+ StatusCode: 0,
117
+ Uri: "foo://a_broken.url",
118
+ Err: "Get foo://a_broken.url: unsupported protocol scheme \"foo\"",
119
+ }
120
+
121
+ res, err := GetandProcess("foo://a_broken.url")
122
+
123
+ Expect(res).To(Equal(expected))
124
+ Expect(err.Error()).To(Equal("Get foo://a_broken.url: unsupported protocol scheme \"foo\""))
125
+ })
126
+ })
127
+
128
+ Context("with an error processing", func() {
129
+ BeforeEach(func() {
130
+ httpmock.RegisterResponder("GET", "https://api.parliament.uk/query/person_by_id?person_id=43RHonMf",
131
+ httpmock.NewStringResponder(200, "{\"error\":\"Definitely not Triples\"}"))
132
+ })
133
+
134
+ It("returns the expected data", func() {
135
+ expected := Response{
136
+ StatementsBySubject: nil,
137
+ EdgesBySubject: nil,
138
+ StatusCode: 200,
139
+ Uri: "https://api.parliament.uk/query/person_by_id?person_id=43RHonMf",
140
+ Err: "lenient parsing: line 1: invalid subject in {\"error\":\"Definitely not Triples\"}",
141
+ }
142
+
143
+ res, err := GetandProcess("https://api.parliament.uk/query/person_by_id?person_id=43RHonMf")
144
+
145
+ Expect(res).To(Equal(expected))
146
+ Expect(err.Error()).To(Equal("lenient parsing: line 1: invalid subject in {\"error\":\"Definitely not Triples\"}"))
147
+ })
148
+ })
149
+ })
150
+ })
data/ext/net/net.go ADDED
@@ -0,0 +1,63 @@
1
+ package net
2
+
3
+ import (
4
+ "errors"
5
+ "fmt"
6
+ netType "github.com/ukparliament/gromnative/ext/types/net"
7
+ "io/ioutil"
8
+ "net/http"
9
+ )
10
+
11
+ func Get(input *netType.GetInput) (*netType.GetOutput, error) {
12
+ output := &netType.GetOutput{Uri: input.Uri}
13
+
14
+ // Build a new get request object
15
+ request, err := http.NewRequest("GET", input.Uri, nil)
16
+ if err != nil {
17
+ output.Error = err.Error()
18
+ return output, err
19
+ }
20
+
21
+ // Add any header objects to our request
22
+ for i := 0; i < len(input.Headers); i++ {
23
+ request.Header.Add(input.Headers[i].Key, input.Headers[i].Value)
24
+ }
25
+
26
+ // Perform our request
27
+ client := http.Client{}
28
+ resp, err := client.Do(request)
29
+ if resp != nil {
30
+ defer resp.Body.Close()
31
+ }
32
+
33
+ if err != nil {
34
+ output.Error = err.Error()
35
+ return output, err
36
+ }
37
+
38
+ // Store the response code
39
+ if resp.StatusCode != 0 {
40
+ output.StatusCode = int32(resp.StatusCode)
41
+ }
42
+
43
+ // Read the body into a []byte
44
+ body, err := ioutil.ReadAll(resp.Body)
45
+
46
+ if err != nil {
47
+ errorMessage := fmt.Sprintf("Error reading body from %v: %v", input.Uri, err)
48
+ output.Error = errorMessage
49
+ return output, err
50
+ }
51
+
52
+ output.Body = body
53
+
54
+ // Handle non-200 responses
55
+ if resp.StatusCode != 200 {
56
+ errorMessage := fmt.Sprintf("Received %v status code from %v: %s", resp.StatusCode, input.Uri, body)
57
+
58
+ output.Error = errorMessage
59
+ return output, errors.New(errorMessage)
60
+ }
61
+
62
+ return output, err
63
+ }