cardlike 0.0.1 → 0.1.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.
- data/README.md +29 -3
- data/lib/cardlike.rb +3 -5
- data/lib/cardlike/card.rb +23 -21
- data/lib/cardlike/hand.rb +23 -5
- data/lib/cardlike/score.rb +1 -1
- data/lib/cardlike/version.rb +1 -1
- data/spec/integration/card_construction_spec.rb +38 -12
- data/spec/integration/dealing_spec.rb +66 -24
- data/spec/units/hand_spec.rb +44 -2
- metadata +2 -2
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"
|
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
|
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.
|
10
|
-
#
|
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
|
-
|
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"
|
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 << "
|
69
|
-
|
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.
|
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
|
-
|
24
|
-
self.
|
25
|
-
|
26
|
-
end
|
42
|
+
cards = ["Hand: #{name}"]
|
43
|
+
cards += self.collect { |c| "-> #{c}" }
|
44
|
+
cards.join("\n")
|
27
45
|
end
|
28
46
|
end
|
data/lib/cardlike/score.rb
CHANGED
data/lib/cardlike/version.rb
CHANGED
@@ -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"
|
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
|
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
|
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
|
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
|
95
|
+
it "sets the property properly" do
|
94
96
|
@card[:suit].should eq 'Spades'
|
95
97
|
end
|
96
98
|
|
97
|
-
it "
|
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
|
-
|
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
|
-
@
|
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
|
-
|
20
|
-
|
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
|
-
|
24
|
-
|
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 "
|
45
|
+
context "for a deck of custom cards" do
|
29
46
|
before do
|
30
|
-
|
31
|
-
|
32
|
-
|
47
|
+
Cardlike.game do
|
48
|
+
type_of_card :monster_card do
|
49
|
+
has :strength
|
50
|
+
end
|
33
51
|
|
34
|
-
|
35
|
-
|
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
|
-
|
39
|
-
|
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
|
data/spec/units/hand_spec.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
+
date: 2013-02-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|