magic_tcg_finder 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae6746697a1a2c8d0e7b91eb12b563a0db93bfc7
4
- data.tar.gz: 9a09bbd7aa5b1905b23d83ea8f1c137d2e8b6998
3
+ metadata.gz: fc50cb1eec2425c089d79ddb627e515ab7a3e65d
4
+ data.tar.gz: 3fa482305de2d27ade8db72ec5adc2b09d627016
5
5
  SHA512:
6
- metadata.gz: 04b2486ad97b105df6b2c10bd7978d3ecb07c63466d2598c020c1b61e4b2c88a7b1a09c3c692ded8b8a564f55aded3c05d8e64983197b4b41f8854625d4315d8
7
- data.tar.gz: b334687d88a08e53995273d339e7bbfad811919e94b29f0c238fa37f5df069223f434b6680abca439c0d8281283c0e4a08a080e83b04ecdc68d97d91f3394933
6
+ metadata.gz: 22aebe3f7a81c4afd59e7d3e67cbc0b19263b56b5b135c6cad85f10fd5da2c4623231215fb4c9d83c8061c08db35b54c7fe31cf73fff9acc061dbea1c531baf2
7
+ data.tar.gz: 04547d510c8835ade0cfe1de2fe0a3287edc8fd0e83bd91a62f31d324daee8942fc6bf2a275d370f2f1561909072d26d7e34abd8d9bd13bbd4573708df720700
@@ -0,0 +1,8 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'colorize'
4
+ require 'pry'
5
+
6
+ require_relative '../lib/magic_tcg_finder/command_line_interface.rb'
7
+ require_relative '../lib/magic_tcg_finder/card.rb'
8
+ require_relative "../lib/magic_tcg_finder/scraper.rb"
@@ -0,0 +1,31 @@
1
+ class Card
2
+
3
+ attr_accessor :name, :rarity, :sets, :price, :rules_text, :flavor_text, :color, :cost, :purchase_url, :card_type, :combat_stats, :url
4
+
5
+ @@all = []
6
+
7
+ def initialize(attributes)
8
+ attributes.each {|attribute, value| self.send(("#{attribute}="), value)}
9
+ @@all << self
10
+ end
11
+
12
+ def self.all
13
+ @@all
14
+ end
15
+
16
+ def self.destroy_all
17
+ self.all.clear
18
+ end
19
+
20
+ def self.create_from_collection(card_arr)
21
+ card_arr.each do |card|
22
+ new_card = Card.new(card)
23
+ end
24
+ end
25
+
26
+ def add_card_attributes(attribute_hash)
27
+ attribute_hash.each {|attribute, value| self.send(("#{attribute}="), value)}
28
+ end
29
+
30
+ end
31
+
@@ -0,0 +1,187 @@
1
+ class CommandLine
2
+
3
+
4
+ def clear_screen
5
+ print %x{clear}
6
+ end
7
+
8
+ def start_screen
9
+ clear_screen
10
+ puts " _ _____ _ ___ _ _ _ ".colorize(:light_green)
11
+ puts " /\\/\\ __ _ __ _(_) ___ _ /__ \\ |__ ___ / _ \\__ _| |_| |__ ___ _ __(_)_ __ __ _ ".colorize(:light_green)
12
+ puts " / \\ / _` |/ _` | |/ __| (_) / /\\/ '_ \\ / _ \\ / /_\\/ _` | __| '_ \\ / _ \\ '__| | '_ \\ / _` |".colorize(:light_green)
13
+ puts "/ /\\/\\ \\ (_| | (_| | | (__ _ / / | | | | __/ / /_\\\\ (_| | |_| | | | __/ | | | | | | (_| |".colorize(:light_green)
14
+ puts "\\/ \\/\\__,_|\\__, |_|\\___| (_) \\/ |_| |_|\\___| \\____/\\__,_|\\__|_| |_|\\___|_| |_|_| |_|\\__, |".colorize(:light_green)
15
+ puts " |___/ |___/ ".colorize(:light_green)
16
+ puts " ___ _ ___ _ _ ".colorize(:light_green)
17
+ puts " / __\\__ _ _ __ __| | / __(_)_ __ __| | ___ _ __ ".colorize(:light_green)
18
+ puts " / / / _` | '__/ _` | / _\\ | | '_ \\ / _` |/ _ \\ '__| ".colorize(:light_green)
19
+ puts " / /__| (_| | | | (_| | / / | | | | | (_| | __/ | ".colorize(:light_green)
20
+ puts " \\____/\\__,_|_| \\__,_| \\/ |_|_| |_|\\__,_|\\___|_| ".colorize(:light_green)
21
+
22
+ puts ""
23
+
24
+ run
25
+ end
26
+
27
+ def get_query
28
+ puts "Please enter the name of a card you want to find"
29
+ gets.strip
30
+ end
31
+
32
+ def call_scraper(input)
33
+ new_search = Scraper.new(input)
34
+ new_search.scrape_search_page
35
+ end
36
+
37
+ def load_attributes(card)
38
+ card_hash = Scraper.scrape_card_page(card.url)
39
+ card.add_card_attributes(card_hash)
40
+ end
41
+
42
+ def create_cards(card_arr)
43
+ Card.create_from_collection(card_arr)
44
+ end
45
+
46
+ def list_cards
47
+ clear_screen
48
+ Card.all.each_with_index do |card, index|
49
+ puts "#{index + 1}.#{card.name}"
50
+ end
51
+ end
52
+
53
+ def access_list
54
+ max = Card.all.size
55
+ puts "Please make a selection"
56
+ input = gets.strip.to_i
57
+ if input < 0 || input > max
58
+ puts "Invalid selection"
59
+ card_menu
60
+ end
61
+ input
62
+ end
63
+
64
+ def colorize_cost(cost)
65
+ return cost if cost.nil?
66
+ cost = cost.gsub(/\{W\}/) { |match| match.colorize(:light_yellow) }
67
+ cost = cost.gsub(/\{U\}/) { |match| match.colorize(:light_cyan) }
68
+ cost = cost.gsub(/\{B\}/) { |match| match.colorize(:magenta) }
69
+ cost = cost.gsub(/\{R\}/) { |match| match.colorize(:red) }
70
+ cost = cost.gsub(/\{G\}/) { |match| match.colorize(:green) }
71
+ cost = cost.gsub(/\{T\}/) { |match| match.colorize(:light_black) }
72
+ cost = cost.gsub(/\{\d\}/) { |match| match.colorize(:light_black) }
73
+ end
74
+
75
+ def colorize_identity(card)
76
+ color = card.color
77
+
78
+ case color
79
+ when "White"
80
+ card.color.colorize(:light_yellow)
81
+ when "Blue"
82
+ card.color.colorize(:light_cyan)
83
+ when "Black"
84
+ card.color.colorize(:magenta)
85
+ when "Red"
86
+ card.color.colorize(:red)
87
+ when "Green"
88
+ card.color.colorize(:green)
89
+ when "Multicolor"
90
+ card.color.colorize(:yellow)
91
+ else
92
+ card.color.colorize(:light_black)
93
+ end
94
+ end
95
+
96
+ def load_card(input)
97
+ chosen_card = Card.all[input - 1]
98
+ load_attributes(chosen_card) if chosen_card.rules_text.nil?
99
+ puts "#{chosen_card.name} - #{colorize_cost(chosen_card.cost)}"
100
+ puts ""
101
+ puts "Color Identity: #{colorize_identity(chosen_card)}"
102
+ puts "Type: #{chosen_card.card_type}"
103
+ puts "Rarity: #{chosen_card.rarity}"
104
+ puts ""
105
+ puts "#{colorize_cost(chosen_card.rules_text)}"
106
+ puts "#{chosen_card.flavor_text}"
107
+ puts "#{chosen_card.combat_stats}" unless chosen_card.combat_stats.nil?
108
+ puts ""
109
+ puts "Appears in the following set(s): #{chosen_card.sets.join(', ')}"
110
+ puts ""
111
+ puts "Average price: $#{chosen_card.price}" unless chosen_card.price.nil?
112
+ puts "Purchase at #{chosen_card.purchase_url}"
113
+ puts ""
114
+ end
115
+
116
+ def card_menu
117
+ if Card.all.size == 1
118
+ clear_screen
119
+ load_card(1)
120
+ interaction
121
+ else
122
+ list_cards
123
+ input = access_list
124
+ clear_screen
125
+ load_card(input)
126
+ interaction
127
+ end
128
+
129
+ end
130
+
131
+ def interaction
132
+ puts "Please make a selection"
133
+ puts "1. Return to card list"
134
+ puts "2. New search"
135
+ puts "3. Exit"
136
+ input = gets.strip.downcase
137
+ case input
138
+ when "1"
139
+ card_menu
140
+ when "2"
141
+ clear_screen
142
+ run
143
+ when "3"
144
+ clear_screen
145
+ exit
146
+ else
147
+ puts "Invalid selection"
148
+ interaction
149
+ end
150
+
151
+ end
152
+
153
+ def try_again
154
+ puts ""
155
+ puts "Please make a selection:"
156
+ puts "1. Search for a new card"
157
+ puts "2. Exit this program"
158
+ input = gets.strip
159
+
160
+ case input
161
+ when "1"
162
+ clear_screen
163
+ run
164
+ when "2"
165
+ clear_screen
166
+ exit
167
+ else
168
+ "Please enter a valid selection"
169
+ try_again
170
+ end
171
+ end
172
+
173
+ def run
174
+ Card.destroy_all
175
+ query = get_query
176
+ clear_screen
177
+ card_arr = call_scraper(query)
178
+ if card_arr == []
179
+ try_again
180
+ end
181
+ create_cards(card_arr)
182
+ card_menu
183
+ interaction
184
+ end
185
+
186
+
187
+ end
@@ -0,0 +1,95 @@
1
+ class Scraper
2
+
3
+ SEARCH_URL = "https://scryfall.com/search?q="
4
+ SITE_URL = "https://scryfall.com"
5
+
6
+ attr_accessor :query
7
+
8
+ def initialize(query)
9
+ @query = query
10
+ end
11
+
12
+ def scrape_search_page(url = nil)
13
+ url = self.input_parser if url.nil?
14
+ begin
15
+ card_index = Nokogiri::HTML(open(url))
16
+ rescue
17
+ puts "No cards found"
18
+ return []
19
+ end
20
+
21
+ cards = card_index.css('a.card-grid-item')
22
+ if cards.empty?
23
+ [{name: 'placeholder', url: url}]
24
+ else
25
+ card_collection = []
26
+ cards.each do |card|
27
+ card_hash = {}
28
+ card_hash[:name] = card.css('img.card').attr('alt').text.gsub(/\s\(...\)/, "")
29
+ card_hash[:url] = SITE_URL + card['href']
30
+ card_collection << card_hash
31
+ end
32
+ if card_index.css("a.button-primary.js-paginate-forward").any?
33
+ #looks for more pages
34
+ new_url = SITE_URL + card_index.css("a.button-primary.js-paginate-forward").attr('href').text
35
+ card_collection << scrape_search_page(new_url)
36
+ #Recurses if it finds more pages
37
+ card_collection.flatten
38
+ else
39
+ card_collection
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ def input_parser
46
+ input = self.query.downcase.split.collect{|string|string.scan(/[a-z]/)}
47
+ input = input.collect {|arr|arr.join("")}.join('+')
48
+ SEARCH_URL + input
49
+ end
50
+
51
+ def self.color_finder(cost)
52
+ colors = {'{W}' =>'White','{U}' => 'Blue','{B}' => 'Black','{R}' => 'Red','{G}' => 'Green'}
53
+ matches = 0
54
+ color_identity = "Colorless"
55
+ #Not all cards have a casting cost
56
+ return color_identity if cost.nil?
57
+
58
+ colors.each do |symbol, value|
59
+ if cost.include?(symbol)
60
+ matches += 1
61
+ color_identity = value
62
+ end
63
+ end
64
+
65
+
66
+ if matches > 1
67
+ "Multicolor"
68
+ else
69
+ color_identity
70
+ end
71
+ end
72
+
73
+
74
+ def self.scrape_card_page(profile_url)
75
+ card_hash = {}
76
+ card_profile = Nokogiri::HTML(open(profile_url))
77
+ title_text = card_profile.css('h1.card-text-title').text.strip.gsub(/\n/, '||').split("||")
78
+ card_hash[:name] = title_text.first
79
+ #Not all cards have a casting cost, such as a land... .gsub on nil makes ruby sad.
80
+ card_hash[:cost] = title_text[1].gsub(/\s/,"") unless title_text[1] == nil
81
+ card_hash[:rarity] = card_profile.css('span.prints-current-set-details').text.strip.split(', ')[1]
82
+ card_hash[:sets] = card_profile.css('tbody tr').collect {|element|element.css('td').text.strip[/^.*(?=(\n))/]}.delete_if{|element|element.nil?}
83
+ card_hash[:price] = card_profile.css('span.price.currency-usd').text.split('$')[1]
84
+ card_hash[:color] = self.color_finder(card_hash[:cost])
85
+ card_hash[:purchase_url] = card_profile.css('#stores > ul > li:nth-child(1) > a').attr('href').text
86
+ card_hash[:card_type] = card_profile.css('p.card-text-type-line').text.strip
87
+ card_hash[:combat_stats] = card_profile.css('div.card-text-stats').text.strip
88
+ card_hash[:rules_text] = card_profile.css('div.card-text-oracle').text.strip
89
+ card_hash[:flavor_text] = card_profile.css('div.card-text-flavor').text.strip
90
+ card_hash.delete_if {|key, value| value == "" || value == nil}
91
+ card_hash
92
+ end
93
+
94
+ end
95
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magic_tcg_finder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandra Wright
@@ -104,6 +104,10 @@ extensions: []
104
104
  extra_rdoc_files: []
105
105
  files:
106
106
  - bin/magic_tcg_finder
107
+ - config/environment.rb
108
+ - lib/magic_tcg_finder/card.rb
109
+ - lib/magic_tcg_finder/command_line_interface.rb
110
+ - lib/magic_tcg_finder/scraper.rb
107
111
  homepage: https://github.com/f3mshep/magic_tcg_finder-cli-app
108
112
  licenses:
109
113
  - MIT
@@ -112,6 +116,7 @@ post_install_message:
112
116
  rdoc_options: []
113
117
  require_paths:
114
118
  - lib
119
+ - config
115
120
  required_ruby_version: !ruby/object:Gem::Requirement
116
121
  requirements:
117
122
  - - ">="
@@ -124,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
129
  version: '0'
125
130
  requirements: []
126
131
  rubyforge_project:
127
- rubygems_version: 2.4.8
132
+ rubygems_version: 2.6.11
128
133
  signing_key:
129
134
  specification_version: 4
130
135
  summary: 'Magic: The Gathering card finder'