pax_global_header00006660000000000000000000000064147345315600014522gustar00rootroot0000000000000052 comment=1f6fbd0650fcd255fc668cbed7335c5073134319 fog-xml-0.1.5/000077500000000000000000000000001473453156000130765ustar00rootroot00000000000000fog-xml-0.1.5/.github/000077500000000000000000000000001473453156000144365ustar00rootroot00000000000000fog-xml-0.1.5/.github/FUNDING.yml000066400000000000000000000000521473453156000162500ustar00rootroot00000000000000github: geemus tidelift: rubygems/fog-xml fog-xml-0.1.5/.github/dependabot.yml000066400000000000000000000003211473453156000172620ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "bundler" directory: "/" schedule: interval: "weekly" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" fog-xml-0.1.5/.github/workflows/000077500000000000000000000000001473453156000164735ustar00rootroot00000000000000fog-xml-0.1.5/.github/workflows/ci.yml000066400000000000000000000013071473453156000176120ustar00rootroot00000000000000name: CI on: push: branches: [ master ] pull_request: branches: [ master ] schedule: - cron: '0 0 * * 1' # At 00:00 on Monday. permissions: contents: read jobs: test: runs-on: ubuntu-latest strategy: matrix: ruby-version: ['3.0', '3.1', '3.2', '3.3', 'head'] continue-on-error: ${{ matrix.ruby-version == 'head' }} steps: - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Run tests run: bundle exec rake RUBYOPT="--enable-frozen-string-literal" fog-xml-0.1.5/.gitignore000066400000000000000000000003101473453156000150600ustar00rootroot00000000000000*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp *.bundle *.so *.o *.a mkmf.log gemfiles/*.lockfog-xml-0.1.5/.hound.yml000077700000000000000000000000001473453156000172612.rubocop.ymlustar00rootroot00000000000000fog-xml-0.1.5/.rubocop.yml000066400000000000000000000004161473453156000153510ustar00rootroot00000000000000Metrics/LineLength: Enabled: false Style/EachWithObject: Enabled: false Style/FormatString: Enabled: false Style/HashSyntax: EnforcedStyle: hash_rockets Style/SignalException: EnforcedStyle: only_raise Style/StringLiterals: EnforcedStyle: double_quotes fog-xml-0.1.5/.ruby-gemset000066400000000000000000000000071473453156000153370ustar00rootroot00000000000000fog-xmlfog-xml-0.1.5/CONTRIBUTING.md000066400000000000000000000015171473453156000153330ustar00rootroot00000000000000## Getting Involved New contributors are always welcome, when it doubt please ask questions. We strive to be an open and welcoming community. Please be nice to one another. ### Coding * Pick a task: * Offer feedback on open [pull requests](https://github.com/fog/fog-xml/pulls). * Review open [issues](https://github.com/fog/fog-xml/issues) for things to help on. * [Create an issue](https://github.com/fog/fog-xml/issues/new) to start a discussion on additions or features. * Fork the project, add your changes and tests to cover them in a topic branch. * Commit your changes and rebase against `fog/fog-xml` to ensure everything is up to date. * [Submit a pull request](https://github.com/fog/fog-xml/compare/) ### Non-Coding * Offer feedback on open [issues](https://github.com/fog/fog-xml/issues). * Organize or volunteer at events.fog-xml-0.1.5/CONTRIBUTORS.md000066400000000000000000000003111473453156000153500ustar00rootroot00000000000000* Michael Hale * Paul Thornthwaite * Paulo Henrique Lopes Ribeiro * Wesley Beary * Tomer Brisker fog-xml-0.1.5/Gemfile000066400000000000000000000001341473453156000143670ustar00rootroot00000000000000source "https://rubygems.org" # Specify your gem's dependencies in fog-xml.gemspec gemspec fog-xml-0.1.5/LICENSE.md000066400000000000000000000022001473453156000144740ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014-2014 [CONTRIBUTORS.md](https://github.com/zertico/fog-xml/blob/master/CONTRIBUTORS.md) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.fog-xml-0.1.5/README.md000066400000000000000000000017411473453156000143600ustar00rootroot00000000000000# Fog::Xml Shared XML related functionality for fog ![Gem Version](https://badge.fury.io/rb/fog-xml.svg) [![Build Status](https://github.com/fog/fog-xml/actions/workflows/ruby.yml/badge.svg)](https://github.com/fog/fog-xml/actions/workflows/ruby.yml) [![Coverage Status](https://img.shields.io/coveralls/fog/fog-xml.svg)](https://coveralls.io/r/fog/fog-xml?branch=master) [![Code Climate](https://codeclimate.com/github/fog/fog-xml/badges/gpa.svg)](https://codeclimate.com/github/fog/fog-xml) ## Installation Add this line to your application's Gemfile: gem 'fog-xml' And then execute: $ bundle Or install it yourself as: $ gem install fog-xml ## Usage TODO: Write usage instructions here ## Contributing 1. Fork it ( https://github.com/fog/fog-xml/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request fog-xml-0.1.5/Rakefile000066400000000000000000000003321473453156000145410ustar00rootroot00000000000000require "bundler/gem_tasks" require "rake/testtask" Rake::TestTask.new do |t| t.libs.push %w(spec) t.test_files = FileList["spec/**/*_spec.rb"] t.verbose = true end desc "Default Task" task :default => [:test] fog-xml-0.1.5/SECURITY.md000066400000000000000000000002721473453156000146700ustar00rootroot00000000000000## Security contact information To report a security vulnerability, please contact [Tidelift security](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. fog-xml-0.1.5/fog-xml.gemspec000066400000000000000000000024321473453156000160150ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require "fog/xml/version" Gem::Specification.new do |spec| spec.name = "fog-xml" spec.version = Fog::Xml::VERSION spec.authors = ["Wesley Beary (geemus)", "Paul Thornthwaite (tokengeek)", "The fog team"] spec.email = ["geemus@gmail.com", "tokengeek@gmail.com"] spec.summary = "XML parsing for fog providers" spec.description = "Extraction of the XML parsing tools shared between a number of providers in the 'fog' gem" spec.homepage = "https://github.com/fog/fog-xml" spec.license = "MIT" files = `git ls-files -z`.split("\x0") files.delete(".hound.yml") spec.files = files spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) } spec.test_files = spec.files.grep(/^(test|spec|features)\//) spec.require_paths = %w(lib) spec.required_ruby_version = '>= 2.0.0' spec.add_dependency "fog-core" spec.add_dependency "nokogiri", ">= 1.5.11", "< 2.0.0" #pinned for 2.0 support spec.add_development_dependency "rake" spec.add_development_dependency "minitest" spec.add_development_dependency "pry" spec.add_development_dependency "coveralls" end fog-xml-0.1.5/gemfiles/000077500000000000000000000000001473453156000146715ustar00rootroot00000000000000fog-xml-0.1.5/gemfiles/Gemfile.1.9.3+000066400000000000000000000002051473453156000167030ustar00rootroot00000000000000source "https://rubygems.org" gem 'activesupport', '>= 3.0', '< 4' gem 'mime-types', '< 2.0' gem 'fog-core' gemspec :path => '../' fog-xml-0.1.5/lib/000077500000000000000000000000001473453156000136445ustar00rootroot00000000000000fog-xml-0.1.5/lib/fog/000077500000000000000000000000001473453156000144175ustar00rootroot00000000000000fog-xml-0.1.5/lib/fog/parsers/000077500000000000000000000000001473453156000160765ustar00rootroot00000000000000fog-xml-0.1.5/lib/fog/parsers/base.rb000066400000000000000000000021511473453156000173340ustar00rootroot00000000000000require "nokogiri" module Fog module Parsers class Base < Nokogiri::XML::SAX::Document attr_reader :response def initialize reset end def attr_value(name, attrs) (entry = attrs.find {|a| a.localname == name }) && entry.value end def reset @response = {} end def characters(string) @value ||= +'' @value << string end # ############################################################################### # This is a workaround. Original implementation from Nokogiri is overwritten with # one that does not join namespace prefix with local name. def start_element_namespace name, attrs = [], prefix = nil, uri = nil, ns = [] start_element name, attrs end def end_element_namespace name, prefix = nil, uri = nil end_element name end # ############################################################################### def start_element(name, attrs = []) @value = nil end def value @value && @value.dup end end end end fog-xml-0.1.5/lib/fog/to_hash_document.rb000066400000000000000000000033521473453156000202720ustar00rootroot00000000000000module Fog class ToHashDocument < Nokogiri::XML::SAX::Document def initialize @stack = [] end def characters(string) @value ||= +'' @value << string.strip end def end_element(name) last = @stack.pop @stack.push({}) if @stack.empty? if last&.empty? && @value.empty? @stack.last[name.to_sym] = +'' elsif last == { :i_nil => "true" } @stack.last[name.to_sym] = nil elsif !@value.empty? @stack.last[name.to_sym] = @value end @value = +'' end def body @stack.first end def response body end def start_element(name, attributes = []) @value = +'' parsed_attributes = {} until attributes.empty? if attributes.first.is_a?(Array) key, value = attributes.shift else key, value = attributes.shift, attributes.shift end parsed_attributes[key.gsub(":", "_").to_sym] = value end if @stack.last.is_a?(Array) @stack.last << { name.to_sym => parsed_attributes } else data = if @stack.empty? @stack.push(parsed_attributes) parsed_attributes elsif @stack.last[name.to_sym] unless @stack.last[name.to_sym].is_a?(Array) @stack.last[name.to_sym] = [@stack.last[name.to_sym]] end @stack.last[name.to_sym] << parsed_attributes @stack.last[name.to_sym].last else @stack.last[name.to_sym] = {} @stack.last[name.to_sym].merge!(parsed_attributes) @stack.last[name.to_sym] end @stack.push(data) end end end end fog-xml-0.1.5/lib/fog/xml.rb000066400000000000000000000010251473453156000155420ustar00rootroot00000000000000require "fog/core" require "nokogiri" require File.expand_path("../xml/version", __FILE__) module Fog autoload :ToHashDocument, File.expand_path("../to_hash_document", __FILE__) module XML autoload :SAXParserConnection, File.expand_path("../xml/sax_parser_connection", __FILE__) autoload :Connection, File.expand_path("../xml/connection", __FILE__) autoload :Response, File.expand_path("../xml/response", __FILE__) end module Parsers autoload :Base, File.expand_path("../parsers/base", __FILE__) end end fog-xml-0.1.5/lib/fog/xml/000077500000000000000000000000001473453156000152175ustar00rootroot00000000000000fog-xml-0.1.5/lib/fog/xml/connection.rb000066400000000000000000000004301473453156000177000ustar00rootroot00000000000000module Fog module XML class Connection < SAXParserConnection def request(params, &_block) parser = params.delete(:parser) if parser super(parser, params) else original_request(params) end end end end end fog-xml-0.1.5/lib/fog/xml/response.rb000066400000000000000000000011001473453156000173720ustar00rootroot00000000000000module Fog module XML class Response def initialize(parser) @parser = parser @data_stream = Nokogiri::XML::SAX::PushParser.new(parser) @response_string = +'' end def call(chunk, _remaining, _total) @response_string << chunk if ENV["DEBUG_RESPONSE"] @data_stream << chunk end def rewind @parser.reset @response_string = +'' end def finish Fog::Logger.debug "\n#{@response_string}" if ENV["DEBUG_RESPONSE"] @data_stream.finish end end end end fog-xml-0.1.5/lib/fog/xml/sax_parser_connection.rb000066400000000000000000000027761473453156000221460ustar00rootroot00000000000000module Fog module XML class SAXParserConnection < ::Fog::Core::Connection # Makes a request using the connection using Excon # # @param [Hash] params # @option params [String] :body text to be sent over a socket # @option params [Hash] :headers The default headers to supply in a request # @option params [String] :host The destination host"s reachable DNS name or IP, in the form of a String # @option params [String] :path appears after "scheme://host:port/" # @option params [Fixnum] :port The port on which to connect, to the destination host # @option params [Hash] :query appended to the "scheme://host:port/path/" in the form of "?key=value" # @option params [String] :scheme The protocol; "https" causes OpenSSL to be used # @option params [Proc] :response_block # @option params [Nokogiri::XML::SAX::Document] :parser # # @return [Excon::Response] # # @raise [Excon::Errors::StubNotFound] # @raise [Excon::Errors::Timeout] # @raise [Excon::Errors::SocketError] # def request(parser, params) reset unless @persistent params[:response_block] = ::Fog::XML::Response.new(parser) # Make request which read chunks into parser response = @excon.request(params) # Cease parsing and override response.body with parsed data params[:response_block].finish response.body = parser.response response end end end end fog-xml-0.1.5/lib/fog/xml/version.rb000066400000000000000000000000701473453156000172260ustar00rootroot00000000000000module Fog module Xml VERSION = "0.1.5" end end fog-xml-0.1.5/spec/000077500000000000000000000000001473453156000140305ustar00rootroot00000000000000fog-xml-0.1.5/spec/fog/000077500000000000000000000000001473453156000146035ustar00rootroot00000000000000fog-xml-0.1.5/spec/fog/parsers/000077500000000000000000000000001473453156000162625ustar00rootroot00000000000000fog-xml-0.1.5/spec/fog/parsers/base_spec.rb000066400000000000000000000031031473453156000205300ustar00rootroot00000000000000require "minitest_helper" describe Fog::Parsers::Base do def parse(input, parser_class) document = parser_class.new parser = Nokogiri::XML::SAX::Parser.new(document) parser.parse input document.response end describe 'value' do class ValueTest < Fog::Parsers::Base def start_element(name, attrs) @stack.push({}) super end def reset super @stack = [@response] end def end_element name top = @stack.pop if top.empty? @stack.last[name] = value else @stack.last[name] = top if @stack.any? end end end it 'extracts the characters for the current element' do doc = <<-XML FooValue BarValue XML assert_equal({'Test'=> {'Foo' => 'FooValue', 'Bar' => 'BarValue'}}, parse(doc, ValueTest)) end end describe 'attr_value' do class AttrParser < Fog::Parsers::Base def start_element(name, attrs=[]) super @response[name] = {'foo' => attr_value('foo', attrs)} end end describe 'the attribute exists' do it 'returns the value' do doc = <<-XML XML assert_equal({'Test'=> {'foo' => 'bar'}}, parse(doc, AttrParser)) end end describe 'the attribute does not exist' do it 'returns nil' do doc = <<-XML XML assert_equal({'Test'=> {'foo' => nil}}, parse(doc, AttrParser)) end end end endfog-xml-0.1.5/spec/fog/to_hash_document_spec.rb000066400000000000000000000071141473453156000214700ustar00rootroot00000000000000# frozen_string_literal: true require 'minitest_helper' require 'fog/xml' # We expose accessors just for testing purposes Fog::ToHashDocument.attr_accessor(:value, :stack) describe Fog::ToHashDocument do before do @document = Fog::ToHashDocument.new end describe '#characters' do it 'appends characters to @value' do @document.characters('some text') _(@document.value).must_equal 'some text' end it 'strips whitespace from characters' do @document.characters(' some text ') _(@document.value).must_equal 'some text' end end describe '#end_element' do before do @document.stack << {} @document.characters('some text') end it 'adds element with text content to the stack' do @document.end_element('element') expected = { element: 'some text' } _(@document.stack.last).must_equal(expected) end it 'can mutate the new empty value' do @document.end_element('element') _(@document.value).must_equal('') # Mutate the new empty value even when frozen string literals are enabled _(@document.characters('one')) end it 'adds empty string if element is empty and value is empty' do @document.value = '' @document.end_element('element') expected = { element: '' } _(@document.stack.last).must_equal(expected) end it 'adds nil if element has :i_nil attribute' do @document.stack.last[:i_nil] = 'true' @document.value = '' @document.end_element('element') expected = { element: nil } _(@document.stack.last).must_equal(expected) end end describe '#body' do it 'returns the first element of the stack' do @document.stack << { key: 'value' } expected = { key: 'value' } _(@document.body).must_equal(expected) end end describe '#response' do it 'returns the body' do @document.stack << { key: 'value' } expected = { key: 'value' } _(@document.response).must_equal(expected) end end describe '#start_element' do it 'parses attributes correctly' do @document.start_element('element', [%w[key value]]) expected = { key: 'value' } _(@document.stack.last).must_equal(expected) end it 'handles elements without attributes' do @document.start_element('element') _(@document.stack.last).must_equal({}) end it 'adds nested elements to the stack' do @document.start_element('parent') @document.start_element('child') _(@document.stack).must_equal([{ child: {} }, { child: {} }, {}]) end it 'adds nested elements with attributes to the stack' do @document.start_element('parent') @document.start_element('child', [%w[key value]]) expected = [ { child: { key: 'value' } }, { child: { key: 'value' } }, { key: 'value' } ] _(@document.stack).must_equal(expected) end it 'handles multiple children elements correctly' do @document.start_element('parent') @document.start_element('child1') @document.end_element('child1') @document.start_element('child2', [%w[key value]]) @document.end_element('child2') expected = { child1: '', child2: { key: 'value' } } _(@document.stack.first).must_equal(expected) end it 'handles text content within elements' do @document.start_element('parent') @document.characters('some text') @document.end_element('parent') expected = { parent: 'some text' } _(@document.stack.first).must_equal(expected) end end end fog-xml-0.1.5/spec/fog/xml/000077500000000000000000000000001473453156000154035ustar00rootroot00000000000000fog-xml-0.1.5/spec/fog/xml/connection_spec.rb000066400000000000000000000015611473453156000211040ustar00rootroot00000000000000require "minitest_helper" describe Fog::XML::Connection do before do @connection = Fog::XML::Connection.new("http://localhost") end after do Excon.stubs.clear end it "responds to #request" do assert_respond_to @connection, :request end describe "when request is passed a parser" do it "returns the body after parsing" do @parser = Fog::ToHashDocument.new Excon.stub({}, { :status => 200, :body => "" }) response = @connection.request(:parser => @parser, :mock => true) assert_equal({ :xml => "" }, response.body) end end describe "when request excludes a parser" do it "returns the response body without change" do Excon.stub({}, { :status => 200, :body => "" }) response = @connection.request(:mock => true) assert_equal("", response.body) end end end fog-xml-0.1.5/spec/minitest_helper.rb000066400000000000000000000004571473453156000175560ustar00rootroot00000000000000require "minitest/spec" require "minitest/autorun" require "excon" require "fog/core" if ENV["COVERAGE"] require "coveralls" require "simplecov" SimpleCov.start do add_filter "/spec/" end end require File.join(File.dirname(__FILE__), "../lib/fog/xml") Coveralls.wear! if ENV["COVERAGE"]