luna_park 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.overcommit.yml +18 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +106 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +6 -0
  9. data/CHANGELOG.md +308 -0
  10. data/Gemfile +8 -0
  11. data/Gemfile.lock +182 -0
  12. data/LICENSE +21 -0
  13. data/LICENSE.txt +21 -0
  14. data/README.md +54 -0
  15. data/Rakefile +30 -0
  16. data/bin/console +15 -0
  17. data/bin/setup +8 -0
  18. data/docs/.nojekyll +0 -0
  19. data/docs/CNAME +1 -0
  20. data/docs/README.md +190 -0
  21. data/docs/_coverpage.md +18 -0
  22. data/docs/_imgs/adapter.png +0 -0
  23. data/docs/_imgs/bender.jpeg +0 -0
  24. data/docs/_imgs/bender_header.jpeg +0 -0
  25. data/docs/_imgs/collecting.png +0 -0
  26. data/docs/_imgs/conductor_schema.png +0 -0
  27. data/docs/_imgs/ddd_header.jpeg +0 -0
  28. data/docs/_imgs/ddd_map.png +0 -0
  29. data/docs/_imgs/domain_context.jpeg +0 -0
  30. data/docs/_imgs/drunk_master.jpg +0 -0
  31. data/docs/_imgs/full_map.png +0 -0
  32. data/docs/_imgs/full_map_hight_res.png +0 -0
  33. data/docs/_imgs/graph_1.png +0 -0
  34. data/docs/_imgs/graph_2.jpg +0 -0
  35. data/docs/_imgs/graph_3.png +0 -0
  36. data/docs/_imgs/graph_4.jpg +0 -0
  37. data/docs/_imgs/graph_5.jpg +0 -0
  38. data/docs/_imgs/graph_5.png +0 -0
  39. data/docs/_imgs/processing.png +0 -0
  40. data/docs/_imgs/representation.png +0 -0
  41. data/docs/_imgs/storage.png +0 -0
  42. data/docs/_imgs/tourtle_context_map.png +0 -0
  43. data/docs/_imgs/tree.png +0 -0
  44. data/docs/_imgs/wm.jpeg +0 -0
  45. data/docs/_media/bender.jpg +0 -0
  46. data/docs/_media/black_cover.jpg +0 -0
  47. data/docs/_media/logo.svg +7 -0
  48. data/docs/_sidebar.md +9 -0
  49. data/docs/architecture.md +214 -0
  50. data/docs/google48f1e6f5c35eae5f.html +1 -0
  51. data/docs/index.html +32 -0
  52. data/docs/methodology.md +376 -0
  53. data/docs/patterns/entity.md +193 -0
  54. data/docs/patterns/sequence.md +332 -0
  55. data/docs/patterns/service.md +280 -0
  56. data/docs/patterns/value.md +197 -0
  57. data/docs/way.md +66 -0
  58. data/lib/luna_park.rb +72 -0
  59. data/lib/luna_park/callable.rb +7 -0
  60. data/lib/luna_park/entities/attributable.rb +18 -0
  61. data/lib/luna_park/entities/nested.rb +28 -0
  62. data/lib/luna_park/entities/simple.rb +39 -0
  63. data/lib/luna_park/errors.rb +16 -0
  64. data/lib/luna_park/errors/base.rb +244 -0
  65. data/lib/luna_park/errors/business.rb +9 -0
  66. data/lib/luna_park/errors/http.rb +90 -0
  67. data/lib/luna_park/errors/json_parse.rb +11 -0
  68. data/lib/luna_park/errors/system.rb +9 -0
  69. data/lib/luna_park/extensions/attributable.rb +26 -0
  70. data/lib/luna_park/extensions/callable.rb +44 -0
  71. data/lib/luna_park/extensions/comparable.rb +90 -0
  72. data/lib/luna_park/extensions/comparable_debug.rb +96 -0
  73. data/lib/luna_park/extensions/data_mapper.rb +195 -0
  74. data/lib/luna_park/extensions/dsl/attributes.rb +135 -0
  75. data/lib/luna_park/extensions/dsl/foreign_key.rb +97 -0
  76. data/lib/luna_park/extensions/exceptions/substitutive.rb +83 -0
  77. data/lib/luna_park/extensions/has_errors.rb +125 -0
  78. data/lib/luna_park/extensions/injector.rb +189 -0
  79. data/lib/luna_park/extensions/injector/dependencies.rb +74 -0
  80. data/lib/luna_park/extensions/predicate_attr_accessor.rb +23 -0
  81. data/lib/luna_park/extensions/repositories/postgres/create.rb +20 -0
  82. data/lib/luna_park/extensions/repositories/postgres/delete.rb +15 -0
  83. data/lib/luna_park/extensions/repositories/postgres/read.rb +63 -0
  84. data/lib/luna_park/extensions/repositories/postgres/update.rb +21 -0
  85. data/lib/luna_park/extensions/serializable.rb +99 -0
  86. data/lib/luna_park/extensions/severity_levels.rb +120 -0
  87. data/lib/luna_park/extensions/typed_attr_accessor.rb +26 -0
  88. data/lib/luna_park/extensions/validatable.rb +80 -0
  89. data/lib/luna_park/extensions/validatable/dry.rb +24 -0
  90. data/lib/luna_park/extensions/wrappable.rb +43 -0
  91. data/lib/luna_park/forms/simple.rb +63 -0
  92. data/lib/luna_park/forms/single_item.rb +74 -0
  93. data/lib/luna_park/handlers/simple.rb +17 -0
  94. data/lib/luna_park/http/client.rb +328 -0
  95. data/lib/luna_park/http/request.rb +225 -0
  96. data/lib/luna_park/http/response.rb +381 -0
  97. data/lib/luna_park/http/send.rb +103 -0
  98. data/lib/luna_park/mappers/simple.rb +92 -0
  99. data/lib/luna_park/notifiers/bugsnag.rb +48 -0
  100. data/lib/luna_park/notifiers/log.rb +174 -0
  101. data/lib/luna_park/notifiers/sentry.rb +50 -0
  102. data/lib/luna_park/repositories/postgres.rb +38 -0
  103. data/lib/luna_park/repositories/sequel.rb +11 -0
  104. data/lib/luna_park/repository.rb +9 -0
  105. data/lib/luna_park/serializers/simple.rb +28 -0
  106. data/lib/luna_park/tools.rb +19 -0
  107. data/lib/luna_park/use_cases/scenario.rb +325 -0
  108. data/lib/luna_park/use_cases/service.rb +13 -0
  109. data/lib/luna_park/validators/dry.rb +67 -0
  110. data/lib/luna_park/values/attributable.rb +21 -0
  111. data/lib/luna_park/values/compound.rb +26 -0
  112. data/lib/luna_park/values/single.rb +35 -0
  113. data/lib/luna_park/version.rb +5 -0
  114. data/luna_park.gemspec +54 -0
  115. data/node_modules/.yarn-integrity +12 -0
  116. data/package-lock.json +3 -0
  117. data/yarn.lock +4 -0
  118. metadata +414 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LunaPark
4
+ module Extensions
5
+ module TypedAttrAccessor
6
+ def typed_attr_accessor(*names, callable, is_array: false)
7
+ attr_reader(*names)
8
+ typed_attr_writer(*names, callable, is_array: is_array)
9
+ end
10
+
11
+ def typed_attr_writer(*names, callable, is_array: false)
12
+ return attr_writer(*names) if callable.nil?
13
+
14
+ names.each do |name|
15
+ setter = :"#{name}="
16
+ ivar = :"@#{name}"
17
+ if is_array
18
+ define_method(setter) { |input| instance_variable_set(ivar, input&.map { |elem| callable.call(elem) }) }
19
+ else
20
+ define_method(setter) { |input| instance_variable_set(ivar, callable.call(input)) }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LunaPark
4
+ module Extensions
5
+ # @example
6
+ # class MyForm
7
+ # include LunaPark::Extensions::Validatable
8
+ #
9
+ # validator MyValidator # must respond_to #errors, #success?, #valid_params, .validate
10
+ #
11
+ # def initialize(params)
12
+ # @params = params
13
+ # end
14
+ #
15
+ # def data
16
+ # OpenStruct.new(valid_params) if valid?
17
+ # end
18
+ #
19
+ # private
20
+ #
21
+ # attr_reader :params # define abstract method
22
+ # end
23
+ #
24
+ # form = MyForm.new(foo: 'Foo')
25
+ # form.valid? # => false
26
+ # form.validation_errors # => { bar: ['is missing'] }
27
+ # form.data # => nil
28
+ #
29
+ # form = MyForm.new(foo: 'Foo', bar: 'Bar')
30
+ # form.valid? # => true
31
+ # form.data # => #<OpenStruct foo="Foo" bar="Bar" }
32
+ module Validatable
33
+ def self.included(klass)
34
+ klass.include InstanceMethods
35
+ klass.extend ClassMethods
36
+ super
37
+ end
38
+
39
+ module InstanceMethods
40
+ def validation_errors_array
41
+ validation ? validation.errors_array : {}
42
+ end
43
+
44
+ def validation_errors_tree
45
+ validation ? validation.errors_tree : []
46
+ end
47
+
48
+ def validation_errors
49
+ validation ? validation.errors : {}
50
+ end
51
+
52
+ def valid?
53
+ validation ? validation.success? : true
54
+ end
55
+
56
+ private
57
+
58
+ def valid_params
59
+ validation ? validation.valid_params : params
60
+ end
61
+
62
+ def validation
63
+ @validation ||= self.class.validator.validate(params)
64
+ end
65
+
66
+ # :nocov:
67
+ def params
68
+ raise Errors::AbstractMethod
69
+ end
70
+ # :nocov:
71
+ end
72
+
73
+ module ClassMethods
74
+ def validator(klass = nil)
75
+ klass.nil? ? @validator : @validator = klass
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/validators/dry'
4
+
5
+ module LunaPark
6
+ module Extensions
7
+ module Validatable
8
+ module Dry
9
+ def self.included(base)
10
+ base.include Validatable
11
+ base.extend self
12
+ end
13
+
14
+ def validator(klass = nil, &block)
15
+ return super unless block_given?
16
+
17
+ klass = Class.new(Validators::Dry)
18
+ klass.validation_schema(&block)
19
+ super(klass)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/errors'
4
+
5
+ module LunaPark
6
+ module Extensions
7
+ ##
8
+ # class-level mixin
9
+ #
10
+ # @example
11
+ # class Account
12
+ # extend LunaPark::Extensions::Wrappable
13
+ #
14
+ # attr_reader :type, :id
15
+ #
16
+ # def initialize(type:, id:)
17
+ # @type, @id = type, id
18
+ # end
19
+ # end
20
+ #
21
+ # hash = { type: 'user', id: 42 }
22
+ # acccount = Account.new(hash)
23
+ #
24
+ # Account.new(hash) # => #<Account type='user', id=42>
25
+ # Account.new(acccount) # => raise ArgumentError
26
+ # Account.wrap(hash) # => #<Account type='user', id=42>
27
+ # Account.wrap(acccount) # => #<Account type='user', id=42>
28
+ # Account.wrap(nil) # => nil
29
+ # Account.wrap(true) # => raise 'Account can not wrap TrueClass'
30
+ #
31
+ # Account.wrap(account).eql?(account) # => true
32
+ module Wrappable
33
+ def wrap(input)
34
+ case input
35
+ when self then input
36
+ when Hash then new(input)
37
+ when nil then nil
38
+ else raise Errors::Unwrapable, "#{self} can not wrap #{input.class}"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/extensions/validatable'
4
+ require 'luna_park/errors'
5
+
6
+ module LunaPark
7
+ module Forms
8
+ ##
9
+ # Form object represents blank document, required to filled right, and can be performed
10
+ #
11
+ # @example
12
+ # class MyForm < LunaPark::Forms::SingleItem
13
+ # validation MyValidator # respond to .validate, #valid?, #errors, #valid_params
14
+ #
15
+ # def perform(valid_params)
16
+ # "Performed #{valid_params[:foo_bar]}"
17
+ # end
18
+ # end
19
+ #
20
+ # form = MyForm.new({ foo_bar: 'FooBar' })
21
+ #
22
+ # if form.submit
23
+ # form.result # => 'Performed FooBar'
24
+ # else
25
+ # form.errors # => { foo_bar: ['is wrong'] }
26
+ # end
27
+ class Simple
28
+ include Extensions::Validatable
29
+
30
+ attr_reader :result
31
+
32
+ def initialize(params = {})
33
+ @params = params
34
+ end
35
+
36
+ def submit
37
+ if valid?
38
+ perform!
39
+ true
40
+ else false
41
+ end
42
+ end
43
+
44
+ alias errors validation_errors
45
+
46
+ private
47
+
48
+ attr_reader :params
49
+
50
+ def perform!
51
+ @result = perform(valid_params)
52
+ end
53
+
54
+ # :nocov:
55
+
56
+ # @abstract
57
+ def perform(_valid_params)
58
+ raise Errors::AbstractMethod
59
+ end
60
+ # :nocov:
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/extensions/validatable'
4
+ require 'luna_park/extensions/attributable'
5
+ require 'luna_park/errors'
6
+
7
+ module LunaPark
8
+ module Forms
9
+ ##
10
+ # Form object represents blank document, required to filled right, and can be performed
11
+ #
12
+ # @example
13
+ # class MyForm < LunaPark::Forms::SingleItem
14
+ # validator MyValidator # respond to .validate, #valid?, #validation_errors, #valid_params
15
+ #
16
+ # def perform
17
+ # 'PerformResult'
18
+ # end
19
+ #
20
+ # def foo_bar=(foo_bar)
21
+ # @foo_bar = foo_bar
22
+ # end
23
+ # end
24
+ #
25
+ # form = MyForm.new({ foo_bar: {} })
26
+ #
27
+ # if form.submit
28
+ # form.result # => 'PerformResult'
29
+ # else
30
+ # form.errors # => { foo_bar: ['is wrong'] }
31
+ # end
32
+ class SingleItem
33
+ include Extensions::Attributable
34
+ include Extensions::Validatable
35
+
36
+ attr_reader :result
37
+
38
+ def initialize(params = {})
39
+ @params = params
40
+ end
41
+
42
+ def submit
43
+ if valid?
44
+ fill!
45
+ perform!
46
+ true
47
+ else false
48
+ end
49
+ end
50
+
51
+ alias errors validation_errors
52
+
53
+ private
54
+
55
+ attr_reader :params
56
+
57
+ def fill!
58
+ set_attributes valid_params
59
+ end
60
+
61
+ def perform!
62
+ @result = perform
63
+ end
64
+
65
+ # :nocov:
66
+
67
+ # @abstract
68
+ def perform
69
+ raise Errors::AbstractMethod
70
+ end
71
+ # :nocov:
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/errors'
4
+
5
+ module LunaPark
6
+ module Handlers
7
+ class Simple
8
+ # :nocov:
9
+
10
+ # @abstract
11
+ def self.catch
12
+ raise Errors::AbstractMethod
13
+ end
14
+ # :nocov:
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,328 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'luna_park/http/request'
4
+ require 'luna_park/http/response'
5
+ require 'luna_park/http/send'
6
+
7
+ module LunaPark
8
+ module Http
9
+ # Client are useful for organize a repository where the source of the date is the http-server,
10
+ # you should to inherit from this class. And interpret all the necessary endpoints as logical methods.
11
+ #
12
+ # <b>For example</b>:
13
+ # You have api endpoint, which get list of all users (GET http://api.example.com/users),
14
+ # as part of json api. Then you should define `Client` in your `Users` domain and
15
+ # define `all` method which get list of all users.
16
+ #
17
+ # module Users
18
+ # class Client < LunaPark::Http::Client
19
+ # def all
20
+ # response = get! json_request(
21
+ # title: 'Get users',
22
+ # url: 'http://api.example.com/users',
23
+ # )
24
+ # response.json_parse || []
25
+ # end
26
+ # end
27
+ # end
28
+ #
29
+ # == Handle errors in the simple way
30
+ #
31
+ # But how to handle http errors? You have two ways: simple and flexible. In first case
32
+ # you realize all request with bang-methods (get!, post!, put!, etc.). And if something
33
+ # went wrong client raise {LunaPark::Errors::Http} exception.
34
+ #
35
+ # # Server is unavailable
36
+ # client = Users::Clients.new
37
+ # client.all # => raise LunaPark::Errors::Http (Service Unavailable)
38
+ # # And your clients will see server error.
39
+ #
40
+ # == Handle errors in the flexible way
41
+ #
42
+ # But if you have different cases based on different HTTP codes, you should choose
43
+ # flexible way.
44
+ #
45
+ # <b>For example</b>:
46
+ # You develop application for a delivery service. And you should realize Orders domain.
47
+ # The Orders domain makes payment requests to the microservice responsible for transactions.
48
+ #
49
+ # Transactions microservice on payment endpoint has four uses cases, based on Http codes:
50
+ # - 201 - payment is successfully created.
51
+ # - 400 - request, has wrong structure, validation error.
52
+ # - 422 - business logic error (small balance for example).
53
+ # {"error":"Not enough funds in your account"}
54
+ # - 500 - server error
55
+ # Your transaction service client should process this code is:
56
+ # - 200 - return true
57
+ # - 422 - forward business logic error message to your customer
58
+ # - in others ways show server error to your client, and you your should notify developers about that.
59
+ #
60
+ # @example
61
+ # module Payments
62
+ # class Client < LunaPark::Http::Client
63
+ # def create(account:, money:)
64
+ # response = post json_request(
65
+ # title: 'Make payment for order',
66
+ # url: 'http://api.transactions.example.com/payments',
67
+ # data: {account: account, money: money}
68
+ # )
69
+ # case response.code
70
+ # when 200 then true
71
+ # when 422 then raise Error::Business.new(response.body.parse_json(payload_key: error), action: :catch)
72
+ # else raise Errors::Http.new(response.status, notify: true, response: response)
73
+ # end
74
+ # end
75
+ # end
76
+ # end
77
+ #
78
+ # # In your checkout scenario, payment is being made
79
+ # module Orders
80
+ # module Scenarios
81
+ # class Checkout < LunaPark::UseCases::Scenario
82
+ # def call!
83
+ # # ...
84
+ # payments.create(account: 42, money: Values::Money.new(100, :usd))
85
+ # # ...
86
+ # end
87
+ # end
88
+ # end
89
+ # end
90
+ #
91
+ # # In endpoint, if the client does not have enough money on his balance
92
+ # checkout.call
93
+ # checkout.success? # => false
94
+ # checkout.fail_message # => "Not enough funds in your account"
95
+ class Client
96
+ DEFAULT_OPEN_TIMEOUT = 60
97
+ DEFAULT_READ_TIMEOUT = 60
98
+ DEFAULT_DRIVER = LunaPark::Http::Send
99
+ DEFAULT_METHOD = :get
100
+ # Build plain request
101
+ #
102
+ # @param [String] title business description for request
103
+ # @param [String] url request url
104
+ # @param [String,Symbol] method http method (get, post, etc)
105
+ # @param [NilClass,String] body http request body
106
+ # @param [Hash] headers http headers
107
+ #
108
+ # @example
109
+ # request = form_request(
110
+ # title: 'get users list',
111
+ # url: 'http://api.example.com/users'
112
+ # )
113
+ #
114
+ # request # => <LunaPark::Http::Request @title="get users list"
115
+ # # @url="http://api.example.com/users" @method="get"
116
+ # # @headers={ 'Content-Type' => 'application/x-www-form-urlencoded' }
117
+ # # @body="" @sent_at="">
118
+ #
119
+ # @return [LunaPark::Http::Request]
120
+ # rubocop:disable Metrics/ParameterLists
121
+ def form_request(title:, url:, method: nil, body: nil, headers: nil, data: nil, **opts)
122
+ form_body = body || data # * we have no a good generator for `x-www-form-urlencoded` type, but Driver has
123
+
124
+ build_request(
125
+ title: title,
126
+ url: url,
127
+ method: method,
128
+ body: form_body,
129
+ headers: headers,
130
+ content_type: 'application/x-www-form-urlencoded',
131
+ **opts
132
+ )
133
+ end
134
+ # rubocop:enable Metrics/ParameterLists
135
+
136
+ # Build form request. Body will convert to json format automatically.
137
+ #
138
+ # @param [String] title business description for request
139
+ # @param [String] url request url
140
+ # @param [String,Symbol] method http method (get, post, etc)
141
+ # @param [NilClass,String,Hash] body http request body
142
+ # @param [Hash] headers http headers
143
+ #
144
+ # @example
145
+ # request = json_request(
146
+ # title: 'Ping pong',
147
+ # url: 'http://api.example.com/ping',
148
+ # data: { message: 'ping' }
149
+ # )
150
+ #
151
+ # request # => <LunaPark::Http::Request
152
+ # # @title="Ping pong"
153
+ # # @url="http://api.example.com/ping" @method="get"
154
+ # # @headers={ 'Content-Type' => 'application/json' }
155
+ # # @body="{"message":"ping"}" @sent_at=""
156
+ # # >
157
+ #
158
+ # @return [LunaPark::Http::Request]
159
+ # rubocop:disable Metrics/ParameterLists
160
+ def json_request(title:, url:, method: nil, body: nil, data: nil, headers: nil, **opts)
161
+ json_body = body || data && JSON.generate(data)
162
+
163
+ build_request(
164
+ title: title,
165
+ url: url,
166
+ method: method,
167
+ body: json_body,
168
+ headers: headers,
169
+ content_type: 'application/json',
170
+ **opts
171
+ )
172
+ end
173
+ # rubocop:enable Metrics/ParameterLists
174
+
175
+ # Send GET request. Always return response even if the response is not successful.
176
+ #
177
+ # @example success response
178
+ # get json_request(title: 'Hi world', url: 'http://example.com/hi')
179
+ # # => <LunaPark::Http::Response @code=200
180
+ # # @body="{"version":1,"data":"Hello World!"}" @headers={:content_type=>"application/json",
181
+ # # :connection=>"close", :server=>"thin"} @cookies={}>
182
+ #
183
+ # @example server is unavailable
184
+ # get json_request(title: 'Hi world', url: 'http://example.com/hi')
185
+ # # => <LunaPark::Http::Response @code=503
186
+ # # @body="" @headers={} @cookies={}>
187
+ #
188
+ # @return [LunaPark::Http::Response]
189
+ def get(request)
190
+ request.method = :get
191
+ request.call
192
+ end
193
+
194
+ # Send POST request. Always return response even if the response is not successful.
195
+ # @see #get
196
+ def post(request)
197
+ request.method = :post
198
+ request.call
199
+ end
200
+
201
+ # Send PUT request. Always return response even if the response is not successful.
202
+ # @see #get
203
+ def put(request)
204
+ request.method = :put
205
+ request.call
206
+ end
207
+
208
+ # Send PATCH request. Always return response even if the response is not successful.
209
+ # @see #get
210
+ def patch(request)
211
+ request.method = :patch
212
+ request.call
213
+ end
214
+
215
+ # Send DELETE request. Always return response even if the response is not successful.
216
+ # @see #get
217
+ def delete(request)
218
+ request.method = :delete
219
+ request.call
220
+ end
221
+
222
+ # Send GET request. Raise {LunaPark::Errors::Http} on bad response.
223
+ #
224
+ # @example success response
225
+ # get json_request(title: 'Hi world', url: 'http://example.com/hi')
226
+ # # => <LunaPark::Http::Response @code=200
227
+ # # @body="{"version":1,"data":"Hello World!"}" @headers={:content_type=>"application/json",
228
+ # # :connection=>"close", :server=>"thin"} @cookies={}>
229
+ #
230
+ # @example server is unavailable
231
+ # get json_request(title: 'Hi world', url: 'http://example.com/hi')
232
+ # # => raise LunaPark::Errors::Http
233
+ #
234
+ # @raise [LunaPark::Errors::Http] on bad response, timeout or server is unavailable
235
+ # @return [LunaPark::Http::Response]
236
+ def get!(request)
237
+ request.method = :get
238
+ request.call!
239
+ end
240
+
241
+ # Send POST request. Raise {LunaPark::Errors::Http} on bad response.
242
+ # @see #get!
243
+ def post!(request)
244
+ request.method = :post
245
+ request.call!
246
+ end
247
+
248
+ # Send PUT request. Raise {LunaPark::Errors::Http} on bad response.
249
+ # @see #get!
250
+ def put!(request)
251
+ request.method = :put
252
+ request.call!
253
+ end
254
+
255
+ # Send PATCh request. Raise {LunaPark::Errors::Http} on bad response.
256
+ # @see #get!
257
+ def patch!(request)
258
+ request.method = :patch
259
+ request.call!
260
+ end
261
+
262
+ # Send DELETE request. Raise {LunaPark::Errors::Http} on bad response.
263
+ # @see #get!
264
+ def delete!(request)
265
+ request.method = :delete
266
+ request.call!
267
+ end
268
+
269
+ private
270
+
271
+ def build_request(title:, url:, method: nil, body: nil, headers: nil, content_type: nil, open_timeout: nil, read_timeout: nil, driver: nil) # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
272
+ headers ||= {}
273
+ headers['Content-Type'] = content_type || 'text/plain'
274
+
275
+ # rubocop:disable Layout/HashAlignment
276
+ Request.new(
277
+ title: title,
278
+ url: url.to_s, # TODO: Use {LunaPark::Tools::URI} with @query
279
+ method: method || DEFAULT_METHOD,
280
+ body: body,
281
+ headers: headers,
282
+ open_timeout: open_timeout || self.class.open_timeout,
283
+ read_timeout: read_timeout || self.class.read_timeout,
284
+ driver: driver || self.class.driver
285
+ )
286
+ # rubocop:enable Layout/HashAlignment
287
+ end
288
+
289
+ class << self
290
+ # Set default diver for this Client
291
+ #
292
+ # @example set driver
293
+ # class Users < Client
294
+ # driver URI::Send
295
+ # end
296
+ #
297
+ # Foobar.driver # => URI::Send
298
+ def driver(driver = nil)
299
+ driver.nil? ? @driver || DEFAULT_DRIVER : @driver = driver
300
+ end
301
+
302
+ # Set default open_timeout for this Client
303
+ #
304
+ # @example set open_timeout
305
+ # class Users < Client
306
+ # open_timeout URI::Send
307
+ # end
308
+ #
309
+ # Foobar.open_timeout # => URI::Send
310
+ def open_timeout(timeout = nil)
311
+ timeout.nil? ? @open_timeout || DEFAULT_OPEN_TIMEOUT : @open_timeout = timeout
312
+ end
313
+
314
+ # Set default read_timeout for this Client
315
+ #
316
+ # @example set read_timeout
317
+ # class Users < Client
318
+ # read_timeout URI::Send
319
+ # end
320
+ #
321
+ # Foobar.read_timeout # => URI::Send
322
+ def read_timeout(timeout = nil)
323
+ timeout.nil? ? @read_timeout || DEFAULT_READ_TIMEOUT : @read_timeout = timeout
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end