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 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