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.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +3 -0
  4. data/GETTING-STARTED.md +17 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +73 -0
  8. data/Rakefile +11 -0
  9. data/TODO.md +38 -0
  10. data/lib/rsbe/client.rb +50 -0
  11. data/lib/rsbe/client/base.rb +140 -0
  12. data/lib/rsbe/client/collection.rb +84 -0
  13. data/lib/rsbe/client/connection.rb +24 -0
  14. data/lib/rsbe/client/method_not_implemented_error.rb +6 -0
  15. data/lib/rsbe/client/not_found_error.rb +6 -0
  16. data/lib/rsbe/client/partner.rb +82 -0
  17. data/lib/rsbe/client/provider.rb +47 -0
  18. data/lib/rsbe/client/se.rb +97 -0
  19. data/lib/rsbe/client/search.rb +80 -0
  20. data/lib/rsbe/client/search_results.rb +41 -0
  21. data/lib/rsbe/client/unrecognized_resource_error.rb +6 -0
  22. data/lib/rsbe/client/version.rb +5 -0
  23. data/lib/rsbe/client/wrong_origin_error.rb +6 -0
  24. data/rsbe-client.gemspec +30 -0
  25. data/spec/fixtures/partners/partners_all.json +1 -0
  26. data/spec/fixtures/partners/partners_none.json +1 -0
  27. data/spec/rsbe/client/base_spec.rb +10 -0
  28. data/spec/rsbe/client/collection_spec.rb +186 -0
  29. data/spec/rsbe/client/connection_spec.rb +20 -0
  30. data/spec/rsbe/client/partner_spec.rb +185 -0
  31. data/spec/rsbe/client/provider_spec.rb +122 -0
  32. data/spec/rsbe/client/se_spec.rb +273 -0
  33. data/spec/rsbe/client/search_results_spec.rb +140 -0
  34. data/spec/rsbe/client/search_spec.rb +74 -0
  35. data/spec/rsbe/client_spec.rb +52 -0
  36. data/spec/spec_helper.rb +43 -0
  37. data/spec/vcr_cassettes/client/find_collection.yml +53 -0
  38. data/spec/vcr_cassettes/client/find_partner.yml +52 -0
  39. data/spec/vcr_cassettes/client/find_provider.yml +52 -0
  40. data/spec/vcr_cassettes/client/find_se.yml +53 -0
  41. data/spec/vcr_cassettes/collection/find-existing.yml +53 -0
  42. data/spec/vcr_cassettes/collection/find-non_existent.yml +50 -0
  43. data/spec/vcr_cassettes/collection/lazy-eval-dne.yml +285 -0
  44. data/spec/vcr_cassettes/collection/lazy-eval-exists.yml +53 -0
  45. data/spec/vcr_cassettes/collection/save-create-known-id.yml +103 -0
  46. data/spec/vcr_cassettes/collection/save-create-unknown-id.yml +56 -0
  47. data/spec/vcr_cassettes/collection/save-invalid.yml +143 -0
  48. data/spec/vcr_cassettes/collection/save-update-valid.yml +99 -0
  49. data/spec/vcr_cassettes/partner/all.yml +300 -0
  50. data/spec/vcr_cassettes/partner/dne-with-id.yml +238 -0
  51. data/spec/vcr_cassettes/partner/find-existing.yml +52 -0
  52. data/spec/vcr_cassettes/partner/find-non_existent.yml +50 -0
  53. data/spec/vcr_cassettes/partner/lazy-eval-exists.yml +53 -0
  54. data/spec/vcr_cassettes/partner/save-create-known-id.yml +101 -0
  55. data/spec/vcr_cassettes/partner/save-create-unknown-id.yml +54 -0
  56. data/spec/vcr_cassettes/partner/save-invalid.yml +177 -0
  57. data/spec/vcr_cassettes/partner/save-unknown-id.yml +54 -0
  58. data/spec/vcr_cassettes/partner/save-update-valid.yml +98 -0
  59. data/spec/vcr_cassettes/partner/with-collections.yml +203 -0
  60. data/spec/vcr_cassettes/partner/without-collections.yml +101 -0
  61. data/spec/vcr_cassettes/provider/all.yml +248 -0
  62. data/spec/vcr_cassettes/provider/find-existing.yml +52 -0
  63. data/spec/vcr_cassettes/provider/find-non_existent.yml +50 -0
  64. data/spec/vcr_cassettes/provider/save-create-known-id.yml +101 -0
  65. data/spec/vcr_cassettes/provider/save-create-unknown-id.yml +54 -0
  66. data/spec/vcr_cassettes/provider/save-invalid.yml +178 -0
  67. data/spec/vcr_cassettes/provider/save-update-valid.yml +144 -0
  68. data/spec/vcr_cassettes/se/find-existing.yml +53 -0
  69. data/spec/vcr_cassettes/se/find-non_existent.yml +50 -0
  70. data/spec/vcr_cassettes/se/lazy-eval-exists.yml +52 -0
  71. data/spec/vcr_cassettes/se/save-create-known-id.yml +146 -0
  72. data/spec/vcr_cassettes/se/save-create-unknown-id.yml +56 -0
  73. data/spec/vcr_cassettes/se/save-invalid.yml +305 -0
  74. data/spec/vcr_cassettes/se/save-update-valid.yml +99 -0
  75. data/spec/vcr_cassettes/se/search-malformed-uuid.yml +54 -0
  76. data/spec/vcr_cassettes/se/search-with-existing-se.yml +52 -0
  77. data/spec/vcr_cassettes/se/search-with-missing-se.yml +52 -0
  78. data/spec/vcr_cassettes/search/search-with-existing-se.yml +52 -0
  79. data/spec/vcr_cassettes/search_results/no-results.yml +52 -0
  80. data/spec/vcr_cassettes/search_results/search-by-digi_id.yml +101 -0
  81. data/spec/vcr_cassettes/search_results/search-by-step.yml +201 -0
  82. 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,6 @@
1
+ module Rsbe
2
+ module Client
3
+ class MethodNotImplementedError < RuntimeError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Rsbe
2
+ module Client
3
+ class RecordNotFound < RuntimeError
4
+ end
5
+ end
6
+ 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
@@ -0,0 +1,6 @@
1
+ module Rsbe
2
+ module Client
3
+ class UnrecognizedResourceError < ArgumentError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Rsbe
2
+ module Client
3
+ VERSION = "0.5.0"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module Rsbe
2
+ module Client
3
+ class WrongOriginError < ArgumentError
4
+ end
5
+ end
6
+ end
@@ -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