cardshark 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0b7dc3f06fe56ae72385c66266ddd97cd2da7aa24521d995d19bd6a117388783
4
+ data.tar.gz: c91be32f5aa41e6dae0a55c8cbb8fd7129fcc438371d1d23c97ff147f728ca6c
5
+ SHA512:
6
+ metadata.gz: 6f7ff3b232fa6e3d467fab0755dca1d05faee036579ceb6ddc39d3b92f0cd9ff007df15d2604c17e7533357a2179b204cce6c926f334de45e8dd781414755836
7
+ data.tar.gz: 67e7205a272f453e42352bcebfa8571cb9aca30e5c37cbf462686ff942ab0af5b234d6e670e637d4e574d6b2e95fbf461889ebcfb59022673f4f762e717c6739
@@ -0,0 +1,20 @@
1
+ name: RSpec
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+
10
+ steps:
11
+ - uses: actions/checkout@v2
12
+ - name: Set up Ruby 2.6
13
+ uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6.x
16
+ - name: Build and test with RSpec
17
+ run: |
18
+ gem install bundler
19
+ bundle install --jobs 4 --retry 3
20
+ bundle exec rspec
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ spec/examples.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper --order random --fail-fast --format documentation
@@ -0,0 +1,20 @@
1
+ # The behavior of RuboCop can be controlled via the .rubocop.yml
2
+ # configuration file. It makes it possible to enable/disable
3
+ # certain cops (checks) and to alter their behavior if they accept
4
+ # any parameters. The file can be placed either in your home
5
+ # directory or in some project directory.
6
+ #
7
+ # RuboCop will start looking for the configuration file in the directory
8
+ # where the inspected file is and continue its way up to the root directory.
9
+ #
10
+ # See https://github.com/rubocop-hq/rubocop/blob/master/manual/configuration.md
11
+
12
+ Metrics/BlockLength:
13
+ Exclude:
14
+ - 'Rakefile'
15
+ - '**/*.rake'
16
+ - 'test/**/*.rb'
17
+ - 'spec/**/*.rb'
18
+
19
+ Style/Documentation:
20
+ Enabled: false
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- # Specify your gem's dependencies in cardshark.gemspec
3
+ source 'http://rubygems.org'
4
4
  gemspec
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, cmd: 'bundle exec rspec', failed_mode: :keep do
4
+ require 'guard/rspec/dsl'
5
+ dsl = Guard::RSpec::Dsl.new(self)
6
+
7
+ rspec = dsl.rspec
8
+ watch(rspec.spec_helper) { rspec.spec_dir }
9
+ watch(rspec.spec_support) { rspec.spec_dir }
10
+ watch(rspec.spec_files)
11
+
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
14
+ end
15
+
16
+ rubocop_options = {
17
+ all_on_start: false,
18
+ cli: '--auto-correct --format simple'
19
+ }
20
+ guard :rubocop, rubocop_options do
21
+ watch(/.+\.rb$/)
22
+ watch(%r{(?:.+\/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
23
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011 by John Britton - http://www.johndbritton.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # Cardshark
2
+
3
+ ## Example usage:
4
+
5
+ ```ruby
6
+ require 'cardshark'
7
+
8
+ class Deck < Cardshark::Deck; end
9
+ class Card < Cardshark::Card; end
10
+ class Rank < Cardshark::Dimension; end
11
+ class Suit < Cardshark::Dimension; end
12
+
13
+ ranks = [
14
+ :ace,
15
+ :two,
16
+ :three,
17
+ :four,
18
+ :five,
19
+ :six,
20
+ :seven,
21
+ :eight,
22
+ :nine,
23
+ :ten,
24
+ :jack,
25
+ :queen,
26
+ :king
27
+ ].each do |name|
28
+ Rank.new(name)
29
+ end
30
+
31
+ suits = [
32
+ :clubs,
33
+ :diamonds,
34
+ :hearts,
35
+ :spades
36
+ ].each do |name|
37
+ Suit.new(name)
38
+ end
39
+
40
+ deck = Deck.new do
41
+ cards = []
42
+ Suit.all.each do |suit|
43
+ Rank.all.each do |rank|
44
+ cards << Card.new(rank, suit)
45
+ end
46
+ end
47
+ cards
48
+ end
49
+ ```
data/Rakefile CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler'
2
4
  Bundler::GemHelper.install_tasks
@@ -1,23 +1,30 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "cardshark/version"
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
4
+ require 'cardshark/version'
4
5
 
5
6
  Gem::Specification.new do |s|
6
- s.name = "cardshark"
7
+ s.name = 'cardshark'
7
8
  s.version = Cardshark::VERSION
8
9
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["John Britton - @johndbritton"]
10
- s.email = ["public@johndbritton.com"]
11
- s.homepage = "http://www.johndbritton.com"
12
- s.summary = %q{A library for various types of card decks}
13
- s.description = %q{Supports Canasta, French, Piquet, and Uno Decks}
10
+ s.authors = ['John Britton - @johndbritton']
11
+ s.email = ['public@johndbritton.com']
12
+ s.homepage = 'https://github.com/johndbritton/cardshark'
13
+ s.summary = 'A library for building decks of cards.'
14
+ s.description = 'A library for building decks of cards.'
14
15
 
15
- s.rubyforge_project = "cardshark"
16
+ s.rubyforge_project = 'cardshark'
16
17
 
17
18
  s.files = `git ls-files`.split("\n")
18
19
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
- s.require_paths = ["lib"]
20
+ s.executables = `git ls-files -- bin/*`
21
+ .split("\n")
22
+ .map { |f| File.basename(f) }
23
+ s.require_paths = ['lib']
21
24
 
22
- s.add_development_dependency "rspec", "~> 2.0.0.beta.22"
25
+ s.add_development_dependency 'guard-rspec', '~> 4.7.3'
26
+ s.add_development_dependency 'guard-rubocop', '~>1.3.0'
27
+ s.add_development_dependency 'rspec', '~> 3.9.0'
28
+ s.add_development_dependency 'rubocop', '~> 0.79.0'
29
+ s.add_development_dependency 'terminal-notifier-guard', '~> 1.7.0'
23
30
  end
@@ -1,3 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/card'
4
+ require 'cardshark/deck'
5
+ require 'cardshark/dimension'
6
+ require 'cardshark/error'
7
+ require 'cardshark/version'
8
+
1
9
  module Cardshark
2
- # Your code goes here...
3
10
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/error'
4
+
5
+ module Cardshark
6
+ module Abstract
7
+ def self.included(base)
8
+ base.instance_variable_set(:@abstract, true)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def new(*)
14
+ if instance_variable_defined?(:@abstract)
15
+ if instance_variable_get(:@abstract) == true
16
+ raise Error::AbstractClass
17
+ end
18
+ end
19
+
20
+ super
21
+ end
22
+
23
+ private
24
+
25
+ def inherited(subclass)
26
+ subclass.instance_variable_set(:@abstract, false)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,10 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/dimension'
4
+
1
5
  module Cardshark
2
6
  class Card
3
- attr_reader :rank, :suit
4
- def initialize(card)
5
- @rank = card[:rank]
6
- @suit = card[:suit]
7
- self.freeze
7
+ def initialize(*args)
8
+ validate_arguments(args)
9
+
10
+ @dimensions = {}
11
+ args.each { |arg| @dimensions[arg.class.id] = arg }
12
+ define_dimension_methods
13
+ end
14
+
15
+ def dimensions
16
+ @dimensions.keys
17
+ end
18
+
19
+ private
20
+
21
+ def define_dimension_methods
22
+ @dimensions.keys.each do |dimension|
23
+ define_singleton_method dimension do
24
+ @dimensions[dimension]
25
+ end
26
+ end
27
+ end
28
+
29
+ def validate_arguments(args)
30
+ raise ArgumentError if args.empty?
31
+ raise ArgumentError if args.detect { |arg| !arg.is_a?(Dimension) }
32
+ raise ArgumentError unless args.uniq(&:class).count == args.count
8
33
  end
9
34
  end
10
- end
35
+ end
@@ -1,33 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/error'
4
+
1
5
  module Cardshark
2
- module Deck
3
- def size
4
- @cards.size
6
+ class Deck
7
+ def initialize(&block)
8
+ raise ArgumentError if block.nil?
9
+
10
+ @deck_order = nil
11
+ @draw_position = 0
12
+ @cards = yield || []
13
+
14
+ @cards.each do |card|
15
+ raise ArgumentError if card.class.is_a?(Card)
16
+ end
5
17
  end
6
-
7
- def cards
8
- @cards
18
+
19
+ def draw
20
+ raise Error::DeckExhausted if draw_position >= cards.count
21
+
22
+ card = cards[deck_order[draw_position]]
23
+ @draw_position += 1
24
+ card
9
25
  end
10
-
11
- def shuffle!
12
- @cards.shuffle!
13
- @shuffled = true
26
+
27
+ def count
28
+ cards.count
14
29
  end
15
-
30
+
16
31
  def shuffled?
17
- return false unless @shuffled
18
- true
19
- end
20
-
21
- # Helper method that builds cards
22
- def create_cards(suits, ranks)
23
- created_cards = Array.new
24
- suits.each do |suit|
25
- ranks.each do |rank|
26
- created_cards.push Card.new(:rank => rank, :suit => suit)
27
- end
32
+ !@deck_order.nil?
33
+ end
34
+
35
+ def shuffle!(mapping)
36
+ raise Error::DeckAlreadyShuffled if shuffled?
37
+
38
+ validate_mapping(mapping)
39
+
40
+ @deck_order = mapping
41
+
42
+ self
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :cards, :draw_position
48
+
49
+ def deck_order
50
+ return @deck_order unless @deck_order.nil?
51
+
52
+ count.times.collect { |i| i }
53
+ end
54
+
55
+ def validate_mapping(mapping)
56
+ ensure_mapping_is_array(mapping)
57
+ ensure_mapping_is_correct_arity(mapping)
58
+ ensure_mapping_is_correct_type(mapping)
59
+ ensure_mapping_elements_in_bounds(mapping)
60
+ end
61
+
62
+ def ensure_mapping_is_array(mapping)
63
+ raise ArgumentError if mapping.class != Array
64
+ end
65
+
66
+ def ensure_mapping_is_correct_arity(mapping)
67
+ raise Error::DeckOrderInvalid if mapping.count != count
68
+ end
69
+
70
+ def ensure_mapping_is_correct_type(mapping)
71
+ raise Error::DeckOrderInvalid if mapping.detect { |i| i.class != Integer }
72
+ end
73
+
74
+ def ensure_mapping_elements_in_bounds(mapping)
75
+ raise Error::DeckOrderInvalid if mapping.detect do |i|
76
+ i.negative? || i >= count
28
77
  end
29
- created_cards
30
78
  end
31
-
32
79
  end
33
- end
80
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cardshark/abstract'
4
+ require 'cardshark/error'
5
+
6
+ module Cardshark
7
+ class Dimension
8
+ include Abstract
9
+
10
+ def self.new(id)
11
+ raise ArgumentError if id.class != Symbol
12
+
13
+ if instances[id].nil?
14
+ instances[id] = super
15
+ else
16
+ instances[id]
17
+ end
18
+ end
19
+
20
+ def self.all
21
+ instances.values
22
+ end
23
+
24
+ def self.id
25
+ if name.nil?
26
+ object_id.to_s.downcase.to_sym
27
+ else
28
+ name.split('::').last.gsub(/(.)([A-Z])/, '\1_\2').downcase.to_sym
29
+ end
30
+ end
31
+
32
+ def initialize(id)
33
+ @id = id
34
+ end
35
+
36
+ def to_s
37
+ id.to_s.capitalize
38
+ end
39
+
40
+ private
41
+
42
+ class << self
43
+ private
44
+
45
+ def instances
46
+ @instances ||= {}
47
+ end
48
+ attr_writer :instances
49
+ end
50
+
51
+ attr_accessor :id
52
+
53
+ def inherited(_subclass)
54
+ raise Error::DimensionInheritanceLimit
55
+ end
56
+ end
57
+ end