yobi-http 0.14.0 → 0.16.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42bdd81cec29bd949acd4b1a96698e219bc6298a71eced3aa36c8cee4b965dc4
4
- data.tar.gz: f0cf545e7c5d13f5543dbbfa63e72d563d03afc12d74cdbd45c47479f14064a6
3
+ metadata.gz: 3558906f242a7670158833610ad7b062bf25e308e4985804241bdba30a9d6968
4
+ data.tar.gz: d96e600ccdf03ebcddb0c9ce14a3a2c141fb1a1ba2ffe04ee7cdb0a1a5383c7d
5
5
  SHA512:
6
- metadata.gz: bf2635eba8c559e6459d638dd944d315cb571833d60cffa208a7629d4d07110c86a39ac924b18639e3e94381575ea2cdbf039c70e9186006f69f11f889a8ae30
7
- data.tar.gz: 98f048dbbf3512cb34782e14d26f737a06ea6ce68ca75ab2df13b158d5a8b8f00e9d7a0f7d08b0518254559ca587ee6bc5114bed543b61522816387ccab9a8be
6
+ metadata.gz: 68ec04f8b731ebc0e9f508ed332d6414292963d1dbbd97aaba96a360e930ce3d1421812d11c1031305126633db9ad012fb2f4efa6e170aba4e09e3eeef37cf3e
7
+ data.tar.gz: 61c69a1bfdc761df2c791396fb84a3ce5183bf24b71ffb4073fbebdbd1e86b3e5e6986fbeeb977a7c2225624d72d083270e585e0afe186030066b3dab05f0e6c
data/exe/yobi CHANGED
@@ -16,7 +16,7 @@ require "yobi"
16
16
  # parsing arguments
17
17
  @options = {
18
18
  print: "HB", auth: nil, auth_type: "basic", verbose: false, raw: false, offline: false, follow: false, debug: false,
19
- timeout: nil, download: false
19
+ timeout: nil, download: false, output: nil, content_type: :json
20
20
  }
21
21
 
22
22
  parser = OptionParser.new do |opts|
@@ -28,7 +28,7 @@ parser = OptionParser.new do |opts|
28
28
 
29
29
  Examples:
30
30
  yobi https://api.example.com/users
31
- yobi POST https://api.example.com/users name=John age=30
31
+ yobi POST https://api.example.com/products name="New Product" price:=19.99 enabled:=true tags:=@tags.json
32
32
  yobi GET :8080/api/items Authorization:"Bearer $TOKEN"
33
33
  yobi -A basic -a user:pass https://api.example.com/secure-data
34
34
  yobi --raw --print B POST https://httpbin.org/anything | jq '.headers["User-Agent"]'
@@ -53,6 +53,27 @@ parser = OptionParser.new do |opts|
53
53
  @options[:raw] = true
54
54
  end
55
55
 
56
+ opts.on("--form", "Send data as application/x-www-form-urlencoded instead of JSON") do
57
+ @options[:content_type] = :form
58
+ end
59
+
60
+ opts.on("--multipart", "Send data as multipart/form-data instead of JSON") do
61
+ @options[:content_type] = :multipart
62
+ end
63
+
64
+ opts.on("--xml", "Send data as application/xml instead of JSON") do
65
+ @options[:content_type] = :xml
66
+ end
67
+
68
+ opts.on("--binary", "Send data as application/octet-stream instead of JSON") do
69
+ @options[:content_type] = :binary
70
+ end
71
+
72
+ opts.on("--json", "Send data as application/json (default)") do
73
+ # This option is implicit since JSON is the default, but we can set it explicitly if needed
74
+ @options[:content_type] = :json
75
+ end
76
+
56
77
  opts.on("-h", "--help", "Print this help message") do
57
78
  puts opts
58
79
  exit
@@ -101,13 +122,14 @@ method = Yobi.args.http_method?(ARGV[0]) ? ARGV.shift : "GET"
101
122
  # resolve the URL
102
123
  url = Yobi.args.url(ARGV.shift)
103
124
 
104
- data = Yobi.args.parse_data(ARGV)
105
- headers = Yobi.args.parse_headers(ARGV)
125
+ data = Yobi.args.parse_data(ARGV, @options)
126
+ query = Yobi.args.parse_query(ARGV, @options)
127
+ headers = Yobi.args.parse_headers(ARGV, @options)
106
128
 
107
129
  # prepare authentication header if auth is provided
108
130
  Yobi.args.auth_header(headers, @options) if @options[:auth]
109
131
 
110
- Yobi::Http.request(method, url, data: data, headers: headers, options: @options) do |http, request|
132
+ Yobi::Http.request(method, url, data: data, headers: headers, query: query, options: @options) do |http, request|
111
133
  options = @options
112
134
 
113
135
  # follow redirects, offline, download or standard request mode
@@ -22,12 +22,16 @@ module Yobi
22
22
  end
23
23
  end
24
24
 
25
+ def parse_query(args, _options)
26
+ args.select { |arg| arg.match?(/::/) }.map.to_h { |arg| arg.split("::", 2).map(&:strip) }
27
+ end
28
+
25
29
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
26
- def parse_data(args)
27
- args.select { |arg| arg.match?("^.*(=|:=|=@|:=@).*$") }.map.to_h do |arg|
30
+ def parse_data(args, _options)
31
+ args.select { |arg| arg.match?("^.*(={1}|:=|=@|:=@).*$") }.map do |arg|
28
32
  case arg
29
33
  when /:=@/
30
- arg.split(/:=@/, 2).map do |part|
34
+ arg.split(":=@", 2).map do |part|
31
35
  part = String(part)&.strip
32
36
  File.exist?(part) ? JSON.parse(File.read(part)) : part
33
37
  end
@@ -47,15 +51,18 @@ module Yobi
47
51
  else
48
52
  arg.split("=", 2).map(&:strip)
49
53
  end
50
- end
54
+ end.compact.to_h
51
55
  end
52
56
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
53
57
 
54
- def parse_headers(args)
55
- { "Content-Type" => "application/json", "User-Agent" => "#{Yobi.name}/#{Yobi::VERSION}" }
56
- .merge(args.select do |arg|
57
- arg.match?(/:/) && !arg.match?(/:=/)
58
- end.map.to_h { |arg| arg.split(":", 2).map(&:strip) })
58
+ def parse_headers(args, options)
59
+ content_type = content_type_for options[:content_type]
60
+
61
+ { "Content-Type" => content_type, "User-Agent" => "#{Yobi.name}/#{Yobi::VERSION}" }.merge(
62
+ args
63
+ .select { |arg| arg.match?(/:{1}/) && !arg.match?(/:=/) && !arg.match?(/::/) }
64
+ .map.to_h { |arg| arg.split(/:{1}/, 2).map(&:strip) }
65
+ )
59
66
  end
60
67
 
61
68
  def auth_header(headers, options)
@@ -73,6 +80,25 @@ module Yobi
73
80
  exit 1
74
81
  end
75
82
  end
83
+
84
+ private
85
+
86
+ def content_type_for(value)
87
+ case value
88
+ when :form
89
+ "application/x-www-form-urlencoded"
90
+ when :multipart
91
+ "multipart/form-data"
92
+ when :xml
93
+ "application/xml"
94
+ when :binary
95
+ "application/octet-stream"
96
+ when :json, nil
97
+ "application/json"
98
+ else
99
+ "application/json"
100
+ end
101
+ end
76
102
  end
77
103
  end
78
104
  end
data/lib/yobi/http.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json"
3
4
  require "net/http"
4
5
 
5
6
  module Yobi
@@ -7,10 +8,22 @@ module Yobi
7
8
  module Http
8
9
  METHODS = %w[GET POST PUT DELETE PATCH HEAD OPTIONS].freeze
9
10
 
11
+ CONTENT_TYPES = {
12
+ text: "text/plain",
13
+ html: "text/html",
14
+ form: "application/x-www-form-urlencoded",
15
+ multipart: "multipart/form-data",
16
+ xml: "application/xml",
17
+ binary: "application/octet-stream",
18
+ json: "application/json"
19
+ }.freeze
20
+
10
21
  class << self
11
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
12
- def request(method, url, data: {}, headers: {}, options: {})
22
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/ParameterLists
23
+ def request(method, url, data: {}, query: {}, headers: {}, options: {})
13
24
  @uri = URI(url)
25
+ @uri.query = URI.encode_www_form(**query) unless query.empty?
26
+
14
27
  @options = options
15
28
  @method = method.capitalize
16
29
 
@@ -33,7 +46,7 @@ module Yobi
33
46
  exit 1
34
47
  end
35
48
  end
36
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
49
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/ParameterLists
37
50
 
38
51
  # rubocop:disable Metrics/ParameterLists
39
52
  def follow_redirects(response, url, method, data, headers, options)
@@ -50,7 +63,7 @@ module Yobi
50
63
  end
51
64
  # rubocop:enable Metrics/ParameterLists
52
65
 
53
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
66
+ # rubocop:disable Metrics/AbcSize
54
67
  def offline_mode(_request, options)
55
68
  Net::HTTP.class_eval do
56
69
  def connect; end
@@ -59,7 +72,7 @@ module Yobi
59
72
  options[:verbose] = true
60
73
 
61
74
  Net::HTTPResponse.new("1.1", "200", "OK").tap do |response|
62
- response["Content-Type"] = "application/json"
75
+ response["Content-Type"] = CONTENT_TYPES.fetch(options[:content_type], CONTENT_TYPES[:json])
63
76
  response["Access-Control-Allow-Credentials"] = true
64
77
  response["Access-Control-Allow-Origin"] = "*"
65
78
  response["Connection"] = "close"
@@ -71,9 +84,9 @@ module Yobi
71
84
  response.instance_variable_set(:@read, true)
72
85
  end
73
86
  end
74
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
87
+ # rubocop:enable Metrics/AbcSize
75
88
 
76
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
89
+ # rubocop:disable Metrics/AbcSize
77
90
  def download(request, http, options)
78
91
  http.request(request) do |response|
79
92
  url = request.uri.to_s
@@ -93,7 +106,7 @@ module Yobi
93
106
 
94
107
  exit 0
95
108
  end
96
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
109
+ # rubocop:enable Metrics/AbcSize
97
110
  end
98
111
  end
99
112
  end
data/lib/yobi/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Yobi
4
4
  # Yobi gem version
5
- VERSION = "0.14.0"
5
+ VERSION = "0.16.0"
6
6
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yobi-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Vinciguerra
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-02-27 00:00:00.000000000 Z
10
+ date: 2026-03-05 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64