smooth_operator 0.4.4 → 1.2.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 (68) hide show
  1. checksums.yaml +9 -9
  2. data/.gitignore +2 -1
  3. data/.rspec +4 -0
  4. data/Gemfile +13 -0
  5. data/README.md +258 -10
  6. data/console.rb +44 -0
  7. data/lib/smooth_operator/array_with_meta_data.rb +31 -0
  8. data/lib/smooth_operator/attribute_assignment.rb +102 -0
  9. data/lib/smooth_operator/attribute_methods.rb +87 -0
  10. data/lib/smooth_operator/attributes/base.rb +107 -0
  11. data/lib/smooth_operator/attributes/dirty.rb +29 -0
  12. data/lib/smooth_operator/attributes/normal.rb +15 -0
  13. data/lib/smooth_operator/delegation.rb +60 -0
  14. data/lib/smooth_operator/finder_methods.rb +43 -0
  15. data/lib/smooth_operator/helpers.rb +79 -0
  16. data/lib/smooth_operator/model_schema.rb +81 -0
  17. data/lib/smooth_operator/open_struct.rb +37 -0
  18. data/lib/smooth_operator/operator.rb +145 -0
  19. data/lib/smooth_operator/operators/faraday.rb +75 -0
  20. data/lib/smooth_operator/operators/typhoeus.rb +77 -0
  21. data/lib/smooth_operator/persistence.rb +144 -0
  22. data/lib/smooth_operator/relation/array_relation.rb +13 -0
  23. data/lib/smooth_operator/relation/association_reflection.rb +75 -0
  24. data/lib/smooth_operator/relation/associations.rb +75 -0
  25. data/lib/smooth_operator/relation/reflection.rb +41 -0
  26. data/lib/smooth_operator/relation/single_relation.rb +14 -0
  27. data/lib/smooth_operator/remote_call/base.rb +80 -0
  28. data/lib/smooth_operator/remote_call/errors/connection_failed.rb +20 -0
  29. data/lib/smooth_operator/remote_call/errors/timeout.rb +20 -0
  30. data/lib/smooth_operator/remote_call/faraday.rb +19 -0
  31. data/lib/smooth_operator/remote_call/typhoeus.rb +19 -0
  32. data/lib/smooth_operator/serialization.rb +79 -0
  33. data/lib/smooth_operator/translation.rb +27 -0
  34. data/lib/smooth_operator/validations.rb +15 -0
  35. data/lib/smooth_operator/version.rb +1 -1
  36. data/lib/smooth_operator.rb +26 -5
  37. data/smooth_operator.gemspec +12 -3
  38. data/spec/factories/user_factory.rb +34 -0
  39. data/spec/require_helper.rb +11 -0
  40. data/spec/smooth_operator/attribute_assignment_spec.rb +351 -0
  41. data/spec/smooth_operator/attributes_dirty_spec.rb +53 -0
  42. data/spec/smooth_operator/delegation_spec.rb +139 -0
  43. data/spec/smooth_operator/finder_methods_spec.rb +105 -0
  44. data/spec/smooth_operator/model_schema_spec.rb +31 -0
  45. data/spec/smooth_operator/operator_spec.rb +46 -0
  46. data/spec/smooth_operator/persistence_spec.rb +424 -0
  47. data/spec/smooth_operator/remote_call_spec.rb +320 -0
  48. data/spec/smooth_operator/serialization_spec.rb +80 -0
  49. data/spec/smooth_operator/validations_spec.rb +42 -0
  50. data/spec/spec_helper.rb +25 -0
  51. data/spec/support/helpers/persistence_helper.rb +38 -0
  52. data/spec/support/localhost_server.rb +97 -0
  53. data/spec/support/models/address.rb +14 -0
  54. data/spec/support/models/comment.rb +3 -0
  55. data/spec/support/models/post.rb +13 -0
  56. data/spec/support/models/user.rb +41 -0
  57. data/spec/support/models/user_with_address_and_posts.rb +89 -0
  58. data/spec/support/test_server.rb +165 -0
  59. metadata +108 -18
  60. data/lib/smooth_operator/base.rb +0 -30
  61. data/lib/smooth_operator/core.rb +0 -218
  62. data/lib/smooth_operator/http_handlers/typhoeus/base.rb +0 -58
  63. data/lib/smooth_operator/http_handlers/typhoeus/orm.rb +0 -34
  64. data/lib/smooth_operator/http_handlers/typhoeus/remote_call.rb +0 -28
  65. data/lib/smooth_operator/operator/base.rb +0 -43
  66. data/lib/smooth_operator/operator/exceptions.rb +0 -64
  67. data/lib/smooth_operator/operator/orm.rb +0 -118
  68. data/lib/smooth_operator/operator/remote_call.rb +0 -84
@@ -1,58 +0,0 @@
1
- require 'typhoeus'
2
- require "smooth_operator/http_handlers/typhoeus/remote_call"
3
-
4
- module SmoothOperator
5
- module HttpHandlers
6
- module Typhoeus
7
-
8
- class Base
9
-
10
- def self.make_the_call(http_verb, url, options, basic_auth_credentials)
11
- hydra = get_hydra_and_remove_it_from options
12
- options = { (http_verb == :get ? :params : :body) => options, :method => http_verb, :headers => { "Content-type" => "application/x-www-form-urlencoded" } }.merge auth_credentials(basic_auth_credentials)
13
-
14
- if hydra.present?
15
- make_asynchronous_request(url, options, hydra)
16
- else
17
- make_synchronous_request(url, options)
18
- end
19
- end
20
-
21
- private ###################### PRIVATE ##################
22
-
23
- def self.auth_credentials(basic_auth_credentials)
24
- basic_auth_credentials.blank? ? {} : { userpwd: "#{basic_auth_credentials[:username]}:#{basic_auth_credentials[:password]}" }
25
- end
26
-
27
- def self.get_hydra_and_remove_it_from(options)
28
- options.delete(:hydra)
29
- end
30
-
31
- def self.make_synchronous_request(url, options)
32
- hydra = ::Typhoeus::Hydra::hydra
33
- remote_call = make_asynchronous_request(url, options, hydra)
34
-
35
- remote_call.request.on_complete do |response|
36
- remote_call.raw_response = response
37
- remote_call.response = remote_call.parsed_response
38
- end
39
-
40
- hydra.run
41
- remote_call
42
- end
43
-
44
- def self.make_asynchronous_request(url, options, hydra)
45
- request = ::Typhoeus::Request.new(url, options)
46
-
47
- remote_call = SmoothOperator::HttpHandlers::Typhoeus::RemoteCall.new(request)
48
-
49
- hydra.queue(request)
50
-
51
- remote_call
52
- end
53
-
54
- end
55
-
56
- end
57
- end
58
- end
@@ -1,34 +0,0 @@
1
- module SmoothOperator
2
- module HttpHandlers
3
- module Typhoeus
4
-
5
- class ORM
6
-
7
- attr_reader :object_class
8
-
9
- def initialize(object_class)
10
- @object_class = object_class
11
- end
12
-
13
- def make_the_call(http_verb, options, relative_path, &block)
14
- injected_hydra = options[:hydra]
15
- hydra = injected_hydra || ::Typhoeus::Hydra::hydra
16
- options[:hydra] = hydra
17
-
18
- remote_call = @object_class.make_the_call(http_verb, relative_path, options)
19
-
20
- remote_call.request.on_complete do |typhoeus_response|
21
- remote_call.raw_response = typhoeus_response
22
- yield(remote_call)
23
- end
24
-
25
- hydra.run if injected_hydra.blank?
26
-
27
- remote_call
28
- end
29
-
30
- end
31
-
32
- end
33
- end
34
- end
@@ -1,28 +0,0 @@
1
- require "smooth_operator/operator/remote_call"
2
-
3
- module SmoothOperator
4
- module HttpHandlers
5
- module Typhoeus
6
-
7
- class RemoteCall < SmoothOperator::Operator::RemoteCall
8
-
9
- attr_reader :request
10
-
11
- def initialize(request)
12
- @request = request
13
- end
14
-
15
- def parse_response
16
- begin
17
- @parse_response ||= ::HTTParty::Parser.call(@raw_response.body, :json)
18
- rescue
19
- nil
20
- end
21
- end
22
-
23
- end
24
-
25
- end
26
-
27
- end
28
- end
@@ -1,43 +0,0 @@
1
- module SmoothOperator
2
- module Operator
3
-
4
- module Base
5
-
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- end
9
-
10
- module ClassMethods
11
-
12
- def get(relative_path, options = {})
13
- make_the_call(:get, relative_path, options)
14
- end
15
-
16
- def post(relative_path, options = {})
17
- make_the_call(:post, relative_path, options)
18
- end
19
-
20
- def put(relative_path, options = {})
21
- make_the_call(:put, relative_path, options)
22
- end
23
-
24
- def delete(relative_path, options = {})
25
- make_the_call(:delete, relative_path, options)
26
- end
27
-
28
- def make_the_call(http_verb, relative_path, options = {})
29
- url = build_url(relative_path)
30
- options = query_string(options || {})
31
- http_handler_base.make_the_call(http_verb, url, options, get_basic_auth_credentials)
32
- end
33
-
34
- def query_string(options)
35
- options
36
- end
37
-
38
- end
39
-
40
- end
41
-
42
- end
43
- end
@@ -1,64 +0,0 @@
1
- module SmoothOperator
2
- module Operator
3
-
4
- module Exceptions
5
-
6
- extend self
7
-
8
- def raise_proper_exception(response, code)
9
- return nil if CODES_TO_IGNORE.include?(code)
10
- exception_to_raise = (CODE_VS_EXCEPTIONS[code] || SmoothOperator::Operator::Exceptions::Unknown).new(response)
11
- #raise exception_to_raise, exception_to_raise.message
12
- end
13
-
14
- class Base < StandardError
15
- attr_reader :response
16
-
17
- def initialize(response)
18
- @response = response
19
- end
20
- end
21
-
22
- class Unknown < SmoothOperator::Operator::Exceptions::Base
23
- def message
24
- 'Unknown Error'
25
- end
26
- end
27
-
28
- class NotFound < SmoothOperator::Operator::Exceptions::Base
29
- def message
30
- 'NotFound'
31
- end
32
- end
33
-
34
- class EntityNotProcessed < SmoothOperator::Operator::Exceptions::Base
35
- def message
36
- 'EntityNotProcessed'
37
- end
38
- end
39
-
40
- class ServerError < SmoothOperator::Operator::Exceptions::Base
41
- def message
42
- 'ServerError'
43
- end
44
- end
45
-
46
- class AuthorizationRequired < SmoothOperator::Operator::Exceptions::Base
47
- def message
48
- 'AuthorizationRequired'
49
- end
50
- end
51
-
52
- CODES_TO_IGNORE = [200]
53
-
54
- CODE_VS_EXCEPTIONS = {
55
- 401 => AuthorizationRequired,
56
- 422 => EntityNotProcessed,
57
- 404 => NotFound,
58
- 500 => ServerError
59
- }
60
-
61
- end
62
-
63
- end
64
- end
@@ -1,118 +0,0 @@
1
- module SmoothOperator
2
- module Operator
3
-
4
- module ORM
5
-
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- base.send(:attr_reader, :last_response)
9
- base.send(:attr_reader, :exception)
10
- end
11
-
12
- module ClassMethods
13
-
14
- def find(id, options = {})
15
- if id == :all
16
- find_each('', options)
17
- else
18
- find_one(id, options)
19
- end
20
- end
21
-
22
- def safe_find(id, options = {})
23
- begin
24
- find(id, options)
25
- rescue Exception => exception #exception.response contains the server response
26
- id == :all ? [] : nil
27
- end
28
- end
29
-
30
- def create(options = {})
31
- new_object = new(options)
32
-
33
- http_handler_orm.make_the_call(:post, { model_name_downcase => new_object.safe_table_hash }, '') do |remote_call|
34
- new_object.send('after_create_update_or_destroy', remote_call)
35
- end
36
-
37
- new_object
38
- end
39
-
40
- def find_each(relative_path, options)
41
- http_handler_orm.make_the_call(:get, options, relative_path) do |remote_call|
42
- objects_list = remote_call.get_attributes(table_name)
43
-
44
- if objects_list.kind_of?(Array)
45
- remote_call.response = objects_list.map { |attributes| new remote_call.get_attributes(model_name_downcase, attributes) }
46
- else
47
- remote_call.response = objects_list
48
- end
49
- end
50
- end
51
-
52
- def find_one(relative_path, options)
53
- http_handler_orm.make_the_call(:get, options, relative_path) do |remote_call|
54
- remote_call.response = new remote_call.get_attributes(model_name_downcase)
55
- end
56
- end
57
-
58
- end
59
-
60
- def save(options = {})
61
- begin
62
- save!(options)
63
- rescue Exception => exception
64
- send("exception=", exception)
65
- false
66
- end
67
- end
68
-
69
- def save!(options = {})
70
- options = build_options_for_save(options)
71
-
72
- if new_record?
73
- http_handler_orm.make_the_call(:post, options, '') { |remote_call| after_create_update_or_destroy(remote_call) }
74
- else
75
- http_handler_orm.make_the_call(:put, options, id) { |remote_call| after_create_update_or_destroy(remote_call) }
76
- end
77
- end
78
-
79
- def destroy(options = {})
80
- return true if new_record?
81
-
82
- http_handler_orm.make_the_call(:delete, options, id) do |remote_call|
83
- after_create_update_or_destroy(remote_call)
84
- end
85
- end
86
-
87
- private ####################### private #######################
88
-
89
- def build_options_for_save(options = {})
90
- options ||= {}
91
- options[self.class.model_name_downcase] ||= safe_table_hash
92
- options
93
- end
94
-
95
- def after_create_update_or_destroy(remote_call)
96
- new_attributes = remote_call.get_attributes(self.class.model_name_downcase)
97
- assign_attributes(new_attributes)
98
- set_raw_response_exception_and_build_proper_response(remote_call)
99
- end
100
-
101
- def set_raw_response_exception_and_build_proper_response(remote_call)
102
- send("last_response=", remote_call.raw_response)
103
- send("exception=", remote_call.exception)
104
- remote_call.response = remote_call.successful_response?
105
- end
106
-
107
- def last_response=(response)
108
- @last_response = response
109
- end
110
-
111
- def exception=(exception)
112
- @exception = exception
113
- end
114
-
115
- end
116
-
117
- end
118
- end
@@ -1,84 +0,0 @@
1
- require "smooth_operator/operator/exceptions"
2
-
3
- module SmoothOperator
4
- module Operator
5
-
6
- class RemoteCall
7
-
8
- attr_reader :protocol_handler, :raw_response, :parsed_response, :exception
9
- attr_writer :response
10
-
11
- HTTP_SUCCESS_CODES = [200, 201, 202, 203, 204]
12
-
13
- def parse_response # TO BE OVERWRITTEN IF NECESSARY
14
- @raw_response
15
- end
16
-
17
- def successful_response? # TO BE OVERWRITTEN IF NECESSARY
18
- @raw_response.blank? || HTTP_SUCCESS_CODES.include?(code)
19
- end
20
-
21
- def code # TO BE OVERWRITTEN IF NECESSARY
22
- @raw_response.code
23
- end
24
-
25
- def ok?; successful_response?; end
26
-
27
- def error?; !ok? && exception.present?; end
28
-
29
- def raw_response=(response)
30
- @raw_response = response
31
- @parsed_response = parse_response_and_set_exception_if_necessary
32
- end
33
-
34
- def response
35
- exception.present? ? false : @response
36
- end
37
-
38
- def ==(object_to_compare)
39
- response == object_to_compare
40
- end
41
-
42
- def <<(object)
43
- if response.is_a? Array
44
- response << object
45
- else
46
- response += object
47
- end
48
- end
49
-
50
- def respond_to?(symbol, include_priv = false)
51
- response.respond_to?(symbol, include_priv)
52
- end
53
-
54
- def to_s
55
- response
56
- end
57
-
58
- def get_attributes(key, attributes = nil)
59
- attributes ||= @parsed_response
60
-
61
- if attributes.kind_of?(Hash)
62
- attributes.include?(key) ? attributes[key] : attributes
63
- else
64
- attributes
65
- end
66
- end
67
-
68
- protected ####################### protected ##################
69
-
70
- def parse_response_and_set_exception_if_necessary
71
- @exception = successful_response? ? nil : SmoothOperator::Operator::Exceptions.raise_proper_exception(@raw_response, code)
72
- parse_response
73
- end
74
-
75
- private ####################### private ######################
76
-
77
- def method_missing(method, *args, &block)
78
- response.send(method, *args, &block)
79
- end
80
-
81
- end
82
-
83
- end
84
- end