From b8b6ed66045ec11169e5d51c82d741d8b0bd333d Mon Sep 17 00:00:00 2001 From: mechetel Date: Tue, 23 Feb 2021 16:41:21 +0200 Subject: [PATCH 01/63] change setup --- .circleci/config.yml | 70 ++++++++++++++++++-- .fasterer.yml | 22 +++++++ .rubocop.yml | 32 +++++++-- .ruby-version | 1 + Gemfile | 10 +-- Gemfile.lock | 132 +++++++++++++++++++++++++++++++++++++ Rakefile | 8 +-- bin/console | 7 +- codebreaker.gemspec | 27 ++++---- lib/codebreaker.rb | 4 +- lib/codebreaker/version.rb | 4 +- spec/codebreaker_spec.rb | 6 +- spec/spec_helper.rb | 17 +++-- 13 files changed, 279 insertions(+), 61 deletions(-) create mode 100644 .fasterer.yml create mode 100644 .ruby-version create mode 100644 Gemfile.lock diff --git a/.circleci/config.yml b/.circleci/config.yml index 75e45da..fa43b0c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,13 +1,69 @@ version: 2.1 -jobs: - build: + +executors: + default: + working_directory: ~/repo + description: The official CircleCI Ruby Docker image docker: - - image: ruby:2.4.2 + - image: circleci/ruby:2.7.2 + +caches: + - &bundle_cache_full v2-repo-{{ checksum "Gemfile.lock" }} + - &bundle_cache v2-repo- + +commands: + defaults: steps: - checkout + - restore_cache: + keys: + - *bundle_cache_full + - *bundle_cache + - run: bundle install --path vendor/bundle + - save_cache: + key: *bundle_cache_full + paths: + - vendor/bundle + run_linters: + description: command to start linters + steps: + - run: + name: rubocop + command: bundle exec rubocop + - run: + name: fasterer + command: bundle exec fasterer + run_specs: + steps: - run: - name: Run the default task + name: run specs command: | - gem install bundler -v 2.2.4 - bundle install - bundle exec rake + mkdir /tmp/test-results + TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)" + bundle exec rspec --format progress \ + --out /tmp/test-results/rspec.xml \ + $TEST_FILES + - store_artifacts: + path: ~/repo/coverage + destination: coverage + +jobs: + lintering: + executor: default + steps: + - defaults + - run_linters + run_specs: + executor: default + steps: + - defaults + - run_specs + +workflows: + version: 2.1 + build: + jobs: + - lintering + - run_specs: + requires: + - lintering diff --git a/.fasterer.yml b/.fasterer.yml new file mode 100644 index 0000000..9641667 --- /dev/null +++ b/.fasterer.yml @@ -0,0 +1,22 @@ +speedups: + rescue_vs_respond_to: true + module_eval: true + shuffle_first_vs_sample: true + for_loop_vs_each: true + each_with_index_vs_while: false + map_flatten_vs_flat_map: true + reverse_each_vs_reverse_each: true + select_first_vs_detect: true + sort_vs_sort_by: true + fetch_with_argument_vs_block: true + keys_each_vs_each_key: true + hash_merge_bang_vs_hash_brackets: true + block_vs_symbol_to_proc: true + proc_call_vs_yield: true + gsub_vs_tr: true + select_last_vs_reverse_detect: true + getter_vs_attr_reader: true + setter_vs_attr_writer: true + +exclude_paths: + - 'vendor/**/*.rb' diff --git a/.rubocop.yml b/.rubocop.yml index 00a72e3..a94e0f7 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,10 +1,30 @@ -Style/StringLiterals: - Enabled: true - EnforcedStyle: double_quotes +require: + - rubocop-performance + - rubocop-rspec -Style/StringLiteralsInInterpolation: - Enabled: true - EnforcedStyle: double_quotes +AllCops: + NewCops: enable + Exclude: + - 'codebreaker.gemspec' + - 'vendor/bundle/**/*' + +Metrics/BlockLength: + Exclude: + - 'spec/codebreaker/**/*' + +Metrics/ModuleLength: + Exclude: + - 'spec/codebreaker/**/*' + +Lint/AmbiguousBlockAssociation: + Exclude: + - 'spec/codebreaker/**/*' + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/Documentation: + Enabled: false Layout/LineLength: Max: 120 diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile index 241197e..3fac2ed 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,4 @@ -# frozen_string_literal: true - -source "https://rubygems.org" +source 'https://rubygems.org' # Specify your gem's dependencies in codebreaker.gemspec gemspec - -gem "rake", "~> 13.0" - -gem "rspec", "~> 3.0" - -gem "rubocop", "~> 0.80" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..8b4b3f3 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,132 @@ +PATH + remote: . + specs: + codebreaker (0.1.0) + +GEM + remote: https://rubygems.org/ + specs: + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + ast (2.4.2) + axiom-types (0.1.1) + descendants_tracker (~> 0.0.4) + ice_nine (~> 0.11.0) + thread_safe (~> 0.3, >= 0.3.1) + coercible (1.0.0) + descendants_tracker (~> 0.0.1) + colorize (0.8.1) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) + diff-lcs (1.4.4) + docile (1.3.5) + equalizer (0.0.11) + erubis (2.7.0) + fasterer (0.9.0) + colorize (~> 0.7) + ruby_parser (>= 3.14.1) + flay (2.12.1) + erubis (~> 2.7.0) + path_expander (~> 1.0) + ruby_parser (~> 3.0) + sexp_processor (~> 4.0) + flog (4.6.4) + path_expander (~> 1.0) + ruby_parser (~> 3.1, > 3.1.0) + sexp_processor (~> 4.8) + ice_nine (0.11.2) + kwalify (0.7.2) + launchy (2.5.0) + addressable (~> 2.7) + parallel (1.20.1) + parser (3.0.0.0) + ast (~> 2.4.1) + path_expander (1.1.0) + psych (3.3.0) + public_suffix (4.0.6) + rainbow (3.0.0) + rake (13.0.3) + reek (6.0.3) + kwalify (~> 0.7.0) + parser (~> 3.0.0) + psych (~> 3.1) + rainbow (>= 2.0, < 4.0) + regexp_parser (2.1.0) + rexml (3.2.4) + rspec (3.10.0) + rspec-core (~> 3.10.0) + rspec-expectations (~> 3.10.0) + rspec-mocks (~> 3.10.0) + rspec-core (3.10.1) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.10.0) + rspec-mocks (3.10.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.10.0) + rspec-support (3.10.2) + rubocop (1.10.0) + parallel (~> 1.10) + parser (>= 3.0.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.2.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.4.1) + parser (>= 2.7.1.5) + rubocop-performance (1.9.2) + rubocop (>= 0.90.0, < 2.0) + rubocop-ast (>= 0.4.0) + rubocop-rspec (2.2.0) + rubocop (~> 1.0) + rubocop-ast (>= 1.1.0) + ruby-progressbar (1.11.0) + ruby_parser (3.15.1) + sexp_processor (~> 4.9) + rubycritic (4.6.0) + flay (~> 2.8) + flog (~> 4.4) + launchy (>= 2.0.0) + parser (>= 2.6.0) + rainbow (~> 3.0) + reek (~> 6.0, < 7.0) + ruby_parser (~> 3.8) + simplecov (>= 0.17.0, < 0.21) + tty-which (~> 0.4.0) + virtus (~> 1.0) + sexp_processor (4.15.2) + simplecov (0.20.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.2) + thread_safe (0.3.6) + tty-which (0.4.2) + unicode-display_width (2.0.0) + virtus (1.0.5) + axiom-types (~> 0.1) + coercible (~> 1.0) + descendants_tracker (~> 0.0, >= 0.0.3) + equalizer (~> 0.0, >= 0.0.9) + +PLATFORMS + ruby + x86_64-darwin-20 + +DEPENDENCIES + codebreaker! + fasterer + rake + rspec + rubocop + rubocop-performance + rubocop-rspec + rubycritic + simplecov + +BUNDLED WITH + 2.2.3 diff --git a/Rakefile b/Rakefile index cca7175..85b3874 100644 --- a/Rakefile +++ b/Rakefile @@ -1,11 +1,9 @@ -# frozen_string_literal: true - -require "bundler/gem_tasks" -require "rspec/core/rake_task" +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) -require "rubocop/rake_task" +require 'rubocop/rake_task' RuboCop::RakeTask.new diff --git a/bin/console b/bin/console index a3c76e4..7654e6c 100755 --- a/bin/console +++ b/bin/console @@ -1,8 +1,7 @@ #!/usr/bin/env ruby -# frozen_string_literal: true -require "bundler/setup" -require "codebreaker" +require 'bundler/setup' +require 'codebreaker' # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. @@ -11,5 +10,5 @@ require "codebreaker" # require "pry" # Pry.start -require "irb" +require 'irb' IRB.start(__FILE__) diff --git a/codebreaker.gemspec b/codebreaker.gemspec index f1050ea..93de943 100644 --- a/codebreaker.gemspec +++ b/codebreaker.gemspec @@ -1,5 +1,3 @@ -# frozen_string_literal: true - require_relative "lib/codebreaker/version" Gem::Specification.new do |spec| @@ -8,29 +6,34 @@ Gem::Specification.new do |spec| spec.authors = ["mechetel"] spec.email = ["dima.homa5@gmail.com"] - spec.summary = "TODO: Write a short summary, because RubyGems requires one." - spec.description = "TODO: Write a longer description or delete this line." - spec.homepage = "TODO: Put your gem's website or public repo URL here." + spec.summary = 'Codebreaker game' + spec.description = 'Second rubygarage task' + spec.homepage = 'https://github.com/mechetel/codebreaker' spec.license = "MIT" - spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0") - - spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" + spec.required_ruby_version = Gem::Requirement.new(">= 2.7.2") spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." - spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." + spec.metadata["source_code_uri"] = "https://github.com/mechetel/codebreaker" # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) } end - spec.bindir = "exe" + spec.bindir = 'exe' spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } - spec.require_paths = ["lib"] + spec.require_paths = ['lib'] # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0" + spec.add_development_dependency 'rake' + spec.add_development_dependency 'fasterer' + spec.add_development_dependency 'rspec' + spec.add_development_dependency 'rubocop' + spec.add_development_dependency 'rubocop-performance' + spec.add_development_dependency 'rubocop-rspec' + spec.add_development_dependency 'rubycritic' + spec.add_development_dependency 'simplecov' # For more information and examples about making a new gem, checkout our # guide at: https://bundler.io/guides/creating_gem.html diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index dd39b2d..26a27a0 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -1,6 +1,4 @@ -# frozen_string_literal: true - -require_relative "codebreaker/version" +require_relative 'codebreaker/version' module Codebreaker class Error < StandardError; end diff --git a/lib/codebreaker/version.rb b/lib/codebreaker/version.rb index 8a35c43..98e7d70 100644 --- a/lib/codebreaker/version.rb +++ b/lib/codebreaker/version.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module Codebreaker - VERSION = "0.1.0" + VERSION = '0.1.0'.freeze end diff --git a/spec/codebreaker_spec.rb b/spec/codebreaker_spec.rb index 49eae29..87fddd2 100644 --- a/spec/codebreaker_spec.rb +++ b/spec/codebreaker_spec.rb @@ -1,11 +1,7 @@ # frozen_string_literal: true RSpec.describe Codebreaker do - it "has a version number" do + it 'has a version number' do expect(Codebreaker::VERSION).not_to be nil end - - it "does something useful" do - expect(false).to eq(true) - end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6827d7b..f1d1539 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,12 +1,15 @@ -# frozen_string_literal: true - -require "codebreaker" +require 'simplecov' +SimpleCov.start do + enable_coverage :branch + add_filter 'spec/' +end +SimpleCov.minimum_coverage 95 +require 'bundler/setup' +require 'codebreaker' RSpec.configure do |config| - # Enable flags like --only-failures and --next-failure - config.example_status_persistence_file_path = ".rspec_status" - - # Disable RSpec exposing methods globally on `Module` and `main` + config.example_status_persistence_file_path = '.rspec_status' + config.filter_run_when_matching :focus config.disable_monkey_patching! config.expect_with :rspec do |c| From 4f8c83521c23f76a19a9ccdec33a9e5008db5ee4 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 25 Feb 2021 23:52:02 +0200 Subject: [PATCH 02/63] add entities like player, game, difficulty --- lib/codebreaker.rb | 2 -- lib/codebreaker/entities/difficulties.rb | 21 +++++++++++++++++++++ lib/codebreaker/entities/game.rb | 21 +++++++++++++++++++++ lib/codebreaker/entities/player.rb | 9 +++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 lib/codebreaker/entities/difficulties.rb create mode 100644 lib/codebreaker/entities/game.rb create mode 100644 lib/codebreaker/entities/player.rb diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index 26a27a0..6d43374 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -1,6 +1,4 @@ require_relative 'codebreaker/version' module Codebreaker - class Error < StandardError; end - # Your code goes here... end diff --git a/lib/codebreaker/entities/difficulties.rb b/lib/codebreaker/entities/difficulties.rb new file mode 100644 index 0000000..026666d --- /dev/null +++ b/lib/codebreaker/entities/difficulties.rb @@ -0,0 +1,21 @@ +module Codebreaker + class Difficulty + DIFFICULTIES = { easy: { attempts: 15, hints: 2 }, + medium: { attempts: 10, hints: 1 }, + hell: { attempts: 5, hints: 1 } }.freeze + + attr_reader :difficulty + + def initialize(difficulty) + @difficulty = difficulty.to_sym + end + + def attempts + DIFFICULTIES[@difficulty][:attempts] + end + + def hints + DIFFICULTIES[@difficulty][:hints] + end + end +end diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb new file mode 100644 index 0000000..4f010b3 --- /dev/null +++ b/lib/codebreaker/entities/game.rb @@ -0,0 +1,21 @@ +module Codebreaker + class Game + SECRET_CODE_SIZE = 4 + SECRET_CODE_RANGE = (1..6).freeze + attr_reader :secret_code, :hints, :hint_number, :attempts, :player, :result, :difficulty + + def initialize(player, difficulty) + @player = player + @difficulty = difficulty + @attempts = difficulty.attempts + @hints = difficulty.hints + @secret_code = generate_secret_code + @hint_number = @secret_code.clone + end + + private + + def generate_secret_code + Array.new(SECRET_CODE_SIZE) { rand(SECRET_CODE_RANGE) } + end end +end diff --git a/lib/codebreaker/entities/player.rb b/lib/codebreaker/entities/player.rb new file mode 100644 index 0000000..c4f2ba1 --- /dev/null +++ b/lib/codebreaker/entities/player.rb @@ -0,0 +1,9 @@ +module Codebreaker + class Player + attr_reader :name + + def initialize(name) + @name = name + end + end +end From a2ad60ace23cfe4c64cdc98655c7578c093854f6 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 25 Feb 2021 23:56:29 +0200 Subject: [PATCH 03/63] refactor by rubocop --- lib/codebreaker/entities/game.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 4f010b3..b677a50 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -17,5 +17,6 @@ def initialize(player, difficulty) def generate_secret_code Array.new(SECRET_CODE_SIZE) { rand(SECRET_CODE_RANGE) } - end end + end + end end From 4f5f9bb1ec80f82abb79f04ffb33b6b1142a5acc Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 4 Mar 2021 16:09:58 +0200 Subject: [PATCH 04/63] add validations in class --- .../{difficulties.rb => difficulty.rb} | 16 +++++++++-- lib/codebreaker/entities/game.rb | 19 ++++++++++++- lib/codebreaker/entities/player.rb | 28 ++++++++++++++++++- lib/codebreaker/modules/validator.rb | 8 ++++++ 4 files changed, 67 insertions(+), 4 deletions(-) rename lib/codebreaker/entities/{difficulties.rb => difficulty.rb} (62%) create mode 100644 lib/codebreaker/modules/validator.rb diff --git a/lib/codebreaker/entities/difficulties.rb b/lib/codebreaker/entities/difficulty.rb similarity index 62% rename from lib/codebreaker/entities/difficulties.rb rename to lib/codebreaker/entities/difficulty.rb index 026666d..a7a1c90 100644 --- a/lib/codebreaker/entities/difficulties.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -1,13 +1,15 @@ module Codebreaker class Difficulty + include Validator + attr_reader :difficulty, :errors + DIFFICULTIES = { easy: { attempts: 15, hints: 2 }, medium: { attempts: 10, hints: 1 }, hell: { attempts: 5, hints: 1 } }.freeze - attr_reader :difficulty - def initialize(difficulty) @difficulty = difficulty.to_sym + @errors = [] end def attempts @@ -17,5 +19,15 @@ def attempts def hints DIFFICULTIES[@difficulty][:hints] end + + private + + def validate! + validate_difficulty + end + + def validate_difficulty + errors << DifficultyError unless DIFFICULTIES_LIST.include? difficulty + end end end diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index b677a50..def4b6d 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -1,8 +1,11 @@ module Codebreaker class Game + include Validator + SECRET_CODE_SIZE = 4 SECRET_CODE_RANGE = (1..6).freeze - attr_reader :secret_code, :hints, :hint_number, :attempts, :player, :result, :difficulty + + attr_reader :secret_code, :hints, :hint_number, :attempts, :player, :result, :difficulty, :errors def initialize(player, difficulty) @player = player @@ -11,6 +14,7 @@ def initialize(player, difficulty) @hints = difficulty.hints @secret_code = generate_secret_code @hint_number = @secret_code.clone + @errors = [] end private @@ -18,5 +22,18 @@ def initialize(player, difficulty) def generate_secret_code Array.new(SECRET_CODE_SIZE) { rand(SECRET_CODE_RANGE) } end + + def validate! + validate_player + validate_difficulty if errors.empty? + end + + def validate_player + errors << ExpectedPlayerInstanceError unless user.class == Codebreaker::Player + end + + def validate_difficulty + errors << ExpectedDifficultyInstanceError unless difficulty.class == Codebreaker::Difficulty + end end end diff --git a/lib/codebreaker/entities/player.rb b/lib/codebreaker/entities/player.rb index c4f2ba1..fe99cba 100644 --- a/lib/codebreaker/entities/player.rb +++ b/lib/codebreaker/entities/player.rb @@ -1,9 +1,35 @@ module Codebreaker class Player - attr_reader :name + include Validator + attr_reader :name,:errors + + NAME_MIN_LENGTH = 3 + NAME_MAX_LENGTH = 20 def initialize(name) @name = name + @errors = [] + end + + private + + def validate! + validate_name_class + validate_name_min_length if errors.empty? + validate_name_max_length if errors.empty? + end + + def validate_name_class + errors << NameIsNotStringError unless name.is_a? String end + + def validate_name_min_length + errors << ShortNameError if name.length < NAME_MIN_LENGTH + end + + def validate_name_max_length + errors << LongNameError if name.length > NAME_MAX_LENGTH + end + end end diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb new file mode 100644 index 0000000..5d4faac --- /dev/null +++ b/lib/codebreaker/modules/validator.rb @@ -0,0 +1,8 @@ +module Codebreaker + module Validator + def valid? + validate! + @errors.empty? + end + end +end From d7aa03b0e52c5fc6bb645e34835e2536329a80b9 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 5 Mar 2021 14:45:17 +0200 Subject: [PATCH 05/63] end gem with no specs --- lib/codebreaker/entities/difficulty.rb | 5 +- lib/codebreaker/entities/game.rb | 61 ++++++++++++++----- lib/codebreaker/entities/guess_checker.rb | 24 ++++++++ .../entities/{player.rb => user.rb} | 5 +- lib/codebreaker/errors/difficulty_error.rb | 9 +++ lib/codebreaker/errors/digit_range_error.rb | 9 +++ lib/codebreaker/errors/digits_count_error.rb | 9 +++ .../expected_difficulty_instance_error.rb | 9 +++ .../errors/expected_user_instance_error.rb | 9 +++ lib/codebreaker/errors/long_name_error.rb | 9 +++ .../errors/name_is_not_string_error.rb | 9 +++ lib/codebreaker/errors/short_name_error.rb | 9 +++ .../services/statistics_service.rb | 41 +++++++++++++ 13 files changed, 188 insertions(+), 20 deletions(-) create mode 100644 lib/codebreaker/entities/guess_checker.rb rename lib/codebreaker/entities/{player.rb => user.rb} (93%) create mode 100644 lib/codebreaker/errors/difficulty_error.rb create mode 100644 lib/codebreaker/errors/digit_range_error.rb create mode 100644 lib/codebreaker/errors/digits_count_error.rb create mode 100644 lib/codebreaker/errors/expected_difficulty_instance_error.rb create mode 100644 lib/codebreaker/errors/expected_user_instance_error.rb create mode 100644 lib/codebreaker/errors/long_name_error.rb create mode 100644 lib/codebreaker/errors/name_is_not_string_error.rb create mode 100644 lib/codebreaker/errors/short_name_error.rb create mode 100644 lib/codebreaker/services/statistics_service.rb diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index a7a1c90..fe81d91 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -1,15 +1,14 @@ module Codebreaker class Difficulty include Validator - attr_reader :difficulty, :errors DIFFICULTIES = { easy: { attempts: 15, hints: 2 }, medium: { attempts: 10, hints: 1 }, hell: { attempts: 5, hints: 1 } }.freeze + attr_reader :difficulty def initialize(difficulty) @difficulty = difficulty.to_sym - @errors = [] end def attempts @@ -27,7 +26,7 @@ def validate! end def validate_difficulty - errors << DifficultyError unless DIFFICULTIES_LIST.include? difficulty + errors << DifficultyError unless DIFFICULTIES_LIST.include? kind end end end diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index def4b6d..a63acf7 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -1,39 +1,72 @@ module Codebreaker class Game include Validator + attr_reader :user, :difficulty, :secret_code, :errors, :date, :hints_list - SECRET_CODE_SIZE = 4 - SECRET_CODE_RANGE = (1..6).freeze + MIN_CODE_NUM = 1 + MAX_CODE_NUM = 6 + DIGITS_NUM = 4 - attr_reader :secret_code, :hints, :hint_number, :attempts, :player, :result, :difficulty, :errors - - def initialize(player, difficulty) - @player = player + def initialize(user, difficulty) + @user = user @difficulty = difficulty - @attempts = difficulty.attempts - @hints = difficulty.hints + @attempts = @difficulty.attempts + @hints = @difficulty.hints @secret_code = generate_secret_code - @hint_number = @secret_code.clone + @hints_list = secret_code.clone @errors = [] + @date = Time.now.getlocal + end + + def use_hint + @hints -= 1 + index = rand(hints_list.size) + digit = hints_list[index] + hints_list.delete_at index + digit + end + + def check_attempt(guess) + @attempts -= 1 + GuessChecker.new(@secret_code.clone, guess).check + end + + def new_game + @secret_code = generate_secret_code + @hints_list = @secret_code.clone + @attempts = @difficulty.attempts.clone + @hints = @difficulty.hints.clone + end + + def lose? + difficulty.current_attempts.zero? + end + + def win?(user_code) + user_code == secret_code.join + end + + def no_hints? + difficulty.current_hints.zero? end private def generate_secret_code - Array.new(SECRET_CODE_SIZE) { rand(SECRET_CODE_RANGE) } + Array.new(DIGITS_NUM) { rand(MIN_CODE_NUM..MAX_CODE_NUM) }.join end def validate! - validate_player + validate_user validate_difficulty if errors.empty? end - def validate_player - errors << ExpectedPlayerInstanceError unless user.class == Codebreaker::Player + def validate_user + errors << ExpectedUserInstanceError unless user.instance_of?(Codebreaker::User) end def validate_difficulty - errors << ExpectedDifficultyInstanceError unless difficulty.class == Codebreaker::Difficulty + errors << ExpectedDifficultyInstanceError unless difficulty.instance_of?(Codebreaker::Difficulty) end end end diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb new file mode 100644 index 0000000..08675b2 --- /dev/null +++ b/lib/codebreaker/entities/guess_checker.rb @@ -0,0 +1,24 @@ +module Codebreaker + class GuessChecker + RIGHT_ANSWER_SYMBOL = '+'.freeze + WRONG_ANSWER_SYMBOL = '-'.freeze + attr_reader :secret_code, :user_code + + def initialize(code, input) + @secret_code = code + @user_input = input + end + + def check + answer = [] + @user_input.each_char.each_with_index do |digit, index| + if @secret_code[index] == digit + answer.push RIGHT_ANSWER_SYMBOL + elsif @secret_code.include? digit + answer.push WRONG_ANSWER_SYMBOL + end + end + answer.sort.join + end + end +end diff --git a/lib/codebreaker/entities/player.rb b/lib/codebreaker/entities/user.rb similarity index 93% rename from lib/codebreaker/entities/player.rb rename to lib/codebreaker/entities/user.rb index fe99cba..da6f9a0 100644 --- a/lib/codebreaker/entities/player.rb +++ b/lib/codebreaker/entities/user.rb @@ -1,7 +1,7 @@ module Codebreaker - class Player + class User include Validator - attr_reader :name,:errors + attr_reader :name, :errors NAME_MIN_LENGTH = 3 NAME_MAX_LENGTH = 20 @@ -30,6 +30,5 @@ def validate_name_min_length def validate_name_max_length errors << LongNameError if name.length > NAME_MAX_LENGTH end - end end diff --git a/lib/codebreaker/errors/difficulty_error.rb b/lib/codebreaker/errors/difficulty_error.rb new file mode 100644 index 0000000..141ed19 --- /dev/null +++ b/lib/codebreaker/errors/difficulty_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class DifficultyError < StandardError + def message + 'No such difficulty' + end + end +end diff --git a/lib/codebreaker/errors/digit_range_error.rb b/lib/codebreaker/errors/digit_range_error.rb new file mode 100644 index 0000000..df4bbd7 --- /dev/null +++ b/lib/codebreaker/errors/digit_range_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class DigitRangeError < StandardError + def message + 'Digit is not in a range' + end + end +end diff --git a/lib/codebreaker/errors/digits_count_error.rb b/lib/codebreaker/errors/digits_count_error.rb new file mode 100644 index 0000000..971f1e9 --- /dev/null +++ b/lib/codebreaker/errors/digits_count_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class DigitsCountError < StandardError + def message + 'Invalid digits count' + end + end +end diff --git a/lib/codebreaker/errors/expected_difficulty_instance_error.rb b/lib/codebreaker/errors/expected_difficulty_instance_error.rb new file mode 100644 index 0000000..00d8017 --- /dev/null +++ b/lib/codebreaker/errors/expected_difficulty_instance_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class ExpectedDifficultyInstanceError < StandardError + def message + 'Object should be an instance of Difficulty class' + end + end +end diff --git a/lib/codebreaker/errors/expected_user_instance_error.rb b/lib/codebreaker/errors/expected_user_instance_error.rb new file mode 100644 index 0000000..8b062a9 --- /dev/null +++ b/lib/codebreaker/errors/expected_user_instance_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class ExpectedUserInstanceError < StandardError + def message + 'Object should be an instance of User class' + end + end +end diff --git a/lib/codebreaker/errors/long_name_error.rb b/lib/codebreaker/errors/long_name_error.rb new file mode 100644 index 0000000..7a412ef --- /dev/null +++ b/lib/codebreaker/errors/long_name_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class LongNameError < StandardError + def message + 'Name is too long' + end + end +end diff --git a/lib/codebreaker/errors/name_is_not_string_error.rb b/lib/codebreaker/errors/name_is_not_string_error.rb new file mode 100644 index 0000000..0694687 --- /dev/null +++ b/lib/codebreaker/errors/name_is_not_string_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class NameIsNotStringError < StandardError + def message + 'Name should be an instance of String' + end + end +end diff --git a/lib/codebreaker/errors/short_name_error.rb b/lib/codebreaker/errors/short_name_error.rb new file mode 100644 index 0000000..b10ad4f --- /dev/null +++ b/lib/codebreaker/errors/short_name_error.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Codebreaker + class ShortNameError < StandardError + def message + 'Name is too short' + end + end +end diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb new file mode 100644 index 0000000..2b28e8f --- /dev/null +++ b/lib/codebreaker/services/statistics_service.rb @@ -0,0 +1,41 @@ +module Codebreaker + class StatisticsService + attr_reader :game, :path + + def initialize(path) + @path = path + end + + def store(game) + statistics = File.exist?(path) && !File.zero?(path) ? YAML.load_file(path) : [] + statistics << pack_game_data(game) + file = File.open(path, 'w') + file.write(statistics.to_yaml) + file.close + end + + def sort_statistics + load.sort_by { |user| [user[:attempts_total], user[:attempts_used], user[:hints_used]] } + end + + def load + return unless File.exist? path + + YAML.load_file path + end + + private + + def game_to_h(game) + { + name: game.user.name, + difficulty: game.difficulty.defficulty.to_s, + attempts_total: game.difficulty.attempts, + attempts_used: game.difficulty.attempts - game.attempts, + hints_total: game.hints, + hints_used: game.difficulty.hints - game.hints, + date: game.date + } + end + end +end From 8aec67fa2b0f4643c4e97aa614e3ba7ba4d9d17d Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 5 Mar 2021 15:54:51 +0200 Subject: [PATCH 06/63] add libs to require --- lib/codebreaker.rb | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index 6d43374..e853244 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -1,4 +1,21 @@ require_relative 'codebreaker/version' -module Codebreaker -end +require 'yaml' + +require_relative 'codebreaker/errors/name_is_not_string_error' +require_relative 'codebreaker/errors/short_name_error' +require_relative 'codebreaker/errors/long_name_error' +require_relative 'codebreaker/errors/difficulty_error' +require_relative 'codebreaker/errors/digit_range_error' +require_relative 'codebreaker/errors/digits_count_error' +require_relative 'codebreaker/errors/expected_difficulty_instance_error' +require_relative 'codebreaker/errors/expected_user_instance_error' + +require_relative 'codebreaker/modules/validator' + +require_relative 'codebreaker/services/statistics_service' + +require_relative 'codebreaker/entities/difficulty' +require_relative 'codebreaker/entities/game' +require_relative 'codebreaker/entities/guess_checker' +require_relative 'codebreaker/entities/user' From 2cf9d87d8eff5f4815fe9c548e333d48c76ed0bb Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 5 Mar 2021 16:10:06 +0200 Subject: [PATCH 07/63] fix naming error --- lib/codebreaker/entities/difficulty.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index fe81d91..5b9241d 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -26,7 +26,7 @@ def validate! end def validate_difficulty - errors << DifficultyError unless DIFFICULTIES_LIST.include? kind + errors << DifficultyError unless DIFFICULTIES.include? kind end end end From 136d1f50ea3bf17757416f3869d27e9e722492c0 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 5 Mar 2021 16:13:43 +0200 Subject: [PATCH 08/63] refactor naming difficulty to level --- lib/codebreaker/entities/difficulty.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 5b9241d..1f66c9a 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -5,18 +5,18 @@ class Difficulty DIFFICULTIES = { easy: { attempts: 15, hints: 2 }, medium: { attempts: 10, hints: 1 }, hell: { attempts: 5, hints: 1 } }.freeze - attr_reader :difficulty + attr_reader :level - def initialize(difficulty) - @difficulty = difficulty.to_sym + def initialize(level) + @level = level.to_sym end def attempts - DIFFICULTIES[@difficulty][:attempts] + DIFFICULTIES[@level][:attempts] end def hints - DIFFICULTIES[@difficulty][:hints] + DIFFICULTIES[@level][:hints] end private @@ -26,7 +26,6 @@ def validate! end def validate_difficulty - errors << DifficultyError unless DIFFICULTIES.include? kind - end + errors << DifficultyError unless DIFFICULTIES.include? @level end end From 623636afbb4447186f112e9b04636520f44e47c9 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 5 Mar 2021 16:15:02 +0200 Subject: [PATCH 09/63] fix --- lib/codebreaker/entities/difficulty.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 1f66c9a..1b04ec5 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -27,5 +27,6 @@ def validate! def validate_difficulty errors << DifficultyError unless DIFFICULTIES.include? @level + end end end From 67da80b60e2efc5d0b8d5d77ea6a3e63e7ab3bd6 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 5 Mar 2021 16:24:33 +0200 Subject: [PATCH 10/63] delete useless validations --- lib/codebreaker/errors/difficulty_error.rb | 2 -- lib/codebreaker/errors/digit_range_error.rb | 9 --------- lib/codebreaker/errors/digits_count_error.rb | 9 --------- .../errors/expected_difficulty_instance_error.rb | 2 -- lib/codebreaker/errors/expected_user_instance_error.rb | 2 -- lib/codebreaker/errors/long_name_error.rb | 2 -- lib/codebreaker/errors/name_is_not_string_error.rb | 2 -- lib/codebreaker/errors/short_name_error.rb | 2 -- 8 files changed, 30 deletions(-) delete mode 100644 lib/codebreaker/errors/digit_range_error.rb delete mode 100644 lib/codebreaker/errors/digits_count_error.rb diff --git a/lib/codebreaker/errors/difficulty_error.rb b/lib/codebreaker/errors/difficulty_error.rb index 141ed19..280b34c 100644 --- a/lib/codebreaker/errors/difficulty_error.rb +++ b/lib/codebreaker/errors/difficulty_error.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module Codebreaker class DifficultyError < StandardError def message diff --git a/lib/codebreaker/errors/digit_range_error.rb b/lib/codebreaker/errors/digit_range_error.rb deleted file mode 100644 index df4bbd7..0000000 --- a/lib/codebreaker/errors/digit_range_error.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Codebreaker - class DigitRangeError < StandardError - def message - 'Digit is not in a range' - end - end -end diff --git a/lib/codebreaker/errors/digits_count_error.rb b/lib/codebreaker/errors/digits_count_error.rb deleted file mode 100644 index 971f1e9..0000000 --- a/lib/codebreaker/errors/digits_count_error.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Codebreaker - class DigitsCountError < StandardError - def message - 'Invalid digits count' - end - end -end diff --git a/lib/codebreaker/errors/expected_difficulty_instance_error.rb b/lib/codebreaker/errors/expected_difficulty_instance_error.rb index 00d8017..04f63ee 100644 --- a/lib/codebreaker/errors/expected_difficulty_instance_error.rb +++ b/lib/codebreaker/errors/expected_difficulty_instance_error.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module Codebreaker class ExpectedDifficultyInstanceError < StandardError def message diff --git a/lib/codebreaker/errors/expected_user_instance_error.rb b/lib/codebreaker/errors/expected_user_instance_error.rb index 8b062a9..b95bdab 100644 --- a/lib/codebreaker/errors/expected_user_instance_error.rb +++ b/lib/codebreaker/errors/expected_user_instance_error.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module Codebreaker class ExpectedUserInstanceError < StandardError def message diff --git a/lib/codebreaker/errors/long_name_error.rb b/lib/codebreaker/errors/long_name_error.rb index 7a412ef..373957b 100644 --- a/lib/codebreaker/errors/long_name_error.rb +++ b/lib/codebreaker/errors/long_name_error.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module Codebreaker class LongNameError < StandardError def message diff --git a/lib/codebreaker/errors/name_is_not_string_error.rb b/lib/codebreaker/errors/name_is_not_string_error.rb index 0694687..04f281d 100644 --- a/lib/codebreaker/errors/name_is_not_string_error.rb +++ b/lib/codebreaker/errors/name_is_not_string_error.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module Codebreaker class NameIsNotStringError < StandardError def message diff --git a/lib/codebreaker/errors/short_name_error.rb b/lib/codebreaker/errors/short_name_error.rb index b10ad4f..e67a182 100644 --- a/lib/codebreaker/errors/short_name_error.rb +++ b/lib/codebreaker/errors/short_name_error.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - module Codebreaker class ShortNameError < StandardError def message From a5f7790f60f028625a20497492ca0ab19d4d89fa Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 5 Mar 2021 16:25:52 +0200 Subject: [PATCH 11/63] fix --- lib/codebreaker.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index e853244..a1d6cd7 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -6,8 +6,6 @@ require_relative 'codebreaker/errors/short_name_error' require_relative 'codebreaker/errors/long_name_error' require_relative 'codebreaker/errors/difficulty_error' -require_relative 'codebreaker/errors/digit_range_error' -require_relative 'codebreaker/errors/digits_count_error' require_relative 'codebreaker/errors/expected_difficulty_instance_error' require_relative 'codebreaker/errors/expected_user_instance_error' From 7e9cab49c9f9f6e5f263695ec40e7fd03308910c Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:04:54 +0200 Subject: [PATCH 12/63] add errors to difficulty --- lib/codebreaker/entities/difficulty.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 1b04ec5..e019e11 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -5,10 +5,11 @@ class Difficulty DIFFICULTIES = { easy: { attempts: 15, hints: 2 }, medium: { attempts: 10, hints: 1 }, hell: { attempts: 5, hints: 1 } }.freeze - attr_reader :level + attr_reader :level, :errors def initialize(level) @level = level.to_sym + @errors = [] end def attempts From 7c6fde52fe2d1820baf84e049e04244947df6e67 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:07:57 +0200 Subject: [PATCH 13/63] fix naming --- lib/codebreaker/entities/game.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index a63acf7..e2b026b 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -39,7 +39,7 @@ def new_game end def lose? - difficulty.current_attempts.zero? + difficulty.attempts.zero? end def win?(user_code) From d27973db5817ba42cf6c7a83dc0798de80ecd563 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:27:10 +0200 Subject: [PATCH 14/63] remove useless join method --- lib/codebreaker/entities/game.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index e2b026b..d8f7648 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -43,7 +43,7 @@ def lose? end def win?(user_code) - user_code == secret_code.join + user_code == secret_code end def no_hints? From 375af5a221c7b28d1065c90566029225e3e480c9 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:36:45 +0200 Subject: [PATCH 15/63] add validations to guess --- lib/codebreaker/errors/digit_range_error.rb | 7 +++++++ lib/codebreaker/errors/digits_count_error.rb | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 lib/codebreaker/errors/digit_range_error.rb create mode 100644 lib/codebreaker/errors/digits_count_error.rb diff --git a/lib/codebreaker/errors/digit_range_error.rb b/lib/codebreaker/errors/digit_range_error.rb new file mode 100644 index 0000000..a83c09d --- /dev/null +++ b/lib/codebreaker/errors/digit_range_error.rb @@ -0,0 +1,7 @@ +module Codebreaker + class DigitRangeError < StandardError + def message + 'Digit is not in a range' + end + end +end diff --git a/lib/codebreaker/errors/digits_count_error.rb b/lib/codebreaker/errors/digits_count_error.rb new file mode 100644 index 0000000..bab0254 --- /dev/null +++ b/lib/codebreaker/errors/digits_count_error.rb @@ -0,0 +1,7 @@ +module Codebreaker + class DigitsCountError < StandardError + def message + 'Invalid digits count' + end + end +end From 5d926e21606df74766cd560455d21e88c2bd0c37 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:38:17 +0200 Subject: [PATCH 16/63] fix naming --- lib/codebreaker/entities/game.rb | 2 +- lib/codebreaker/entities/guess_checker.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index d8f7648..01528df 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -47,7 +47,7 @@ def win?(user_code) end def no_hints? - difficulty.current_hints.zero? + difficulty.hints.zero? end private diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 08675b2..356fba5 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -20,5 +20,10 @@ def check end answer.sort.join end + + def self.validate(guess) + raise DigitsCountError unless guess.size == Game::DIGITS_NUM + raise DigitRangeError unless guess.chars.all? { |num| num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM } + end end end From 6e7d1f8f7a6cb543f25575e6a6c813f29a1e0559 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:49:24 +0200 Subject: [PATCH 17/63] fix generating method --- lib/codebreaker/entities/game.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 01528df..27ca463 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -43,7 +43,7 @@ def lose? end def win?(user_code) - user_code == secret_code + user_code == secret_code.join end def no_hints? @@ -53,7 +53,7 @@ def no_hints? private def generate_secret_code - Array.new(DIGITS_NUM) { rand(MIN_CODE_NUM..MAX_CODE_NUM) }.join + Array.new(DIGITS_NUM) { rand(MIN_CODE_NUM..MAX_CODE_NUM) } end def validate! From a53d67f896cc955895d245325a70e65663950209 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:53:07 +0200 Subject: [PATCH 18/63] fix getters --- lib/codebreaker/entities/game.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 27ca463..b8e256e 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -1,7 +1,7 @@ module Codebreaker class Game include Validator - attr_reader :user, :difficulty, :secret_code, :errors, :date, :hints_list + attr_reader :user, :secret_code, :errors, :date, :hints_list, :attempts, :hints MIN_CODE_NUM = 1 MAX_CODE_NUM = 6 From 65020e75a5c9b82489b98db99e852dcdb88e2362 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 10:56:42 +0200 Subject: [PATCH 19/63] fix getters --- lib/codebreaker/entities/game.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index b8e256e..bbf7a7f 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -1,7 +1,7 @@ module Codebreaker class Game include Validator - attr_reader :user, :secret_code, :errors, :date, :hints_list, :attempts, :hints + attr_reader :user, :difficulty, :secret_code, :errors, :date, :hints_list, :attempts, :hints MIN_CODE_NUM = 1 MAX_CODE_NUM = 6 From 5b0e429cedc4607e58432f120d15002af61877d2 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 11:02:27 +0200 Subject: [PATCH 20/63] add exceptiond to require --- lib/codebreaker.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index a1d6cd7..43f457e 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -8,6 +8,8 @@ require_relative 'codebreaker/errors/difficulty_error' require_relative 'codebreaker/errors/expected_difficulty_instance_error' require_relative 'codebreaker/errors/expected_user_instance_error' +require_relative 'codebreaker/errors/digit_range_error' +require_relative 'codebreaker/errors/digits_count_error' require_relative 'codebreaker/modules/validator' From 7ff78499b580ace3defdf062beec0221b39eaaed Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 12:49:05 +0200 Subject: [PATCH 21/63] fix check method --- lib/codebreaker/entities/guess_checker.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 356fba5..911ff98 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -9,9 +9,10 @@ def initialize(code, input) @user_input = input end + def check answer = [] - @user_input.each_char.each_with_index do |digit, index| + @user_input.split('').map(&:to_i).each_with_index do |digit, index| if @secret_code[index] == digit answer.push RIGHT_ANSWER_SYMBOL elsif @secret_code.include? digit From 0a6bb276ecf4f1ea91dd872c5f401c7779be49eb Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 13:01:16 +0200 Subject: [PATCH 22/63] refactor getters to instance vars --- lib/codebreaker/entities/difficulty.rb | 2 +- lib/codebreaker/entities/game.rb | 16 ++++++++-------- lib/codebreaker/entities/user.rb | 6 +++--- lib/codebreaker/services/statistics_service.rb | 10 +++++----- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index e019e11..6581173 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -27,7 +27,7 @@ def validate! end def validate_difficulty - errors << DifficultyError unless DIFFICULTIES.include? @level + @errors << DifficultyError unless DIFFICULTIES.include? @level end end end diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index bbf7a7f..b039cf2 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -20,9 +20,9 @@ def initialize(user, difficulty) def use_hint @hints -= 1 - index = rand(hints_list.size) + index = rand(@hints_list.size) digit = hints_list[index] - hints_list.delete_at index + @hints_list.delete_at index digit end @@ -39,15 +39,15 @@ def new_game end def lose? - difficulty.attempts.zero? + @attempts.zero? end def win?(user_code) - user_code == secret_code.join + user_code == @secret_code.join end def no_hints? - difficulty.hints.zero? + @hints.zero? end private @@ -58,15 +58,15 @@ def generate_secret_code def validate! validate_user - validate_difficulty if errors.empty? + validate_difficulty if @errors.empty? end def validate_user - errors << ExpectedUserInstanceError unless user.instance_of?(Codebreaker::User) + @errors << ExpectedUserInstanceError unless @user.instance_of?(Codebreaker::User) end def validate_difficulty - errors << ExpectedDifficultyInstanceError unless difficulty.instance_of?(Codebreaker::Difficulty) + @errors << ExpectedDifficultyInstanceError unless @difficulty.instance_of?(Codebreaker::Difficulty) end end end diff --git a/lib/codebreaker/entities/user.rb b/lib/codebreaker/entities/user.rb index da6f9a0..367ea29 100644 --- a/lib/codebreaker/entities/user.rb +++ b/lib/codebreaker/entities/user.rb @@ -20,15 +20,15 @@ def validate! end def validate_name_class - errors << NameIsNotStringError unless name.is_a? String + @errors << NameIsNotStringError unless @name.is_a? String end def validate_name_min_length - errors << ShortNameError if name.length < NAME_MIN_LENGTH + @errors << ShortNameError if @name.length < NAME_MIN_LENGTH end def validate_name_max_length - errors << LongNameError if name.length > NAME_MAX_LENGTH + @errors << LongNameError if @name.length > NAME_MAX_LENGTH end end end diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index 2b28e8f..2c4d598 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -7,9 +7,9 @@ def initialize(path) end def store(game) - statistics = File.exist?(path) && !File.zero?(path) ? YAML.load_file(path) : [] + statistics = File.exist?(@path) && !File.zero?(@path) ? YAML.load_file(@path) : [] statistics << pack_game_data(game) - file = File.open(path, 'w') + file = File.open(@path, 'w') file.write(statistics.to_yaml) file.close end @@ -19,9 +19,9 @@ def sort_statistics end def load - return unless File.exist? path + return unless File.exist? @path - YAML.load_file path + YAML.load_file @path end private @@ -29,7 +29,7 @@ def load def game_to_h(game) { name: game.user.name, - difficulty: game.difficulty.defficulty.to_s, + difficulty: game.difficulty.level.to_s, attempts_total: game.difficulty.attempts, attempts_used: game.difficulty.attempts - game.attempts, hints_total: game.hints, From 5caddb866e807ca9b9b9c317432b205eeb93ff06 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 6 Mar 2021 14:10:15 +0200 Subject: [PATCH 23/63] refactor line priority --- lib/codebreaker/entities/difficulty.rb | 1 + lib/codebreaker/entities/game.rb | 3 ++- lib/codebreaker/entities/guess_checker.rb | 2 +- lib/codebreaker/entities/user.rb | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 6581173..038b858 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -5,6 +5,7 @@ class Difficulty DIFFICULTIES = { easy: { attempts: 15, hints: 2 }, medium: { attempts: 10, hints: 1 }, hell: { attempts: 5, hints: 1 } }.freeze + attr_reader :level, :errors def initialize(level) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index b039cf2..5399707 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -1,12 +1,13 @@ module Codebreaker class Game include Validator - attr_reader :user, :difficulty, :secret_code, :errors, :date, :hints_list, :attempts, :hints MIN_CODE_NUM = 1 MAX_CODE_NUM = 6 DIGITS_NUM = 4 + attr_reader :user, :difficulty, :secret_code, :errors, :date, :hints_list, :attempts, :hints + def initialize(user, difficulty) @user = user @difficulty = difficulty diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 911ff98..9fb9dd6 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -2,6 +2,7 @@ module Codebreaker class GuessChecker RIGHT_ANSWER_SYMBOL = '+'.freeze WRONG_ANSWER_SYMBOL = '-'.freeze + attr_reader :secret_code, :user_code def initialize(code, input) @@ -9,7 +10,6 @@ def initialize(code, input) @user_input = input end - def check answer = [] @user_input.split('').map(&:to_i).each_with_index do |digit, index| diff --git a/lib/codebreaker/entities/user.rb b/lib/codebreaker/entities/user.rb index 367ea29..321f2bd 100644 --- a/lib/codebreaker/entities/user.rb +++ b/lib/codebreaker/entities/user.rb @@ -1,11 +1,12 @@ module Codebreaker class User include Validator - attr_reader :name, :errors NAME_MIN_LENGTH = 3 NAME_MAX_LENGTH = 20 + attr_reader :name, :errors + def initialize(name) @name = name @errors = [] From b9ddd5369cbfed98798db177c6b610c1459b17fb Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:02:54 +0200 Subject: [PATCH 24/63] add pry debuger --- Gemfile.lock | 24 +++++++++++++++++------- codebreaker.gemspec | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8b4b3f3..7ee1cf4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,6 +13,8 @@ GEM descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) + byebug (11.1.3) + coderay (1.1.3) coercible (1.0.0) descendants_tracker (~> 0.0.1) colorize (0.8.1) @@ -38,11 +40,18 @@ GEM kwalify (0.7.2) launchy (2.5.0) addressable (~> 2.7) + method_source (1.0.0) parallel (1.20.1) parser (3.0.0.0) ast (~> 2.4.1) path_expander (1.1.0) - psych (3.3.0) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.9.0) + byebug (~> 11.0) + pry (~> 0.13.0) + psych (3.3.1) public_suffix (4.0.6) rainbow (3.0.0) rake (13.0.3) @@ -51,7 +60,7 @@ GEM parser (~> 3.0.0) psych (~> 3.1) rainbow (>= 2.0, < 4.0) - regexp_parser (2.1.0) + regexp_parser (2.1.1) rexml (3.2.4) rspec (3.10.0) rspec-core (~> 3.10.0) @@ -66,7 +75,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.10.0) rspec-support (3.10.2) - rubocop (1.10.0) + rubocop (1.11.0) parallel (~> 1.10) parser (>= 3.0.0.0) rainbow (>= 2.2.2, < 4.0) @@ -77,7 +86,7 @@ GEM unicode-display_width (>= 1.4.0, < 3.0) rubocop-ast (1.4.1) parser (>= 2.7.1.5) - rubocop-performance (1.9.2) + rubocop-performance (1.10.1) rubocop (>= 0.90.0, < 2.0) rubocop-ast (>= 0.4.0) rubocop-rspec (2.2.0) @@ -86,7 +95,7 @@ GEM ruby-progressbar (1.11.0) ruby_parser (3.15.1) sexp_processor (~> 4.9) - rubycritic (4.6.0) + rubycritic (4.5.2) flay (~> 2.8) flog (~> 4.4) launchy (>= 2.0.0) @@ -94,11 +103,11 @@ GEM rainbow (~> 3.0) reek (~> 6.0, < 7.0) ruby_parser (~> 3.8) - simplecov (>= 0.17.0, < 0.21) + simplecov (>= 0.17.0) tty-which (~> 0.4.0) virtus (~> 1.0) sexp_processor (4.15.2) - simplecov (0.20.0) + simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) @@ -120,6 +129,7 @@ PLATFORMS DEPENDENCIES codebreaker! fasterer + pry-byebug rake rspec rubocop diff --git a/codebreaker.gemspec b/codebreaker.gemspec index 93de943..87d634a 100644 --- a/codebreaker.gemspec +++ b/codebreaker.gemspec @@ -26,6 +26,8 @@ Gem::Specification.new do |spec| # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0" + + spec.add_development_dependency 'pry-byebug' spec.add_development_dependency 'rake' spec.add_development_dependency 'fasterer' spec.add_development_dependency 'rspec' From 78d1b60c352877db9e26e539712c5669486cd79f Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:05:13 +0200 Subject: [PATCH 25/63] change naming --- lib/codebreaker/services/statistics_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index 2c4d598..d5fc036 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -8,7 +8,7 @@ def initialize(path) def store(game) statistics = File.exist?(@path) && !File.zero?(@path) ? YAML.load_file(@path) : [] - statistics << pack_game_data(game) + statistics << game_to_h(game) file = File.open(@path, 'w') file.write(statistics.to_yaml) file.close From c17ba79f8fb3cbbd9b90433b852759e3977b7812 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:06:58 +0200 Subject: [PATCH 26/63] remove unnecessary errors --- lib/codebreaker.rb | 4 ++-- .../errors/expected_difficulty_instance_error.rb | 7 ------- lib/codebreaker/errors/expected_user_instance_error.rb | 7 ------- 3 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 lib/codebreaker/errors/expected_difficulty_instance_error.rb delete mode 100644 lib/codebreaker/errors/expected_user_instance_error.rb diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index 43f457e..6ef0045 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -1,13 +1,13 @@ require_relative 'codebreaker/version' require 'yaml' +require 'pry' +require_relative 'codebreaker/errors/guess_is_not_integer_error' require_relative 'codebreaker/errors/name_is_not_string_error' require_relative 'codebreaker/errors/short_name_error' require_relative 'codebreaker/errors/long_name_error' require_relative 'codebreaker/errors/difficulty_error' -require_relative 'codebreaker/errors/expected_difficulty_instance_error' -require_relative 'codebreaker/errors/expected_user_instance_error' require_relative 'codebreaker/errors/digit_range_error' require_relative 'codebreaker/errors/digits_count_error' diff --git a/lib/codebreaker/errors/expected_difficulty_instance_error.rb b/lib/codebreaker/errors/expected_difficulty_instance_error.rb deleted file mode 100644 index 04f63ee..0000000 --- a/lib/codebreaker/errors/expected_difficulty_instance_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class ExpectedDifficultyInstanceError < StandardError - def message - 'Object should be an instance of Difficulty class' - end - end -end diff --git a/lib/codebreaker/errors/expected_user_instance_error.rb b/lib/codebreaker/errors/expected_user_instance_error.rb deleted file mode 100644 index b95bdab..0000000 --- a/lib/codebreaker/errors/expected_user_instance_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class ExpectedUserInstanceError < StandardError - def message - 'Object should be an instance of User class' - end - end -end From a41c043ab4b29df9c86aca7a065d2ec248582e0c Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:08:21 +0200 Subject: [PATCH 27/63] fix check method --- lib/codebreaker/entities/guess_checker.rb | 40 +++++++++++++++-------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 9fb9dd6..e8d417b 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -2,29 +2,43 @@ module Codebreaker class GuessChecker RIGHT_ANSWER_SYMBOL = '+'.freeze WRONG_ANSWER_SYMBOL = '-'.freeze - - attr_reader :secret_code, :user_code + NOTHING_SYMBOL = '' .freeze def initialize(code, input) - @secret_code = code - @user_input = input + @secret_code = code.to_s.split(NOTHING_SYMBOL).map(&:to_i) + @user_input = input.to_s.split(NOTHING_SYMBOL).map(&:to_i) end def check - answer = [] - @user_input.split('').map(&:to_i).each_with_index do |digit, index| - if @secret_code[index] == digit - answer.push RIGHT_ANSWER_SYMBOL - elsif @secret_code.include? digit - answer.push WRONG_ANSWER_SYMBOL - end - end - answer.sort.join + pluses + minuses end def self.validate(guess) + raise GuessIsNotInteger unless guess[/^\d+$/] raise DigitsCountError unless guess.size == Game::DIGITS_NUM raise DigitRangeError unless guess.chars.all? { |num| num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM } end + + private + + def pluses + answer = '' + @user_input.map.with_index do |number, index| + if @secret_code[index] == number + answer << RIGHT_ANSWER_SYMBOL + @secret_code[index], @user_input[index] = nil + end + end + answer + end + + def minuses + answer = '' + @user_input.compact! + @secret_code.compact! + near_matchers = @secret_code & @user_input + near_matchers.size.times { answer << WRONG_ANSWER_SYMBOL } + answer + end end end From c2fc9967b71a7890383001b5bfd9fcb7b3fe5786 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:09:43 +0200 Subject: [PATCH 28/63] remove validations --- lib/codebreaker/entities/game.rb | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 5399707..26a18bf 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -1,7 +1,5 @@ module Codebreaker class Game - include Validator - MIN_CODE_NUM = 1 MAX_CODE_NUM = 6 DIGITS_NUM = 4 @@ -15,7 +13,6 @@ def initialize(user, difficulty) @hints = @difficulty.hints @secret_code = generate_secret_code @hints_list = secret_code.clone - @errors = [] @date = Time.now.getlocal end @@ -29,7 +26,7 @@ def use_hint def check_attempt(guess) @attempts -= 1 - GuessChecker.new(@secret_code.clone, guess).check + GuessChecker.new(@secret_code.join, guess).check end def new_game @@ -56,18 +53,5 @@ def no_hints? def generate_secret_code Array.new(DIGITS_NUM) { rand(MIN_CODE_NUM..MAX_CODE_NUM) } end - - def validate! - validate_user - validate_difficulty if @errors.empty? - end - - def validate_user - @errors << ExpectedUserInstanceError unless @user.instance_of?(Codebreaker::User) - end - - def validate_difficulty - @errors << ExpectedDifficultyInstanceError unless @difficulty.instance_of?(Codebreaker::Difficulty) - end end end From 662500ac9153abed448d337e91fc33b342ab2809 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:10:38 +0200 Subject: [PATCH 29/63] refactor --- lib/codebreaker/entities/user.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codebreaker/entities/user.rb b/lib/codebreaker/entities/user.rb index 321f2bd..a9abf4e 100644 --- a/lib/codebreaker/entities/user.rb +++ b/lib/codebreaker/entities/user.rb @@ -16,8 +16,8 @@ def initialize(name) def validate! validate_name_class - validate_name_min_length if errors.empty? - validate_name_max_length if errors.empty? + validate_name_min_length if @errors.empty? + validate_name_max_length if @errors.empty? end def validate_name_class From c5e57b8f5bfaf880840754234dd37f1568334574 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:11:26 +0200 Subject: [PATCH 30/63] add new error class --- lib/codebreaker/errors/guess_is_not_integer_error.rb | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lib/codebreaker/errors/guess_is_not_integer_error.rb diff --git a/lib/codebreaker/errors/guess_is_not_integer_error.rb b/lib/codebreaker/errors/guess_is_not_integer_error.rb new file mode 100644 index 0000000..271ec40 --- /dev/null +++ b/lib/codebreaker/errors/guess_is_not_integer_error.rb @@ -0,0 +1,7 @@ +module Codebreaker + class GuessIsNotInteger < StandardError + def message + 'Guess should be Integer class' + end + end +end From 292664b9b9bcf753cb8120de9005fb2c6c2757ee Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:11:53 +0200 Subject: [PATCH 31/63] add specs --- spec/codebreaker/difficulty_spec.rb | 71 ++++++++++ spec/codebreaker/game_spec.rb | 152 +++++++++++++++++++++ spec/codebreaker/guess_checker_spec.rb | 67 +++++++++ spec/codebreaker/statistic_service_spec.rb | 25 ++++ spec/codebreaker/user_spec.rb | 79 +++++++++++ 5 files changed, 394 insertions(+) create mode 100644 spec/codebreaker/difficulty_spec.rb create mode 100644 spec/codebreaker/game_spec.rb create mode 100644 spec/codebreaker/guess_checker_spec.rb create mode 100644 spec/codebreaker/statistic_service_spec.rb create mode 100644 spec/codebreaker/user_spec.rb diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb new file mode 100644 index 0000000..07b847d --- /dev/null +++ b/spec/codebreaker/difficulty_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +RSpec.describe Codebreaker::Difficulty do + let(:difficulty) { described_class.new level } + let(:level) { 'easy' } + let(:invalid_difficulty) { described_class.new invalid_level } + let(:invalid_level) { 'qwerty' } + let(:difficulty_constant) { { easy: { attempts: 15, hints: 2 }, + medium: { attempts: 10, hints: 1 }, + hell: { attempts: 5, hints: 1 } } } + + describe '#level' do + context 'when level set' do + it 'level is a symbol' do + expect(difficulty.level).to eq(:easy) + end + end + end + + describe '#errors' do + context 'when errors set' do + it 'has 0 items' do + expect(difficulty.errors.size).to eq(0) + end + end + end + + describe '#initialize' do + it 'has level and errors field' do + expect(difficulty.instance_variables).to include(:@level, :@errors) + end + end + + describe 'check Difficulty constants' do + it 'check content of DIFFICULTIES constant' do + expect(described_class::DIFFICULTIES).to eq(difficulty_constant) + end + end + + describe '#valid?' do + context 'when entered level of difficulty is wrong' do + it 'validation returns false' do + expect(invalid_difficulty.valid?).to eq false + end + + it 'adds DifficultyError to errors' do + invalid_difficulty.valid? + expect(invalid_difficulty.errors).to include Codebreaker::DifficultyError + end + end + + context 'when entered level of difficulty is right' do + it 'validation returns true' do + expect(difficulty.valid?).to eq true + end + + it 'adds nothing to errors' do + difficulty.valid? + expect(difficulty.errors).to be_empty + end + + it 'returs number of attempts of appropriate difficulty' do + expect(difficulty.attempts).to eq(15) + end + + it 'returs number of hints of appropriate difficulty' do + expect(difficulty.hints).to eq(2) + end + end + end +end diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb new file mode 100644 index 0000000..3a621bb --- /dev/null +++ b/spec/codebreaker/game_spec.rb @@ -0,0 +1,152 @@ +require 'spec_helper' + +RSpec.describe Codebreaker::Game do + let(:range) { (described_class::MIN_CODE_NUM..described_class::MAX_CODE_NUM - 1).to_a } + let(:user) { Codebreaker::User.new user_name } + let(:user_name) { 'Mechetel' } + let(:difficulty) { Codebreaker::Difficulty.new difficulty_level } + let(:difficulty_level) { 'hell' } + let(:game) { described_class.new user, difficulty } + let(:attempts_at_new_game) { game.difficulty.attempts } + let(:hints_at_new_game) { game.difficulty.hints } + + describe '#initialize' do + context 'when game starts it initializes with secret number' do + subject(:game_secret_number) { game.secret_code } + + let(:secret_number) { '6616' } + + it 'has secret number' do + allow_any_instance_of(described_class).to receive(:generate_secret_code).and_return(secret_number) + expect(game_secret_number).to eq(secret_number) + end + + it 'has valid secret number length' do + expect(game_secret_number.length).to eq(4) + end + + it 'has valid secret number digits' do + game_secret_number.each do |digit| + expect(digit.to_i).to be_between(1, 6) + end + end + + it 'secret code is an Array' do + expect(game_secret_number.class).to eq Array + end + + it 'secret code size equal to DIGITS_NUM constant' do + expect(game_secret_number.size).to eq described_class::DIGITS_NUM + end + + it 'each element of secret code is between MIN_CODE_NUM and MAX_CODE_NUM contstants' do + game_secret_number.each do |digit| + expect(digit.to_i).to be_between(described_class::MIN_CODE_NUM, described_class::MAX_CODE_NUM).inclusive + end + end + + it 'hints list is equal to secret code' do + expect(game.hints_list).to eq game_secret_number + end + + it 'user field class equal to User' do + expect(game.user.class).to eq Codebreaker::User + end + + it 'difficulty field class equal to Difficulty' do + expect(game.difficulty.class).to eq Codebreaker::Difficulty + end + end + end + + describe '#take_hint' do + subject(:game_secret_number) { game.secret_code } + subject(:game_use_hint) { game.use_hint } + + it 'returns Integer' do + expect(game_use_hint.class).to eq Integer + end + + it 'returns only one number' do + expect(game_use_hint.to_s.size).to eq 1 + end + + it 'changes current_hints counter by 1' do + expect { game_use_hint }.to change { game.instance_variable_get(:@hints) }.by(-1) + end + + it 'removes one element from hints list' do + expect { game_use_hint }.to change { game.instance_variable_get(:@hints_list).size }.by(-1) + end + end + + describe '#lose?' do + subject(:game_lose) { game.lose? } + + it 'returns false when attempts are set' do + expect(game_lose).to be_falsey + end + + it 'returns true when attempts are equal to zero' do + game.instance_variable_set(:@attempts, 0) + expect(game_lose).to be_truthy + end + end + + describe '#win?' do + it 'returns false when user code is not equal to secret code' do + game.instance_variable_set(:@secret_code, [1, 2, 3, 4]) + expect(game.win?('2345')).to be_falsey + end + + it 'returns true when user code is equal to secret code' do + expect(game.win?(game.secret_code.join)).to be_truthy + end + end + + describe '#no_hints?' do + subject(:game_no_hints) { game.no_hints? } + + it 'returns false when hints are set' do + expect(game_no_hints).to be_falsey + end + + it 'returns true when hints are equal to zero' do + game.instance_variable_set(:@hints, 0) + expect(game_no_hints).to be_truthy + end + end + + describe '#new_game' do + before do + game.new_game + end + + it 'set secret code Array to secret_code' do + expect(game.secret_code.class).to eq Array + end + + it 'set secret code to hints_list' do + expect(game.hints_list).to eq game.secret_code + end + + it 'current_attempts are equal to previous game current_attempts' do + expect(game.attempts).to eq attempts_at_new_game + end + + it 'current_hints are equal to previous game current_hints' do + expect(game.hints).to eq hints_at_new_game + end + end + + describe '#check_attempt' do + it 'returns String' do + expect(game.check_attempt('2456').class).to eq String + end + + it 'returns string which size is between 0 and 4' do + expect(game.check_attempt('6163').length).to be_between(0, 4).inclusive + end + + end +end diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb new file mode 100644 index 0000000..6f2527a --- /dev/null +++ b/spec/codebreaker/guess_checker_spec.rb @@ -0,0 +1,67 @@ +require 'spec_helper' + +RSpec.describe Codebreaker::GuessChecker do + let(:plus_symbol) { '+' } + let(:minus_symbol) { '-' } + let(:nothing_symbol) { '' } + + describe '#initialize' do + let(:guess_checker) { described_class.new(secret_code, user_input) } + let(:secret_code) { '1234' } + let(:user_input) { '2345' } + + it 'has secret_code and user_input field' do + expect(guess_checker.instance_variables).to include(:@secret_code, :@user_input) + end + end + + describe 'check GuessChecker constants' do + it 'check content of RIGHT_ANSWER_SYMBOL constant' do + expect(described_class::RIGHT_ANSWER_SYMBOL).to eq(plus_symbol) + end + + it 'check content of WRONG_ANSWER_SYMBOL constant' do + expect(described_class::WRONG_ANSWER_SYMBOL).to eq(minus_symbol) + end + + it 'check content of NOTHING_SYMBOL constant' do + expect(described_class::NOTHING_SYMBOL).to eq(nothing_symbol) + end + end + + describe '#validate' do + it 'raises DigitsCountError when digits count is invalid' do + expect { described_class.validate('102') }.to raise_error Codebreaker::DigitsCountError + end + + it 'raises DigitsCountError when guess is not a numbers' do + expect { described_class.validate('sdfg') }.to raise_error Codebreaker::GuessIsNotInteger + end + + it 'raises DigitRangeError when any digit is not in the range' do + expect { described_class.validate('6969') }.to raise_error Codebreaker::DigitRangeError + end + end + + describe '#result' do + context 'when have some result' do + [ + { secret_number: '6543', input: '5643', result: '++--' }, + { secret_number: '6543', input: '6411', result: '+-' }, + { secret_number: '6543', input: '6544', result: '+++' }, + { secret_number: '6543', input: '3456', result: '----' }, + { secret_number: '6543', input: '6666', result: '+' }, + { secret_number: '6543', input: '2666', result: '-' }, + { secret_number: '6543', input: '2222', result: '' }, + { secret_number: '6666', input: '1661', result: '++' }, + { secret_number: '1234', input: '3124', result: '+---' }, + { secret_number: '1234', input: '1524', result: '++-' }, + { secret_number: '1234', input: '1234', result: '++++' } + ].each do |line| + it "returns #{line[:result]} when secret number - #{line[:secret_number]} and input - #{line[:input]}" do + expect(described_class.new(line[:secret_number], line[:input]).check).to eq(line[:result]) + end + end + end + end +end diff --git a/spec/codebreaker/statistic_service_spec.rb b/spec/codebreaker/statistic_service_spec.rb new file mode 100644 index 0000000..74e08f3 --- /dev/null +++ b/spec/codebreaker/statistic_service_spec.rb @@ -0,0 +1,25 @@ +RSpec.describe Codebreaker::StatisticsService do + let(:game) { Codebreaker::Game.new Codebreaker::User.new('Mechetel'), + Codebreaker::Difficulty.new('hell') } + let(:path) { './lib/codebreaker/test.yaml' } + let(:service) { described_class.new(path) } + + before { service.store game } + after(:each) { File.delete(path) } + + describe '#store' do + it 'create file' do + expect(File.exist?(path)).to be true + end + end + + describe '#load' do + it 'returns Array' do + expect(service.load.class).to be Array + end + + it 'each array element is a Hash' do + expect(service.load.all?(Hash)).to be true + end + end +end diff --git a/spec/codebreaker/user_spec.rb b/spec/codebreaker/user_spec.rb new file mode 100644 index 0000000..221c8c6 --- /dev/null +++ b/spec/codebreaker/user_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper' + +RSpec.describe Codebreaker::User do + let(:user) { described_class.new name } + let(:name) { 'Mechetel' } + let(:short_name_user) { described_class.new short_name } + let(:short_name) { 'Me' } + let(:long_name_user) { described_class.new long_name } + let(:long_name) { 'dima' * 10 } + let(:invalid_user) { described_class.new inappropriate_user_name } + let(:inappropriate_user_name) { 322 } + + describe '#name' do + context 'when name set' do + it 'has appropriate name' do + expect(user.name).to eq(name) + end + end + end + + describe '#errors' do + context 'when errors set' do + it 'has 0 items' do + expect(user.errors.size).to eq(0) + end + end + end + + describe '#initialize' do + it 'has name and errors field field' do + expect(user.instance_variables).to include(:@name, :@errors) + end + end + + describe 'check User constants' do + it 'check content of NAME_MIN_LENGTH constant' do + expect(described_class::NAME_MIN_LENGTH).to eq(3) + end + + it 'check content of NAME_MAX_LENGTH constant' do + expect(described_class::NAME_MAX_LENGTH).to eq(20) + end + end + + describe '#valid?' do + context 'when entered name is too short' do + it 'returns false' do + expect(short_name_user.valid?).to be_falsey + end + + it 'adds ShortNameError to errors' do + short_name_user.valid? + expect(short_name_user.errors).to include Codebreaker::ShortNameError + end + end + + context 'when entered name is too long' do + it 'returns false' do + expect(long_name_user.valid?).to be_falsey + end + + it 'adds longnameerror to errors' do + long_name_user.valid? + expect(long_name_user.errors).to include Codebreaker::LongNameError + end + end + + context 'when entered name is not an instance of String' do + it 'returns false' do + expect(invalid_user.valid?).to be_falsey + end + + it 'adds NameIsNotStringError to errors' do + invalid_user.valid? + expect(invalid_user.errors).to include Codebreaker::NameIsNotStringError + end + end + end +end From a309b9e3d815c448b1404c29168e3055027ebdd9 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 00:19:05 +0200 Subject: [PATCH 32/63] corrected with rubocop --- lib/codebreaker/entities/guess_checker.rb | 4 ++-- spec/codebreaker/difficulty_spec.rb | 8 +++++--- spec/codebreaker/game_spec.rb | 8 ++++---- spec/codebreaker/statistic_service_spec.rb | 9 ++++++--- spec/codebreaker/user_spec.rb | 6 +++--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index e8d417b..c871fc9 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -2,7 +2,7 @@ module Codebreaker class GuessChecker RIGHT_ANSWER_SYMBOL = '+'.freeze WRONG_ANSWER_SYMBOL = '-'.freeze - NOTHING_SYMBOL = '' .freeze + NOTHING_SYMBOL = ''.freeze def initialize(code, input) @secret_code = code.to_s.split(NOTHING_SYMBOL).map(&:to_i) @@ -26,7 +26,7 @@ def pluses @user_input.map.with_index do |number, index| if @secret_code[index] == number answer << RIGHT_ANSWER_SYMBOL - @secret_code[index], @user_input[index] = nil + @secret_code[index], @user_input[index] = nil end end answer diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb index 07b847d..3856bf1 100644 --- a/spec/codebreaker/difficulty_spec.rb +++ b/spec/codebreaker/difficulty_spec.rb @@ -5,9 +5,11 @@ let(:level) { 'easy' } let(:invalid_difficulty) { described_class.new invalid_level } let(:invalid_level) { 'qwerty' } - let(:difficulty_constant) { { easy: { attempts: 15, hints: 2 }, - medium: { attempts: 10, hints: 1 }, - hell: { attempts: 5, hints: 1 } } } + let(:difficulty_constant) do + { easy: { attempts: 15, hints: 2 }, + medium: { attempts: 10, hints: 1 }, + hell: { attempts: 5, hints: 1 } } + end describe '#level' do context 'when level set' do diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index 3a621bb..04a289c 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -60,9 +60,10 @@ end describe '#take_hint' do - subject(:game_secret_number) { game.secret_code } subject(:game_use_hint) { game.use_hint } + let(:game_secret_number) { game.secret_code } + it 'returns Integer' do expect(game_use_hint.class).to eq Integer end @@ -96,11 +97,11 @@ describe '#win?' do it 'returns false when user code is not equal to secret code' do game.instance_variable_set(:@secret_code, [1, 2, 3, 4]) - expect(game.win?('2345')).to be_falsey + expect(game).not_to be_win('2345') end it 'returns true when user code is equal to secret code' do - expect(game.win?(game.secret_code.join)).to be_truthy + expect(game).to be_win(game.secret_code.join) end end @@ -147,6 +148,5 @@ it 'returns string which size is between 0 and 4' do expect(game.check_attempt('6163').length).to be_between(0, 4).inclusive end - end end diff --git a/spec/codebreaker/statistic_service_spec.rb b/spec/codebreaker/statistic_service_spec.rb index 74e08f3..8f235eb 100644 --- a/spec/codebreaker/statistic_service_spec.rb +++ b/spec/codebreaker/statistic_service_spec.rb @@ -1,11 +1,14 @@ RSpec.describe Codebreaker::StatisticsService do - let(:game) { Codebreaker::Game.new Codebreaker::User.new('Mechetel'), - Codebreaker::Difficulty.new('hell') } + let(:game) do + Codebreaker::Game.new Codebreaker::User.new('Mechetel'), + Codebreaker::Difficulty.new('hell') + end let(:path) { './lib/codebreaker/test.yaml' } let(:service) { described_class.new(path) } before { service.store game } - after(:each) { File.delete(path) } + + after { File.delete(path) } describe '#store' do it 'create file' do diff --git a/spec/codebreaker/user_spec.rb b/spec/codebreaker/user_spec.rb index 221c8c6..d9a9d27 100644 --- a/spec/codebreaker/user_spec.rb +++ b/spec/codebreaker/user_spec.rb @@ -45,7 +45,7 @@ describe '#valid?' do context 'when entered name is too short' do it 'returns false' do - expect(short_name_user.valid?).to be_falsey + expect(short_name_user).not_to be_valid end it 'adds ShortNameError to errors' do @@ -56,7 +56,7 @@ context 'when entered name is too long' do it 'returns false' do - expect(long_name_user.valid?).to be_falsey + expect(long_name_user).not_to be_valid end it 'adds longnameerror to errors' do @@ -67,7 +67,7 @@ context 'when entered name is not an instance of String' do it 'returns false' do - expect(invalid_user.valid?).to be_falsey + expect(invalid_user).not_to be_valid end it 'adds NameIsNotStringError to errors' do From 957597d293d258cd5453aa39328aa9d3427cd3cd Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 01:01:53 +0200 Subject: [PATCH 33/63] almost done rafactoring specs --- .rubocop.yml | 4 ++++ spec/codebreaker/game_spec.rb | 23 +++++++++---------- spec/codebreaker/guess_checker_spec.rb | 4 +--- ...ice_spec.rb => statistics_service_spec.rb} | 0 spec/codebreaker/user_spec.rb | 15 +++++++----- 5 files changed, 25 insertions(+), 21 deletions(-) rename spec/codebreaker/{statistic_service_spec.rb => statistics_service_spec.rb} (100%) diff --git a/.rubocop.yml b/.rubocop.yml index a94e0f7..be411c3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -20,6 +20,10 @@ Lint/AmbiguousBlockAssociation: Exclude: - 'spec/codebreaker/**/*' +RSpec/AnyInstance: + Exclude: + - 'spec/codebreaker/**/*' + Style/FrozenStringLiteralComment: Enabled: false diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index 04a289c..fe87271 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -1,14 +1,11 @@ require 'spec_helper' RSpec.describe Codebreaker::Game do - let(:range) { (described_class::MIN_CODE_NUM..described_class::MAX_CODE_NUM - 1).to_a } let(:user) { Codebreaker::User.new user_name } let(:user_name) { 'Mechetel' } let(:difficulty) { Codebreaker::Difficulty.new difficulty_level } let(:difficulty_level) { 'hell' } let(:game) { described_class.new user, difficulty } - let(:attempts_at_new_game) { game.difficulty.attempts } - let(:hints_at_new_game) { game.difficulty.hints } describe '#initialize' do context 'when game starts it initializes with secret number' do @@ -48,22 +45,20 @@ it 'hints list is equal to secret code' do expect(game.hints_list).to eq game_secret_number end + end + end - it 'user field class equal to User' do - expect(game.user.class).to eq Codebreaker::User - end + it 'user field class equal to User' do + expect(game.user.class).to eq Codebreaker::User + end - it 'difficulty field class equal to Difficulty' do - expect(game.difficulty.class).to eq Codebreaker::Difficulty - end - end + it 'difficulty field class equal to Difficulty' do + expect(game.difficulty.class).to eq Codebreaker::Difficulty end describe '#take_hint' do subject(:game_use_hint) { game.use_hint } - let(:game_secret_number) { game.secret_code } - it 'returns Integer' do expect(game_use_hint.class).to eq Integer end @@ -119,6 +114,10 @@ end describe '#new_game' do + subject(:hints_at_new_game) { game.difficulty.hints } + + let(:attempts_at_new_game) { game.difficulty.attempts } + before do game.new_game end diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index 6f2527a..655aebc 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -6,9 +6,7 @@ let(:nothing_symbol) { '' } describe '#initialize' do - let(:guess_checker) { described_class.new(secret_code, user_input) } - let(:secret_code) { '1234' } - let(:user_input) { '2345' } + let(:guess_checker) { described_class.new('1234', '2345') } it 'has secret_code and user_input field' do expect(guess_checker.instance_variables).to include(:@secret_code, :@user_input) diff --git a/spec/codebreaker/statistic_service_spec.rb b/spec/codebreaker/statistics_service_spec.rb similarity index 100% rename from spec/codebreaker/statistic_service_spec.rb rename to spec/codebreaker/statistics_service_spec.rb diff --git a/spec/codebreaker/user_spec.rb b/spec/codebreaker/user_spec.rb index d9a9d27..453a850 100644 --- a/spec/codebreaker/user_spec.rb +++ b/spec/codebreaker/user_spec.rb @@ -3,12 +3,6 @@ RSpec.describe Codebreaker::User do let(:user) { described_class.new name } let(:name) { 'Mechetel' } - let(:short_name_user) { described_class.new short_name } - let(:short_name) { 'Me' } - let(:long_name_user) { described_class.new long_name } - let(:long_name) { 'dima' * 10 } - let(:invalid_user) { described_class.new inappropriate_user_name } - let(:inappropriate_user_name) { 322 } describe '#name' do context 'when name set' do @@ -44,6 +38,9 @@ describe '#valid?' do context 'when entered name is too short' do + let(:short_name_user) { described_class.new short_name } + let(:short_name) { 'Me' } + it 'returns false' do expect(short_name_user).not_to be_valid end @@ -55,6 +52,9 @@ end context 'when entered name is too long' do + let(:long_name_user) { described_class.new long_name } + let(:long_name) { 'dima' * 10 } + it 'returns false' do expect(long_name_user).not_to be_valid end @@ -66,6 +66,9 @@ end context 'when entered name is not an instance of String' do + let(:invalid_user) { described_class.new inappropriate_user_name } + let(:inappropriate_user_name) { 322 } + it 'returns false' do expect(invalid_user).not_to be_valid end From 9921bf5f21e31327861f582980d811f5869f6a79 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 13:56:11 +0200 Subject: [PATCH 34/63] change sort by difficulty --- lib/codebreaker/services/statistics_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index d5fc036..9d650f8 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -15,7 +15,7 @@ def store(game) end def sort_statistics - load.sort_by { |user| [user[:attempts_total], user[:attempts_used], user[:hints_used]] } + load.sort_by { |user| [user[:difficulty], user[:attempts_used], user[:hints_used]] } end def load From 341e01fd2721576e8c3cb0cf3a800ba2d10c19e6 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 14:18:48 +0200 Subject: [PATCH 35/63] fix naming in module --- lib/codebreaker/entities/game.rb | 2 +- lib/codebreaker/modules/validator.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 26a18bf..bb35c6b 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -4,7 +4,7 @@ class Game MAX_CODE_NUM = 6 DIGITS_NUM = 4 - attr_reader :user, :difficulty, :secret_code, :errors, :date, :hints_list, :attempts, :hints + attr_reader :user, :difficulty, :secret_code, :date, :hints_list, :attempts, :hints def initialize(user, difficulty) @user = user diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb index 5d4faac..6d53891 100644 --- a/lib/codebreaker/modules/validator.rb +++ b/lib/codebreaker/modules/validator.rb @@ -2,7 +2,7 @@ module Codebreaker module Validator def valid? validate! - @errors.empty? + errors.empty? end end end From 3ffb9d128396a538db515e5719dbe60866eeb90d Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 14:28:21 +0200 Subject: [PATCH 36/63] move validations to module --- lib/codebreaker/entities/difficulty.rb | 4 ---- lib/codebreaker/entities/user.rb | 15 --------------- lib/codebreaker/modules/validator.rb | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 038b858..acae7a3 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -26,9 +26,5 @@ def hints def validate! validate_difficulty end - - def validate_difficulty - @errors << DifficultyError unless DIFFICULTIES.include? @level - end end end diff --git a/lib/codebreaker/entities/user.rb b/lib/codebreaker/entities/user.rb index a9abf4e..8b40d20 100644 --- a/lib/codebreaker/entities/user.rb +++ b/lib/codebreaker/entities/user.rb @@ -2,9 +2,6 @@ module Codebreaker class User include Validator - NAME_MIN_LENGTH = 3 - NAME_MAX_LENGTH = 20 - attr_reader :name, :errors def initialize(name) @@ -19,17 +16,5 @@ def validate! validate_name_min_length if @errors.empty? validate_name_max_length if @errors.empty? end - - def validate_name_class - @errors << NameIsNotStringError unless @name.is_a? String - end - - def validate_name_min_length - @errors << ShortNameError if @name.length < NAME_MIN_LENGTH - end - - def validate_name_max_length - @errors << LongNameError if @name.length > NAME_MAX_LENGTH - end end end diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb index 6d53891..9a0e020 100644 --- a/lib/codebreaker/modules/validator.rb +++ b/lib/codebreaker/modules/validator.rb @@ -1,8 +1,27 @@ module Codebreaker module Validator + NAME_MIN_LENGTH = 3 + NAME_MAX_LENGTH = 20 + def valid? validate! errors.empty? end + + def validate_difficulty + errors << DifficultyError unless Difficulty::DIFFICULTIES.include? level + end + + def validate_name_class + errors << NameIsNotStringError unless name.is_a? String + end + + def validate_name_min_length + errors << ShortNameError if name.length < NAME_MIN_LENGTH + end + + def validate_name_max_length + errors << LongNameError if name.length > NAME_MAX_LENGTH + end end end From 906b04da8341d0c6b967b3882848a6412da8ed54 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 18:27:25 +0200 Subject: [PATCH 37/63] refactor many validation classes to one --- lib/codebreaker.rb | 8 +------ lib/codebreaker/entities/difficulty.rb | 7 +++--- lib/codebreaker/entities/guess_checker.rb | 17 ++++++++----- lib/codebreaker/entities/user.rb | 11 ++++----- lib/codebreaker/errors/difficulty_error.rb | 7 ------ lib/codebreaker/errors/digit_range_error.rb | 7 ------ lib/codebreaker/errors/digits_count_error.rb | 7 ------ .../errors/guess_is_not_integer_error.rb | 7 ------ lib/codebreaker/errors/long_name_error.rb | 7 ------ .../errors/name_is_not_string_error.rb | 7 ------ lib/codebreaker/errors/short_name_error.rb | 7 ------ lib/codebreaker/errors/validation_error.rb | 7 ++++++ lib/codebreaker/modules/validator.rb | 24 +++++++++---------- spec/codebreaker/difficulty_spec.rb | 2 +- spec/codebreaker/guess_checker_spec.rb | 6 ++--- spec/codebreaker/user_spec.rb | 6 ++--- 16 files changed, 46 insertions(+), 91 deletions(-) delete mode 100644 lib/codebreaker/errors/difficulty_error.rb delete mode 100644 lib/codebreaker/errors/digit_range_error.rb delete mode 100644 lib/codebreaker/errors/digits_count_error.rb delete mode 100644 lib/codebreaker/errors/guess_is_not_integer_error.rb delete mode 100644 lib/codebreaker/errors/long_name_error.rb delete mode 100644 lib/codebreaker/errors/name_is_not_string_error.rb delete mode 100644 lib/codebreaker/errors/short_name_error.rb create mode 100644 lib/codebreaker/errors/validation_error.rb diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index 6ef0045..6bbb943 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -3,13 +3,7 @@ require 'yaml' require 'pry' -require_relative 'codebreaker/errors/guess_is_not_integer_error' -require_relative 'codebreaker/errors/name_is_not_string_error' -require_relative 'codebreaker/errors/short_name_error' -require_relative 'codebreaker/errors/long_name_error' -require_relative 'codebreaker/errors/difficulty_error' -require_relative 'codebreaker/errors/digit_range_error' -require_relative 'codebreaker/errors/digits_count_error' +require_relative 'codebreaker/errors/validation_error' require_relative 'codebreaker/modules/validator' diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index acae7a3..4b825a0 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -21,10 +21,9 @@ def hints DIFFICULTIES[@level][:hints] end - private - - def validate! - validate_difficulty + def valid? + validate_difficulty(@level, @errors) + @errors.empty? end end end diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index c871fc9..0d4445b 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -1,8 +1,11 @@ module Codebreaker class GuessChecker - RIGHT_ANSWER_SYMBOL = '+'.freeze - WRONG_ANSWER_SYMBOL = '-'.freeze - NOTHING_SYMBOL = ''.freeze + RIGHT_ANSWER_SYMBOL = '+'.freeze + WRONG_ANSWER_SYMBOL = '-'.freeze + NOTHING_SYMBOL = ''.freeze + GUESS_IS_NOT_INTEGER = 'Guess should be Integer class'.freeze + DIGITS_COUNT_ERROR = 'Invalid digits count'.freeze + DIGIT_RANGE_ERROR = 'Digit is not in a range'.freeze def initialize(code, input) @secret_code = code.to_s.split(NOTHING_SYMBOL).map(&:to_i) @@ -14,9 +17,11 @@ def check end def self.validate(guess) - raise GuessIsNotInteger unless guess[/^\d+$/] - raise DigitsCountError unless guess.size == Game::DIGITS_NUM - raise DigitRangeError unless guess.chars.all? { |num| num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM } + raise ValidationError, GUESS_IS_NOT_INTEGER unless guess[/^\d+$/] + raise ValidationError, DIGITS_COUNT_ERROR unless guess.size == Game::DIGITS_NUM + raise ValidationError, DIGIT_RANGE_ERROR unless guess.chars.all? do |num| + num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM + end end private diff --git a/lib/codebreaker/entities/user.rb b/lib/codebreaker/entities/user.rb index 8b40d20..76dcd9d 100644 --- a/lib/codebreaker/entities/user.rb +++ b/lib/codebreaker/entities/user.rb @@ -9,12 +9,11 @@ def initialize(name) @errors = [] end - private - - def validate! - validate_name_class - validate_name_min_length if @errors.empty? - validate_name_max_length if @errors.empty? + def valid? + validate_name_class(@name, @errors) + validate_name_min_length(@name, @errors) if @errors.empty? + validate_name_max_length(@name, @errors) if @errors.empty? + @errors.empty? end end end diff --git a/lib/codebreaker/errors/difficulty_error.rb b/lib/codebreaker/errors/difficulty_error.rb deleted file mode 100644 index 280b34c..0000000 --- a/lib/codebreaker/errors/difficulty_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class DifficultyError < StandardError - def message - 'No such difficulty' - end - end -end diff --git a/lib/codebreaker/errors/digit_range_error.rb b/lib/codebreaker/errors/digit_range_error.rb deleted file mode 100644 index a83c09d..0000000 --- a/lib/codebreaker/errors/digit_range_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class DigitRangeError < StandardError - def message - 'Digit is not in a range' - end - end -end diff --git a/lib/codebreaker/errors/digits_count_error.rb b/lib/codebreaker/errors/digits_count_error.rb deleted file mode 100644 index bab0254..0000000 --- a/lib/codebreaker/errors/digits_count_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class DigitsCountError < StandardError - def message - 'Invalid digits count' - end - end -end diff --git a/lib/codebreaker/errors/guess_is_not_integer_error.rb b/lib/codebreaker/errors/guess_is_not_integer_error.rb deleted file mode 100644 index 271ec40..0000000 --- a/lib/codebreaker/errors/guess_is_not_integer_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class GuessIsNotInteger < StandardError - def message - 'Guess should be Integer class' - end - end -end diff --git a/lib/codebreaker/errors/long_name_error.rb b/lib/codebreaker/errors/long_name_error.rb deleted file mode 100644 index 373957b..0000000 --- a/lib/codebreaker/errors/long_name_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class LongNameError < StandardError - def message - 'Name is too long' - end - end -end diff --git a/lib/codebreaker/errors/name_is_not_string_error.rb b/lib/codebreaker/errors/name_is_not_string_error.rb deleted file mode 100644 index 04f281d..0000000 --- a/lib/codebreaker/errors/name_is_not_string_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class NameIsNotStringError < StandardError - def message - 'Name should be an instance of String' - end - end -end diff --git a/lib/codebreaker/errors/short_name_error.rb b/lib/codebreaker/errors/short_name_error.rb deleted file mode 100644 index e67a182..0000000 --- a/lib/codebreaker/errors/short_name_error.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Codebreaker - class ShortNameError < StandardError - def message - 'Name is too short' - end - end -end diff --git a/lib/codebreaker/errors/validation_error.rb b/lib/codebreaker/errors/validation_error.rb new file mode 100644 index 0000000..89882fc --- /dev/null +++ b/lib/codebreaker/errors/validation_error.rb @@ -0,0 +1,7 @@ +module Codebreaker + class ValidationError < StandardError + def initialize(msg = 'Validation error') + super(msg) + end + end +end diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb index 9a0e020..70fa8fc 100644 --- a/lib/codebreaker/modules/validator.rb +++ b/lib/codebreaker/modules/validator.rb @@ -3,25 +3,25 @@ module Validator NAME_MIN_LENGTH = 3 NAME_MAX_LENGTH = 20 - def valid? - validate! - errors.empty? - end + DIFFICULTY_ERROR = 'No such difficulty'.freeze + NAME_IS_NOT_STRING_ERROR = 'Name should be an instance of String'.freeze + SHORT_NAME_ERROR = 'Name is too short'.freeze + LONG_NAME_ERROR = 'Name is too long'.freeze - def validate_difficulty - errors << DifficultyError unless Difficulty::DIFFICULTIES.include? level + def validate_difficulty(level, errors) + errors << ValidationError.new(DIFFICULTY_ERROR) unless Difficulty::DIFFICULTIES.include? level end - def validate_name_class - errors << NameIsNotStringError unless name.is_a? String + def validate_name_class(name, errors) + errors << ValidationError.new(NAME_IS_NOT_STRING_ERROR) unless name.is_a? String end - def validate_name_min_length - errors << ShortNameError if name.length < NAME_MIN_LENGTH + def validate_name_min_length(name, errors) + errors << ValidationError.new(SHORT_NAME_ERROR) if name.length < NAME_MIN_LENGTH end - def validate_name_max_length - errors << LongNameError if name.length > NAME_MAX_LENGTH + def validate_name_max_length(name, errors) + errors << ValidationError.new(LONG_NAME_ERROR) if name.length > NAME_MAX_LENGTH end end end diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb index 3856bf1..f347fa2 100644 --- a/spec/codebreaker/difficulty_spec.rb +++ b/spec/codebreaker/difficulty_spec.rb @@ -47,7 +47,7 @@ it 'adds DifficultyError to errors' do invalid_difficulty.valid? - expect(invalid_difficulty.errors).to include Codebreaker::DifficultyError + expect(invalid_difficulty.errors).to include Codebreaker::ValidationError end end diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index 655aebc..73bd747 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -29,15 +29,15 @@ describe '#validate' do it 'raises DigitsCountError when digits count is invalid' do - expect { described_class.validate('102') }.to raise_error Codebreaker::DigitsCountError + expect { described_class.validate('102') }.to raise_error Codebreaker::ValidationError end it 'raises DigitsCountError when guess is not a numbers' do - expect { described_class.validate('sdfg') }.to raise_error Codebreaker::GuessIsNotInteger + expect { described_class.validate('sdfg') }.to raise_error Codebreaker::ValidationError end it 'raises DigitRangeError when any digit is not in the range' do - expect { described_class.validate('6969') }.to raise_error Codebreaker::DigitRangeError + expect { described_class.validate('6969') }.to raise_error Codebreaker::ValidationError end end diff --git a/spec/codebreaker/user_spec.rb b/spec/codebreaker/user_spec.rb index 453a850..64b7720 100644 --- a/spec/codebreaker/user_spec.rb +++ b/spec/codebreaker/user_spec.rb @@ -47,7 +47,7 @@ it 'adds ShortNameError to errors' do short_name_user.valid? - expect(short_name_user.errors).to include Codebreaker::ShortNameError + expect(short_name_user.errors).to include Codebreaker::ValidationError end end @@ -61,7 +61,7 @@ it 'adds longnameerror to errors' do long_name_user.valid? - expect(long_name_user.errors).to include Codebreaker::LongNameError + expect(long_name_user.errors).to include Codebreaker::ValidationError end end @@ -75,7 +75,7 @@ it 'adds NameIsNotStringError to errors' do invalid_user.valid? - expect(invalid_user.errors).to include Codebreaker::NameIsNotStringError + expect(invalid_user.errors).to include Codebreaker::ValidationError end end end From 544b4969502f97a525dc3ae656ec47d993dad49b Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 20:07:25 +0200 Subject: [PATCH 38/63] change logic of validation class --- lib/codebreaker/errors/validation_error.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codebreaker/errors/validation_error.rb b/lib/codebreaker/errors/validation_error.rb index 89882fc..fb0ce53 100644 --- a/lib/codebreaker/errors/validation_error.rb +++ b/lib/codebreaker/errors/validation_error.rb @@ -1,7 +1,9 @@ module Codebreaker class ValidationError < StandardError + attr_reader :message def initialize(msg = 'Validation error') super(msg) + @message = msg end end end From 50e022eafddeaea92574f7953ed295475ccc13af Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 11 Mar 2021 20:13:37 +0200 Subject: [PATCH 39/63] undo last commit --- lib/codebreaker/errors/validation_error.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/codebreaker/errors/validation_error.rb b/lib/codebreaker/errors/validation_error.rb index fb0ce53..89882fc 100644 --- a/lib/codebreaker/errors/validation_error.rb +++ b/lib/codebreaker/errors/validation_error.rb @@ -1,9 +1,7 @@ module Codebreaker class ValidationError < StandardError - attr_reader :message def initialize(msg = 'Validation error') super(msg) - @message = msg end end end From 978e4a01e4c3fac8c809d296a8b189bbdfc8865a Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 12 Mar 2021 16:32:20 +0200 Subject: [PATCH 40/63] test sorting by attempts --- lib/codebreaker/services/statistics_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index 9d650f8..d4090b2 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -15,7 +15,7 @@ def store(game) end def sort_statistics - load.sort_by { |user| [user[:difficulty], user[:attempts_used], user[:hints_used]] } + load.sort_by { |user| [-user[:attempts_total], user[:attempts_used], user[:hints_used]] } end def load From ad97b17aac08c51b8588eb17bed3fa5ed08a5904 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 12 Mar 2021 16:39:40 +0200 Subject: [PATCH 41/63] undo test sorting --- lib/codebreaker/services/statistics_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index d4090b2..d5fc036 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -15,7 +15,7 @@ def store(game) end def sort_statistics - load.sort_by { |user| [-user[:attempts_total], user[:attempts_used], user[:hints_used]] } + load.sort_by { |user| [user[:attempts_total], user[:attempts_used], user[:hints_used]] } end def load From 766d9ab94ce3f9433f1205e0c95a25968bc24982 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 18 Mar 2021 10:19:04 +0200 Subject: [PATCH 42/63] change .split(NOTHING_SYMBOL) to .chars --- lib/codebreaker/entities/guess_checker.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 0d4445b..3482c27 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -8,8 +8,8 @@ class GuessChecker DIGIT_RANGE_ERROR = 'Digit is not in a range'.freeze def initialize(code, input) - @secret_code = code.to_s.split(NOTHING_SYMBOL).map(&:to_i) - @user_input = input.to_s.split(NOTHING_SYMBOL).map(&:to_i) + @secret_code = code.to_s.chars.map(&:to_i) + @user_input = input.to_s.chars.map(&:to_i) end def check From 02853e4fe1408b5f19c9fd8bff1956daaa82774d Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 18 Mar 2021 10:44:03 +0200 Subject: [PATCH 43/63] change all about hints --- lib/codebreaker/entities/game.rb | 7 ++----- spec/codebreaker/game_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index bb35c6b..2094bf3 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -12,16 +12,13 @@ def initialize(user, difficulty) @attempts = @difficulty.attempts @hints = @difficulty.hints @secret_code = generate_secret_code - @hints_list = secret_code.clone + @hints_list = @secret_code.shuffle @date = Time.now.getlocal end def use_hint @hints -= 1 - index = rand(@hints_list.size) - digit = hints_list[index] - @hints_list.delete_at index - digit + @hints_list.pop end def check_attempt(guess) diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index fe87271..8976a81 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -11,7 +11,7 @@ context 'when game starts it initializes with secret number' do subject(:game_secret_number) { game.secret_code } - let(:secret_number) { '6616' } + let(:secret_number) { [6, 6, 1, 6] } it 'has secret number' do allow_any_instance_of(described_class).to receive(:generate_secret_code).and_return(secret_number) @@ -43,7 +43,7 @@ end it 'hints list is equal to secret code' do - expect(game.hints_list).to eq game_secret_number + expect(game.hints_list).not_to eq game_secret_number end end end From 05ec41ea1cfcbcc06a3f9b21638f910810904df6 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 18 Mar 2021 10:48:58 +0200 Subject: [PATCH 44/63] delete new_game method --- lib/codebreaker/entities/game.rb | 7 ------- spec/codebreaker/game_spec.rb | 26 -------------------------- 2 files changed, 33 deletions(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 2094bf3..6d71222 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -26,13 +26,6 @@ def check_attempt(guess) GuessChecker.new(@secret_code.join, guess).check end - def new_game - @secret_code = generate_secret_code - @hints_list = @secret_code.clone - @attempts = @difficulty.attempts.clone - @hints = @difficulty.hints.clone - end - def lose? @attempts.zero? end diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index 8976a81..cee4c4f 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -113,32 +113,6 @@ end end - describe '#new_game' do - subject(:hints_at_new_game) { game.difficulty.hints } - - let(:attempts_at_new_game) { game.difficulty.attempts } - - before do - game.new_game - end - - it 'set secret code Array to secret_code' do - expect(game.secret_code.class).to eq Array - end - - it 'set secret code to hints_list' do - expect(game.hints_list).to eq game.secret_code - end - - it 'current_attempts are equal to previous game current_attempts' do - expect(game.attempts).to eq attempts_at_new_game - end - - it 'current_hints are equal to previous game current_hints' do - expect(game.hints).to eq hints_at_new_game - end - end - describe '#check_attempt' do it 'returns String' do expect(game.check_attempt('2456').class).to eq String From 3c8cd5c8c29a339d6a85a061dfb22e3f748580b3 Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 18 Mar 2021 11:13:27 +0200 Subject: [PATCH 45/63] change store method + remove nothing symbol --- lib/codebreaker/entities/guess_checker.rb | 1 - lib/codebreaker/services/statistics_service.rb | 8 ++++---- spec/codebreaker/guess_checker_spec.rb | 5 ----- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 3482c27..29599f7 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -2,7 +2,6 @@ module Codebreaker class GuessChecker RIGHT_ANSWER_SYMBOL = '+'.freeze WRONG_ANSWER_SYMBOL = '-'.freeze - NOTHING_SYMBOL = ''.freeze GUESS_IS_NOT_INTEGER = 'Guess should be Integer class'.freeze DIGITS_COUNT_ERROR = 'Invalid digits count'.freeze DIGIT_RANGE_ERROR = 'Digit is not in a range'.freeze diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index d5fc036..c60f4be 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -7,7 +7,7 @@ def initialize(path) end def store(game) - statistics = File.exist?(@path) && !File.zero?(@path) ? YAML.load_file(@path) : [] + statistics = load || [] statistics << game_to_h(game) file = File.open(@path, 'w') file.write(statistics.to_yaml) @@ -19,9 +19,9 @@ def sort_statistics end def load - return unless File.exist? @path - - YAML.load_file @path + if File.exist?(@path) && !File.zero?(@path) + YAML.load_file(@path) + end end private diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index 73bd747..ffa5d16 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -3,7 +3,6 @@ RSpec.describe Codebreaker::GuessChecker do let(:plus_symbol) { '+' } let(:minus_symbol) { '-' } - let(:nothing_symbol) { '' } describe '#initialize' do let(:guess_checker) { described_class.new('1234', '2345') } @@ -21,10 +20,6 @@ it 'check content of WRONG_ANSWER_SYMBOL constant' do expect(described_class::WRONG_ANSWER_SYMBOL).to eq(minus_symbol) end - - it 'check content of NOTHING_SYMBOL constant' do - expect(described_class::NOTHING_SYMBOL).to eq(nothing_symbol) - end end describe '#validate' do From ee73ec059e9578ae1cef2f6de67b5b3ba81ffa1d Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 18 Mar 2021 11:43:53 +0200 Subject: [PATCH 46/63] refactor --- lib/codebreaker/services/statistics_service.rb | 4 +--- spec/codebreaker/difficulty_spec.rb | 4 ++-- spec/codebreaker/game_spec.rb | 12 +++++------- spec/codebreaker/guess_checker_spec.rb | 4 ++-- spec/codebreaker/statistics_service_spec.rb | 5 +---- 5 files changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index c60f4be..11e48d8 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -19,9 +19,7 @@ def sort_statistics end def load - if File.exist?(@path) && !File.zero?(@path) - YAML.load_file(@path) - end + YAML.load_file(@path) if File.exist?(@path) && !File.zero?(@path) end private diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb index f347fa2..ed7afca 100644 --- a/spec/codebreaker/difficulty_spec.rb +++ b/spec/codebreaker/difficulty_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' RSpec.describe Codebreaker::Difficulty do - let(:difficulty) { described_class.new level } + let(:difficulty) { described_class.new(level) } let(:level) { 'easy' } - let(:invalid_difficulty) { described_class.new invalid_level } + let(:invalid_difficulty) { described_class.new(invalid_level) } let(:invalid_level) { 'qwerty' } let(:difficulty_constant) do { easy: { attempts: 15, hints: 2 }, diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index cee4c4f..fc55539 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -1,21 +1,19 @@ require 'spec_helper' RSpec.describe Codebreaker::Game do - let(:user) { Codebreaker::User.new user_name } + let(:user) { Codebreaker::User.new(user_name) } let(:user_name) { 'Mechetel' } - let(:difficulty) { Codebreaker::Difficulty.new difficulty_level } + let(:difficulty) { Codebreaker::Difficulty.new(difficulty_level) } let(:difficulty_level) { 'hell' } - let(:game) { described_class.new user, difficulty } + let(:game) { described_class.new(user, difficulty) } describe '#initialize' do context 'when game starts it initializes with secret number' do subject(:game_secret_number) { game.secret_code } - let(:secret_number) { [6, 6, 1, 6] } - it 'has secret number' do - allow_any_instance_of(described_class).to receive(:generate_secret_code).and_return(secret_number) - expect(game_secret_number).to eq(secret_number) + allow_any_instance_of(described_class).to receive(:generate_secret_code).and_return([6, 6, 1, 6]) + expect(game_secret_number).to eq([6, 6, 1, 6]) end it 'has valid secret number length' do diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index ffa5d16..8742cca 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -14,11 +14,11 @@ describe 'check GuessChecker constants' do it 'check content of RIGHT_ANSWER_SYMBOL constant' do - expect(described_class::RIGHT_ANSWER_SYMBOL).to eq(plus_symbol) + expect(described_class::RIGHT_ANSWER_SYMBOL).to eq plus_symbol end it 'check content of WRONG_ANSWER_SYMBOL constant' do - expect(described_class::WRONG_ANSWER_SYMBOL).to eq(minus_symbol) + expect(described_class::WRONG_ANSWER_SYMBOL).to eq minus_symbol end end diff --git a/spec/codebreaker/statistics_service_spec.rb b/spec/codebreaker/statistics_service_spec.rb index 8f235eb..a0781be 100644 --- a/spec/codebreaker/statistics_service_spec.rb +++ b/spec/codebreaker/statistics_service_spec.rb @@ -1,8 +1,5 @@ RSpec.describe Codebreaker::StatisticsService do - let(:game) do - Codebreaker::Game.new Codebreaker::User.new('Mechetel'), - Codebreaker::Difficulty.new('hell') - end + let(:game) { Codebreaker::Game.new(Codebreaker::User.new('Mechetel'), Codebreaker::Difficulty.new('hell')) } let(:path) { './lib/codebreaker/test.yaml' } let(:service) { described_class.new(path) } From d297ba695bfb39b2568b59c8bd5c366293484503 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 19 Mar 2021 13:46:55 +0200 Subject: [PATCH 47/63] add new method --- lib/codebreaker/services/statistics_service.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index 11e48d8..114ce5b 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -19,11 +19,17 @@ def sort_statistics end def load + make_files(@path) YAML.load_file(@path) if File.exist?(@path) && !File.zero?(@path) end private + def make_files(file_path) + Dir.mkdir('db') unless Dir.exist?('db') + File.new(file_path, 'w') unless File.exist?(file_path) + end + def game_to_h(game) { name: game.user.name, From 694a349644da74c08d63d178319bef5661361495 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 19 Mar 2021 13:57:24 +0200 Subject: [PATCH 48/63] hints total fix --- lib/codebreaker/services/statistics_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index 114ce5b..0ae1ee5 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -36,7 +36,7 @@ def game_to_h(game) difficulty: game.difficulty.level.to_s, attempts_total: game.difficulty.attempts, attempts_used: game.difficulty.attempts - game.attempts, - hints_total: game.hints, + hints_total: game.difficulty.hints, hints_used: game.difficulty.hints - game.hints, date: game.date } From 9e92f436ba0aed703a4b599431a3d42b6b9401e2 Mon Sep 17 00:00:00 2001 From: mechetel Date: Fri, 19 Mar 2021 14:05:31 +0200 Subject: [PATCH 49/63] refactor to fix lintering --- lib/codebreaker/services/statistics_service.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index 0ae1ee5..10dc2d1 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -31,13 +31,14 @@ def make_files(file_path) end def game_to_h(game) + game_difficulty = game.difficulty { name: game.user.name, - difficulty: game.difficulty.level.to_s, - attempts_total: game.difficulty.attempts, - attempts_used: game.difficulty.attempts - game.attempts, - hints_total: game.difficulty.hints, - hints_used: game.difficulty.hints - game.hints, + difficulty: game_difficulty.level.to_s, + attempts_total: game_difficulty.attempts, + attempts_used: game_difficulty.attempts - game.attempts, + hints_total: game_difficulty.hints, + hints_used: game_difficulty.hints - game.hints, date: game.date } end From f4c115cc0d83f27a539d8bf06821209f67923ec3 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 20 Mar 2021 19:59:27 +0200 Subject: [PATCH 50/63] refactor --- Gemfile.lock | 4 ++++ codebreaker.gemspec | 1 + lib/codebreaker.rb | 4 ++++ lib/codebreaker/entities/guess_checker.rb | 21 +++++++++--------- lib/codebreaker/modules/validator.rb | 27 +++++++++++++++-------- locales/en.yml | 8 +++++++ 6 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 locales/en.yml diff --git a/Gemfile.lock b/Gemfile.lock index 7ee1cf4..a01ccd3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -18,6 +18,7 @@ GEM coercible (1.0.0) descendants_tracker (~> 0.0.1) colorize (0.8.1) + concurrent-ruby (1.1.8) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.4.4) @@ -36,6 +37,8 @@ GEM path_expander (~> 1.0) ruby_parser (~> 3.1, > 3.1.0) sexp_processor (~> 4.8) + i18n (1.8.9) + concurrent-ruby (~> 1.0) ice_nine (0.11.2) kwalify (0.7.2) launchy (2.5.0) @@ -129,6 +132,7 @@ PLATFORMS DEPENDENCIES codebreaker! fasterer + i18n pry-byebug rake rspec diff --git a/codebreaker.gemspec b/codebreaker.gemspec index 87d634a..e282019 100644 --- a/codebreaker.gemspec +++ b/codebreaker.gemspec @@ -28,6 +28,7 @@ Gem::Specification.new do |spec| # spec.add_dependency "example-gem", "~> 1.0" spec.add_development_dependency 'pry-byebug' + spec.add_development_dependency 'i18n' spec.add_development_dependency 'rake' spec.add_development_dependency 'fasterer' spec.add_development_dependency 'rspec' diff --git a/lib/codebreaker.rb b/lib/codebreaker.rb index 6bbb943..1e764d4 100644 --- a/lib/codebreaker.rb +++ b/lib/codebreaker.rb @@ -2,6 +2,10 @@ require 'yaml' require 'pry' +require 'i18n' + +I18n.load_path << Dir["#{File.expand_path('locales')}/*.yml"] +I18n.default_locale = :en require_relative 'codebreaker/errors/validation_error' diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 29599f7..72529f8 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -1,10 +1,9 @@ module Codebreaker class GuessChecker + extend Validator + RIGHT_ANSWER_SYMBOL = '+'.freeze WRONG_ANSWER_SYMBOL = '-'.freeze - GUESS_IS_NOT_INTEGER = 'Guess should be Integer class'.freeze - DIGITS_COUNT_ERROR = 'Invalid digits count'.freeze - DIGIT_RANGE_ERROR = 'Digit is not in a range'.freeze def initialize(code, input) @secret_code = code.to_s.chars.map(&:to_i) @@ -16,11 +15,9 @@ def check end def self.validate(guess) - raise ValidationError, GUESS_IS_NOT_INTEGER unless guess[/^\d+$/] - raise ValidationError, DIGITS_COUNT_ERROR unless guess.size == Game::DIGITS_NUM - raise ValidationError, DIGIT_RANGE_ERROR unless guess.chars.all? do |num| - num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM - end + validate_guess_count(guess) + validate_guess_for_not_integer(guess) + validate_guess_range(guess) end private @@ -29,8 +26,7 @@ def pluses answer = '' @user_input.map.with_index do |number, index| if @secret_code[index] == number - answer << RIGHT_ANSWER_SYMBOL - @secret_code[index], @user_input[index] = nil + pluses_helper(answer, index) end end answer @@ -44,5 +40,10 @@ def minuses near_matchers.size.times { answer << WRONG_ANSWER_SYMBOL } answer end + + def pluses_helper(answer, index) + answer << RIGHT_ANSWER_SYMBOL + @secret_code[index], @user_input[index] = nil + end end end diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb index 70fa8fc..9fdd195 100644 --- a/lib/codebreaker/modules/validator.rb +++ b/lib/codebreaker/modules/validator.rb @@ -3,25 +3,34 @@ module Validator NAME_MIN_LENGTH = 3 NAME_MAX_LENGTH = 20 - DIFFICULTY_ERROR = 'No such difficulty'.freeze - NAME_IS_NOT_STRING_ERROR = 'Name should be an instance of String'.freeze - SHORT_NAME_ERROR = 'Name is too short'.freeze - LONG_NAME_ERROR = 'Name is too long'.freeze - def validate_difficulty(level, errors) - errors << ValidationError.new(DIFFICULTY_ERROR) unless Difficulty::DIFFICULTIES.include? level + errors << ValidationError.new(I18n.t('difficulty_error')) unless Difficulty::DIFFICULTIES.include? level end def validate_name_class(name, errors) - errors << ValidationError.new(NAME_IS_NOT_STRING_ERROR) unless name.is_a? String + errors << ValidationError.new(I18n.t('name_is_not_string_error')) unless name.is_a? String end def validate_name_min_length(name, errors) - errors << ValidationError.new(SHORT_NAME_ERROR) if name.length < NAME_MIN_LENGTH + errors << ValidationError.new(I18n.t('short_name_error')) if name.length < NAME_MIN_LENGTH end def validate_name_max_length(name, errors) - errors << ValidationError.new(LONG_NAME_ERROR) if name.length > NAME_MAX_LENGTH + errors << ValidationError.new(I18n.t('long_name_error')) if name.length > NAME_MAX_LENGTH + end + + def validate_guess_for_not_integer(guess) + raise ValidationError, I18n.t('guess_is_not_integer') unless guess[/^\d+$/] + end + + def validate_guess_count(guess) + raise ValidationError, I18n.t('digits_count_error') unless guess.size == Game::DIGITS_NUM + end + + def validate_guess_range(guess) + raise ValidationError, I18n.t('digit_range_error') unless guess.chars.all? do |num| + num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM + end end end end diff --git a/locales/en.yml b/locales/en.yml new file mode 100644 index 0000000..b50a86f --- /dev/null +++ b/locales/en.yml @@ -0,0 +1,8 @@ +en: + guess_is_not_integer: 'Guess should be Integer class' + digits_count_error: 'Invalid digits count' + digit_range_error: 'Digit is not in a range' + difficulty_error: 'No such difficulty' + name_is_not_string_error: 'Name should be an instance of String' + short_name_error: 'Name is too short' + long_name_error: 'Name is too long' From 5a3284f13609fe69d4c2fa5652f80b064c6ad99e Mon Sep 17 00:00:00 2001 From: mechetel Date: Sat, 20 Mar 2021 20:01:38 +0200 Subject: [PATCH 51/63] refactor by rubocop --- lib/codebreaker/entities/guess_checker.rb | 4 +--- lib/codebreaker/modules/validator.rb | 5 +++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 72529f8..97192fe 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -25,9 +25,7 @@ def self.validate(guess) def pluses answer = '' @user_input.map.with_index do |number, index| - if @secret_code[index] == number - pluses_helper(answer, index) - end + pluses_helper(answer, index) if @secret_code[index] == number end answer end diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb index 9fdd195..9caca3a 100644 --- a/lib/codebreaker/modules/validator.rb +++ b/lib/codebreaker/modules/validator.rb @@ -29,8 +29,9 @@ def validate_guess_count(guess) def validate_guess_range(guess) raise ValidationError, I18n.t('digit_range_error') unless guess.chars.all? do |num| - num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM - end + num.to_i.between? Game::MIN_CODE_NUM, + Game::MAX_CODE_NUM + end end end end From c54ffbeb4eeeb1a7ac1ccd9b35907a819d4f7b5c Mon Sep 17 00:00:00 2001 From: mechetel Date: Sun, 21 Mar 2021 00:41:05 +0200 Subject: [PATCH 52/63] refactor check method --- lib/codebreaker/entities/game.rb | 2 +- lib/codebreaker/entities/guess_checker.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 6d71222..12951f8 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -23,7 +23,7 @@ def use_hint def check_attempt(guess) @attempts -= 1 - GuessChecker.new(@secret_code.join, guess).check + GuessChecker.new(@secret_code, guess).check end def lose? diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 97192fe..2b99e2a 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -7,7 +7,7 @@ class GuessChecker def initialize(code, input) @secret_code = code.to_s.chars.map(&:to_i) - @user_input = input.to_s.chars.map(&:to_i) + @user_input = input.chars.map(&:to_i) end def check From 36d06d794acda2989edb4477544a1d304a5e17b7 Mon Sep 17 00:00:00 2001 From: mechetel Date: Sun, 21 Mar 2021 00:57:15 +0200 Subject: [PATCH 53/63] some more refactor check method --- lib/codebreaker/entities/game.rb | 2 +- lib/codebreaker/entities/guess_checker.rb | 2 +- spec/codebreaker/guess_checker_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index 12951f8..d0d2c01 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -23,7 +23,7 @@ def use_hint def check_attempt(guess) @attempts -= 1 - GuessChecker.new(@secret_code, guess).check + GuessChecker.new(@secret_code.clone, guess).check end def lose? diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index 2b99e2a..b4cbecc 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -6,7 +6,7 @@ class GuessChecker WRONG_ANSWER_SYMBOL = '-'.freeze def initialize(code, input) - @secret_code = code.to_s.chars.map(&:to_i) + @secret_code = code @user_input = input.chars.map(&:to_i) end diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index 8742cca..e8bb099 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -52,7 +52,7 @@ { secret_number: '1234', input: '1234', result: '++++' } ].each do |line| it "returns #{line[:result]} when secret number - #{line[:secret_number]} and input - #{line[:input]}" do - expect(described_class.new(line[:secret_number], line[:input]).check).to eq(line[:result]) + expect(described_class.new(line[:secret_number].chars.map(&:to_i), line[:input]).check).to eq(line[:result]) end end end From a09328044cd1e1c65466b6e27466cfd24234e50c Mon Sep 17 00:00:00 2001 From: mechetel Date: Sun, 21 Mar 2021 01:26:36 +0200 Subject: [PATCH 54/63] spec vars to consts --- lib/codebreaker/entities/guess_checker.rb | 4 +--- spec/codebreaker/difficulty_spec.rb | 12 +----------- spec/codebreaker/guess_checker_spec.rb | 13 ------------- spec/codebreaker/statistics_service_spec.rb | 2 +- 4 files changed, 3 insertions(+), 28 deletions(-) diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index b4cbecc..eb37564 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -31,12 +31,10 @@ def pluses end def minuses - answer = '' @user_input.compact! @secret_code.compact! near_matchers = @secret_code & @user_input - near_matchers.size.times { answer << WRONG_ANSWER_SYMBOL } - answer + Array.new(near_matchers.size) { '-' }.join end def pluses_helper(answer, index) diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb index ed7afca..8e73b23 100644 --- a/spec/codebreaker/difficulty_spec.rb +++ b/spec/codebreaker/difficulty_spec.rb @@ -5,11 +5,7 @@ let(:level) { 'easy' } let(:invalid_difficulty) { described_class.new(invalid_level) } let(:invalid_level) { 'qwerty' } - let(:difficulty_constant) do - { easy: { attempts: 15, hints: 2 }, - medium: { attempts: 10, hints: 1 }, - hell: { attempts: 5, hints: 1 } } - end + let(:difficulty_constant) { Difficulty::DIFFICULTIES } describe '#level' do context 'when level set' do @@ -33,12 +29,6 @@ end end - describe 'check Difficulty constants' do - it 'check content of DIFFICULTIES constant' do - expect(described_class::DIFFICULTIES).to eq(difficulty_constant) - end - end - describe '#valid?' do context 'when entered level of difficulty is wrong' do it 'validation returns false' do diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index e8bb099..cebeeff 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -1,9 +1,6 @@ require 'spec_helper' RSpec.describe Codebreaker::GuessChecker do - let(:plus_symbol) { '+' } - let(:minus_symbol) { '-' } - describe '#initialize' do let(:guess_checker) { described_class.new('1234', '2345') } @@ -12,16 +9,6 @@ end end - describe 'check GuessChecker constants' do - it 'check content of RIGHT_ANSWER_SYMBOL constant' do - expect(described_class::RIGHT_ANSWER_SYMBOL).to eq plus_symbol - end - - it 'check content of WRONG_ANSWER_SYMBOL constant' do - expect(described_class::WRONG_ANSWER_SYMBOL).to eq minus_symbol - end - end - describe '#validate' do it 'raises DigitsCountError when digits count is invalid' do expect { described_class.validate('102') }.to raise_error Codebreaker::ValidationError diff --git a/spec/codebreaker/statistics_service_spec.rb b/spec/codebreaker/statistics_service_spec.rb index a0781be..87235e8 100644 --- a/spec/codebreaker/statistics_service_spec.rb +++ b/spec/codebreaker/statistics_service_spec.rb @@ -1,6 +1,6 @@ RSpec.describe Codebreaker::StatisticsService do let(:game) { Codebreaker::Game.new(Codebreaker::User.new('Mechetel'), Codebreaker::Difficulty.new('hell')) } - let(:path) { './lib/codebreaker/test.yaml' } + let(:path) { './lib/codebreaker/.yaml' } let(:service) { described_class.new(path) } before { service.store game } From c6f2084fbe0a41b2f9f7e1e9da2403032d6d6fcc Mon Sep 17 00:00:00 2001 From: mechetel Date: Thu, 15 Apr 2021 20:26:45 +0300 Subject: [PATCH 55/63] refactor after review --- .rubocop.yml | 12 --------- Gemfile.lock | 35 ++++++++++++++------------ codebreaker.gemspec | 29 ++++++++------------- spec/codebreaker/difficulty_spec.rb | 20 ++++++++++----- spec/codebreaker/game_spec.rb | 7 ++---- spec/codebreaker/guess_checker_spec.rb | 2 -- spec/codebreaker/user_spec.rb | 23 +++++++++++++---- spec/codebreaker_spec.rb | 2 -- 8 files changed, 64 insertions(+), 66 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index be411c3..19ce8b6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -12,18 +12,6 @@ Metrics/BlockLength: Exclude: - 'spec/codebreaker/**/*' -Metrics/ModuleLength: - Exclude: - - 'spec/codebreaker/**/*' - -Lint/AmbiguousBlockAssociation: - Exclude: - - 'spec/codebreaker/**/*' - -RSpec/AnyInstance: - Exclude: - - 'spec/codebreaker/**/*' - Style/FrozenStringLiteralComment: Enabled: false diff --git a/Gemfile.lock b/Gemfile.lock index a01ccd3..07dfb8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -37,7 +37,7 @@ GEM path_expander (~> 1.0) ruby_parser (~> 3.1, > 3.1.0) sexp_processor (~> 4.8) - i18n (1.8.9) + i18n (1.8.10) concurrent-ruby (~> 1.0) ice_nine (0.11.2) kwalify (0.7.2) @@ -45,7 +45,7 @@ GEM addressable (~> 2.7) method_source (1.0.0) parallel (1.20.1) - parser (3.0.0.0) + parser (3.0.1.0) ast (~> 2.4.1) path_expander (1.1.0) pry (0.13.1) @@ -64,7 +64,7 @@ GEM psych (~> 3.1) rainbow (>= 2.0, < 4.0) regexp_parser (2.1.1) - rexml (3.2.4) + rexml (3.2.5) rspec (3.10.0) rspec-core (~> 3.10.0) rspec-expectations (~> 3.10.0) @@ -78,7 +78,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.10.0) rspec-support (3.10.2) - rubocop (1.11.0) + rubocop (1.12.1) parallel (~> 1.10) parser (>= 3.0.0.0) rainbow (>= 2.2.2, < 4.0) @@ -89,16 +89,18 @@ GEM unicode-display_width (>= 1.4.0, < 3.0) rubocop-ast (1.4.1) parser (>= 2.7.1.5) - rubocop-performance (1.10.1) + rubocop-performance (1.10.2) rubocop (>= 0.90.0, < 2.0) rubocop-ast (>= 0.4.0) + rubocop-rake (0.5.1) + rubocop rubocop-rspec (2.2.0) rubocop (~> 1.0) rubocop-ast (>= 1.1.0) ruby-progressbar (1.11.0) ruby_parser (3.15.1) sexp_processor (~> 4.9) - rubycritic (4.5.2) + rubycritic (4.6.1) flay (~> 2.8) flog (~> 4.4) launchy (>= 2.0.0) @@ -131,16 +133,17 @@ PLATFORMS DEPENDENCIES codebreaker! - fasterer - i18n - pry-byebug - rake - rspec - rubocop - rubocop-performance - rubocop-rspec - rubycritic - simplecov + fasterer (~> 0.9.0) + i18n (~> 1.8.10) + pry-byebug (~> 3.9.0) + rake (~> 13.0.3) + rspec (~> 3.10.0) + rubocop (~> 1.12.1) + rubocop-performance (~> 1.10.2) + rubocop-rake (~> 0.5.1) + rubocop-rspec (~> 2.2.0) + rubycritic (~> 4.6.1) + simplecov (~> 0.21.2) BUNDLED WITH 2.2.3 diff --git a/codebreaker.gemspec b/codebreaker.gemspec index e282019..3144d01 100644 --- a/codebreaker.gemspec +++ b/codebreaker.gemspec @@ -15,8 +15,6 @@ Gem::Specification.new do |spec| spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = "https://github.com/mechetel/codebreaker" - # Specify which files should be added to the gem when it is released. - # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) } end @@ -24,20 +22,15 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] - # Uncomment to register a new dependency of your gem - # spec.add_dependency "example-gem", "~> 1.0" - - spec.add_development_dependency 'pry-byebug' - spec.add_development_dependency 'i18n' - spec.add_development_dependency 'rake' - spec.add_development_dependency 'fasterer' - spec.add_development_dependency 'rspec' - spec.add_development_dependency 'rubocop' - spec.add_development_dependency 'rubocop-performance' - spec.add_development_dependency 'rubocop-rspec' - spec.add_development_dependency 'rubycritic' - spec.add_development_dependency 'simplecov' - - # For more information and examples about making a new gem, checkout our - # guide at: https://bundler.io/guides/creating_gem.html + spec.add_development_dependency 'pry-byebug', '~> 3.9.0' + spec.add_development_dependency 'i18n', '~> 1.8.10' + spec.add_development_dependency 'rake', '~> 13.0.3' + spec.add_development_dependency 'fasterer', '~> 0.9.0' + spec.add_development_dependency 'rspec', '~> 3.10.0' + spec.add_development_dependency 'rubocop', '~> 1.12.1' + spec.add_development_dependency 'rubocop-performance', '~> 1.10.2' + spec.add_development_dependency 'rubocop-rspec', '~> 2.2.0' + spec.add_development_dependency 'rubocop-rake', '~> 0.5.1' + spec.add_development_dependency 'rubycritic', '~> 4.6.1' + spec.add_development_dependency 'simplecov', '~> 0.21.2' end diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb index 8e73b23..bad0b61 100644 --- a/spec/codebreaker/difficulty_spec.rb +++ b/spec/codebreaker/difficulty_spec.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - RSpec.describe Codebreaker::Difficulty do let(:difficulty) { described_class.new(level) } let(:level) { 'easy' } @@ -31,23 +29,33 @@ describe '#valid?' do context 'when entered level of difficulty is wrong' do + subject(:invalid_difficulty_valid?) { invalid_difficulty.valid? } + + before do + invalid_difficulty_valid? + end + it 'validation returns false' do - expect(invalid_difficulty.valid?).to eq false + expect(invalid_difficulty_valid?).to eq false end it 'adds DifficultyError to errors' do - invalid_difficulty.valid? expect(invalid_difficulty.errors).to include Codebreaker::ValidationError end end context 'when entered level of difficulty is right' do + subject(:valid_difficulty_valid?) { difficulty.valid? } + + before do + valid_difficulty_valid? + end + it 'validation returns true' do - expect(difficulty.valid?).to eq true + expect(valid_difficulty_valid?).to eq true end it 'adds nothing to errors' do - difficulty.valid? expect(difficulty.errors).to be_empty end diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index fc55539..5bd6da6 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - RSpec.describe Codebreaker::Game do let(:user) { Codebreaker::User.new(user_name) } let(:user_name) { 'Mechetel' } @@ -11,9 +9,8 @@ context 'when game starts it initializes with secret number' do subject(:game_secret_number) { game.secret_code } - it 'has secret number' do - allow_any_instance_of(described_class).to receive(:generate_secret_code).and_return([6, 6, 1, 6]) - expect(game_secret_number).to eq([6, 6, 1, 6]) + before do + allow(game).to receive(:generate_secret_code) end it 'has valid secret number length' do diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index cebeeff..f58acc7 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - RSpec.describe Codebreaker::GuessChecker do describe '#initialize' do let(:guess_checker) { described_class.new('1234', '2345') } diff --git a/spec/codebreaker/user_spec.rb b/spec/codebreaker/user_spec.rb index 64b7720..d610799 100644 --- a/spec/codebreaker/user_spec.rb +++ b/spec/codebreaker/user_spec.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - RSpec.describe Codebreaker::User do let(:user) { described_class.new name } let(:name) { 'Mechetel' } @@ -38,43 +36,58 @@ describe '#valid?' do context 'when entered name is too short' do + subject(:invalid_user_valid?) { short_name_user.valid? } + let(:short_name_user) { described_class.new short_name } let(:short_name) { 'Me' } + before do + invalid_user_valid? + end + it 'returns false' do expect(short_name_user).not_to be_valid end it 'adds ShortNameError to errors' do - short_name_user.valid? expect(short_name_user.errors).to include Codebreaker::ValidationError end end context 'when entered name is too long' do + subject(:long_name_user_valid?) { long_name_user.valid? } + let(:long_name_user) { described_class.new long_name } let(:long_name) { 'dima' * 10 } + before do + long_name_user_valid? + end + it 'returns false' do expect(long_name_user).not_to be_valid end it 'adds longnameerror to errors' do - long_name_user.valid? expect(long_name_user.errors).to include Codebreaker::ValidationError end end context 'when entered name is not an instance of String' do + subject(:invalid_user_valid?) { invalid_user.valid? } + let(:invalid_user) { described_class.new inappropriate_user_name } let(:inappropriate_user_name) { 322 } + before do + invalid_user_valid? + end + it 'returns false' do expect(invalid_user).not_to be_valid end it 'adds NameIsNotStringError to errors' do - invalid_user.valid? expect(invalid_user.errors).to include Codebreaker::ValidationError end end diff --git a/spec/codebreaker_spec.rb b/spec/codebreaker_spec.rb index 87fddd2..137754c 100644 --- a/spec/codebreaker_spec.rb +++ b/spec/codebreaker_spec.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - RSpec.describe Codebreaker do it 'has a version number' do expect(Codebreaker::VERSION).not_to be nil From 648d18a7f71b705d2cb52367f369a49572b0450d Mon Sep 17 00:00:00 2001 From: mechetel Date: Sun, 1 Aug 2021 22:16:57 +0300 Subject: [PATCH 56/63] refactor: change lines up --- index.html | 12 ++++++++++++ lib/codebreaker/entities/difficulty.rb | 2 +- spec/spec_helper.rb | 6 ++++-- 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..bc40179 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + + +

+ hello there +

+ + diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 4b825a0..61ddbc5 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -26,4 +26,4 @@ def valid? @errors.empty? end end -end +e diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f1d1539..56d2bd2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,11 +1,13 @@ require 'simplecov' +require 'bundler/setup' +require 'codebreaker' + SimpleCov.start do enable_coverage :branch add_filter 'spec/' end + SimpleCov.minimum_coverage 95 -require 'bundler/setup' -require 'codebreaker' RSpec.configure do |config| config.example_status_persistence_file_path = '.rspec_status' From 428f90641c905f5b828d95a6ffe2772e68520371 Mon Sep 17 00:00:00 2001 From: mechetel Date: Mon, 23 Aug 2021 22:13:04 +0300 Subject: [PATCH 57/63] fix cops --- index.html | 12 ------------ lib/codebreaker/entities/difficulty.rb | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 index.html diff --git a/index.html b/index.html deleted file mode 100644 index bc40179..0000000 --- a/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - -

- hello there -

- - diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 61ddbc5..4b825a0 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -26,4 +26,4 @@ def valid? @errors.empty? end end -e +end From a7f7a8de2bdae76c2713bdfebedec484a5fa7d6e Mon Sep 17 00:00:00 2001 From: Mechetel Date: Mon, 5 Dec 2022 18:21:54 +0200 Subject: [PATCH 58/63] refactor: something --- .rubocop.yml | 6 ++-- .rvmrc | 1 + lib/codebreaker/entities/difficulty.rb | 8 +++-- lib/codebreaker/entities/game.rb | 8 ++++- lib/codebreaker/entities/guess_checker.rb | 4 +-- lib/codebreaker/modules/validator.rb | 33 +++++++++++++------ .../services/statistics_service.rb | 5 ++- spec/codebreaker/difficulty_spec.rb | 4 +-- spec/codebreaker/game_spec.rb | 6 ++-- spec/codebreaker/guess_checker_spec.rb | 10 +++--- spec/codebreaker/statistics_service_spec.rb | 2 +- spec/codebreaker/user_spec.rb | 12 +++---- 12 files changed, 62 insertions(+), 37 deletions(-) create mode 100644 .rvmrc diff --git a/.rubocop.yml b/.rubocop.yml index 19ce8b6..5b60fbd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,12 +5,12 @@ require: AllCops: NewCops: enable Exclude: - - 'codebreaker.gemspec' - - 'vendor/bundle/**/*' + - "codebreaker.gemspec" + - "vendor/bundle/**/*" Metrics/BlockLength: Exclude: - - 'spec/codebreaker/**/*' + - "spec/codebreaker/**/*" Style/FrozenStringLiteralComment: Enabled: false diff --git a/.rvmrc b/.rvmrc new file mode 100644 index 0000000..fc87a40 --- /dev/null +++ b/.rvmrc @@ -0,0 +1 @@ +rvm use 2.7.2@codebreaker --create diff --git a/lib/codebreaker/entities/difficulty.rb b/lib/codebreaker/entities/difficulty.rb index 4b825a0..948ba78 100644 --- a/lib/codebreaker/entities/difficulty.rb +++ b/lib/codebreaker/entities/difficulty.rb @@ -2,9 +2,11 @@ module Codebreaker class Difficulty include Validator - DIFFICULTIES = { easy: { attempts: 15, hints: 2 }, - medium: { attempts: 10, hints: 1 }, - hell: { attempts: 5, hints: 1 } }.freeze + DIFFICULTIES = { + easy: { attempts: 15, hints: 2 }, + medium: { attempts: 10, hints: 1 }, + hell: { attempts: 5, hints: 1 } + }.freeze attr_reader :level, :errors diff --git a/lib/codebreaker/entities/game.rb b/lib/codebreaker/entities/game.rb index d0d2c01..1d774b8 100644 --- a/lib/codebreaker/entities/game.rb +++ b/lib/codebreaker/entities/game.rb @@ -4,7 +4,13 @@ class Game MAX_CODE_NUM = 6 DIGITS_NUM = 4 - attr_reader :user, :difficulty, :secret_code, :date, :hints_list, :attempts, :hints + attr_reader :user, + :difficulty, + :secret_code, + :date, + :hints_list, + :attempts, + :hints def initialize(user, difficulty) @user = user diff --git a/lib/codebreaker/entities/guess_checker.rb b/lib/codebreaker/entities/guess_checker.rb index eb37564..66ea9ab 100644 --- a/lib/codebreaker/entities/guess_checker.rb +++ b/lib/codebreaker/entities/guess_checker.rb @@ -2,8 +2,8 @@ module Codebreaker class GuessChecker extend Validator - RIGHT_ANSWER_SYMBOL = '+'.freeze - WRONG_ANSWER_SYMBOL = '-'.freeze + RIGHT_ANSWER_SYMBOL = '+'.freeze + WRONG_ANSWER_SYMBOL = '-'.freeze def initialize(code, input) @secret_code = code diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb index 9caca3a..dd9f064 100644 --- a/lib/codebreaker/modules/validator.rb +++ b/lib/codebreaker/modules/validator.rb @@ -4,34 +4,47 @@ module Validator NAME_MAX_LENGTH = 20 def validate_difficulty(level, errors) - errors << ValidationError.new(I18n.t('difficulty_error')) unless Difficulty::DIFFICULTIES.include? level + unless Difficulty::DIFFICULTIES.include? level + errors << ValidationError.new(I18n.t('difficulty_error')) + end end def validate_name_class(name, errors) - errors << ValidationError.new(I18n.t('name_is_not_string_error')) unless name.is_a? String + unless name.is_a? String + errors << ValidationError.new(I18n.t('name_is_not_string_error')) + end end def validate_name_min_length(name, errors) - errors << ValidationError.new(I18n.t('short_name_error')) if name.length < NAME_MIN_LENGTH + if name.length < NAME_MIN_LENGTH + errors << ValidationError.new(I18n.t('short_name_error')) + end end def validate_name_max_length(name, errors) - errors << ValidationError.new(I18n.t('long_name_error')) if name.length > NAME_MAX_LENGTH + if name.length > NAME_MAX_LENGTH + errors << ValidationError.new(I18n.t('long_name_error')) + end end def validate_guess_for_not_integer(guess) - raise ValidationError, I18n.t('guess_is_not_integer') unless guess[/^\d+$/] + unless guess[/^\d+$/] + raise ValidationError, I18n.t('guess_is_not_integer') + end end def validate_guess_count(guess) - raise ValidationError, I18n.t('digits_count_error') unless guess.size == Game::DIGITS_NUM + unless guess.size == Game::DIGITS_NUM + raise ValidationError, I18n.t('digits_count_error') + end end def validate_guess_range(guess) - raise ValidationError, I18n.t('digit_range_error') unless guess.chars.all? do |num| - num.to_i.between? Game::MIN_CODE_NUM, - Game::MAX_CODE_NUM - end + unless guess.chars.all? do |num| + num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM + end + raise ValidationError, I18n.t('digit_range_error') + end end end end diff --git a/lib/codebreaker/services/statistics_service.rb b/lib/codebreaker/services/statistics_service.rb index 10dc2d1..0c6e454 100644 --- a/lib/codebreaker/services/statistics_service.rb +++ b/lib/codebreaker/services/statistics_service.rb @@ -15,7 +15,9 @@ def store(game) end def sort_statistics - load.sort_by { |user| [user[:attempts_total], user[:attempts_used], user[:hints_used]] } + load.sort_by do |user| + [user[:attempts_total], user[:attempts_used], user[:hints_used]] + end end def load @@ -32,6 +34,7 @@ def make_files(file_path) def game_to_h(game) game_difficulty = game.difficulty + { name: game.user.name, difficulty: game_difficulty.level.to_s, diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb index bad0b61..c3bea06 100644 --- a/spec/codebreaker/difficulty_spec.rb +++ b/spec/codebreaker/difficulty_spec.rb @@ -1,7 +1,7 @@ RSpec.describe Codebreaker::Difficulty do - let(:difficulty) { described_class.new(level) } + let(:difficulty) { Difficulty.new(level) } let(:level) { 'easy' } - let(:invalid_difficulty) { described_class.new(invalid_level) } + let(:invalid_difficulty) { Difficulty.new(invalid_level) } let(:invalid_level) { 'qwerty' } let(:difficulty_constant) { Difficulty::DIFFICULTIES } diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index 5bd6da6..d0895f7 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -3,7 +3,7 @@ let(:user_name) { 'Mechetel' } let(:difficulty) { Codebreaker::Difficulty.new(difficulty_level) } let(:difficulty_level) { 'hell' } - let(:game) { described_class.new(user, difficulty) } + let(:game) { Game.new(user, difficulty) } describe '#initialize' do context 'when game starts it initializes with secret number' do @@ -28,12 +28,12 @@ end it 'secret code size equal to DIGITS_NUM constant' do - expect(game_secret_number.size).to eq described_class::DIGITS_NUM + expect(game_secret_number.size).to eq Game::DIGITS_NUM end it 'each element of secret code is between MIN_CODE_NUM and MAX_CODE_NUM contstants' do game_secret_number.each do |digit| - expect(digit.to_i).to be_between(described_class::MIN_CODE_NUM, described_class::MAX_CODE_NUM).inclusive + expect(digit.to_i).to be_between(Game::MIN_CODE_NUM, Game::MAX_CODE_NUM).inclusive end end diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index f58acc7..aa57543 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -1,6 +1,6 @@ RSpec.describe Codebreaker::GuessChecker do describe '#initialize' do - let(:guess_checker) { described_class.new('1234', '2345') } + let(:guess_checker) { GuessChecker.new('1234', '2345') } it 'has secret_code and user_input field' do expect(guess_checker.instance_variables).to include(:@secret_code, :@user_input) @@ -9,15 +9,15 @@ describe '#validate' do it 'raises DigitsCountError when digits count is invalid' do - expect { described_class.validate('102') }.to raise_error Codebreaker::ValidationError + expect { GuessChecker.validate('102') }.to raise_error Codebreaker::ValidationError end it 'raises DigitsCountError when guess is not a numbers' do - expect { described_class.validate('sdfg') }.to raise_error Codebreaker::ValidationError + expect { GuessChecker.validate('sdfg') }.to raise_error Codebreaker::ValidationError end it 'raises DigitRangeError when any digit is not in the range' do - expect { described_class.validate('6969') }.to raise_error Codebreaker::ValidationError + expect { GuessChecker.validate('6969') }.to raise_error Codebreaker::ValidationError end end @@ -37,7 +37,7 @@ { secret_number: '1234', input: '1234', result: '++++' } ].each do |line| it "returns #{line[:result]} when secret number - #{line[:secret_number]} and input - #{line[:input]}" do - expect(described_class.new(line[:secret_number].chars.map(&:to_i), line[:input]).check).to eq(line[:result]) + expect(GuessChecker.new(line[:secret_number].chars.map(&:to_i), line[:input]).check).to eq(line[:result]) end end end diff --git a/spec/codebreaker/statistics_service_spec.rb b/spec/codebreaker/statistics_service_spec.rb index 87235e8..558e86f 100644 --- a/spec/codebreaker/statistics_service_spec.rb +++ b/spec/codebreaker/statistics_service_spec.rb @@ -1,7 +1,7 @@ RSpec.describe Codebreaker::StatisticsService do let(:game) { Codebreaker::Game.new(Codebreaker::User.new('Mechetel'), Codebreaker::Difficulty.new('hell')) } let(:path) { './lib/codebreaker/.yaml' } - let(:service) { described_class.new(path) } + let(:service) { StatisticsService.new(path) } before { service.store game } diff --git a/spec/codebreaker/user_spec.rb b/spec/codebreaker/user_spec.rb index d610799..921b60d 100644 --- a/spec/codebreaker/user_spec.rb +++ b/spec/codebreaker/user_spec.rb @@ -1,5 +1,5 @@ RSpec.describe Codebreaker::User do - let(:user) { described_class.new name } + let(:user) { User.new name } let(:name) { 'Mechetel' } describe '#name' do @@ -26,11 +26,11 @@ describe 'check User constants' do it 'check content of NAME_MIN_LENGTH constant' do - expect(described_class::NAME_MIN_LENGTH).to eq(3) + expect(User::NAME_MIN_LENGTH).to eq(3) end it 'check content of NAME_MAX_LENGTH constant' do - expect(described_class::NAME_MAX_LENGTH).to eq(20) + expect(User::NAME_MAX_LENGTH).to eq(20) end end @@ -38,7 +38,7 @@ context 'when entered name is too short' do subject(:invalid_user_valid?) { short_name_user.valid? } - let(:short_name_user) { described_class.new short_name } + let(:short_name_user) { User.new short_name } let(:short_name) { 'Me' } before do @@ -57,7 +57,7 @@ context 'when entered name is too long' do subject(:long_name_user_valid?) { long_name_user.valid? } - let(:long_name_user) { described_class.new long_name } + let(:long_name_user) { User.new long_name } let(:long_name) { 'dima' * 10 } before do @@ -76,7 +76,7 @@ context 'when entered name is not an instance of String' do subject(:invalid_user_valid?) { invalid_user.valid? } - let(:invalid_user) { described_class.new inappropriate_user_name } + let(:invalid_user) { User.new inappropriate_user_name } let(:inappropriate_user_name) { 322 } before do From df5c5c22e80c573e290832d1df275eff711a8c13 Mon Sep 17 00:00:00 2001 From: Mechetel Date: Mon, 5 Dec 2022 18:34:14 +0200 Subject: [PATCH 59/63] refactor: something --- lib/codebreaker/modules/validator.rb | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/lib/codebreaker/modules/validator.rb b/lib/codebreaker/modules/validator.rb index dd9f064..c128c07 100644 --- a/lib/codebreaker/modules/validator.rb +++ b/lib/codebreaker/modules/validator.rb @@ -4,45 +4,33 @@ module Validator NAME_MAX_LENGTH = 20 def validate_difficulty(level, errors) - unless Difficulty::DIFFICULTIES.include? level - errors << ValidationError.new(I18n.t('difficulty_error')) - end + errors << ValidationError.new(I18n.t('difficulty_error')) unless Difficulty::DIFFICULTIES.include? level end def validate_name_class(name, errors) - unless name.is_a? String - errors << ValidationError.new(I18n.t('name_is_not_string_error')) - end + errors << ValidationError.new(I18n.t('name_is_not_string_error')) unless name.is_a? String end def validate_name_min_length(name, errors) - if name.length < NAME_MIN_LENGTH - errors << ValidationError.new(I18n.t('short_name_error')) - end + errors << ValidationError.new(I18n.t('short_name_error')) if name.length < NAME_MIN_LENGTH end def validate_name_max_length(name, errors) - if name.length > NAME_MAX_LENGTH - errors << ValidationError.new(I18n.t('long_name_error')) - end + errors << ValidationError.new(I18n.t('long_name_error')) if name.length > NAME_MAX_LENGTH end def validate_guess_for_not_integer(guess) - unless guess[/^\d+$/] - raise ValidationError, I18n.t('guess_is_not_integer') - end + raise ValidationError, I18n.t('guess_is_not_integer') unless guess[/^\d+$/] end def validate_guess_count(guess) - unless guess.size == Game::DIGITS_NUM - raise ValidationError, I18n.t('digits_count_error') - end + raise ValidationError, I18n.t('digits_count_error') unless guess.size == Game::DIGITS_NUM end def validate_guess_range(guess) unless guess.chars.all? do |num| - num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM - end + num.to_i.between? Game::MIN_CODE_NUM, Game::MAX_CODE_NUM + end raise ValidationError, I18n.t('digit_range_error') end end From 0d9752ba1ba3597aa150971b63c71361fbe3f38a Mon Sep 17 00:00:00 2001 From: Mechetel Date: Mon, 5 Dec 2022 18:43:12 +0200 Subject: [PATCH 60/63] refactor: something --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fa43b0c..98769d0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,8 +40,8 @@ commands: command: | mkdir /tmp/test-results TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)" - bundle exec rspec --format progress \ - --out /tmp/test-results/rspec.xml \ + bundle exec rspec -format progress \ + -out /tmp/test-results/rspec.xml \ $TEST_FILES - store_artifacts: path: ~/repo/coverage From 3afb7334c1f5b292c89fc2ebb08d6b9e61a1dc9f Mon Sep 17 00:00:00 2001 From: Mechetel Date: Mon, 5 Dec 2022 18:52:26 +0200 Subject: [PATCH 61/63] refactor: something --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 98769d0..9bb0e70 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,8 +40,8 @@ commands: command: | mkdir /tmp/test-results TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)" - bundle exec rspec -format progress \ - -out /tmp/test-results/rspec.xml \ + bundle exec rspec --format progress \ + --out /tmp/rspec.xml \ $TEST_FILES - store_artifacts: path: ~/repo/coverage From 27228a4c25082d3000fbb2df39c0431088651348 Mon Sep 17 00:00:00 2001 From: Mechetel Date: Mon, 5 Dec 2022 18:58:47 +0200 Subject: [PATCH 62/63] refactor: something --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9bb0e70..f633983 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,9 +39,9 @@ commands: name: run specs command: | mkdir /tmp/test-results - TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)" + TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split)" bundle exec rspec --format progress \ - --out /tmp/rspec.xml \ + --out /tmp/test-results/rspec.xml \ $TEST_FILES - store_artifacts: path: ~/repo/coverage From 127a5c9dab190ab098fe0f907be51f3eb4cde35c Mon Sep 17 00:00:00 2001 From: Mechetel Date: Mon, 5 Dec 2022 19:37:14 +0200 Subject: [PATCH 63/63] refactor: something --- .circleci/config.yml | 2 +- .rvmrc | 1 - spec/codebreaker/difficulty_spec.rb | 4 ++-- spec/codebreaker/game_spec.rb | 6 +++--- spec/codebreaker/guess_checker_spec.rb | 10 +++++----- spec/codebreaker/statistics_service_spec.rb | 2 +- spec/codebreaker/user_spec.rb | 12 ++++++------ 7 files changed, 18 insertions(+), 19 deletions(-) delete mode 100644 .rvmrc diff --git a/.circleci/config.yml b/.circleci/config.yml index f633983..fa43b0c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,7 @@ commands: name: run specs command: | mkdir /tmp/test-results - TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split)" + TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)" bundle exec rspec --format progress \ --out /tmp/test-results/rspec.xml \ $TEST_FILES diff --git a/.rvmrc b/.rvmrc deleted file mode 100644 index fc87a40..0000000 --- a/.rvmrc +++ /dev/null @@ -1 +0,0 @@ -rvm use 2.7.2@codebreaker --create diff --git a/spec/codebreaker/difficulty_spec.rb b/spec/codebreaker/difficulty_spec.rb index c3bea06..bad0b61 100644 --- a/spec/codebreaker/difficulty_spec.rb +++ b/spec/codebreaker/difficulty_spec.rb @@ -1,7 +1,7 @@ RSpec.describe Codebreaker::Difficulty do - let(:difficulty) { Difficulty.new(level) } + let(:difficulty) { described_class.new(level) } let(:level) { 'easy' } - let(:invalid_difficulty) { Difficulty.new(invalid_level) } + let(:invalid_difficulty) { described_class.new(invalid_level) } let(:invalid_level) { 'qwerty' } let(:difficulty_constant) { Difficulty::DIFFICULTIES } diff --git a/spec/codebreaker/game_spec.rb b/spec/codebreaker/game_spec.rb index d0895f7..5bd6da6 100644 --- a/spec/codebreaker/game_spec.rb +++ b/spec/codebreaker/game_spec.rb @@ -3,7 +3,7 @@ let(:user_name) { 'Mechetel' } let(:difficulty) { Codebreaker::Difficulty.new(difficulty_level) } let(:difficulty_level) { 'hell' } - let(:game) { Game.new(user, difficulty) } + let(:game) { described_class.new(user, difficulty) } describe '#initialize' do context 'when game starts it initializes with secret number' do @@ -28,12 +28,12 @@ end it 'secret code size equal to DIGITS_NUM constant' do - expect(game_secret_number.size).to eq Game::DIGITS_NUM + expect(game_secret_number.size).to eq described_class::DIGITS_NUM end it 'each element of secret code is between MIN_CODE_NUM and MAX_CODE_NUM contstants' do game_secret_number.each do |digit| - expect(digit.to_i).to be_between(Game::MIN_CODE_NUM, Game::MAX_CODE_NUM).inclusive + expect(digit.to_i).to be_between(described_class::MIN_CODE_NUM, described_class::MAX_CODE_NUM).inclusive end end diff --git a/spec/codebreaker/guess_checker_spec.rb b/spec/codebreaker/guess_checker_spec.rb index aa57543..f58acc7 100644 --- a/spec/codebreaker/guess_checker_spec.rb +++ b/spec/codebreaker/guess_checker_spec.rb @@ -1,6 +1,6 @@ RSpec.describe Codebreaker::GuessChecker do describe '#initialize' do - let(:guess_checker) { GuessChecker.new('1234', '2345') } + let(:guess_checker) { described_class.new('1234', '2345') } it 'has secret_code and user_input field' do expect(guess_checker.instance_variables).to include(:@secret_code, :@user_input) @@ -9,15 +9,15 @@ describe '#validate' do it 'raises DigitsCountError when digits count is invalid' do - expect { GuessChecker.validate('102') }.to raise_error Codebreaker::ValidationError + expect { described_class.validate('102') }.to raise_error Codebreaker::ValidationError end it 'raises DigitsCountError when guess is not a numbers' do - expect { GuessChecker.validate('sdfg') }.to raise_error Codebreaker::ValidationError + expect { described_class.validate('sdfg') }.to raise_error Codebreaker::ValidationError end it 'raises DigitRangeError when any digit is not in the range' do - expect { GuessChecker.validate('6969') }.to raise_error Codebreaker::ValidationError + expect { described_class.validate('6969') }.to raise_error Codebreaker::ValidationError end end @@ -37,7 +37,7 @@ { secret_number: '1234', input: '1234', result: '++++' } ].each do |line| it "returns #{line[:result]} when secret number - #{line[:secret_number]} and input - #{line[:input]}" do - expect(GuessChecker.new(line[:secret_number].chars.map(&:to_i), line[:input]).check).to eq(line[:result]) + expect(described_class.new(line[:secret_number].chars.map(&:to_i), line[:input]).check).to eq(line[:result]) end end end diff --git a/spec/codebreaker/statistics_service_spec.rb b/spec/codebreaker/statistics_service_spec.rb index 558e86f..87235e8 100644 --- a/spec/codebreaker/statistics_service_spec.rb +++ b/spec/codebreaker/statistics_service_spec.rb @@ -1,7 +1,7 @@ RSpec.describe Codebreaker::StatisticsService do let(:game) { Codebreaker::Game.new(Codebreaker::User.new('Mechetel'), Codebreaker::Difficulty.new('hell')) } let(:path) { './lib/codebreaker/.yaml' } - let(:service) { StatisticsService.new(path) } + let(:service) { described_class.new(path) } before { service.store game } diff --git a/spec/codebreaker/user_spec.rb b/spec/codebreaker/user_spec.rb index 921b60d..d610799 100644 --- a/spec/codebreaker/user_spec.rb +++ b/spec/codebreaker/user_spec.rb @@ -1,5 +1,5 @@ RSpec.describe Codebreaker::User do - let(:user) { User.new name } + let(:user) { described_class.new name } let(:name) { 'Mechetel' } describe '#name' do @@ -26,11 +26,11 @@ describe 'check User constants' do it 'check content of NAME_MIN_LENGTH constant' do - expect(User::NAME_MIN_LENGTH).to eq(3) + expect(described_class::NAME_MIN_LENGTH).to eq(3) end it 'check content of NAME_MAX_LENGTH constant' do - expect(User::NAME_MAX_LENGTH).to eq(20) + expect(described_class::NAME_MAX_LENGTH).to eq(20) end end @@ -38,7 +38,7 @@ context 'when entered name is too short' do subject(:invalid_user_valid?) { short_name_user.valid? } - let(:short_name_user) { User.new short_name } + let(:short_name_user) { described_class.new short_name } let(:short_name) { 'Me' } before do @@ -57,7 +57,7 @@ context 'when entered name is too long' do subject(:long_name_user_valid?) { long_name_user.valid? } - let(:long_name_user) { User.new long_name } + let(:long_name_user) { described_class.new long_name } let(:long_name) { 'dima' * 10 } before do @@ -76,7 +76,7 @@ context 'when entered name is not an instance of String' do subject(:invalid_user_valid?) { invalid_user.valid? } - let(:invalid_user) { User.new inappropriate_user_name } + let(:invalid_user) { described_class.new inappropriate_user_name } let(:inappropriate_user_name) { 322 } before do