rsbe-client 0.5.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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/GETTING-STARTED.md +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +73 -0
- data/Rakefile +11 -0
- data/TODO.md +38 -0
- data/lib/rsbe/client.rb +50 -0
- data/lib/rsbe/client/base.rb +140 -0
- data/lib/rsbe/client/collection.rb +84 -0
- data/lib/rsbe/client/connection.rb +24 -0
- data/lib/rsbe/client/method_not_implemented_error.rb +6 -0
- data/lib/rsbe/client/not_found_error.rb +6 -0
- data/lib/rsbe/client/partner.rb +82 -0
- data/lib/rsbe/client/provider.rb +47 -0
- data/lib/rsbe/client/se.rb +97 -0
- data/lib/rsbe/client/search.rb +80 -0
- data/lib/rsbe/client/search_results.rb +41 -0
- data/lib/rsbe/client/unrecognized_resource_error.rb +6 -0
- data/lib/rsbe/client/version.rb +5 -0
- data/lib/rsbe/client/wrong_origin_error.rb +6 -0
- data/rsbe-client.gemspec +30 -0
- data/spec/fixtures/partners/partners_all.json +1 -0
- data/spec/fixtures/partners/partners_none.json +1 -0
- data/spec/rsbe/client/base_spec.rb +10 -0
- data/spec/rsbe/client/collection_spec.rb +186 -0
- data/spec/rsbe/client/connection_spec.rb +20 -0
- data/spec/rsbe/client/partner_spec.rb +185 -0
- data/spec/rsbe/client/provider_spec.rb +122 -0
- data/spec/rsbe/client/se_spec.rb +273 -0
- data/spec/rsbe/client/search_results_spec.rb +140 -0
- data/spec/rsbe/client/search_spec.rb +74 -0
- data/spec/rsbe/client_spec.rb +52 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/vcr_cassettes/client/find_collection.yml +53 -0
- data/spec/vcr_cassettes/client/find_partner.yml +52 -0
- data/spec/vcr_cassettes/client/find_provider.yml +52 -0
- data/spec/vcr_cassettes/client/find_se.yml +53 -0
- data/spec/vcr_cassettes/collection/find-existing.yml +53 -0
- data/spec/vcr_cassettes/collection/find-non_existent.yml +50 -0
- data/spec/vcr_cassettes/collection/lazy-eval-dne.yml +285 -0
- data/spec/vcr_cassettes/collection/lazy-eval-exists.yml +53 -0
- data/spec/vcr_cassettes/collection/save-create-known-id.yml +103 -0
- data/spec/vcr_cassettes/collection/save-create-unknown-id.yml +56 -0
- data/spec/vcr_cassettes/collection/save-invalid.yml +143 -0
- data/spec/vcr_cassettes/collection/save-update-valid.yml +99 -0
- data/spec/vcr_cassettes/partner/all.yml +300 -0
- data/spec/vcr_cassettes/partner/dne-with-id.yml +238 -0
- data/spec/vcr_cassettes/partner/find-existing.yml +52 -0
- data/spec/vcr_cassettes/partner/find-non_existent.yml +50 -0
- data/spec/vcr_cassettes/partner/lazy-eval-exists.yml +53 -0
- data/spec/vcr_cassettes/partner/save-create-known-id.yml +101 -0
- data/spec/vcr_cassettes/partner/save-create-unknown-id.yml +54 -0
- data/spec/vcr_cassettes/partner/save-invalid.yml +177 -0
- data/spec/vcr_cassettes/partner/save-unknown-id.yml +54 -0
- data/spec/vcr_cassettes/partner/save-update-valid.yml +98 -0
- data/spec/vcr_cassettes/partner/with-collections.yml +203 -0
- data/spec/vcr_cassettes/partner/without-collections.yml +101 -0
- data/spec/vcr_cassettes/provider/all.yml +248 -0
- data/spec/vcr_cassettes/provider/find-existing.yml +52 -0
- data/spec/vcr_cassettes/provider/find-non_existent.yml +50 -0
- data/spec/vcr_cassettes/provider/save-create-known-id.yml +101 -0
- data/spec/vcr_cassettes/provider/save-create-unknown-id.yml +54 -0
- data/spec/vcr_cassettes/provider/save-invalid.yml +178 -0
- data/spec/vcr_cassettes/provider/save-update-valid.yml +144 -0
- data/spec/vcr_cassettes/se/find-existing.yml +53 -0
- data/spec/vcr_cassettes/se/find-non_existent.yml +50 -0
- data/spec/vcr_cassettes/se/lazy-eval-exists.yml +52 -0
- data/spec/vcr_cassettes/se/save-create-known-id.yml +146 -0
- data/spec/vcr_cassettes/se/save-create-unknown-id.yml +56 -0
- data/spec/vcr_cassettes/se/save-invalid.yml +305 -0
- data/spec/vcr_cassettes/se/save-update-valid.yml +99 -0
- data/spec/vcr_cassettes/se/search-malformed-uuid.yml +54 -0
- data/spec/vcr_cassettes/se/search-with-existing-se.yml +52 -0
- data/spec/vcr_cassettes/se/search-with-missing-se.yml +52 -0
- data/spec/vcr_cassettes/search/search-with-existing-se.yml +52 -0
- data/spec/vcr_cassettes/search_results/no-results.yml +52 -0
- data/spec/vcr_cassettes/search_results/search-by-digi_id.yml +101 -0
- data/spec/vcr_cassettes/search_results/search-by-step.yml +201 -0
- metadata +307 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Rsbe
|
4
|
+
module Client
|
5
|
+
class Connection
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@conn, :get, :put, :post, :delete, :patch
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@user = ENV['RSBE_USER'] || 'foo'
|
11
|
+
@password = ENV['RSBE_PASSWORD'] || 'bar'
|
12
|
+
@url = ENV['RSBE_URL'] || 'http://localhost:3000'
|
13
|
+
@conn = Faraday.new(url: @url) do |faraday|
|
14
|
+
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
15
|
+
end
|
16
|
+
@conn.basic_auth(@user, @password)
|
17
|
+
end
|
18
|
+
|
19
|
+
def same_origin?(url)
|
20
|
+
(url =~ /\A#{@url}/) ? true : false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module Rsbe
|
4
|
+
module Client
|
5
|
+
# Class simplifies interaction with RSBE Partner resources
|
6
|
+
class Partner < Base
|
7
|
+
def self.base_path
|
8
|
+
super + '/partners'
|
9
|
+
end
|
10
|
+
|
11
|
+
# implementation objectives:
|
12
|
+
# - expose attributes via standard setter/getter methods
|
13
|
+
# - create getters for all Read-Only (RO) attributes
|
14
|
+
# - create setters only for Read/Write (RW) attributes
|
15
|
+
# - use hash for internal representation to simplify passing
|
16
|
+
# data back and forth to back end app
|
17
|
+
|
18
|
+
def self.rw_attrs
|
19
|
+
[:id, :code, :name, :rel_path]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.ro_attrs
|
23
|
+
[:created_at, :updated_at, :lock_version]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.all_attrs
|
27
|
+
rw_attrs + ro_attrs
|
28
|
+
end
|
29
|
+
|
30
|
+
# define setter methods for RW attributes
|
31
|
+
rw_attrs.each { |m| define_method("#{m}=") {|v| @hash[m] = v} }
|
32
|
+
|
33
|
+
# define getter methods for ALL attributes
|
34
|
+
# all_attrs.each { |m| define_method("#{m}") { @hash[m]} }
|
35
|
+
all_attrs.each do |m|
|
36
|
+
define_method("#{m}") do
|
37
|
+
@hash[m] || begin
|
38
|
+
# only fetch if Partner has a known id
|
39
|
+
if @hash[:id]
|
40
|
+
# TODO: CLEAN THIS UP
|
41
|
+
# This works currently because when a 404 is
|
42
|
+
# returned there is nothing in the response
|
43
|
+
# hash that matches the resource attributes,
|
44
|
+
# but relying on this behavior seems very
|
45
|
+
# brittle. Additionally, for every attribute
|
46
|
+
# queried, a GET operation is performed.
|
47
|
+
# Should store the object lifecycle state,
|
48
|
+
# e.g.,
|
49
|
+
# - new, no ID, no matching resource in RSBE: don't query RSBE
|
50
|
+
# - new, ID assigned, but not yet in RSBE: don't query RSBE
|
51
|
+
# - existing, partially populated,
|
52
|
+
# not fully updated with RSBE values: query RSBE
|
53
|
+
# - existing, fully populated with data from RSBE
|
54
|
+
# - existing, local modifications, not persisted to RSBE
|
55
|
+
#
|
56
|
+
get
|
57
|
+
update_hash_nils_from_response
|
58
|
+
end
|
59
|
+
@hash[m]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(vals = {})
|
65
|
+
fail(ArgumentError, 'Constructor requires a Hash') unless vals.is_a?(Hash)
|
66
|
+
super()
|
67
|
+
@hash = {}
|
68
|
+
@response = nil
|
69
|
+
|
70
|
+
# initialize local hash with incoming values, restrict to RW attrs
|
71
|
+
self.class.rw_attrs.each { |x| @hash[x] = (vals[x] || vals[x.to_s]) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def collections
|
75
|
+
fail 'Error getting collections' unless get_children('colls')
|
76
|
+
JSON.parse(@response.body).collect do |json_hash|
|
77
|
+
Rsbe::Client::Collection.new(json_hash)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module Rsbe
|
4
|
+
module Client
|
5
|
+
class Provider < Base
|
6
|
+
|
7
|
+
def self.base_path
|
8
|
+
super + '/providers'
|
9
|
+
end
|
10
|
+
|
11
|
+
# implementation objectives:
|
12
|
+
# - expose attributes via standard setter/getter methods
|
13
|
+
# - create getters for all Read-Only (RO) attributes
|
14
|
+
# - create setters only for Read/Write (RW) attributes
|
15
|
+
# - use hash for internal representation to simplify passing
|
16
|
+
# data back and forth to back end app
|
17
|
+
|
18
|
+
def self.rw_attrs
|
19
|
+
[:id, :name]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.ro_attrs
|
23
|
+
[:created_at, :updated_at, :lock_version]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.all_attrs
|
27
|
+
self.rw_attrs + self.ro_attrs
|
28
|
+
end
|
29
|
+
|
30
|
+
# define setter methods for RW attributes
|
31
|
+
self.rw_attrs.each {|m| define_method("#{m}=") {|v| @hash[m] = v}}
|
32
|
+
|
33
|
+
# define getter methods for ALL attributes
|
34
|
+
self.all_attrs.each {|m| define_method("#{m}") { @hash[m]}}
|
35
|
+
|
36
|
+
def initialize(vals = {})
|
37
|
+
raise ArgumentError.new("Constructor requires a Hash") unless vals.is_a?(Hash)
|
38
|
+
super()
|
39
|
+
@hash = {}
|
40
|
+
@response = nil
|
41
|
+
|
42
|
+
# initialize local hash with incoming values, restrict to RW attrs
|
43
|
+
self.class.rw_attrs.each { |x| @hash[x] = (vals[x] || vals[x.to_s]) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module Rsbe
|
4
|
+
module Client
|
5
|
+
class Se < Base
|
6
|
+
def self.all
|
7
|
+
emsg = 'Method not supported. Access via Rsbe::Client::Partner#collections'
|
8
|
+
fail Rsbe::Client::MethodNotImplementedError, emsg
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.base_path
|
12
|
+
super + '/ses'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.search(params = {})
|
16
|
+
string_keys = []
|
17
|
+
raise ArgumentError.new("Required params: #{search_required_keys}") if
|
18
|
+
params.empty?
|
19
|
+
required_params = search_required_keys
|
20
|
+
search_params = {params: params, required_params: required_params, scope: search_scope}
|
21
|
+
Search.search(search_params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.search_required_keys
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.search_scope
|
29
|
+
"ses"
|
30
|
+
end
|
31
|
+
|
32
|
+
private_class_method :search_required_keys, :search_scope
|
33
|
+
|
34
|
+
# implementation objectives:
|
35
|
+
# - expose attributes via standard setter/getter methods
|
36
|
+
# - create getters for all Read-Only (RO) attributes
|
37
|
+
# - create setters only for Read/Write (RW) attributes
|
38
|
+
# - use hash for internal representation to simplify passing
|
39
|
+
# data back and forth to back end app
|
40
|
+
|
41
|
+
def self.rw_attrs
|
42
|
+
[:id, :coll_id, :digi_id, :do_type, :phase, :step, :status, :label, :notes]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.ro_attrs
|
46
|
+
[:created_at, :updated_at, :lock_version]
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.all_attrs
|
50
|
+
self.rw_attrs + self.ro_attrs
|
51
|
+
end
|
52
|
+
|
53
|
+
# define setter methods for RW attributes
|
54
|
+
self.rw_attrs.each {|m| define_method("#{m}=") {|v| @hash[m] = v}}
|
55
|
+
|
56
|
+
# define getter methods for ALL attributes
|
57
|
+
all_attrs.each do |m|
|
58
|
+
define_method("#{m}") do
|
59
|
+
@hash[m] || begin
|
60
|
+
# only fetch if object has a known id
|
61
|
+
if @hash[:id]
|
62
|
+
# TODO: CLEAN THIS UP
|
63
|
+
# This works currently because when a 404 is
|
64
|
+
# returned there is nothing in the response
|
65
|
+
# hash that matches the resource attributes,
|
66
|
+
# but relying on this behavior seems very
|
67
|
+
# brittle. Additionally, for every attribute
|
68
|
+
# queried, a GET operation is performed.
|
69
|
+
# Should store the object lifecycle state,
|
70
|
+
# e.g.,
|
71
|
+
# - new, no ID, no matching resource in RSBE: don't query RSBE
|
72
|
+
# - new, ID assigned, but not yet in RSBE: don't query RSBE
|
73
|
+
# - existing, partially populated,
|
74
|
+
# not fully updated with RSBE values: query RSBE
|
75
|
+
# - existing, fully populated with data from RSBE
|
76
|
+
# - existing, local modifications, not persisted to RSBE
|
77
|
+
#
|
78
|
+
get
|
79
|
+
update_hash_nils_from_response
|
80
|
+
end
|
81
|
+
@hash[m]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize(vals = {})
|
87
|
+
raise ArgumentError.new("Constructor requires a Hash") unless vals.is_a?(Hash)
|
88
|
+
super()
|
89
|
+
@hash = {}
|
90
|
+
@response = nil
|
91
|
+
|
92
|
+
# initialize local hash with incoming values, restrict to RW attrs
|
93
|
+
self.class.rw_attrs.each { |x| @hash[x] = (vals[x] || vals[x.to_s]) }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Rsbe
|
2
|
+
module Client
|
3
|
+
module Search
|
4
|
+
def self.search(hsh = {})
|
5
|
+
raise ArgumentError.new("These args must be present: #{hsh_valid_keys}") if hsh.empty?
|
6
|
+
@hsh = hsh
|
7
|
+
# check if search params are valid
|
8
|
+
is_valid?
|
9
|
+
@args = hsh[:params]
|
10
|
+
@required_keys = hsh[:required_params]
|
11
|
+
@scope = hsh[:scope]
|
12
|
+
# check search args sent
|
13
|
+
chk_search_args
|
14
|
+
# build query url
|
15
|
+
@search_url = query_search_url
|
16
|
+
query
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.query_search_url
|
20
|
+
base_url = Rsbe::Client::Base.base_path
|
21
|
+
query_hsh = parameterize_params
|
22
|
+
search_url = "#{base_url}/#{search_url_fragment}?#{query_hsh}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.query
|
26
|
+
conn = Rsbe::Client::Connection.new
|
27
|
+
@response = conn.get @search_url
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.search_url_fragment
|
31
|
+
"search"
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.parameterize_params
|
35
|
+
query_hsh = @args.merge({scope: @scope})
|
36
|
+
arr = []
|
37
|
+
query_hsh.each_pair { |q,v|
|
38
|
+
arr << "#{q}=#{v}"
|
39
|
+
}
|
40
|
+
arr.join("&")
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.chk_search_args
|
44
|
+
string_keys?
|
45
|
+
incoming_keys = @args.keys.sort
|
46
|
+
compare_keys(incoming_keys,@required_keys)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.string_keys?
|
50
|
+
string_keys = []
|
51
|
+
@args.keys.each { |k|
|
52
|
+
string_keys << k unless k.is_a?(Symbol)
|
53
|
+
}
|
54
|
+
raise ArgumentError.new("Param key: #{string_keys} should be of type Symbol") if string_keys.size > 0
|
55
|
+
end
|
56
|
+
def self.compare_keys(incoming_keys, required_keys)
|
57
|
+
unless required_keys.empty?
|
58
|
+
compare_keys = incoming_keys - required_keys
|
59
|
+
raise ArgumentError.new("Required params: #{required_keys}") unless compare_keys.empty?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.is_valid?
|
64
|
+
case @hsh.class.to_s
|
65
|
+
when "Hash"
|
66
|
+
incoming_keys = @hsh.keys.sort
|
67
|
+
compare_keys(incoming_keys,hsh_valid_keys)
|
68
|
+
else
|
69
|
+
raise ArgumentError.new("Expecting hash as a arguments with the following arguments: #{hsh_valid_keys}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.hsh_valid_keys
|
74
|
+
[:params, :required_params, :scope].sort
|
75
|
+
end
|
76
|
+
|
77
|
+
private_class_method :chk_search_args, :compare_keys, :hsh_valid_keys, :is_valid?, :query_search_url, :parameterize_params, :search_url_fragment, :query, :string_keys?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Rsbe
|
2
|
+
module Client
|
3
|
+
class SearchResults
|
4
|
+
def initialize(api_response)
|
5
|
+
@api_response = api_response
|
6
|
+
# init json
|
7
|
+
json
|
8
|
+
end
|
9
|
+
|
10
|
+
def success?
|
11
|
+
@api_response.status == 200
|
12
|
+
end
|
13
|
+
|
14
|
+
def num_found
|
15
|
+
response['numFound']
|
16
|
+
end
|
17
|
+
|
18
|
+
def results
|
19
|
+
@results ||= urls.collect {|u| Rsbe::Client.find(u)}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def response
|
25
|
+
@response ||= json['response']
|
26
|
+
end
|
27
|
+
|
28
|
+
def json
|
29
|
+
@json ||= JSON.parse(@api_response.body)
|
30
|
+
end
|
31
|
+
|
32
|
+
def docs
|
33
|
+
@docs ||= response['docs']
|
34
|
+
end
|
35
|
+
|
36
|
+
def urls
|
37
|
+
@urls ||= docs.collect {|d| d['url']}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/rsbe-client.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rsbe/client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rsbe-client"
|
8
|
+
spec.version = Rsbe::Client::VERSION
|
9
|
+
spec.authors = ["jgpawletko"]
|
10
|
+
spec.email = ["jgpawletko@gmail.com"]
|
11
|
+
spec.summary = %q{Client library for interacting with rsbe API.}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.5.0"
|
23
|
+
spec.add_development_dependency "rspec-its", "~> 1.0.1"
|
24
|
+
spec.add_development_dependency "vcr", "~> 2.9.3"
|
25
|
+
spec.add_development_dependency "webmock", "~> 1.18.0"
|
26
|
+
spec.add_development_dependency "pry", "~> 0.10.1"
|
27
|
+
|
28
|
+
spec.add_dependency "faraday", "~> 0.9.0"
|
29
|
+
spec.add_dependency "activesupport", "~> 4.1.6"
|
30
|
+
end
|