cardlike 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -69,7 +69,8 @@ to define your whole game in a `Cardlike.game` block.
69
69
  end
70
70
  end
71
71
 
72
- You can also prefix the class methods with Cardlike.
72
+ You can also prefix the class methods with Cardlike and pass card, deck, and
73
+ hand objects around yourself.
73
74
 
74
75
  Cardlike.type_of_card :playing_card do
75
76
  has :suit
@@ -88,7 +89,8 @@ You can also prefix the class methods with Cardlike.
88
89
  ### Creating Cards
89
90
 
90
91
  The `card` method can be used to create a new Card object. Created cards are
91
- stored globally and can be accessed with `the_card` and the card's name.
92
+ stored globally and can be accessed with `the_card` and the card's name (unless
93
+ they were created directly in a Deck).
92
94
 
93
95
  Cardlike.card "Draw one Play one" # => creates (and returns) a new Card object
94
96
  Cardlike.the_card "Draw one Play one" # => the Card object created above (NOT a copy)
@@ -100,23 +102,37 @@ to do this.
100
102
  Cardlike.type_of_card :action_card do
101
103
  has :power_level
102
104
  has :color
105
+ has :speed
106
+ has_block :activate
103
107
  end
104
108
 
105
109
  Cardlike.new_action_card "Magic Spell" do
106
110
  power_level 5
107
111
  color :red
112
+ speed :fast
113
+ activate { "zzzzZZZZAP!!" }
108
114
  end # => new Card object (actually a new ActionCard object)
109
115
 
110
116
  Cardlike.the_card("Magic Spell")[:color] # => :red
111
117
  Cardlike.the_card("Magic Spell")[:power_level] # => 5
118
+ Cardlike.the_card("Magic Spell").speed # => :fast (this style available after 0.0.2)
119
+ Cardlike.the_card("Magic Spell").activate.call # => "zzzzZZZZAP!!" (this style available after 0.0.2)
112
120
 
113
121
  The `type_of_card` method creates a new subclass of Card. Use the `has` method in
114
122
  a `card` block to add a property. A new card creation method is added to the DSL
115
123
  with the type of card prefixed by `new_`.
116
124
 
125
+ A `has_block` method takes a block and stores it as a property on the Card.
126
+
117
127
  To assign a property to a new card in the card block, use a method of the same
118
128
  name as the property. To retrieve that property, treat the card as a hash and
119
- reference the property name as the key.
129
+ reference the property name as the key. As of version 0.0.2, you can also get
130
+ the property value by calling a getter method of the same name as the key.
131
+
132
+ If you'd like to know what kind of card you're dealing with, just ask it with
133
+ `card_type`.
134
+
135
+ Cardlike.the_card("Magic Spell").card_type # => :action_card
120
136
 
121
137
  ### Creating Decks
122
138
 
@@ -213,6 +229,16 @@ Hands can be accessed by `the_hand`, just like the other Cardlike objects.
213
229
  the_hand("Player 1").size # => 1
214
230
  end
215
231
 
232
+ A Hand also has a few tricks up its sleve:
233
+
234
+ Cardlike.game do
235
+ the_hand("Player 1").remove_card_at(1) # Removes and returns the card at index 1 (0-based index)
236
+
237
+ the_hand("Player 1").remove_random_card # Removes and returns a random card from the hand.
238
+
239
+ the_hand("Player 1").remove_random_card { |card| card.name =~ /^Magic/ } # Removes and returns a random card from the cards in the hand for which the block returns true.
240
+ end
241
+
216
242
  ### Defining a Turn
217
243
 
218
244
  As most games have turns, you can define a block of code as a turn using the
data/lib/cardlike.rb CHANGED
@@ -97,9 +97,7 @@ module Cardlike
97
97
  # the Card. Returns the Card (that can also be accessed with +the_card+). You
98
98
  # may use the Card DSL in the block.
99
99
  #
100
- # Cardlike.card "Fire Monster" do
101
- # text "A red-hot monster."
102
- # end
100
+ # Cardlike.card "Fire Monster"
103
101
  #
104
102
  def self.card(name, &block)
105
103
  c = Card.create(name, &block)
@@ -145,8 +143,8 @@ module Cardlike
145
143
  c = Object.const_get(klass_name)
146
144
  c.class_eval(&block) if block_given?
147
145
 
148
- Deck.send(:define_method, "new_#{name_underscored}", lambda { |arg, &blk| card = c.create(arg, &blk); self << card; card })
149
- self.class.send(:define_method, "new_#{name_underscored}", lambda { |arg, &blk| card = c.create(arg, &blk); @cards ||= {}; @cards[arg] = card; card })
146
+ Deck.send(:define_method, "new_#{name_underscored}", lambda { |arg, &blk| card = c.create(arg, &blk); card.card_type = name_underscored.to_sym; self << card; card })
147
+ self.class.send(:define_method, "new_#{name_underscored}", lambda { |arg, &blk| card = c.create(arg, &blk); card.card_type = name_underscored.to_sym; @cards ||= {}; @cards[arg] = card; card })
150
148
 
151
149
  c
152
150
  end
data/lib/cardlike/card.rb CHANGED
@@ -2,20 +2,26 @@
2
2
  # Represents a game card. Best used with the Card and Deck DSL. See Cardlike.
3
3
  #
4
4
  class Cardlike::Card
5
- attr_accessor :name, :text
5
+ attr_accessor :name
6
+
7
+ attr_reader :card_type
6
8
 
7
9
  #
8
10
  # Create an instance of a Card. Arguments are a hash that should include
9
- # +:name+ at a minimum. Optionally all cards have a +text+ accessor that can
10
- # be set in the constructor by including the option +:text+. Perhaps a better
11
- # idea is to use Card.create or Cardlike.card.
11
+ # +:name+ at a minimum. Perhaps a better idea is to use Card.create or
12
+ # Cardlike.card. Also see Cardlike.type_of_card.
12
13
  #
13
14
  def initialize(options={})
14
15
  self.name = options[:name]
15
- self.text = options[:text]
16
+ @card_type = options[:card_type] || nil
16
17
  @properties = {}
17
18
  end
18
19
 
20
+ def card_type=(type)
21
+ raise "Cannot re-set type after it has been set." if @card_type
22
+ @card_type = type
23
+ end
24
+
19
25
  #
20
26
  # Factory method to create an instance of a Card. This sets the name of the
21
27
  # card and its properties using the Card DSL in the corresponding block. You
@@ -23,9 +29,7 @@ class Cardlike::Card
23
29
  # is to create custom card types using Cardlike.type_of_card and create them
24
30
  # using the +new_+ methods.
25
31
  #
26
- # Card.create "Big Monster" do
27
- # text "Spend 1 Mana to Attack"
28
- # end
32
+ # Card.create "Big Monster"
29
33
  #
30
34
  # Preferred over Card.new.
31
35
  #
@@ -35,15 +39,6 @@ class Cardlike::Card
35
39
  c
36
40
  end
37
41
 
38
- #
39
- # DSL method for setting the card text. Still works as a getter if no args are
40
- # passed.
41
- #
42
- def text(card_text=nil)
43
- return @text unless card_text
44
- @text = card_text
45
- end
46
-
47
42
  #
48
43
  # Return custom properties of this Card. Custom properties can be set using
49
44
  # the Card.has method, ideally inside a Cardlike.type_of_card block.
@@ -54,20 +49,27 @@ class Cardlike::Card
54
49
  @properties[prop]
55
50
  end
56
51
 
52
+ #
53
+ # Class DSL method for setting custom properties for a Card that include a
54
+ # block. See Cardlike.type_of_card.
55
+ #
56
+ def self.has_block(prop)
57
+ define_method(prop, lambda { |&block| return @properties[prop] unless block; raise "Cards are immutable." if @properties.has_key? prop; @properties[prop] = block })
58
+ end
59
+
57
60
  #
58
61
  # Class DSL method for setting custom properties for a Card. See
59
62
  # Cardlike.type_of_card.
60
63
  #
61
64
  def self.has(prop)
62
- define_method(prop, lambda { |arg| raise "Cards are immutable." if @properties.has_key? prop; @properties[prop] = arg })
65
+ define_method(prop, lambda { |arg=nil| return @properties[prop] unless arg; raise "Cards are immutable." if @properties.has_key? prop; @properties[prop] = arg })
63
66
  end
64
67
 
65
68
  def to_s
66
69
  t = []
67
70
  t << "Name: #{name}"
68
- t << "Text: #{text}" if text
69
- @properties.each { |p,v| t << "#{p}: #{v}" }
70
- t.join("\n")
71
+ @properties.each { |p,v| t << "#{p}: #{v}" unless v.nil? or v.is_a? Proc }
72
+ "[ "+t.join("; ")+" ]"
71
73
  end
72
74
 
73
75
  end
data/lib/cardlike/hand.rb CHANGED
@@ -7,7 +7,26 @@ class Cardlike::Hand < Cardlike::Deck
7
7
  # Remove and return a Card from this hand by name.
8
8
  #
9
9
  def remove_card(card_name)
10
- self.delete(self.select { |card| card.name == card_name }.first)
10
+ self.delete(self.find { |card| card.name == card_name })
11
+ end
12
+
13
+ #
14
+ # Remove and return a Card from this hand at the index.
15
+ #
16
+ def remove_card_at(index)
17
+ self.delete_at(index)
18
+ end
19
+
20
+ def remove_random_card(&block)
21
+ if block
22
+ options = []
23
+ self.each { |c| options << c if block.call(c) }
24
+ c = options.sample
25
+ return self.delete(c)
26
+ else
27
+ c = self.sample
28
+ return self.delete(c)
29
+ end
11
30
  end
12
31
 
13
32
  #
@@ -20,9 +39,8 @@ class Cardlike::Hand < Cardlike::Deck
20
39
  end
21
40
 
22
41
  def to_s
23
- puts "Hand: #{name}"
24
- self.each do |card|
25
- puts "-> #{card}\n"
26
- end
42
+ cards = ["Hand: #{name}"]
43
+ cards += self.collect { |c| "-> #{c}" }
44
+ cards.join("\n")
27
45
  end
28
46
  end
@@ -34,7 +34,7 @@ module Cardlike
34
34
  #
35
35
  def self.the_score(target)
36
36
  @scores ||= {}
37
- @scores[target]
37
+ @scores[target] || 0
38
38
  end
39
39
 
40
40
  #
@@ -1,3 +1,3 @@
1
1
  module Cardlike
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -5,9 +5,7 @@ describe 'Defining a card' do
5
5
 
6
6
  context "for a basic card" do
7
7
  before do
8
- @card = Cardlike.card "Fire Monster" do
9
- text "A red-hot monster."
10
- end
8
+ @card = Cardlike.card "Fire Monster"
11
9
  end
12
10
 
13
11
  it "creates a Card object" do
@@ -17,10 +15,6 @@ describe 'Defining a card' do
17
15
  it "properly sets the card name" do
18
16
  @card.name.should eq "Fire Monster"
19
17
  end
20
-
21
- it "properly sets the card text" do
22
- @card.text.should eq "A red-hot monster."
23
- end
24
18
  end
25
19
 
26
20
  end
@@ -45,7 +39,7 @@ describe 'Defining a card' do
45
39
  @playing_card.name.should eq "PlayingCard"
46
40
  end
47
41
 
48
- it "creates an accessor for the custom field" do
42
+ it "creates an accessor for the custom property" do
49
43
  @playing_card.new.should respond_to :suit
50
44
  end
51
45
 
@@ -64,9 +58,17 @@ describe 'Defining a card' do
64
58
  @card.should be_a_kind_of Cardlike::Card
65
59
  end
66
60
 
67
- it "creates an accessor for the custom field" do
61
+ it "creates an accessor for the custom property" do
68
62
  @card.should respond_to :suit
69
63
  end
64
+
65
+ it "responds to the Card.card_type method with the type" do
66
+ @card.card_type.should eq :playing_card
67
+ end
68
+
69
+ it "does not allow setting of card_type" do
70
+ lambda { @card.card_type = 'Special Card' }.should raise_error(StandardError)
71
+ end
70
72
  end
71
73
 
72
74
  context "when instantiated" do
@@ -81,7 +83,7 @@ describe 'Defining a card' do
81
83
  @card.should be_a_kind_of Cardlike::Card
82
84
  end
83
85
 
84
- it "creates an accessor for the custom field" do
86
+ it "creates an accessor for the custom property" do
85
87
  @card.should respond_to :suit
86
88
  end
87
89
 
@@ -90,11 +92,15 @@ describe 'Defining a card' do
90
92
  @card2.should_not respond_to :suit
91
93
  end
92
94
 
93
- it "sets the field properly" do
95
+ it "sets the property properly" do
94
96
  @card[:suit].should eq 'Spades'
95
97
  end
96
98
 
97
- it "does not allow fields to be set again" do
99
+ it "also returns the property from the accessor version of the setter" do
100
+ @card.suit.should eq 'Spades'
101
+ end
102
+
103
+ it "does not allow properties to be set again" do
98
104
  lambda { @card.suit 'Clubs' }.should raise_error(StandardError)
99
105
  end
100
106
 
@@ -102,4 +108,24 @@ describe 'Defining a card' do
102
108
 
103
109
  end
104
110
 
111
+ context "that includes a block" do
112
+ before do
113
+ Cardlike.game do
114
+ type_of_card :monster_card do
115
+ has_block :action
116
+ end
117
+
118
+ new_monster_card "Ogre" do
119
+ action do
120
+ :action_complete
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ it "completes the action" do
127
+ Cardlike.the_card("Ogre").action.call.should eq :action_complete
128
+ end
129
+ end
130
+
105
131
  end
@@ -1,42 +1,84 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'A deck of cards' do
4
- before do
5
- @cards = []
6
- @cards << Cardlike::Card.new(name: 'Leonardo', text: 'Has two swords.')
7
- @cards << Cardlike::Card.new(name: 'Donatello', text: 'Has a Bo staff.')
8
- @cards << Cardlike::Card.new(name: 'Michaelangelo', text: 'Has Nunchuku.')
9
- @cards << Cardlike::Card.new(name: 'Raphael', text: 'Has Sai.')
10
-
11
- @deck = Cardlike::Deck.new(name: 'Turtles', cards: @cards)
12
- end
13
-
14
- context 'when a card is drawn' do
4
+ context "for a simple deck" do
15
5
  before do
16
- @drawn = @deck.draw
6
+ @cards = []
7
+ @cards << Cardlike::Card.new(name: 'Leonardo')
8
+ @cards << Cardlike::Card.new(name: 'Donatello')
9
+ @cards << Cardlike::Card.new(name: 'Michaelangelo')
10
+ @cards << Cardlike::Card.new(name: 'Raphael')
11
+
12
+ @deck = Cardlike::Deck.new(name: 'Turtles', cards: @cards)
17
13
  end
18
14
 
19
- it 'is one of the cards from the deck' do
20
- @cards.should include @drawn
15
+ context 'when a card is drawn' do
16
+ before do
17
+ @drawn = @deck.draw
18
+ end
19
+
20
+ it 'is one of the cards from the deck' do
21
+ @cards.should include @drawn
22
+ end
23
+
24
+ it 'is no longer in the deck' do
25
+ @deck.should_not include @drawn
26
+ end
21
27
  end
22
28
 
23
- it 'is no longer in the deck' do
24
- @deck.should_not include @drawn
29
+ context "when a card is drawn into a Hand" do
30
+ before do
31
+ @hand = Cardlike::Hand.new(name: 'Player 1')
32
+ @drawn = @deck.draw_into @hand
33
+ end
34
+
35
+ it "inserts the card into the Hand" do
36
+ @hand.should include @drawn
37
+ end
38
+
39
+ it "removes the card from the Deck" do
40
+ @deck.should_not include @drawn
41
+ end
25
42
  end
26
43
  end
27
44
 
28
- context "when a card is drawn into a Hand" do
45
+ context "for a deck of custom cards" do
29
46
  before do
30
- @hand = Cardlike::Hand.new(name: 'Player 1')
31
- @drawn = @deck.draw_into @hand
32
- end
47
+ Cardlike.game do
48
+ type_of_card :monster_card do
49
+ has :strength
50
+ end
33
51
 
34
- it "inserts the card into the Hand" do
35
- @hand.should include @drawn
52
+ deck "Monsters" do
53
+ new_monster_card("Giant Snake") { strength 5 }
54
+ new_monster_card("Giant Spider") { strength 3 }
55
+ new_monster_card("Giant Giant") { strength 8 }
56
+ new_monster_card("Giant Cow") { strength 2 }
57
+ end
58
+ end
36
59
  end
37
60
 
38
- it "removes the card from the Deck" do
39
- @deck.should_not include @drawn
61
+ context "when a card is drawn into a Hand" do
62
+ before do
63
+ @top_card = Cardlike.game do
64
+ hand "My Hand"
65
+ top_card = the_deck("Monsters").last
66
+ the_deck("Monsters").draw_into the_hand("My Hand")
67
+ top_card
68
+ end
69
+ end
70
+
71
+ it "removes a card from the deck" do
72
+ Cardlike.the_deck("Monsters").size.should eq 3
73
+ end
74
+
75
+ it "adds a card to the Hand" do
76
+ Cardlike.the_hand("My Hand").size.should eq 1
77
+ end
78
+
79
+ it "the drawn card is the top card from the deck" do
80
+ @top_card.should eq Cardlike.the_hand("My Hand").first
81
+ end
40
82
  end
41
83
  end
42
84
  end
@@ -19,7 +19,7 @@ describe "A hand of cards" do
19
19
  Cardlike.the_hand("Player 1").first.name.should eq "Boring Card One"
20
20
  end
21
21
 
22
- context "when removing a specific card" do
22
+ context "when removing a card by name" do
23
23
  before do
24
24
  @card1 = Cardlike.the_hand("Player 1").remove_card "Boring Card One"
25
25
  end
@@ -33,7 +33,49 @@ describe "A hand of cards" do
33
33
  end
34
34
  end
35
35
 
36
- context "when removing a card with remove_card_if" do
36
+ context "when removing a card at random" do
37
+ before do
38
+ @card1 = Cardlike.the_hand("Player 1").remove_random_card
39
+ end
40
+
41
+ it "removes a Card" do
42
+ @card1.should be_a_kind_of Cardlike::Card
43
+ end
44
+
45
+ it "removes the card from the Hand" do
46
+ Cardlike.the_hand("Player 1").size.should eq 3
47
+ end
48
+ end
49
+
50
+ context "when removing a card at random with specific parameters (a block)" do
51
+ before do
52
+ @card1 = Cardlike.the_hand("Player 1").remove_random_card { |c| c.name =~ /^Boring Card T/ }
53
+ end
54
+
55
+ it "removes a card matching the parameters" do
56
+ @card1.name.should satisfy { |s| ["Boring Card Two", "Boring Card Three"].include?(s) }
57
+ end
58
+
59
+ it "removes the card from the Hand" do
60
+ Cardlike.the_hand("Player 1").size.should eq 3
61
+ end
62
+ end
63
+
64
+ context "when removing a card by index" do
65
+ before do
66
+ @card1 = Cardlike.the_hand("Player 1").remove_card_at 3
67
+ end
68
+
69
+ it "can remove a specific card" do
70
+ @card1.name.should eq "Boring Card Four"
71
+ end
72
+
73
+ it "removes the card from the Hand" do
74
+ Cardlike.the_hand("Player 1").size.should eq 3
75
+ end
76
+ end
77
+
78
+ context "when removing cards with remove_card_if" do
37
79
  before do
38
80
  @card1 = Cardlike.the_hand("Player 1").remove_card_if { |c| c.name =~ /Three/ }.first
39
81
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cardlike
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-12 00:00:00.000000000 Z
12
+ date: 2013-02-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec