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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d4bf34c7cdf9c459325cce7cc6c4571057eafa9d9d0f3937badf593a7edf4e0
4
- data.tar.gz: 905237976614eba95b0a5ff2a5089c537ecc2d6f27c18e23a622e81d30ab7dba
3
+ metadata.gz: '04786b19e7983cba95b256a974cc0624c69e693ddb64b40e7d7a40753691d779'
4
+ data.tar.gz: 0207e10a74a4130183379db1c99470c63b332b7c489103fb4d0efb47685dc0f7
5
5
  SHA512:
6
- metadata.gz: a15dc8568124039c2297460033ab55447197358977523a2245d1e1470f44d0ce1f9602ff0998c8cb3f63a77c64bebf70ad3b20d5c8f956b0ffb32e270d175e15
7
- data.tar.gz: 5805e36c1f2418ad1428eae2c1129feb54734fa321b0f5cbcc2e8cd34c2327f9a4189ec7888e6de3b031bbac353023f7749525a5772e5f265f3ed94d71d7f555
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.0...main)
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
@@ -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 ||= nil
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.call(body, @parser_options || {})
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)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Faraday
4
4
  module XML
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.1'
6
6
  end
7
7
  end
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.0
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-13 00:00:00.000000000 Z
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.0/CHANGELOG.md
166
- documentation_uri: http://www.rubydoc.info/gems/faraday-xml/0.1.0
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