cardlike 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ module Cardlike
2
+ #
3
+ # Increment the score for a target (usually a string or symbol).
4
+ #
5
+ # Cardlike.score "player 1" # => sets the score to 1
6
+ #
7
+ def self.score(target)
8
+ @scores ||= {}
9
+ @scores[target] ||= 0
10
+ @scores[target] += 1
11
+ end
12
+
13
+ #
14
+ # Clear all scores.
15
+ #
16
+ def self.clear_scores
17
+ @scores = {}
18
+ end
19
+
20
+ #
21
+ # Return the hash of the form <tt>{target: score}</tt>.
22
+ #
23
+ def self.scores
24
+ @scores ||= {}
25
+ @scores
26
+ end
27
+
28
+ #
29
+ # Retrieve the score for a target (usually a string or symbol).
30
+ #
31
+ # Cardlike.score "player 1" # => sets the score to 1
32
+ # Cardlike.score "player 1" # => sets the score to 2
33
+ # Cardlike.the_score "player 1" # => 2
34
+ #
35
+ def self.the_score(target)
36
+ @scores ||= {}
37
+ @scores[target]
38
+ end
39
+
40
+ #
41
+ # Set the score for a target to a particular value.
42
+ #
43
+ def self.set_score(target, value)
44
+ @scores ||= {}
45
+ @scores[target] = value
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ module Cardlike
2
+ #
3
+ # Define a turn block that can be run with Cardlike.begin_new_turn.
4
+ #
5
+ # Cardlike.define_turn do |current_player|
6
+ # puts "#{current_player}'s turn"
7
+ # end
8
+ #
9
+ def self.define_turn(&block)
10
+ @turn = block
11
+ end
12
+
13
+ #
14
+ # Return the turn block set by Cardlike.define_turn.
15
+ #
16
+ def self.the_turn
17
+ @turn
18
+ end
19
+
20
+ #
21
+ # Call the block defined by Cardlike.define_turn. You can pass arguments to
22
+ # the block as well.
23
+ #
24
+ def self.begin_new_turn(*args)
25
+ @turn.call(*args)
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Cardlike
2
+ VERSION = "0.0.1"
3
+ end
data/lib/cardlike.rb ADDED
@@ -0,0 +1,154 @@
1
+ require "cardlike/version"
2
+ require "cardlike/deck"
3
+ require "cardlike/card"
4
+ require "cardlike/hand"
5
+ require "cardlike/score"
6
+ require "cardlike/turn"
7
+ require "active_support/inflector"
8
+
9
+ module Cardlike
10
+ def self.version
11
+ "#{self} version #{VERSION}"
12
+ end
13
+
14
+ #
15
+ # Optionally use this to wrap Cardlike DSL methods to avoid having to prefix
16
+ # them with +Cardlike+. This is mainly useful for large blocks.
17
+ #
18
+ # Cardlike.game do
19
+ # type_of_card :playing_card { has :suit }
20
+ # end
21
+ #
22
+ # is the same as
23
+ #
24
+ # Cardlike.type_of_card :playing_card { has :suit }
25
+ #
26
+ def self.game(&block)
27
+ self.class_eval(&block)
28
+ end
29
+
30
+ #
31
+ # Set up a new Deck with the given name. Returns the created Deck which can
32
+ # also be accessed with +the_deck+. Within the block you may use the Deck DSL.
33
+ #
34
+ # Cardlike.deck "Poker Deck" do
35
+ # include_card "King of Diamonds"
36
+ # include_card "Three of Clubs"
37
+ # end
38
+ #
39
+ def self.deck(name, &block)
40
+ @decks ||= {}
41
+ d = Deck.new(name: name)
42
+ d.instance_eval(&block) if block_given?
43
+ @decks[name] = d
44
+ d
45
+ end
46
+
47
+ #
48
+ # Set up a new Hand with the given name. Returns the created Hand which can
49
+ # also be accessed with +the_deck+. Within the block you may use the Hand DSL.
50
+ #
51
+ # Cardlike.hand "Poker Hand" do
52
+ # include_card "King of Diamonds"
53
+ # include_card "Three of Clubs"
54
+ # end
55
+ #
56
+ def self.hand(name, &block)
57
+ @hands ||= {}
58
+ d = Hand.new(name: name)
59
+ d.instance_eval(&block) if block_given?
60
+ @hands[name] = d
61
+ d
62
+ end
63
+
64
+ #
65
+ # Return a Deck created by the +deck+ method by +name+.
66
+ #
67
+ # Cardlike.the_deck("Blackjack Deck").size # => 52
68
+ #
69
+ def self.the_deck(name)
70
+ @decks ||= {}
71
+ @decks[name]
72
+ end
73
+
74
+ #
75
+ # Return a Hand created by the +hand+ method by +name+.
76
+ #
77
+ # Cardlike.the_hand("Poker Hand").size # => 5
78
+ #
79
+ def self.the_hand(name)
80
+ @hands ||= {}
81
+ @hands[name]
82
+ end
83
+
84
+ #
85
+ # Return a Card created by the +card+ method. Also will return cards created
86
+ # by the custom +new_+ card methods (see +type_of_card+).
87
+ #
88
+ # Cardlike.the_card("Six of Diamonds").name # => "Six of Diamonds"
89
+ #
90
+ def self.the_card(name)
91
+ @cards ||= {}
92
+ @cards[name]
93
+ end
94
+
95
+ #
96
+ # Create a new Card with the given name and block evaluated in the context of
97
+ # the Card. Returns the Card (that can also be accessed with +the_card+). You
98
+ # may use the Card DSL in the block.
99
+ #
100
+ # Cardlike.card "Fire Monster" do
101
+ # text "A red-hot monster."
102
+ # end
103
+ #
104
+ def self.card(name, &block)
105
+ c = Card.create(name, &block)
106
+ @cards ||= {}
107
+ @cards[name] = c
108
+ c
109
+ end
110
+
111
+ #
112
+ # Create a new subclass of Card with its own properties as defined in the
113
+ # block. You may use the Card class DSL in the block. Automatically defines a
114
+ # method for creating new objects of that class, prefixed by +new_+. For
115
+ # example, a <tt>type_of_card :fun_card</tt> defines the method +new_fun_card+
116
+ # (which operates like the +card+ method) that can be used in either a +deck+
117
+ # block or directly.
118
+ #
119
+ # Cardlike.type_of_card :playing_card do
120
+ # has :value
121
+ # has :suit
122
+ # end
123
+ #
124
+ # You can then access the card with:
125
+ #
126
+ # Cardlike.new_playing_card "Six of Spades" do
127
+ # value 6
128
+ # suit 'spades'
129
+ # end
130
+ #
131
+ # or:
132
+ #
133
+ # Cardlike.deck "Poker Deck" do
134
+ # new_playing_card "Six of Spades" do
135
+ # value 6
136
+ # suit 'spades'
137
+ # end
138
+ # end
139
+ #
140
+ def self.type_of_card(name, &block)
141
+ klass = Class.new(Card)
142
+ klass_name = name.to_s.camelize
143
+ name_underscored = name.to_s.downcase.underscore
144
+ Object.const_set(klass_name, klass) if not Object.const_defined?(klass_name)
145
+ c = Object.const_get(klass_name)
146
+ c.class_eval(&block) if block_given?
147
+
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 })
150
+
151
+ c
152
+ end
153
+
154
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Defining a card' do
4
+ context "using the basic card DSL" do
5
+
6
+ context "for a basic card" do
7
+ before do
8
+ @card = Cardlike.card "Fire Monster" do
9
+ text "A red-hot monster."
10
+ end
11
+ end
12
+
13
+ it "creates a Card object" do
14
+ @card.should be_a_kind_of Cardlike::Card
15
+ end
16
+
17
+ it "properly sets the card name" do
18
+ @card.name.should eq "Fire Monster"
19
+ end
20
+
21
+ it "properly sets the card text" do
22
+ @card.text.should eq "A red-hot monster."
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ context "using the custom card DSL" do
29
+ before do
30
+ @playing_card = Cardlike.type_of_card :playing_card do
31
+ has :value
32
+ has :suit
33
+ end
34
+ end
35
+
36
+ it "creates a new Class" do
37
+ @playing_card.should be_a_kind_of Class
38
+ end
39
+
40
+ it "creates a subclass of Card" do
41
+ @playing_card.should < Cardlike::Card
42
+ end
43
+
44
+ it "creates a dynamic custom Class" do
45
+ @playing_card.name.should eq "PlayingCard"
46
+ end
47
+
48
+ it "creates an accessor for the custom field" do
49
+ @playing_card.new.should respond_to :suit
50
+ end
51
+
52
+ context "when instantiated with the 'new_' factory" do
53
+ before do
54
+ deck = Cardlike.deck "Test" do
55
+ new_playing_card "Six of Spades" do
56
+ value 6
57
+ suit 'Spades'
58
+ end
59
+ end
60
+ @card = deck.first
61
+ end
62
+
63
+ it "creates a custom Card object" do
64
+ @card.should be_a_kind_of Cardlike::Card
65
+ end
66
+
67
+ it "creates an accessor for the custom field" do
68
+ @card.should respond_to :suit
69
+ end
70
+ end
71
+
72
+ context "when instantiated" do
73
+ before do
74
+ @card = @playing_card.create "Six of Spades" do
75
+ value 6
76
+ suit 'Spades'
77
+ end
78
+ end
79
+
80
+ it "creates a custom Card object" do
81
+ @card.should be_a_kind_of Cardlike::Card
82
+ end
83
+
84
+ it "creates an accessor for the custom field" do
85
+ @card.should respond_to :suit
86
+ end
87
+
88
+ it "does not affect other Card instances" do
89
+ @card2 = Cardlike.card "Castle"
90
+ @card2.should_not respond_to :suit
91
+ end
92
+
93
+ it "sets the field properly" do
94
+ @card[:suit].should eq 'Spades'
95
+ end
96
+
97
+ it "does not allow fields to be set again" do
98
+ lambda { @card.suit 'Clubs' }.should raise_error(StandardError)
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
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
15
+ before do
16
+ @drawn = @deck.draw
17
+ end
18
+
19
+ it 'is one of the cards from the deck' do
20
+ @cards.should include @drawn
21
+ end
22
+
23
+ it 'is no longer in the deck' do
24
+ @deck.should_not include @drawn
25
+ end
26
+ end
27
+
28
+ context "when a card is drawn into a Hand" do
29
+ before do
30
+ @hand = Cardlike::Hand.new(name: 'Player 1')
31
+ @drawn = @deck.draw_into @hand
32
+ end
33
+
34
+ it "inserts the card into the Hand" do
35
+ @hand.should include @drawn
36
+ end
37
+
38
+ it "removes the card from the Deck" do
39
+ @deck.should_not include @drawn
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Building a deck" do
4
+ context "with a simple card" do
5
+ before do
6
+ Cardlike.game do
7
+ deck "Simple Deck" do
8
+ card "Boring Card"
9
+ end
10
+ end
11
+ end
12
+
13
+ it "has 1 card" do
14
+ Cardlike.the_deck("Simple Deck").size.should eq 1
15
+ end
16
+
17
+ it "contains the first card" do
18
+ Cardlike.the_deck("Simple Deck").first.name.should eq "Boring Card"
19
+ end
20
+ end
21
+
22
+ context "with a bunch of cards defined in the block" do
23
+ before do
24
+ Cardlike.game do
25
+ type_of_card :playing_card do
26
+ has :value
27
+ has :suit
28
+ end
29
+
30
+ deck "Poker Deck" do
31
+ new_playing_card "Ace of Spades" do
32
+ value 11
33
+ suit 'Spades'
34
+ end
35
+
36
+ new_playing_card "Ace of Diamonds" do
37
+ value 11
38
+ suit 'Diamonds'
39
+ end
40
+
41
+ new_playing_card "Five of Clubs" do
42
+ value 5
43
+ suit 'Clubs'
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ it "contains the right number of cards" do
51
+ Cardlike.the_deck("Poker Deck").size.should eq 3
52
+ end
53
+
54
+ it "contains a card created in the block" do
55
+ Cardlike.the_deck("Poker Deck").first.name.should eq "Ace of Spades"
56
+ end
57
+
58
+ context "and another deck exists" do
59
+ before do
60
+ Cardlike.deck "Go Fish Deck" do
61
+ new_playing_card "Seven of Spades" do
62
+ value 7
63
+ suit :spades
64
+ end
65
+ end
66
+ end
67
+
68
+ it "the first deck contains the right number of cards" do
69
+ Cardlike.the_deck("Poker Deck").size.should eq 3
70
+ end
71
+
72
+ it "the new deck contains the right number of cards" do
73
+ Cardlike.the_deck("Go Fish Deck").size.should eq 1
74
+ end
75
+
76
+ end
77
+ end
78
+
79
+ context "with a bunch of cards pre-defined" do
80
+ before do
81
+ Cardlike.type_of_card :playing_card do
82
+ has :value
83
+ has :suit
84
+ end
85
+
86
+ Cardlike.new_playing_card "King of Diamonds" do
87
+ value 10
88
+ suit :diamonds
89
+ end
90
+
91
+ Cardlike.new_playing_card "Three of Clubs" do
92
+ value 3
93
+ suit :clubs
94
+ end
95
+
96
+ Cardlike.deck "Blackjack Deck" do
97
+ include_card "King of Diamonds"
98
+ include_card "Three of Clubs"
99
+ end
100
+ end
101
+
102
+ it "contains the right number of cards" do
103
+ Cardlike.the_deck("Blackjack Deck").size.should eq 2
104
+ end
105
+
106
+ it "contains a card created in the block" do
107
+ Cardlike.the_deck("Blackjack Deck").first.name.should eq "King of Diamonds"
108
+ end
109
+
110
+ end
111
+
112
+ context "with multiple copies of a card" do
113
+ before do
114
+ Cardlike.type_of_card :playing_card do
115
+ has :value
116
+ has :suit
117
+ end
118
+
119
+ Cardlike.new_playing_card "Queen of Diamonds" do
120
+ value 10
121
+ suit :diamonds
122
+ end
123
+
124
+ Cardlike.deck "Copy Deck" do
125
+ 6.times { copy_card "Queen of Diamonds" }
126
+ end
127
+ end
128
+
129
+ it "contains the right number of cards" do
130
+ Cardlike.the_deck("Copy Deck").size.should eq 6
131
+ end
132
+
133
+ it "contains a card created in the block" do
134
+ Cardlike.the_deck("Copy Deck").first.name.should eq "Queen of Diamonds"
135
+ end
136
+
137
+ it "contains another card created in the block" do
138
+ Cardlike.the_deck("Copy Deck")[2].name.should eq "Queen of Diamonds"
139
+ end
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,4 @@
1
+ require 'cardlike'
2
+
3
+ RSpec.configure do |config|
4
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cardlike do
4
+ describe '.version' do
5
+ it 'returns correct version' do
6
+ Cardlike.version.should eq "Cardlike version #{Cardlike::VERSION}"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cardlike::Deck do
4
+ let (:deck) { Cardlike::Deck.new(cards: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']) }
5
+
6
+ describe "#shuffle" do
7
+ before do
8
+ @orig_deck = deck.dup
9
+ @shuffled = deck.shuffle
10
+ end
11
+
12
+ it "returns a Deck" do
13
+ @shuffled.should be_a_kind_of Cardlike::Deck
14
+ end
15
+
16
+ it "returns a differently-ordered deck" do
17
+ @shuffled.should_not eq @orig_deck
18
+ end
19
+
20
+ it "retains the order of the deck" do
21
+ deck.should eq @orig_deck
22
+ end
23
+ end
24
+
25
+ describe "#shuffle!" do
26
+ before do
27
+ @orig_deck = deck.dup
28
+ @shuffled = deck.shuffle!
29
+ end
30
+
31
+ it "the deck remains a Deck" do
32
+ @shuffled.should be_a_kind_of Cardlike::Deck
33
+ end
34
+
35
+ it "returns a differently-ordered deck" do
36
+ deck.should_not eq @orig_deck
37
+ end
38
+
39
+ it "changes the order of the deck" do
40
+ deck.should_not eq @orig_deck
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe "A hand of cards" do
4
+ context "with 4 cards added" do
5
+ before do
6
+ Cardlike.hand "Player 1" do
7
+ card "Boring Card One"
8
+ card "Boring Card Two"
9
+ card "Boring Card Three"
10
+ card "Boring Card Four"
11
+ end
12
+ end
13
+
14
+ it "has 4 cards" do
15
+ Cardlike.the_hand("Player 1").size.should eq 4
16
+ end
17
+
18
+ it "contains the first card" do
19
+ Cardlike.the_hand("Player 1").first.name.should eq "Boring Card One"
20
+ end
21
+
22
+ context "when removing a specific card" do
23
+ before do
24
+ @card1 = Cardlike.the_hand("Player 1").remove_card "Boring Card One"
25
+ end
26
+
27
+ it "can remove a specific card" do
28
+ @card1.name.should eq "Boring Card One"
29
+ end
30
+
31
+ it "removes the card from the Hand" do
32
+ Cardlike.the_hand("Player 1").size.should eq 3
33
+ end
34
+ end
35
+
36
+ context "when removing a card with remove_card_if" do
37
+ before do
38
+ @card1 = Cardlike.the_hand("Player 1").remove_card_if { |c| c.name =~ /Three/ }.first
39
+ end
40
+
41
+ it "removes and returns the correct card" do
42
+ @card1.name.should eq "Boring Card Three"
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
+ end
50
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cardlike do
4
+ describe ".score" do
5
+ context "with a new target" do
6
+ before do
7
+ Cardlike.clear_scores
8
+ Cardlike.score :foobar
9
+ end
10
+
11
+ it "sets a new target with the score" do
12
+ Cardlike.the_score(:foobar).should eq 1
13
+ end
14
+ end
15
+
16
+ context "with an existing target" do
17
+ before do
18
+ Cardlike.game do
19
+ 3.times { score :foobaz }
20
+ end
21
+ end
22
+
23
+ it "increments the score for the target" do
24
+ Cardlike.the_score(:foobaz).should eq 3
25
+ end
26
+ end
27
+ end
28
+
29
+ describe ".clear_scores" do
30
+ before do
31
+ Cardlike.score :barfoo
32
+ Cardlike.clear_scores
33
+ end
34
+
35
+ it "removes all scores" do
36
+ Cardlike.scores.should be_empty
37
+ end
38
+ end
39
+
40
+ describe ".scores" do
41
+ before do
42
+ Cardlike.clear_scores
43
+ Cardlike.game do
44
+ 2.times { score :foo }
45
+ 3.times { score :bar }
46
+ 1.times { score :baz }
47
+ end
48
+ end
49
+
50
+ it "returns a hash of target => score" do
51
+ hash = {:foo => 2, :bar => 3, :baz => 1}
52
+ Cardlike.scores.should eq hash
53
+ end
54
+ end
55
+
56
+ describe ".set_score" do
57
+ before do
58
+ Cardlike.clear_scores
59
+ Cardlike.game do
60
+ score :foo
61
+ score :foo
62
+ score :bar
63
+
64
+ set_score :foo, 5
65
+ end
66
+ end
67
+
68
+ it "sets a score to particular value" do
69
+ Cardlike.the_score(:foo).should eq 5
70
+ end
71
+ end
72
+ end
73
+