cardshark 0.0.1 → 0.0.2

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.
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cardshark
4
+ class Error < StandardError
5
+ class AbstractClass < Error; end
6
+ class DeckAlreadyShuffled < Error; end
7
+ class DeckExhausted < Error; end
8
+ class DeckOrderInvalid < Error; end
9
+ class DimensionInheritanceLimit < Error; end
10
+ end
11
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Cardshark
2
- VERSION = "0.0.1"
4
+ VERSION = '0.0.2'
3
5
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/abstract'
4
+
5
+ RSpec.describe Cardshark::Abstract do
6
+ context 'included into a new class' do
7
+ let(:klass) { Class.new { include Cardshark::Abstract } }
8
+
9
+ describe '::new' do
10
+ it 'raises a Cardshark::Error::AbstractClass' do
11
+ expect { klass.new }.to raise_error(Cardshark::Error::AbstractClass)
12
+ end
13
+
14
+ context 'it has been subclassed' do
15
+ let(:subclass) { Class.new(klass) }
16
+
17
+ it 'does not raise an error' do
18
+ expect { subclass.new }.not_to raise_error
19
+ end
20
+
21
+ it 'returns an instance of the subclass' do
22
+ expect(subclass.new).to be_a(subclass)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/card'
4
+
5
+ RSpec.describe Cardshark::Card do
6
+ let(:rank) { Class.new(Cardshark::Dimension) }
7
+ let(:suit) { Class.new(Cardshark::Dimension) }
8
+
9
+ let(:ace) { rank.new(:ace) }
10
+ let(:spades) { suit.new(:spades) }
11
+ let(:clubs) { suit.new(:clubs) }
12
+
13
+ describe '::new' do
14
+ context 'invalid arguments' do
15
+ context 'no arguments' do
16
+ it 'raises an ArgumentError' do
17
+ expect { described_class.new }.to raise_error(ArgumentError)
18
+ end
19
+ end
20
+
21
+ context 'invalid argument type' do
22
+ it 'raises an ArgumentError' do
23
+ expect { described_class.new('invalid-arguments') }
24
+ .to raise_error(ArgumentError)
25
+ end
26
+ end
27
+
28
+ context 'more than one argument of the same dimension' do
29
+ it 'raises an ArgumentError' do
30
+ expect { described_class.new(spades, clubs) }
31
+ .to raise_error(ArgumentError)
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'valid arguments' do
37
+ it 'does not raise an error' do
38
+ expect { described_class.new(ace, spades) }.not_to raise_error
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#dimensions' do
44
+ let(:card) { described_class.new(ace, spades) }
45
+
46
+ before do
47
+ @result = card.dimensions
48
+ end
49
+
50
+ it 'returns an Array' do
51
+ expect(@result).to be_an(Array)
52
+ end
53
+
54
+ it 'contains one entry for each type of dimension' do
55
+ expect(@result.count).to eq(2)
56
+ end
57
+
58
+ it 'contains a symbol for the first dimension' do
59
+ expect(@result).to include(rank.id)
60
+ end
61
+
62
+ it 'contains a symbol for the second dimension' do
63
+ expect(@result).to include(suit.id)
64
+ end
65
+ end
66
+
67
+ describe 'dynamic dimension methods' do
68
+ let(:card) { described_class.new(ace, spades) }
69
+
70
+ it 'has a method for the first dimension' do
71
+ expect(card.respond_to?(suit.id)).to eq(true)
72
+ end
73
+
74
+ it 'has a method for the second dimension' do
75
+ expect(card.respond_to?(rank.id)).to eq(true)
76
+ end
77
+
78
+ it 'returns the correct value for the first dimension' do
79
+ expect(card.send(suit.id)).to eq(spades)
80
+ end
81
+
82
+ it 'returns the correct value for the second dimension' do
83
+ expect(card.send(rank.id)).to eq(ace)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,252 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/card'
4
+ require 'cardshark/deck'
5
+
6
+ RSpec.describe Cardshark::Deck do
7
+ context 'class methods' do
8
+ describe '::new' do
9
+ context 'invalid arguments' do
10
+ context 'no arguments' do
11
+ it 'raises an ArgumentError' do
12
+ expect { described_class.new }.to raise_error(ArgumentError)
13
+ end
14
+ end
15
+
16
+ context 'invalid arguments' do
17
+ it 'raises an ArgumentError' do
18
+ expect { described_class.new('invalid-arguments') }
19
+ .to raise_error(ArgumentError)
20
+ end
21
+ end
22
+
23
+ context 'valid arguments' do
24
+ it 'does not raise an error' do
25
+ expect { described_class.new {} }.not_to raise_error
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ context 'instance methods' do
33
+ let(:suit) { Class.new(Cardshark::Dimension) }
34
+ let!(:spades) { suit.new(:spades) }
35
+ let!(:hearts) { suit.new(:hearts) }
36
+
37
+ let(:rank) { Class.new(Cardshark::Dimension) }
38
+ let!(:king) { rank.new(:king) }
39
+ let!(:queen) { rank.new(:queen) }
40
+ let!(:jack) { rank.new(:jack) }
41
+
42
+ let(:cards) do
43
+ cards = []
44
+ suit.all.each do |suit|
45
+ rank.all.each do |rank|
46
+ cards << Cardshark::Card.new(rank, suit)
47
+ end
48
+ end
49
+ cards
50
+ end
51
+
52
+ describe '#draw' do
53
+ context 'new deck' do
54
+ let(:deck) { described_class.new { cards } }
55
+
56
+ before do
57
+ @one = deck.draw
58
+ @two = deck.draw
59
+ @three = deck.draw
60
+ @four = deck.draw
61
+ @five = deck.draw
62
+ @six = deck.draw
63
+ end
64
+
65
+ it 'returns a Cardshark::Card' do
66
+ expect(@one).to be_a(Cardshark::Card)
67
+ end
68
+
69
+ it 'returns the first card first' do
70
+ expect(@one).to eq(cards[0])
71
+ end
72
+
73
+ it 'returns the second card second' do
74
+ expect(@two).to eq(cards[1])
75
+ end
76
+
77
+ it 'returns the third card third' do
78
+ expect(@three).to eq(cards[2])
79
+ end
80
+
81
+ it 'returns the fourth card fourth' do
82
+ expect(@four).to eq(cards[3])
83
+ end
84
+
85
+ it 'returns the fifth card fifth' do
86
+ expect(@five).to eq(cards[4])
87
+ end
88
+
89
+ it 'returns the sixth card sixth' do
90
+ expect(@six).to eq(cards[5])
91
+ end
92
+
93
+ context 'all cards drawn' do
94
+ it 'raises an error' do
95
+ expect { deck.draw }.to raise_error(Cardshark::Error::DeckExhausted)
96
+ end
97
+ end
98
+ end
99
+
100
+ context 'shuffled deck' do
101
+ let(:deck) { described_class.new { cards } }
102
+
103
+ before do
104
+ deck.shuffle!([3, 4, 1, 5, 2, 0])
105
+
106
+ @one = deck.draw
107
+ @two = deck.draw
108
+ @three = deck.draw
109
+ @four = deck.draw
110
+ @five = deck.draw
111
+ @six = deck.draw
112
+ end
113
+
114
+ it 'returns a Cardshark::Card' do
115
+ expect(@one).to be_a(Cardshark::Card)
116
+ end
117
+
118
+ it 'returns the fourth card first' do
119
+ expect(@one).to eq(cards[3])
120
+ end
121
+
122
+ it 'returns the fifth card second' do
123
+ expect(@two).to eq(cards[4])
124
+ end
125
+
126
+ it 'returns the second card third' do
127
+ expect(@three).to eq(cards[1])
128
+ end
129
+
130
+ it 'returns the sixth card fourth' do
131
+ expect(@four).to eq(cards[5])
132
+ end
133
+
134
+ it 'returns the third card fifth' do
135
+ expect(@five).to eq(cards[2])
136
+ end
137
+
138
+ it 'returns the first card sixth' do
139
+ expect(@six).to eq(cards[0])
140
+ end
141
+
142
+ context 'all cards drawn' do
143
+ it 'raises an error' do
144
+ expect { deck.draw }.to raise_error(Cardshark::Error::DeckExhausted)
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ describe '#count' do
151
+ let(:deck) { described_class.new { cards } }
152
+
153
+ it 'returns the correct number of cards' do
154
+ expect(deck.count).to eq(6)
155
+ end
156
+ end
157
+
158
+ describe '#shuffled?' do
159
+ context 'new deck' do
160
+ let(:deck) { described_class.new { cards } }
161
+
162
+ it 'returns false' do
163
+ expect(deck.shuffled?).to eq(false)
164
+ end
165
+ end
166
+
167
+ context 'shuffled deck' do
168
+ let(:deck) { described_class.new { cards } }
169
+
170
+ before do
171
+ deck.shuffle!([3, 1, 2, 0, 5, 4])
172
+ end
173
+
174
+ it 'returns true' do
175
+ expect(deck.shuffled?).to eq(true)
176
+ end
177
+ end
178
+ end
179
+
180
+ describe 'shuffle!' do
181
+ let(:deck) { described_class.new { cards } }
182
+
183
+ context 'invalid arguments' do
184
+ context 'no arguments' do
185
+ it 'raises an ArgumentError' do
186
+ expect { deck.shuffle! }.to raise_error(ArgumentError)
187
+ end
188
+ end
189
+
190
+ context 'wrong argument type' do
191
+ it 'raises an ArgumentError' do
192
+ expect { deck.shuffle!('invalid-argument') }
193
+ .to raise_error(ArgumentError)
194
+ end
195
+ end
196
+
197
+ context 'invalid deck mapping' do
198
+ context 'non-integer elements' do
199
+ it 'raises an Cardshark::Error::DeckOrderInvalid' do
200
+ expect { deck.shuffle!(['a', 1, 2, 3, 4, 5]) }
201
+ .to raise_error(Cardshark::Error::DeckOrderInvalid)
202
+ end
203
+ end
204
+
205
+ context 'elements out of bounds' do
206
+ it 'raises an Cardshark::Error::DeckOrderInvalid' do
207
+ expect { deck.shuffle!([0, 1, 2, 3, 4, 6]) }
208
+ .to raise_error(Cardshark::Error::DeckOrderInvalid)
209
+ end
210
+ end
211
+
212
+ context 'too many elements' do
213
+ it 'raises an Cardshark::Error::DeckOrderInvalid' do
214
+ expect { deck.shuffle!([0, 1, 2, 3, 4, 5, 6]) }
215
+ .to raise_error(Cardshark::Error::DeckOrderInvalid)
216
+ end
217
+ end
218
+
219
+ context 'too few elements' do
220
+ it 'raises an Cardshark::Error::DeckOrderInvalid' do
221
+ expect { deck.shuffle!([0, 1, 2, 3]) }
222
+ .to raise_error(Cardshark::Error::DeckOrderInvalid)
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ context 'valid arguments' do
229
+ let(:deck_mapping) { [5, 4, 3, 2, 1, 0] }
230
+
231
+ before do
232
+ @result = deck.shuffle!(deck_mapping)
233
+ end
234
+
235
+ it 'returns an instance of the described class' do
236
+ expect(@result).to be_a(described_class)
237
+ end
238
+
239
+ it 'returns the same instance' do
240
+ expect(@result).to equal(deck)
241
+ end
242
+
243
+ context 'alredy shuffled' do
244
+ it 'raises a Cardshark::Error::AlreadyShuffled' do
245
+ expect { deck.shuffle!(deck_mapping) }
246
+ .to raise_error(Cardshark::Error::DeckAlreadyShuffled)
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/dimension'
4
+
5
+ RSpec.describe Cardshark::Dimension do
6
+ describe '::new' do
7
+ it 'raises an Error::AbstractClass' do
8
+ expect { described_class.new(:id) }
9
+ .to raise_exception(Cardshark::Error::AbstractClass)
10
+ end
11
+ end
12
+
13
+ context 'when subclassed' do
14
+ let(:subclass) { Class.new(described_class) }
15
+
16
+ describe '::new' do
17
+ context 'invalid arguments' do
18
+ context 'no arguments' do
19
+ it 'raises an ArgumentError' do
20
+ expect { subclass.new }.to raise_exception(ArgumentError)
21
+ end
22
+ end
23
+
24
+ context 'invalid arguments' do
25
+ it 'raises an ArgumentError' do
26
+ expect { subclass.new('invalid-argument') }
27
+ .to raise_exception(ArgumentError)
28
+ end
29
+ end
30
+ end
31
+
32
+ context 'valid arguments' do
33
+ before do
34
+ @result = subclass.new(:id)
35
+ end
36
+
37
+ context 'return value' do
38
+ it 'is a an instance of the class' do
39
+ expect(@result).to be_an_instance_of(subclass)
40
+ end
41
+
42
+ it 'is a subclass of the described class' do
43
+ expect(@result.class.superclass).to eq(described_class)
44
+ end
45
+
46
+ it 'returns the same object for the same id' do
47
+ expect(@result).to equal(subclass.new(:id))
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '::all' do
54
+ before { @result = subclass.all }
55
+
56
+ it 'returns an Array' do
57
+ expect(@result).to be_an(Array)
58
+ end
59
+
60
+ context 'it has not been instantiated' do
61
+ it 'returns an empty Array' do
62
+ expect(@result.count).to eq(0)
63
+ end
64
+ end
65
+
66
+ context 'it has been instantiated' do
67
+ before do
68
+ @instances = []
69
+ 3.times { |i| @instances.push(subclass.new(i.to_s.to_sym)) }
70
+ @result = subclass.all
71
+ end
72
+ after { clear_instance_metadata }
73
+
74
+ it 'returns an array of instances' do
75
+ expect(@result.first.class).to eq(subclass)
76
+ end
77
+
78
+ it 'returns all of the instances' do
79
+ expect(@result).to match_array(@instances)
80
+ end
81
+ end
82
+ end
83
+
84
+ describe '::id' do
85
+ it 'returns a symbol' do
86
+ expect(subclass.id.class).to eq(Symbol)
87
+ end
88
+
89
+ context 'named subclass' do
90
+ before { class NamedClassExample < described_class; end }
91
+ after { Object.send(:remove_const, 'NamedClassExample') }
92
+
93
+ it 'returns a symbol version of the class name' do
94
+ expect(NamedClassExample.id).to eq(:named_class_example)
95
+ end
96
+ end
97
+ end
98
+
99
+ describe '#to_s' do
100
+ let(:instance) { subclass.new(:name) }
101
+
102
+ it 'returns a capitalized string' do
103
+ expect(instance.to_s).to eq('Name')
104
+ end
105
+ end
106
+ end
107
+
108
+ # This cleans up metadata about subclasses so that
109
+ # these specs can be run reliably in any order
110
+ def clear_instance_metadata
111
+ subclass.instance_variable_set(:@instances, {})
112
+ end
113
+ end