cb_nitride 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +10 -0
- data/cb_nitride.gemspec +23 -0
- data/lib/cb_nitride/category_sorter.rb +70 -0
- data/lib/cb_nitride/configuration.rb +15 -0
- data/lib/cb_nitride/diamond_item.rb +95 -0
- data/lib/cb_nitride/diamond_login.rb +45 -0
- data/lib/cb_nitride/diamond_number_generator.rb +52 -0
- data/lib/cb_nitride/exceptions.rb +3 -0
- data/lib/cb_nitride/hasher_methods.rb +20 -0
- data/lib/cb_nitride/module_methods.rb +17 -0
- data/lib/cb_nitride/private_hasher.rb +72 -0
- data/lib/cb_nitride/public_hasher.rb +83 -0
- data/lib/cb_nitride/version.rb +3 -0
- data/lib/cb_nitride.rb +43 -0
- data/test/cassettes/test_that_it_can_log_in_cassette.yml +880 -0
- data/test/cassettes/test_that_it_fails_with_bad_information_cassette.yml +294 -0
- data/test/cassettes/test_that_it_resets_the_agent_cassette.yml +2188 -0
- data/test/cassettes/test_that_the_private_diamond_item_contains_the_right_fields_cassette.yml +660 -0
- data/test/cassettes/test_that_the_private_hash_contains_the_right_fields_cassette.yml +708 -0
- data/test/cassettes/test_that_the_private_hash_identifies_collection_cassette.yml +714 -0
- data/test/cassettes/test_that_the_private_hash_identifies_invalid_diamond_codes_cassette.yml +636 -0
- data/test/cassettes/test_that_the_private_hash_identifies_issues_cassette.yml +707 -0
- data/test/cassettes/test_that_the_private_hash_identifies_merchandise_cassette.yml +705 -0
- data/test/cassettes/test_that_the_private_hash_identifies_variants_cassette.yml +708 -0
- data/test/cassettes/test_that_the_private_hash_produces_a_diamond_item_cassette.yml +660 -0
- data/test/cassettes/test_that_the_public_diamond_item_contains_the_right_fields_cassette.yml +196 -0
- data/test/cassettes/test_that_the_public_hash_contains_the_right_fields_cassette.yml +208 -0
- data/test/cassettes/test_that_the_public_hash_identifies_collection_cassette.yml +212 -0
- data/test/cassettes/test_that_the_public_hash_identifies_invalid_diamond_codes_cassette.yml +570 -0
- data/test/cassettes/test_that_the_public_hash_identifies_issues_cassette.yml +208 -0
- data/test/cassettes/test_that_the_public_hash_identifies_merchandise_cassette.yml +207 -0
- data/test/cassettes/test_that_the_public_hash_identifies_variants_cassette.yml +209 -0
- data/test/cassettes/test_that_the_public_hash_produces_a_diamond_item_cassette.yml +599 -0
- data/test/test_helper.rb +67 -0
- data/test/unit/configuration_test.rb +19 -0
- data/test/unit/diamond_item_test.rb +42 -0
- data/test/unit/diamond_login_test.rb +42 -0
- data/test/unit/private_hasher_test.rb +67 -0
- data/test/unit/public_hasher_test.rb +59 -0
- data/test/unit/pull_test.rb +8 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0670f6bb606e0d7eca5f95cf36733f35ea56e1c1
|
4
|
+
data.tar.gz: 2305137bd690a5b10b0e60197c3aa1ed93c722b6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e8be45555b36f5e63ae56608283d00a7e63b7cc5d047774f28e9f531af65defcca318a64a4dfddbe274310f06eda3369d7d12eff3006e6fd6acbf78c5e744fb
|
7
|
+
data.tar.gz: 59fb28a9c7297dbfcc63cb90f65a1901aabce95107476908ed55b029feaaec84c2c14ec6ae301ac79d57226f81a493ba2c7ee5914a486aba5e6c532a095d1982
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Alex Jarvis
|
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,29 @@
|
|
1
|
+
# CbNitride
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'cb_nitride'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install cb_nitride
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/cb_nitride.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cb_nitride/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cb_nitride"
|
8
|
+
spec.version = CbNitride::VERSION
|
9
|
+
spec.authors = ["Alex Jarvis"]
|
10
|
+
spec.email = ["alxjrvs@gmail.com"]
|
11
|
+
spec.description = %q{A Gem for accessing information from the diamond comics backend.}
|
12
|
+
spec.summary = %q{Only useable with a qualified Diamond Comic Retailer!}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
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.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module CbNitride
|
2
|
+
class CategorySorter
|
3
|
+
|
4
|
+
ISSUE_CODE = "1"
|
5
|
+
COLLECTION_CODE = "3"
|
6
|
+
MERCHANDISE_CODES = ["2", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"]
|
7
|
+
|
8
|
+
attr_reader :hash
|
9
|
+
|
10
|
+
def initialize(hash)
|
11
|
+
@hash = hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def sort
|
15
|
+
return hash[:category_code] unless hash[:category_code].nil?
|
16
|
+
return ISSUE_CODE if is_variant?
|
17
|
+
return COLLECTION_CODE if is_collection?
|
18
|
+
return "16" if is_merch?
|
19
|
+
return ISSUE_CODE if is_issue?
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def is_variant?
|
25
|
+
return @is_variant unless @is_variant.nil?
|
26
|
+
@is_variant = true if hash[:title].include? "VAR ED"
|
27
|
+
@is_variant = true if hash[:title].include? "COMBO PACK"
|
28
|
+
@is_variant = true if hash[:title].match(/(CVR)\s[B-Z]/)
|
29
|
+
@is_variant = false if @is_variant.nil?
|
30
|
+
return @is_variant
|
31
|
+
end
|
32
|
+
|
33
|
+
def is_issue?
|
34
|
+
return @is_issue unless @is_issue.nil?
|
35
|
+
if hash[:title].match(/(CVR)\s[A]/)
|
36
|
+
@is_issue = true
|
37
|
+
elsif is_variant?
|
38
|
+
@is_issue = false
|
39
|
+
elsif is_collection?
|
40
|
+
@is_issue = false
|
41
|
+
elsif is_merch?
|
42
|
+
@is_issue = false
|
43
|
+
else
|
44
|
+
@is_issue = true
|
45
|
+
end
|
46
|
+
return @is_issue
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_collection?
|
50
|
+
return @is_collection unless @is_collection.nil?
|
51
|
+
@is_collection = true if hash[:title].include?(" GN ")
|
52
|
+
@is_collection = true if hash[:title].include?(" TP ")
|
53
|
+
@is_collection = true if hash[:title].match(/\s(VOL)\s\d+/)
|
54
|
+
@is_collection = false if hash[:title].match(/\s[#]\d+/)
|
55
|
+
@is_collection = false if @is_collection.nil?
|
56
|
+
return @is_collection
|
57
|
+
end
|
58
|
+
|
59
|
+
def is_merch?
|
60
|
+
return @is_merch unless @is_merch.nil?
|
61
|
+
case hash[:creators]
|
62
|
+
when ""
|
63
|
+
@is_merch = true
|
64
|
+
else
|
65
|
+
@is_merch = false
|
66
|
+
end
|
67
|
+
return @is_merch
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CbNitride
|
2
|
+
|
3
|
+
def self.configure(configuration = CbNitride::Configuration.new)
|
4
|
+
yield configuration if block_given?
|
5
|
+
@@configuration = configuration
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.configuration
|
9
|
+
@@configuration ||= CbNitride::Configuration.new
|
10
|
+
end
|
11
|
+
|
12
|
+
class Configuration
|
13
|
+
attr_accessor :username, :password, :account_number
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module CbNitride
|
2
|
+
class DiamondItem
|
3
|
+
|
4
|
+
attr_reader :state, :diamond_number, :title, :stock_number, :image_url, :publisher, :creators, :description, :release_date, :price, :category_code
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@state = options[:state]
|
8
|
+
@title = options[:title]
|
9
|
+
@diamond_number = options[:diamond_number]
|
10
|
+
@stock_number = options[:stock_number]
|
11
|
+
@image_url = options[:image_url]
|
12
|
+
@publisher = options[:publisher]
|
13
|
+
@creators = options[:creators]
|
14
|
+
@description = options[:description]
|
15
|
+
@release_date = options[:release_date]
|
16
|
+
@price = options[:price]
|
17
|
+
@category_code = options[:category_code]
|
18
|
+
@errors = options[:errors]
|
19
|
+
end
|
20
|
+
|
21
|
+
def writer
|
22
|
+
@_writer ||= creators_hash["W"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def artist
|
26
|
+
@_artist ||= creators_hash["A"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def cover_artist
|
30
|
+
@_cover_artist ||= creators_hash["CA"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def product_type?
|
34
|
+
return :issue if is_issue?
|
35
|
+
return :variant if is_variant?
|
36
|
+
return :collection if is_collection?
|
37
|
+
return :merchandise if is_merch?
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def creators_hash
|
43
|
+
return @_creators_hash if @_creators_hash
|
44
|
+
array = creators.split('(').map {|x| x.split(')')}.flatten.map {|x| x.strip}
|
45
|
+
hash ={}
|
46
|
+
array.each_with_index do |val, i|
|
47
|
+
if i.even? || i == 0
|
48
|
+
if val.include? '/'
|
49
|
+
val.split('/').each_with_index do |key, index|
|
50
|
+
instance_variable_set("@key#{index + 1}".to_sym, key)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
@key = val
|
54
|
+
end
|
55
|
+
elsif i.odd?
|
56
|
+
@value = val
|
57
|
+
hash.merge! @key => @value if @key
|
58
|
+
hash.merge! @key1 => @value if @key1
|
59
|
+
hash.merge! @key2 => @value if @key2
|
60
|
+
hash.merge! @key3 => @value if @key3
|
61
|
+
@value = nil
|
62
|
+
@key = nil
|
63
|
+
@key1= nil
|
64
|
+
@key2 = nil
|
65
|
+
@key3 = nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@_creators_hash = hash
|
69
|
+
end
|
70
|
+
|
71
|
+
def is_collection?
|
72
|
+
@_is_collection ||= CategorySorter::COLLECTION_CODE == category_code
|
73
|
+
end
|
74
|
+
|
75
|
+
def is_merch?
|
76
|
+
@_is_merch ||= CategorySorter::MERCHANDISE_CODES.include? category_code
|
77
|
+
end
|
78
|
+
|
79
|
+
def is_issue?
|
80
|
+
@_is_issue ||=
|
81
|
+
category_code == CategorySorter::ISSUE_CODE && is_variant? == false
|
82
|
+
end
|
83
|
+
|
84
|
+
def is_variant?
|
85
|
+
@_is_variant ||=
|
86
|
+
value = false
|
87
|
+
if category_code == CategorySorter::ISSUE_CODE
|
88
|
+
value = true if title.include?("VAR ED")
|
89
|
+
value = true if title.include?("COMBO PACK")
|
90
|
+
value = true if title.match(/(CVR)\s[B-Z]/)
|
91
|
+
end
|
92
|
+
value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
module CbNitride
|
3
|
+
|
4
|
+
class DiamondLogin
|
5
|
+
|
6
|
+
LOGIN_URL = "https://retailerservices.diamondcomics.com/Login/Login"
|
7
|
+
|
8
|
+
HOME_URL = "https://retailerservices.diamondcomics.com/Home/Index"
|
9
|
+
|
10
|
+
attr_accessor :agent
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def agent
|
14
|
+
self.new.login
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def agent
|
19
|
+
@agent ||= login
|
20
|
+
end
|
21
|
+
|
22
|
+
def reset_agent
|
23
|
+
self.agent = nil
|
24
|
+
login
|
25
|
+
end
|
26
|
+
|
27
|
+
def login
|
28
|
+
empty_agent = Mechanize.new
|
29
|
+
page = empty_agent.get(LOGIN_URL)
|
30
|
+
empty_agent.user_agent_alias = 'Mac Safari'
|
31
|
+
form = page.form
|
32
|
+
form.UserName = CbNitride.username
|
33
|
+
form.EnteredCustNo = CbNitride.account_number
|
34
|
+
form.Password = CbNitride.password
|
35
|
+
empty_agent.submit(form)
|
36
|
+
agent = empty_agent
|
37
|
+
unless agent.page.uri.to_s.include? LOGIN_URL
|
38
|
+
agent
|
39
|
+
else
|
40
|
+
raise InvalidLoginError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module CbNitride
|
2
|
+
class DiamondNumberGenerator
|
3
|
+
|
4
|
+
attr_reader :month, :year
|
5
|
+
attr_accessor :count
|
6
|
+
|
7
|
+
MONTH_CODES = ['JAN', 'FEB', 'MAR', 'APR', 'JUN', 'MAY', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
|
8
|
+
YEAR_CODES = ['06','07','08','09','10','11','12','13']
|
9
|
+
|
10
|
+
def self.generate
|
11
|
+
new.formatted_numbers
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(year = nil, options = {})
|
15
|
+
@target_month = month
|
16
|
+
@target_year = year
|
17
|
+
end
|
18
|
+
|
19
|
+
def formatted_numbers
|
20
|
+
YEAR_CODES.map do |year|
|
21
|
+
MONTH_CODES.map do |month|
|
22
|
+
generate_numbers(year, month)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def all_for_year
|
28
|
+
MONTH_CODES.map do |month|
|
29
|
+
generate_numbers(year, month)
|
30
|
+
end.flatten
|
31
|
+
end
|
32
|
+
private
|
33
|
+
|
34
|
+
def generate_numbers(year, month)
|
35
|
+
(1...3000).map do |num|
|
36
|
+
format_single_number(year, month, num)
|
37
|
+
end.flatten.compact
|
38
|
+
end
|
39
|
+
|
40
|
+
def format_single_number(year, month, num)
|
41
|
+
month + year + calculate_zeroes(num)
|
42
|
+
end
|
43
|
+
|
44
|
+
def formatted_number(num)
|
45
|
+
month + year + calculate_zeroes(num)
|
46
|
+
end
|
47
|
+
|
48
|
+
def calculate_zeroes(num)
|
49
|
+
("0" * (4 - num.to_s.size)) + num.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CbNitride
|
2
|
+
module HasherMethods
|
3
|
+
|
4
|
+
def find_text_with(code)
|
5
|
+
item_page.css(code).text.strip
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_image_url(base_url, image_class)
|
9
|
+
base_url + item_page.css(image_class).children[1].attributes["src"].value
|
10
|
+
end
|
11
|
+
|
12
|
+
def clean_price_float(price)
|
13
|
+
price.match(/\d+[.]\d+/).to_s.to_f
|
14
|
+
end
|
15
|
+
|
16
|
+
def clean_date_string(date)
|
17
|
+
Date.strptime(date.match(/\d+[\/]\d+[\/]\d+/).to_s, "%m/%d/%Y")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CbNitride
|
2
|
+
def self.password
|
3
|
+
self.configuration.password
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.username
|
7
|
+
self.configuration.username
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.account_number
|
11
|
+
self.configuration.account_number
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.qualified?
|
15
|
+
password && username && account_number ? true : false
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module CbNitride
|
2
|
+
class PrivateHasher
|
3
|
+
include HasherMethods
|
4
|
+
attr_reader :diamond_number, :agent, :container_class, :search_url, :image_class
|
5
|
+
|
6
|
+
BASE_URL = "https://retailerservices.diamondcomics.com"
|
7
|
+
DIAMOND_NUMBER_SEARCH_PATH = "/ShoppingList/AddItem/"
|
8
|
+
|
9
|
+
SEARCH_URL = BASE_URL + DIAMOND_NUMBER_SEARCH_PATH
|
10
|
+
|
11
|
+
IMAGE_CLASS = 'a.ImagePopup'
|
12
|
+
TITLE_CLASS = '.ItemDetails_ItemName'
|
13
|
+
PUBLISHER_CLASS = '.ItemDetails_Publisher'
|
14
|
+
CREATOR_CLASS = '.ItemDetails_Creator'
|
15
|
+
DESCRIPTION_CLASS = '.ItemDetails_Description'
|
16
|
+
CONTAINER_CLASS = '.PopupContent'
|
17
|
+
|
18
|
+
def self.item(diamond_number, agent = DiamondLogin.agent)
|
19
|
+
item = new(diamond_number, agent)
|
20
|
+
if item.valid_diamond_number?
|
21
|
+
item.spawn_item
|
22
|
+
else
|
23
|
+
return nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(diamond_number, agent = DiamondLogin.agent)
|
28
|
+
@diamond_number = diamond_number
|
29
|
+
@agent = agent
|
30
|
+
end
|
31
|
+
|
32
|
+
def spawn_item
|
33
|
+
DiamondItem.new(branded_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def valid_diamond_number?
|
37
|
+
if item_page.css(CONTAINER_CLASS).empty?
|
38
|
+
return false
|
39
|
+
else
|
40
|
+
return true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def native_hash
|
47
|
+
@native_hash ||= item_page.css('.LookupItemData_Item').map do |l|
|
48
|
+
Hash[l.css('.LookupItemData_Label').text.strip => l.css('.LookupItemData_Value').text.strip]
|
49
|
+
end.reduce Hash.new, :merge
|
50
|
+
end
|
51
|
+
|
52
|
+
def branded_hash
|
53
|
+
@branded_hash ||= {
|
54
|
+
title: find_text_with(TITLE_CLASS),
|
55
|
+
diamond_number: diamond_number,
|
56
|
+
stock_number: native_hash["Stock #"],
|
57
|
+
image_url: get_image_url(BASE_URL, IMAGE_CLASS),
|
58
|
+
publisher: find_text_with(PUBLISHER_CLASS),
|
59
|
+
creators: find_text_with(CREATOR_CLASS),
|
60
|
+
description: find_text_with(DESCRIPTION_CLASS),
|
61
|
+
release_date: clean_date_string(native_hash["Est Ship Date"]),
|
62
|
+
price: clean_price_float(native_hash["Price Before Discount"]),
|
63
|
+
category_code: native_hash["Category Code"],
|
64
|
+
state: :private
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def item_page
|
69
|
+
@item_page ||= Nokogiri::HTML(agent.get(SEARCH_URL + diamond_number).content)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module CbNitride
|
5
|
+
class PublicHasher
|
6
|
+
include HasherMethods
|
7
|
+
attr_reader :diamond_number, :agent, :container_class, :search_url, :image_class
|
8
|
+
|
9
|
+
BASE_URL = "http://www.previewsworld.com"
|
10
|
+
DIAMOND_NUMBER_SEARCH_PATH = "/Home/1/1/71/952?stockItemID="
|
11
|
+
|
12
|
+
SEARCH_URL = BASE_URL + DIAMOND_NUMBER_SEARCH_PATH
|
13
|
+
|
14
|
+
IMAGE_CLASS = "a.FancyPopupImage"
|
15
|
+
CONTAINER_CLASS = ".StockCode"
|
16
|
+
TITLE_CLASS = ".StockCodeDescription"
|
17
|
+
PUBLISHER_CLASS = ".StockCodePublisher"
|
18
|
+
CREATOR_CLASS = ".StockCodeCreators"
|
19
|
+
DESCRIPTION_CLASS = ".PreviewsHtml"
|
20
|
+
RELEASE_CLASS = ".StockCodeInShopsDate"
|
21
|
+
PRICE_CLASS = ".StockCodeSrp"
|
22
|
+
|
23
|
+
def self.item(diamond_number)
|
24
|
+
item = new(diamond_number)
|
25
|
+
if item.valid_diamond_number?
|
26
|
+
item.spawn_item
|
27
|
+
else
|
28
|
+
return nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(diamond_number)
|
33
|
+
@diamond_number = diamond_number
|
34
|
+
@agent = Mechanize.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def spawn_item
|
38
|
+
DiamondItem.new(branded_hash)
|
39
|
+
end
|
40
|
+
|
41
|
+
def valid_diamond_number?
|
42
|
+
if item_page.css(CONTAINER_CLASS).empty?
|
43
|
+
return false
|
44
|
+
else
|
45
|
+
return true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def get_stock_number
|
52
|
+
item_page.css("a.FancyPopupImage").children[1]["alt"].gsub(" Image", "")
|
53
|
+
end
|
54
|
+
|
55
|
+
def uncategorized_hash
|
56
|
+
@_uncategorized_hash ||= {
|
57
|
+
title: find_text_with(TITLE_CLASS),
|
58
|
+
diamond_number: diamond_number,
|
59
|
+
stock_number: get_stock_number,
|
60
|
+
image_url: get_image_url(BASE_URL, IMAGE_CLASS),
|
61
|
+
publisher: find_text_with(PUBLISHER_CLASS).gsub(/Publisher:\W*/, ""),
|
62
|
+
creators: find_text_with(CREATOR_CLASS),
|
63
|
+
description: find_text_with(DESCRIPTION_CLASS),
|
64
|
+
release_date: clean_date_string(find_text_with(RELEASE_CLASS)),
|
65
|
+
price: clean_price_float(find_text_with(PRICE_CLASS)),
|
66
|
+
state: :public
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def branded_hash
|
71
|
+
@_branded_hash ||=
|
72
|
+
uncategorized_hash.merge!(
|
73
|
+
category_code: CategorySorter.new(uncategorized_hash).sort
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
def item_page
|
80
|
+
@item_page ||= Nokogiri::HTML(agent.get(SEARCH_URL + diamond_number).content)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/cb_nitride.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require "cb_nitride/version"
|
3
|
+
require "cb_nitride/exceptions"
|
4
|
+
require "cb_nitride/module_methods"
|
5
|
+
require "cb_nitride/hasher_methods"
|
6
|
+
require "cb_nitride/configuration"
|
7
|
+
require "cb_nitride/diamond_login"
|
8
|
+
require "cb_nitride/public_hasher"
|
9
|
+
require "cb_nitride/private_hasher"
|
10
|
+
require "cb_nitride/category_sorter"
|
11
|
+
require "cb_nitride/diamond_item"
|
12
|
+
require "cb_nitride/diamond_number_generator"
|
13
|
+
|
14
|
+
module CbNitride
|
15
|
+
def self.item(diamond_number, qualified = false)
|
16
|
+
unless qualified?
|
17
|
+
PublicHasher.item(diamond_number)
|
18
|
+
else
|
19
|
+
PrivateHasher.item(diamond_number)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.generate_diamond_numbers
|
24
|
+
@_generate_diamond_numbers ||= DiamondNumberGenerator.generate
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.scrape_all!
|
28
|
+
generate_diamond_numbers.map do |year_scope|
|
29
|
+
year_scope.each do |month|
|
30
|
+
month.each do |diamond_number|
|
31
|
+
diamond_item = item(diamond_number)
|
32
|
+
if diamond_item.nil?
|
33
|
+
binding.pry
|
34
|
+
else
|
35
|
+
diamond_item
|
36
|
+
puts "Recorded #{diamond_item.title}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end.flatten
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|