smooth_operator 0.0.2 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,4 +3,6 @@ module SmoothOperator
3
3
  end
4
4
 
5
5
  require "smooth_operator/version"
6
+ require "smooth_operator/core"
6
7
  require "smooth_operator/base"
8
+ require "smooth_operator/rollback"
@@ -1,62 +1,30 @@
1
- require "smooth_operator/operator"
2
- require "smooth_operator/orm"
1
+ require "smooth_operator/operator/base"
2
+ require "smooth_operator/operator/orm"
3
3
 
4
- module SmoothOperator
5
- class Base < OpenStruct
6
-
7
- include SmoothOperator::Operator
8
- include SmoothOperator::ORM
9
-
10
- def hash_of_full_content
11
- @table
12
- end
13
-
14
- def as_json(options = nil)
15
- @table.as_json(options)
16
- end
17
-
18
- def self.nested_objects_classes(hash)
19
- hash.each do |nested_object_symbol, nested_object_class|
20
- define_method(nested_object_symbol.to_s) do
21
- get_nested_object_variable(nested_object_symbol, nested_object_class)
22
- end
23
- end
24
- end
4
+ require "smooth_operator/http_handlers/typhoeus/base"
5
+ require "smooth_operator/http_handlers/typhoeus/orm"
25
6
 
26
- private #---------------------------- private
27
-
28
- def get_nested_object_variable(nested_object_symbol, nested_object_class)
29
- nested_object_variable = instance_variable_get("@#{nested_object_symbol}")
30
-
31
- return nested_object_variable if nested_object_variable.present?
32
-
33
- nested_object_variable = initialize_nested_object_variable(hash_of_full_content[nested_object_symbol], nested_object_class, nested_object_symbol)
7
+ module SmoothOperator
34
8
 
35
- instance_variable_set("@#{nested_object_symbol}", nested_object_variable)
9
+ class Base < OpenStruct
10
+ include SmoothOperator::Core
11
+ include SmoothOperator::Operator::Base
12
+ include SmoothOperator::Operator::ORM
36
13
 
37
- nested_object_variable
38
- end
14
+ protected ################### PROTECTED ###################
39
15
 
40
- def initialize_nested_object_variable(attributes, nested_object_class, nested_object_symbol)
41
- if attributes.kind_of? Array
42
- attributes.map { |_attributes| get_nested_object(_attributes, nested_object_class, nested_object_symbol) }
43
- else
44
- get_nested_object(attributes, nested_object_class, nested_object_symbol)
45
- end
16
+ def self.http_handler_base
17
+ SmoothOperator::HttpHandlers::Typhoeus::Base
46
18
  end
47
19
 
48
- def get_nested_object(nested_objects_attributes, nested_object_class, nested_object_symbol)
49
- if nested_objects_attributes.blank?
50
- plural?(nested_object_symbol) ? [] : nil
51
- else
52
- nested_object_class.new(nested_objects_attributes)
53
- end
20
+ def self.http_handler_orm
21
+ @http_handler_orm ||= SmoothOperator::HttpHandlers::Typhoeus::ORM.new(self)
54
22
  end
55
23
 
56
- def plural?(string)
57
- string = string.to_s
58
- string == string.pluralize
24
+ def http_handler_orm
25
+ self.class.http_handler_orm
59
26
  end
60
27
 
61
28
  end
29
+
62
30
  end
@@ -0,0 +1,162 @@
1
+ module SmoothOperator
2
+ module Core
3
+
4
+ def table_hash
5
+ @table
6
+ end
7
+
8
+ def as_json(options = nil)
9
+ @table.as_json(options)
10
+ end
11
+
12
+ def new_record?
13
+ !persisted?
14
+ end
15
+
16
+ def persisted?
17
+ try(:id).present?
18
+ end
19
+
20
+ def to_partial_path
21
+ class_name_plural = self.class.table_name
22
+ "#{class_name_plural}/#{class_name_plural.singularize}"
23
+ end
24
+
25
+ def valid?
26
+ errors.blank?
27
+ end
28
+
29
+ def invalid?
30
+ !valid?
31
+ end
32
+
33
+ def assign_attributes(attributes = {})
34
+ return if attributes.blank?
35
+
36
+ attributes.each do |name, value|
37
+ send("#{name}=", value)
38
+ end
39
+ end
40
+
41
+ def safe_table_hash
42
+ safe_hash = table_hash.dup
43
+
44
+ if self.class.save_attr_white_list.present?
45
+ safe_hash.slice!(*self.class.save_attr_white_list)
46
+ else
47
+ self.class.save_attr_black_list.each { |attribute| safe_hash.delete(attribute) }
48
+ end
49
+
50
+ safe_hash
51
+ end
52
+
53
+
54
+ private ######################### PRIVATE ###############################
55
+
56
+ def get_nested_object_variable(nested_object_symbol, nested_object_class)
57
+ nested_object_variable = instance_variable_get("@#{nested_object_symbol}")
58
+
59
+ return nested_object_variable if nested_object_variable.present?
60
+
61
+ nested_object_variable = initialize_nested_object_variable(table_hash[nested_object_symbol], nested_object_class, nested_object_symbol)
62
+
63
+ instance_variable_set("@#{nested_object_symbol}", nested_object_variable)
64
+
65
+ nested_object_variable
66
+ end
67
+
68
+ def initialize_nested_object_variable(attributes, nested_object_class, nested_object_symbol)
69
+ if attributes.kind_of? Array
70
+ attributes.map { |_attributes| get_nested_object(_attributes, nested_object_class, nested_object_symbol) }
71
+ else
72
+ get_nested_object(attributes, nested_object_class, nested_object_symbol)
73
+ end
74
+ end
75
+
76
+ def get_nested_object(nested_objects_attributes, nested_object_class, nested_object_symbol)
77
+ if nested_objects_attributes.blank?
78
+ plural?(nested_object_symbol) ? [] : nil
79
+ else
80
+ nested_object_class.new(nested_objects_attributes)
81
+ end
82
+ end
83
+
84
+ def plural?(string)
85
+ string = string.to_s
86
+ string == string.pluralize
87
+ end
88
+
89
+
90
+ def self.included(base)
91
+ base.extend(ClassMethods)
92
+ end
93
+
94
+ module ClassMethods
95
+
96
+ def nested_objects_classes(hash)
97
+ hash.each do |nested_object_symbol, nested_object_class|
98
+ define_method(nested_object_symbol.to_s) do
99
+ get_nested_object_variable(nested_object_symbol, nested_object_class)
100
+ end
101
+ end
102
+ end
103
+
104
+ attr_writer :endpoint
105
+ def endpoint
106
+ @endpoint ||= ENV["API_ENDPOINT"]
107
+ end
108
+
109
+ attr_writer :endpoint_user
110
+ def endpoint_user
111
+ @endpoint_user ||= ENV["API_USER"]
112
+ end
113
+
114
+ attr_writer :endpoint_pass
115
+ def endpoint_pass
116
+ @endpoint_pass ||= ENV["API_PASS"]
117
+ end
118
+
119
+ attr_writer :save_attr_black_list
120
+ def save_attr_black_list
121
+ @save_attr_black_list ||= [:id, :created_at, :updated_at, :errors]
122
+ end
123
+
124
+ attr_writer :save_attr_white_list
125
+ def save_attr_white_list
126
+ @save_attr_white_list ||= []
127
+ end
128
+
129
+ attr_writer :model_name
130
+ def model_name
131
+ @model_name ||= name.split('::').last.underscore.capitalize
132
+ end
133
+
134
+ def model_name_downcase
135
+ model_name.downcase
136
+ end
137
+
138
+ attr_writer :table_name
139
+ def table_name
140
+ @table_name ||= model_name_downcase.to_s.pluralize
141
+ end
142
+
143
+ private ################################ PRIVATE #########################
144
+
145
+ def build_url(relative_path)
146
+ slash = '/' if relative_path.present?
147
+ extention = '.json'
148
+ [endpoint, table_name, slash, relative_path.to_s, extention].join
149
+ end
150
+
151
+ def get_basic_auth_credentials
152
+ if endpoint_user.present? || endpoint_pass.present?
153
+ { username: endpoint_user, password: endpoint_pass }
154
+ else
155
+ nil
156
+ end
157
+ end
158
+
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,58 @@
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 = { params: options, method: http_verb }.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
+ request = ::Typhoeus::Request.new(url, options)
33
+ remote_call = SmoothOperator::HttpHandlers::Typhoeus::RemoteCall.new(request)
34
+
35
+ request.on_complete do |response|
36
+ remote_call.raw_response = response
37
+ remote_call.response = remote_call.parsed_response
38
+ end
39
+
40
+ request.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
@@ -0,0 +1,33 @@
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, id, &block)
14
+ injected_hydra = options[:hydra]
15
+ options[:hydra] = injected_hydra || ::Typhoeus::Hydra.hydra
16
+
17
+ remote_call = @object_class.make_the_call(http_verb, id, options)
18
+
19
+ remote_call.request.on_complete do |typhoeus_response|
20
+ remote_call.raw_response = typhoeus_response
21
+ yield(remote_call)
22
+ end
23
+
24
+ remote_call.request.run if injected_hydra.blank?
25
+
26
+ remote_call
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
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
@@ -0,0 +1,38 @@
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
+ http_handler_base.make_the_call(http_verb, url, (options || {}), get_basic_auth_credentials)
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,64 @@
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
@@ -0,0 +1,120 @@
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
+ protected ####################### protected #######################
41
+
42
+ def find_each(options)
43
+ http_handler_orm.make_the_call(:get, options, '') do |remote_call|
44
+ objects_list = remote_call.get_attributes(table_name)
45
+
46
+ if objects_list.kind_of?(Array)
47
+ remote_call.response = objects_list.map { |attributes| new remote_call.get_attributes(model_name_downcase, attributes) }
48
+ else
49
+ remote_call.response = objects_list
50
+ end
51
+ end
52
+ end
53
+
54
+ def find_one(id, options)
55
+ http_handler_orm.make_the_call(:get, options, id) do |remote_call|
56
+ remote_call.response = new remote_call.get_attributes(model_name_downcase)
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ def save(options = {})
63
+ begin
64
+ save!(options)
65
+ rescue Exception => exception
66
+ send("exception=", exception)
67
+ false
68
+ end
69
+ end
70
+
71
+ def save!(options = {})
72
+ options = build_options_for_save(options)
73
+
74
+ if new_record?
75
+ http_handler_orm.make_the_call(:post, options, '') { |remote_call| after_create_update_or_destroy(remote_call) }
76
+ else
77
+ http_handler_orm.make_the_call(:put, options, id) { |remote_call| after_create_update_or_destroy(remote_call) }
78
+ end
79
+ end
80
+
81
+ def destroy(options = {})
82
+ return true if new_record?
83
+
84
+ http_handler_orm.make_the_call(:delete, options, id) do |remote_call|
85
+ after_create_update_or_destroy(remote_call)
86
+ end
87
+ end
88
+
89
+ private ####################### private #######################
90
+
91
+ def build_options_for_save(options = {})
92
+ options ||= {}
93
+ options[self.class.model_name_downcase] ||= safe_table_hash
94
+ options
95
+ end
96
+
97
+ def after_create_update_or_destroy(remote_call)
98
+ new_attributes = remote_call.get_attributes(self.class.model_name_downcase)
99
+ assign_attributes(new_attributes)
100
+ set_raw_response_exception_and_build_proper_response(remote_call)
101
+ end
102
+
103
+ def set_raw_response_exception_and_build_proper_response(remote_call)
104
+ send("last_response=", remote_call.raw_response)
105
+ send("exception=", remote_call.exception)
106
+ remote_call.response = remote_call.successful_response?
107
+ end
108
+
109
+ def last_response=(response)
110
+ @last_response = response
111
+ end
112
+
113
+ def exception=(exception)
114
+ @exception = exception
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,84 @@
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
@@ -0,0 +1,16 @@
1
+ module SmoothOperator
2
+
3
+ class Rollback < SmoothOperator::Base
4
+
5
+ def rollback(options = {}, dont_update = false)
6
+ http_handler_orm.make_the_call(:delete, options, "#{version_id}/rollback") do |remote_call|
7
+ set_raw_response_exception_and_build_proper_response(remote_call)
8
+
9
+ new_attributes = remote_call.get_attributes(self.class.model_name_downcase)
10
+ assign_attributes(new_attributes.slice("id", "version_id"))
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -1,3 +1,3 @@
1
1
  module SmoothOperator
2
- VERSION = "0.0.2"
2
+ VERSION = "0.3.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smooth_operator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-02 00:00:00.000000000 Z
12
+ date: 2013-08-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -73,11 +73,15 @@ files:
73
73
  - Rakefile
74
74
  - lib/smooth_operator.rb
75
75
  - lib/smooth_operator/base.rb
76
- - lib/smooth_operator/exceptions.rb
77
- - lib/smooth_operator/open_struct.rb
78
- - lib/smooth_operator/operator.rb
79
- - lib/smooth_operator/orm.rb
80
- - lib/smooth_operator/protocol_handler.rb
76
+ - lib/smooth_operator/core.rb
77
+ - lib/smooth_operator/http_handlers/typhoeus/base.rb
78
+ - lib/smooth_operator/http_handlers/typhoeus/orm.rb
79
+ - lib/smooth_operator/http_handlers/typhoeus/remote_call.rb
80
+ - lib/smooth_operator/operator/base.rb
81
+ - lib/smooth_operator/operator/exceptions.rb
82
+ - lib/smooth_operator/operator/orm.rb
83
+ - lib/smooth_operator/operator/remote_call.rb
84
+ - lib/smooth_operator/rollback.rb
81
85
  - lib/smooth_operator/version.rb
82
86
  - smooth_operator.gemspec
83
87
  homepage: https://github.com/goncalvesjoao/smooth_operator
@@ -1,60 +0,0 @@
1
- module SmoothOperator
2
- module Exceptions
3
-
4
- extend self
5
-
6
- def raise_proper_exception(response)
7
- return nil if CODES_TO_IGNORE.include?(response.code)
8
- exception_to_raise = (CODE_VS_EXCEPTIONS[response.code] || SmoothOperator::Exceptions::Unknown).new(response)
9
- raise exception_to_raise, exception_to_raise.message
10
- end
11
-
12
- class Base < StandardError
13
- attr_reader :response
14
-
15
- def initialize(response)
16
- @response = response
17
- end
18
- end
19
-
20
- class Unknown < SmoothOperator::Exceptions::Base
21
- def message
22
- 'Unknown Error'
23
- end
24
- end
25
-
26
- class NotFound < SmoothOperator::Exceptions::Base
27
- def message
28
- 'NotFound'
29
- end
30
- end
31
-
32
- class EntityNotProcessed < SmoothOperator::Exceptions::Base
33
- def message
34
- 'EntityNotProcessed'
35
- end
36
- end
37
-
38
- class ServerError < SmoothOperator::Exceptions::Base
39
- def message
40
- 'ServerError'
41
- end
42
- end
43
-
44
- class AuthorizationRequired < SmoothOperator::Exceptions::Base
45
- def message
46
- 'AuthorizationRequired'
47
- end
48
- end
49
-
50
- CODES_TO_IGNORE = [200]
51
-
52
- CODE_VS_EXCEPTIONS = {
53
- 401 => AuthorizationRequired,
54
- 422 => EntityNotProcessed,
55
- 404 => NotFound,
56
- 500 => ServerError
57
- }
58
-
59
- end
60
- end
@@ -1,16 +0,0 @@
1
- module SmoothOperator
2
- module OpenStruct
3
-
4
- extend self # extends the module Class with its instance methods and
5
- # makes it possible do 'SmoothOperator::OpenStruct.new'
6
-
7
- def new(attributes = {})
8
- ::OpenStruct.new(attributes).extend(SmoothOperator::OpenStruct)
9
- end
10
-
11
- def to_hash
12
- @table
13
- end
14
-
15
- end
16
- end
@@ -1,100 +0,0 @@
1
- require "smooth_operator/protocol_handler"
2
-
3
- module SmoothOperator
4
- module Operator
5
-
6
- HTTP_SUCCESS_CODES = [200, 201, 202, 203, 204]
7
-
8
- def self.included(base)
9
- base.extend(ClassMethods)
10
- end
11
-
12
- module ClassMethods
13
-
14
- attr_writer :endpoint
15
- def endpoint
16
- @endpoint ||= ENV["API_ENDPOINT"]
17
- end
18
-
19
- attr_writer :endpoint_user
20
- def endpoint_user
21
- @endpoint_user ||= ENV["API_USER"]
22
- end
23
-
24
- attr_writer :endpoint_pass
25
- def endpoint_pass
26
- @endpoint_pass ||= ENV["API_PASS"]
27
- end
28
-
29
- def get(relative_path, options = {})
30
- make_the_call(:get, relative_path, SmoothOperator::ProtocolHandler.get_options(options))
31
- end
32
-
33
- def post(relative_path, options = {})
34
- make_the_call(:post, relative_path, SmoothOperator::ProtocolHandler.post_options(options))
35
- end
36
-
37
- def put(relative_path, options = {})
38
- make_the_call(:put, relative_path, SmoothOperator::ProtocolHandler.put_options(options))
39
- end
40
-
41
- def delete(relative_path, options = {})
42
- make_the_call(:delete, relative_path, SmoothOperator::ProtocolHandler.delete_options(options))
43
- end
44
-
45
-
46
- def safe_get(relative_path, options = {})
47
- safe_response(get(relative_path, options)) rescue nil
48
- end
49
-
50
- def safe_post(relative_path, options = {})
51
- safe_response(post(relative_path, options)) rescue nil
52
- end
53
-
54
- def safe_put(relative_path, options = {})
55
- safe_response(put(relative_path, options)) rescue nil
56
- end
57
-
58
- def safe_delete(relative_path, options = {})
59
- safe_response(delete(relative_path, options)) rescue nil
60
- end
61
-
62
- def safe_response(response)
63
- successful_response?(response) ? response.parsed_response : nil
64
- end
65
-
66
-
67
- def make_the_call(http_verb, relative_path, options = {})
68
- url = build_url(relative_path)
69
- options = build_options(options)
70
- response = SmoothOperator::ProtocolHandler.send(http_verb, url, options)
71
- response
72
- end
73
-
74
- def build_url(relative_path)
75
- slash = '/' if relative_path.present?
76
- extention = '.json'
77
- [endpoint, table_name, slash, relative_path.to_s, extention].join
78
- end
79
-
80
- def set_basic_auth_credentials(options)
81
- if endpoint_user.present? || endpoint_pass.present? && !options.include?(:basic_auth)
82
- options.merge({ basic_auth: { username: endpoint_user, password: endpoint_pass } })
83
- else
84
- options
85
- end
86
- end
87
-
88
- def build_options(options)
89
- options = {} if options.blank?
90
- set_basic_auth_credentials(options)
91
- end
92
-
93
- def successful_response?(response)
94
- HTTP_SUCCESS_CODES.include?(response.code) || response.blank?
95
- end
96
-
97
- end
98
-
99
- end
100
- end
@@ -1,154 +0,0 @@
1
- require "smooth_operator/exceptions"
2
-
3
- module SmoothOperator
4
- module ORM
5
-
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- base.send(:attr_reader, :last_response)
9
- end
10
-
11
- module ClassMethods
12
-
13
- attr_writer :save_attr_black_list
14
- def save_attr_black_list
15
- @save_attr_black_list ||= [:id, :created_at, :updated_at]
16
- end
17
-
18
- attr_writer :save_attr_white_list
19
- def save_attr_white_list
20
- @save_attr_white_list ||= []
21
- end
22
-
23
- def find(id, options = {})
24
- if id == :all
25
- find_each(options)
26
- else
27
- find_one(id, options)
28
- end
29
- end
30
-
31
- def safe_find(id, options = {})
32
- begin
33
- find(id, options)
34
- rescue Exception => exception #exception.response contains the server response
35
- id == :all ? [] : nil
36
- end
37
- end
38
-
39
- attr_writer :model_name
40
- def model_name
41
- @model_name ||= name.split('::').last.underscore.capitalize
42
- end
43
-
44
- def model_name_downcase
45
- model_name.downcase
46
- end
47
-
48
- attr_writer :table_name
49
- def table_name
50
- @table_name ||= model_name_downcase.to_s.pluralize
51
- end
52
-
53
- private #------------------------------------------------ private
54
-
55
- def instantiate_each(objects)
56
- objects.map { |object| new(object) }
57
- end
58
-
59
- def find_each(options)
60
- response = get(nil, options)
61
- parsed_response = parse_response_or_raise_proper_exception(response)
62
- parsed_response.kind_of?(Array) ? instantiate_each(parsed_response) : parsed_response
63
- end
64
-
65
- def find_one(id, options)
66
- response = get(id, options)
67
- parsed_response = parse_response_or_raise_proper_exception(response)
68
- new(parsed_response)
69
- end
70
-
71
- def parse_response_or_raise_proper_exception(response)
72
- if successful_response?(response)
73
- response.parsed_response
74
- else
75
- SmoothOperator::Exceptions.raise_proper_exception(response)
76
- end
77
- end
78
-
79
- end
80
-
81
- def save
82
- begin
83
- save!
84
- rescue Exception => exception
85
- false
86
- end
87
- end
88
-
89
- def save!
90
- @last_response = create_or_update
91
- import_response_errors(@last_response)
92
- SmoothOperator::Exceptions.raise_proper_exception(@last_response) unless self.class.successful_response?(@last_response)
93
- true
94
- end
95
-
96
- def destroy
97
- return true if new_record?
98
-
99
- @last_response = self.class.delete(self.id)
100
- import_response_errors(@last_response)
101
- self.class.successful_response?(@last_response)
102
- end
103
-
104
- def new_record?
105
- !persisted?
106
- end
107
-
108
- def persisted?
109
- try(:id).present?
110
- end
111
-
112
- def to_partial_path
113
- class_name_plural = self.class.table_name
114
- "#{class_name_plural}/#{class_name_plural.singularize}"
115
- end
116
-
117
- def valid?
118
- errors.blank?
119
- end
120
-
121
- def invalid?
122
- !valid?
123
- end
124
-
125
- def hash_of_safe_content
126
- safe_hash = hash_of_full_content.dup
127
-
128
- if self.class.save_attr_white_list.present?
129
- safe_hash.slice!(*self.class.save_attr_white_list)
130
- else
131
- self.class.save_attr_black_list.each { |attribute| safe_hash.delete(attribute) }
132
- end
133
-
134
- safe_hash
135
- end
136
-
137
- private #-------------------------------------- private
138
-
139
- def create_or_update
140
- if new_record?
141
- self.class.post('', { self.class.model_name_downcase => hash_of_safe_content })
142
- else
143
- self.class.put(self.id, { self.class.model_name_downcase => hash_of_safe_content })
144
- end
145
- end
146
-
147
- def import_response_errors(response)
148
- if response.present? && response.parsed_response.include?('errors')
149
- self.errors = response.parsed_response['errors']
150
- end
151
- end
152
-
153
- end
154
- end
@@ -1,26 +0,0 @@
1
- require 'httparty'
2
-
3
- module SmoothOperator
4
- class ProtocolHandler
5
-
6
- include ::HTTParty
7
- format :json
8
-
9
- def self.get_options(options)
10
- { query: options }
11
- end
12
-
13
- def self.post_options(options)
14
- { body: options }
15
- end
16
-
17
- def self.put_options(options)
18
- { body: options }
19
- end
20
-
21
- def self.delete_options(options)
22
- { body: options }
23
- end
24
-
25
- end
26
- end