gun_broker 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5f1909c07880bf70fd3f4c385c456168ae2409e5
4
+ data.tar.gz: c11c711ae5950ba9d3c7a3cb18618d3dde0977ea
5
+ SHA512:
6
+ metadata.gz: 49b71a28c539403d802d1be79ae5960bb41cfec1a6e8c8e980e75785686221b3722a4bca874d90fea7fdb74ba7e9657b4504bfd938ccfadf21cb5604d579f9b2
7
+ data.tar.gz: 4cc1b3c0eedf8b3cc18d0e00aa7951a5e6401f1d0b176d80f54174b575d69b57efcbd5060c2f20be6e0018e35de9649b4de6dd97604e1316fbf61d68afab3106
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ gun_broker
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p481
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gun_broker.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Dale Campbell
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # GunBroker
2
+
3
+ GunBroker.com API Ruby library.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'gun_broker'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install gun_broker
20
+
21
+ ## Usage
22
+
23
+ ### Developer Token
24
+
25
+ You **must** set a developer key obtained from GunBroker.com in order to use this library.
26
+
27
+ ```ruby
28
+ GunBroker.dev_key = 'your-sekret-dev-key'
29
+ ```
30
+
31
+ ### GunBroker::User
32
+
33
+ Authentication requires a `username` and an 'auth options' hash that requires **at least** a `password`
34
+ *or* `token`. If a password is given, you must call `User#authenticate!` to obtain an access token.
35
+
36
+ ```ruby
37
+ # By username/password:
38
+ user = GunBroker::User.new('username', password: 'sekret-password')
39
+ user.authenticate!
40
+ user.token # => 'user-access-token'
41
+
42
+ # Or with an existing Access Token:
43
+ user = GunBroker::User.new('username', token: 'user-access-token')
44
+ # No need to call #authenticate! since we already have an access token.
45
+ user.token # => 'user-access-token'
46
+ ```
47
+
48
+ Once the User has an access token, you can then grab all of their items (listings). All items methods
49
+ return an array of `GunBroker::Item` instances.
50
+
51
+ ```ruby
52
+ user.items # => [GunBroker::Item, ...]
53
+ user.unsold_items # => [GunBroker::Item, ...]
54
+ user.sold_items # => [GunBroker::Item, ...]
55
+ ```
56
+
57
+ ### GunBroker::Item
58
+
59
+ Represents an item (listing) on GunBroker. The `Item#id` method returns the value of the `itemID` attribute
60
+ from the response. All other attributes can be accessed through the `Item#[]` method.
61
+
62
+ ```ruby
63
+ item.id # => '1234567'
64
+ item['title'] # => 'Super Awesome Scope'
65
+ ```
66
+
67
+ ### GunBroker::Category
68
+
69
+ Returns GunBroker category responses. To get an array of all categories, call `Category#all()`.
70
+
71
+ ```ruby
72
+ GunBroker::Category.all
73
+ # => [GunBroker::Category, ...]
74
+ ```
75
+
76
+ You can also pass an optional parent category ID, to only return subcategories of the given parent.
77
+ For example, if the 'Firearms' category has an ID of '123', get all Firearm subcategories like this:
78
+
79
+ ```ruby
80
+ firearms = '123' # ID of the Firearms Category
81
+ GunBroker::Category.all(firearms)
82
+ # => [GunBroker::Category, ...]
83
+ ```
84
+
85
+ Much like GunBroker::Item, the `Category#id` method returns the `categoryID` attribute from the response.
86
+ All other attributes can be accessed with `Category#[]`.
87
+
88
+ ```ruby
89
+ category.id # => '123'
90
+ category['categoryName'] # => 'Firearms'
91
+ ```
92
+
93
+ ### GunBroker::API
94
+
95
+ If you need to access an API endpoint not yet supported, you can use `GunBroker::API` directly. Currently
96
+ supported HTTP methods are `GET`, `DELETE`, and `POST`, with each having a corresponding method on the
97
+ `GunBroker::API` class.
98
+
99
+ Each method requires a `path` and accepts optional `params` and `headers` hashes. If making a `GET` request,
100
+ the `params` will be URL params; if making a `POST` request, the `params` will be turned into JSON and set
101
+ as the request body.
102
+
103
+ You can also set HTTP headers by passing a hash as the third argument. Headers will **always** contain:
104
+
105
+ * `Content-Type: application/json`
106
+ * `X-DevKey: your-sekret-dev-key`
107
+
108
+ The response will be parsed JSON (hash).
109
+
110
+ ```ruby
111
+ GunBroker::API.get('/some/resource')
112
+ # => { 'name' => 'resource', 'foo' => 'bar' }
113
+
114
+ GunBroker::API.post('/some/resource', { name: 'some data' })
115
+
116
+ # No params, but some headers:
117
+ GunBroker::API.delete('/some/resource', {}, { 'X-TestHeader' => 'FooBar' })
118
+ ```
119
+
120
+ ### Error Handling
121
+
122
+ Methods that require authorization (with an access token) will raise a `GunBroker::Error::NotAuthorized`
123
+ exception if the token isn't valid. Otherwise, if there is some other issue with the request (namely,
124
+ the response status code is not in the `2xx` range), a `GunBroker::Error::RequestError` will be raised.
125
+
126
+ ## Contributing
127
+
128
+ 1. Fork it ( https://github.com/ammoready/gun_broker/fork )
129
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
130
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
131
+ 4. Push to the branch (`git push origin my-new-feature`)
132
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => :spec
5
+
6
+ desc 'Run the specs'
7
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gun_broker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gun_broker"
8
+ spec.version = GunBroker::VERSION
9
+ spec.authors = ["Dale Campbell"]
10
+ spec.email = ["oshuma@gmail.com"]
11
+ spec.summary = %q{GunBroker.com API Ruby library.}
12
+ spec.description = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.1"
24
+ spec.add_development_dependency "webmock", "~> 1.20"
25
+ end
data/lib/gun_broker.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'gun_broker/version'
2
+
3
+ require 'gun_broker/api'
4
+ require 'gun_broker/category'
5
+ require 'gun_broker/error'
6
+ require 'gun_broker/item'
7
+ require 'gun_broker/user'
8
+
9
+ module GunBroker
10
+
11
+ def self.dev_key=(dev_key)
12
+ @@dev_key = dev_key
13
+ end
14
+
15
+ def self.dev_key
16
+ raise 'GunBroker developer key not set.' unless dev_key_present?
17
+ @@dev_key
18
+ end
19
+
20
+ private
21
+
22
+ def self.dev_key_present?
23
+ defined?(@@dev_key) && !@@dev_key.nil? && !@@dev_key.empty?
24
+ end
25
+
26
+ end
@@ -0,0 +1,82 @@
1
+ require 'json'
2
+ require 'net/https'
3
+
4
+ module GunBroker
5
+ class API
6
+
7
+ GUNBROKER_API = 'https://api.gunbroker.com/v1'
8
+
9
+ def initialize(path, params = {}, headers = {})
10
+ raise "Path must start with '/': #{path}" unless path.start_with?('/')
11
+
12
+ @path = path
13
+ @params = params
14
+ @headers = headers
15
+ end
16
+
17
+ def self.delete(*args)
18
+ new(*args).delete!
19
+ end
20
+
21
+ def self.get(*args)
22
+ new(*args).get!
23
+ end
24
+
25
+ def self.post(*args)
26
+ new(*args).post!
27
+ end
28
+
29
+ def delete!
30
+ request = Net::HTTP::Delete.new(uri)
31
+ response = get_response(request)
32
+ handle_response(response)
33
+ end
34
+
35
+ def get!
36
+ uri.query = URI.encode_www_form(@params)
37
+
38
+ request = Net::HTTP::Get.new(uri)
39
+ response = get_response(request)
40
+ handle_response(response)
41
+ end
42
+
43
+ def post!
44
+ request = Net::HTTP::Post.new(uri)
45
+ request.body = @params.to_json
46
+
47
+ response = get_response(request)
48
+ handle_response(response)
49
+ end
50
+
51
+ private
52
+
53
+ def get_response(request)
54
+ request['Content-Type'] = 'application/json'
55
+ request['X-DevKey'] = GunBroker.dev_key
56
+
57
+ @headers.each { |header, value| request[header] = value }
58
+
59
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
60
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
61
+ http.ssl_version = :SSLv3
62
+ http.request(request)
63
+ end
64
+ end
65
+
66
+ def handle_response(response)
67
+ case response
68
+ when Net::HTTPOK, Net::HTTPSuccess
69
+ JSON.parse(response.body)
70
+ when Net::HTTPUnauthorized
71
+ raise GunBroker::Error::NotAuthorized.new(response)
72
+ else
73
+ raise GunBroker::Error::RequestError.new(response)
74
+ end
75
+ end
76
+
77
+ def uri
78
+ @uri ||= URI([GUNBROKER_API, @path].join)
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,25 @@
1
+ module GunBroker
2
+ class Category
3
+
4
+ # The top-level category ID.
5
+ ROOT_CATEGORY_ID = 0
6
+
7
+ def self.all(parent = ROOT_CATEGORY_ID)
8
+ response = GunBroker::API.get('/Categories', { 'ParentCategoryID' => parent })
9
+ response['results'].map { |attrs| new(attrs) }
10
+ end
11
+
12
+ def self.find(category_id)
13
+ new(GunBroker::API.get("/Categories/#{category_id}"))
14
+ end
15
+
16
+ def initialize(attrs = {})
17
+ @attrs = attrs
18
+ end
19
+
20
+ def id
21
+ @attrs['categoryID']
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,8 @@
1
+ module GunBroker
2
+ class Error < StandardError
3
+
4
+ class NotAuthorized < GunBroker::Error; end
5
+ class RequestError < GunBroker::Error; end
6
+
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ module GunBroker
2
+ class Item
3
+
4
+ def initialize(attrs = {})
5
+ @attrs = attrs
6
+ end
7
+
8
+ def id
9
+ @attrs['itemID']
10
+ end
11
+
12
+ def [](key)
13
+ @attrs[key]
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ module GunBroker
2
+ class User
3
+
4
+ attr_reader :username
5
+ attr_reader :token
6
+
7
+ def initialize(username, auth_options = {})
8
+ @username = username
9
+ @password = auth_options[:password] || auth_options['password']
10
+ @token = auth_options[:token] || auth_options['token']
11
+ end
12
+
13
+ def authenticate!
14
+ response = GunBroker::API.post('/Users/AccessToken', { username: @username, password: @password })
15
+ @token = response['accessToken']
16
+ end
17
+
18
+ # Sends a DELETE request to deactivate the current access token.
19
+ def deauthenticate!
20
+ GunBroker::API.delete('/Users/AccessToken', {}, { 'X-AccessToken' => @token })
21
+ @token = nil
22
+ true # Explicit `true` so this method won't return the `nil` set above.
23
+ end
24
+
25
+ def items
26
+ response = GunBroker::API.get('/Items', { 'SellerName' => @username }, { 'X-AccessToken' => @token })
27
+ response['results'].map { |result| GunBroker::Item.new(result) }
28
+ end
29
+
30
+ def unsold_items
31
+ response = GunBroker::API.get('/ItemsUnsold', {}, { 'X-AccessToken' => @token })
32
+ response['results'].map { |result| GunBroker::Item.new(result) }
33
+ end
34
+
35
+ def sold_items
36
+ response = GunBroker::API.get('/ItemsSold', {}, { 'X-AccessToken' => @token })
37
+ response['results'].map { |result| GunBroker::Item.new(result) }
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module GunBroker
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1 @@
1
+ {"accessToken":"test-user-access-token"}
@@ -0,0 +1 @@
1
+ {"count":29,"pageIndex":1,"pageSize":25,"results":[{"categoryID":851,"categoryName":"Firearms","canContainItems":false,"description":"Modern Firearms are defined by the ATF as firearms built after 1898. All items listed in this category must be modern firearms. Firearm parts, ammunition, and accessories have their own categories and must be listed there. Items which meet the Collectible firearms, including antiques, commemoratives, and firearms which meet the ATF definition of a 'Curio and Relic' may be listed in the Collectible Firearms category.","categoryPath":{"id":0,"name":"All","child":{"id":851,"name":"Firearms","child":null}},"subCategories":[{"categoryId":978,"categoryName":"Pistols","hasSubCategories":true},{"categoryId":979,"categoryName":"Rifles","hasSubCategories":true},{"categoryId":980,"categoryName":"Shotguns","hasSubCategories":true},{"categoryId":2330,"categoryName":"Cowboy Action Shooting","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=851","verb":"GET","title":"Search for items in Firearms"}]},{"categoryID":982,"categoryName":"Gun Parts","canContainItems":false,"description":"Any type of firearm parts or accessories should be listed here.","categoryPath":{"id":0,"name":"All","child":{"id":982,"name":"Gun Parts","child":null}},"subCategories":[{"categoryId":983,"categoryName":"Other Gun Accessories & Parts","hasSubCategories":false},{"categoryId":1017,"categoryName":"Scopes & Gun Optics","hasSubCategories":true},{"categoryId":3013,"categoryName":"Gun Holsters & Gun Leather","hasSubCategories":false},{"categoryId":3014,"categoryName":"Gun Cases & Gun Storage","hasSubCategories":false},{"categoryId":3031,"categoryName":"Gun Cleaning Kits & Gun Cleaning Supplies","hasSubCategories":false},{"categoryId":3035,"categoryName":"Gun Parts Kits","hasSubCategories":false},{"categoryId":3036,"categoryName":"Gun Sights","hasSubCategories":false},{"categoryId":3037,"categoryName":"Shotgun Parts","hasSubCategories":true},{"categoryId":3038,"categoryName":"Pistol Parts","hasSubCategories":true},{"categoryId":3039,"categoryName":"Rifle Parts","hasSubCategories":true},{"categoryId":3040,"categoryName":"1911 Parts","hasSubCategories":false},{"categoryId":3041,"categoryName":"TC Contender Barrels & Parts","hasSubCategories":false},{"categoryId":3042,"categoryName":"SKS Parts","hasSubCategories":false},{"categoryId":3043,"categoryName":"AK47 Parts","hasSubCategories":false},{"categoryId":3044,"categoryName":"AR15 Parts","hasSubCategories":false},{"categoryId":3045,"categoryName":"Glock Parts","hasSubCategories":false},{"categoryId":3046,"categoryName":"HK Parts","hasSubCategories":false},{"categoryId":3074,"categoryName":"Gun Safes & Trigger Locks","hasSubCategories":false},{"categoryId":3097,"categoryName":"Gunsmithing Tools & Gunsmith Supplies","hasSubCategories":false},{"categoryId":4011,"categoryName":"Shooting Glasses & Hearing Protection","hasSubCategories":false},{"categoryId":4013,"categoryName":"Shooting Targets","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=982","verb":"GET","title":"Search for items in Gun Parts"}]},{"categoryID":1012,"categoryName":"Ammunition","canContainItems":false,"description":"This category is for ready-to-shoot ammunition for firearms. Reloading supplies such as bullets, brass, primers, etc belong in the Reloading : Supplies category, not here. Clips, magazines, ammo belts, and equipment to carry or load ammunition have their own categories and should not be listed here.","categoryPath":{"id":0,"name":"All","child":{"id":1012,"name":"Ammunition","child":null}},"subCategories":[{"categoryId":3017,"categoryName":"Rifle Ammunition","hasSubCategories":false},{"categoryId":3018,"categoryName":"Pistol Ammunition","hasSubCategories":false},{"categoryId":3019,"categoryName":"Shotgun Shells","hasSubCategories":false},{"categoryId":3020,"categoryName":"Other Ammunition","hasSubCategories":false},{"categoryId":3030,"categoryName":"Vintage Ammo","hasSubCategories":false},{"categoryId":3053,"categoryName":"Ammo Storage","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=1012","verb":"GET","title":"Search for items in Ammunition"}]},{"categoryID":3094,"categoryName":"Black Powder & Muzzleloaders","canContainItems":false,"description":"","categoryPath":{"id":0,"name":"All","child":{"id":3094,"name":"Black Powder & Muzzleloaders","child":null}},"subCategories":[{"categoryId":3095,"categoryName":"Black Powder Pistols & Muzzleloader Pistols","hasSubCategories":false},{"categoryId":3096,"categoryName":"Black Powder Rifles & Muzzleloader Rifles","hasSubCategories":false},{"categoryId":4030,"categoryName":"Muzzleloader Supplies & Black Powder Parts","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=3094","verb":"GET","title":"Search for items in Black Powder & Muzzleloaders"}]},{"categoryID":2338,"categoryName":"Class 3 Firearms, NFA & Destructive Devices","canContainItems":false,"description":"All types of federally restricted firearms, including machine guns, destructive devices, and silencers","categoryPath":{"id":0,"name":"All","child":{"id":2338,"name":"Class 3 Firearms, NFA & Destructive Devices","child":null}},"subCategories":[{"categoryId":2326,"categoryName":"Machine Guns","hasSubCategories":false},{"categoryId":3098,"categoryName":"Class 3 Parts & Accessories","hasSubCategories":false},{"categoryId":3099,"categoryName":"Silencers & Suppressed Firearms","hasSubCategories":false},{"categoryId":3100,"categoryName":"Destructive Devices","hasSubCategories":false},{"categoryId":4031,"categoryName":"Short Barrel Rifles (SBR)","hasSubCategories":false},{"categoryId":4032,"categoryName":"Any Other Weapon (AOW)","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=2338","verb":"GET","title":"Search for items in Class 3 Firearms, NFA & Destructive Devices"}]},{"categoryID":1014,"categoryName":"Collectible Firearms","canContainItems":false,"description":"Items listed in the Collectible Firearms category must be a firearm. Parts and accessories for Collectible Firearms may be listed in Collectible Firearms : Collectible Parts / Accessories provided the item being listed is itself a collectible piece. Non-collectible parts and accessories should be listed in the most appropriate Firearm Parts or Firearm Accessories category.","categoryPath":{"id":0,"name":"All","child":{"id":1014,"name":"Collectible Firearms","child":null}},"subCategories":[{"categoryId":2322,"categoryName":"Antique Guns","hasSubCategories":false},{"categoryId":2323,"categoryName":"Curios & Relics","hasSubCategories":false},{"categoryId":2324,"categoryName":"Muzzleloading Collectibles","hasSubCategories":false},{"categoryId":3012,"categoryName":"Other Collectible Guns","hasSubCategories":false},{"categoryId":3047,"categoryName":"Commemorative Guns","hasSubCategories":false},{"categoryId":3061,"categoryName":"Collectible Gun Parts & Accessories","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=1014","verb":"GET","title":"Search for items in Collectible Firearms"}]},{"categoryID":1013,"categoryName":"Air Guns","canContainItems":false,"description":"Only air guns should be listed in this category. Air guns include AirSoft, paintball, BB guns, pellet guns, adult air rifles and pistols, CO2-powered rifles and pistols, and any other type of air or compressed gas powered gun. Air gun parts, supplies, and accessories should be listed in the Air Guns : Supplies / Accessories / Other category.","categoryPath":{"id":0,"name":"All","child":{"id":1013,"name":"Air Guns","child":null}},"subCategories":[{"categoryId":3048,"categoryName":"Airsoft","hasSubCategories":false},{"categoryId":3049,"categoryName":"Air Pistols","hasSubCategories":false},{"categoryId":3050,"categoryName":"Air Rifles","hasSubCategories":false},{"categoryId":3051,"categoryName":"Paintball Guns","hasSubCategories":false},{"categoryId":3052,"categoryName":"Air Gun Accessories","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=1013","verb":"GET","title":"Search for items in Air Guns"}]},{"categoryID":1016,"categoryName":"Ammunition Reloading","canContainItems":false,"description":"Equipment and supplies for reloading ammunition should be listed here. ","categoryPath":{"id":0,"name":"All","child":{"id":1016,"name":"Ammunition Reloading","child":null}},"subCategories":[{"categoryId":3015,"categoryName":"Reloading Equipment","hasSubCategories":false},{"categoryId":3016,"categoryName":"Reloading Supplies","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=1016","verb":"GET","title":"Search for items in Ammunition Reloading"}]},{"categoryID":984,"categoryName":"Archery & Bow Hunting","canContainItems":false,"description":"This category is for bows, crossbows, and bow hunting supplies and accessories.","categoryPath":{"id":0,"name":"All","child":{"id":984,"name":"Archery & Bow Hunting","child":null}},"subCategories":[{"categoryId":3054,"categoryName":"Bows","hasSubCategories":false},{"categoryId":3055,"categoryName":"Crossbows","hasSubCategories":false},{"categoryId":3056,"categoryName":"Archery Supplies","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=984","verb":"GET","title":"Search for items in Archery & Bow Hunting"}]},{"categoryID":2329,"categoryName":"Books, Videos & Literature","canContainItems":false,"description":"This category is for books, magazines (the kind you read, not the kind you load!), CD-ROM based books or information, videos or DVDs, and any other kind of gun-related reading or viewing materials.","categoryPath":{"id":0,"name":"All","child":{"id":2329,"name":"Books, Videos & Literature","child":null}},"subCategories":[{"categoryId":3057,"categoryName":"Books","hasSubCategories":false},{"categoryId":3058,"categoryName":"Videos & DVDs","hasSubCategories":false},{"categoryId":3059,"categoryName":"Magazines","hasSubCategories":false},{"categoryId":3060,"categoryName":"CD-ROMS","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=2329","verb":"GET","title":"Search for items in Books, Videos & Literature"}]},{"categoryID":2332,"categoryName":"Charity Gun Auctions","canContainItems":false,"description":"Charity auctions are reserved for charitable organizations or for auctioning off items in which the proceeds will be donated to a charitable cause. Items cannot be listed in this category without the assistance of the auction site. To list an item here please contact auction site tech support by clicking <a href=\"/Support/\">Contact Us</a> from the bottom of any auction site page.","categoryPath":{"id":0,"name":"All","child":{"id":2332,"name":"Charity Gun Auctions","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=2332","verb":"GET","title":"Search for items in Charity Gun Auctions"}]},{"categoryID":3000,"categoryName":"Clothing, Bags & Wearables","canContainItems":false,"description":"Any type of clothing, jewelry, hats, bags, backpacks, and other wearable items must be listed here. The only exceptions are items that would be better listed in Collectibles, like collectible pins, badges, etc.","categoryPath":{"id":0,"name":"All","child":{"id":3000,"name":"Clothing, Bags & Wearables","child":null}},"subCategories":[{"categoryId":3062,"categoryName":"Coats & Jackets","hasSubCategories":false},{"categoryId":3064,"categoryName":"Pants & Coveralls","hasSubCategories":false},{"categoryId":3065,"categoryName":"Gloves","hasSubCategories":false},{"categoryId":3066,"categoryName":"Watches & Jewelry","hasSubCategories":false},{"categoryId":3069,"categoryName":"Eyewear","hasSubCategories":false},{"categoryId":3070,"categoryName":"Hats & Headwear","hasSubCategories":false},{"categoryId":3071,"categoryName":"Belts & Belt Buckles","hasSubCategories":false},{"categoryId":3072,"categoryName":"Other Clothing","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=3000","verb":"GET","title":"Search for items in Clothing, Bags & Wearables"}]},{"categoryID":3001,"categoryName":"Collectibles & Militaria","canContainItems":false,"description":"Any type of non-firearm collectible items related to firearms or hunting may be listed here. This includes war collectibles, souvenirs, logo merchandise, and catalogs. If the item is a firearm, either modern or antique, it must be placed in either the Collectible Firearms or Modern Firearms categories.","categoryPath":{"id":0,"name":"All","child":{"id":3001,"name":"Collectibles & Militaria","child":null}},"subCategories":[{"categoryId":1015,"categoryName":"Other Military Collectibles","hasSubCategories":false},{"categoryId":3005,"categoryName":"Old West Collectibles","hasSubCategories":false},{"categoryId":3006,"categoryName":"Civil War Collectibles","hasSubCategories":false},{"categoryId":3007,"categoryName":"WW1 & WW2 Collectibles","hasSubCategories":false},{"categoryId":3009,"categoryName":"Souvenirs","hasSubCategories":false},{"categoryId":3010,"categoryName":"Other Collectibles","hasSubCategories":false},{"categoryId":3021,"categoryName":"Badges & Insignias","hasSubCategories":false},{"categoryId":3028,"categoryName":"Logo Merchandise","hasSubCategories":false},{"categoryId":3073,"categoryName":"Flags","hasSubCategories":false},{"categoryId":3109,"categoryName":"Collectible Coins","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=3001","verb":"GET","title":"Search for items in Collectibles & Militaria"}]},{"categoryID":2334,"categoryName":"Domain Names","canContainItems":true,"description":"Internet domain names","categoryPath":{"id":0,"name":"All","child":{"id":2334,"name":"Domain Names","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=2334","verb":"GET","title":"Search for items in Domain Names"}]},{"categoryID":3004,"categoryName":"Everything Else","canContainItems":true,"description":"Anything that does not fit cleanly into any other category should be listed here.","categoryPath":{"id":0,"name":"All","child":{"id":3004,"name":"Everything Else","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=3004","verb":"GET","title":"Search for items in Everything Else"}]},{"categoryID":4040,"categoryName":"Fishing Tackle","canContainItems":false,"description":"This is the general area for everything related to fishing. GunBroker.com has places for freshwater, saltwater and fly fishing equipment and tackle of all kinds. You can even buy and sell collectible and vintage fishing tackle, rods and reels.","categoryPath":{"id":0,"name":"All","child":{"id":4040,"name":"Fishing Tackle","child":null}},"subCategories":[{"categoryId":4041,"categoryName":"Fishing Collectibles","hasSubCategories":false},{"categoryId":4042,"categoryName":"Fish Finders","hasSubCategories":false},{"categoryId":4043,"categoryName":"Fly Fishing Tackle","hasSubCategories":true},{"categoryId":4044,"categoryName":"Freshwater Fishing Tackle","hasSubCategories":true},{"categoryId":4045,"categoryName":"Saltwater Fishing","hasSubCategories":true},{"categoryId":4046,"categoryName":"Terminal Tackle","hasSubCategories":false},{"categoryId":4047,"categoryName":"Tackle Storage","hasSubCategories":false},{"categoryId":4048,"categoryName":"Other General Fishing","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=4040","verb":"GET","title":"Search for items in Fishing Tackle"}]},{"categoryID":901,"categoryName":"Furniture & Cabinets","canContainItems":true,"description":"Furniture, including gun storage cabinets, display cases, and stand-up safes should be listed here.","categoryPath":{"id":0,"name":"All","child":{"id":901,"name":"Furniture & Cabinets","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=901","verb":"GET","title":"Search for items in Furniture & Cabinets"}]},{"categoryID":3002,"categoryName":"Hunting Gear","canContainItems":false,"description":"This category is for all hunting gear that is not better suited for another category, such as tree stands, scents, traps, and other hunting equipment. Firearms may not be listed here; firearms must be listed in the Modern Firearms category. ","categoryPath":{"id":0,"name":"All","child":{"id":3002,"name":"Hunting Gear","child":null}},"subCategories":[{"categoryId":4000,"categoryName":"Animal Traps","hasSubCategories":false},{"categoryId":4001,"categoryName":"Bags & Packs","hasSubCategories":false},{"categoryId":4002,"categoryName":"Camo Clothing & Accessories","hasSubCategories":false},{"categoryId":4003,"categoryName":"Game Feed & Feeders","hasSubCategories":false},{"categoryId":4004,"categoryName":"Game Cameras","hasSubCategories":false},{"categoryId":4005,"categoryName":"Hunting Dog Supplies","hasSubCategories":false},{"categoryId":4006,"categoryName":"Hunting Scents & Deer Lure","hasSubCategories":false},{"categoryId":4007,"categoryName":"Tree Stands","hasSubCategories":false},{"categoryId":4008,"categoryName":"Hunting Accessories","hasSubCategories":false},{"categoryId":4009,"categoryName":"Hunting Decoys","hasSubCategories":false},{"categoryId":4010,"categoryName":"Game Calls","hasSubCategories":false},{"categoryId":4065,"categoryName":"Scent Elimination","hasSubCategories":false},{"categoryId":4066,"categoryName":"GPS","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=3002","verb":"GET","title":"Search for items in Hunting Gear"}]},{"categoryID":3029,"categoryName":"Hunting Trips & Safaris","canContainItems":true,"description":"This category is for hunting or fishing trips, vacations, and excursions.","categoryPath":{"id":0,"name":"All","child":{"id":3029,"name":"Hunting Trips & Safaris","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=3029","verb":"GET","title":"Search for items in Hunting Trips & Safaris"}]},{"categoryID":2328,"categoryName":"Knives & Swords","canContainItems":false,"description":"All knives, swords, axes, pocket knives, bayonets, machetes, and other bladed items must be listed here. Knives may not be listed in any other category, with the sole exceptions of bayonets which may be listed in the Collectible Firearms : Collectible Parts & Accessories category provided the bayonet is a collectible and attaches to a collectible firearm.","categoryPath":{"id":0,"name":"All","child":{"id":2328,"name":"Knives & Swords","child":null}},"subCategories":[{"categoryId":3075,"categoryName":"Collectible Knives","hasSubCategories":false},{"categoryId":3076,"categoryName":"Daggers","hasSubCategories":false},{"categoryId":3077,"categoryName":"Hunting Knives","hasSubCategories":false},{"categoryId":3078,"categoryName":"Automatic Knives","hasSubCategories":false},{"categoryId":3079,"categoryName":"Pocket Knives","hasSubCategories":false},{"categoryId":3080,"categoryName":"Swords & Axes","hasSubCategories":false},{"categoryId":3081,"categoryName":"Bayonets","hasSubCategories":false},{"categoryId":3082,"categoryName":"Fixed Blade Knives","hasSubCategories":false},{"categoryId":3111,"categoryName":"Knife Accessories","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=2328","verb":"GET","title":"Search for items in Knives & Swords"}]},{"categoryID":3003,"categoryName":"Land & Leases","canContainItems":true,"description":"Property for sale, rent, or lease should be listed here. ","categoryPath":{"id":0,"name":"All","child":{"id":3003,"name":"Land & Leases","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=3003","verb":"GET","title":"Search for items in Land & Leases"}]},{"categoryID":900,"categoryName":"Non-Firing Replica Guns","canContainItems":true,"description":"The category includes non-firing replica guns (full size or miniature), guns that shoot blanks, or de-militarized firearms. The important distinction is that none of these items can shoot live ammunition nor can be converted to do so and are therefore not subject to FFL transfer.","categoryPath":{"id":0,"name":"All","child":{"id":900,"name":"Non-Firing Replica Guns","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=900","verb":"GET","title":"Search for items in Non-Firing Replica Guns"}]},{"categoryID":902,"categoryName":"Non-Lethal Weapons","canContainItems":true,"description":"This category is for non-lethal self-defense items, such as pepper spray, stun guns, tasers, and other non-firearm items.","categoryPath":{"id":0,"name":"All","child":{"id":902,"name":"Non-Lethal Weapons","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=902","verb":"GET","title":"Search for items in Non-Lethal Weapons"}]},{"categoryID":2335,"categoryName":"Services","canContainItems":false,"description":"Gunsmithing services, including repair and customizing","categoryPath":{"id":0,"name":"All","child":{"id":2335,"name":"Services","child":null}},"subCategories":[{"categoryId":3092,"categoryName":"Taxidermy Services","hasSubCategories":false},{"categoryId":3093,"categoryName":"Gunsmithing","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=2335","verb":"GET","title":"Search for items in Services"}]},{"categoryID":9001,"categoryName":"Staff Picks","canContainItems":true,"description":"Picks that we think are the best items or the coolest items to have.","categoryPath":{"id":0,"name":"All","child":{"id":9001,"name":"Staff Picks","child":null}},"subCategories":[],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=9001","verb":"GET","title":"Search for items in Staff Picks"}]}],"links":[{"rel":"next","href":"https://api.gunbroker.com/v1/Categories?PageIndex=2","verb":"GET","title":"next"}]}
@@ -0,0 +1 @@
1
+ {"categoryID":851,"categoryName":"Firearms","canContainItems":false,"description":"Modern Firearms are defined by the ATF as firearms built after 1898. All items listed in this category must be modern firearms. Firearm parts, ammunition, and accessories have their own categories and must be listed there. Items which meet the Collectible firearms, including antiques, commemoratives, and firearms which meet the ATF definition of a 'Curio and Relic' may be listed in the Collectible Firearms category.","categoryPath":{"id":0,"name":"All","child":{"id":851,"name":"Firearms","child":null}},"subCategories":[{"categoryId":978,"categoryName":"Pistols","hasSubCategories":true},{"categoryId":979,"categoryName":"Rifles","hasSubCategories":true},{"categoryId":980,"categoryName":"Shotguns","hasSubCategories":true},{"categoryId":2330,"categoryName":"Cowboy Action Shooting","hasSubCategories":false}],"links":[{"rel":"search","href":"https://api.gunbroker.com/v1/items?Categories=851","verb":"GET","title":"Search for items in Firearms"}]}
@@ -0,0 +1 @@
1
+ {"userMessage": "Access token deleted.", "developerMessage": "Access token deleted.", "links": []}
@@ -0,0 +1 @@
1
+ []
@@ -0,0 +1 @@
1
+ {"itemID":465370483,"bidIncrement":0.0,"bids":0,"buyer":null,"cashDiscount":0.0,"categoryID":3032,"categoryName":"Rifle Stocks","collectsSalesTax":false,"condition":{"1":"Factory New"},"currentBid":0.0,"description":"The Magpul STR (Storage/Type Restricted) is a drop-in replacement buttstock for AR15/M4 carbines using mil-spec sized receiver extension tubes. A storage-capable version of the CTR®, the STR has improved cheek weld and two water resistant battery tubes on a compact, reinforced polymer A-frame design. A shielded operation lever and supplemental friction locking system prevent accidental operation and minimize excessive stock movement for enhanced weapon stability and accuracy.","eligibleForImmediateCheckout":false,"endingDate":"2015-02-25T15:37:19Z","fixedPrice":49.99,"hasBuyNow":false,"buyNowPrice":0.0,"hasColor":false,"hasQuickLook":false,"hasPictures":true,"hasReserve":false,"hasReserveBeenMet":false,"hasStarted":true,"hasWinningBid":false,"isActive":true,"isCurrentUserHighBidder":false,"isFeaturedItem":false,"isfflRequired":false,"isFixedPrice":true,"isHighlighted":false,"isShowCaseItem":false,"isTitleBoldface":false,"isWatching":false,"inspectionPeriod":{"1":"AS IS - No refund or exchange"},"itemCharacteristics":[],"location":"Taylors, SC 29687","minimumBid":0.0,"paymentMethods":{"512":"PayPal"},"pictures":["http://pics.gunbroker.com/GB/465370000/465370483/pix789199977.jpg"],"quantity":3,"relistedAsItemID":0,"salesTaxes":[],"seller":{"userID":2266088,"username":"dangerangell","feedbackRating":"C(2)","isffl":false,"isVerified":true},"serialNumber":"","shippingClassCosts":{},"shippingClassesSupported":{"32":"Priority"},"sku":"","startingBid":0.00,"startingDate":"2015-01-26T15:37:19Z","subTitle":"","thumbnailURL":"http://pics.gunbroker.com/GB/465370000/465370483/thumb.jpg","timeLeft":"P26DT14H17M15S","title":"Magpul STR Carbine Stock Mil Spec Black","titleColor":"#000000","upc":"","viewCounter":15,"weight":null,"weightUnit":{"1":"Pounds"},"whoPaysForShipping":{"1":"See item description","4":"Buyer pays actual shipping cost"},"willShipInternational":false,"links":[{"rel":"fixedprice","href":"https://api.gunbroker.com/v1/fixedprice","verb":"POST","title":"Purchase"},{"rel":"watch","href":"https://api.gunbroker.com/v1/itemswatched","verb":"POST","title":"Add to Watch List"},{"rel":"feedback","href":"https://api.gunbroker.com/v1/feedback/summary/2266088","verb":"GET","title":"Feedback"},{"rel":"question","href":"https://api.gunbroker.com/v1/messages/askuser","verb":"POST","title":"Ask a question"},{"rel":"sellersitems","href":"https://api.gunbroker.com/v1/items?IncludeSellers=2266088","verb":"GET","title":"View Seller's Items"},{"rel":"share","href":"http://www.gunbroker.com/Auction/ViewItem.aspx?Item=465370483","verb":"GET","title":"Check out what I found on GunBroker.com!"}]}
@@ -0,0 +1 @@
1
+ {"count":1,"pageIndex":1,"pageSize":25,"results":[{"itemID":465370483,"bids":0,"eligibleForImmediateCheckout":false,"endingDate":"2015-02-25T15:37:19Z","isFeaturedItem":false,"isFixedPrice":true,"isHighlighted":false,"isShowCaseItem":false,"isTitleBoldface":false,"hasBuyNow":false,"hasColor":false,"hasQuickLook":false,"hasPictures":true,"hasReserve":false,"hasReserveBeenMet":false,"highBidderID":0,"quantity":3,"price":49.9900,"serialNumber":"","sku":"","subTitle":"","thumbnailURL":"http://pics.gunbroker.com/GB/465370000/465370483/thumb.jpg","timeLeft":"P26DT18H52M28S","title":"Magpul STR Carbine Stock Mil Spec Black","titleColor":"#000000","links":[{"rel":"self","href":"https://api.gunbroker.com/v1/items/465370483","verb":"GET","title":"465370483"}]}],"categoryCounts":[{"id":3032,"name":"Rifle Stocks","count":1}],"links":[{"rel":"share","href":"http://www.gunbroker.com/All/BI.aspx?IncludeSellers=2266088&PageSize=25","verb":"GET","title":"Check out what I found on GunBroker.com!"}]}
@@ -0,0 +1 @@
1
+ {"userMessage":"Unauthorized","developerMessage":"Unauthorized","links":[]}
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe GunBroker::API do
4
+
5
+ let(:token) { 'test-user-access-token' }
6
+
7
+ let(:path) { '/some/resource' }
8
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, path].join }
9
+
10
+ before(:all) do
11
+ GunBroker.dev_key = 'test-dev-key'
12
+ end
13
+
14
+ it 'has a GUNBROKER_API constant' do
15
+ expect(GunBroker::API::GUNBROKER_API).not_to be_nil
16
+ end
17
+
18
+ context '.delete' do
19
+ context 'on success' do
20
+ it 'returns JSON parsed response' do
21
+ stub_request(:delete, endpoint)
22
+ .with(headers: headers('X-AccessToken' => token))
23
+ .to_return(body: response_fixture('deauthenticate'))
24
+
25
+ response = GunBroker::API.delete(path, {}, headers('X-AccessToken' => token))
26
+ expect(response).to eq(JSON.parse(response_fixture('deauthenticate')))
27
+ end
28
+ end
29
+
30
+ context 'on failure' do
31
+ it 'raises an exception' do
32
+ stub_request(:delete, endpoint)
33
+ .with(headers: headers('X-AccessToken' => token))
34
+ .to_return(body: response_fixture('empty'), status: 500)
35
+
36
+ api = GunBroker::API.new(path, {}, headers('X-AccessToken' => token))
37
+ expect { api.delete! }.to raise_error(GunBroker::Error::RequestError)
38
+ end
39
+ end
40
+ end
41
+
42
+ context '.get' do
43
+ context 'on success' do
44
+ it 'returns JSON parsed response' do
45
+ stub_request(:get, endpoint)
46
+ .with(query: { 'SellerName' => 'test-user' })
47
+ .to_return(body: response_fixture('items'))
48
+
49
+ response = GunBroker::API.get(path, { 'SellerName' => 'test-user' })
50
+ expect(response).to eq(JSON.parse(response_fixture('items')))
51
+ end
52
+ end
53
+
54
+ context 'on failure' do
55
+ it 'raises an exception' do
56
+ stub_request(:get, endpoint)
57
+ .to_return(body: response_fixture('empty'), status: 500)
58
+
59
+ api = GunBroker::API.new(path)
60
+ expect { api.get! }.to raise_error(GunBroker::Error::RequestError)
61
+ end
62
+ end
63
+ end
64
+
65
+ context '.post' do
66
+ context 'on success' do
67
+ it 'returns JSON parsed response' do
68
+ stub_request(:post, endpoint)
69
+ .with(
70
+ headers: headers,
71
+ body: { username: 'test-user' }
72
+ )
73
+ .to_return(body: response_fixture('authenticate'))
74
+
75
+ response = GunBroker::API.post(path, { username: 'test-user' }, headers)
76
+ expect(response).to eq(JSON.parse(response_fixture('authenticate')))
77
+ end
78
+ end
79
+
80
+ context 'on failure' do
81
+ it 'raises an exception' do
82
+ stub_request(:post, endpoint)
83
+ .to_return(body: response_fixture('empty'), status: 500)
84
+
85
+ api = GunBroker::API.new(path)
86
+ expect { api.post! }.to raise_error(GunBroker::Error::RequestError)
87
+ end
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe GunBroker::Category do
4
+
5
+ let(:attrs) { JSON.parse(response_fixture('category')) }
6
+
7
+ before(:all) do
8
+ GunBroker.dev_key = 'test-dev-key'
9
+ end
10
+
11
+ it 'has a ROOT_CATEGORY_ID constant' do
12
+ expect(GunBroker::Category::ROOT_CATEGORY_ID).not_to be_nil
13
+ end
14
+
15
+ it 'should have an #id' do
16
+ category = GunBroker::Category.new(attrs)
17
+ expect(category.id).to eq(attrs['categoryID'])
18
+ end
19
+
20
+ context '.all' do
21
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, '/Categories'].join }
22
+
23
+ context 'on success' do
24
+ it 'returns all categories' do
25
+ stub_request(:get, endpoint)
26
+ .with(
27
+ headers: headers,
28
+ query: { 'ParentCategoryID' => GunBroker::Category::ROOT_CATEGORY_ID }
29
+ )
30
+ .to_return(body: response_fixture('categories'))
31
+
32
+ categories = GunBroker::Category.all
33
+ expect(categories).not_to be_empty
34
+ expect(categories.first).to be_a(GunBroker::Category)
35
+ end
36
+ end
37
+
38
+ context 'on failure' do
39
+ it 'should raise a GunBroker::Error::RequestError exception' do
40
+ stub_request(:get, endpoint)
41
+ .with(
42
+ headers: headers,
43
+ query: { 'ParentCategoryID' => GunBroker::Category::ROOT_CATEGORY_ID }
44
+ )
45
+ .to_return(body: response_fixture('not_authorized'), status: 401)
46
+
47
+ expect { GunBroker::Category.all }.to raise_error(GunBroker::Error::NotAuthorized)
48
+ end
49
+ end
50
+ end
51
+
52
+ context '.find' do
53
+ let(:attrs) { JSON.parse(response_fixture('category')) }
54
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, "/Categories/#{attrs['categoryID']}"].join }
55
+
56
+ context 'on success' do
57
+ it 'returns the Category' do
58
+ stub_request(:get, endpoint)
59
+ .with(headers: headers)
60
+ .to_return(body: response_fixture('category'))
61
+
62
+ id = attrs['categoryID']
63
+ category = GunBroker::Category.find(id)
64
+ expect(category).to be_a(GunBroker::Category)
65
+ expect(category.id).to eq(id)
66
+ end
67
+ end
68
+
69
+ context 'on failure' do
70
+ it 'should raise a GunBroker::Error::RequestError exception' do
71
+ stub_request(:get, endpoint)
72
+ .with(headers: headers)
73
+ .to_return(body: response_fixture('not_authorized'), status: 401)
74
+
75
+ id = attrs['categoryID']
76
+ expect { GunBroker::Category.find(id) }.to raise_error(GunBroker::Error::NotAuthorized)
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe GunBroker::Item do
4
+
5
+ let(:attrs) { JSON.parse(response_fixture('item')) }
6
+
7
+ it 'should have an #id' do
8
+ item = GunBroker::Item.new(attrs)
9
+ expect(item.id).to eq(attrs['itemID'])
10
+ end
11
+
12
+ context '#[]' do
13
+ it 'should return the value from @attrs' do
14
+ item = GunBroker::Item.new(attrs)
15
+ attrs.each { |k, v| expect(item[k]).to eq(v) }
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+
3
+ describe GunBroker::User do
4
+ let(:username) { 'test-user' }
5
+ let(:password) { 'sekret-passw0rd' }
6
+ let(:token) { 'test-user-access-token' }
7
+
8
+ before(:all) do
9
+ GunBroker.dev_key = 'test-dev-key'
10
+ end
11
+
12
+ context '#initialize' do
13
+ context 'auth_options' do
14
+ it 'should accept a password' do
15
+ user = GunBroker::User.new(username, password: password)
16
+ expect(user.instance_variable_get(:@username)).to eq(username)
17
+ end
18
+
19
+ it 'should accept an access token' do
20
+ user = GunBroker::User.new(username, token: token)
21
+ expect(user.token).to eq(token)
22
+ end
23
+ end
24
+ end
25
+
26
+ context '#authenticate!' do
27
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, '/Users/AccessToken'].join }
28
+
29
+ context 'on success' do
30
+ it 'should set the access token' do
31
+ stub_request(:post, endpoint)
32
+ .with(
33
+ headers: headers,
34
+ body: { username: username, password: password },
35
+ )
36
+ .to_return(body: { 'accessToken' => token }.to_json)
37
+
38
+ user = GunBroker::User.new(username, password: password)
39
+ user.authenticate!
40
+
41
+ expect(user.token).to eq(token)
42
+ end
43
+ end
44
+
45
+ context 'on failure' do
46
+ it 'should raise a GunBroker::Error::NotAuthorized exception' do
47
+ stub_request(:post, endpoint)
48
+ .with(
49
+ headers: headers,
50
+ body: { username: username, password: password }
51
+ ).to_return(body: response_fixture('not_authorized'), status: 401)
52
+
53
+ user = GunBroker::User.new(username, password: password)
54
+ expect { user.authenticate! }.to raise_error(GunBroker::Error::NotAuthorized)
55
+ end
56
+ end
57
+ end
58
+
59
+ context '#deauthenticate!' do
60
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, '/Users/AccessToken'].join }
61
+
62
+ context 'on success' do
63
+ it 'should deactivate the current access token' do
64
+ user = GunBroker::User.new(username, token: token)
65
+
66
+ stub_request(:delete, endpoint)
67
+ .with(headers: headers)
68
+ .to_return(body: response_fixture('deauthenticate'))
69
+
70
+ expect(user.deauthenticate!).to eq(true)
71
+ expect(user.token).to be_nil
72
+ end
73
+ end
74
+
75
+ context 'on failure' do
76
+ it 'should raise an exception' do
77
+ user = GunBroker::User.new(username, token: token)
78
+
79
+ stub_request(:delete, endpoint)
80
+ .with(headers: headers)
81
+ .to_return(body: response_fixture('not_authorized'), status: 401)
82
+
83
+ expect { user.deauthenticate! }.to raise_error(GunBroker::Error::NotAuthorized)
84
+ end
85
+ end
86
+ end
87
+
88
+ context '#items' do
89
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, '/Items'].join }
90
+
91
+ context 'on success' do
92
+ it 'returns the User items' do
93
+ stub_request(:get, endpoint)
94
+ .with(
95
+ headers: headers('X-AccessToken' => token),
96
+ query: { 'SellerName' => username }
97
+ )
98
+ .to_return(body: response_fixture('items'))
99
+
100
+ user = GunBroker::User.new(username, token: token)
101
+ expect(user.items).not_to be_empty
102
+ expect(user.items.first).to be_a(GunBroker::Item)
103
+ end
104
+ end
105
+
106
+ context 'on failure' do
107
+ it 'should raise an exception' do
108
+ stub_request(:get, endpoint)
109
+ .with(
110
+ headers: headers('X-AccessToken' => token),
111
+ query: { 'SellerName' => username }
112
+ )
113
+ .to_return(body: response_fixture('not_authorized'), status: 401)
114
+
115
+ user = GunBroker::User.new(username, token: token)
116
+ expect { user.items }.to raise_error(GunBroker::Error::NotAuthorized)
117
+ end
118
+ end
119
+ end
120
+
121
+ context '#unsold_items' do
122
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, '/ItemsUnsold'].join }
123
+
124
+ context 'on success' do
125
+ it 'returns unsold Items' do
126
+ stub_request(:get, endpoint)
127
+ .with(headers: headers('X-AccessToken' => token))
128
+ .to_return(body: response_fixture('items'))
129
+
130
+ user = GunBroker::User.new(username, token: token)
131
+ expect(user.unsold_items).not_to be_empty
132
+ expect(user.unsold_items.first).to be_a(GunBroker::Item)
133
+ end
134
+ end
135
+
136
+ context 'on failure' do
137
+ it 'raises an exception' do
138
+ stub_request(:get, endpoint)
139
+ .with(headers: headers('X-AccessToken' => token))
140
+ .to_return(body: response_fixture('not_authorized'), status: 401)
141
+
142
+ user = GunBroker::User.new(username, token: token)
143
+ expect { user.unsold_items }.to raise_error(GunBroker::Error::NotAuthorized)
144
+ end
145
+ end
146
+ end
147
+
148
+ context '#sold_items' do
149
+ let(:endpoint) { [GunBroker::API::GUNBROKER_API, '/ItemsSold'].join }
150
+
151
+ context 'on success' do
152
+ it 'returns sold Items' do
153
+ stub_request(:get, endpoint)
154
+ .with(headers: headers('X-AccessToken' => token))
155
+ .to_return(body: response_fixture('items'))
156
+
157
+ user = GunBroker::User.new(username, token: token)
158
+ expect(user.sold_items).not_to be_empty
159
+ expect(user.sold_items.first).to be_a(GunBroker::Item)
160
+ end
161
+ end
162
+
163
+ context 'on failure' do
164
+ it 'raises an exception' do
165
+ stub_request(:get, endpoint)
166
+ .with(headers: headers('X-AccessToken' => token))
167
+ .to_return(body: response_fixture('not_authorized'), status: 401)
168
+
169
+ user = GunBroker::User.new(username, token: token)
170
+ expect { user.sold_items }.to raise_error(GunBroker::Error::NotAuthorized)
171
+ end
172
+ end
173
+ end
174
+
175
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe GunBroker do
4
+
5
+ it 'has a VERSION' do
6
+ expect(GunBroker::VERSION).to be_a(String)
7
+ end
8
+
9
+ context 'dev_key' do
10
+ let(:key) { 'foo' }
11
+
12
+ it 'sets @@dev_key' do
13
+ GunBroker.dev_key = key
14
+ expect(GunBroker.class_variable_get(:@@dev_key)).to eq(key)
15
+ end
16
+
17
+ it 'returns @@dev_key' do
18
+ GunBroker.dev_key = key
19
+ expect(GunBroker.dev_key).to eq(key)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,11 @@
1
+ require 'rspec'
2
+ require 'webmock/rspec'
3
+
4
+ Dir['./spec/support/**/*.rb'].each { |support| require support }
5
+
6
+ require 'gun_broker'
7
+
8
+ RSpec.configure do |config|
9
+ config.include GunBroker::Test::Fixtures
10
+ config.include GunBroker::Test::Headers
11
+ end
@@ -0,0 +1,11 @@
1
+ module GunBroker
2
+ module Test
3
+ module Fixtures
4
+
5
+ def response_fixture(name)
6
+ File.read(File.expand_path("../../fixtures/#{name}.json", __FILE__))
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module GunBroker
2
+ module Test
3
+ module Headers
4
+
5
+ def headers(overrides = {})
6
+ {
7
+ 'Content-Type' => 'application/json',
8
+ 'X-DevKey' => GunBroker.dev_key
9
+ }.merge(overrides)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gun_broker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dale Campbell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-31 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.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
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: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.20'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.20'
69
+ description: ''
70
+ email:
71
+ - oshuma@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - .rspec
78
+ - .ruby-gemset
79
+ - .ruby-version
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - gun_broker.gemspec
85
+ - lib/gun_broker.rb
86
+ - lib/gun_broker/api.rb
87
+ - lib/gun_broker/category.rb
88
+ - lib/gun_broker/error.rb
89
+ - lib/gun_broker/item.rb
90
+ - lib/gun_broker/user.rb
91
+ - lib/gun_broker/version.rb
92
+ - spec/fixtures/authenticate.json
93
+ - spec/fixtures/categories.json
94
+ - spec/fixtures/category.json
95
+ - spec/fixtures/deauthenticate.json
96
+ - spec/fixtures/empty.json
97
+ - spec/fixtures/item.json
98
+ - spec/fixtures/items.json
99
+ - spec/fixtures/not_authorized.json
100
+ - spec/gun_broker/api_spec.rb
101
+ - spec/gun_broker/category_spec.rb
102
+ - spec/gun_broker/item_spec.rb
103
+ - spec/gun_broker/user_spec.rb
104
+ - spec/gun_broker_spec.rb
105
+ - spec/spec_helper.rb
106
+ - spec/support/fixtures.rb
107
+ - spec/support/headers.rb
108
+ homepage: ''
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.4.1
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: GunBroker.com API Ruby library.
132
+ test_files:
133
+ - spec/fixtures/authenticate.json
134
+ - spec/fixtures/categories.json
135
+ - spec/fixtures/category.json
136
+ - spec/fixtures/deauthenticate.json
137
+ - spec/fixtures/empty.json
138
+ - spec/fixtures/item.json
139
+ - spec/fixtures/items.json
140
+ - spec/fixtures/not_authorized.json
141
+ - spec/gun_broker/api_spec.rb
142
+ - spec/gun_broker/category_spec.rb
143
+ - spec/gun_broker/item_spec.rb
144
+ - spec/gun_broker/user_spec.rb
145
+ - spec/gun_broker_spec.rb
146
+ - spec/spec_helper.rb
147
+ - spec/support/fixtures.rb
148
+ - spec/support/headers.rb