http-client-generator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0e5c3210ef78433dbd893dd84ab971e11b72aa0485cafc8ba368e15f6f9b17ae
4
+ data.tar.gz: e4037a905331797ec6c6592b5e60fbdf4d21096f0145af079843036083ae7ece
5
+ SHA512:
6
+ metadata.gz: 243f6a23d704b53248ec48e5097c02a39127b6fd66bdda1b37cb61d2296b092c073a18544bc48f5fbf686e4ebcf202440f05361bfebd2c202158bb32fb1d8cc8
7
+ data.tar.gz: db2e2547997536e89ac232d5d78ddfa6fcfebe7d6a7d143c41a598040eabe906b9279be5465ee4254383af56f2744a924294ad71b5e33fdf27a969b532b21648
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Http::Client::Generator
2
+
3
+ TODO: Delete this and the text below, and describe your gem
4
+
5
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/http/client/generator`. To experiment with that code, run `bin/console` for an interactive prompt.
6
+
7
+ ## Installation
8
+
9
+ TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
10
+
11
+ Install the gem and add to the application's Gemfile by executing:
12
+
13
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
14
+
15
+ If bundler is not being used to manage dependencies, install the gem by executing:
16
+
17
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Development
24
+
25
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
26
+
27
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
28
+
29
+ ## Contributing
30
+
31
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/http-client-generator. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/http-client-generator/blob/master/CODE_OF_CONDUCT.md).
32
+
33
+ ## License
34
+
35
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
36
+
37
+ ## Code of Conduct
38
+
39
+ Everyone interacting in the Http::Client::Generator project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/http-client-generator/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HttpClientGenerator
4
+ class Plugs
5
+ class CamelizeBody
6
+ Plugs.register :camelize_body, self
7
+
8
+ def initialize(_); end
9
+
10
+ def call(req)
11
+ body =
12
+ if req.json? && req.body.is_a?(Hash)
13
+ req.body.deep_transform_keys { |key| key.to_s.camelize(:lower).to_sym }
14
+ else
15
+ req.body
16
+ end
17
+
18
+ req.body = body
19
+
20
+ req
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module HttpClientGenerator
6
+ class Plugs
7
+ class SetRequestid
8
+ Plugs.register :set_request_id, self
9
+
10
+ def initialize(header_name)
11
+ @header_name = header_name
12
+ end
13
+
14
+ def call(req)
15
+ req.headers[@header_name] = req.rest_args[:request_id] || SecureRandom.uuid
16
+ req
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HttpClientGenerator
4
+ class Plugs
5
+ class UnderscoreResponse
6
+ Plugs.register :underscore_response, self
7
+
8
+ def initialize(_); end
9
+
10
+ def call(req)
11
+ return req unless req.response_body.is_a?(Hash)
12
+
13
+ req.response_body = req.response_body.deep_transform_keys(&:underscore)
14
+
15
+ req
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HttpClientGenerator
4
+ class Plugs
5
+ include Singleton
6
+
7
+ def self.reqister(key, plug)
8
+ unless plug.respond_to?(:call)
9
+ raise "Plug should respond to #call got #{plug.inspect}"
10
+ end
11
+
12
+ instance.register(key, plug)
13
+ end
14
+
15
+ def self.read(key)
16
+ unless key.is_a?(Symbol)
17
+ raise "Expected symbol got #{key.inspect}"
18
+ end
19
+
20
+ instance.read(key)
21
+ end
22
+
23
+ def register(key, plug)
24
+ storage[key] = plug
25
+ end
26
+
27
+ def read(key)
28
+ storage[key]
29
+ end
30
+
31
+ private
32
+
33
+ def storage
34
+ @storage ||= {}
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'http'
4
+
5
+ module HttpClientGenerator
6
+ class Request
7
+ CONTENT_TYPES = %i[json text].freeze
8
+
9
+ DEFAULT_HEADERS_BY_CONTENT_TYPE = {
10
+ json: { accept: 'application/json', content_type: 'application/json' },
11
+ text: { content_type: 'text/plain' },
12
+ }.freeze
13
+
14
+ CONTENT_TYPES.each do |content_type|
15
+ define_method "#{content_type}?" do |request|
16
+ content_type == request.content_type
17
+ end
18
+ end
19
+
20
+ attr_accessor :verb, :content_type, :url, :headers, :body, :request_id, :response_body
21
+
22
+ def initialize(verb:, content_type:, url:, body:, rest_args:)
23
+ @verb = verb
24
+ @content_type = content_type
25
+ @url = url
26
+ @rest_args = rest_args
27
+ @body = body
28
+ @headers = {}
29
+ end
30
+
31
+ private
32
+
33
+ def default_headers
34
+ DEFAULT_HEADERS_BY_CONTENT_TYPE[content_type]
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HttpClientGenerator
4
+ class Resource
5
+ attr_reader :verb, :content_type, :name, :req_plugs, :resp_plugs
6
+
7
+ def initialize(verb:, content_type:, name:, req_plugs:, resp_plugs:)
8
+ @verb = verb
9
+ @content_type = content_type
10
+ @name = name
11
+ @req_plugs = req_plugs
12
+ @resp_plugs = resp_plugs
13
+ end
14
+
15
+ def perform_request(url_helper, base, url_options, body, rest_args)
16
+ request = prepare_request(url_helper, url_options, body, rest_args)
17
+
18
+ request_attributes = [request.verb, request.url]
19
+
20
+ if request.body
21
+ request.body = request.body.to_json if request.json?
22
+ request_attributes << { body: request.body }
23
+ end
24
+
25
+ request.response_body = HTTP[request.headers].public_send(*request_attributes).to_s
26
+
27
+ process_response(request)
28
+ rescue HTTP::Error => e
29
+ raise base::RequestError, e.message, e.backtrace, cause: nil
30
+ end
31
+
32
+ private
33
+
34
+ def prepare_request(url_helper, url_options, body, rest_args)
35
+ url = url_helper.public_send(:"#{name}", url_options)
36
+
37
+ request = Request.new(
38
+ verb: verb, url: url, content_type: content_type, body: body, rest_args: rest_args
39
+ )
40
+
41
+ req_plugs.reduce(request) { |req, plug| plug.call(req) }
42
+ end
43
+
44
+ def process_response(request)
45
+ request.response_body =
46
+ begin
47
+ request.response_body = JSON.parse(request.response_body, symbolize_names: true)
48
+ rescue JSON::ParserError
49
+ request.response_body
50
+ end
51
+
52
+ resp_plugs.reduce(request) { |req, plug| plug.call(req) }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HttpClientGenerator
4
+ class ResourcesDefinition
5
+ attr_reader :resources
6
+
7
+ DEFAULT_OPTIONS = {
8
+ content_type: :json
9
+ }.freeze
10
+
11
+ HTTP_VERBS = %i[get post put patch].freeze
12
+
13
+ def initialize(req_plugs = [], resp_plugs = [])
14
+ @resources = []
15
+ @req_plugs = req_plugs
16
+ @resp_plugs = resp_plugs
17
+ end
18
+
19
+ HTTP_VERBS.each do |verb|
20
+ define_method(verb) do |name, **options|
21
+ @resources << build_resource(verb, name, options)
22
+ end
23
+ end
24
+
25
+ def req_plug(plug, *args, **kwargs)
26
+ @req_plugs <<
27
+ if plug.respond_to?(:call)
28
+ plug
29
+ else if plug.respond_to?(:new)
30
+ plug.new(*args, **kwargs)
31
+ else
32
+ Plugs.read(plug).new(*args, **kwargs)
33
+ end
34
+ end
35
+
36
+ def resp_plug(plug, *args, **kwargs)
37
+ @resp_plugs <<
38
+ if plug.respond_to?(:call)
39
+ plug
40
+ else if plug.respond_to?(:new)
41
+ plug.new(*args, **kwargs)
42
+ else
43
+ Plugs.read(plug).new(*args, **kwargs)
44
+ end
45
+ end
46
+
47
+ def namespace(_name, &block)
48
+ namespaced_definition = ResourcesDefinition.new(req_plugs, resp_plugs)
49
+ namespaced_definition.instance_eval(&block)
50
+ @resources << namespaced_definition.resources
51
+ end
52
+
53
+ private
54
+
55
+ def build_resource(verb, name, options)
56
+ Resource.new(
57
+ verb: verb, name: name, req_plugs: @req_plugs, resp_plugs: @resp_plugs, **with_defaults(options)
58
+ )
59
+ end
60
+
61
+ def with_defaults(options)
62
+ DEFAULT_OPTIONS.merge(options)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HttpClientGenerator
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ Zeitwerk::Loader.for_gem.setup
4
+
5
+ module HttpClientGenerator
6
+ def self.included(base)
7
+ super
8
+
9
+ base.extend(self)
10
+ base.const_set(:Error, Class.new(StandardError))
11
+ base.const_set(:RequestError, Class.new(base::Error))
12
+ end
13
+
14
+ def url_helper(module_name)
15
+ @url_helper = module_name
16
+ end
17
+
18
+ def resources(&block)
19
+ resources_definition = ResourcesDefinition.new
20
+ resources_definition.instance_eval(&block)
21
+ resources = resources_definition.resources
22
+
23
+ resources.each do |resource|
24
+ method_name = :"#{resource.name}_#{resource.verb}"
25
+
26
+ define_singleton_method(method_name) do |url_options = {}, body: nil, **rest_args|
27
+ resource.perform_request(@url_helper, @base, url_options, body, rest_args)
28
+ end
29
+ end
30
+ end
31
+
32
+ def configure(&configure)
33
+ @config = self.class::Configuration.new
34
+ .tap(&configure)
35
+ .tap { |c| user_process_config(c) if respond_to?(:user_process_config) }
36
+ .tap(&:freeze)
37
+ end
38
+
39
+ def process_config(&block)
40
+ define_singleton_method(:user_process_config, block)
41
+ end
42
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http-client-generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Egorov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: http
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: zeitwerk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.6'
41
+ description: Ruby Http Client generator
42
+ email:
43
+ - moonmeander47@ya.ru
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - README.md
49
+ - lib/http_client_generator.rb
50
+ - lib/http_client_generator/plugs.rb
51
+ - lib/http_client_generator/plugs/camelize_body.rb
52
+ - lib/http_client_generator/plugs/set_request_id.rb
53
+ - lib/http_client_generator/plugs/underscore_response.rb
54
+ - lib/http_client_generator/request.rb
55
+ - lib/http_client_generator/resource.rb
56
+ - lib/http_client_generator/resources_definition.rb
57
+ - lib/http_client_generator/version.rb
58
+ homepage:
59
+ licenses: []
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '3.1'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.4.19
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Ruby Http Client generator
80
+ test_files: []