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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cbe2f4df6b2093758c0f6a52a8f9aba968ba27ce
4
- data.tar.gz: f88fc1c1bb4cf23930c0c9461b8da1d89b027816
3
+ metadata.gz: bb686756ff30c067c2dde3c08f6367790c019e12
4
+ data.tar.gz: 240175bfe4d9bab525a44a601d9f0dcbb7296c4a
5
5
  SHA512:
6
- metadata.gz: a0509832f03d91c5ab0731b3c703be207118ee6df885aefe52ffd2971e9c8cf532eca60304b943df176e55be25b47d1be8d0974a020019d25a17c427beae88d6
7
- data.tar.gz: e771a347d9d859886625ac3b2b18e3204fc574ab8b2d6aa860295dd08cbdd1236fa6a65e47a16d92d5d43fc7cb339b208b1d796ad74a018ff46ec45377558d44
6
+ metadata.gz: b38d99aa163b0cd8f1bc7271b0aabcfab959dc8b640a47c3fe95ab699e8af9510f890ff7962d698d3a6e6d09b5c1047cd8d76295a41220cdb45e572b191c90a7
7
+ data.tar.gz: a6cb1073895bd9ba916c09100be60d6f74a051ac13204dfc3d5ac87cace28e2935141835295705c2871931c17d829b456a2bf69a2cb1f2de80ddb7129c262bee
@@ -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
- require_relative 'tamiyo/dummy_scrape_chain'
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
- require_relative 'tamiyo/gatherer_scrape_chain'
16
- Tamiyo::GathererScrapeChain.create(args.first || "Champions of Kamigawa").pump
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
@@ -1,4 +1,4 @@
1
- require_relative 'value'
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(self.text, new_text)
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
@@ -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
- require_relative 'dummy_scrape'
2
- require_relative 'scrape_parser'
3
- require_relative 'yaml_sink'
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, ScrapeParser.new, YamlSink.new
8
+ Process.chain DummyScrape.new,
9
+ ScrapeParser.new,
10
+ Yaml::YamlSink.new
9
11
  end
10
12
  end
11
13
  end
@@ -0,0 +1,11 @@
1
+ require 'tamiyo/yaml/yaml_source'
2
+ require 'tamiyo/cockatrice_db_sink'
3
+
4
+ module Tamiyo
5
+ class ExportAllChain
6
+ def self.create
7
+ Process.chain Yaml::YamlSource.new,
8
+ CockatriceDbSink.new
9
+ end
10
+ end
11
+ 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 = HTTPClient.new.get url
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};)/, '&amp;'
24
38
  end
@@ -1,11 +1,13 @@
1
- require_relative 'gatherer_scrape'
2
- require_relative 'scrape_parser'
3
- require_relative 'yaml_sink'
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), ScrapeParser.new, YamlSink.new
8
+ Process.chain GathererScrape.new(set),
9
+ ScrapeParser.new,
10
+ Yaml::YamlSink.new
9
11
  end
10
12
  end
11
13
  end
@@ -7,7 +7,10 @@ module Tamiyo
7
7
  end
8
8
 
9
9
  def self.chain(*nodes)
10
- nodes.inject {|p, n| n.affix p; n}
10
+ nodes.inject do |prev_link, next_link|
11
+ next_link.affix prev_link
12
+ next_link
13
+ end
11
14
  end
12
15
  end
13
16
  end
@@ -1,5 +1,5 @@
1
- require_relative 'process'
2
- require_relative 'card'
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 = card.with_left_split @cost, @text
69
+ card = if @name.start_with? part_name
70
+ card.with_left_split @cost, @text
66
71
  else
67
- card = card.with_right_split @cost, @text
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 = bottom_card_part_of @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 remember_top_bottom_link(top_name, bottom_name)
90
- @flip_card_links ||= {}
91
- @flip_card_links[top_name] = bottom_name
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 bottom_card_part_of(top_name)
95
- @flip_card_links ||= {}
96
- @flip_card_links[top_name]
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
- {'W' => ' is white.',
129
- 'U' => ' is blue.',
130
- 'B' => ' is black.',
131
- 'R' => ' is red.',
132
- 'G' => ' is green.'
133
- }.each_with_object [] do |(color, identity), colors|
134
- if @cost.include?(color) || @text.include?(@name + identity)
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
@@ -1,3 +1,3 @@
1
1
  module Tamiyo
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -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.2.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-16 00:00:00.000000000 Z
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:
@@ -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
@@ -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