ebay-trader 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,151 @@
1
+ #require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/string'
3
+ require 'hash_with_indifferent_access'
4
+
5
+ module EbayTrader
6
+ class SaxHandler
7
+
8
+ attr_accessor :stack
9
+ attr_accessor :path
10
+ attr_reader :skip_type_casting
11
+ attr_reader :known_arrays
12
+
13
+ def initialize(args = {})
14
+ @stack = []
15
+ @stack.push(HashWithIndifferentAccess.new)
16
+ @path = []
17
+ @hash = nil
18
+ @attributes = {}
19
+
20
+ @skip_type_casting = args[:skip_type_casting] || []
21
+ @skip_type_casting = [@skip_type_casting] unless @skip_type_casting.is_a?(Array)
22
+ @skip_type_casting.map! { |key| format(key.to_s) }
23
+
24
+ @known_arrays = args[:known_arrays] || []
25
+ @known_arrays = [@known_arrays] unless @known_arrays.is_a?(Array)
26
+ @known_arrays.map! { |key| format(key.to_s) }
27
+ end
28
+
29
+ def to_hash
30
+ stack[0]
31
+ end
32
+
33
+ def start_element(name)
34
+ @attributes.clear
35
+ name = name.to_s
36
+ path.push(name)
37
+
38
+ hash = HashWithIndifferentAccess.new
39
+ append(format_key(name), hash)
40
+ stack.push(hash)
41
+ end
42
+
43
+ def end_element(_)
44
+ @stack.pop
45
+ @path.pop
46
+ end
47
+
48
+ def text(value)
49
+ key = format_key(path.last)
50
+ auto_cast = !(skip_type_casting.include?(path.last) || skip_type_casting.include?(key.to_s))
51
+ parent = @stack[-2]
52
+
53
+ # If 'CurrencyID' is a defined attribute we are dealing with money type
54
+ if @attributes.key?('CurrencyID')
55
+ currency = @attributes.delete('CurrencyID')
56
+ value = BigDecimal.new(value)
57
+ if EbayTrader.configuration.price_type == :money && EbayTrader.is_money_gem_installed?
58
+ value = Money.new((value * 100).round.to_i, currency)
59
+ else
60
+ @attributes['Currency'] = currency
61
+ value = value.to_f if EbayTrader.configuration.price_type == :float
62
+ value = (value * 100).round.to_i if EbayTrader.configuration.price_type == :fixnum
63
+ end
64
+ end
65
+
66
+ if auto_cast && value.is_a?(String)
67
+ case
68
+ when value.downcase == 'false' then value = false
69
+ when value.downcase == 'true' then value = true
70
+ when value.match(/^[0-9]+$/) then value = value.to_i
71
+ when value.match(/^[0-9]+[.][0-9]+$/) then value = value.to_f
72
+ when value.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2}[T ][0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9a-z]+)?$/i)
73
+ value = Time.parse(value)
74
+ end
75
+ end
76
+
77
+ if parent[key].is_a?(Array)
78
+ parent[key].pop if parent[key].last.is_a?(Hash) && parent[key].last.empty?
79
+ parent[key] << value
80
+ else
81
+ parent[key] = value
82
+ end
83
+
84
+ unless @attributes.empty?
85
+ @attributes.each_pair do |attr_key, attr_value|
86
+ attr_key_element_name = format_key("#{path.last}#{attr_key}")
87
+ parent[attr_key_element_name] = attr_value
88
+ end
89
+ end
90
+ end
91
+
92
+ def cdata(value)
93
+ key = format_key(path.last)
94
+ parent = @stack[-2]
95
+ parent[key] = value
96
+ end
97
+
98
+ def attr(name, value)
99
+ return if name.to_s.downcase == 'xmlns'
100
+ last = path.last
101
+ return if last.nil?
102
+
103
+ name = name[0].upcase + name[1...name.length]
104
+ @attributes[name] = value
105
+ end
106
+
107
+ def error(message, line, column)
108
+ raise Exception.new("#{message} at #{line}:#{column}")
109
+ end
110
+
111
+ def append(key, value)
112
+ key = key.to_s
113
+ h = @stack.last
114
+ if h.key?(key)
115
+ v = h[key]
116
+ if v.is_a?(Array)
117
+ v << value
118
+ else
119
+ h[key] = [v, value]
120
+ end
121
+ else
122
+ if known_arrays.include?(key)
123
+ h[key] = [value]
124
+ else
125
+ h[key] = value
126
+ end
127
+ end
128
+ end
129
+
130
+ #-------------------------------------------------------------------------
131
+ private
132
+
133
+ # Ensure the key is an underscored Symbol.
134
+ #
135
+ # Examples:
136
+ #
137
+ # 'ApplyBuyerProtection' -> :apply_buyer_protection
138
+ # 'PayPalEmailAddress' -> :paypal_email_address
139
+ # 'SoldOffeBay' -> :sold_off_ebay
140
+ #
141
+ # @return [Symbol] the reformatted key.
142
+ #
143
+ def format_key(key)
144
+ key = key.to_s
145
+ key = key.gsub('PayPal', 'Paypal')
146
+ key = key.gsub('eBay', 'Ebay')
147
+ key = key.gsub('EBay', 'Ebay')
148
+ key.underscore.to_sym
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,71 @@
1
+ require 'cgi'
2
+ require 'ebay_trader/request'
3
+
4
+ module EbayTrader
5
+
6
+ # Request a session ID from the eBay API.
7
+ #
8
+ # @see http://developer.ebay.com/DevZone/XML/docs/Reference/eBay/GetSessionID.html
9
+ # @see http://developer.ebay.com/DevZone/XML/docs/HowTo/Tokens/GettingTokens.html
10
+ # @see http://developer.ebay.com/DevZone/guides/ebayfeatures/Basics/Tokens-MultipleUsers.html
11
+ #
12
+ class SessionID < Request
13
+
14
+ CALL_NAME = 'GetSessionID'
15
+
16
+ # The application RuName defined in {Configuration#ru_name}, unless over-ridden in {#initialize} args.
17
+ # @return [String] the RuName for this call.
18
+ # @see https://developer.ebay.com/DevZone/account/appsettings/Consent/
19
+ #
20
+ attr_reader :ru_name
21
+
22
+ # Construct a GetSessionID eBay API call.
23
+ # @param [Hash] args a hash of optional arguments.
24
+ # @option args [String] :ru_name Override the default RuName,
25
+ # which should be defined in {Configuration#ru_name}.
26
+ #
27
+ def initialize(args = {})
28
+ @ru_name = (args[:ru_name] || EbayTrader.configuration.ru_name).freeze
29
+
30
+ super(CALL_NAME, args) do
31
+ RuName ru_name
32
+ end
33
+ end
34
+
35
+ # Get the session ID returned by the API call.
36
+ # @return [String] the session ID.
37
+ #
38
+ def id
39
+ response_hash[:session_id]
40
+ end
41
+
42
+ # Get the URL through which a user must sign in using this session ID.
43
+ # @param [Hash] ruparams eBay appends this data to the AcceptURL and RejectURL.
44
+ # In a typical rails app this might include the user's model primary key.
45
+ # @return [String] the sign-in URL.
46
+ #
47
+ def sign_in_url(ruparams = {})
48
+ url = EbayTrader.configuration.production? ? 'https://signin.ebay.com' : 'https://signin.sandbox.ebay.com'
49
+ url << '/ws/eBayISAPI.dll?SignIn'
50
+ url << "&runame=#{url_encode ru_name}"
51
+ url << "&SessID=#{url_encode id}"
52
+ if ruparams && ruparams.is_a?(Hash) && !ruparams.empty?
53
+ params = []
54
+ ruparams.each_pair { |key, value| params << "#{key}=#{value}" }
55
+ url << "&ruparams=#{url_encode(params.join('&'))}"
56
+ end
57
+ url
58
+ end
59
+
60
+ #---------------------------------------------------------------
61
+ private
62
+
63
+ def url_encode(string)
64
+ CGI.escape string
65
+ end
66
+
67
+ def url_decode(string)
68
+ CGI.unescape string
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ module EbayTrader
2
+ VERSION = '0.9.5'
3
+ end
@@ -0,0 +1,113 @@
1
+ module EbayTrader
2
+ class XMLBuilder
3
+
4
+ attr_reader :context, :xml, :depth, :tab_width
5
+
6
+ def initialize(args = {})
7
+ @xml = ''
8
+ @depth = 0
9
+ @tab_width = (args[:tab_width] || 0).to_i
10
+ end
11
+
12
+ # Catch-all method to avoid having to create individual methods for each XML tag name.
13
+ def method_missing(method_name, *args, &block)
14
+ if @context && @context.respond_to?(method_name)
15
+ @context.send(method_name, *args, &block)
16
+ else
17
+ node(method_name, args, &block)
18
+ end
19
+ end
20
+
21
+ # Only respond to method names with only numbers and letters.
22
+ # Do not respond to names with underscores.
23
+ def respond_to_missing?(method_name, include_private = false)
24
+ super || method_name.to_s =~ /^[a-z0-9]+$/i
25
+ end
26
+
27
+ # Begin creating an XML string by specifying the root node.
28
+ # This also set the context scope, allowing methods and variable
29
+ # outside the block to be accessed.
30
+ # @param [String] name the name of the root node element.
31
+ # @param [Array] args the data for this element.
32
+ # @param [Block] block an optional block of sub-elements to be nested
33
+ # within the root node.
34
+ def root(name, *args, &block)
35
+ set_context(&block)
36
+ node(name, args, &block)
37
+ end
38
+
39
+ #---------------------------------------------------------------------------
40
+ private
41
+
42
+ # @see https://github.com/sparklemotion/nokogiri/blob/master/lib/nokogiri/xml/builder.rb
43
+ def set_context(&block)
44
+ @context = block_given? ? eval('self', block.binding) : nil
45
+ @context = nil if @context.is_a?(XMLBuilder)
46
+ end
47
+
48
+ # Create an XML node
49
+ # @param [String|Symbol] name the name of the XML element (ul, li, strong, etc...)
50
+ # @param [Array] args Can contain a String of text or a Hash of attributes
51
+ # @param [Block] block An optional block which will further nest XML
52
+ def node(name, args, &block)
53
+ content = get_node_content(args)
54
+ options = format_node_attributes(get_node_attributes(args))
55
+
56
+ @xml << "#{indent_new_line}<#{name}#{options}>#{content}"
57
+ if block_given?
58
+ @depth += 1
59
+ instance_eval(&block)
60
+ @depth -= 1
61
+ @xml << indent_new_line
62
+ end
63
+ @xml << "</#{name}>"
64
+ @xml.strip
65
+ end
66
+
67
+ # Return the first Hash in the list of arguments to #node
68
+ # as this defines the attributes for the XML node.
69
+ # @return [Hash] the hash of attributes for this node.
70
+ #
71
+ def get_node_attributes(args)
72
+ args.detect { |arg| arg.is_a? Hash } || {}
73
+ end
74
+
75
+ # Return the node content as a String, unless a block is given.
76
+ # @return [String] the node data.
77
+ #
78
+ def get_node_content(args)
79
+ return nil if block_given?
80
+ content = nil
81
+ args.each do |arg|
82
+ case arg
83
+ when Hash
84
+ next
85
+ when Time
86
+ # eBay official TimeStamp format YYYY-MM-DDTHH:MM:SS.SSSZ
87
+ content = arg.strftime('%Y-%m-%dT%H:%M:%S.%Z')
88
+ when DateTime
89
+ content = arg.strftime('%Y-%m-%dT%H:%M:%S.%Z')
90
+ break
91
+ else
92
+ content = arg.to_s
93
+ break
94
+ end
95
+ end
96
+ content
97
+ end
98
+
99
+ # Convert the given Hash of options into a string of XML element attributes.
100
+ #
101
+ def format_node_attributes(options)
102
+ options.collect { |key, value|
103
+ value = value.to_s.gsub('"', '\"')
104
+ " #{key}=\"#{value}\""
105
+ }.join('')
106
+ end
107
+
108
+ # Add a new line to the XML and indent with the appropriate number of spaces.
109
+ def indent_new_line
110
+ tab_width > 0 ? ("\n" + (' ' * tab_width * depth)) : ''
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,23 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+
3
+ class HashWithIndifferentAccess
4
+
5
+ # Perform a depth first search of this hash and return the first element
6
+ # matching +path+, or +default+ if nothing found.
7
+ # @param [Array[String | Symbol] | String | Symbol] path to the element of interest.
8
+ # @param [Object] default the object to be returned if there is no result for +path+.
9
+ # @return [Object] the first object found on +path+ or +default+.
10
+ #
11
+ def deep_find(path, default = nil)
12
+ return default unless path
13
+ path = [path] if path.is_a?(String) || path.is_a?(Symbol)
14
+ return default unless path.is_a?(Array) && !path.empty?
15
+
16
+ location = self
17
+ path.each do |key|
18
+ return default if location.nil? || !location.key?(key)
19
+ location = location[key]
20
+ end
21
+ return location
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ebay-trader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.5
5
+ platform: ruby
6
+ authors:
7
+ - Rob Graham
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ox
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.2'
83
+ description: |2
84
+ EbayTrader is a lightweight easy to use Ruby gem for interacting with eBay's Trading API.
85
+ Using its simple DSL you can quickly and intuitively post XML requests to eBay and rapidly interpret the responses.
86
+ email:
87
+ - rob@altabyte.com
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".rspec"
94
+ - ".travis.yml"
95
+ - Gemfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - bin/console
100
+ - bin/setup
101
+ - ebay_trader.gemspec
102
+ - examples/get_categories.rb
103
+ - examples/more_examples.rb
104
+ - lib/ebay_trader.rb
105
+ - lib/ebay_trader/configuration.rb
106
+ - lib/ebay_trader/fetch_token.rb
107
+ - lib/ebay_trader/request.rb
108
+ - lib/ebay_trader/sax_handler.rb
109
+ - lib/ebay_trader/session_id.rb
110
+ - lib/ebay_trader/version.rb
111
+ - lib/ebay_trader/xml_builder.rb
112
+ - lib/hash_with_indifferent_access.rb
113
+ homepage: https://github.com/altabyte/ebay_trader
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubyforge_project:
133
+ rubygems_version: 2.4.6
134
+ signing_key:
135
+ specification_version: 4
136
+ summary: A DSL to interact with eBay's Trading API using Ruby
137
+ test_files: []
138
+ has_rdoc: