faraday-xml 0.1.0 → 0.2.1
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 +4 -4
- data/CHANGELOG.md +11 -2
- data/README.md +17 -1
- data/lib/faraday/xml/encoder.rb +104 -0
- data/lib/faraday/xml/parser.rb +55 -0
- data/lib/faraday/xml/request.rb +58 -0
- data/lib/faraday/xml/response.rb +4 -35
- data/lib/faraday/xml/version.rb +1 -1
- data/lib/faraday/xml.rb +6 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '04786b19e7983cba95b256a974cc0624c69e693ddb64b40e7d7a40753691d779'
|
4
|
+
data.tar.gz: 0207e10a74a4130183379db1c99470c63b332b7c489103fb4d0efb47685dc0f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee0a896484ea4884d05f192df27800017fe255dfe19357dcaf1d5799e36e8e436eeeacf4a7c9a7bc734b4208e7a93e57572fc2913f91703ba93846f1d590456c
|
7
|
+
data.tar.gz: fe11c2aacb78691b099b295424e749572ebdb67881cec6abbf0546dbdaf598eb8fd1397a83e83ce029cac880b3e20001005a8044f84fd1243e279acaf1ed9f70
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [Unreleased](https://github.com/gemhome/faraday-xml/compare/v0.1
|
3
|
+
## [Unreleased](https://github.com/gemhome/faraday-xml/compare/v0.2.1...main)
|
4
|
+
|
5
|
+
## [0.2.1](https://github.com/gemhome/faraday-xml/compare/v0.2.0...v0.2.1)
|
6
|
+
|
7
|
+
* feat: extract Faraday::XML::Encoder
|
8
|
+
* feat: extract Faraday::XML::Parser
|
9
|
+
|
10
|
+
## [0.2.0](https://github.com/gemhome/faraday-xml/compare/v0.1.0...v0.2.0)
|
11
|
+
|
12
|
+
* feat: simple Hash -> XML request encoder
|
4
13
|
|
5
14
|
## [0.1.0](https://github.com/gemhome/faraday-xml/blob/v0.1.0) (2023-01-12)
|
6
15
|
|
7
|
-
* Initial release.
|
16
|
+
* feat: Initial release.
|
data/README.md
CHANGED
@@ -37,12 +37,28 @@ conn = Faraday.new do |builder|
|
|
37
37
|
"Accept" => "application/xml",
|
38
38
|
"Content-Type" => "application/xml;charset=UTF-8",
|
39
39
|
)
|
40
|
-
|
40
|
+
# or builder.use Faraday::XML::Request
|
41
|
+
builder.request :xml # encode Hash as XML
|
41
42
|
# or builder.use Faraday::XML::Response
|
42
43
|
builder.response :xml # decode response bodies from XML
|
43
44
|
end
|
44
45
|
```
|
45
46
|
|
47
|
+
There is also basic support for first class XML encoding/parsing
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
require 'faraday'
|
51
|
+
require 'faraday/xml'
|
52
|
+
hash = { 'user' => { 'name' => 'Erik Michaels-Ober', 'screen_name' => 'sferik' } }
|
53
|
+
xml = '<user><name>Erik Michaels-Ober</name><screen_name>sferik</screen_name></user>'
|
54
|
+
|
55
|
+
encoder = Faraday::XML::Encoder.build!(indent: 0)
|
56
|
+
encoder.encode(hash) == xml
|
57
|
+
|
58
|
+
parser = Faraday::XML::Parser.build!
|
59
|
+
parser.parse(xml) == hash
|
60
|
+
```
|
61
|
+
|
46
62
|
## Development
|
47
63
|
|
48
64
|
After checking out the repo, run `bin/setup` to install dependencies.
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
module XML
|
5
|
+
# Utility fucntion that encodes input as XML.
|
6
|
+
#
|
7
|
+
# Doesn't try to encode input which already are in string form.
|
8
|
+
class Encoder
|
9
|
+
def self.build!(encoder_options = {})
|
10
|
+
encoder = new(encoder_options)
|
11
|
+
encoder.encoder!
|
12
|
+
encoder
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(encoder_options = {})
|
16
|
+
@encoder_options = encoder_options || {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def encode(data)
|
20
|
+
encoder.call(data)
|
21
|
+
end
|
22
|
+
|
23
|
+
def encoder
|
24
|
+
@encoder ||= nil
|
25
|
+
if @encoder.nil?
|
26
|
+
@encoder = set_encoder
|
27
|
+
@encoder && test_encoder
|
28
|
+
end
|
29
|
+
@encoder or raise 'Missing dependencies Builder'
|
30
|
+
end
|
31
|
+
alias encoder! encoder
|
32
|
+
|
33
|
+
def test_encoder
|
34
|
+
encode({ success: true })
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_encoder
|
38
|
+
@encoder ||= # rubocop:disable Naming/MemoizedInstanceVariableName
|
39
|
+
begin
|
40
|
+
require 'builder'
|
41
|
+
lambda do |parameter_hash|
|
42
|
+
parameters_as_xml(parameter_hash)
|
43
|
+
end
|
44
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def parameters_as_xml(parameter_hash) # rubocop:disable Metrics/MethodLength
|
49
|
+
xml_markup = build_xml_markup(skip_instruct: true)
|
50
|
+
parameter_hash.each_pair do |key, value|
|
51
|
+
key = key.to_s
|
52
|
+
if _parameter_as_xml?(value)
|
53
|
+
xml_markup.tag!(key) do
|
54
|
+
xml = _parameter_as_xml(value)
|
55
|
+
xml_markup << xml
|
56
|
+
end
|
57
|
+
else
|
58
|
+
xml_markup.tag!(key, _parameter_as_xml(value))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
xml_markup.target!
|
62
|
+
end
|
63
|
+
|
64
|
+
def _parameter_as_xml?(value)
|
65
|
+
case value
|
66
|
+
when Hash, Array then true
|
67
|
+
else false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def _parameter_as_xml(value)
|
72
|
+
case value
|
73
|
+
when Hash
|
74
|
+
parameters_as_xml(value) # recursive case
|
75
|
+
when Array
|
76
|
+
_parameter_as_list_xml(value) # recursive case
|
77
|
+
else
|
78
|
+
value.to_s.encode(xml: :text) # end case
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def _parameter_as_list_xml(array_of_hashes)
|
83
|
+
xml_markup = build_xml_markup(skip_instruct: true)
|
84
|
+
array_of_hashes.each do |value|
|
85
|
+
xml_markup << parameters_as_xml(value) # recursive case
|
86
|
+
end
|
87
|
+
xml_markup.target!
|
88
|
+
end
|
89
|
+
|
90
|
+
def build_xml_markup(**options)
|
91
|
+
# https://github.com/rails/rails/blob/86fd8d0143b1a0578b359f4b86fea94c718139ae/activesupport/lib/active_support/builder.rb
|
92
|
+
# https://github.com/rails/rails/blob/86fd8d0143b1a0578b359f4b86fea94c718139ae/activesupport/lib/active_support/core_ext/hash/conversions.rb
|
93
|
+
require 'builder'
|
94
|
+
options.merge!(@encoder_options)
|
95
|
+
options[:indent] = 2 unless options.key?(:indent)
|
96
|
+
xml_markup = ::Builder::XmlMarkup.new(**options)
|
97
|
+
if !options.delete(:skip_instruct) # rubocop:disable Style/NegatedIf
|
98
|
+
xml_markup.instruct! :xml, version: '1.0', encoding: 'UTF-8'
|
99
|
+
end
|
100
|
+
xml_markup
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
module XML
|
5
|
+
# Utility fucntion that parses XML input.
|
6
|
+
class Parser
|
7
|
+
def self.build!
|
8
|
+
parser = new
|
9
|
+
parser.parser!
|
10
|
+
parser
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(xml, parser_options = {})
|
14
|
+
parser.call(xml, parser_options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def parser
|
18
|
+
@parser ||= nil
|
19
|
+
if @parser.nil?
|
20
|
+
@parser = set_parser
|
21
|
+
@parser && test_parser
|
22
|
+
end
|
23
|
+
@parser or raise 'Missing dependencies ActiveSupport::XmlMini or MultiXml'
|
24
|
+
end
|
25
|
+
alias parser! parser
|
26
|
+
|
27
|
+
def test_parser
|
28
|
+
parse('<success>true</success>')
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_parser # rubocop:disable Metrics/MethodLength
|
32
|
+
@parser ||=
|
33
|
+
begin
|
34
|
+
require 'multi_xml'
|
35
|
+
lambda do |xml, options|
|
36
|
+
::MultiXml.parse(xml, options)
|
37
|
+
end
|
38
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
39
|
+
end
|
40
|
+
@parser ||= # rubocop:disable Naming/MemoizedInstanceVariableName
|
41
|
+
begin
|
42
|
+
require 'active_support'
|
43
|
+
require 'active_support/xml_mini'
|
44
|
+
require 'active_support/core_ext/hash/conversions'
|
45
|
+
require 'active_support/core_ext/array/conversions'
|
46
|
+
lambda do |xml, options|
|
47
|
+
disallowed_types = options[:disallowed_types]
|
48
|
+
Hash.from_xml(xml, disallowed_types)
|
49
|
+
end
|
50
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'encoder'
|
4
|
+
|
5
|
+
module Faraday
|
6
|
+
module XML
|
7
|
+
# Request middleware that encodes the body as XML.
|
8
|
+
#
|
9
|
+
# Processes only requests with matching Content-type or those without a type.
|
10
|
+
# If a request doesn't have a type but has a body, it sets the Content-type
|
11
|
+
# to XML MIME-type.
|
12
|
+
#
|
13
|
+
# Doesn't try to encode bodies that already are in string form.
|
14
|
+
class Request < Middleware
|
15
|
+
MIME_TYPE = 'application/xml'
|
16
|
+
MIME_TYPE_REGEX = %r{^application/(vnd\..+\+)?xml$}.freeze
|
17
|
+
|
18
|
+
def initialize(app = nil, options = {})
|
19
|
+
super(app)
|
20
|
+
@encoder_options = options.fetch(:encoder_options, {})
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_request(env)
|
24
|
+
match_content_type(env) do |data|
|
25
|
+
env[:body] = encoder.encode(data)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def encoder
|
30
|
+
@encoder ||= Encoder.build!(@encoder_options)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def match_content_type(env)
|
36
|
+
return unless process_request?(env)
|
37
|
+
|
38
|
+
env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
|
39
|
+
yield env[:body] unless env[:body].respond_to?(:to_str)
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_request?(env)
|
43
|
+
type = request_type(env)
|
44
|
+
body?(env) && (type.empty? || type.match?(MIME_TYPE_REGEX))
|
45
|
+
end
|
46
|
+
|
47
|
+
def body?(env)
|
48
|
+
(body = env[:body]) && !(body.respond_to?(:to_str) && body.empty?)
|
49
|
+
end
|
50
|
+
|
51
|
+
def request_type(env)
|
52
|
+
type = env[:request_headers][CONTENT_TYPE].to_s
|
53
|
+
type = type.split(';', 2).first if type.index(';')
|
54
|
+
type
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/faraday/xml/response.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'parser'
|
4
|
+
|
3
5
|
module Faraday
|
4
6
|
module XML
|
5
7
|
# Parse response bodies as XML
|
@@ -10,7 +12,6 @@ module Faraday
|
|
10
12
|
@content_types = Array(options.fetch(:content_type, /\bxml$/))
|
11
13
|
@preserve_raw = options.fetch(:preserve_raw, false)
|
12
14
|
end
|
13
|
-
ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
|
14
15
|
|
15
16
|
# @param env [Faraday::Env] the environment of the response being processed.
|
16
17
|
def on_complete(env)
|
@@ -18,12 +19,7 @@ module Faraday
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def parser
|
21
|
-
@parser ||=
|
22
|
-
if @parser.nil?
|
23
|
-
@parser = set_parser
|
24
|
-
@parser && test_parser
|
25
|
-
end
|
26
|
-
@parser or raise 'Missing dependencies ActiveSupport::XmlMini or MultiXml'
|
22
|
+
@parser ||= Parser.build!
|
27
23
|
end
|
28
24
|
|
29
25
|
private
|
@@ -38,34 +34,7 @@ module Faraday
|
|
38
34
|
def parse(body)
|
39
35
|
return nil if body.strip.empty?
|
40
36
|
|
41
|
-
parser.
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_parser
|
45
|
-
parse('<success>true</success>')
|
46
|
-
end
|
47
|
-
|
48
|
-
def set_parser # rubocop:disable Metrics/MethodLength
|
49
|
-
@parser ||=
|
50
|
-
begin
|
51
|
-
require 'multi_xml'
|
52
|
-
lambda do |xml, options|
|
53
|
-
::MultiXml.parse(xml, options)
|
54
|
-
end
|
55
|
-
rescue LoadError # rubocop:disable Lint/SuppressedException
|
56
|
-
end
|
57
|
-
@parser ||= # rubocop:disable Naming/MemoizedInstanceVariableName
|
58
|
-
begin
|
59
|
-
require 'active_support'
|
60
|
-
require 'active_support/xml_mini'
|
61
|
-
require 'active_support/core_ext/hash/conversions'
|
62
|
-
require 'active_support/core_ext/array/conversions'
|
63
|
-
lambda do |xml, options|
|
64
|
-
disallowed_types = options[:disallowed_types]
|
65
|
-
Hash.from_xml(xml, disallowed_types)
|
66
|
-
end
|
67
|
-
rescue LoadError # rubocop:disable Lint/SuppressedException
|
68
|
-
end
|
37
|
+
parser.parse(body, @parser_options || {})
|
69
38
|
end
|
70
39
|
|
71
40
|
def parse_response?(env)
|
data/lib/faraday/xml/version.rb
CHANGED
data/lib/faraday/xml.rb
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'xml/request'
|
3
4
|
require_relative 'xml/response'
|
4
5
|
require_relative 'xml/version'
|
5
6
|
|
6
7
|
module Faraday
|
7
8
|
# The Faraday::XML middleware main module
|
8
9
|
module XML
|
10
|
+
# Load middleware with
|
11
|
+
# conn.use Faraday::XML::Request
|
12
|
+
# or
|
13
|
+
# conn.request :xml
|
14
|
+
Faraday::Request.register_middleware(xml: Faraday::XML::Request)
|
9
15
|
# Load middleware with
|
10
16
|
# conn.use Faraday::XML::Response
|
11
17
|
# or
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faraday-xml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Fleischer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-01-
|
11
|
+
date: 2023-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -155,6 +155,9 @@ files:
|
|
155
155
|
- LICENSE.md
|
156
156
|
- README.md
|
157
157
|
- lib/faraday/xml.rb
|
158
|
+
- lib/faraday/xml/encoder.rb
|
159
|
+
- lib/faraday/xml/parser.rb
|
160
|
+
- lib/faraday/xml/request.rb
|
158
161
|
- lib/faraday/xml/response.rb
|
159
162
|
- lib/faraday/xml/version.rb
|
160
163
|
homepage: https://github.com/gemhome/faraday-xml
|
@@ -162,8 +165,8 @@ licenses:
|
|
162
165
|
- MIT
|
163
166
|
metadata:
|
164
167
|
bug_tracker_uri: https://github.com/gemhome/faraday-xml/issues
|
165
|
-
changelog_uri: https://github.com/gemhome/faraday-xml/blob/v0.1
|
166
|
-
documentation_uri: http://www.rubydoc.info/gems/faraday-xml/0.1
|
168
|
+
changelog_uri: https://github.com/gemhome/faraday-xml/blob/v0.2.1/CHANGELOG.md
|
169
|
+
documentation_uri: http://www.rubydoc.info/gems/faraday-xml/0.2.1
|
167
170
|
homepage_uri: https://github.com/gemhome/faraday-xml
|
168
171
|
rubygems_mfa_required: 'true'
|
169
172
|
source_code_uri: https://github.com/gemhome/faraday-xml
|