rbook 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/COPYING +340 -0
  2. data/LICENSE +13 -0
  3. data/README +16 -0
  4. data/Rakefile +206 -0
  5. data/examples/titlepage.rb +14 -0
  6. data/examples/www/find_all.rb +23 -0
  7. data/examples/www/find_cover_from_amazon.rb +12 -0
  8. data/examples/www/find_url_from_rainbow.rb +12 -0
  9. data/examples/www/list.rb +13 -0
  10. data/lib/rbook/bisac.rb +175 -0
  11. data/lib/rbook/errors.rb +7 -0
  12. data/lib/rbook/isbn.rb +249 -0
  13. data/lib/rbook/onix.rb +68 -0
  14. data/lib/rbook/onix/contributor.rb +60 -0
  15. data/lib/rbook/onix/lists.rb +2 -0
  16. data/lib/rbook/onix/lists/contributor_role.rb +10 -0
  17. data/lib/rbook/onix/lists/product_form.rb +100 -0
  18. data/lib/rbook/onix/message.rb +101 -0
  19. data/lib/rbook/onix/product.rb +188 -0
  20. data/lib/rbook/onix/sales_restriction.rb +51 -0
  21. data/lib/rbook/onix/supply_detail.rb +68 -0
  22. data/lib/rbook/onix/xchar.rb +98 -0
  23. data/lib/rbook/titlepage.rb +96 -0
  24. data/lib/rbook/titlepage/TitleQueryClient.rb +62 -0
  25. data/lib/rbook/titlepage/titlepage_driver.rb +134 -0
  26. data/lib/rbook/titlepage/titlepage_utils.rb +374 -0
  27. data/lib/rbook/www.rb +172 -0
  28. data/lib/rbook/www/aau_scraper.rb +76 -0
  29. data/lib/rbook/www/amazon_uk_scraper.rb +44 -0
  30. data/lib/rbook/www/base.rb +87 -0
  31. data/lib/rbook/www/harper_au_scraper.rb +56 -0
  32. data/lib/rbook/www/harper_us_scraper.rb +55 -0
  33. data/lib/rbook/www/hha_scraper.rb +50 -0
  34. data/lib/rbook/www/macmillan_scraper.rb +62 -0
  35. data/lib/rbook/www/orbis_scraper.rb +48 -0
  36. data/lib/rbook/www/oup_scraper.rb +64 -0
  37. data/lib/rbook/www/paulist_scraper.rb +53 -0
  38. data/lib/rbook/www/pearson_au_scraper.rb +52 -0
  39. data/lib/rbook/www/penguin_scraper.rb +45 -0
  40. data/lib/rbook/www/random_au_scraper.rb +90 -0
  41. data/lib/rbook/www/random_us_scraper.rb +59 -0
  42. data/lib/rbook/www/sas_scraper.rb +54 -0
  43. data/lib/rbook/www/unireps_scraper.rb +58 -0
  44. data/lib/rbook/www/wiley_us_scraper.rb +54 -0
  45. data/test/data/abingdon.xml +38931 -0
  46. data/test/data/augsburg.xml +39009 -0
  47. data/test/data/chalice.xml +10851 -0
  48. data/test/data/eerdsman.xml +36942 -0
  49. data/test/data/invalid_no_product.xml +9 -0
  50. data/test/data/not_xml.csv +1 -0
  51. data/test/data/single_product.xml +50 -0
  52. data/test/data/xml_not_onix.xml +7 -0
  53. data/test/mocks/titlepage_driver.rb +107 -0
  54. data/test/unit/bisac_test.rb +57 -0
  55. data/test/unit/isbn_test.rb +149 -0
  56. data/test/unit/onix/contributor_test.rb +50 -0
  57. data/test/unit/onix/message_test.rb +119 -0
  58. data/test/unit/onix/product_test.rb +101 -0
  59. data/test/unit/onix/sales_restriction_test.rb +48 -0
  60. data/test/unit/onix/supply_detail_test.rb +53 -0
  61. data/test/unit/onix/xchar_test.rb +37 -0
  62. data/test/unit/titlepage_test.rb +127 -0
  63. metadata +130 -0
@@ -0,0 +1,51 @@
1
+ require 'rexml/document'
2
+ require 'rubygems'
3
+
4
+ module RBook
5
+ module Onix
6
+
7
+ class SalesRestriction
8
+ attr_accessor :type, :detail
9
+
10
+ # Attempts to create a contributor object using the supplied xml element
11
+ def SalesRestriction.load_from_element(element)
12
+ raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
13
+
14
+ if REXML::XPath.first(element, '//SalesRestriction').nil?
15
+ raise LoadError, 'supplied REXML document object does not appear contain a valid SalesRestriction fragment'
16
+ end
17
+
18
+ restriction = SalesRestriction.new
19
+
20
+ tmp = REXML::XPath.first(element, '//SalesRestriction/SalesRestrictionType')
21
+ restriction.type = tmp.text if tmp != nil
22
+
23
+ tmp = REXML::XPath.first(element, '//SalesRestriction/SalesRestrictionDetail')
24
+ restriction.detail = tmp.text if tmp != nil
25
+
26
+ return restriction
27
+
28
+ end
29
+
30
+ # Return an xml element representing this contributor
31
+ def to_element
32
+ raise 'SalesRestriction must have a type to create an element' if self.type.nil?
33
+ raise 'Contributor must have a detail to create an element' if self.detail.nil?
34
+
35
+ restriction = REXML::Element.new('SalesRestriction')
36
+ restriction.add_element('SalesRestrictionType').text = self.type.to_xs
37
+ restriction.add_element('SalesRestrictionDetail').text = self.detail.to_xs
38
+
39
+ return restriction
40
+ end
41
+
42
+ # Return an XML string representing this contributor
43
+ def to_s
44
+ tmp = to_element
45
+ output = ''
46
+ tmp.write(output, 0)
47
+ return output
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,68 @@
1
+ require 'rexml/document'
2
+ require 'bigdecimal'
3
+ require 'rubygems'
4
+
5
+ module RBook
6
+ module Onix
7
+
8
+ class SupplyDetail
9
+ attr_accessor :supplier_name, :availability_code, :intermediary_availability_code, :price
10
+
11
+ # Attempts to create a contributor object using the supplied xml element
12
+ def self.load_from_element(element)
13
+ raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
14
+
15
+ if REXML::XPath.first(element, '//SupplyDetail').nil?
16
+ raise LoadError, 'supplied REXML document object does not appear contain a valid SupplyDetail fragment'
17
+ end
18
+
19
+ supply_detail = SupplyDetail.new
20
+
21
+ tmp = REXML::XPath.first(element, '//SupplyDetail/SupplierName')
22
+ supply_detail.supplier_name = tmp.text if tmp != nil
23
+
24
+ tmp = REXML::XPath.first(element, '//SupplyDetail/AvailabilityCode')
25
+ supply_detail.availability_code = tmp.text if tmp != nil
26
+
27
+ tmp = REXML::XPath.first(element, '//SupplyDetail/IntermediaryAvailabilityCode')
28
+ supply_detail.intermediary_availability_code = tmp.text if tmp != nil
29
+
30
+ tmp = REXML::XPath.first(element, '//SupplyDetail/Price/PriceAmount')
31
+ supply_detail.price = BigDecimal(tmp.text) if tmp != nil
32
+
33
+ return supply_detail
34
+
35
+ end
36
+
37
+ # Return an xml element representing this contributor
38
+ def to_element
39
+ raise 'SupplyDetail must have a supplier name to create an element' if self.supplier_name.nil?
40
+ raise 'SupplyDetail must have a availability code to create an element' if self.availability_code.nil?
41
+
42
+ supply_detail = REXML::Element.new('SupplyDetail')
43
+ supply_detail.add_element('SupplierName').text = self.supplier_name.to_xs
44
+ supply_detail.add_element('AvailabilityCode').text = self.availability_code.to_xs unless self.availability_code.nil?
45
+ supply_detail.add_element('IntermediaryAvailabilityCode').text = self.intermediary_availability_code_to_xs unless self.intermediary_availability_code.nil?
46
+ unless self.price.nil?
47
+ tmp = REXML::Element.new('Price')
48
+ if self.price.kind_of?(BigDecimal)
49
+ tmp.add_element('PriceAmount').text = self.price.to_s("F")
50
+ else
51
+ tmp.add_element('PriceAmount').text = self.price.to_s
52
+ end
53
+ supply_detail.add_element(tmp)
54
+ end
55
+
56
+ return supply_detail
57
+ end
58
+
59
+ # Return an XML string representing this contributor
60
+ def to_s
61
+ tmp = to_element
62
+ output = ''
63
+ tmp.write(output, 0)
64
+ return output
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,98 @@
1
+ # sourced from http://www.intertwingly.net/blog/2005/09/28/XML-Cleansing
2
+
3
+ module XChar
4
+ # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
5
+ CP1252 = {
6
+ 128 => 8364, # euro sign
7
+ 130 => 8218, # single low-9 quotation mark
8
+ 131 => 402, # latin small letter f with hook
9
+ 132 => 8222, # double low-9 quotation mark
10
+ 133 => 8230, # horizontal ellipsis
11
+ 134 => 8224, # dagger
12
+ 135 => 8225, # double dagger
13
+ 136 => 710, # modifier letter circumflex accent
14
+ 137 => 8240, # per mille sign
15
+ 138 => 352, # latin capital letter s with caron
16
+ 139 => 8249, # single left-pointing angle quotation mark
17
+ 140 => 338, # latin capital ligature oe
18
+ 142 => 381, # latin capital letter z with caron
19
+ 145 => 8216, # left single quotation mark
20
+ 146 => 8217, # right single quotation mark
21
+ 147 => 8220, # left double quotation mark
22
+ 148 => 8221, # right double quotation mark
23
+ 149 => 8226, # bullet
24
+ 150 => 8211, # en dash
25
+ 151 => 8212, # em dash
26
+ 152 => 732, # small tilde
27
+ 153 => 8482, # trade mark sign
28
+ 154 => 353, # latin small letter s with caron
29
+ 155 => 8250, # single right-pointing angle quotation mark
30
+ 156 => 339, # latin small ligature oe
31
+ 158 => 382, # latin small letter z with caron
32
+ 159 => 376} # latin capital letter y with diaeresis
33
+
34
+ # http://www.w3.org/TR/REC-xml/#dt-chardata
35
+ PREDEFINED = {
36
+ 38 => '&', # ampersand
37
+ 60 => '<', # left angle bracket
38
+ 62 => '>'} # right angle bracket
39
+
40
+ # http://www.w3.org/TR/REC-xml/#charsets
41
+ VALID = [[0x9, 0xA, 0xD], (0x20..0xD7FF),
42
+ (0xE000..0xFFFD), (0x10000..0x10FFFF)]
43
+ end
44
+
45
+ class Fixnum
46
+ # xml escaped version of chr
47
+ def xchr
48
+ n = XChar::CP1252[self] || self
49
+ n = 42 unless XChar::VALID.find {|range| range.include? n}
50
+ XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
51
+ end
52
+ end
53
+
54
+ class String
55
+ # xml escaped version of to_s
56
+ def to_xs
57
+ unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8
58
+ rescue
59
+ unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
60
+ end
61
+ end
62
+
63
+ =begin
64
+ require 'test/unit'
65
+
66
+ class TestXmlEscaping < Test::Unit::TestCase
67
+ def test_ascii
68
+ assert_equal 'abc', 'abc'.to_xs
69
+ end
70
+
71
+ def test_predefined
72
+ assert_equal '&amp;', '&'.to_xs # ampersand
73
+ assert_equal '&lt;', '<'.to_xs # left angle bracket
74
+ assert_equal '&gt;', '>'.to_xs # right angle bracket
75
+ end
76
+
77
+ def test_invalid
78
+ assert_equal '*', "\x00".to_xs # null
79
+ assert_equal '*', "\x0C".to_xs # form feed
80
+ assert_equal '*', "\xEF\xBF\xBF".to_xs # U+FFFF
81
+ end
82
+
83
+ def test_iso_8859_1
84
+ assert_equal '&#231;', "\xE7".to_xs # small c cedilla
85
+ assert_equal '&#169;', "\xA9".to_xs # copyright symbol
86
+ end
87
+
88
+ def test_win_1252
89
+ assert_equal '&#8217;', "\x92".to_xs # smart quote
90
+ assert_equal '&#8364;', "\x80".to_xs # euro
91
+ end
92
+
93
+ def test_utf8
94
+ assert_equal '&#8217;', "\xE2\x80\x99".to_xs # right single quote
95
+ assert_equal '&#169;', "\xC2\xA9".to_xs # copy
96
+ end
97
+ end
98
+ =end
@@ -0,0 +1,96 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../")
2
+
3
+ require 'rbook/isbn'
4
+ require 'rbook/errors'
5
+ require 'rbook/titlepage/titlepage_driver'
6
+
7
+ module RBook
8
+
9
+ # a convenience class for accessing the SOAP API for http://www.titlepage.com.
10
+ # Uses boilerplate code generated by soap4r.
11
+ #
12
+ # You should be aware of any limits of query volume imposed by the provider - currently a
13
+ # maximum of 30 queries per minute is permitted.
14
+ #
15
+ # All examples require the following two lines at the top of your file:
16
+ # require 'rubygems'
17
+ # require 'rbook/titlepage'
18
+ #
19
+ # Basic usage:
20
+ # tp = Book::TitlePage.new
21
+ # tp.login('someuser','topsecret')
22
+ # puts tp.find("0091835135").inspect
23
+ # sleep 3
24
+ # puts tp.find("9780672327568").inspect
25
+ # tp.logout
26
+ #
27
+ # Alternative Usage:
28
+ # RBook::TitlePage.open("username","password") do |tp|
29
+ # puts tp.find("0091835135").inspect
30
+ # sleep 3
31
+ # puts tp.find("9780672327568").inspect
32
+ # end
33
+ class TitlePage
34
+
35
+ # Optional driver parameter allows an alternative SOAP driver to the default to be specified.
36
+ # This is primarily for testing purposes and probably isn't useful to anyone in the real world.
37
+ def initialize(driver = nil)
38
+ @driver = driver || TitleQueryPortType.new
39
+ @token = nil
40
+ end
41
+
42
+ # login to the titlepage API.
43
+ def login(username, password)
44
+ raise InvalidRubyVersionError, 'Ruby 1.8.3 or higher is required to use this class' unless RUBY_VERSION >= "1.8.3"
45
+ logout if @token
46
+ @token = @driver.login(username, password)
47
+ return true if @token
48
+ end
49
+
50
+ # logout from the titlepage API
51
+ def logout
52
+ if @token
53
+ @driver.logout(@token)
54
+ end
55
+ end
56
+
57
+ # retrieve information on a specified ISBN
58
+ def find(isbn)
59
+ return NotLoggedInError, 'You must login to titlepage API before performing a search' unless @token
60
+ isbn = ISBN::convert_to_isbn13(isbn)
61
+ return nil if isbn.nil?
62
+ begin
63
+ result = @driver.SearchByEAN(@token, isbn)
64
+ if result.Product.nil?
65
+ return nil
66
+ else
67
+ return result
68
+ end
69
+ rescue
70
+ return nil
71
+ end
72
+
73
+ end
74
+
75
+ # a convenience method to make queries to title page a little cleaner. This function
76
+ # essentially calls the login and logout functions for you automatically.
77
+ #
78
+ # RBook::TitlePage.open("username","password") do |tp|
79
+ # result = tp.find("9780091835132")
80
+ # end
81
+ def TitlePage.open(username, password, driver = nil)
82
+
83
+ tp = TitlePage.new(driver || TitleQueryPortType.new)
84
+
85
+ begin
86
+ tp.login(username, password)
87
+
88
+ yield(tp)
89
+
90
+ ensure
91
+ tp.logout
92
+ end
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ require 'defaultDriver.rb'
3
+
4
+ endpoint_url = ARGV.shift
5
+ obj = TitleQueryPortType.new(endpoint_url)
6
+
7
+ # run ruby with -d to see SOAP wiredumps.
8
+ obj.wiredump_dev = STDERR if $DEBUG
9
+
10
+ # SYNOPSIS
11
+ # Login(userName, password)
12
+ #
13
+ # ARGS
14
+ # userName String - {http://www.w3.org/2001/XMLSchema}string
15
+ # password String - {http://www.w3.org/2001/XMLSchema}string
16
+ #
17
+ # RETURNS
18
+ # token String - {http://www.w3.org/2001/XMLSchema}string
19
+ #
20
+ userName = "rba303"
21
+ password = "ra1nb0Wb"
22
+ puts obj.login(userName, password)
23
+
24
+ # SYNOPSIS
25
+ # SearchByISBN(token, iSBN)
26
+ #
27
+ # ARGS
28
+ # token String - {http://www.w3.org/2001/XMLSchema}string
29
+ # iSBN String - {http://www.w3.org/2001/XMLSchema}string
30
+ #
31
+ # RETURNS
32
+ # searchResults SearchResults - {urn:TitleQuery}SearchResults
33
+ #
34
+ token = iSBN = nil
35
+ puts obj.searchByISBN(token, iSBN)
36
+
37
+ # SYNOPSIS
38
+ # SearchByEAN(token, eAN)
39
+ #
40
+ # ARGS
41
+ # token String - {http://www.w3.org/2001/XMLSchema}string
42
+ # eAN String - {http://www.w3.org/2001/XMLSchema}string
43
+ #
44
+ # RETURNS
45
+ # searchResults SearchResults - {urn:TitleQuery}SearchResults
46
+ #
47
+ token = eAN = nil
48
+ puts obj.searchByEAN(token, eAN)
49
+
50
+ # SYNOPSIS
51
+ # Logout(token)
52
+ #
53
+ # ARGS
54
+ # token String - {http://www.w3.org/2001/XMLSchema}string
55
+ #
56
+ # RETURNS
57
+ # N/A
58
+ #
59
+ token = nil
60
+ puts obj.logout(token)
61
+
62
+
@@ -0,0 +1,134 @@
1
+ require File.dirname(__FILE__) + '/titlepage_utils.rb'
2
+
3
+ require 'soap/rpc/driver'
4
+
5
+ class TitleQueryPortType < ::SOAP::RPC::Driver
6
+ DefaultEndpointUrl = "http://www.titlepage.com.au/ws/TitleQuery.php"
7
+ MappingRegistry = ::SOAP::Mapping::Registry.new
8
+
9
+ MappingRegistry.set(
10
+ SearchResults,
11
+ ::SOAP::SOAPStruct,
12
+ ::SOAP::Mapping::Registry::TypedStructFactory,
13
+ { :type => XSD::QName.new("urn:TitleQuery", "SearchResults") }
14
+ )
15
+ MappingRegistry.set(
16
+ Product,
17
+ ::SOAP::SOAPStruct,
18
+ ::SOAP::Mapping::Registry::TypedStructFactory,
19
+ { :type => XSD::QName.new("urn:TitleQuery", "Product") }
20
+ )
21
+ MappingRegistry.set(
22
+ ArrayOfProductIdentifier,
23
+ ::SOAP::SOAPArray,
24
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
25
+ { :type => XSD::QName.new("urn:TitleQuery", "ProductIdentifier") }
26
+ )
27
+ MappingRegistry.set(
28
+ Title,
29
+ ::SOAP::SOAPStruct,
30
+ ::SOAP::Mapping::Registry::TypedStructFactory,
31
+ { :type => XSD::QName.new("urn:TitleQuery", "Title") }
32
+ )
33
+ MappingRegistry.set(
34
+ ArrayOfContributor,
35
+ ::SOAP::SOAPArray,
36
+ ::SOAP::Mapping::Registry::TypedArrayFactory,
37
+ { :type => XSD::QName.new("urn:TitleQuery", "Contributor") }
38
+ )
39
+ MappingRegistry.set(
40
+ SupplyDetail,
41
+ ::SOAP::SOAPStruct,
42
+ ::SOAP::Mapping::Registry::TypedStructFactory,
43
+ { :type => XSD::QName.new("urn:TitleQuery", "SupplyDetail") }
44
+ )
45
+ MappingRegistry.set(
46
+ Stock,
47
+ ::SOAP::SOAPStruct,
48
+ ::SOAP::Mapping::Registry::TypedStructFactory,
49
+ { :type => XSD::QName.new("urn:TitleQuery", "Stock") }
50
+ )
51
+ MappingRegistry.set(
52
+ Price,
53
+ ::SOAP::SOAPStruct,
54
+ ::SOAP::Mapping::Registry::TypedStructFactory,
55
+ { :type => XSD::QName.new("urn:TitleQuery", "Price") }
56
+ )
57
+ MappingRegistry.set(
58
+ ProductIdentifier,
59
+ ::SOAP::SOAPStruct,
60
+ ::SOAP::Mapping::Registry::TypedStructFactory,
61
+ { :type => XSD::QName.new("urn:TitleQuery", "ProductIdentifier") }
62
+ )
63
+ MappingRegistry.set(
64
+ Contributor,
65
+ ::SOAP::SOAPStruct,
66
+ ::SOAP::Mapping::Registry::TypedStructFactory,
67
+ { :type => XSD::QName.new("urn:TitleQuery", "Contributor") }
68
+ )
69
+
70
+ Methods = [
71
+ [ XSD::QName.new("http://www.titlepage.com/ws", "Login"),
72
+ "http://www.titlepage.com.au/ws/TitleQuery.php/Login",
73
+ "login",
74
+ [ ["in", "UserName", ["::SOAP::SOAPString"]],
75
+ ["in", "Password", ["::SOAP::SOAPString"]],
76
+ ["retval", "Token", ["::SOAP::SOAPString"]] ],
77
+ { :request_style => :rpc, :request_use => :encoded,
78
+ :response_style => :rpc, :response_use => :encoded }
79
+ ],
80
+ [ XSD::QName.new("http://www.titlepage.com/ws", "SearchByISBN"),
81
+ "http://www.titlepage.com.au/ws/TitleQuery.php/SearchByISBN",
82
+ "searchByISBN",
83
+ [ ["in", "Token", ["::SOAP::SOAPString"]],
84
+ ["in", "ISBN", ["::SOAP::SOAPString"]],
85
+ ["retval", "SearchResults", ["SearchResults", "urn:TitleQuery", "SearchResults"]] ],
86
+ { :request_style => :rpc, :request_use => :encoded,
87
+ :response_style => :rpc, :response_use => :encoded }
88
+ ],
89
+ [ XSD::QName.new("http://www.titlepage.com/ws", "SearchByEAN"),
90
+ "http://www.titlepage.com.au/ws/TitleQuery.php/SearchByEAN",
91
+ "searchByEAN",
92
+ [ ["in", "Token", ["::SOAP::SOAPString"]],
93
+ ["in", "EAN", ["::SOAP::SOAPString"]],
94
+ ["retval", "SearchResults", ["SearchResults", "urn:TitleQuery", "SearchResults"]] ],
95
+ { :request_style => :rpc, :request_use => :encoded,
96
+ :response_style => :rpc, :response_use => :encoded }
97
+ ],
98
+ [ XSD::QName.new("http://www.titlepage.com/ws", "Logout"),
99
+ "http://www.titlepage.com.au/ws/TitleQuery.php/Logout",
100
+ "logout",
101
+ [ ["in", "token", ["::SOAP::SOAPString"]] ],
102
+ { :request_style => :rpc, :request_use => :encoded,
103
+ :response_style => :rpc, :response_use => :encoded }
104
+ ]
105
+ ]
106
+
107
+ def initialize(endpoint_url = nil)
108
+ endpoint_url ||= DefaultEndpointUrl
109
+ super(endpoint_url, nil)
110
+ self.mapping_registry = MappingRegistry
111
+ init_methods
112
+ end
113
+
114
+ private
115
+
116
+ def init_methods
117
+ Methods.each do |definitions|
118
+ opt = definitions.last
119
+ if opt[:request_style] == :document
120
+ add_document_operation(*definitions)
121
+ else
122
+ add_rpc_operation(*definitions)
123
+ qname = definitions[0]
124
+ name = definitions[2]
125
+ if qname.name != name and qname.name.capitalize == name.capitalize
126
+ ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg|
127
+ __send__(name, *arg)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+