backpack_tf 0.2.1 → 0.5.0

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
  SHA1:
3
- metadata.gz: 5b3f89b16c6ef3907403d7a9caab7457e740bd02
4
- data.tar.gz: e41e8dbf4ba4bc3db93a40197cac519e22d3b106
3
+ metadata.gz: c0bb160d7663670acc3d14ca49f79e5fc97f8387
4
+ data.tar.gz: d928ca0ec022d0e73cebb5bd174dac654621623e
5
5
  SHA512:
6
- metadata.gz: 29b1583190c592fcba721473e9800d1b9ed2d7b80a2d841917469513ef9db6e73a66ae3ac6c1e044718024f6e04f2192b1440d6da26234075c3a4deff332566e
7
- data.tar.gz: 83f26e2dafd51d449cf205d6244a0575afe9e882a017dec8b8e86b88fb7ab30257c2d40d2ed6d983995c00fc63683ba7409eec4b0ea20f4a10527c966822cb39
6
+ metadata.gz: 5e10182770c9739e8ff40067e3da906923be2b2684a664e8e8d56fe9885e5dd1dda9c22b83fe95e22ee31bae202944e38a9ac81c9aa0b6beb6ba234c1ce9273e
7
+ data.tar.gz: e0f8b763197c2f372385f090d4d9caa2d61688da1c37efeab0ae2ce37e5cffe1cc14d0a78d6b5ec23cb6918eae3cc4b39b44f35b48655ceedd47997ff2e1af1d
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  *.sw*
2
2
  *dump.rdb
3
3
 
4
+ .ruby-version
4
5
  *.gem
5
6
  Gemfile.lock
6
7
 
data/backpack_tf.gemspec CHANGED
@@ -1,16 +1,19 @@
1
+ require_relative './lib/backpack_tf/version.rb'
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = 'backpack_tf'
3
- s.version = '0.2.1'
4
- s.date = '2015-05-01'
5
+ s.date = '2015-05-07'
5
6
  s.summary = 'a wrapper for the backpack.tf API'
6
7
  s.author = 'Rafael Espinoza'
7
8
  s.email = 'rafael@rafaelespinoza.com'
8
9
  s.homepage = 'https://github.com/NerdDiffer/backpack_tf'
9
10
  s.license = 'MIT'
10
- s.description = s.summary
11
+ s.description = 'API client, accessor methods for backpack.tf'
11
12
 
12
13
  s.require_paths = ['lib']
13
14
  s.files = `git ls-files`.split("\n")
15
+ s.version = BackpackTF::VERSION
16
+ s.required_ruby_version = '>=1.9.3'
14
17
 
15
18
  s.add_runtime_dependency 'httparty', '~>0.13', '>=0.13.3'
16
19
 
@@ -34,21 +34,24 @@ module BackpackTF
34
34
 
35
35
  def self.build_url_via action, query_options = {}
36
36
  case action
37
- when :get_prices
37
+ when :get_prices, :prices
38
38
  version = 4
39
39
  interface_url = "/#{Prices.interface}/v#{version}/?"
40
- when :get_currencies
40
+ when :get_currencies, :currencies
41
41
  version = 1
42
42
  interface_url = "/#{Currencies.interface}/v#{version}/?"
43
- when :get_special_items
44
- version = 1
45
- interface_url = "/IGetSpecialItems/v#{version}/?"
46
- when :get_users
47
- version = 3
48
- interface_url = "/IGetUsers/v#{version}/?"
49
- when :get_user_listings
50
- version = 1
51
- interface_url = "/IGetUserListings/v#{version}/?"
43
+ when :get_special_items, :special_items
44
+ raise RuntimeError, "Unfortunately, this interface is not yet supported."
45
+ #version = 1
46
+ #interface_url = "/IGetSpecialItems/v#{version}/?"
47
+ when :get_users, :users
48
+ raise RuntimeError, "Unfortunately, this interface is not yet supported."
49
+ #version = 3
50
+ #interface_url = "/IGetUsers/v#{version}/?"
51
+ when :get_user_listings, :user_listings
52
+ raise RuntimeError, "Unfortunately, this interface is not yet supported."
53
+ #version = 1
54
+ #interface_url = "/IGetUserListings/v#{version}/?"
52
55
  else
53
56
  raise ArgumentError, 'pass in valid action as a Symbol object'
54
57
  end
@@ -75,15 +78,32 @@ module BackpackTF
75
78
  @db = nil
76
79
  end
77
80
 
81
+ def fetch interface, query_options = {}
82
+ get_data(interface, query_options)['response']
83
+ end
84
+
85
+ def update class_to_update, data_to_update
86
+ send_update_to_master_hash(class_to_update, data_to_update)
87
+ refresh_class_hash(class_to_update)
88
+ end
89
+
90
+ private
91
+
92
+ def send_update_to_master_hash class_to_update, data_to_update
93
+ Response.responses( { class_to_update.to_sym => data_to_update } )
94
+ end
95
+
96
+ def refresh_class_hash class_to_update
97
+ class_to_update.response
98
+ end
99
+
78
100
  def get_data action, query_options = {}
79
101
  handle_timeouts do
80
102
  url = self.class.build_url_via(action, query_options)
81
- self.class.get(url)#['response']
103
+ self.class.get(url)
82
104
  end
83
105
  end
84
-
85
- private
86
-
106
+
87
107
  # HTTParty raises an errors after time limit defined by ::default_timeout
88
108
  # * if it cannot connect to server, then it raises Net::OpenTimeout
89
109
  # * if it cannot read response from server, then it raises Net::ReadTimeout
@@ -95,7 +115,6 @@ module BackpackTF
95
115
  {}
96
116
  end
97
117
  end
98
-
99
118
 
100
119
  end
101
120
 
@@ -2,18 +2,25 @@ module BackpackTF
2
2
 
3
3
  # ruby representations of a JSON response to
4
4
  # `IGetCurrencies`['response']
5
- class Currencies
5
+ class Currencies < Response
6
6
 
7
7
  ###########################
8
8
  # Class Methods
9
9
  ###########################
10
10
 
11
- include BackpackTF::Response
11
+ INTERFACE = :IGetCurrencies
12
+ @interface = INTERFACE
13
+ @response = nil
14
+ @@currencies = nil
12
15
 
13
- @interface = :IGetCurrencies
16
+ def self.response
17
+ @response = superclass.responses[to_sym]
18
+ end
14
19
 
15
20
  def self.currencies
16
- @@currencies = hash_keys_to_sym(@response[:currencies])
21
+ return @response if @response.nil?
22
+ @@currencies = response[:currencies]
23
+ hash_keys_to_sym(@@currencies)
17
24
  end
18
25
 
19
26
  ###########################
@@ -0,0 +1,87 @@
1
+ module BackpackTF
2
+ module Finder
3
+
4
+ def self.included(other)
5
+ other.extend(ClassMethods)
6
+ super
7
+ end
8
+
9
+ module ClassMethods
10
+ # returns JSON data for the item
11
+ # does not return data for items with a special particle effect
12
+ def get_item_price quality, item_name
13
+ item = find_item_by_name(item_name)
14
+ ind = @@qualities.find_index(quality)
15
+
16
+ prefix = item['prices'][ind.to_s]['Tradable']
17
+ if prefix.nil?
18
+ raise(ArgumentError, "The item, #{quality} #{item_name}, is not Tradable")
19
+ end
20
+ prefix = prefix['Craftable']
21
+ if prefix.nil?
22
+ raise(ArgumentError, "The item, #{quality} #{item_name}, is not Craftable")
23
+ end
24
+
25
+ # oddly, there are cases (such as the "Lugermorph"), where the
26
+ # type of the object at this point in the JSON data (saved to the `prefix` variable)
27
+ # is a Hash object rather than an Array object.
28
+ # That makes the PriceIndex key a String, "0", rather than a Fixnum, 0.
29
+ if prefix[0].nil?
30
+ prefix[0.to_s]
31
+ else
32
+ prefix[0]
33
+ end
34
+ end
35
+
36
+ def defindex_to_item_name defindex
37
+ items = get_items_hash
38
+ keys = items.keys#.shuffle
39
+
40
+ i = 0
41
+ while i < keys.length
42
+ current_defindex = items[keys[i]]['defindex']
43
+ if(current_defindex[0] == defindex)
44
+ return keys[i]
45
+ end
46
+ i += 1
47
+ end
48
+ raise KeyError, "item with a defindex of #{defindex} was not found"
49
+ end
50
+
51
+ def get_name_of_random_item
52
+ items = get_items_hash
53
+ items.keys.sample
54
+ end
55
+
56
+ # returns JSON representation of pricing for the item
57
+ def find_item_by_name item_name
58
+ items = get_items_hash
59
+ if items[item_name].nil?
60
+ raise KeyError, "item with the name #{item_name} was not found"
61
+ else
62
+ items[item_name]
63
+ end
64
+ end
65
+
66
+ # @param [String] item_name, the item name (according to item_name of item's schema)
67
+ # @param [Symbol] type, checking to see if item is of this type
68
+ # @return [Boolean] `true` if the item is the type
69
+ def is_item_of_type? item_name, type = :weapon
70
+ item = find_item_by_name(item_name)
71
+ defindex = item['defindex'][0]
72
+ tf2_item = Trade.tf2_item_schema.items[defindex]
73
+
74
+ case type
75
+ when :cosmetic
76
+ tf2_item[:item_class] == 'tf_wearable'
77
+ else
78
+ tf2_item[:item_slot] == 'primary' ||
79
+ tf2_item[:item_slot] == 'secondary' ||
80
+ tf2_item[:item_slot] == 'melee'
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+ end
@@ -2,6 +2,35 @@ module BackpackTF
2
2
 
3
3
  class Item
4
4
 
5
+ include BackpackTF::Finder
6
+
7
+ ###########################
8
+ # Class Methods
9
+ ###########################
10
+
11
+ #def self.generate_price_keys item_hash
12
+ # raise TypeError unless item_hash.class == Hash
13
+ # prices = item_hash['prices']
14
+
15
+ # prices.each_pair.inject([]) do |gen_keys, (key, val)|
16
+ # quality = BackpackTF::ItemPrice.qualities[key.to_i]
17
+ # new_key = [quality.to_s]
18
+
19
+ # tradability = val.keys.first
20
+ # new_key << tradability
21
+
22
+ # craftability = prices[key][tradability].keys.first
23
+ # new_key << craftability
24
+
25
+ # gen_keys << new_key.join('_')
26
+ # end
27
+
28
+ #end
29
+
30
+ ###########################
31
+ # Instance Methods
32
+ ###########################
33
+
5
34
  # @return [String] the name of item
6
35
  attr_reader :item_name
7
36
  # @return [Fixnum] the index on which you can link this item to Team Fortress 2's Item Schema
@@ -10,9 +39,61 @@ module BackpackTF
10
39
  attr_reader :prices
11
40
 
12
41
  def initialize item_name, attr
13
- @item_name = item_name
14
- @defindex = attr['defindex'][0]
15
- @prices = nil
42
+ @item_name = item_name
43
+
44
+ unless attr.class == Hash
45
+ attr = JSON.parse(attr)
46
+ end
47
+
48
+ @defindex = attr['defindex'][0]
49
+ @prices = gen_prices_hash(attr)
50
+ end
51
+
52
+ def gen_prices_hash input_hash
53
+
54
+ raise TypeError, 'expecting a Hash object' unless input_hash.class == Hash
55
+ unless input_hash.has_key? 'prices'
56
+ msg = "input_hash must be at the one level above the point where 'prices' is a key in the JSON hash"
57
+ raise KeyError, msg
58
+ end
59
+
60
+ prices = input_hash['prices']
61
+
62
+ prices.inject({}) do |hash, (key, val)|
63
+ quality = BackpackTF::ItemPrice.qualities[key.to_i]
64
+ new_key = [quality.to_s]
65
+
66
+ tradability = val.keys.first
67
+ new_key << tradability
68
+
69
+ craftability = prices[key][tradability].keys.first
70
+ new_key << craftability
71
+
72
+ new_key = new_key.join('_')
73
+
74
+ prefix = prices[key][tradability][craftability]
75
+
76
+ if prefix.class == Array
77
+ item_prices = prefix.first
78
+ item_price_obj = ItemPrice.new(new_key, item_prices)
79
+ hash[new_key] = item_price_obj
80
+ elsif prefix.class == Hash
81
+ if prefix.keys.length <= 1
82
+ item_prices = prefix.values[0]
83
+ item_price_obj = ItemPrice.new(new_key, item_prices)
84
+ hash[new_key] = item_price_obj
85
+ else
86
+ prefix.keys.each do |prefix_key|
87
+ temp_key = "#{new_key}_Effect ##{prefix_key.to_i}"
88
+ item_prices = prefix[prefix_key]
89
+ item_price_obj = ItemPrice.new(temp_key, item_prices, prefix_key)
90
+ hash[new_key] = item_price_obj
91
+ end
92
+ end
93
+ end
94
+
95
+ hash
96
+ end
16
97
  end
17
98
 
18
99
  end
@@ -2,62 +2,81 @@ module BackpackTF
2
2
 
3
3
  class ItemPrice
4
4
 
5
- attr_reader :quality, :tradability, :craftability, :priceindex,
6
- :currency, :value, :value_high, :value_raw, :value_high_raw,
7
- :last_update, :difference
5
+ include BackpackTF::Finder
8
6
 
9
- def initialize
7
+ # @return [String] the quality of the item being priced, converted to String
8
+ attr_reader :quality
9
+ # @return [Symbol] either :Tradable or :'Non-Tradable'
10
+ attr_reader :tradability
11
+ # @return [Symbol] either :Craftable or :'Non-Craftable'
12
+ attr_reader :craftability
13
+ # @return [NilClass or Fixnum] Primarily used to signify crate series or unusual effect. Otherwise, this is 0
14
+ attr_reader :priceindex
15
+ # @return [Symbol] The currency that the item's price is based on
16
+ attr_reader :currency
17
+ # @return [Float] The value of the item in said currency
18
+ attr_reader :value
19
+ # @return [Float] The item's upper value measured in said currency. only set if the item has a price range
20
+ attr_reader :value_high
21
+ # @return [Float] The item's value in the lowest currency without rounding. If raw is set to 2, this is the lower value if a high value exists. Otherwise, this is the average between the high and low value. Requires raw to be enabled.
22
+ attr_reader :value_raw
23
+ # @return [Float] The item's value in the lowest currency without rounding. Reques raw to be enabled and set to 2
24
+ attr_reader :value_high_raw
25
+ # @return [Fixnum] A timestamp of when the price was last updated
26
+ attr_reader :last_update
27
+ # @return [Fixnum] A relative difference between the former price and the current price. If 0, assume new price.
28
+ attr_reader :difference
29
+
30
+ def initialize key, attr, priceindex = nil
31
+ attr = JSON.parse(attr) unless attr.class == Hash
32
+ unless self.class.required_keys.all? {|k| attr.keys.member? k }
33
+ raise KeyError, "The passed-in hash is required to have at least these 4 keys: #{self.class.required_keys.join(', ')}"
34
+ end
35
+
36
+ key_split = key.split('_')
37
+
38
+ @priceindex = priceindex
39
+
40
+ @quality = key_split[0].to_sym
41
+ @tradability = key_split[1].to_sym
42
+ @craftability = key_split[2].to_sym
43
+ @currency = attr['currency'].to_sym
44
+ @value = attr['value']
45
+ @value_high = attr['value_high']
46
+ @value_raw = attr['value_raw']
47
+ @value_high_raw = attr['value_high_raw']
48
+ @last_update = attr['last_update']
49
+ @difference = attr['difference']
10
50
  end
11
51
 
52
+ @@required_keys = %w(currency value last_update difference)
53
+ def self.required_keys; @@required_keys; end
54
+
12
55
  # mapping official API quality integers to quality names
13
56
  # https://wiki.teamfortress.com/wiki/WebAPI/GetSchema#Result_Data
14
57
  @@qualities = [
15
- 'Normal',
16
- 'Genuine',
58
+ :Normal,
59
+ :Genuine,
17
60
  nil,
18
- 'Vintage',
61
+ :Vintage,
19
62
  nil,
20
- 'Unusual',
21
- 'Unique',
22
- 'Community',
23
- 'Valve',
24
- 'Self-Made',
63
+ :Unusual,
64
+ :Unique,
65
+ :Community,
66
+ :Valve,
67
+ :"Self-Made",
25
68
  nil,
26
- 'Strange',
69
+ :Strange,
27
70
  nil,
28
- 'Haunted',
29
- "Collector's"
71
+ :Haunted,
72
+ :"Collector's"
30
73
  ]
31
74
 
32
- @@tradabilities = [:Tradable, :Untradable]
33
- @@craftabilities = [:Craftable, :Uncraftable]
34
-
35
- # returns JSON data for the item
36
- # does not return data for items with a special particle effect
37
- def self.get_item_price quality, item_name
38
- item = find_item_by_name(item_name)
39
- ind = @@qualities.find_index(quality)
40
-
41
- prefix = item['prices'][ind.to_s]['Tradable']
42
- if prefix.nil?
43
- raise(ArgumentError, "The item, #{quality} #{item_name}, is not Tradable")
44
- end
45
- prefix = prefix['Craftable']
46
- if prefix.nil?
47
- raise(ArgumentError, "The item, #{quality} #{item_name}, is not Craftable")
48
- end
49
-
50
- # oddly, there are cases (such as the "Lugermorph"), where the
51
- # type of the object at this point in the JSON data (saved to the `prefix` variable)
52
- # is a Hash object rather than an Array object.
53
- # That makes the PriceIndex key a String, "0", rather than a Fixnum, 0.
54
- if prefix[0].nil?
55
- prefix[0.to_s]
56
- else
57
- prefix[0]
58
- end
59
- end
75
+ def self.qualities; @@qualities; end
60
76
 
77
+ @@tradabilities = [:Tradable, :'Non-Tradable']
78
+ @@craftabilities = [:Craftable, :'Non-Craftable']
79
+
61
80
  end
62
81
 
63
82
  end
@@ -2,66 +2,45 @@ module BackpackTF
2
2
 
3
3
  # ruby representations of a JSON response to
4
4
  # `IGetPrices`['response']
5
- class Prices
5
+ class Prices < Response
6
6
 
7
- include BackpackTF::Response
7
+ include BackpackTF::Finder
8
8
 
9
- @interface = :IGetPrices
9
+ INTERFACE = :IGetPrices
10
+ @interface = INTERFACE
11
+ @response = nil
12
+ @@items = nil
10
13
 
11
- def self.items
12
- @@items = @response[:items]
13
- end
14
-
15
- def self.defindex_to_item_name defindex
16
- items = get_items_hash
17
- keys = items.keys#.shuffle
18
-
19
- i = 0
20
- while i < keys.length
21
- current_defindex = items[keys[i]]['defindex']
22
- if(current_defindex[0] == defindex)
23
- return keys[i]
24
- end
25
- i += 1
26
- end
27
- raise KeyError, "item with a defindex of #{defindex} was not found"
14
+ def self.response
15
+ @response = superclass.responses[to_sym]
28
16
  end
29
17
 
30
- def self.get_name_of_random_item
31
- items = get_items_hash
32
- items.keys.sample
33
- end
34
-
35
- # returns JSON representation of pricing for the item
36
- def self.find_item_by_name item_name
37
- items = get_items_hash
38
- if items[item_name].nil?
39
- raise KeyError, "item with the name #{item_name} was not found"
18
+ def self.items
19
+ if @@items.nil?
20
+ gen_items
40
21
  else
41
- items[item_name]
22
+ @@items
42
23
  end
43
24
  end
44
25
 
45
- # @param [String] item_name, the item name (according to item_name of item's schema)
46
- # @param [Symbol] type, checking to see if item is of this type
47
- # @return [Boolean] `true` if the item is the type
48
- def self.is_item_of_type? item_name, type = :weapon
49
- item = find_item_by_name(item_name)
50
- defindex = item['defindex'][0]
51
- tf2_item = Trade.tf2_item_schema.items[defindex]
26
+ def self.gen_items
27
+ @@items = @response[:items].inject({}) do |items, (name)|
28
+ defindex = @response[:items][name]['defindex'][0]
52
29
 
53
- case type
54
- when :cosmetic
55
- tf2_item[:item_class] == 'tf_wearable'
56
- else
57
- tf2_item[:item_slot] == 'primary' ||
58
- tf2_item[:item_slot] == 'secondary' ||
59
- tf2_item[:item_slot] == 'melee'
30
+ if defindex.nil? || defindex < 0
31
+ items
32
+ else
33
+ items[name] = Item.new(name, @response[:items][name])
34
+ items
35
+ end
60
36
  end
61
37
  end
62
38
 
63
39
  def initialize
64
- msg = "This class is meant to receive the JSON response from the #{self.class.interface} interface. It holds a Hash array of prices of items, but not is meant to be instantiated. See the Item class if you are interested in an item. However, information on items should be stored in the @items property of #{self.class}"
40
+ msg = "This class is meant to receive the JSON response from the #{self.class.interface} interface."
41
+ msg << "It holds a Hash array of prices of items, but not is meant to be instantiated."
42
+ msg << "See the Item class if you are interested in an item."
43
+ msg << "However, information on items should be stored in the @items property of #{self.class}."
65
44
  raise RuntimeError, msg
66
45
  end
67
46
 
@@ -1,43 +1,48 @@
1
1
  module BackpackTF
2
- module Response
2
+ class Response
3
3
 
4
- def self.included(other)
5
- puts "#{self} included in (#{other})"
6
- other.extend(ClassMethods)
7
- super
4
+ ############################
5
+ # CLASS METHODS
6
+ ############################
7
+
8
+ def self.interface; @interface; end
9
+
10
+ def self.to_sym
11
+ self.name.to_sym
8
12
  end
9
13
 
10
- module ClassMethods
14
+ @responses = {}
11
15
 
12
- @response = nil
13
- def interface; @interface; end
16
+ def self.responses key_val = nil
17
+ unless key_val.nil?
18
+ key_val = { key_val => nil } unless key_val.class == Hash
19
+ key = key_val.keys.first
20
+ val = key_val.values.first
14
21
 
15
- def response force_update = false
16
- # if force is true, set value of @response to results of ::fetch
17
- # otherwise, use a `nil guard` to return @response
18
- # if the value is already set, then it returns value of @response
19
- # if the value is not set, then it runs ::fetch
20
- force_update ?
21
- @response = fetch :
22
- @response ||= fetch
23
- end
22
+ if val.nil?
23
+ @responses[key]
24
+ elsif key == :reset && val == :confirm
25
+ @responses = {}
26
+ else
27
+ @responses[key] = hash_keys_to_sym(val)
28
+ end
24
29
 
25
- def fetch client_stuff
26
- @response = hash_keys_to_sym(client_stuff)
27
30
  end
28
31
 
29
- # checks the data type of the keys of a Hash object
30
- # if the key is a String, then changes it to a Symbol
31
- # otherwise, leaves it as is
32
- def hash_keys_to_sym hash
33
- hash.each_pair.inject({}) do |new_hash, (key, val)|
34
- unless key.class == String
35
- new_hash[key] = val
36
- else
37
- new_hash[key.to_sym] = val
38
- end
39
- new_hash
32
+ @responses
33
+ end
34
+
35
+ # checks the data type of the keys of a Hash object
36
+ # if the key is a String, then changes it to a Symbol
37
+ # otherwise, leaves it as is
38
+ def self.hash_keys_to_sym hash
39
+ hash.each_pair.inject({}) do |new_hash, (key, val)|
40
+ unless key.class == String
41
+ new_hash[key] = val
42
+ else
43
+ new_hash[key.to_sym] = val
40
44
  end
45
+ new_hash
41
46
  end
42
47
  end
43
48
 
@@ -0,0 +1,3 @@
1
+ module BackpackTF
2
+ VERSION = "0.5.0"
3
+ end
data/lib/backpack_tf.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'httparty'
2
- require 'byebug'
3
2
 
4
3
  # namespace for classes & modules inside of the wrapper for the BackpackTF API
5
4
  module BackpackTF
@@ -7,7 +6,9 @@ module BackpackTF
7
6
  end
8
7
 
9
8
  # IMPORTANT! require the Response module before any other class or module
9
+ require 'backpack_tf/version'
10
10
  require 'backpack_tf/response'
11
+ require 'backpack_tf/finder'
11
12
  require 'backpack_tf/client'
12
13
  require 'backpack_tf/currencies'
13
14
  require 'backpack_tf/item'