tamiyo 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|