fast_curl 0.3.1 → 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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FastCurl
4
- VERSION = "0.3.1"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/fast_curl.rb CHANGED
@@ -1,13 +1,75 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
+ require 'uri'
4
5
  require_relative "fast_curl/version"
5
- require_relative "fast_curl/fast_curl"
6
6
 
7
7
  module FastCurl
8
8
  class Error < StandardError; end
9
9
  class TimeoutError < Error; end
10
10
 
11
+ class Headers < Hash
12
+ def [](key)
13
+ super(normalize(key))
14
+ end
15
+
16
+ def []=(key, value)
17
+ super(normalize(key), value)
18
+ end
19
+ alias store []=
20
+
21
+ def fetch(key, *args, &block)
22
+ super(normalize(key), *args, &block)
23
+ end
24
+
25
+ def key?(key)
26
+ super(normalize(key))
27
+ end
28
+ alias has_key? key?
29
+ alias include? key?
30
+ alias member? key?
31
+
32
+ def delete(key, &block)
33
+ super(normalize(key), &block)
34
+ end
35
+
36
+ def dig(key, *rest)
37
+ super(normalize(key), *rest)
38
+ end
39
+
40
+ def values_at(*keys)
41
+ super(*keys.map { |key| normalize(key) })
42
+ end
43
+
44
+ def assoc(key)
45
+ super(normalize(key))
46
+ end
47
+
48
+ def merge(*others, &block)
49
+ others.inject(dup) { |acc, other| acc.merge!(other, &block) }
50
+ end
51
+
52
+ def merge!(*others)
53
+ others.each do |other|
54
+ other.each do |key, value|
55
+ self[key] = block_given? && key?(key) ? yield(normalize(key), self[key], value) : value
56
+ end
57
+ end
58
+ self
59
+ end
60
+ alias update merge!
61
+
62
+ private
63
+
64
+ def normalize(key)
65
+ key.is_a?(String) || key.is_a?(Symbol) ? key.to_s.downcase : key
66
+ end
67
+ end
68
+ end
69
+
70
+ require_relative "fast_curl/fast_curl"
71
+
72
+ module FastCurl
11
73
  DEFAULT_OPTIONS = {
12
74
  connections: 20,
13
75
  timeout: 30
@@ -16,13 +78,18 @@ module FastCurl
16
78
  METHODS = %i[get post put delete patch].freeze
17
79
  BODY_METHODS = %i[post put patch].freeze
18
80
 
81
+ JSON_TYPE = "application/json"
82
+ FORM_TYPE = "application/x-www-form-urlencoded"
83
+ BINARY_TYPE = "application/octet-stream"
84
+
19
85
  class << self
20
86
  METHODS.each do |method|
21
87
  define_method(method) do |requests, **options|
22
88
  execute(build_requests(requests, method), **DEFAULT_OPTIONS.merge(options))
23
89
  end
24
90
 
25
- define_method(:"first_#{method}") do |requests, count: 1, **options|
91
+ define_method(:"first_#{method}") do |requests, count: 1, accept: nil, **options|
92
+ options[:accept] = accept unless accept.nil?
26
93
  first_execute(build_requests(requests, method), count: count, **DEFAULT_OPTIONS.merge(options))
27
94
  end
28
95
 
@@ -34,15 +101,71 @@ module FastCurl
34
101
  private
35
102
 
36
103
  def build_requests(requests, method)
37
- requests.map do |req|
38
- r = { url: req[:url], method: method.to_s.upcase }
39
- r[:headers] = req[:headers] if req[:headers]
40
- if req[:body] && BODY_METHODS.include?(method)
41
- r[:body] = req[:body].is_a?(Hash) ? req[:body].to_json : req[:body].to_s
42
- r[:headers] = (r[:headers] || {}).merge("Content-Type" => "application/json") if req[:body].is_a?(Hash)
104
+ source = requests.is_a?(Hash) ? [requests] : requests
105
+
106
+ if source.is_a?(Array)
107
+ source.map { |request| build_request(request, method) }
108
+ elsif source.respond_to?(:each)
109
+ Enumerator.new do |yielder|
110
+ source.each { |request| yielder << build_request(request, method) }
43
111
  end
44
- r
112
+ else
113
+ raise ArgumentError, "requests must be a Hash, Array or respond to #each"
45
114
  end
46
115
  end
116
+
117
+ def build_request(req, method)
118
+ raise ArgumentError, "request must be a Hash" unless req.is_a?(Hash)
119
+
120
+ r = { url: build_url(req), method: method.to_s.upcase }
121
+ headers = req[:headers] ? req[:headers].dup : nil
122
+
123
+ if BODY_METHODS.include?(method)
124
+ body, content_type = build_body(req)
125
+ if body
126
+ r[:body] = body
127
+ if content_type && !content_type?(headers)
128
+ headers ||= {}
129
+ headers["Content-Type"] = content_type
130
+ end
131
+ end
132
+ end
133
+
134
+ r[:headers] = headers if headers && !headers.empty?
135
+ r
136
+ end
137
+
138
+ def build_url(req)
139
+ url = req[:url]
140
+ params = req[:params]
141
+ return url if params.nil? || params.empty? || !url.is_a?(String)
142
+
143
+ separator = url.include?("?") ? "&" : "?"
144
+ "#{url}#{separator}#{URI.encode_www_form(params)}"
145
+ end
146
+
147
+ # Returns [body_string, default_content_type].
148
+ # json: {...} or "..." -> application/json
149
+ # form: {...} -> application/x-www-form-urlencoded
150
+ # body: "..." -> application/octet-stream (set your own type)
151
+ # body: {...} -> application/json (kept for backwards compatibility)
152
+ def build_body(req)
153
+ if req.key?(:json)
154
+ value = req[:json]
155
+ [value.is_a?(String) ? value : value.to_json, JSON_TYPE]
156
+ elsif req.key?(:form)
157
+ value = req[:form]
158
+ [value.is_a?(String) ? value : URI.encode_www_form(value), FORM_TYPE]
159
+ elsif req.key?(:body) && !req[:body].nil?
160
+ value = req[:body]
161
+ value.is_a?(Hash) ? [value.to_json, JSON_TYPE] : [value.to_s, BINARY_TYPE]
162
+ end
163
+ end
164
+
165
+ def content_type?(headers)
166
+ return false unless headers
167
+
168
+ headers.any? { |k, _| k.to_s.casecmp("content-type").zero? }
169
+ end
47
170
  end
48
171
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_curl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - roman-haidarov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-04-24 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: json
@@ -125,7 +124,6 @@ homepage: https://github.com/roman-haidarov/fast_curl
125
124
  licenses:
126
125
  - MIT
127
126
  metadata: {}
128
- post_install_message:
129
127
  rdoc_options: []
130
128
  require_paths:
131
129
  - lib
@@ -140,8 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
138
  - !ruby/object:Gem::Version
141
139
  version: '0'
142
140
  requirements: []
143
- rubygems_version: 3.3.27
144
- signing_key:
141
+ rubygems_version: 3.6.7
145
142
  specification_version: 4
146
143
  summary: Ultra-fast parallel HTTP client as Ruby C extension on libcurl multi
147
144
  test_files: []