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,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