diff --git a/lib/savon.rb b/lib/savon.rb index ea0fe365..b8ece228 100644 --- a/lib/savon.rb +++ b/lib/savon.rb @@ -26,3 +26,4 @@ def self.notify_observers(operation_name, builder, globals, locals) require "savon/version" require "savon/client" require "savon/model" +require "savon/string_utils" diff --git a/lib/savon/builder.rb b/lib/savon/builder.rb index e2c905b6..454c6f4f 100644 --- a/lib/savon/builder.rb +++ b/lib/savon/builder.rb @@ -163,7 +163,7 @@ def serialized_messages message_tag = serialized_message_tag[1] @wsdl.soap_input(@operation_name.to_sym)[message_tag].each_pair do |message, type| break if @locals[:message].nil? - message_locals = @locals[:message][message.snakecase.to_sym] + message_locals = @locals[:message][StringUtils.snakecase(message).to_sym] message_content = Message.new(message_tag, namespace_identifier, @types, @used_namespaces, message_locals, :unqualified, @globals[:convert_request_keys_to], @globals[:unwrap]).to_s messages += "<#{message} xsi:type=\"#{type.join(':')}\">#{message_content}" end diff --git a/lib/savon/core_ext/string.rb b/lib/savon/core_ext/string.rb deleted file mode 100644 index 292afb33..00000000 --- a/lib/savon/core_ext/string.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module Savon - module CoreExt - module String - - def self.included(base) - unless "savon".respond_to?(:snakecase) - base.send(:include, Extension) - end - end - - module Extension - def snakecase - str = dup - str.gsub! /::/, '/' - str.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2' - str.gsub! /([a-z\d])([A-Z])/, '\1_\2' - str.tr! ".", "_" - str.tr! "-", "_" - str.downcase! - str - end - end - - end - end -end - -String.send :include, Savon::CoreExt::String diff --git a/lib/savon/model.rb b/lib/savon/model.rb index 58937f47..a44debc6 100644 --- a/lib/savon/model.rb +++ b/lib/savon/model.rb @@ -29,7 +29,7 @@ def all_operations # Defines a class-level SOAP operation. def define_class_operation(operation) class_operation_module.module_eval %{ - def #{operation.to_s.snakecase}(locals = {}) + def #{StringUtils.snakecase(operation.to_s)}(locals = {}) client.call #{operation.inspect}, locals end } @@ -38,8 +38,8 @@ def #{operation.to_s.snakecase}(locals = {}) # Defines an instance-level SOAP operation. def define_instance_operation(operation) instance_operation_module.module_eval %{ - def #{operation.to_s.snakecase}(locals = {}) - self.class.#{operation.to_s.snakecase} locals + def #{StringUtils.snakecase(operation.to_s)}(locals = {}) + self.class.#{StringUtils.snakecase(operation.to_s)} locals end } end diff --git a/lib/savon/options.rb b/lib/savon/options.rb index 55004aee..71d78666 100644 --- a/lib/savon/options.rb +++ b/lib/savon/options.rb @@ -85,7 +85,7 @@ def initialize(options = {}) :raise_errors => true, :strip_namespaces => true, :delete_namespace_attributes => false, - :convert_response_tags_to => lambda { |tag| tag.snakecase.to_sym}, + :convert_response_tags_to => lambda { |tag| StringUtils.snakecase(tag).to_sym}, :convert_attributes_to => lambda { |k,v| [k,v] }, :multipart => false, :adapter => nil, diff --git a/lib/savon/string_utils.rb b/lib/savon/string_utils.rb new file mode 100644 index 00000000..f6d9f88b --- /dev/null +++ b/lib/savon/string_utils.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Savon + module StringUtils + def self.snakecase(inputstring) + str = inputstring.dup + str.gsub! /::/, '/' + str.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2' + str.gsub! /([a-z\d])([A-Z])/, '\1_\2' + str.tr! ".", "_" + str.tr! "-", "_" + str.downcase! + str + end + end +end + diff --git a/spec/savon/core_ext/string_spec.rb b/spec/savon/core_ext/string_spec.rb deleted file mode 100644 index 54f658b5..00000000 --- a/spec/savon/core_ext/string_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -RSpec.describe String do - - describe "snakecase" do - it "lowercases one word CamelCase" do - expect("Merb".snakecase).to eq("merb") - end - - it "makes one underscore snakecase two word CamelCase" do - expect("MerbCore".snakecase).to eq("merb_core") - end - - it "handles CamelCase with more than 2 words" do - expect("SoYouWantContributeToMerbCore".snakecase).to eq("so_you_want_contribute_to_merb_core") - end - - it "handles CamelCase with more than 2 capital letter in a row" do - expect("CNN".snakecase).to eq("cnn") - expect("CNNNews".snakecase).to eq("cnn_news") - expect("HeadlineCNNNews".snakecase).to eq("headline_cnn_news") - end - - it "does NOT change one word lowercase" do - expect("merb".snakecase).to eq("merb") - end - - it "leaves snake_case as is" do - expect("merb_core".snakecase).to eq("merb_core") - end - - it "converts period characters to underscores" do - expect("User.GetEmail".snakecase).to eq("user_get_email") - end - end - -end diff --git a/spec/savon/options_spec.rb b/spec/savon/options_spec.rb index 247df12e..914d3be4 100644 --- a/spec/savon/options_spec.rb +++ b/spec/savon/options_spec.rb @@ -844,7 +844,7 @@ def to_s it "can be changed to not strip any namespaces" do client = new_client( :endpoint => @server.url(:repeat), - :convert_response_tags_to => lambda { |tag| tag.snakecase }, + :convert_response_tags_to => lambda { |tag| Savon::StringUtils.snakecase(tag) }, :strip_namespaces => false ) @@ -877,7 +877,7 @@ def to_s context "global :convert_response_tags_to" do it "changes how XML tags from the SOAP response are translated into Hash keys" do - client = new_client(:endpoint => @server.url(:repeat), :convert_response_tags_to => lambda { |tag| tag.snakecase.upcase }) + client = new_client(:endpoint => @server.url(:repeat), :convert_response_tags_to => lambda { |tag| Savon::StringUtils.snakecase(tag).upcase }) response = client.call(:authenticate, :xml => Fixture.response(:authentication)) expect(response.full_hash["ENVELOPE"]["BODY"]).to include("AUTHENTICATE_RESPONSE") @@ -888,7 +888,7 @@ def to_s globals.log false globals.wsdl Fixture.wsdl(:authentication) globals.endpoint @server.url(:repeat) - globals.convert_response_tags_to { |tag| tag.snakecase.upcase } + globals.convert_response_tags_to { |tag| Savon::StringUtils.snakecase(tag).upcase } end response = client.call(:authenticate) do |locals| @@ -1115,7 +1115,7 @@ def to_s context "request :response_parser" do it "instructs Nori to change the response parser" do - nori = Nori.new(:strip_namespaces => true, :convert_tags_to => lambda { |tag| tag.snakecase.to_sym }) + nori = Nori.new(:strip_namespaces => true, :convert_tags_to => lambda { |tag| Savon::StringUtils.snakecase(tag).to_sym }) Nori.expects(:new).with { |options| options[:parser] == :nokogiri }.returns(nori) client = new_client(:endpoint => @server.url(:repeat)) diff --git a/spec/savon/soap_fault_spec.rb b/spec/savon/soap_fault_spec.rb index d66ab935..1dde0501 100644 --- a/spec/savon/soap_fault_spec.rb +++ b/spec/savon/soap_fault_spec.rb @@ -12,7 +12,7 @@ let(:soap_fault_no_body) { Savon::SOAPFault.new new_response(:body => {}), nori } let(:no_fault) { Savon::SOAPFault.new new_response, nori } - let(:nori) { Nori.new(:strip_namespaces => true, :convert_tags_to => lambda { |tag| tag.snakecase.to_sym }) } + let(:nori) { Nori.new(:strip_namespaces => true, :convert_tags_to => lambda { |tag| Savon::StringUtils.snakecase(tag).to_sym }) } let(:nori_no_convert) { Nori.new(:strip_namespaces => true, :convert_tags_to => nil) } it "inherits from Savon::Error" do diff --git a/spec/savon/string_utils_spec.rb b/spec/savon/string_utils_spec.rb new file mode 100644 index 00000000..1055ea3d --- /dev/null +++ b/spec/savon/string_utils_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe Savon::StringUtils do + + describe "snakecase" do + it "lowercases one word CamelCase" do + expect(Savon::StringUtils.snakecase("Merb")).to eq("merb") + end + + it "makes one underscore snakecase two word CamelCase" do + expect(Savon::StringUtils.snakecase("MerbCore")).to eq("merb_core") + end + + it "handles CamelCase with more than 2 words" do + expect(Savon::StringUtils.snakecase("SoYouWantContributeToMerbCore")).to eq("so_you_want_contribute_to_merb_core") + end + + it "handles CamelCase with more than 2 capital letter in a row" do + expect(Savon::StringUtils.snakecase("CNN")).to eq("cnn") + expect(Savon::StringUtils.snakecase("CNNNews")).to eq("cnn_news") + expect(Savon::StringUtils.snakecase("HeadlineCNNNews")).to eq("headline_cnn_news") + end + + it "does NOT change one word lowercase" do + expect(Savon::StringUtils.snakecase("merb")).to eq("merb") + end + + it "leaves snake_case as is" do + expect(Savon::StringUtils.snakecase("merb_core")).to eq("merb_core") + end + + it "converts period characters to underscores" do + expect(Savon::StringUtils.snakecase("User.GetEmail")).to eq("user_get_email") + end + end + +end diff --git a/spec/support/fixture.rb b/spec/support/fixture.rb index a4777c5a..a30b060a 100644 --- a/spec/support/fixture.rb +++ b/spec/support/fixture.rb @@ -21,7 +21,7 @@ def full_hash(fixture) private def nori - Nori.new(:strip_namespaces => true, :convert_tags_to => lambda { |tag| tag.snakecase.to_sym }) + Nori.new(:strip_namespaces => true, :convert_tags_to => lambda { |tag| Savon::StringUtils.snakecase(tag).to_sym }) end def fixtures(type)