pupa 0.0.13 → 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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +17 -0
- data/lib/pupa.rb +5 -8
- data/lib/pupa/errors.rb +4 -0
- data/lib/pupa/models/model.rb +5 -5
- data/lib/pupa/models/organization.rb +10 -6
- data/lib/pupa/models/person.rb +10 -6
- data/lib/pupa/processor.rb +14 -15
- data/lib/pupa/processor/connection.rb +26 -0
- data/lib/pupa/processor/connection_adapters/mongodb_adapter.rb +92 -0
- data/lib/pupa/processor/connection_adapters/postgresql_adapter.rb +116 -0
- data/lib/pupa/processor/document_store.rb +3 -0
- data/lib/pupa/processor/middleware/raise_error.rb +1 -0
- data/lib/pupa/refinements/faraday_middleware.rb +1 -1
- data/lib/pupa/runner.rb +14 -21
- data/lib/pupa/version.rb +1 -1
- data/pupa.gemspec +3 -2
- data/schemas/popolo/contact_detail.json +10 -0
- data/schemas/popolo/membership.json +29 -9
- data/schemas/popolo/organization.json +9 -2
- data/schemas/popolo/other_name.json +24 -0
- data/schemas/popolo/person.json +6 -3
- data/schemas/popolo/post.json +16 -2
- data/spec/models/model_spec.rb +1 -1
- data/spec/processor/connection_adapters/mongodb_adapter_spec.rb +61 -0
- data/spec/processor/connection_adapters/postgresql_adapter_spec.rb +70 -0
- data/spec/processor/connection_spec.rb +15 -0
- data/spec/processor/middleware/parse_json_spec.rb +90 -0
- data/spec/processor_spec.rb +9 -10
- data/spec/spec_helper.rb +0 -10
- metadata +83 -75
- data/lib/pupa/processor/persistence.rb +0 -85
- data/spec/cassettes/31ac91ccad069eefc07d96cfbe66fa66c1b41fcf.yml +0 -56
- data/spec/cassettes/4ff54d737afb5d693653752d7bf234a405a80172.yml +0 -48
- data/spec/cassettes/898049a22e6ca51dfa2510d9e0e0207a5c396524.yml +0 -54
- data/spec/cassettes/ce69ff734ce852d2bfaa482bbf55d7ffb4762e87.yml +0 -26
- data/spec/cassettes/da629b01e0836deda8a5540a4e6a08783dd7aef9.yml +0 -46
- data/spec/cassettes/e398f35bea86b3d4c87a6934bae1eb7fca8744f9.yml +0 -26
- data/spec/cassettes/f861172f1df3bdb2052af5451f9922699d574b77.yml +0 -62
- data/spec/processor/persistence_spec.rb +0 -51
@@ -1,85 +0,0 @@
|
|
1
|
-
module Pupa
|
2
|
-
class Processor
|
3
|
-
# A proxy class to save plain old Ruby objects to MongoDB.
|
4
|
-
class Persistence
|
5
|
-
# @param [Object] object an object
|
6
|
-
def initialize(object)
|
7
|
-
@object = object
|
8
|
-
end
|
9
|
-
|
10
|
-
# Finds a document matching the selection criteria.
|
11
|
-
#
|
12
|
-
# The selection criteria *must* set a `_type` key in order to determine
|
13
|
-
# the collection to query.
|
14
|
-
#
|
15
|
-
# @param [Hash] selector the selection criteria
|
16
|
-
# @return [Hash,nil] the matched document, or nil
|
17
|
-
# @raises [Pupa::Errors::TooManyMatches] if multiple documents are found
|
18
|
-
def self.find(selector)
|
19
|
-
collection_name = collection_name_from_class_name(selector[:_type].camelize)
|
20
|
-
query = Pupa.session[collection_name].find(selector)
|
21
|
-
case query.count
|
22
|
-
when 0
|
23
|
-
nil
|
24
|
-
when 1
|
25
|
-
query.first
|
26
|
-
else
|
27
|
-
raise Errors::TooManyMatches, "selector matches multiple documents during find: #{collection_name} #{JSON.dump(selector)}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Inserts or replaces a document in MongoDB.
|
32
|
-
#
|
33
|
-
# @return [Array] whether the object was inserted and the object's database ID
|
34
|
-
# @raises [Pupa::Errors::TooManyMatches] if multiple documents would be updated
|
35
|
-
def save
|
36
|
-
selector = @object.fingerprint
|
37
|
-
query = collection.find(selector)
|
38
|
-
|
39
|
-
# Run query before callbacks to avoid e.g. timestamps in the selector.
|
40
|
-
case query.count
|
41
|
-
when 0
|
42
|
-
@object.run_callbacks(:save) do
|
43
|
-
@object.run_callbacks(:create) do
|
44
|
-
collection.insert(@object.to_h(persist: true))
|
45
|
-
[true, @object._id.to_s]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
when 1
|
49
|
-
# Make the document available to the callbacks.
|
50
|
-
# @see https://github.com/opennorth/pupa-ruby/issues/17
|
51
|
-
@object.document = query.first
|
52
|
-
@object.run_callbacks(:save) do
|
53
|
-
query.update(@object.to_h(persist: true).except(:_id))
|
54
|
-
[false, @object.document['_id'].to_s]
|
55
|
-
end
|
56
|
-
else
|
57
|
-
raise Errors::TooManyMatches, "selector matches multiple documents during save: #{collection_name} #{JSON.dump(selector)} for #{@object._id}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
# Returns the name of the collection in which to save the object.
|
64
|
-
#
|
65
|
-
# @return [String] the name of the object's class
|
66
|
-
def self.collection_name_from_class_name(class_name)
|
67
|
-
class_name.demodulize.underscore.pluralize.to_sym
|
68
|
-
end
|
69
|
-
|
70
|
-
# Returns the name of the collection in which to save the object.
|
71
|
-
#
|
72
|
-
# @return [String] the name of the collection in which to save the object
|
73
|
-
def collection_name
|
74
|
-
self.class.collection_name_from_class_name(@object.class.to_s)
|
75
|
-
end
|
76
|
-
|
77
|
-
# Returns the collection in which to save the object.
|
78
|
-
#
|
79
|
-
# @return [Moped::Collection] the collection in which to save the object
|
80
|
-
def collection
|
81
|
-
Pupa.session[collection_name]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: post
|
5
|
-
uri: http://httpbin.org/post
|
6
|
-
body:
|
7
|
-
encoding: UTF-8
|
8
|
-
string: foo=bar
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.8
|
12
|
-
Content-Type:
|
13
|
-
- application/x-www-form-urlencoded
|
14
|
-
response:
|
15
|
-
status:
|
16
|
-
code: 200
|
17
|
-
message:
|
18
|
-
headers:
|
19
|
-
access-control-allow-origin:
|
20
|
-
- '*'
|
21
|
-
content-type:
|
22
|
-
- application/json
|
23
|
-
date:
|
24
|
-
- Sun, 15 Sep 2013 22:37:07 GMT
|
25
|
-
server:
|
26
|
-
- gunicorn/0.17.4
|
27
|
-
content-length:
|
28
|
-
- '439'
|
29
|
-
connection:
|
30
|
-
- Close
|
31
|
-
body:
|
32
|
-
encoding: UTF-8
|
33
|
-
string: |-
|
34
|
-
{
|
35
|
-
"args": {},
|
36
|
-
"data": "",
|
37
|
-
"json": null,
|
38
|
-
"origin": "70.49.74.123",
|
39
|
-
"files": {},
|
40
|
-
"form": {
|
41
|
-
"foo": "bar"
|
42
|
-
},
|
43
|
-
"headers": {
|
44
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
45
|
-
"User-Agent": "Faraday v0.8.8",
|
46
|
-
"Connection": "close",
|
47
|
-
"Host": "httpbin.org",
|
48
|
-
"Content-Length": "7",
|
49
|
-
"Accept": "*/*",
|
50
|
-
"Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
|
51
|
-
},
|
52
|
-
"url": "http://httpbin.org/post"
|
53
|
-
}
|
54
|
-
http_version:
|
55
|
-
recorded_at: Sun, 15 Sep 2013 22:37:07 GMT
|
56
|
-
recorded_with: VCR 2.5.0
|
@@ -1,48 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: get
|
5
|
-
uri: http://httpbin.org/get?foo=bar
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.8
|
12
|
-
response:
|
13
|
-
status:
|
14
|
-
code: 200
|
15
|
-
message:
|
16
|
-
headers:
|
17
|
-
access-control-allow-origin:
|
18
|
-
- '*'
|
19
|
-
content-type:
|
20
|
-
- application/json
|
21
|
-
date:
|
22
|
-
- Sun, 15 Sep 2013 22:37:07 GMT
|
23
|
-
server:
|
24
|
-
- gunicorn/0.17.4
|
25
|
-
content-length:
|
26
|
-
- '303'
|
27
|
-
connection:
|
28
|
-
- Close
|
29
|
-
body:
|
30
|
-
encoding: UTF-8
|
31
|
-
string: |-
|
32
|
-
{
|
33
|
-
"origin": "70.49.74.123",
|
34
|
-
"url": "http://httpbin.org/get?foo=bar",
|
35
|
-
"args": {
|
36
|
-
"foo": "bar"
|
37
|
-
},
|
38
|
-
"headers": {
|
39
|
-
"Accept": "*/*",
|
40
|
-
"Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
|
41
|
-
"Host": "httpbin.org",
|
42
|
-
"User-Agent": "Faraday v0.8.8",
|
43
|
-
"Connection": "close"
|
44
|
-
}
|
45
|
-
}
|
46
|
-
http_version:
|
47
|
-
recorded_at: Sun, 15 Sep 2013 22:37:07 GMT
|
48
|
-
recorded_with: VCR 2.5.0
|
@@ -1,54 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: post
|
5
|
-
uri: http://httpbin.org/post
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.8
|
12
|
-
Content-Type:
|
13
|
-
- application/x-www-form-urlencoded
|
14
|
-
response:
|
15
|
-
status:
|
16
|
-
code: 200
|
17
|
-
message:
|
18
|
-
headers:
|
19
|
-
access-control-allow-origin:
|
20
|
-
- '*'
|
21
|
-
content-type:
|
22
|
-
- application/json
|
23
|
-
date:
|
24
|
-
- Sun, 15 Sep 2013 22:37:07 GMT
|
25
|
-
server:
|
26
|
-
- gunicorn/0.17.4
|
27
|
-
content-length:
|
28
|
-
- '419'
|
29
|
-
connection:
|
30
|
-
- Close
|
31
|
-
body:
|
32
|
-
encoding: UTF-8
|
33
|
-
string: |-
|
34
|
-
{
|
35
|
-
"json": null,
|
36
|
-
"form": {},
|
37
|
-
"data": "",
|
38
|
-
"files": {},
|
39
|
-
"headers": {
|
40
|
-
"Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
|
41
|
-
"Content-Length": "0",
|
42
|
-
"User-Agent": "Faraday v0.8.8",
|
43
|
-
"Accept": "*/*",
|
44
|
-
"Connection": "close",
|
45
|
-
"Host": "httpbin.org",
|
46
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
47
|
-
},
|
48
|
-
"url": "http://httpbin.org/post",
|
49
|
-
"args": {},
|
50
|
-
"origin": "70.49.74.123"
|
51
|
-
}
|
52
|
-
http_version:
|
53
|
-
recorded_at: Sun, 15 Sep 2013 22:37:07 GMT
|
54
|
-
recorded_with: VCR 2.5.0
|
@@ -1,26 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: post
|
5
|
-
uri: http:/hello
|
6
|
-
body:
|
7
|
-
encoding: UTF-8
|
8
|
-
string: foo=bar
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.8
|
12
|
-
Accept:
|
13
|
-
- text/html
|
14
|
-
response:
|
15
|
-
status:
|
16
|
-
code: 200
|
17
|
-
message:
|
18
|
-
headers:
|
19
|
-
Content-Type:
|
20
|
-
- text/html
|
21
|
-
body:
|
22
|
-
encoding: UTF-8
|
23
|
-
string: hello
|
24
|
-
http_version:
|
25
|
-
recorded_at: Sun, 15 Sep 2013 22:37:06 GMT
|
26
|
-
recorded_with: VCR 2.5.0
|
@@ -1,46 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: get
|
5
|
-
uri: http://httpbin.org/get
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.8
|
12
|
-
response:
|
13
|
-
status:
|
14
|
-
code: 200
|
15
|
-
message:
|
16
|
-
headers:
|
17
|
-
access-control-allow-origin:
|
18
|
-
- '*'
|
19
|
-
content-type:
|
20
|
-
- application/json
|
21
|
-
date:
|
22
|
-
- Sun, 15 Sep 2013 22:37:07 GMT
|
23
|
-
server:
|
24
|
-
- gunicorn/0.17.4
|
25
|
-
content-length:
|
26
|
-
- '275'
|
27
|
-
connection:
|
28
|
-
- Close
|
29
|
-
body:
|
30
|
-
encoding: UTF-8
|
31
|
-
string: |-
|
32
|
-
{
|
33
|
-
"url": "http://httpbin.org/get",
|
34
|
-
"args": {},
|
35
|
-
"origin": "70.49.74.123",
|
36
|
-
"headers": {
|
37
|
-
"Accept": "*/*",
|
38
|
-
"User-Agent": "Faraday v0.8.8",
|
39
|
-
"Connection": "close",
|
40
|
-
"Host": "httpbin.org",
|
41
|
-
"Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
|
42
|
-
}
|
43
|
-
}
|
44
|
-
http_version:
|
45
|
-
recorded_at: Sun, 15 Sep 2013 22:37:07 GMT
|
46
|
-
recorded_with: VCR 2.5.0
|
@@ -1,26 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: get
|
5
|
-
uri: http:/hello
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.8
|
12
|
-
Accept:
|
13
|
-
- text/html
|
14
|
-
response:
|
15
|
-
status:
|
16
|
-
code: 200
|
17
|
-
message:
|
18
|
-
headers:
|
19
|
-
Content-Type:
|
20
|
-
- text/html
|
21
|
-
body:
|
22
|
-
encoding: UTF-8
|
23
|
-
string: hello
|
24
|
-
http_version:
|
25
|
-
recorded_at: Sun, 15 Sep 2013 22:37:06 GMT
|
26
|
-
recorded_with: VCR 2.5.0
|
@@ -1,62 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: get
|
5
|
-
uri: http://example.com/
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.8
|
12
|
-
response:
|
13
|
-
status:
|
14
|
-
code: 200
|
15
|
-
message:
|
16
|
-
headers:
|
17
|
-
accept-ranges:
|
18
|
-
- bytes
|
19
|
-
cache-control:
|
20
|
-
- max-age=604800
|
21
|
-
content-type:
|
22
|
-
- text/html
|
23
|
-
date:
|
24
|
-
- Fri, 27 Sep 2013 00:31:23 GMT
|
25
|
-
etag:
|
26
|
-
- '"3012602696"'
|
27
|
-
expires:
|
28
|
-
- Fri, 04 Oct 2013 00:31:23 GMT
|
29
|
-
last-modified:
|
30
|
-
- Fri, 09 Aug 2013 23:54:35 GMT
|
31
|
-
server:
|
32
|
-
- ECS (mdw/13C6)
|
33
|
-
x-cache:
|
34
|
-
- HIT
|
35
|
-
x-ec-custom-error:
|
36
|
-
- '1'
|
37
|
-
content-length:
|
38
|
-
- '1270'
|
39
|
-
connection:
|
40
|
-
- close
|
41
|
-
body:
|
42
|
-
encoding: UTF-8
|
43
|
-
string: "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n
|
44
|
-
\ <meta charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html;
|
45
|
-
charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width,
|
46
|
-
initial-scale=1\" />\n <style type=\"text/css\">\n body {\n background-color:
|
47
|
-
#f0f0f2;\n margin: 0;\n padding: 0;\n font-family: \"Open
|
48
|
-
Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n
|
49
|
-
\ div {\n width: 600px;\n margin: 5em auto;\n padding:
|
50
|
-
50px;\n background-color: #fff;\n border-radius: 1em;\n }\n
|
51
|
-
\ a:link, a:visited {\n color: #38488f;\n text-decoration:
|
52
|
-
none;\n }\n @media (max-width: 700px) {\n body {\n background-color:
|
53
|
-
#fff;\n }\n div {\n width: auto;\n margin:
|
54
|
-
0 auto;\n border-radius: 0;\n padding: 1em;\n }\n
|
55
|
-
\ }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</h1>\n
|
56
|
-
\ <p>This domain is established to be used for illustrative examples in
|
57
|
-
documents. You may use this\n domain in examples without prior coordination
|
58
|
-
or asking for permission.</p>\n <p><a href=\"http://www.iana.org/domains/example\">More
|
59
|
-
information...</a></p>\n</div>\n</body>\n</html>\n"
|
60
|
-
http_version:
|
61
|
-
recorded_at: Fri, 27 Sep 2013 00:31:23 GMT
|
62
|
-
recorded_with: VCR 2.5.0
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
-
|
3
|
-
describe Pupa::Processor::Persistence do
|
4
|
-
def _type
|
5
|
-
if testing_python_compatibility?
|
6
|
-
'person'
|
7
|
-
else
|
8
|
-
'pupa/person'
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
before :all do
|
13
|
-
Pupa.session = Moped::Session.new(['localhost:27017'], database: 'pupa_test')
|
14
|
-
Pupa.session.collections.each(&:drop)
|
15
|
-
|
16
|
-
Pupa::Processor::Persistence.new(Pupa::Person.new(_id: 'existing', name: 'existing', email: 'existing@example.com')).save
|
17
|
-
|
18
|
-
Pupa.session[:people].insert(_type: 'pupa/person', name: 'non-unique')
|
19
|
-
Pupa.session[:people].insert(_type: 'pupa/person', name: 'non-unique')
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '.find' do
|
23
|
-
it 'should return nil if no matches' do
|
24
|
-
Pupa::Processor::Persistence.find(_type: _type, name: 'nonexistent').should == nil
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should return a document if one match' do
|
28
|
-
Pupa::Processor::Persistence.find(_type: _type, name: 'existing').should be_a(Hash)
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should raise an error if many matches' do
|
32
|
-
expect{Pupa::Processor::Persistence.find(_type: 'pupa/person', name: 'non-unique')}.to raise_error(Pupa::Errors::TooManyMatches)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
describe '#save' do
|
37
|
-
it 'should insert a document if no matches' do
|
38
|
-
Pupa::Processor::Persistence.new(Pupa::Person.new(_id: 'new', name: 'new', email: 'new@example.com')).save.should == [true, 'new']
|
39
|
-
Pupa::Processor::Persistence.find(_type: _type, name: 'new')['email'].should == 'new@example.com'
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'should update a document if one match' do
|
43
|
-
Pupa::Processor::Persistence.new(Pupa::Person.new(_id: 'changed', name: 'existing', email: 'changed@example.com')).save.should == [false, 'existing']
|
44
|
-
Pupa::Processor::Persistence.find(_type: _type, name: 'existing')['email'].should == 'changed@example.com'
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'should raise an error if many matches' do
|
48
|
-
expect{Pupa::Processor::Persistence.new(Pupa::Person.new(name: 'non-unique')).save}.to raise_error(Pupa::Errors::TooManyMatches)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|