tamiyo 0.2.0 → 0.3.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 +4 -4
- data/lib/tamiyo.rb +10 -3
- data/lib/tamiyo/card.rb +6 -2
- data/lib/tamiyo/cockatrice_db_sink.rb +81 -0
- data/lib/tamiyo/data_store.rb +165 -0
- data/lib/tamiyo/dummy_scrape.rb +192 -0
- data/lib/tamiyo/dummy_scrape_chain.rb +6 -4
- data/lib/tamiyo/export_all_chain.rb +11 -0
- data/lib/tamiyo/gatherer_scrape.rb +16 -2
- data/lib/tamiyo/gatherer_scrape_chain.rb +6 -4
- data/lib/tamiyo/process.rb +4 -1
- data/lib/tamiyo/scrape_parser.rb +66 -20
- data/lib/tamiyo/version.rb +1 -1
- data/lib/tamiyo/yaml/yaml_helper.rb +179 -0
- data/lib/tamiyo/yaml/yaml_sink.rb +49 -0
- data/lib/tamiyo/yaml/yaml_source.rb +83 -0
- metadata +8 -4
- data/lib/tamiyo/yaml_helper.rb +0 -70
- data/lib/tamiyo/yaml_sink.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb686756ff30c067c2dde3c08f6367790c019e12
|
4
|
+
data.tar.gz: 240175bfe4d9bab525a44a601d9f0dcbb7296c4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b38d99aa163b0cd8f1bc7271b0aabcfab959dc8b640a47c3fe95ab699e8af9510f890ff7962d698d3a6e6d09b5c1047cd8d76295a41220cdb45e572b191c90a7
|
7
|
+
data.tar.gz: a6cb1073895bd9ba916c09100be60d6f74a051ac13204dfc3d5ac87cace28e2935141835295705c2871931c17d829b456a2bf69a2cb1f2de80ddb7129c262bee
|
data/lib/tamiyo.rb
CHANGED
@@ -5,15 +5,22 @@ opts = Slop.new help: true do
|
|
5
5
|
|
6
6
|
command 'dummy-scrape' do
|
7
7
|
run do |opts, args|
|
8
|
-
|
8
|
+
require 'tamiyo/dummy_scrape_chain'
|
9
9
|
Tamiyo::DummyScrapeChain.create.pump
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
command 'gatherer-scrape' do
|
14
14
|
run do |opts, args|
|
15
|
-
|
16
|
-
Tamiyo::GathererScrapeChain.create(args.first || "
|
15
|
+
require 'tamiyo/gatherer_scrape_chain'
|
16
|
+
Tamiyo::GathererScrapeChain.create(args.first || "Innistrad").pump
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
command 'export-all' do
|
21
|
+
run do |opts, args|
|
22
|
+
require 'tamiyo/export_all_chain'
|
23
|
+
Tamiyo::ExportAllChain.create.pump
|
17
24
|
end
|
18
25
|
end
|
19
26
|
end
|
data/lib/tamiyo/card.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'tamiyo/value'
|
2
2
|
|
3
3
|
module Tamiyo
|
4
4
|
Card = Value.new(:name, :cost, :colors, :type, :text, :pt, :loyalty,
|
@@ -26,7 +26,7 @@ module Tamiyo
|
|
26
26
|
|
27
27
|
def with_flip_bottom(card)
|
28
28
|
new_text = [card.name, card.type, card.text, card.pt].compact.join "\n"
|
29
|
-
with_text merge_parts(
|
29
|
+
with_text merge_parts(text, new_text)
|
30
30
|
end
|
31
31
|
|
32
32
|
def with_right_split(right_cost, right_text)
|
@@ -39,6 +39,10 @@ module Tamiyo
|
|
39
39
|
card.with_text merge_split(left_text, text)
|
40
40
|
end
|
41
41
|
|
42
|
+
def with_transform_hint(back_name)
|
43
|
+
with_text [text, "[Transforms into #{back_name}]"].join "\n"
|
44
|
+
end
|
45
|
+
|
42
46
|
def merge_parts(left_text, right_text)
|
43
47
|
[left_text, right_text].join text_part_separator
|
44
48
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'Nokogiri'
|
2
|
+
require 'tamiyo/process'
|
3
|
+
require 'tamiyo/data_store'
|
4
|
+
|
5
|
+
module Tamiyo
|
6
|
+
class CockatriceDbSink
|
7
|
+
include Process::Node
|
8
|
+
include DataStore
|
9
|
+
|
10
|
+
def pump
|
11
|
+
content = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
12
|
+
xml.cockatrice_carddatabase(version: '2') {
|
13
|
+
add_sets_to xml
|
14
|
+
add_cards_to xml
|
15
|
+
}
|
16
|
+
end
|
17
|
+
store_xml content
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_sets_to(xml)
|
21
|
+
xml.sets {
|
22
|
+
default_set_data['sets'].each do |abbr, name|
|
23
|
+
xml.set {
|
24
|
+
xml.name abbr
|
25
|
+
xml.longname name
|
26
|
+
}
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_cards_to(xml)
|
32
|
+
xml.cards {
|
33
|
+
@chain.pull.each do |card|
|
34
|
+
xml.card {
|
35
|
+
xml.name card.name
|
36
|
+
# sets
|
37
|
+
card.colors.each { |color| xml.color color }
|
38
|
+
xml.manacost first_cost_of card
|
39
|
+
xml.type_ card.type
|
40
|
+
xml.pt card.pt if card.pt
|
41
|
+
xml.loyalty card.loyalty if card.loyalty
|
42
|
+
xml.tablerow row_of card
|
43
|
+
xml.text_ adjusted_text_of card
|
44
|
+
xml.cipt '1' if card.played_tapped
|
45
|
+
}
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def store_xml(content)
|
51
|
+
path = provide_path_for 'cards.xml'
|
52
|
+
File.open(path, 'w') do |file|
|
53
|
+
file.write content.to_xml
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def first_cost_of(card)
|
58
|
+
cost = card.cost
|
59
|
+
cost.is_a?(Array) ? cost.first : cost
|
60
|
+
end
|
61
|
+
|
62
|
+
def row_of(card)
|
63
|
+
case card.table_row
|
64
|
+
when :first; '0'
|
65
|
+
when :second; '1'
|
66
|
+
when :third; '2'
|
67
|
+
when :stack; '3'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def adjusted_text_of(card)
|
72
|
+
text = card.text
|
73
|
+
if card.cost.respond_to? :each
|
74
|
+
first, second = card.cost
|
75
|
+
text = "Mana cost: #{first}\n" << text
|
76
|
+
text = text.sub!(/---\n/) { |m| m << "Mana cost: #{second}\n" }
|
77
|
+
end
|
78
|
+
text
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Tamiyo
|
4
|
+
module DataStore
|
5
|
+
def provide_path_for(file_name)
|
6
|
+
data_dir = File.join Dir.home, '.tamiyo'
|
7
|
+
FileUtils.mkpath data_dir
|
8
|
+
File.join data_dir, file_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_set_data
|
12
|
+
{'sets' =>
|
13
|
+
{'PSG' => 'Promo set for Gatherer',
|
14
|
+
'LEA' => 'Limited Edition Alpha',
|
15
|
+
'LEB' => 'Limited Edition Beta',
|
16
|
+
'ARN' => 'Arabian Nights',
|
17
|
+
'2ED' => 'Unlimited Edition',
|
18
|
+
'ATQ' => 'Antiquities',
|
19
|
+
'3ED' => 'Revised Edition',
|
20
|
+
'LEG' => 'Legends',
|
21
|
+
'DRK' => 'The Dark',
|
22
|
+
'FEM' => 'Fallen Empires',
|
23
|
+
'4ED' => 'Fourth Edition',
|
24
|
+
'ICE' => 'Ice Age',
|
25
|
+
'CHR' => 'Chronicles',
|
26
|
+
'HML' => 'Homelands',
|
27
|
+
'ALL' => 'Alliances',
|
28
|
+
'MIR' => 'Mirage',
|
29
|
+
'VIS' => 'Visions',
|
30
|
+
'5ED' => 'Fifth Edition',
|
31
|
+
'WTH' => 'Weatherlight',
|
32
|
+
'POR' => 'Portal',
|
33
|
+
'VG' => 'Vanguard',
|
34
|
+
'TMP' => 'Tempest',
|
35
|
+
'STH' => 'Stronghold',
|
36
|
+
'EXO' => 'Exodus',
|
37
|
+
'P02' => 'Portal Second Age',
|
38
|
+
'UGL' => 'Unglued',
|
39
|
+
'USG' => 'Urza''s Saga',
|
40
|
+
'ULG' => 'Urza''s Legacy',
|
41
|
+
'6ED' => 'Classic Sixth Edition',
|
42
|
+
'UDS' => 'Urza''s Destiny',
|
43
|
+
'PTK' => 'Portal Three Kingdoms',
|
44
|
+
'S99' => 'Starter 1999',
|
45
|
+
'MMQ' => 'Mercadian Masques',
|
46
|
+
'BRB' => 'Battle Royale Box Set',
|
47
|
+
'NMS' => 'Nemesis',
|
48
|
+
'PCY' => 'Prophecy',
|
49
|
+
'S00' => 'Starter 2000',
|
50
|
+
'INV' => 'Invasion',
|
51
|
+
'BTD' => 'Beatdown Box Set',
|
52
|
+
'PLS' => 'Planeshift',
|
53
|
+
'7ED' => 'Seventh Edition',
|
54
|
+
'APC' => 'Apocalypse',
|
55
|
+
'ODY' => 'Odyssey',
|
56
|
+
'TOR' => 'Torment',
|
57
|
+
'JUD' => 'Judgment',
|
58
|
+
'ONS' => 'Onslaught',
|
59
|
+
'LGN' => 'Legions',
|
60
|
+
'SCG' => 'Scourge',
|
61
|
+
'8ED' => 'Eighth Edition',
|
62
|
+
'MRD' => 'Mirrodin',
|
63
|
+
'DST' => 'Darksteel',
|
64
|
+
'5DN' => 'Fifth Dawn',
|
65
|
+
'CHK' => 'Champions of Kamigawa',
|
66
|
+
'UNH' => 'Unhinged',
|
67
|
+
'BOK' => 'Betrayers of Kamigawa',
|
68
|
+
'SOK' => 'Saviors of Kamigawa',
|
69
|
+
'9ED' => 'Ninth Edition',
|
70
|
+
'RAV' => 'Ravnica: City of Guilds',
|
71
|
+
'GPT' => 'Guildpact',
|
72
|
+
'DIS' => 'Dissension',
|
73
|
+
'CSP' => 'Coldsnap',
|
74
|
+
'TSB' => 'Time Spiral "Timeshifted"',
|
75
|
+
'TSP' => 'Time Spiral',
|
76
|
+
'PLC' => 'Planar Chaos',
|
77
|
+
'FUT' => 'Future Sight',
|
78
|
+
'10E' => 'Tenth Edition',
|
79
|
+
'LRW' => 'Lorwyn',
|
80
|
+
'MED' => 'Masters Edition',
|
81
|
+
'EVG' => 'Duel Decks: Elves vs. Goblins',
|
82
|
+
'MOR' => 'Morningtide',
|
83
|
+
'SHM' => 'Shadowmoor',
|
84
|
+
'EVE' => 'Eventide',
|
85
|
+
'DRB' => 'From the Vault: Dragons',
|
86
|
+
'ME2' => 'Masters Edition II',
|
87
|
+
'ALA' => 'Shards of Alara',
|
88
|
+
'DD2' => 'Duel Decks: Jace vs. Chandra',
|
89
|
+
'CON' => 'Conflux',
|
90
|
+
'ARB' => 'Alara Reborn',
|
91
|
+
'DDC' => 'Duel Decks: Divine vs. Demonic',
|
92
|
+
'M10' => 'Magic 2010',
|
93
|
+
'V09' => 'From the Vault: Exiled',
|
94
|
+
'HOP' => 'Planechase',
|
95
|
+
'ME3' => 'Masters Edition III',
|
96
|
+
'ZEN' => 'Zendikar',
|
97
|
+
'DDD' => 'Duel Decks: Garruk vs. Liliana',
|
98
|
+
'PDS' => 'Premium Deck Series: Slivers',
|
99
|
+
'WWK' => 'Worldwake',
|
100
|
+
'DDE' => 'Duel Decks: Phyrexia vs. the Coalition',
|
101
|
+
'ROE' => 'Rise of the Eldrazi',
|
102
|
+
'ARC' => 'Archenemy',
|
103
|
+
'M11' => 'Magic 2011',
|
104
|
+
'V10' => 'From the Vault: Relics',
|
105
|
+
'DDF' => 'Duel Decks: Elspeth vs. Tezzeret',
|
106
|
+
'SOM' => 'Scars of Mirrodin',
|
107
|
+
'PFL' => 'Premium Deck Series: Fire and Lightning',
|
108
|
+
'ME4' => 'Masters Edition IV',
|
109
|
+
'MBS' => 'Mirrodin Besieged',
|
110
|
+
'DDG' => 'Duel Decks: Knights vs. Dragons',
|
111
|
+
'NPH' => 'New Phyrexia',
|
112
|
+
'CMD' => 'Magic: The Gathering-Commander',
|
113
|
+
'M12' => 'Magic 2012',
|
114
|
+
'DDH' => 'Duel Decks: Ajani vs. Nicol Bolas',
|
115
|
+
'V11' => 'From the Vault: Legends',
|
116
|
+
'ISD' => 'Innistrad',
|
117
|
+
'GRV' => 'Premium Deck Series: Graveborn',
|
118
|
+
'DKA' => 'Dark Ascension',
|
119
|
+
'DDI' => 'Duel Decks: Venser vs. Koth',
|
120
|
+
'AVR' => 'Avacyn Restored',
|
121
|
+
'PC2' => 'Planechase 2012 Edition',
|
122
|
+
'M13' => 'Magic 2013',
|
123
|
+
'V12' => 'From the Vault: Realms',
|
124
|
+
'DDJ' => 'Duel Decks: Izzet vs. Golgari',
|
125
|
+
'RTR' => 'Return to Ravnica',
|
126
|
+
'CMA' => 'Commander''s Arsenal',
|
127
|
+
'GTC' => 'Gatecrash',
|
128
|
+
'DDK' => 'Duel Decks: Sorin vs. Tibalt',
|
129
|
+
'DGM' => 'Dragon''s Maze',
|
130
|
+
'MMA' => 'Modern Masters',
|
131
|
+
'M14' => 'Magic 2014',
|
132
|
+
'V13' => 'From the Vault: Twenty',
|
133
|
+
'DDL' => 'Duel Decks: Heroes vs. Monsters',
|
134
|
+
'THS' => 'Theros',
|
135
|
+
'C13' => 'Commander 2013'},
|
136
|
+
'blocks' =>
|
137
|
+
{['ICE', 'Ice-Age'] => ['ICE', 'ALL', 'CSP'],
|
138
|
+
['MIR', 'Mirage'] => ['MIR', 'VIS', 'WTH'],
|
139
|
+
['TMP', 'Tempest', 'Rath'] => ['TMP', 'STH', 'EXO'],
|
140
|
+
['USG', 'Urza', 'Artifacts'] => ['USG', 'ULG', 'UDS'],
|
141
|
+
['MMQ', 'Masques', 'Masquerade'] => ['MMQ', 'NEM', 'PCY'],
|
142
|
+
['INV', 'Invasion'] => ['INV', 'PLS', 'APC'],
|
143
|
+
['ODY', 'Odyssey'] => ['ODY', 'TOR', 'JUD'],
|
144
|
+
['ONS', 'Onslaught'] => ['ONS', 'LGN', 'SCG'],
|
145
|
+
['MRD', 'Mirrodin'] => ['MRD', 'DST', '5DN'],
|
146
|
+
['CHK', 'Kamigawa'] => ['CHK', 'BOK', 'SOK'],
|
147
|
+
['RAV', 'Ravnica'] => ['RAV', 'GPT', 'DIS'],
|
148
|
+
['TSP', 'Time-Spiral'] => ['TSP', 'TSB', 'PLC', 'FUT'],
|
149
|
+
['LRW', 'Lorwyn'] => ['LRW', 'MOR'],
|
150
|
+
['SHM', 'Shadowmoor'] => ['SHM', 'EVE'],
|
151
|
+
['ALA', 'Alara'] => ['ALA', 'CON', 'ARB'],
|
152
|
+
['ZEN', 'Zendikar'] => ['ZEN', 'WWK', 'ROE'],
|
153
|
+
['SOM', 'Scars-of-Mirrodin'] => ['SOM', 'MBS', 'NPH'],
|
154
|
+
['ISD', 'Innistrad'] => ['ISD', 'DKA', 'AVR'],
|
155
|
+
['RTR', 'Return-to-Ravnica'] => ['RTR', 'GTC', 'DGM'],
|
156
|
+
['THS', 'Theros'] => ['THS']},
|
157
|
+
'formats' =>
|
158
|
+
{'Standard' => ['M14', 'RTR-block', 'THS-block'],
|
159
|
+
'Modern' => ['8ED', '9ED', '10E', 'M10', 'M11', 'M12', 'M13', 'MMA', 'CSP',
|
160
|
+
'MRD-block', 'CHK-block', 'RAV-block', 'TSP-block', 'LRW-block',
|
161
|
+
'SHM-block', 'ALA-block', 'ZEN-block', 'SOM-block', 'ISD-block', 'Standard']}
|
162
|
+
}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
data/lib/tamiyo/dummy_scrape.rb
CHANGED
@@ -288,9 +288,201 @@ If a red source would deal damage to a player, it deals that much damage plus 1
|
|
288
288
|
<td>Champions of Kamigawa Rare</td></tr>
|
289
289
|
<tr>
|
290
290
|
<td colspan="2"><br /></td></tr>
|
291
|
+
<!-- transform card, front side first-->
|
292
|
+
<tr>
|
293
|
+
<td>Name</td>
|
294
|
+
<td><a id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl36_cardLink" class="nameLink" onclick="return CardLinkAction(event, this, 'SameWindow');" href="../Card/Details.aspx?multiverseid=221209">Civilized Scholar</a></td></tr>
|
295
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl36_costRow">
|
296
|
+
<td>Cost:</td>
|
297
|
+
<td>2U</td></tr>
|
298
|
+
<tr>
|
299
|
+
<td>Type:</td>
|
300
|
+
<td>Creature — Human Advisor</td></tr>
|
301
|
+
<tr>
|
302
|
+
<td>Pow/Tgh:</td>
|
303
|
+
<td>(0/1)</td></tr>
|
304
|
+
<tr>
|
305
|
+
<td>Rules Text:</td>
|
306
|
+
<td>{T}: Draw a card, then discard a card. If a creature card is discarded this way, untap Civilized Scholar, then transform it.</td></tr>
|
307
|
+
<tr>
|
308
|
+
<td>Set/Rarity:</td>
|
309
|
+
<td>Innistrad Uncommon</td></tr>
|
310
|
+
<tr>
|
311
|
+
<td colspan="2"><br /></td></tr>
|
312
|
+
<tr>
|
313
|
+
<td>Name</td>
|
314
|
+
<td><a id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl117_cardLink" class="nameLink" onclick="return CardLinkAction(event, this, 'SameWindow');" href="../Card/Details.aspx?multiverseid=221185">Homicidal Brute</a></td></tr>
|
315
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl117_costRow">
|
316
|
+
<td>Cost:</td>
|
317
|
+
<td></td></tr>
|
318
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl117_colorIndicatorRow">
|
319
|
+
<td>Color:</td>
|
320
|
+
<td>Red</td></tr>
|
321
|
+
<tr>
|
322
|
+
<td>Type:</td>
|
323
|
+
<td>Creature — Human Mutant</td></tr>
|
324
|
+
<tr>
|
325
|
+
<td>Pow/Tgh:</td>
|
326
|
+
<td>(5/1)</td></tr>
|
327
|
+
<tr>
|
328
|
+
<td>Rules Text:</td>
|
329
|
+
<td>At the beginning of your end step, if Homicidal Brute didn't attack this turn, tap Homicidal Brute, then transform it.</td></tr>
|
330
|
+
<tr>
|
331
|
+
<td>Set/Rarity:</td>
|
332
|
+
<td>Innistrad Uncommon</td></tr>
|
333
|
+
<tr>
|
334
|
+
<td colspan="2"><br /></td></tr>
|
335
|
+
<!-- ' transform card, back side first-->
|
336
|
+
<tr>
|
337
|
+
<td>Name</td>
|
338
|
+
<td><a id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl14_cardLink" class="nameLink" onclick="return CardLinkAction(event, this, 'SameWindow');" href="../Card/Details.aspx?multiverseid=244687">Bane of Hanweir</a></td></tr>
|
339
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl14_costRow">
|
340
|
+
<td>Cost:</td>
|
341
|
+
<td></td></tr>
|
342
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl14_colorIndicatorRow">
|
343
|
+
<td>Color:</td>
|
344
|
+
<td>Red</td></tr>
|
345
|
+
<tr>
|
346
|
+
<td>Type:</td>
|
347
|
+
<td>Creature — Werewolf</td></tr>
|
348
|
+
<tr>
|
349
|
+
<td>Pow/Tgh:</td>
|
350
|
+
<td>(5/5)</td></tr>
|
351
|
+
<tr>
|
352
|
+
<td>Rules Text:</td>
|
353
|
+
<td>Bane of Hanweir attacks each turn if able.<br />
|
354
|
+
At the beginning of each upkeep, if a player cast two or more spells last turn, transform Bane of Hanweir.</td></tr>
|
355
|
+
<tr>
|
356
|
+
<td>Set/Rarity:</td>
|
357
|
+
<td>Innistrad Uncommon</td></tr>
|
358
|
+
<tr>
|
359
|
+
<td colspan="2"><br /></td></tr>
|
360
|
+
<tr>
|
361
|
+
<td>Name</td>
|
362
|
+
<td><a id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl111_cardLink" class="nameLink" onclick="return CardLinkAction(event, this, 'SameWindow');" href="../Card/Details.aspx?multiverseid=244683">Hanweir Watchkeep</a></td></tr>
|
363
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl111_costRow">
|
364
|
+
<td>Cost:</td>
|
365
|
+
<td>2R</td></tr>
|
366
|
+
<tr>
|
367
|
+
<td>Type:</td>
|
368
|
+
<td>Creature — Human Warrior Werewolf</td></tr>
|
369
|
+
<tr>
|
370
|
+
<td>Pow/Tgh:</td>
|
371
|
+
<td>(1/5)</td></tr>
|
372
|
+
<tr>
|
373
|
+
<td>Rules Text:</td>
|
374
|
+
<td>Defender<br />
|
375
|
+
At the beginning of each upkeep, if no spells were cast last turn, transform Hanweir Watchkeep.</td></tr>
|
376
|
+
<tr>
|
377
|
+
<td>Set/Rarity:</td>
|
378
|
+
<td>Innistrad Uncommon</td></tr>
|
379
|
+
<tr>
|
380
|
+
<td colspan="2"><br /></td></tr>
|
381
|
+
<!-- transform card, transform text only on front -->
|
382
|
+
<tr>
|
383
|
+
<td>Name</td>
|
384
|
+
<td><a id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl21_cardLink" class="nameLink" onclick="return CardLinkAction(event, this, 'SameWindow');" href="../Card/Details.aspx?multiverseid=227061">Bloodline Keeper</a></td></tr>
|
385
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl21_costRow">
|
386
|
+
<td>Cost:</td>
|
387
|
+
<td>2BB</td></tr>
|
388
|
+
<tr>
|
389
|
+
<td>Type:</td>
|
390
|
+
<td>Creature — Vampire</td></tr>
|
391
|
+
<tr>
|
392
|
+
<td>Pow/Tgh:</td>
|
393
|
+
<td>(3/3)</td></tr>
|
394
|
+
<tr>
|
395
|
+
<td>Rules Text:</td>
|
396
|
+
<td>Flying<br />
|
397
|
+
{T}: Put a 2/2 black Vampire creature token with flying onto the battlefield.<br />
|
398
|
+
{B}: Transform Bloodline Keeper. Activate this ability only if you control five or more Vampires.</td></tr>
|
399
|
+
<tr>
|
400
|
+
<td>Set/Rarity:</td>
|
401
|
+
<td>Innistrad Rare</td></tr>
|
402
|
+
<tr>
|
403
|
+
<td colspan="2"><br /></td></tr>
|
404
|
+
<tr>
|
405
|
+
<td>Name</td>
|
406
|
+
<td><a id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl140_cardLink" class="nameLink" onclick="return CardLinkAction(event, this, 'SameWindow');" href="../Card/Details.aspx?multiverseid=227072">Lord of Lineage</a></td></tr>
|
407
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl140_costRow">
|
408
|
+
<td>Cost:</td>
|
409
|
+
<td></td></tr>
|
410
|
+
<tr id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl00_cardEntries_ctl140_colorIndicatorRow">
|
411
|
+
<td>Color:</td>
|
412
|
+
<td>Black</td></tr>
|
413
|
+
<tr>
|
414
|
+
<td>Type:</td>
|
415
|
+
<td>Creature — Vampire</td></tr>
|
416
|
+
<tr>
|
417
|
+
<td>Pow/Tgh:</td>
|
418
|
+
<td>(5/5)</td></tr>
|
419
|
+
<tr>
|
420
|
+
<td>Rules Text:</td>
|
421
|
+
<td>Flying<br />
|
422
|
+
Other Vampire creatures you control get +2/+2.<br />
|
423
|
+
{T}: Put a 2/2 black Vampire creature token with flying onto the battlefield.</td></tr>
|
424
|
+
<tr>
|
425
|
+
<td>Set/Rarity:</td>
|
426
|
+
<td>Innistrad Rare</td></tr>
|
427
|
+
<tr>
|
428
|
+
<td colspan="2"><br /></td></tr>
|
291
429
|
</table>
|
292
430
|
</div>
|
293
431
|
TestXml
|
294
432
|
end
|
433
|
+
|
434
|
+
def xml_card_name_details(card_id)
|
435
|
+
html = case card_id.to_i
|
436
|
+
when 227061, 227072
|
437
|
+
Nokogiri::HTML <<BloodlineKeeper
|
438
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent0" class="cardComponentContainer">
|
439
|
+
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl07_nameRow" class="row">
|
440
|
+
<div class="value">Bloodline Keeper</div>
|
441
|
+
</div>
|
442
|
+
</td>
|
443
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent1" class="cardComponentContainer">
|
444
|
+
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl08_nameRow" class="row">
|
445
|
+
<div class="value">Lord of Lineage</div>
|
446
|
+
</div>
|
447
|
+
</td>
|
448
|
+
BloodlineKeeper
|
449
|
+
when 221209, 221185
|
450
|
+
Nokogiri::HTML <<CivilizedScholar
|
451
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent0" class="cardComponentContainer">
|
452
|
+
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl07_nameRow" class="row">
|
453
|
+
<div class="value">Civilized Scholar</div>
|
454
|
+
</div>
|
455
|
+
</td>
|
456
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent1" class="cardComponentContainer">
|
457
|
+
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl08_nameRow" class="row">
|
458
|
+
<div class="value">Homicidal Brute</div>
|
459
|
+
</div>
|
460
|
+
</td>
|
461
|
+
CivilizedScholar
|
462
|
+
when 244683, 244687
|
463
|
+
Nokogiri::HTML <<HanweirWatchkeep
|
464
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent0" class="cardComponentContainer">
|
465
|
+
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl07_nameRow" class="row">
|
466
|
+
<div class="value">Hanweir Watchkeep</div>
|
467
|
+
</div>
|
468
|
+
</td>
|
469
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent1" class="cardComponentContainer">
|
470
|
+
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_ctl08_nameRow" class="row">
|
471
|
+
<div class="value">Bane of Hanweir</div>
|
472
|
+
</div>
|
473
|
+
</td>
|
474
|
+
HanweirWatchkeep
|
475
|
+
else
|
476
|
+
Nokogiri::HTML <<SingleSide
|
477
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent0" class="cardComponentContainer">
|
478
|
+
<div id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_nameRow" class="row">
|
479
|
+
<div class="value">Example Name</div>
|
480
|
+
</div>
|
481
|
+
</td>
|
482
|
+
<td id="ctl00_ctl00_ctl00_MainContent_SubContent_SubContent_cardComponent1" class="cardComponentContainer"></td>
|
483
|
+
SingleSide
|
484
|
+
end
|
485
|
+
html.css('.cardComponentContainer').css('[id$="nameRow"]')
|
486
|
+
end
|
295
487
|
end
|
296
488
|
end
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'tamiyo/yaml/yaml_sink'
|
2
|
+
require 'tamiyo/dummy_scrape'
|
3
|
+
require 'tamiyo/scrape_parser'
|
4
4
|
|
5
5
|
module Tamiyo
|
6
6
|
class DummyScrapeChain
|
7
7
|
def self.create
|
8
|
-
Process.chain DummyScrape.new,
|
8
|
+
Process.chain DummyScrape.new,
|
9
|
+
ScrapeParser.new,
|
10
|
+
Yaml::YamlSink.new
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -5,20 +5,34 @@ module Tamiyo
|
|
5
5
|
class GathererScrape
|
6
6
|
def initialize(set_name)
|
7
7
|
@set_name = set_name
|
8
|
+
@client = HTTPClient.new
|
8
9
|
end
|
9
10
|
|
10
11
|
def xml_spoiler_rows
|
11
|
-
host = 'http://gatherer.wizards.com/'
|
12
12
|
path = 'Pages/Search/Default.aspx'
|
13
13
|
query = '?output=spoiler&method=text&action=advanced&set=["%s"]&special=true' % @set_name.tr(' ', '+')
|
14
14
|
url = URI.escape "#{host}#{path}#{query}"
|
15
|
-
response =
|
15
|
+
response = @client.get url
|
16
16
|
html = Nokogiri::HTML ampersand_fixed(response.body)
|
17
17
|
html.css 'div.textspoiler tr'
|
18
18
|
end
|
19
19
|
|
20
|
+
def xml_card_name_details(card_id)
|
21
|
+
path = 'Pages/Card/Details.aspx'
|
22
|
+
query = '?multiverseid=%s' % card_id
|
23
|
+
url = URI.escape "#{host}#{path}#{query}"
|
24
|
+
response = @client.get url
|
25
|
+
html = Nokogiri::HTML ampersand_fixed(response.body)
|
26
|
+
# must apply these selectors separately for some reason
|
27
|
+
html.css('.cardComponentContainer').css('[id$="nameRow"]')
|
28
|
+
end
|
29
|
+
|
20
30
|
private
|
21
31
|
|
32
|
+
def host
|
33
|
+
'http://gatherer.wizards.com/'
|
34
|
+
end
|
35
|
+
|
22
36
|
def ampersand_fixed(text)
|
23
37
|
text.gsub /&(?![^;]{,4};)/, '&'
|
24
38
|
end
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'tamiyo/yaml/yaml_sink'
|
2
|
+
require 'tamiyo/gatherer_scrape'
|
3
|
+
require 'tamiyo/scrape_parser'
|
4
4
|
|
5
5
|
module Tamiyo
|
6
6
|
class GathererScrapeChain
|
7
7
|
def self.create(set)
|
8
|
-
Process.chain GathererScrape.new(set),
|
8
|
+
Process.chain GathererScrape.new(set),
|
9
|
+
ScrapeParser.new,
|
10
|
+
Yaml::YamlSink.new
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
data/lib/tamiyo/process.rb
CHANGED
data/lib/tamiyo/scrape_parser.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'tamiyo/process'
|
2
|
+
require 'tamiyo/card'
|
3
3
|
|
4
4
|
module Tamiyo
|
5
5
|
class ScrapeParser
|
@@ -11,6 +11,7 @@ module Tamiyo
|
|
11
11
|
|
12
12
|
def parse_cards_from(xml)
|
13
13
|
@collection = {}
|
14
|
+
@linked_cards = {}
|
14
15
|
xml.each do |tr|
|
15
16
|
tds = tr.css 'td'
|
16
17
|
if tds.length == 2
|
@@ -23,6 +24,8 @@ module Tamiyo
|
|
23
24
|
@name = fold right_text
|
24
25
|
when 'Cost:'
|
25
26
|
@cost = fold right_text
|
27
|
+
when 'Color:'
|
28
|
+
@color = fold right_text
|
26
29
|
when 'Type:'
|
27
30
|
@type = fold right_text
|
28
31
|
when 'Pow/Tgh:'
|
@@ -36,7 +39,7 @@ module Tamiyo
|
|
36
39
|
else
|
37
40
|
card = parse_card
|
38
41
|
@collection[card.name] = card
|
39
|
-
@pt = @loyalty = nil
|
42
|
+
@color = @pt = @loyalty = nil
|
40
43
|
end
|
41
44
|
end
|
42
45
|
@collection.values
|
@@ -56,15 +59,17 @@ module Tamiyo
|
|
56
59
|
end
|
57
60
|
elsif flip_card
|
58
61
|
adjust_for_bottom_flip_card
|
62
|
+
elsif transform_in_card_text
|
63
|
+
adjust_for_transform_card
|
59
64
|
end
|
60
65
|
adjusted_card || new_card
|
61
66
|
end
|
62
67
|
|
63
68
|
def adjust_for_split_card(card, part_name)
|
64
|
-
if @name.start_with? part_name
|
65
|
-
card
|
69
|
+
card = if @name.start_with? part_name
|
70
|
+
card.with_left_split @cost, @text
|
66
71
|
else
|
67
|
-
card
|
72
|
+
card.with_right_split @cost, @text
|
68
73
|
end
|
69
74
|
card.with_extra_colors colors
|
70
75
|
end
|
@@ -79,21 +84,51 @@ module Tamiyo
|
|
79
84
|
end
|
80
85
|
|
81
86
|
def adjust_for_bottom_flip_card
|
82
|
-
bottom_card_name =
|
87
|
+
bottom_card_name = bottom_card_of @name
|
83
88
|
if bottom_card_name
|
84
89
|
bottom_card = @collection.delete bottom_card_name
|
85
90
|
new_card.with_flip_bottom bottom_card
|
86
91
|
end
|
87
92
|
end
|
88
93
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
94
|
+
def adjust_for_transform_card
|
95
|
+
back_name = fetch_back_card_of @name
|
96
|
+
new_card.with_transform_hint back_name if back_name
|
92
97
|
end
|
93
98
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
99
|
+
def fetch_back_card_of(card_name)
|
100
|
+
unless remembers_front_back_link card_name
|
101
|
+
parts = pull_card_details
|
102
|
+
return false if parts == :single
|
103
|
+
front_name, back_name = parts
|
104
|
+
remember_front_back_link front_name, back_name
|
105
|
+
remember_front_back_link back_name, false
|
106
|
+
end
|
107
|
+
back_card_of card_name
|
108
|
+
end
|
109
|
+
|
110
|
+
def pull_card_details
|
111
|
+
xml = @chain.xml_card_name_details @id
|
112
|
+
return :single if xml.one?
|
113
|
+
xml.map do |name_row|
|
114
|
+
beautify fold name_row.at_css('.value').content
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def remember_top_bottom_link(first, second)
|
119
|
+
@linked_cards.store first, second
|
120
|
+
end
|
121
|
+
|
122
|
+
alias :remember_front_back_link :remember_top_bottom_link
|
123
|
+
|
124
|
+
def bottom_card_of(first)
|
125
|
+
@linked_cards[first]
|
126
|
+
end
|
127
|
+
|
128
|
+
alias :back_card_of :bottom_card_of
|
129
|
+
|
130
|
+
def remembers_front_back_link(first)
|
131
|
+
@linked_cards.include? first
|
97
132
|
end
|
98
133
|
|
99
134
|
def new_card
|
@@ -124,14 +159,21 @@ module Tamiyo
|
|
124
159
|
@text[match_flip_text]
|
125
160
|
end
|
126
161
|
|
162
|
+
def transform_in_card_text
|
163
|
+
@text[match_transform_text]
|
164
|
+
end
|
165
|
+
|
127
166
|
def colors
|
128
|
-
|
129
|
-
|
130
|
-
'
|
131
|
-
'
|
132
|
-
'
|
133
|
-
|
134
|
-
|
167
|
+
@color ||= ''
|
168
|
+
{'W' => [' is white.', 'White'],
|
169
|
+
'U' => [' is blue.', 'Blue'],
|
170
|
+
'B' => [' is black.', 'Black'],
|
171
|
+
'R' => [' is red.', 'Red'],
|
172
|
+
'G' => [' is green.', 'Green']
|
173
|
+
}.each_with_object [] do |(color, (text, identity)), colors|
|
174
|
+
if @cost.include?(color) ||
|
175
|
+
@text.include?(@name + text) ||
|
176
|
+
@color.include?(identity)
|
135
177
|
colors << color
|
136
178
|
end
|
137
179
|
end
|
@@ -183,5 +225,9 @@ module Tamiyo
|
|
183
225
|
def match_flip_text
|
184
226
|
%r{flip (it|#{@name}).|flipped.}
|
185
227
|
end
|
228
|
+
|
229
|
+
def match_transform_text
|
230
|
+
/transform/i
|
231
|
+
end
|
186
232
|
end
|
187
233
|
end
|
data/lib/tamiyo/version.rb
CHANGED
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Tamiyo
|
4
|
+
module YamlHelper
|
5
|
+
def setup_yaml_emitter_for(file)
|
6
|
+
@emit = YAML::Emitter.new file
|
7
|
+
end
|
8
|
+
|
9
|
+
def emit_start_of_one_document
|
10
|
+
@emit.start_stream Psych::Nodes::Stream::UTF8
|
11
|
+
@emit.start_document [1, 1], [], true
|
12
|
+
end
|
13
|
+
|
14
|
+
def emit_end_of_one_document
|
15
|
+
@emit.end_document true
|
16
|
+
@emit.end_stream
|
17
|
+
end
|
18
|
+
|
19
|
+
def emit_pair(key, value)
|
20
|
+
emit_plain key
|
21
|
+
emit_plain value
|
22
|
+
end
|
23
|
+
|
24
|
+
def emit_pair_with_literal_value(key, value)
|
25
|
+
emit_plain key
|
26
|
+
emit_literal value
|
27
|
+
end
|
28
|
+
|
29
|
+
def emit_pair_with_optional_sequence_value(key, value)
|
30
|
+
if value.kind_of? Array
|
31
|
+
emit_pair_with_sequence_value key, value
|
32
|
+
else
|
33
|
+
emit_pair key, value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def emit_pair_with_sequence_value(key, value)
|
38
|
+
emit_plain key
|
39
|
+
emit_flow_sequence do
|
40
|
+
value.each { |element| emit_plain element }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def emit_block_sequence
|
45
|
+
@emit.start_sequence nil, nil, true, YAML::Nodes::Sequence::BLOCK
|
46
|
+
yield
|
47
|
+
@emit.end_sequence
|
48
|
+
end
|
49
|
+
|
50
|
+
def emit_flow_sequence
|
51
|
+
@emit.start_sequence nil, nil, true, YAML::Nodes::Sequence::FLOW
|
52
|
+
yield
|
53
|
+
@emit.end_sequence
|
54
|
+
end
|
55
|
+
|
56
|
+
def emit_block_mapping
|
57
|
+
@emit.start_mapping nil, nil, true, YAML::Nodes::Mapping::BLOCK
|
58
|
+
yield
|
59
|
+
@emit.end_mapping
|
60
|
+
end
|
61
|
+
|
62
|
+
def emit_plain(value)
|
63
|
+
@emit.scalar value, nil, nil, true, false, Psych::Nodes::Scalar::PLAIN
|
64
|
+
end
|
65
|
+
|
66
|
+
def emit_literal(value)
|
67
|
+
@emit.scalar value, nil, nil, false, true, YAML::Nodes::Scalar::LITERAL
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module YamlHelper
|
72
|
+
def yaml_event_stream_for(file)
|
73
|
+
queue = Queue.new
|
74
|
+
Thread.new do
|
75
|
+
handler = EventHandler.new queue
|
76
|
+
YAML::Parser.new(handler).parse file
|
77
|
+
end
|
78
|
+
EventStream.new queue
|
79
|
+
end
|
80
|
+
|
81
|
+
class EventStream
|
82
|
+
attr_reader :type
|
83
|
+
attr_reader :value
|
84
|
+
|
85
|
+
def initialize(queue)
|
86
|
+
@queue = queue
|
87
|
+
end
|
88
|
+
|
89
|
+
def each_within_sequence
|
90
|
+
assume_sequence
|
91
|
+
until peak_next_is_end
|
92
|
+
yield
|
93
|
+
end
|
94
|
+
assume_end
|
95
|
+
end
|
96
|
+
|
97
|
+
def each_within_mapping
|
98
|
+
assume_mapping
|
99
|
+
until peak_next_is_end
|
100
|
+
yield
|
101
|
+
end
|
102
|
+
assume_end
|
103
|
+
end
|
104
|
+
|
105
|
+
def on_types(cases)
|
106
|
+
type, _ = peak
|
107
|
+
raise StopIteration, "No case for type #{type} available" unless cases.include? type
|
108
|
+
self.next if type == :scalar
|
109
|
+
cases[type][]
|
110
|
+
end
|
111
|
+
|
112
|
+
def on_keys(cases)
|
113
|
+
value = assume_scalar
|
114
|
+
raise StopIteration, "No case for key #{value} available" unless cases.include? value
|
115
|
+
cases[value][]
|
116
|
+
end
|
117
|
+
|
118
|
+
def assume_scalar
|
119
|
+
self.next
|
120
|
+
raise StopIteration, "Assumed scalar but found #{@type}" unless @type == :scalar
|
121
|
+
@value
|
122
|
+
end
|
123
|
+
|
124
|
+
def assume_sequence
|
125
|
+
self.next
|
126
|
+
raise StopIteration, "Assumed seq but found #{@type}" unless @type == :seq
|
127
|
+
end
|
128
|
+
|
129
|
+
def assume_mapping
|
130
|
+
self.next
|
131
|
+
raise StopIteration, "Assumed map but found #{@type}" unless @type == :map
|
132
|
+
end
|
133
|
+
|
134
|
+
def assume_end
|
135
|
+
self.next
|
136
|
+
raise StopIteration, "Assumed end but found #{@type}" unless @type == :end
|
137
|
+
end
|
138
|
+
|
139
|
+
def peak_next_is_end
|
140
|
+
type, _ = peak
|
141
|
+
type == :end
|
142
|
+
end
|
143
|
+
|
144
|
+
def next
|
145
|
+
event = @peak || @queue.pop
|
146
|
+
@peak = nil
|
147
|
+
@type, @value = event
|
148
|
+
event
|
149
|
+
end
|
150
|
+
|
151
|
+
def peak
|
152
|
+
@peak ||= @queue.pop
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class EventHandler < YAML::Handler
|
157
|
+
def initialize(queue)
|
158
|
+
@queue = queue
|
159
|
+
end
|
160
|
+
|
161
|
+
def scalar(value, anchor, tag, plain, quoted, style)
|
162
|
+
@queue << [:scalar, value]
|
163
|
+
end
|
164
|
+
|
165
|
+
def start_sequence(anchor, tag, implicit, style)
|
166
|
+
@queue << [:seq]
|
167
|
+
end
|
168
|
+
|
169
|
+
def start_mapping(anchor, tag, implicit, style)
|
170
|
+
@queue << [:map]
|
171
|
+
end
|
172
|
+
|
173
|
+
def end_sequence
|
174
|
+
@queue << [:end]
|
175
|
+
end
|
176
|
+
alias :end_mapping :end_sequence
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'tamiyo/process'
|
2
|
+
require 'tamiyo/data_store'
|
3
|
+
require_relative 'yaml_helper'
|
4
|
+
|
5
|
+
module Tamiyo
|
6
|
+
module Yaml
|
7
|
+
class YamlSink
|
8
|
+
include Process::Node
|
9
|
+
include DataStore
|
10
|
+
include YamlHelper
|
11
|
+
|
12
|
+
def pump
|
13
|
+
with_the_cards_file do
|
14
|
+
emit_block_sequence do
|
15
|
+
@chain.pull.each do |card|
|
16
|
+
emit_block_mapping do
|
17
|
+
emit_pair 'name', card.name
|
18
|
+
emit_pair_with_sequence_value 'identity', card.colors unless card.colors.empty?
|
19
|
+
emit_pair_with_optional_sequence_value 'mana cost', card.cost
|
20
|
+
emit_pair 'type', card.type
|
21
|
+
emit_pair_with_literal_value 'text', card.text
|
22
|
+
emit_pair 'pt', card.pt if card.pt
|
23
|
+
emit_pair 'loyalty', card.loyalty if card.loyalty
|
24
|
+
emit_pair 'played tapped', 'true' if card.played_tapped
|
25
|
+
emit_pair 'row', card.table_row.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_the_cards_file(&block)
|
33
|
+
file_name = provide_path_for 'cards.yaml'
|
34
|
+
if block_given?
|
35
|
+
File.open(file_name, 'w') do |file|
|
36
|
+
within_a_yaml_document_of file, &block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def within_a_yaml_document_of(file)
|
42
|
+
setup_yaml_emitter_for file
|
43
|
+
emit_start_of_one_document
|
44
|
+
yield
|
45
|
+
emit_end_of_one_document
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'tamiyo/process'
|
2
|
+
require 'tamiyo/data_store'
|
3
|
+
require 'tamiyo/card'
|
4
|
+
require_relative 'yaml_helper'
|
5
|
+
|
6
|
+
module Tamiyo
|
7
|
+
module Yaml
|
8
|
+
class YamlSource
|
9
|
+
include Process::Node
|
10
|
+
include YamlHelper
|
11
|
+
include DataStore
|
12
|
+
|
13
|
+
def pull
|
14
|
+
using_object [] do |cards|
|
15
|
+
with_the_cards_file do |events|
|
16
|
+
events.each_within_sequence do
|
17
|
+
proto = using_object(Prototype.new) do |proto|
|
18
|
+
events.each_within_mapping do
|
19
|
+
parse_card_data_from(events, proto)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
cards << proto.build_card
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_card_data_from(events, proto)
|
29
|
+
events.on_keys(
|
30
|
+
'name' => ->{ proto.name = events.assume_scalar },
|
31
|
+
'identity' => ->{
|
32
|
+
events.each_within_sequence do
|
33
|
+
proto.colors << events.assume_scalar
|
34
|
+
end },
|
35
|
+
'mana cost' => ->{
|
36
|
+
events.on_types(
|
37
|
+
scalar: ->{ proto.cost = events.value },
|
38
|
+
seq: ->{
|
39
|
+
events.each_within_sequence do
|
40
|
+
proto.cost ||= []
|
41
|
+
proto.cost << events.assume_scalar
|
42
|
+
end }) },
|
43
|
+
'type' => ->{ proto.type = events.assume_scalar },
|
44
|
+
'text' => ->{ proto.text = events.assume_scalar },
|
45
|
+
'pt' => ->{ proto.pt = events.assume_scalar },
|
46
|
+
'loyalty' => ->{ proto.loyalty = events.assume_scalar },
|
47
|
+
'row' => ->{ proto.table_row = events.assume_scalar.to_sym },
|
48
|
+
'played tapped' => ->{
|
49
|
+
events.assume_scalar
|
50
|
+
proto.played_tapped = true },
|
51
|
+
'picture url' => ->{ proto.picture_url = events.assume_scalar })
|
52
|
+
end
|
53
|
+
|
54
|
+
def with_the_cards_file
|
55
|
+
path = provide_path_for 'cards.yaml'
|
56
|
+
if block_given?
|
57
|
+
File.open(path, 'r') do |file|
|
58
|
+
yield yaml_event_stream_for file
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def using_object(obj)
|
64
|
+
yield obj
|
65
|
+
obj
|
66
|
+
end
|
67
|
+
|
68
|
+
Prototype = Struct.new(:name, :cost, :colors, :type, :text, :pt, :loyalty,
|
69
|
+
:table_row, :played_tapped, :picture_url) do
|
70
|
+
def initialize
|
71
|
+
self.colors = []
|
72
|
+
self.played_tapped = false
|
73
|
+
self.picture_url = ''
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_card
|
77
|
+
Card.new name, cost, colors, type, text, pt, loyalty,
|
78
|
+
table_row, played_tapped, picture_url
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tamiyo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roger Norling
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -55,16 +55,20 @@ files:
|
|
55
55
|
- bin/tamiyo
|
56
56
|
- lib/tamiyo.rb
|
57
57
|
- lib/tamiyo/card.rb
|
58
|
+
- lib/tamiyo/cockatrice_db_sink.rb
|
59
|
+
- lib/tamiyo/data_store.rb
|
58
60
|
- lib/tamiyo/dummy_scrape.rb
|
59
61
|
- lib/tamiyo/dummy_scrape_chain.rb
|
62
|
+
- lib/tamiyo/export_all_chain.rb
|
60
63
|
- lib/tamiyo/gatherer_scrape.rb
|
61
64
|
- lib/tamiyo/gatherer_scrape_chain.rb
|
62
65
|
- lib/tamiyo/process.rb
|
63
66
|
- lib/tamiyo/scrape_parser.rb
|
64
67
|
- lib/tamiyo/value.rb
|
65
68
|
- lib/tamiyo/version.rb
|
66
|
-
- lib/tamiyo/yaml_helper.rb
|
67
|
-
- lib/tamiyo/yaml_sink.rb
|
69
|
+
- lib/tamiyo/yaml/yaml_helper.rb
|
70
|
+
- lib/tamiyo/yaml/yaml_sink.rb
|
71
|
+
- lib/tamiyo/yaml/yaml_source.rb
|
68
72
|
- tamiyo.gemspec
|
69
73
|
homepage: https://github.com/rogernorling/tamiyo#readme
|
70
74
|
licenses:
|
data/lib/tamiyo/yaml_helper.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module Tamiyo
|
4
|
-
module YamlHelper
|
5
|
-
def setup_yaml_emitter_for(file)
|
6
|
-
@emit = YAML::Emitter.new file
|
7
|
-
end
|
8
|
-
|
9
|
-
def emit_start_of_one_document
|
10
|
-
@emit.start_stream Psych::Nodes::Stream::UTF8
|
11
|
-
@emit.start_document [1, 1], [], true
|
12
|
-
end
|
13
|
-
|
14
|
-
def emit_end_of_one_document
|
15
|
-
@emit.end_document true
|
16
|
-
@emit.end_stream
|
17
|
-
end
|
18
|
-
|
19
|
-
def emit_pair(key, value)
|
20
|
-
emit_plain key
|
21
|
-
emit_plain value
|
22
|
-
end
|
23
|
-
|
24
|
-
def emit_pair_with_literal_value(key, value)
|
25
|
-
emit_plain key
|
26
|
-
emit_literal value
|
27
|
-
end
|
28
|
-
|
29
|
-
def emit_pair_with_optional_sequence_value(key, value)
|
30
|
-
if value.kind_of? Array
|
31
|
-
emit_pair_with_sequence_value key, value
|
32
|
-
else
|
33
|
-
emit_pair key, value
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def emit_pair_with_sequence_value(key, value)
|
38
|
-
emit_plain key
|
39
|
-
emit_flow_sequence do
|
40
|
-
value.each {|element| emit_plain element}
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def emit_block_sequence
|
45
|
-
@emit.start_sequence nil, nil, true, YAML::Nodes::Sequence::BLOCK
|
46
|
-
yield
|
47
|
-
@emit.end_sequence
|
48
|
-
end
|
49
|
-
|
50
|
-
def emit_flow_sequence
|
51
|
-
@emit.start_sequence nil, nil, true, YAML::Nodes::Sequence::FLOW
|
52
|
-
yield
|
53
|
-
@emit.end_sequence
|
54
|
-
end
|
55
|
-
|
56
|
-
def emit_block_mapping
|
57
|
-
@emit.start_mapping nil, nil, true, YAML::Nodes::Mapping::BLOCK
|
58
|
-
yield
|
59
|
-
@emit.end_mapping
|
60
|
-
end
|
61
|
-
|
62
|
-
def emit_plain(value)
|
63
|
-
@emit.scalar value, nil, nil, true, false, Psych::Nodes::Scalar::PLAIN
|
64
|
-
end
|
65
|
-
|
66
|
-
def emit_literal(value)
|
67
|
-
@emit.scalar value, nil, nil, false, true, YAML::Nodes::Scalar::LITERAL
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
data/lib/tamiyo/yaml_sink.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require_relative 'process'
|
3
|
-
require_relative 'yaml_helper'
|
4
|
-
|
5
|
-
module Tamiyo
|
6
|
-
class YamlSink
|
7
|
-
include Process::Node
|
8
|
-
include YamlHelper
|
9
|
-
|
10
|
-
def pump
|
11
|
-
with_the_cards_file do
|
12
|
-
emit_block_sequence do
|
13
|
-
@chain.pull.each do |card|
|
14
|
-
emit_block_mapping do
|
15
|
-
emit_pair 'name', card.name
|
16
|
-
emit_pair_with_sequence_value 'identity', card.colors unless card.colors.empty?
|
17
|
-
emit_pair_with_optional_sequence_value 'mana cost', card.cost
|
18
|
-
emit_pair 'type', card.type
|
19
|
-
emit_pair_with_literal_value 'text', card.text
|
20
|
-
emit_pair 'pt', card.pt if card.pt
|
21
|
-
emit_pair 'loyalty', card.loyalty if card.loyalty
|
22
|
-
emit_pair 'played tapped', 'true' if card.played_tapped
|
23
|
-
emit_pair 'row', card.table_row.to_s
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def with_the_cards_file(&block)
|
31
|
-
file_name = prepare_for_card_file
|
32
|
-
if block_given?
|
33
|
-
File.open(file_name, 'w') do |file|
|
34
|
-
within_a_yaml_document_of file, &block
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def prepare_for_card_file
|
40
|
-
data_dir = File.join Dir.home, '.tamiyo'
|
41
|
-
FileUtils.mkpath data_dir
|
42
|
-
File.join data_dir, 'cards.yaml'
|
43
|
-
end
|
44
|
-
|
45
|
-
def within_a_yaml_document_of(file)
|
46
|
-
setup_yaml_emitter_for file
|
47
|
-
emit_start_of_one_document
|
48
|
-
yield
|
49
|
-
emit_end_of_one_document
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|