faraday-xml 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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