diff --git a/README.md b/README.md index 10fee7b5..4ebcc048 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Exercism Workspace | July | Jurassic | C (5/5), C++ (5/5), Fortran (0/5) | | August | Apps | Dart (5/5), Java (0/5), Kotlin (0/5) | | September | Slimline | Awk (5/5), Bash\* (5/5), jq (0/5), Perl (0/5) | -| October | Object-Oriented | Ruby (0/5), Java (0/5) | +| October | Object-Oriented | Ruby (1/5), Java (0/5) | | November | Nibbly | | | December | Diversions | | diff --git a/ruby/README.md b/ruby/README.md index 241633f9..49cb1da3 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -67,3 +67,4 @@ - [series](./series/README.md) - [word-count](./word-count/README.md) - [allergies](./allergies/README.md) +- [simple-cipher](./simple-cipher/README.md) diff --git a/ruby/simple-cipher/README.md b/ruby/simple-cipher/README.md index 5254b933..03567418 100644 --- a/ruby/simple-cipher/README.md +++ b/ruby/simple-cipher/README.md @@ -92,4 +92,9 @@ Take a look at [Diffie-Hellman on Wikipedia][dh] for one of the first implementa ### Based on -Substitution Cipher at Wikipedia - https://en.wikipedia.org/wiki/Substitution_cipher \ No newline at end of file +Substitution Cipher at Wikipedia - https://en.wikipedia.org/wiki/Substitution_cipher + +### My Solution + +- [my solution](./simple_cipher.rb) +- [run-tests](./run-tests-ruby.txt) diff --git a/ruby/simple-cipher/coverage/.last_run.json b/ruby/simple-cipher/coverage/.last_run.json new file mode 100644 index 00000000..52d2bf29 --- /dev/null +++ b/ruby/simple-cipher/coverage/.last_run.json @@ -0,0 +1,5 @@ +{ + "result": { + "line": 100.0 + } +} diff --git a/ruby/simple-cipher/coverage/.resultset.json b/ruby/simple-cipher/coverage/.resultset.json new file mode 100644 index 00000000..cd0f7373 --- /dev/null +++ b/ruby/simple-cipher/coverage/.resultset.json @@ -0,0 +1,55 @@ +{ + "test:exercism": { + "coverage": { + "/home/vpayno/git_vpayno/exercism-workspace/ruby/simple-cipher/simple_cipher.rb": { + "lines": [ + null, + null, + null, + null, + 1, + 1, + null, + 1, + 417, + null, + 17, + 16, + null, + null, + 1, + 8, + 83, + null, + null, + null, + 1, + 6, + 60, + null, + null, + null, + 1, + null, + 1, + 83, + null, + null, + 1, + 60, + null, + null, + 1, + 286, + null, + null, + 1, + 143, + null, + null + ] + } + }, + "timestamp": 1698525013 + } +} diff --git a/ruby/simple-cipher/coverage/.resultset.json.lock b/ruby/simple-cipher/coverage/.resultset.json.lock new file mode 100644 index 00000000..e69de29b diff --git a/ruby/simple-cipher/coverage/coverage.xml b/ruby/simple-cipher/coverage/coverage.xml new file mode 100644 index 00000000..b8f3457a --- /dev/null +++ b/ruby/simple-cipher/coverage/coverage.xml @@ -0,0 +1,40 @@ + + + + + + /home/vpayno/git_vpayno/exercism-workspace/ruby/simple-cipher + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruby/simple-cipher/run-tests-ruby.txt b/ruby/simple-cipher/run-tests-ruby.txt new file mode 100644 index 00000000..63bb83ea --- /dev/null +++ b/ruby/simple-cipher/run-tests-ruby.txt @@ -0,0 +1,232 @@ +Running automated test file(s): + + +=============================================================================== + +Running: ../../.github/citools/ruby/ruby-lint-rubycritic + +Running RubyCritic + +Ruby version: + + ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux] + rbenv 1.2.0-11-ge4f61e6 + + + ============================================================================== + +Running: rubycritic --path .rubycritic --format console --no-browser . + +running flay smells +. +running flog smells +.. +running reek smells +.. +running complexity +.. +running attributes +.. +running churn +.. +running simple_cov +.. +/home/vpayno/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/rubycritic-4.6.1/lib/rubycritic/generators/text/list.rb:13: warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments. +/home/vpayno/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/rubycritic-4.6.1/lib/rubycritic/generators/text/list.rb:13: warning: Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead. +Cipher: + Rating: B + Churn: 0 + Complexity: 54.66 + Duplication: 32 + Smells: 4 + * (DuplicateCode) Similar code found in 2 nodes + - simple_cipher.rb:15 + - simple_cipher.rb:21 + * (ControlParameter) Cipher#initialize is controlled by argument 'key' + - simple_cipher.rb:9 + * (UtilityFunction) Cipher#to_char doesn't depend on instance state (maybe move it to another class?) + - simple_cipher.rb:41 + * (UtilityFunction) Cipher#to_ord doesn't depend on instance state (maybe move it to another class?) + - simple_cipher.rb:37 + +RandomKeyCipherTest: + Rating: B + Churn: 0 + Complexity: 62.74 + Duplication: 0 + Smells: 8 + * (InstanceVariableAssumption) PseudoShiftCipherTest assumes too much for instance variable '@cipher' + - simple_cipher_test.rb:128 + * (InstanceVariableAssumption) RandomKeyCipherTest assumes too much for instance variable '@cipher' + - simple_cipher_test.rb:28 + * (InstanceVariableAssumption) SubstitutionCipherTest assumes too much for instance variable '@cipher' + - simple_cipher_test.rb:82 + * (InstanceVariableAssumption) SubstitutionCipherTest assumes too much for instance variable '@key' + - simple_cipher_test.rb:82 + * (IrresponsibleModule) IncorrectKeyCipherTest has no descriptive comment + - simple_cipher_test.rb:59 + * (IrresponsibleModule) PseudoShiftCipherTest has no descriptive comment + - simple_cipher_test.rb:128 + * (IrresponsibleModule) RandomKeyCipherTest has no descriptive comment + - simple_cipher_test.rb:28 + * (IrresponsibleModule) SubstitutionCipherTest has no descriptive comment + - simple_cipher_test.rb:82 +Score: 82.2 + +real 0m0.652s +user 0m0.544s +sys 0m0.104s + + + ============================================================================== + +Exit code: 0 + +real 0m0.740s +user 0m0.588s +sys 0m0.154s + +real 0m0.742s +user 0m0.589s +sys 0m0.155s + +=============================================================================== + +Running: ../../.github/citools/ruby/ruby-lint-formatter + +Running Ruby Formatter + +Ruby version: + + ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux] + rbenv 1.2.0-11-ge4f61e6 + + + ============================================================================== + +Running: rubocop -a . + +Inspecting 2 files +.C + +Offenses: + +simple_cipher_test.rb:28:1: C: Style/Documentation: Missing top-level documentation comment for class RandomKeyCipherTest. +class RandomKeyCipherTest < Minitest::Test +^^^^^^^^^^^^^^^^^^^^^^^^^ +simple_cipher_test.rb:59:1: C: Style/Documentation: Missing top-level documentation comment for class IncorrectKeyCipherTest. +class IncorrectKeyCipherTest < Minitest::Test +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +simple_cipher_test.rb:82:1: C: Style/Documentation: Missing top-level documentation comment for class SubstitutionCipherTest. +class SubstitutionCipherTest < Minitest::Test +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +simple_cipher_test.rb:128:1: C: Style/Documentation: Missing top-level documentation comment for class PseudoShiftCipherTest. +class PseudoShiftCipherTest < Minitest::Test +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +2 files inspected, 4 offenses detected + +real 0m0.944s +user 0m0.809s +sys 0m0.225s + + + ============================================================================== + +Exit code: -1 + +real 0m1.039s +user 0m0.857s +sys 0m0.276s + +real 0m1.041s +user 0m0.858s +sys 0m0.277s + +=============================================================================== + +Running: ../../.github/citools/ruby/ruby-test-with-coverage + +Running Ruby Tests With Coverage + +Ruby version: + + ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux] + rbenv 1.2.0-11-ge4f61e6 + + + ============================================================================== + +Running: rm -rf ./coverage + + +real 0m0.001s +user 0m0.001s +sys 0m0.000s + + + ============================================================================== + +Running: ruby ./simple_cipher_test.rb -v + +Run options: -v --seed 5422 + +# Running: + +RandomKeyCipherTest#test_cipher_encode = 0.00 s = . +RandomKeyCipherTest#test_cipher_key_is_letters = 0.00 s = . +RandomKeyCipherTest#test_cipher_decode = 0.00 s = . +RandomKeyCipherTest#test_cipher_reversible = 0.00 s = . +SubstitutionCipherTest#test_cipher_decode = 0.00 s = . +SubstitutionCipherTest#test_cipher_encode = 0.00 s = . +SubstitutionCipherTest#test_cipher_encode_wrap = 0.00 s = . +SubstitutionCipherTest#test_cipher_key_is_as_submitted = 0.00 s = . +SubstitutionCipherTest#test_cipher_reversible = 0.00 s = . +SubstitutionCipherTest#test_double_shift_encode = 0.00 s = . +PseudoShiftCipherTest#test_cipher_encode = 0.00 s = . +PseudoShiftCipherTest#test_cipher_reversible = 0.00 s = . +PseudoShiftCipherTest#test_cipher_decode = 0.00 s = . +IncorrectKeyCipherTest#test_cipher_with_empty_key = 0.00 s = . +IncorrectKeyCipherTest#test_cipher_with_caps_key = 0.00 s = . +IncorrectKeyCipherTest#test_cipher_with_numeric_key = 0.00 s = . + +Finished in 0.006156s, 2599.2398 runs/s, 2761.6922 assertions/s. + +16 runs, 17 assertions, 0 failures, 0 errors, 0 skips +Coverage report generated for test:exercism to /home/vpayno/git_vpayno/exercism-workspace/ruby/simple-cipher/coverage/coverage.xml. 21 / 21 LOC (100.00%) covered + +real 0m0.189s +user 0m0.133s +sys 0m0.057s + + + ============================================================================== + +Coverage: 100.0% + + ============================================================================== + +Exit code: 0 + +real 0m0.251s +user 0m0.160s +sys 0m0.095s + +real 0m0.253s +user 0m0.161s +sys 0m0.096s + +=============================================================================== + +Running: misspell . + +real 0m0.025s +user 0m0.024s +sys 0m0.013s + +=============================================================================== + +/home/vpayno/git_vpayno/exercism-workspace/ruby + +=============================================================================== + diff --git a/ruby/simple-cipher/simple_cipher.rb b/ruby/simple-cipher/simple_cipher.rb index b1d06967..9a40daff 100644 --- a/ruby/simple-cipher/simple_cipher.rb +++ b/ruby/simple-cipher/simple_cipher.rb @@ -1,7 +1,44 @@ -=begin -Write your code for the 'Simple Cipher' exercise in this file. Make the tests in -`simple_cipher_test.rb` pass. +# frozen_string_literal: false -To get started with TDD, see the `README.md` file in your -`ruby/simple-cipher` directory. -=end +# https://exercism.org/tracks/ruby/exercises/simple-cipher +# Simple Cipher 12in23 challenge +class Cipher + attr_reader :key + + def initialize(key = nil) + @key = key || 100.times.map { ('a'.ord + rand(26)).chr }.join + + raise ArgumentError, 'empty key' if @key.empty? + raise ArgumentError, 'key not composed of only a-z letters' if @key.match?(/[^a-z]/) + end + + def encode(plain_text) + plain_text.chars.zip(@key.chars).map do |rune, key| + to_char(shift_right(rune, key)).chr + end.join + end + + def decode(cipher_text) + cipher_text.chars.zip(@key.chars).map do |rune, key| + to_char(shift_left(rune, key)).chr + end.join + end + + private + + def shift_right(rune, key) + to_ord(rune) + to_ord(key) + end + + def shift_left(rune, key) + to_ord(rune) - to_ord(key) + end + + def to_ord(rune) + rune.ord - 'a'.ord + end + + def to_char(ordinal) + (ordinal % 26 + 'a'.ord).chr + end +end diff --git a/ruby/simple-cipher/simple_cipher_test.rb b/ruby/simple-cipher/simple_cipher_test.rb index 17023e2d..f38406f5 100644 --- a/ruby/simple-cipher/simple_cipher_test.rb +++ b/ruby/simple-cipher/simple_cipher_test.rb @@ -1,3 +1,27 @@ +# frozen_string_literal: false + +# https://github.com/simplecov-ruby/simplecov +require 'simplecov' + +# https://about.codecov.io/blog/getting-started-with-code-coverage-for-ruby/ +require 'simplecov-cobertura' +SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter + +# line coverage +SimpleCov.start if ENV['COVERAGE'] != 'branch' + +# branch coverage +if ENV['COVERAGE'] == 'branch' + SimpleCov.start do + enable_coverage :branch + primary_coverage :branch + end +end + +# name the test file/group +SimpleCov.command_name 'test:exercism' + +# original exercism tests require 'minitest/autorun' require_relative 'simple_cipher' @@ -14,19 +38,19 @@ def test_cipher_key_is_letters # outputs the key. This is a critical problem with shift ciphers, some # characters will always output the key verbatim. def test_cipher_encode - skip + # skip plaintext = 'aaaaaaaaaa' assert_equal(@cipher.key[0, 10], @cipher.encode(plaintext)) end def test_cipher_decode - skip + # skip plaintext = 'aaaaaaaaaa' assert_equal(plaintext, @cipher.decode(@cipher.key[0, 10])) end def test_cipher_reversible - skip + # skip plaintext = 'abcdefghij' assert_equal(plaintext, @cipher.decode(@cipher.encode(plaintext))) end @@ -34,21 +58,21 @@ def test_cipher_reversible class IncorrectKeyCipherTest < Minitest::Test def test_cipher_with_caps_key - skip + # skip assert_raises ArgumentError do Cipher.new('ABCDEF') end end def test_cipher_with_numeric_key - skip + # skip assert_raises ArgumentError do Cipher.new('12345') end end def test_cipher_with_empty_key - skip + # skip assert_raises ArgumentError do Cipher.new('') end @@ -62,39 +86,39 @@ def setup end def test_cipher_key_is_as_submitted - skip + # skip assert_equal(@cipher.key, @key) end def test_cipher_encode - skip + # skip plaintext = 'aaaaaaaaaa' ciphertext = 'abcdefghij' assert_equal(ciphertext, @cipher.encode(plaintext)) end def test_cipher_decode - skip + # skip plaintext = 'aaaaaaaaaa' ciphertext = 'abcdefghij' assert_equal(plaintext, @cipher.decode(ciphertext)) end def test_cipher_reversible - skip + # skip plaintext = 'abcdefghij' assert_equal(plaintext, @cipher.decode(@cipher.encode(plaintext))) end def test_double_shift_encode - skip + # skip plaintext = 'iamapandabear' ciphertext = 'qayaeaagaciai' assert_equal(ciphertext, Cipher.new('iamapandabear').encode(plaintext)) end def test_cipher_encode_wrap - skip + # skip plaintext = 'zzzzzzzzzz' ciphertext = 'zabcdefghi' assert_equal(ciphertext, @cipher.encode(plaintext)) @@ -107,21 +131,21 @@ def setup end def test_cipher_encode - skip + # skip plaintext = 'aaaaaaaaaa' ciphertext = 'dddddddddd' assert_equal(ciphertext, @cipher.encode(plaintext)) end def test_cipher_decode - skip + # skip plaintext = 'aaaaaaaaaa' ciphertext = 'dddddddddd' assert_equal(plaintext, @cipher.decode(ciphertext)) end def test_cipher_reversible - skip + # skip plaintext = 'abcdefghij' assert_equal(plaintext, @cipher.decode(@cipher.encode(plaintext))) end