From ce18f48bc1d393e6acee8ccaa5a21091630d0da7 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Wed, 27 Jan 2021 17:31:55 +0900 Subject: [PATCH 01/58] Add Ruby 3 to required Ruby versions --- rambling-trie.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 46d8daf4..13445c43 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '~> 2.4' + gem.required_ruby_version = '~> 2.4', '~> 3.0.0' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.9' From 4c5d1915805e0d972bee47e5fd97029cbc1838bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Wed, 27 Jan 2021 21:24:18 -0500 Subject: [PATCH 02/58] >= 2.4 and <= 3.0.0 instead of ~> --- rambling-trie.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 13445c43..f7bd6c2e 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '~> 2.4', '~> 3.0.0' + gem.required_ruby_version = '>= 2.4', '<= 3.0.0' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.9' From 7f1e35e2f750fb5bd2b8021fcf58eefda488661d Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 27 Jan 2021 21:27:16 -0500 Subject: [PATCH 03/58] Bump min version to 2.5 --- rambling-trie.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index f7bd6c2e..41ad73ee 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '>= 2.4', '<= 3.0.0' + gem.required_ruby_version = '>= 2.5', '<= 3.0.0' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.9' From 7c782adc0f19755433825fa16ec1df2e87161382 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 27 Jan 2021 21:28:25 -0500 Subject: [PATCH 04/58] Add latest supported versions to CI --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index bea30e24..589a765e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,8 @@ before_install: install: - bundle install --without local rvm: + - 3.0.0 + - 2.7.2 - 2.7.1 - 2.7.0 - 2.6.6 From a1b5da4f634f68955550798c95ad8db138d47145 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 27 Jan 2021 23:01:19 -0500 Subject: [PATCH 05/58] Bump version to 2.2.0 --- lib/rambling/trie/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rambling/trie/version.rb b/lib/rambling/trie/version.rb index 17a67948..3689925b 100644 --- a/lib/rambling/trie/version.rb +++ b/lib/rambling/trie/version.rb @@ -3,6 +3,6 @@ module Rambling module Trie # Current version of the rambling-trie. - VERSION = '2.1.2' + VERSION = '2.2.0' end end From 913fee05db96b94cd752e42947b4c8bffbd1899c Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Wed, 27 Jan 2021 23:07:30 -0500 Subject: [PATCH 06/58] Add v2.2.0 compare to CHANGELOG --- CHANGELOG.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6d3ea85..ab25d142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog -## 2.1.2 [compare][compare_v2_1_1_and_master] +## 2.2.1 [compare][compare_v2_2_0_and_master] + +## 2.2.0 [compare][compare_v2_1_1_and_v2_2_0] + +- Bump min version to 2.5 by [@gonzedge][github_user_gonzedge] +- Add Ruby 3 to required Ruby versions by [@KitaitiMakoto][github_user_kitaitimakoto] ## 2.1.1 [compare][compare_v2_1_0_and_v2_1_1] @@ -831,7 +836,8 @@ Most of these help with the gem's overall performance. [compare_v1_0_3_and_v2_0_0]: https://github.com/gonzedge/rambling-trie/compare/v1.0.3...v2.0.0 [compare_v2_0_0_and_v2_1_0]: https://github.com/gonzedge/rambling-trie/compare/v2.0.0...v2.1.0 [compare_v2_1_0_and_v2_1_1]: https://github.com/gonzedge/rambling-trie/compare/v2.1.0...v2.1.1 -[compare_v2_1_1_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.1.1...master +[compare_v2_1_1_and_v2_2_0]: https://github.com/gonzedge/rambling-trie/compare/v2.1.1...v2.2.0 +[compare_v2_2_0_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.1.1...master [design_patterns_null_object]: http://wiki.c2.com/?NullObject [github_commit_current_key_less_memory]: https://github.com/gonzedge/rambling-trie/commit/218fac218a77e70ba04a3672ff5abfddf6544f57 [github_commit_reduced_memory_footprint]: https://github.com/gonzedge/rambling-trie/commit/aa8c0262f888e88df6a2f1e1351d8f14b21e43c4 @@ -849,4 +855,5 @@ Most of these help with the gem's overall performance. [github_user_gonzedge]: https://github.com/gonzedge [github_user_lilibethdlc]: https://github.com/lilibethdlc [github_user_shinjiikeda]: https://github.com/shinjiikeda +[github_user_kitaitimakoto]: https://github.com/KitaitiMakoto [ruby_bug_13111]: https://bugs.ruby-lang.org/issues/13111 From 8c57c128e2ab58fe48b59fe350c350d9040e0d98 Mon Sep 17 00:00:00 2001 From: Andersen Fan Date: Fri, 18 Jun 2021 11:58:13 +0800 Subject: [PATCH 07/58] Support ruby version 3.0.x --- .travis.yml | 1 + lib/rambling/trie/version.rb | 2 +- rambling-trie.gemspec | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 589a765e..56c41d22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ before_install: install: - bundle install --without local rvm: + - 3.0.1 - 3.0.0 - 2.7.2 - 2.7.1 diff --git a/lib/rambling/trie/version.rb b/lib/rambling/trie/version.rb index 3689925b..d04a8fc6 100644 --- a/lib/rambling/trie/version.rb +++ b/lib/rambling/trie/version.rb @@ -3,6 +3,6 @@ module Rambling module Trie # Current version of the rambling-trie. - VERSION = '2.2.0' + VERSION = '2.2.1' end end diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 41ad73ee..4ce83a33 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '>= 2.5', '<= 3.0.0' + gem.required_ruby_version = '>= 2.5', '< 3.1' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.9' From 2b226cf35c6b2dfb13307a5e173b47a5602feeb6 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 18 Jun 2021 19:23:33 -0400 Subject: [PATCH 08/58] Update CHANGELOG and README with ruby 3.0.x support --- CHANGELOG.md | 12 ++++++++---- README.md | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab25d142..deb6cbfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ -# Changelog +## 2.2.2 [compare][compare_v2_2_1_and_master] -## 2.2.1 [compare][compare_v2_2_0_and_master] +## 2.2.1 [compare][compare_v2_2_0_and_v2_2_1] + +- Add support for Ruby 3.0.x by [@as181920][github_user_as181920] ## 2.2.0 [compare][compare_v2_1_1_and_v2_2_0] @@ -837,7 +839,8 @@ Most of these help with the gem's overall performance. [compare_v2_0_0_and_v2_1_0]: https://github.com/gonzedge/rambling-trie/compare/v2.0.0...v2.1.0 [compare_v2_1_0_and_v2_1_1]: https://github.com/gonzedge/rambling-trie/compare/v2.1.0...v2.1.1 [compare_v2_1_1_and_v2_2_0]: https://github.com/gonzedge/rambling-trie/compare/v2.1.1...v2.2.0 -[compare_v2_2_0_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.1.1...master +[compare_v2_2_0_and_v2_2_1]: https://github.com/gonzedge/rambling-trie/compare/v2.2.0...v2.2.1 +[compare_v2_2_1_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.2.1...master [design_patterns_null_object]: http://wiki.c2.com/?NullObject [github_commit_current_key_less_memory]: https://github.com/gonzedge/rambling-trie/commit/218fac218a77e70ba04a3672ff5abfddf6544f57 [github_commit_reduced_memory_footprint]: https://github.com/gonzedge/rambling-trie/commit/aa8c0262f888e88df6a2f1e1351d8f14b21e43c4 @@ -851,9 +854,10 @@ Most of these help with the gem's overall performance. [github_issue_09]: https://github.com/gonzedge/rambling-trie/issues/9 [github_issue_10]: https://github.com/gonzedge/rambling-trie/issues/10 [github_issue_11]: https://github.com/gonzedge/rambling-trie/issues/11 +[github_user_as181920]: https://github.com/as181920 [github_user_godsent]: https://github.com/godsent [github_user_gonzedge]: https://github.com/gonzedge +[github_user_kitaitimakoto]: https://github.com/KitaitiMakoto [github_user_lilibethdlc]: https://github.com/lilibethdlc [github_user_shinjiikeda]: https://github.com/shinjiikeda -[github_user_kitaitimakoto]: https://github.com/KitaitiMakoto [ruby_bug_13111]: https://bugs.ruby-lang.org/issues/13111 diff --git a/README.md b/README.md index b9d5a04e..6a7c9939 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,7 @@ You can find further API documentation on the autogenerated [rambling-trie gem R The Rambling Trie has been tested with the following Ruby versions: +* 3.0.x * 2.7.x * 2.6.x * 2.5.x @@ -295,7 +296,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [rubydoc_github]: http://rubydoc.info/github/gonzedge/rambling-trie [rubyzip]: https://github.com/rubyzip/rubyzip [rvm]: https://rvm.io -[travis_ci_badge]: https://travis-ci.org/gonzedge/rambling-trie.svg -[travis_ci_link]: https://travis-ci.org/gonzedge/rambling-trie +[travis_ci_badge]: https://travis-ci.com/gonzedge/rambling-trie.svg?branch=master +[travis_ci_link]: https://travis-ci.com/github/gonzedge/rambling-trie [trie_wiki]: https://en.wikipedia.org/wiki/Trie [yaml]: https://ruby-doc.org/stdlib-2.5.0/libdoc/yaml/rdoc/YAML.html From 2c595e930298d6fdb25090d98d126e380163336d Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 18 Jun 2021 20:09:40 -0400 Subject: [PATCH 09/58] Add ruby 2.7.3, 2.6.7, 2.5.9 to CI build --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 56c41d22..8d681ac1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,11 @@ install: rvm: - 3.0.1 - 3.0.0 + - 2.7.3 - 2.7.2 - 2.7.1 - 2.7.0 + - 2.6.7 - 2.6.6 - 2.6.5 - 2.6.4 @@ -19,6 +21,7 @@ rvm: - 2.6.2 - 2.6.1 - 2.6.0 + - 2.5.9 - 2.5.8 - 2.5.7 - 2.5.6 From f191aeff43e3fdda1e94d5b9124b6715824d6261 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 18 Jun 2021 20:11:35 -0400 Subject: [PATCH 10/58] Upgrade dev dependencies to latest --- rambling-trie.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 4ce83a33..9c33d7c5 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -32,6 +32,6 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 2.5', '< 3.1' gem.add_development_dependency 'rake', '~> 13.0' - gem.add_development_dependency 'rspec', '~> 3.9' - gem.add_development_dependency 'yard', '~> 0.9.25' + gem.add_development_dependency 'rspec', '~> 3.10' + gem.add_development_dependency 'yard', '~> 0.9.26' end From fbb87e33474dd3a0add5ccc6140bc7aadb495045 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 27 Dec 2021 13:45:49 +0900 Subject: [PATCH 11/58] Don't use YAML.safe_load's legacy API --- lib/rambling/trie/serializers/yaml.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/rambling/trie/serializers/yaml.rb b/lib/rambling/trie/serializers/yaml.rb index 42059483..394cf3b2 100644 --- a/lib/rambling/trie/serializers/yaml.rb +++ b/lib/rambling/trie/serializers/yaml.rb @@ -23,13 +23,12 @@ def load filepath require 'yaml' ::YAML.safe_load( serializer.load(filepath), - [ + permitted_classes: [ Symbol, Rambling::Trie::Nodes::Raw, Rambling::Trie::Nodes::Compressed, ], - [], - true, + aliases: true, ) end From 6cbdc2ad3af4a87e8e6b18dd68af1bfce255fec4 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 27 Dec 2021 13:46:16 +0900 Subject: [PATCH 12/58] Include Ruby 3.1 in supported versions --- rambling-trie.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 9c33d7c5..b7baf064 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '>= 2.5', '< 3.1' + gem.required_ruby_version = '>= 2.5', '< 3.2' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.10' From fec3dcd8143d73421afd82b7fd1875abdd565f57 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 27 Dec 2021 13:47:19 +0900 Subject: [PATCH 13/58] Add block to Coveralls.wear! to prevent SimpleCove.start being called twice --- spec/spec_helper.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2d033be9..3cd5d364 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,14 +3,12 @@ require 'simplecov' require 'coveralls' -Coveralls.wear! - SimpleCov.formatters = [ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter, ] -SimpleCov.start do +Coveralls.wear! do add_filter '/spec/' end From 1b571b0b6d82099da599e86e2607351364f4ef2b Mon Sep 17 00:00:00 2001 From: agate Date: Tue, 14 Mar 2023 18:19:59 -0700 Subject: [PATCH 14/58] add ruby 3.2 support --- .travis.yml | 17 +++++++++++++++++ lib/rambling/trie/serializers/yaml.rb | 5 ++--- lib/rambling/trie/version.rb | 2 +- rambling-trie.gemspec | 2 +- spec/spec_helper.rb | 4 +--- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d681ac1..8c77d4b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,29 @@ before_install: install: - bundle install --without local rvm: + - 3.2.1 + - 3.2.0 + - 3.1.3 + - 3.1.2 + - 3.1.1 + - 3.1.0 + - 3.0.5 + - 3.0.4 + - 3.0.3 + - 3.0.2 - 3.0.1 - 3.0.0 + - 2.7.7 + - 2.7.6 + - 2.7.5 + - 2.7.4 - 2.7.3 - 2.7.2 - 2.7.1 - 2.7.0 + - 2.6.10 + - 2.6.9 + - 2.6.8 - 2.6.7 - 2.6.6 - 2.6.5 diff --git a/lib/rambling/trie/serializers/yaml.rb b/lib/rambling/trie/serializers/yaml.rb index 42059483..394cf3b2 100644 --- a/lib/rambling/trie/serializers/yaml.rb +++ b/lib/rambling/trie/serializers/yaml.rb @@ -23,13 +23,12 @@ def load filepath require 'yaml' ::YAML.safe_load( serializer.load(filepath), - [ + permitted_classes: [ Symbol, Rambling::Trie::Nodes::Raw, Rambling::Trie::Nodes::Compressed, ], - [], - true, + aliases: true, ) end diff --git a/lib/rambling/trie/version.rb b/lib/rambling/trie/version.rb index d04a8fc6..6c4bfce2 100644 --- a/lib/rambling/trie/version.rb +++ b/lib/rambling/trie/version.rb @@ -3,6 +3,6 @@ module Rambling module Trie # Current version of the rambling-trie. - VERSION = '2.2.1' + VERSION = '2.2.3' end end diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 9c33d7c5..56b181ee 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '>= 2.5', '< 3.1' + gem.required_ruby_version = '>= 2.5', '<= 3.2' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.10' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2d033be9..3cd5d364 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,14 +3,12 @@ require 'simplecov' require 'coveralls' -Coveralls.wear! - SimpleCov.formatters = [ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter, ] -SimpleCov.start do +Coveralls.wear! do add_filter '/spec/' end From 73e9a3be48e2fa03b7aeee39809ac1f9184a7cf7 Mon Sep 17 00:00:00 2001 From: agate Date: Tue, 14 Mar 2023 18:27:56 -0700 Subject: [PATCH 15/58] make sure gem also support all the sub version of 3.2 --- rambling-trie.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 56b181ee..4514b2ed 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '>= 2.5', '<= 3.2' + gem.required_ruby_version = '>= 2.5', '< 3.3' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.10' From 96ba2b3cb3a8f0b8f81f4c97a743a2e819922c93 Mon Sep 17 00:00:00 2001 From: agate Date: Tue, 14 Mar 2023 18:49:55 -0700 Subject: [PATCH 16/58] use new coveralls_reborn to support new ruby --- Gemfile | 2 +- spec/spec_helper.rb | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index bcb70db2..c56dc583 100644 --- a/Gemfile +++ b/Gemfile @@ -16,7 +16,7 @@ group :development do end group :test do - gem 'coveralls', '~>0.8.21', require: false + gem 'coveralls_reborn', '~> 0.27.0', require: false gem 'simplecov', require: false end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3cd5d364..2d033be9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,12 +3,14 @@ require 'simplecov' require 'coveralls' +Coveralls.wear! + SimpleCov.formatters = [ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter, ] -Coveralls.wear! do +SimpleCov.start do add_filter '/spec/' end From efbb345bc377b88f6d3ad5613fe7a7d7e7acc166 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 30 Mar 2023 23:14:58 -0400 Subject: [PATCH 17/58] Update required ruby version bounds to `>= 2.7, < 4` (drops explicit support for 2.5.x and 2.6.x) --- rambling-trie.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 4514b2ed..391beecd 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |gem| gem.license = 'MIT' gem.version = Rambling::Trie::VERSION gem.platform = Gem::Platform::RUBY - gem.required_ruby_version = '>= 2.5', '< 3.3' + gem.required_ruby_version = '>= 2.7', '< 4' gem.add_development_dependency 'rake', '~> 13.0' gem.add_development_dependency 'rspec', '~> 3.10' From 69d8f6c771040691f97468c363a6ea82852347b7 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 30 Mar 2023 23:25:55 -0400 Subject: [PATCH 18/58] Drop support for Ruby 2.5.x and 2.6.x --- .travis.yml | 21 --------------------- README.md | 16 +++++++++------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c77d4b1..1c4a8627 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,27 +27,6 @@ rvm: - 2.7.2 - 2.7.1 - 2.7.0 - - 2.6.10 - - 2.6.9 - - 2.6.8 - - 2.6.7 - - 2.6.6 - - 2.6.5 - - 2.6.4 - - 2.6.3 - - 2.6.2 - - 2.6.1 - - 2.6.0 - - 2.5.9 - - 2.5.8 - - 2.5.7 - - 2.5.6 - - 2.5.5 - - 2.5.4 - - 2.5.3 - - 2.5.2 - - 2.5.1 - - 2.5.0 before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter diff --git a/README.md b/README.md index 6a7c9939..cb34769b 100644 --- a/README.md +++ b/README.md @@ -242,20 +242,22 @@ You can find further API documentation on the autogenerated [rambling-trie gem R The Rambling Trie has been tested with the following Ruby versions: +* 3.2.x +* 3.1.x * 3.0.x * 2.7.x -* 2.6.x -* 2.5.x **No longer supported**: +* 2.6.x (EOL'ed) +* 2.5.x (EOL'ed) * 2.4.x (EOL'ed) * 2.3.x (EOL'ed) -* 2.2.x -* 2.1.x -* 2.0.x -* 1.9.x -* 1.8.x +* 2.2.x (EOL'ed) +* 2.1.x (EOL'ed) +* 2.0.x (EOL'ed) +* 1.9.x (EOL'ed) +* 1.8.x (EOL'ed) ## Contributing to Rambling Trie From a7a0cdfe18f9602e64d76a3d25502a6c6a680c66 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 30 Mar 2023 23:26:54 -0400 Subject: [PATCH 19/58] Add Ruby 2.7.8, 3.0.6, 3.1.4, 3.2.2 to supported versions --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1c4a8627..5e78ea79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,18 +7,22 @@ before_install: install: - bundle install --without local rvm: + - 3.2.2 - 3.2.1 - 3.2.0 + - 3.1.4 - 3.1.3 - 3.1.2 - 3.1.1 - 3.1.0 + - 3.0.6 - 3.0.5 - 3.0.4 - 3.0.3 - 3.0.2 - 3.0.1 - 3.0.0 + - 2.7.8 - 2.7.7 - 2.7.6 - 2.7.5 From 247c31cd5234f317abb4b8e0dcbbb93f259e31a9 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 30 Mar 2023 23:32:45 -0400 Subject: [PATCH 20/58] Upgrade development dependencies --- rambling-trie.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 391beecd..2b35572b 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -32,6 +32,6 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 2.7', '< 4' gem.add_development_dependency 'rake', '~> 13.0' - gem.add_development_dependency 'rspec', '~> 3.10' - gem.add_development_dependency 'yard', '~> 0.9.26' + gem.add_development_dependency 'rspec', '~> 3.12' + gem.add_development_dependency 'yard', '~> 0.9.28' end From e5c65e2e0a7d211e665780ee6ab3fd4fe1936949 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 30 Mar 2023 23:45:04 -0400 Subject: [PATCH 21/58] Update documentation links to min required ruby version (2.7) --- README.md | 6 +++--- lib/rambling/trie.rb | 2 +- lib/rambling/trie/configuration/provider_collection.rb | 4 ++-- lib/rambling/trie/container.rb | 2 +- lib/rambling/trie/enumerable.rb | 2 +- lib/rambling/trie/nodes/node.rb | 8 ++++---- lib/rambling/trie/serializers/marshal.rb | 6 +++--- lib/rambling/trie/serializers/yaml.rb | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index cb34769b..5711b678 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wik You will need: -* Ruby 2.5.0 or up +* Ruby 2.7.0 or up * RubyGems See [RVM][rvm], [rbenv][rbenv] or [chruby][chruby] for more information on how to manage Ruby versions. @@ -289,7 +289,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [inch_ci_link]: https://inch-ci.org/github/gonzedge/rambling-trie [license_badge]: https://badges.frapsoft.com/os/mit/mit.svg?v=103 [license_link]: https://opensource.org/licenses/mit-license.php -[marshal]: https://ruby-doc.org/core-2.5.0/Marshal.html +[marshal]: https://ruby-doc.org/core-2.7.0/Marshal.html [rambling_trie_configuration]: https://github.com/gonzedge/rambling-trie#configuration [rambling_trie_contributing_guide]: https://github.com/gonzedge/rambling-trie/blob/master/CONTRIBUTING.md [rambling_trie_plain_text_reader]: https://github.com/gonzedge/rambling-trie/blob/master/lib/rambling/trie/readers/plain_text.rb @@ -301,4 +301,4 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [travis_ci_badge]: https://travis-ci.com/gonzedge/rambling-trie.svg?branch=master [travis_ci_link]: https://travis-ci.com/github/gonzedge/rambling-trie [trie_wiki]: https://en.wikipedia.org/wiki/Trie -[yaml]: https://ruby-doc.org/stdlib-2.5.0/libdoc/yaml/rdoc/YAML.html +[yaml]: https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html diff --git a/lib/rambling/trie.rb b/lib/rambling/trie.rb index 3319d5e8..6909b157 100644 --- a/lib/rambling/trie.rb +++ b/lib/rambling/trie.rb @@ -45,7 +45,7 @@ def create filepath = nil, reader = nil # @yield [Container] the trie just loaded. # @see Rambling::Trie::Serializers Serializers. # @note Use of - # {https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-load + # {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load # Marshal.load} is generally discouraged. Only use the `.marshal` # format with trusted input. def load filepath, serializer = nil diff --git a/lib/rambling/trie/configuration/provider_collection.rb b/lib/rambling/trie/configuration/provider_collection.rb index ccba8eca..27183c25 100644 --- a/lib/rambling/trie/configuration/provider_collection.rb +++ b/lib/rambling/trie/configuration/provider_collection.rb @@ -77,7 +77,7 @@ def reset # Get provider corresponding to a given format. # @return [Array] the provider corresponding to that format. - # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-5B-5D + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D # Hash#keys def formats providers.keys @@ -86,7 +86,7 @@ def formats # Get provider corresponding to a given format. # @param [Symbol] format the format to search for in the collection. # @return [Object] the provider corresponding to that format. - # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-5B-5D + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D # Hash#[] def [] format providers[format] diff --git a/lib/rambling/trie/container.rb b/lib/rambling/trie/container.rb index 15a529d6..0ed9c8e4 100644 --- a/lib/rambling/trie/container.rb +++ b/lib/rambling/trie/container.rb @@ -168,7 +168,7 @@ def compressed? # Array of words contained in the root {Nodes::Node Node}. # @return [Array] all words contained in this trie. - # @see https://ruby-doc.org/core-2.5.0/Enumerable.html#method-i-to_a + # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a # Enumerable#to_a def to_a root.to_a diff --git a/lib/rambling/trie/enumerable.rb b/lib/rambling/trie/enumerable.rb index 3a1b5333..64937547 100644 --- a/lib/rambling/trie/enumerable.rb +++ b/lib/rambling/trie/enumerable.rb @@ -7,7 +7,7 @@ module Enumerable include ::Enumerable # Returns number of words contained in the trie - # @see https://ruby-doc.org/core-2.5.0/Enumerable.html#method-i-count + # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-count # Enumerable#count alias_method :size, :count diff --git a/lib/rambling/trie/nodes/node.rb b/lib/rambling/trie/nodes/node.rb index 2c7975ae..43e40db3 100644 --- a/lib/rambling/trie/nodes/node.rb +++ b/lib/rambling/trie/nodes/node.rb @@ -128,7 +128,7 @@ def match_prefix chars # Get {Node Node} corresponding to a given letter. # @param [Symbol] letter the letter to search for in the node. # @return [Node] the node corresponding to that letter. - # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-5B-5D + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D # Hash#[] def [] letter children_tree[letter] @@ -139,7 +139,7 @@ def [] letter # @param [Node] node the {Node Node} to assign to that letter. # @return [Node] the node corresponding to the inserted or # updated letter. - # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-5B-5D + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D # Hash#[] def []= letter, node children_tree[letter] = node @@ -149,7 +149,7 @@ def []= letter, node # letter. # @param [Symbol] letter the letter to search for in the node. # @return [Boolean] `true` if the letter is present, `false` otherwise - # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-has_key-3F + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F # Hash#key? def key? letter children_tree.key? letter @@ -160,7 +160,7 @@ def key? letter # @param [Symbol] letter the letter to delete from the node's children # tree. # @return [Node] the node corresponding to the deleted letter. - # @see https://ruby-doc.org/core-2.5.0/Hash.html#method-i-delete + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-delete # Hash#delete def delete letter children_tree.delete letter diff --git a/lib/rambling/trie/serializers/marshal.rb b/lib/rambling/trie/serializers/marshal.rb index 568c1b3f..859dce3d 100644 --- a/lib/rambling/trie/serializers/marshal.rb +++ b/lib/rambling/trie/serializers/marshal.rb @@ -17,10 +17,10 @@ def initialize serializer = nil # @param [String] filepath the full path of the file to load the # marshaled object from. # @return [Nodes::Node] The deserialized {Nodes::Node Node}. - # @see https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-load + # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load # Marshal.load # @note Use of - # {https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-load + # {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load # Marshal.load} is generally discouraged. Only use this with trusted # input. def load filepath @@ -33,7 +33,7 @@ def load filepath # @param [String] filepath the full path of the file to dump the # marshaled object into. # @return [Numeric] number of bytes written to disk. - # @see https://ruby-doc.org/core-2.5.0/Marshal.html#method-c-dump + # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-dump # Marshal.dump def dump node, filepath serializer.dump ::Marshal.dump(node), filepath diff --git a/lib/rambling/trie/serializers/yaml.rb b/lib/rambling/trie/serializers/yaml.rb index 394cf3b2..28987d4b 100644 --- a/lib/rambling/trie/serializers/yaml.rb +++ b/lib/rambling/trie/serializers/yaml.rb @@ -17,7 +17,7 @@ def initialize serializer = nil # @param [String] filepath the full path of the file to load the # serialized YAML object from. # @return [Nodes::Node] The deserialized {Nodes::Node Node}. - # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/psych/rdoc/Psych.html#method-c-safe_load + # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-safe_load # Psych.safe_load def load filepath require 'yaml' @@ -38,7 +38,7 @@ def load filepath # @param [String] filepath the full path of the file to dump the YAML # object into. # @return [Numeric] number of bytes written to disk. - # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/psych/rdoc/Psych.html#method-c-dump + # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-dump # Psych.dump def dump node, filepath require 'yaml' From 3d781eaffe80531feedd4765fc92aea2a5f80067 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 30 Mar 2023 23:39:19 -0400 Subject: [PATCH 22/58] Update CHANGELOG with ruby 3.1.x and 3.2.x support --- CHANGELOG.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index deb6cbfc..9ba18ebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,18 @@ -## 2.2.2 [compare][compare_v2_2_1_and_master] +## 2.3.1 [compare][compare_v2_3_0_and_master] + +## 2.3.0 [compare][compare_v2_2_1_and_v2_3_0] + +- Don't use `YAML.safe_load`'s legacy API by [@KitaitiMakoto][github_user_kitaitimakoto] +- Add explicit support for Ruby 3.1.x by [@KitaitiMakoto][github_user_kitaitimakoto] +- Add block to `Coveralls.wear!` to prevent `SimpleCove.start` being called twice by [@KitaitiMakoto][github_user_kitaitimakoto] +- Add explicit support for Ruby 3.2.x by [@agate][github_user_agate] +- Make sure gem also supports all the sub version of 3.2 by [@agate][github_user_agate] + - Includes adding support for 2.7.{4,5,6,7}, 3.0.{2,3,4,5}, 3.1.{0,1,2,3} and 3.2.{0,1} +- Use new `coveralls_reborn` to support new ruby by [@agate][github_user_agate] +- Update `required_ruby_version` bounds to `>= 2.7, < 4` by [@gonzedge][github_user_gonzedge] +- Drop support for Ruby 2.5.x and 2.6.x by [@gonzedge][github_user_gonzedge] +- Add Ruby 2.7.8, 3.0.6, 3.1.4, 3.2.2 to supported versions by [@gonzedge][github_user_gonzedge] +- Update documentation links to min required ruby version by [@gonzedge][github_user_gonzedge] ## 2.2.1 [compare][compare_v2_2_0_and_v2_2_1] @@ -840,7 +854,8 @@ Most of these help with the gem's overall performance. [compare_v2_1_0_and_v2_1_1]: https://github.com/gonzedge/rambling-trie/compare/v2.1.0...v2.1.1 [compare_v2_1_1_and_v2_2_0]: https://github.com/gonzedge/rambling-trie/compare/v2.1.1...v2.2.0 [compare_v2_2_0_and_v2_2_1]: https://github.com/gonzedge/rambling-trie/compare/v2.2.0...v2.2.1 -[compare_v2_2_1_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.2.1...master +[compare_v2_2_1_and_v2_3_0]: https://github.com/gonzedge/rambling-trie/compare/v2.2.1...v2.3.0 +[compare_v2_3_0_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.3.0...master [design_patterns_null_object]: http://wiki.c2.com/?NullObject [github_commit_current_key_less_memory]: https://github.com/gonzedge/rambling-trie/commit/218fac218a77e70ba04a3672ff5abfddf6544f57 [github_commit_reduced_memory_footprint]: https://github.com/gonzedge/rambling-trie/commit/aa8c0262f888e88df6a2f1e1351d8f14b21e43c4 @@ -854,6 +869,7 @@ Most of these help with the gem's overall performance. [github_issue_09]: https://github.com/gonzedge/rambling-trie/issues/9 [github_issue_10]: https://github.com/gonzedge/rambling-trie/issues/10 [github_issue_11]: https://github.com/gonzedge/rambling-trie/issues/11 +[github_user_agate]: https://github.com/agate [github_user_as181920]: https://github.com/as181920 [github_user_godsent]: https://github.com/godsent [github_user_gonzedge]: https://github.com/gonzedge From 60fcb546a88666825fd935d6b716dfbd8fe7533d Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 30 Mar 2023 23:05:17 -0400 Subject: [PATCH 23/58] Bump version to 2.3.0 --- lib/rambling/trie/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rambling/trie/version.rb b/lib/rambling/trie/version.rb index 6c4bfce2..eab526e6 100644 --- a/lib/rambling/trie/version.rb +++ b/lib/rambling/trie/version.rb @@ -3,6 +3,6 @@ module Rambling module Trie # Current version of the rambling-trie. - VERSION = '2.2.3' + VERSION = '2.3.0' end end From a7403890490e933cb907d69c3606498200b2ae68 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sat, 1 Apr 2023 23:10:32 -0400 Subject: [PATCH 24/58] Fix `Rambling::Trie.load` docs in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5711b678..e8c0da30 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ Rambling::Trie.dump trie, '/path/to/file' Then, when you need to use a trie next time, you don't have to create a new one with all the necessary words. Rather, you can retrieve a previously stored one with `.load` like this: ``` ruby -trie = Rambling::Trie.load trie, '/path/to/file' +trie = Rambling::Trie.load '/path/to/file' ``` #### Supported formats @@ -197,7 +197,7 @@ Then, you can load contents form a `.zip` file like this: ``` ruby require 'zip' -trie = Rambling::Trie.load trie, '/path/to/file.zip' +trie = Rambling::Trie.load '/path/to/file.zip' ``` > For `.zip` files, the format is also determined automatically based on the From 2a09fcfb8d71eefef171afd88e63ef6b97c9fe7f Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sat, 1 Apr 2023 23:27:21 -0400 Subject: [PATCH 25/58] Destructure args hash before passing to performance rake task --- tasks/performance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/performance.rb b/tasks/performance.rb index 59032c79..efcc922a 100644 --- a/tasks/performance.rb +++ b/tasks/performance.rb @@ -14,7 +14,7 @@ configuration = Performance::Configuration.new task = Performance::Task.new configuration - task.run args + task.run **args end namespace :performance do From aeb23ed9e4134ba69d9a8fc4394efc0b783628eb Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sun, 2 Apr 2023 00:04:35 -0400 Subject: [PATCH 26/58] Update copyright years --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e8c0da30..a61e686c 100644 --- a/README.md +++ b/README.md @@ -265,7 +265,7 @@ Take a look at the [contributing guide][rambling_trie_contributing_guide] to get ## License and copyright -Copyright (c) 2012-2017 Edgar Gonzalez +Copyright (c) 2012-2023 Edgar González MIT License From d86e79174915bc878b6bfe6a942587c91e78b250 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sun, 2 Apr 2023 00:12:31 -0400 Subject: [PATCH 27/58] Attempt to clear gem version badge being cached by GitHub (?) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a61e686c..caa4de22 100644 --- a/README.md +++ b/README.md @@ -275,7 +275,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg +[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.3.0 [badge_fury_link]: https://badge.fury.io/rb/rambling-trie [chruby]: https://github.com/postmodern/chruby [code_climage_link]: https://codeclimate.com/github/gonzedge/rambling-trie From 0fb0d380694264f8b51fa7056fecb49eaf309556 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Sun, 2 Apr 2023 04:19:49 +0000 Subject: [PATCH 28/58] Set up semaphore * Use RSpec starter workflow * Update Semaphore configuration * Update Semaphore configuration * Update Semaphore configuration * Update Semaphore configuration * Add all ruby versions * Add test reporting * Use badge from semaphore * Publish results after pipeline --- .semaphore/semaphore.yml | 257 +++++++++++++++++++++++++++++++++++++++ Gemfile | 1 + README.md | 6 +- 3 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 .semaphore/semaphore.yml diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml new file mode 100644 index 00000000..179d0ebd --- /dev/null +++ b/.semaphore/semaphore.yml @@ -0,0 +1,257 @@ +version: v1.0 +name: ruby +agent: + machine: + type: e1-standard-2 + os_image: ubuntu2004 +blocks: + - name: 3.2.1 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.2.1 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + epilogue: + always: + commands: + - test-results publish junit.xml + - name: 3.2.0 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.2.0 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.1.3 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.1.3 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.1.2 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.1.2 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.1.1 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.1.1 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.1.0 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.1.0 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.0.5 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.0.5 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.0.4 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.0.4 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.0.3 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.0.3 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.0.2 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.0.2 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.0.1 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.0.1 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 3.0.0 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 3.0.0 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.7 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.7 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.6 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.6 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.5 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.5 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.4 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.4 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.3 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.3 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.2 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.2 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.1 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.1 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - name: 2.7.0 + dependencies: [] + task: + prologue: + commands: + - checkout + - sem-version ruby 2.7.0 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation +after_pipeline: + task: + jobs: + - name: test report + commands: + - test-results gen-pipeline-report diff --git a/Gemfile b/Gemfile index c56dc583..1c5bad23 100644 --- a/Gemfile +++ b/Gemfile @@ -18,6 +18,7 @@ end group :test do gem 'coveralls_reborn', '~> 0.27.0', require: false gem 'simplecov', require: false + gem 'rspec_junit_formatter' end group :local do diff --git a/README.md b/README.md index caa4de22..ec291937 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Rambling Trie -[![Gem Version][badge_fury_badge]][badge_fury_link] [![Build Status][travis_ci_badge]][travis_ci_link] [![Code Climate][code_climate_badge]][code_climage_link] [![Coverage Status][coveralls_badge]][coveralls_link] [![Documentation Status][inch_ci_badge]][inch_ci_link] [![License][license_badge]][license_link] +[![Gem Version][badge_fury_badge]][badge_fury_link] [![Build Status][semaphore_ci_badge]][semaphore_ci_link] [![Code Climate][code_climate_badge]][code_climage_link] [![Coverage Status][coveralls_badge]][coveralls_link] [![Documentation Status][inch_ci_badge]][inch_ci_link] [![License][license_badge]][license_link] The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse. @@ -298,7 +298,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [rubydoc_github]: http://rubydoc.info/github/gonzedge/rambling-trie [rubyzip]: https://github.com/rubyzip/rubyzip [rvm]: https://rvm.io -[travis_ci_badge]: https://travis-ci.com/gonzedge/rambling-trie.svg?branch=master -[travis_ci_link]: https://travis-ci.com/github/gonzedge/rambling-trie +[semaphore_ci_badge]: https://gonzedge.semaphoreci.com/badges/rambling-trie/branches/master.svg?style=shields&key=70cb32ae-6165-4aa1-92c0-1610cc4101ca +[semaphore_ci_link]: https://gonzedge.semaphoreci.com/projects/rambling-trie [trie_wiki]: https://en.wikipedia.org/wiki/Trie [yaml]: https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html From 112e77d42332edda540db4319bcf7621e11498f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 4 May 2023 14:22:16 -0400 Subject: [PATCH 29/58] Be more lax with file size (#26) So that tests in semaphore don't fail because of a small byte difference in compression depending on ruby version. --- spec/support/shared_examples/a_serializer.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/support/shared_examples/a_serializer.rb b/spec/support/shared_examples/a_serializer.rb index bd19d833..2f2000ce 100644 --- a/spec/support/shared_examples/a_serializer.rb +++ b/spec/support/shared_examples/a_serializer.rb @@ -21,7 +21,8 @@ end it 'converts the contents to the appropriate format' do - expect(File.read(filepath).size).to be_within(10).of formatted_content.size + file = File.read(filepath) + expect(file.size).to be_within(15).of formatted_content.size end end From c01f54786c4f196dab7bc46ce9e9b3146b7be40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 4 May 2023 14:58:53 -0400 Subject: [PATCH 30/58] Add missing `compress!` in container spec (#25) To actually test the non-matching tree shared example for compressed tries. --- spec/lib/rambling/trie/container_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/lib/rambling/trie/container_spec.rb b/spec/lib/rambling/trie/container_spec.rb index b976dea8..c43ff557 100644 --- a/spec/lib/rambling/trie/container_spec.rb +++ b/spec/lib/rambling/trie/container_spec.rb @@ -392,6 +392,8 @@ end context 'and the root has been compressed' do + before { container.compress! } + it_behaves_like 'a non matching tree' end end From 2848687d6e63a6701690f7a8a3e49f8f1bb97234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 4 May 2023 17:45:54 -0400 Subject: [PATCH 31/58] Rubocop: upgrade and apply (#24) #### Issues found in `lib/` and `tasks/` 1. Explicitly disable `Style/ExplicitBlockArgument` due to performance hits ([0a6aec0](https://github.com/gonzedge/rambling-trie/pull/24/commits/0a6aec07b6c5c00ecf527f8233ec668651ee1d93)) 2. Add missing `super`s 3. Yoda-style conditionals 4. Bump target ruby required version to current min supported (`2.7.0`) #### Issues found in `spec/` 1. Use `instance_double` instead of `double` 2. Split tests into single-assertion specs when parameterization is possible; disable otherwise 3. Use `let!` instead of instance variables 4. Remove duplicate test groups 5. Use `when` at the start of `context` block descriptions 6. Use `described_class`, `subject` in specs where possible 7. Single-line `before` where possible #### Other 1. Explicitly add `rubocop-performance`, `rubocop-rake`, `rubocop-rspec` plugins 2. Remove unused `Rails` rules 3. Remove unused/deprecated `RSpec`/`Layout`/`Style`/`Lint` rules --- .rubocop.disabled.yml | 10 - .rubocop.enabled.yml | 288 ++-------- .rubocop.yml | 255 ++------- Gemfile | 5 +- lib/rambling/trie/compressible.rb | 2 +- lib/rambling/trie/container.rb | 1 + lib/rambling/trie/nodes/node.rb | 6 +- rambling-trie.gemspec | 2 +- spec/integration/rambling/trie_spec.rb | 29 +- spec/lib/rambling/trie/comparable_spec.rb | 68 +-- spec/lib/rambling/trie/compressor_spec.rb | 31 +- .../trie/configuration/properties_spec.rb | 32 +- .../configuration/provider_collection_spec.rb | 56 +- spec/lib/rambling/trie/container_spec.rb | 524 +++++++----------- spec/lib/rambling/trie/enumerable_spec.rb | 22 +- spec/lib/rambling/trie/inspectable_spec.rb | 12 +- spec/lib/rambling/trie/nodes/node_spec.rb | 2 +- spec/lib/rambling/trie/nodes/raw_spec.rb | 49 +- .../rambling/trie/readers/plain_text_spec.rb | 4 +- .../rambling/trie/serializers/file_spec.rb | 2 - .../rambling/trie/serializers/marshal_spec.rb | 2 - .../rambling/trie/serializers/yaml_spec.rb | 2 - .../lib/rambling/trie/serializers/zip_spec.rb | 4 +- spec/lib/rambling/trie/stringifyable_spec.rb | 30 +- spec/lib/rambling/trie_spec.rb | 150 +++-- spec/spec_helper.rb | 3 +- .../shared_examples/a_compressible_trie.rb | 12 +- .../a_container_partial_word.rb | 18 + .../shared_examples/a_container_scan.rb | 14 + .../shared_examples/a_container_word.rb | 44 ++ .../a_container_words_within.rb | 44 ++ .../shared_examples/a_serializable_trie.rb | 12 +- spec/support/shared_examples/a_serializer.rb | 2 + .../shared_examples/a_trie_data_structure.rb | 34 +- spec/support/shared_examples/a_trie_node.rb | 31 +- .../a_trie_node_implementation.rb | 83 ++- tasks/ips.rb | 4 +- tasks/performance.rb | 2 +- tasks/performance/configuration.rb | 8 +- tasks/performance/reporters/benchmark.rb | 1 + .../reporters/call_tree_profile.rb | 1 + tasks/performance/reporters/flamegraph.rb | 1 + tasks/performance/reporters/memory_profile.rb | 1 + tasks/performance/reporters/reporter.rb | 6 +- tasks/performance/sub_tasks/initialization.rb | 1 + tasks/performance/sub_tasks/lookups/lookup.rb | 1 + .../sub_tasks/lookups/scan/compressed.rb | 1 + .../performance/sub_tasks/lookups/scan/raw.rb | 1 + 48 files changed, 840 insertions(+), 1073 deletions(-) create mode 100644 spec/support/shared_examples/a_container_partial_word.rb create mode 100644 spec/support/shared_examples/a_container_scan.rb create mode 100644 spec/support/shared_examples/a_container_word.rb create mode 100644 spec/support/shared_examples/a_container_words_within.rb diff --git a/.rubocop.disabled.yml b/.rubocop.disabled.yml index 7235d2a9..202a9970 100644 --- a/.rubocop.disabled.yml +++ b/.rubocop.disabled.yml @@ -38,16 +38,6 @@ Layout/MultilineAssignmentLayout: # Description: 'Checks unsafe usage of number conversion methods.' # Enabled: false -# By default, the rails cops are not run. Override in project or home -# directory .rubocop.yml files, or by giving the -R/--rails option. -Rails: - Enabled: false - -Rails/SaveBang: - Description: 'Identifies possible cases where Active Record save! or related should be used.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#save-bang' - Enabled: false - Style/AutoResourceCleanup: Description: 'Suggests the usage of an auto resource cleanup version of a method (if available).' Enabled: false diff --git a/.rubocop.enabled.yml b/.rubocop.enabled.yml index 44bb9fef..5310d679 100644 --- a/.rubocop.enabled.yml +++ b/.rubocop.enabled.yml @@ -1,4 +1,8 @@ # These are all the cops that are enabled in the default configuration. +require: + - rubocop-performance + - rubocop-rake + - rubocop-rspec #################### Bundler ############################### @@ -58,20 +62,20 @@ Layout/AccessModifierIndentation: StyleGuide: '#indent-public-private-protected' Enabled: true -Layout/AlignArray: +Layout/ArrayAlignment: Description: >- Align the elements of an array literal if they span more than one line. StyleGuide: '#align-multiline-arrays' Enabled: true -Layout/AlignHash: +Layout/HashAlignment: Description: >- Align the elements of a hash literal if they span more than one line. Enabled: true -Layout/AlignParameters: +Layout/ParameterAlignment: Description: >- Align the parameters of a method call if they span more than one line. @@ -175,23 +179,23 @@ Layout/FirstParameterIndentation: Description: 'Checks the indentation of the first parameter in a method call.' Enabled: true -Layout/IndentArray: +Layout/FirstArrayElementIndentation: Description: >- Checks the indentation of the first element in an array literal. Enabled: true -Layout/IndentAssignment: +Layout/AssignmentIndentation: Description: >- Checks the indentation of the first line of the right-hand-side of a multi-line assignment. Enabled: true -Layout/IndentHash: +Layout/FirstHashElementIndentation: Description: 'Checks the indentation of the first key in a hash literal.' Enabled: true -Layout/IndentHeredoc: +Layout/HeredocIndentation: Description: 'This cops checks the indentation of the here document bodies.' StyleGuide: '#squiggly-heredocs' Enabled: true @@ -385,12 +389,12 @@ Layout/SpaceInsideStringInterpolation: StyleGuide: '#string-interpolation' Enabled: true -Layout/Tab: +Layout/IndentationStyle: Description: 'No hard tabs.' StyleGuide: '#spaces-indentation' Enabled: true -Layout/TrailingBlankLines: +Layout/TrailingEmptyLines: Description: 'Checks trailing blank lines and final newline.' StyleGuide: '#newline-eof' Enabled: true @@ -432,7 +436,7 @@ Lint/AssignmentInCondition: # Description: '`BigDecimal.new()` is deprecated. Use `BigDecimal()` instead.' # Enabled: true -Lint/BlockAlignment: +Layout/BlockAlignment: Description: 'Align block ends correctly.' Enabled: true @@ -444,7 +448,7 @@ Lint/CircularArgumentReference: Description: "Default values in optional keyword arguments and optional ordinal arguments should not refer back to the name of the argument." Enabled: true -Lint/ConditionPosition: +Layout/ConditionPosition: Description: >- Checks for condition placed in a confusing position relative to the keyword. @@ -455,7 +459,7 @@ Lint/Debugger: Description: 'Check for debugger calls.' Enabled: true -Lint/DefEndAlignment: +Layout/DefEndAlignment: Description: 'Align ends corresponding to defs correctly.' Enabled: true @@ -471,7 +475,7 @@ Lint/DuplicateMethods: Description: 'Check for duplicate method definitions.' Enabled: true -Lint/DuplicatedKey: +Lint/DuplicateHashKey: Description: 'Check for duplicate keys in hash literals.' Enabled: true @@ -500,14 +504,10 @@ Lint/EmptyWhen: Description: 'Checks for `when` branches with empty bodies.' Enabled: true -Lint/EndAlignment: +Layout/EndAlignment: Description: 'Align ends correctly.' Enabled: true -Lint/EndInMethod: - Description: 'END blocks should not be placed inside method definitions.' - Enabled: true - Lint/EnsureReturn: Description: 'Do not use return in an ensure block.' StyleGuide: '#no-return-ensure' @@ -523,7 +523,7 @@ Lint/FormatParameterMismatch: Description: 'The number of parameters to format/sprint must match the fields.' Enabled: true -Lint/HandleExceptions: +Lint/SuppressedException: Description: "Don't suppress exception." StyleGuide: '#dont-hide-exceptions' Enabled: true @@ -567,7 +567,7 @@ Lint/MissingCopEnableDirective: Description: 'Checks for a `# rubocop:enable` after `# rubocop:disable`' Enabled: true -Lint/MultipleCompare: +Lint/MultipleComparison: Description: "Use `&&` operator to compare multiple value." Enabled: true @@ -674,15 +674,11 @@ Lint/ShadowingOuterLocalVariable: for block arguments or block local variables. Enabled: true -Lint/StringConversionInInterpolation: +Lint/RedundantStringCoercion: Description: 'Checks for Object#to_s usage in string interpolation.' StyleGuide: '#no-to-s' Enabled: true -Lint/Syntax: - Description: 'Checks syntax error' - Enabled: true - Lint/UnderscorePrefixedVariableName: Description: 'Do not use prefix `_` for a variable that is used.' Enabled: true @@ -703,11 +699,11 @@ Lint/UnifiedInteger: # # Enabled: true -Lint/UnneededRequireStatement: +Lint/RedundantRequireStatement: Description: 'Checks for unnecessary `require` statement.' Enabled: true -Lint/UnneededSplatExpansion: +Lint/RedundantSplatExpansion: Description: 'Checks for splat unnecessarily being called on literals' Enabled: true @@ -750,7 +746,7 @@ Lint/UselessAssignment: StyleGuide: '#underscore-unused-vars' Enabled: true -Lint/UselessComparison: +Lint/BinaryOperatorWithIdenticalOperands: Description: 'Checks for comparison of something with itself.' Enabled: true @@ -794,7 +790,7 @@ Metrics/CyclomaticComplexity: of test cases needed to validate a method. Enabled: true -Metrics/LineLength: +Layout/LineLength: Description: 'Limit lines to 80 characters.' StyleGuide: '#80-character-limits' Enabled: true @@ -923,8 +919,8 @@ Performance/Count: # This cop has known compatibility issues with `ActiveRecord` and other # frameworks. ActiveRecord's `count` ignores the block that is passed to it. # For more information, see the documentation in the cop itself. - # If you understand the known risk, you can disable `SafeMode`. - SafeMode: true + # If you understand the known risk, you can disable `SafeAutoCorrect`. + SafeAutoCorrect: true Enabled: true Performance/Detect: @@ -936,7 +932,7 @@ Performance/Detect: # frameworks. `ActiveRecord` does not implement a `detect` method and `find` # has its own meaning. Correcting `ActiveRecord` methods with this cop # should be considered unsafe. - SafeMode: true + SafeAutoCorrect: true Enabled: true Performance/DoubleStartEndWith: @@ -971,7 +967,7 @@ Performance/FlatMap: # This can be dangerous since `flat_map` will only flatten 1 level, and # `flatten` without any parameters can flatten multiple levels. -Performance/HashEachMethods: +Style/HashEachMethods: Description: >- Use `Hash#each_key` and `Hash#each_value` instead of `Hash#keys.each` and `Hash#values.each`. @@ -979,10 +975,6 @@ Performance/HashEachMethods: Enabled: true AutoCorrect: false -Performance/LstripRstrip: - Description: 'Use `strip` instead of `lstrip.rstrip`.' - Enabled: true - Performance/RangeInclude: Description: 'Use `Range#cover?` instead of `Range#include?`.' Reference: 'https://github.com/JuanitoFatas/fast-ruby#cover-vs-include-code' @@ -1004,7 +996,7 @@ Performance/RedundantMerge: Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashmerge-vs-hash-code' Enabled: true -Performance/RedundantSortBy: +Style/RedundantSortBy: Description: 'Use `sort` instead of `sort_by { |x| x }`.' Enabled: true @@ -1019,7 +1011,7 @@ Performance/ReverseEach: Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code' Enabled: true -Performance/Sample: +Style/Sample: Description: >- Use `sample` instead of `shuffle.first`, `shuffle.last`, and `shuffle[Integer]`. @@ -1063,205 +1055,6 @@ Performance/UriDefaultParser: Description: 'Use `URI::DEFAULT_PARSER` instead of `URI::Parser.new`.' Enabled: true -#################### Rails ################################# - -Rails/ActionFilter: - Description: 'Enforces consistent use of action filter methods.' - Enabled: true - -Rails/ActiveSupportAliases: - Description: >- - Avoid ActiveSupport aliases of standard ruby methods: - `String#starts_with?`, `String#ends_with?`, - `Array#append`, `Array#prepend`. - Enabled: true - -Rails/ApplicationJob: - Description: 'Check that jobs subclass ApplicationJob.' - Enabled: true - -Rails/ApplicationRecord: - Description: 'Check that models subclass ApplicationRecord.' - Enabled: true - -Rails/Blank: - Description: 'Enforce using `blank?` and `present?`.' - Enabled: true - # Convert checks for `nil` or `empty?` to `blank?` - NilOrEmpty: true - # Convert usages of not `present?` to `blank?` - NotPresent: true - # Convert usages of `unless` `present?` to `if` `blank?` - UnlessPresent: true - -Rails/CreateTableWithTimestamps: - Description: >- - Checks the migration for which timestamps are not included - when creating a new table. - Enabled: true - -Rails/Date: - Description: >- - Checks the correct usage of date aware methods, - such as Date.today, Date.current etc. - Enabled: true - -Rails/Delegate: - Description: 'Prefer delegate method for delegations.' - Enabled: true - -Rails/DelegateAllowBlank: - Description: 'Do not use allow_blank as an option to delegate.' - Enabled: true - -Rails/DynamicFindBy: - Description: 'Use `find_by` instead of dynamic `find_by_*`.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#find_by' - Enabled: true - -Rails/EnumUniqueness: - Description: 'Avoid duplicate integers in hash-syntax `enum` declaration.' - Enabled: true - -Rails/EnvironmentComparison: - Description: "Favor `Rails.env.production?` over `Rails.env == 'production'`" - Enabled: true - -Rails/Exit: - Description: >- - Favor `fail`, `break`, `return`, etc. over `exit` in - application or library code outside of Rake files to avoid - exits during unit testing or running in production. - Enabled: true - -Rails/FilePath: - Description: 'Use `Rails.root.join` for file path joining.' - Enabled: true - -Rails/FindBy: - Description: 'Prefer find_by over where.first.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#find_by' - Enabled: true - -Rails/FindEach: - Description: 'Prefer all.find_each over all.find.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#find-each' - Enabled: true - -Rails/HasAndBelongsToMany: - Description: 'Prefer has_many :through to has_and_belongs_to_many.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#has-many-through' - Enabled: true - -Rails/HasManyOrHasOneDependent: - Description: 'Define the dependent option to the has_many and has_one associations.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#has_many-has_one-dependent-option' - Enabled: true - -Rails/HttpPositionalArguments: - Description: 'Use keyword arguments instead of positional arguments in http method calls.' - Enabled: true - Include: - - 'spec/**/*' - - 'test/**/*' - -Rails/InverseOf: - Description: 'Checks for associations where the inverse cannot be determined automatically.' - Enabled: true - -Rails/LexicallyScopedActionFilter: - Description: "Checks that methods specified in the filter's `only` or `except` options are explicitly defined in the controller." - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#lexically-scoped-action-filter' - Enabled: true - -Rails/NotNullColumn: - Description: 'Do not add a NOT NULL column without a default value' - Enabled: true - -Rails/Output: - Description: 'Checks for calls to puts, print, etc.' - Enabled: true - -Rails/OutputSafety: - Description: 'The use of `html_safe` or `raw` may be a security risk.' - Enabled: true - -Rails/PluralizationGrammar: - Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.' - Enabled: true - -Rails/Presence: - Description: 'Checks code that can be written more easily using `Object#presence` defined by Active Support.' - Enabled: true - -Rails/Present: - Description: 'Enforce using `blank?` and `present?`.' - Enabled: true - NotNilAndNotEmpty: true - # Convert checks for not `nil` and not `empty?` to `present?` - NotBlank: true - # Convert usages of not `blank?` to `present?` - UnlessBlank: true - # Convert usages of `unless` `blank?` to `if` `present?` - -Rails/ReadWriteAttribute: - Description: >- - Checks for read_attribute(:attr) and - write_attribute(:attr, val). - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#read-attribute' - Enabled: true - -Rails/RedundantReceiverInWithOptions: - Description: 'Checks for redundant receiver in `with_options`.' - Enabled: true - -Rails/RelativeDateConstant: - Description: 'Do not assign relative date to constants.' - Enabled: true - -Rails/RequestReferer: - Description: 'Use consistent syntax for request.referer.' - Enabled: true - -Rails/ReversibleMigration: - Description: 'Checks whether the change method of the migration file is reversible.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#reversible-migration' - Reference: 'http://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html' - Enabled: true - -Rails/SafeNavigation: - Description: "Use Ruby's safe navigation operator (`&.`) instead of `try!`" - Enabled: true - -Rails/ScopeArgs: - Description: 'Checks the arguments of ActiveRecord scopes.' - Enabled: true - -Rails/SkipsModelValidations: - Description: >- - Use methods that skips model validations with caution. - See reference for more information. - Reference: 'http://guides.rubyonrails.org/active_record_validations.html#skipping-validations' - Enabled: true - -Rails/TimeZone: - Description: 'Checks the correct usage of time zone aware methods.' - StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time' - Reference: 'http://danilenko.org/2012/7/6/rails_timezones' - Enabled: true - -Rails/UniqBeforePluck: - Description: 'Prefer the use of uniq or distinct before pluck.' - Enabled: true - -Rails/UnknownEnv: - Description: 'Use correct environment name.' - Enabled: true - -Rails/Validation: - Description: 'Use validates :attribute, hash of validations.' - Enabled: true - #################### Security ############################## Security/Eval: @@ -1346,10 +1139,6 @@ Style/BlockDelimiters: StyleGuide: '#single-line-blocks' Enabled: true -Style/BracesAroundHashParameters: - Description: 'Enforce braces style around hash parameters.' - Enabled: true - Style/CaseEquality: Description: 'Avoid explicit use of the case equality operator(===).' StyleGuide: '#no-case-equality' @@ -1497,7 +1286,7 @@ Style/EvenOdd: # Description: "Use `expand_path(__dir__)` instead of `expand_path('..', __FILE__)`." # Enabled: true -Style/FlipFlop: +Lint/FlipFlop: Description: 'Checks for flip flops' StyleGuide: '#no-flip-flops' Enabled: true @@ -1607,7 +1396,12 @@ Style/MethodDefParentheses: StyleGuide: '#method-parens' Enabled: true -Style/MethodMissing: +Lint/MissingSuper: + Description: 'Avoid using `method_missing`.' + StyleGuide: '#no-method-missing' + Enabled: true + +Style/MissingRespondToMissing: Description: 'Avoid using `method_missing`.' StyleGuide: '#no-method-missing' Enabled: true @@ -1975,15 +1769,15 @@ Style/UnlessElse: StyleGuide: '#no-else-with-unless' Enabled: true -Style/UnneededCapitalW: +Style/RedundantCapitalW: Description: 'Checks for %W when interpolation is not needed.' Enabled: true -Style/UnneededInterpolation: +Style/RedundantInterpolation: Description: 'Checks for strings that are just an interpolated expression.' Enabled: true -Style/UnneededPercentQ: +Style/RedundantPercentQ: Description: 'Checks for %q/%Q when single quotes or double quotes would do.' StyleGuide: '#percent-q' Enabled: true diff --git a/.rubocop.yml b/.rubocop.yml index 5190c275..49e8b479 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -17,7 +17,7 @@ AllCops: - 'pkg/**/*' - 'reports/**/*' - 'tmp/**/*' - TargetRubyVersion: 2.5.0 + TargetRubyVersion: 2.7.0 #################### Layout ########################### @@ -25,8 +25,11 @@ AllCops: Layout/AccessModifierIndentation: EnforcedStyle: indent +Layout/ArgumentAlignment: + EnforcedStyle: with_fixed_indentation + # Align the elements of a hash literal if they span more than one line. -Layout/AlignHash: +Layout/HashAlignment: # Alignment of entries using colon as separator. Valid values are: # # key - left alignment of keys @@ -72,7 +75,7 @@ Layout/AlignHash: # b: 2) EnforcedLastArgumentHashStyle: ignore_implicit -Layout/AlignParameters: +Layout/ParameterAlignment: # Alignment of parameters in multi-line method calls. # # The `with_first_parameter` style aligns the following lines along the same @@ -166,7 +169,7 @@ Layout/FirstParameterIndentation: # # Same as `special_for_inner_method_call` except that the special rule only # # applies if the outer method call encloses its arguments in parentheses. # - special_for_inner_method_call_in_parentheses - EnforcedStyle: special_for_inner_method_call_in_parentheses + EnforcedStyle: consistent Layout/IndentationConsistency: # The difference between `rails` and `normal` is that the `rails` style @@ -183,7 +186,7 @@ Layout/IndentationWidth: IgnoredPatterns: [] # Checks the indentation of the first element in an array literal. -Layout/IndentArray: +Layout/FirstArrayElementIndentation: # The value `special_inside_parentheses` means that array literals with # brackets that have their opening bracket on the same line as a surrounding # opening round parenthesis, shall have their first element indented relative @@ -205,13 +208,13 @@ Layout/IndentArray: IndentationWidth: ~ # Checks the indentation of assignment RHS, when on a different line from LHS -Layout/IndentAssignment: +Layout/AssignmentIndentation: # By default, the indentation width from `Layout/IndentationWidth` is used # But it can be overridden by setting this parameter IndentationWidth: ~ # Checks the indentation of the first key in a hash literal. -Layout/IndentHash: +Layout/FirstHashElementIndentation: # The value `special_inside_parentheses` means that hash literals with braces # that have their opening brace on the same line as a surrounding opening # round parenthesis, shall have their first key indented relative to the @@ -232,7 +235,7 @@ Layout/IndentHash: # But it can be overridden by setting this parameter IndentationWidth: ~ -Layout/IndentHeredoc: +Layout/HeredocIndentation: EnforcedStyle: auto_detection SupportedStyles: - auto_detection @@ -427,14 +430,14 @@ Layout/ClassStructure: - protected_methods - private_methods -Layout/Tab: +Layout/IndentationStyle: # By default, the indentation width from Layout/IndentationWidth is used # But it can be overridden by setting this parameter # It is used during auto-correction to determine how many spaces should # replace each tab. IndentationWidth: ~ -Layout/TrailingBlankLines: +Layout/TrailingEmptyLines: EnforcedStyle: final_newline SupportedStyles: - final_newline @@ -504,7 +507,7 @@ Naming/FileName: - XSS Naming/HeredocDelimiterNaming: - Blacklist: + ForbiddenDelimiters: - END - !ruby/regexp '/EO[A-Z]{1}/' @@ -527,13 +530,13 @@ Naming/PredicateName: - has_ - have_ # Predicate name prefixes that should be removed. - NamePrefixBlacklist: + ForbiddenPrefixes: - is_ - has_ - have_ # Predicate names which, despite having a blacklisted prefix, or no `?`, # should still be accepted - NameWhitelist: + AllowedMethods: - is_a? # Method definition macros for dynamically generated methods. MethodDefinitionMacros: @@ -548,20 +551,16 @@ Naming/PredicateName: # # Parameter names may be equal to or greater than this value # MinNameLength: 1 # AllowNamesEndingInNumbers: true -# # Whitelisted names that will not register an offense # AllowedNames: [] -# # Blacklisted names that will register an offense # ForbiddenNames: [] # # Naming/UncommunicativeMethodParamName: # # Parameter names may be equal to or greater than this value # MinNameLength: 3 # AllowNamesEndingInNumbers: true -# # Whitelisted names that will not register an offense # AllowedNames: # - io # - id -# # Blacklisted names that will register an offense # ForbiddenNames: [] Naming/VariableName: @@ -676,20 +675,6 @@ Style/BlockDelimiters: - proc - it -Style/BracesAroundHashParameters: - EnforcedStyle: context_dependent - SupportedStyles: - # The `braces` style enforces braces around all method parameters that are - # hashes. - - braces - # The `no_braces` style checks that the last parameter doesn't have braces - # around it. - - no_braces - # The `context_dependent` style checks that the last parameter doesn't have - # braces around it, but requires braces if the second to last parameter is - # also a hash literal. - - context_dependent - Style/ClassAndModuleChildren: # Checks the style of children definitions at classes and modules. # @@ -817,6 +802,10 @@ Style/EmptyMethod: - compact - expanded +# Disable explicit block argument as it has a significant effect on performance +Style/ExplicitBlockArgument: + Enabled: false + # Checks use of for or each in multiline loops. Style/For: EnforcedStyle: each @@ -844,19 +833,7 @@ Style/FormatStringToken: - unannotated Style/FrozenStringLiteralComment: - EnforcedStyle: when_needed - SupportedStyles: - # `when_needed` will add the frozen string literal comment to files - # only when the `TargetRubyVersion` is set to 2.3+. - - when_needed - # `always` will always add the frozen string literal comment to a file - # regardless of the Ruby version or if `freeze` or `<<` are called on a - # string literal. If you run code against multiple versions of Ruby, it is - # possible that this will create errors in Ruby 2.3.0+. - - always - # `never` will enforce that the frozen string literal comment does not - # exist in a file. - - never + EnforcedStyle: always_true # Built-in global variables are allowed by default. Style/GlobalVars: @@ -1188,7 +1165,18 @@ Style/TrailingCommaInArguments: # for all parenthesized method calls with arguments. EnforcedStyleForMultiline: comma -Style/TrailingCommaInLiteral: +Style/TrailingCommaInArrayLiteral: +# # SupportedStylesForMultiline: +# # - comma +# # - consistent_comma +# # - no_comma +# # If `comma`, the cop requires a comma after the last item in an array, +# # but only when each item is on its own line. +# # If `consistent_comma`, the cop requires a comma after the last item of all +# # non-empty array literals. + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInHashLiteral: # # SupportedStylesForMultiline: # # - comma # # - consistent_comma @@ -1244,7 +1232,7 @@ Style/TrivialAccessors: # Commonly used in DSLs AllowDSLWriters: false IgnoreClassMethods: false - Whitelist: + AllowedMethods: - to_ary - to_a - to_c @@ -1281,19 +1269,14 @@ Style/WordArray: WordRegex: !ruby/regexp '/\A[\p{Word}\n\t]+\z/' Style/YodaCondition: - EnforcedStyle: all_comparison_operators - SupportedStyles: - # check all comparison operators - - all_comparison_operators - # check only equality operators: `!=` and `==` - - equality_operators_only + EnforcedStyle: require_for_all_comparison_operators #################### Metrics ############################### Metrics/AbcSize: # The ABC size is a calculated magnitude, so this number can be an Integer or # a Float. - Max: 15 + Max: 20 Exclude: - 'tasks/*.rb' @@ -1320,7 +1303,7 @@ Metrics/ClassLength: Metrics/CyclomaticComplexity: Max: 6 -Metrics/LineLength: +Layout/LineLength: Max: 80 # To make it possible to copy or click on URIs in the code, we allow lines # containing a URI to be longer than Max. @@ -1359,7 +1342,7 @@ Lint/AssignmentInCondition: AllowSafeAssignment: true # checks whether the end keywords are aligned properly for `do` `end` blocks. -Lint/BlockAlignment: +Layout/BlockAlignment: # The value `start_of_block` means that the `end` should be aligned with line # where the `do` keyword appears. # The value `start_of_line` means it should be aligned with the whole @@ -1367,7 +1350,7 @@ Lint/BlockAlignment: # The value `either` means both are allowed. EnforcedStyleAlignWith: start_of_line -Lint/DefEndAlignment: +Layout/DefEndAlignment: # The value `def` means that `end` should be aligned with the def keyword. # The value `start_of_line` means that `end` should be aligned with method # calls like `private`, `public`, etc, if present in front of the `def` @@ -1377,7 +1360,7 @@ Lint/DefEndAlignment: Severity: warning # Align ends correctly. -Lint/EndAlignment: +Layout/EndAlignment: # The value `keyword` means that `end` should be aligned with the matching # keyword (`if`, `while`, etc.). # The value `variable` means that in assignments, `end` should be aligned @@ -1389,7 +1372,7 @@ Lint/EndAlignment: # AutoCorrect: false Severity: warning -Lint/HandleExceptions: +Lint/SuppressedException: Exclude: - 'spec/**/*' @@ -1411,7 +1394,7 @@ Lint/MissingCopEnableDirective: MaximumRangeSize: .inf Lint/SafeNavigationChain: - Whitelist: + AllowedMethods: - present? - blank? - presence @@ -1434,6 +1417,14 @@ Lint/UnusedMethodArgument: # Lint/Void: # CheckForMethodsWithNoSideEffects: false +#################### RSpec ################################# + +RSpec/MultipleMemoizedHelpers: + Max: 10 + +RSpec/NestedGroups: + Max: 5 + #################### Performance ########################### Performance/DoubleStartEndWith: @@ -1445,152 +1436,6 @@ Performance/RedundantMerge: # Max number of key-value pairs to consider an offense MaxKeyValuePairs: 2 -#################### Rails ################################# - -Rails/ActionFilter: - EnforcedStyle: action - SupportedStyles: - - action - - filter - Include: - - app/controllers/**/*.rb - -Rails/CreateTableWithTimestamps: - Include: - - db/migrate/*.rb - -Rails/Date: - # The value `strict` disallows usage of `Date.today`, `Date.current`, - # `Date#to_time` etc. - # The value `flexible` allows usage of `Date.current`, `Date.yesterday`, etc - # (but not `Date.today`) which are overridden by ActiveSupport to handle current - # time zone. - EnforcedStyle: flexible - SupportedStyles: - - strict - - flexible - -Rails/Delegate: - # When set to true, using the target object as a prefix of the - # method name without using the `delegate` method will be a - # violation. When set to false, this case is legal. - EnforceForPrefixed: true - -Rails/DynamicFindBy: - Whitelist: - - find_by_sql - -Rails/EnumUniqueness: - Include: - - app/models/**/*.rb - -Rails/Exit: - Include: - - app/**/*.rb - - config/**/*.rb - - lib/**/*.rb - Exclude: - - lib/**/*.rake - -Rails/FindBy: - Include: - - app/models/**/*.rb - -Rails/FindEach: - Include: - - app/models/**/*.rb - -Rails/HasAndBelongsToMany: - Include: - - app/models/**/*.rb - -Rails/HasManyOrHasOneDependent: - Include: - - app/models/**/*.rb - -Rails/InverseOf: - Include: - - app/models/**/*.rb - -Rails/LexicallyScopedActionFilter: - Include: - - app/controllers/**/*.rb - -Rails/NotNullColumn: - Include: - - db/migrate/*.rb - -Rails/Output: - Include: - - app/**/*.rb - - config/**/*.rb - - db/**/*.rb - - lib/**/*.rb - -Rails/ReadWriteAttribute: - Include: - - app/models/**/*.rb - -Rails/RequestReferer: - EnforcedStyle: referer - SupportedStyles: - - referer - - referrer - -Rails/ReversibleMigration: - Include: - - db/migrate/*.rb - -Rails/SafeNavigation: - # This will convert usages of `try` to use safe navigation as well as `try!`. - # `try` and `try!` work slightly differently. `try!` and safe navigation will - # both raise a `NoMethodError` if the receiver of the method call does not - # implement the intended method. `try` will not raise an exception for this. - ConvertTry: false - -Rails/ScopeArgs: - Include: - - app/models/**/*.rb - -Rails/TimeZone: - # The value `strict` means that `Time` should be used with `zone`. - # The value `flexible` allows usage of `in_time_zone` instead of `zone`. - EnforcedStyle: flexible - SupportedStyles: - - strict - - flexible - -Rails/UniqBeforePluck: - EnforcedStyle: conservative - SupportedStyles: - - conservative - - aggressive - AutoCorrect: false - -Rails/UnknownEnv: - Environments: - - development - - test - - production - -Rails/SkipsModelValidations: - Blacklist: - - decrement! - - decrement_counter - - increment! - - increment_counter - - toggle! - - touch - - update_all - - update_attribute - - update_column - - update_columns - - update_counters - -Rails/Validation: - Include: - - app/models/**/*.rb - Bundler/OrderedGems: TreatCommentsAsGroupSeparators: true diff --git a/Gemfile b/Gemfile index 1c5bad23..f37dc915 100644 --- a/Gemfile +++ b/Gemfile @@ -17,11 +17,14 @@ end group :test do gem 'coveralls_reborn', '~> 0.27.0', require: false - gem 'simplecov', require: false gem 'rspec_junit_formatter' + gem 'simplecov', require: false end group :local do gem 'guard-rspec' gem 'rubocop', require: false + gem 'rubocop-performance', require: false + gem 'rubocop-rake', require: false + gem 'rubocop-rspec', require: false end diff --git a/lib/rambling/trie/compressible.rb b/lib/rambling/trie/compressible.rb index 2b3faa43..d685a7e4 100644 --- a/lib/rambling/trie/compressible.rb +++ b/lib/rambling/trie/compressible.rb @@ -9,7 +9,7 @@ module Compressible # @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes # with one child, `false` otherwise. def compressible? - !(root? || terminal?) && children_tree.size == 1 + !(root? || terminal?) && 1 == children_tree.size end end end diff --git a/lib/rambling/trie/container.rb b/lib/rambling/trie/container.rb index 0ed9c8e4..d38801fb 100644 --- a/lib/rambling/trie/container.rb +++ b/lib/rambling/trie/container.rb @@ -59,6 +59,7 @@ def compress! # compressed. def compress return self if root.compressed? + Rambling::Trie::Container.new compress_root, compressor end diff --git a/lib/rambling/trie/nodes/node.rb b/lib/rambling/trie/nodes/node.rb index 43e40db3..c528dbac 100644 --- a/lib/rambling/trie/nodes/node.rb +++ b/lib/rambling/trie/nodes/node.rb @@ -51,9 +51,9 @@ def children def first_child return if children_tree.empty? - children_tree.each_value do |child| - return child - end + # rubocop:disable Lint/UnreachableLoop + children_tree.each_value { |child| return child } + # rubocop:enable Lint/UnreachableLoop end # Indicates if the current node is the root node. diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 2b35572b..b1e710be 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -1,6 +1,6 @@ # frozen_string_literal: true -$LOAD_PATH.push File.expand_path('../lib', __FILE__) +$LOAD_PATH.push File.expand_path('lib', __dir__) require 'rambling/trie/version' Gem::Specification.new do |gem| diff --git a/spec/integration/rambling/trie_spec.rb b/spec/integration/rambling/trie_spec.rb index 4fe58bf6..7b162f5f 100644 --- a/spec/integration/rambling/trie_spec.rb +++ b/spec/integration/rambling/trie_spec.rb @@ -8,30 +8,26 @@ context 'when providing words directly' do it_behaves_like 'a compressible trie' do - let(:trie) { Rambling::Trie.create } + let(:trie) { described_class.create } let(:words) { %w(a couple of words for our full trie integration test) } - before do - trie.concat words - end + before { trie.concat words } end end context 'when provided with words with unicode characters' do it_behaves_like 'a compressible trie' do - let(:trie) { Rambling::Trie.create } + let(:trie) { described_class.create } let(:words) do %w(poquísimas palabras para nuestra prueba de integración completa 🙃) end - before do - trie.concat words - end + before { trie.concat words } end end context 'when provided with a filepath' do - let(:trie) { Rambling::Trie.create filepath } + let(:trie) { described_class.create filepath } let(:words) { File.readlines(filepath).map(&:chomp) } context 'with english words' do @@ -53,33 +49,34 @@ context 'when serialized with Ruby marshal format (default)' do it_behaves_like 'a serializable trie' do - let(:trie_to_serialize) { Rambling::Trie.create words_filepath } + let(:trie_to_serialize) { described_class.create words_filepath } let(:format) { :marshal } end end context 'when serialized with YAML' do it_behaves_like 'a serializable trie' do - let(:trie_to_serialize) { Rambling::Trie.create words_filepath } + let(:trie_to_serialize) { described_class.create words_filepath } let(:format) { :yml } end end context 'when serialized with zipped Ruby marshal format' do + let!(:original_on_exists_proc) { ::Zip.on_exists_proc } + let!(:original_continue_on_exists_proc) { ::Zip.continue_on_exists_proc } + before do - @original_on_exists_proc = ::Zip.on_exists_proc - @original_continue_on_exists_proc = ::Zip.continue_on_exists_proc ::Zip.on_exists_proc = true ::Zip.continue_on_exists_proc = true end after do - ::Zip.on_exists_proc = @original_on_exists_proc - ::Zip.continue_on_exists_proc = @original_continue_on_exists_proc + ::Zip.on_exists_proc = original_on_exists_proc + ::Zip.continue_on_exists_proc = original_continue_on_exists_proc end it_behaves_like 'a serializable trie' do - let(:trie_to_serialize) { Rambling::Trie.create words_filepath } + let(:trie_to_serialize) { described_class.create words_filepath } let(:format) { 'marshal.zip' } end end diff --git a/spec/lib/rambling/trie/comparable_spec.rb b/spec/lib/rambling/trie/comparable_spec.rb index f205c243..93e4d58e 100644 --- a/spec/lib/rambling/trie/comparable_spec.rb +++ b/spec/lib/rambling/trie/comparable_spec.rb @@ -4,93 +4,83 @@ describe Rambling::Trie::Comparable do describe '#==' do - let(:node_1) { Rambling::Trie::Nodes::Raw.new } - let(:node_2) { Rambling::Trie::Nodes::Raw.new } + let(:node_one) { Rambling::Trie::Nodes::Raw.new } + let(:node_two) { Rambling::Trie::Nodes::Raw.new } context 'when the nodes do not have the same letter' do before do - node_1.letter = :a - node_2.letter = :b + node_one.letter = :a + node_two.letter = :b end it 'returns false' do - expect(node_1).not_to eq node_2 + expect(node_one).not_to eq node_two end end - context 'when the nodes have the same letter and no children' do + context 'when nodes have same letter, not terminal and no children' do before do - node_1.letter = :a - node_2.letter = :a + node_one.letter = :a + node_two.letter = :a end it 'returns true' do - expect(node_1).to eq node_2 + expect(node_one).to eq node_two end end context 'when the nodes have the same letter and are terminal' do before do - node_1.letter = :a - node_1.terminal! + node_one.letter = :a + node_one.terminal! - node_2.letter = :a - node_2.terminal! + node_two.letter = :a + node_two.terminal! end it 'returns true' do - expect(node_1).to eq node_2 - end - end - - context 'when the nodes have the same letter and are not terminal' do - before do - node_1.letter = :a - node_2.letter = :a - end - - it 'returns true' do - expect(node_1).to eq node_2 + expect(node_one).to eq node_two end end context 'when the nodes have the same letter but are not both terminal' do before do - node_1.letter = :a - node_1.terminal! + node_one.letter = :a + node_one.terminal! - node_2.letter = :a + node_two.letter = :a end + it 'returns false' do - expect(node_1).not_to eq node_2 + expect(node_one).not_to eq node_two end end context 'when the nodes have the same letter and the same children' do before do - node_1.letter = :t - add_words node_1, %w(hese hree hings) + node_one.letter = :t + add_words node_one, %w(hese hree hings) - node_2.letter = :t - add_words node_2, %w(hese hree hings) + node_two.letter = :t + add_words node_two, %w(hese hree hings) end it 'returns true' do - expect(node_1).to eq node_2 + expect(node_one).to eq node_two end end context 'when the nodes have the same letter but different children' do before do - node_1.letter = :t - add_words node_1, %w(hese wo) + node_one.letter = :t + add_words node_one, %w(hese wo) - node_2.letter = :t - add_words node_2, %w(hese hree hings) + node_two.letter = :t + add_words node_two, %w(hese hree hings) end it 'returns false' do - expect(node_1).not_to eq node_2 + expect(node_one).not_to eq node_two end end end diff --git a/spec/lib/rambling/trie/compressor_spec.rb b/spec/lib/rambling/trie/compressor_spec.rb index a8b213fa..79e7dbd5 100644 --- a/spec/lib/rambling/trie/compressor_spec.rb +++ b/spec/lib/rambling/trie/compressor_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Rambling::Trie::Compressor do - let(:compressor) { Rambling::Trie::Compressor.new } + let(:compressor) { described_class.new } describe '#compress' do let(:node) { Rambling::Trie::Nodes::Raw.new } @@ -16,9 +16,7 @@ end context 'with at least one word' do - before do - add_words node, %w(all the words) - end + before { add_words node, %w(all the words) } it 'keeps the node letter nil' do compressed = compressor.compress node @@ -28,25 +26,25 @@ end context 'with a single word' do - before do - add_word node, 'all' - end + before { add_word node, 'all' } + # rubocop:disable RSpec/ExampleLength, RSpec/MultipleExpectations it 'compresses into a single node without children' do compressed = compressor.compress node + compressed_node_a = compressed[:a] - expect(compressed[:a].letter).to eq :all - expect(compressed[:a].children.size).to eq 0 - expect(compressed[:a]).to be_terminal - expect(compressed[:a]).to be_compressed + expect(compressed_node_a.letter).to eq :all + expect(compressed_node_a.children.size).to eq 0 + expect(compressed_node_a).to be_terminal + expect(compressed_node_a).to be_compressed end + # rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations end context 'with two words' do - before do - add_words node, %w(all ask) - end + before { add_words node, %w(all ask) } + # rubocop:disable RSpec/ExampleLength, RSpec/MultipleExpectations it 'compresses into corresponding three nodes' do compressed = compressor.compress node @@ -65,8 +63,10 @@ expect(compressed[:a][:l]).to be_compressed expect(compressed[:a][:s]).to be_compressed end + # rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations end + # rubocop:disable RSpec/ExampleLength, RSpec/MultipleExpectations it 'reassigns the parent nodes correctly' do add_words node, %w(repay rest repaint) compressed = compressor.compress node @@ -91,7 +91,9 @@ expect(compressed[:r][:p][:i].parent).to eq compressed[:r][:p] expect(compressed[:r][:p][:i].children.size).to eq 0 end + # rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations + # rubocop:disable RSpec/ExampleLength, RSpec/MultipleExpectations it 'does not compress terminal nodes' do add_words node, %w(you your yours) compressed = compressor.compress node @@ -104,5 +106,6 @@ expect(compressed[:y][:r][:s].letter).to eq :s expect(compressed[:y][:r][:s]).to be_compressed end + # rubocop:enable RSpec/ExampleLength, RSpec/MultipleExpectations end end diff --git a/spec/lib/rambling/trie/configuration/properties_spec.rb b/spec/lib/rambling/trie/configuration/properties_spec.rb index 36dddccd..ace496c1 100644 --- a/spec/lib/rambling/trie/configuration/properties_spec.rb +++ b/spec/lib/rambling/trie/configuration/properties_spec.rb @@ -3,13 +3,17 @@ require 'spec_helper' describe Rambling::Trie::Configuration::Properties do - let(:properties) { Rambling::Trie::Configuration::Properties.new } + let(:properties) { described_class.new } describe '.new' do - it 'configures the serializers' do + it 'configures the serializer formats' do serializers = properties.serializers - expect(serializers.formats).to match_array %i(marshal yaml yml zip) + end + + # rubocop:disable RSpec/ExampleLength + it 'configures the serializer providers' do + serializers = properties.serializers expect(serializers.providers.to_a).to match_array [ [:marshal, Rambling::Trie::Serializers::Marshal], [:yaml, Rambling::Trie::Serializers::Yaml], @@ -17,11 +21,15 @@ [:zip, Rambling::Trie::Serializers::Zip], ] end + # rubocop:enable RSpec/ExampleLength - it 'configures the readers' do + it 'configures the reader formats' do readers = properties.readers - expect(readers.formats).to match_array %i(txt) + end + + it 'configures the reader providers' do + readers = properties.readers expect(readers.providers.to_a).to match_array [ [:txt, Rambling::Trie::Readers::PlainText], ] @@ -44,14 +52,24 @@ properties.readers.add :test, 'test' end - it 'resets the serializers and readers to initial values' do + # rubocop:disable RSpec/MultipleExpectations + it 'resets the serializers to initial values' do expect(properties.serializers.formats).to include :test - expect(properties.readers.formats).to include :test properties.reset expect(properties.serializers.formats).not_to include :test + end + # rubocop:enable RSpec/MultipleExpectations + + # rubocop:disable RSpec/MultipleExpectations + it 'resets the readers to initial values' do + expect(properties.readers.formats).to include :test + + properties.reset + expect(properties.readers.formats).not_to include :test end + # rubocop:enable RSpec/MultipleExpectations end end diff --git a/spec/lib/rambling/trie/configuration/provider_collection_spec.rb b/spec/lib/rambling/trie/configuration/provider_collection_spec.rb index 86f5c1fe..f725febc 100644 --- a/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +++ b/spec/lib/rambling/trie/configuration/provider_collection_spec.rb @@ -8,11 +8,15 @@ { one: first_provider, two: second_provider } end - let(:first_provider) { double :first_provider } - let(:second_provider) { double :second_provider } + let(:first_provider) do + instance_double 'Rambling::Trie::Serializers::Marshal', :first_provider + end + let(:second_provider) do + instance_double 'Rambling::Trie::Serializers::Marshal', :second_provider + end let(:provider_collection) do - Rambling::Trie::Configuration::ProviderCollection.new( + described_class.new( :provider, configured_providers, configured_default, @@ -46,25 +50,31 @@ let(:providers) { provider_collection.providers } before do - allow(providers) .to receive_messages( + allow(providers).to receive_messages( :[] => 'value', keys: %i(a b), ) end + # rubocop:disable RSpec/MultipleExpectations it 'delegates `#[]` to providers' do expect(provider_collection[:key]).to eq 'value' expect(providers).to have_received(:[]).with :key end + # rubocop:enable RSpec/MultipleExpectations + # rubocop:disable RSpec/MultipleExpectations it 'aliases `#formats` to `providers#keys`' do expect(provider_collection.formats).to eq %i(a b) expect(providers).to have_received :keys end + # rubocop:enable RSpec/MultipleExpectations end describe '#add' do - let(:provider) { double :provider } + let(:provider) do + instance_double 'Rambling::Trie::Serializers::Marshal', :provider + end before do provider_collection.add :three, provider @@ -76,7 +86,9 @@ end describe '#default=' do - let(:other_provider) { double :other_provider } + let(:other_provider) do + instance_double 'Rambling::Trie::Serializers::Marshal', :other_provider + end context 'when the given value is in the providers list' do it 'changes the default provider' do @@ -106,43 +118,59 @@ expect(provider_collection.default).to be_nil end + # rubocop:disable RSpec/MultipleExpectations it 'raises an ArgumentError for any other provider' do expect do provider_collection.default = other_provider end.to raise_error ArgumentError expect(provider_collection.default).to be_nil end + # rubocop:enable RSpec/MultipleExpectations end end describe '#resolve' do context 'when the file extension is one of the providers' do - it 'returns the corresponding provider' do - expect(provider_collection.resolve 'hola.one').to eq first_provider - expect(provider_collection.resolve 'hola.two').to eq second_provider + [ + ['hola.one', :first_provider], + ['hola.two', :second_provider], + ].each do |test_params| + filepath, provider = test_params + + it 'returns the corresponding provider' do + provider_instance = public_send provider + expect(provider_collection.resolve filepath).to eq provider_instance + end end end context 'when the file extension is not one of the providers' do - it 'returns the default provider' do - expect(provider_collection.resolve 'hola.unknown').to eq first_provider - expect(provider_collection.resolve 'hola').to eq first_provider + %w(hola.unknown hola).each do |filepath| + it 'returns the default provider' do + expect(provider_collection.resolve filepath).to eq first_provider + end end end end describe '#reset' do let(:configured_default) { second_provider } - let(:provider) { double :provider } + let(:provider) do + instance_double 'Rambling::Trie::Serializers::Marshal', :provider + end before do provider_collection.add :three, provider provider_collection.default = provider end - it 'resets to back to the initially configured values' do + it 'resets to back to the initially configured values (:three => nil)' do provider_collection.reset expect(provider_collection[:three]).to be_nil + end + + it 'resets to back to the initially configured default' do + provider_collection.reset expect(provider_collection.default).to eq second_provider end end diff --git a/spec/lib/rambling/trie/container_spec.rb b/spec/lib/rambling/trie/container_spec.rb index c43ff557..a7b288b0 100644 --- a/spec/lib/rambling/trie/container_spec.rb +++ b/spec/lib/rambling/trie/container_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' describe Rambling::Trie::Container do - let(:container) { Rambling::Trie::Container.new root, compressor } + subject(:container) { described_class.new root, compressor } + let(:compressor) { Rambling::Trie::Compressor.new } let(:root) { Rambling::Trie::Nodes::Raw.new } @@ -16,7 +17,7 @@ it 'yields the container' do yielded = nil - container = Rambling::Trie::Container.new root, compressor do |c| + container = described_class.new root, compressor do |c| yielded = c end @@ -26,15 +27,18 @@ end describe '#add' do + # rubocop:disable RSpec/MultipleExpectations it 'adds the word to the root node' do add_word container, 'hello' expect(root.children.size).to eq 1 expect(root.to_a).to eq %w(hello) end + # rubocop:enable RSpec/MultipleExpectations end describe '#concat' do + # rubocop:disable RSpec/MultipleExpectations it 'adds all the words to the root node' do container.concat %w(other words) @@ -48,42 +52,7 @@ expect(nodes.first.letter).to eq :o expect(nodes.last.letter).to eq :w end - end - - describe '#compress!' do - let(:node) { Rambling::Trie::Nodes::Compressed.new } - - before do - allow(compressor).to receive(:compress).and_return node - - add_word root, 'yes' - node[:yes] = Rambling::Trie::Nodes::Compressed.new - end - - it 'compresses the trie using the compressor' do - container.compress! - - expect(compressor).to have_received(:compress).with root - end - - it 'changes to the root returned by the compressor' do - container.compress! - - expect(container.root).not_to eq root - expect(container.root).to eq node - end - - it 'returns itself' do - expect(container.compress!).to eq container - end - - it 'does not compress multiple times' do - container.compress! - allow(node).to receive(:compressed?).and_return(true) - - container.compress! - expect(compressor).to have_received(:compress).once - end + # rubocop:enable RSpec/MultipleExpectations end describe '#compress' do @@ -102,12 +71,14 @@ expect(compressor).to have_received(:compress).with root end + # rubocop:disable RSpec/MultipleExpectations it 'returns a container with the new root' do new_container = container.compress expect(new_container.root).not_to eq root expect(new_container.root).to eq node end + # rubocop:enable RSpec/MultipleExpectations it 'returns a new container' do expect(container.compress).not_to eq container @@ -128,153 +99,53 @@ end end - describe '#word?' do - let(:root) do - double :root, - compressed?: compressed, - word?: nil - end + describe '#compress!' do + let(:node) { Rambling::Trie::Nodes::Compressed.new } - context 'for an uncompressed root' do - let(:compressed) { true } + context 'with a mocked result' do + before do + allow(compressor).to receive(:compress).and_return node - it 'calls the root with the word characters' do - container.word? 'words' - expect(root).to have_received(:word?).with %w(w o r d s) + add_word root, 'yes' + node[:yes] = Rambling::Trie::Nodes::Compressed.new end - end - context 'for a compressed root' do - let(:compressed) { false } + it 'compresses the trie using the compressor' do + container.compress! - it 'calls the root with the full word' do - container.word? 'words' - expect(root).to have_received(:word?).with %w(w o r d s) + expect(compressor).to have_received(:compress).with root end - end - end - - describe '#partial_word?' do - let(:root) do - double :root, - compressed?: compressed, - partial_word?: nil - end - context 'for an uncompressed root' do - let(:compressed) { true } + # rubocop:disable RSpec/MultipleExpectations + it 'changes to the root returned by the compressor' do + container.compress! - it 'calls the root with the word characters' do - container.partial_word? 'words' - expect(root).to have_received(:partial_word?).with %w(w o r d s) + expect(container.root).not_to eq root + expect(container.root).to eq node end - end - - context 'for a compressed root' do - let(:compressed) { false } + # rubocop:enable RSpec/MultipleExpectations - it 'calls the root with the word characters' do - container.partial_word? 'words' - expect(root).to have_received(:partial_word?).with %w(w o r d s) + it 'returns itself' do + expect(container.compress!).to eq container end - end - end - - describe 'delegates and aliases' do - before do - allow(root).to receive_messages( - :[] => nil, - add: nil, - as_word: nil, - children: nil, - children_tree: nil, - compressed?: nil, - each: nil, - key?: nil, - inspect: nil, - letter: nil, - parent: nil, - partial_word?: nil, - scan: nil, - size: nil, - to_s: nil, - word?: nil, - ) - end - - it 'aliases `#include?` to `#word?`' do - container.include? 'words' - expect(root).to have_received(:word?).with %w(w o r d s) - end - it 'aliases `#match?` to `#partial_word?`' do - container.match? 'words' - expect(root).to have_received(:partial_word?).with %w(w o r d s) - end - - it 'aliases `#words` to `#scan`' do - container.words 'hig' - expect(root).to have_received(:scan).with %w(h i g) - end - - it 'aliases `#<<` to `#add`' do - container << 'words' - expect(root).to have_received(:add).with %i(s d r o w) - end - - it 'delegates `#[]` to the root node' do - container[:yep] - expect(root).to have_received(:[]).with :yep - end - - it 'delegates `#children` to the root node' do - container.children - expect(root).to have_received :children - end - - it 'delegates `#children_tree` to the root node' do - container.children_tree - expect(root).to have_received :children_tree - end - - it 'delegates `#compressed?` to the root node' do - container.compressed? - expect(root).to have_received :compressed? - end - - it 'delegates `#key?` to the root node' do - container.key? :yup - expect(root).to have_received(:key?).with :yup - end - - it 'aliases `#has_key?` to `#key?`' do - container.has_key? :yup - expect(root).to have_received(:key?).with :yup - end - - it 'aliases `#has_letter?` to `#has_key?`' do - container.has_letter? :yup - expect(root).to have_received(:key?).with :yup - end - - it 'delegates `#inspect` to the root node' do - container.inspect - expect(root).to have_received :inspect - end + it 'does not compress multiple times' do + container.compress! + allow(node).to receive(:compressed?).and_return(true) - it 'delegates `#size` to the root node' do - container.size - expect(root).to have_received :size - end - end + container.compress! + expect(compressor).to have_received(:compress).once + end - describe '#compress!' do - it 'gets a new root from the compressor' do - container.compress! + # rubocop:disable RSpec/MultipleExpectations + it 'gets a new root from the compressor' do + container.compress! - expect(container.root).not_to be root - expect(container.root).to be_compressed - expect(root).not_to be_compressed + expect(container.root).not_to be root + expect(container.root).to be_compressed + expect(root).not_to be_compressed + end + # rubocop:enable RSpec/MultipleExpectations end it 'generates a new root with the words from the passed root' do @@ -283,9 +154,7 @@ add_words container, words container.compress! - words.each do |word| - expect(container).to include word - end + words.each { |word| expect(container).to include word } end describe 'and trying to add a word' do @@ -301,140 +170,92 @@ end describe '#word?' do - context 'word is contained' do - before do - add_words container, %w(hello high) - end + it_behaves_like 'a propagating node' do + let(:method) { :word? } + end - it 'matches the whole word' do - expect(container.word? 'hello').to be true - expect(container.word? 'high').to be true - end + context 'when word is contained' do + before { add_words container, %w(hello high) } - context 'and the root has been compressed' do - before do - container.compress! - end + it_behaves_like 'a matching container#word' - it 'matches the whole word' do - expect(container.word? 'hello').to be true - expect(container.word? 'high').to be true - end + context 'with compressed root' do + before { container.compress! } + + it_behaves_like 'a matching container#word' end end - context 'word is not contained' do - before do - add_word container, 'hello' - end + context 'when word is not contained' do + before { add_word container, 'hello' } - it 'does not match the whole word' do - expect(container.word? 'halt').to be false - expect(container.word? 'al').to be false - end + it_behaves_like 'a non-matching container#word' - context 'and the root has been compressed' do - before do - container.compress! - end + context 'with compressed root' do + before { container.compress! } - it 'does not match the whole word' do - expect(container.word? 'halt').to be false - expect(container.word? 'al').to be false - end + it_behaves_like 'a non-matching container#word' end end end describe '#partial_word?' do - context 'word is contained' do - before do - add_words container, %w(hello high) - end + context 'with underlying node' do - it 'matches part of the word' do - expect(container.partial_word? 'hell').to be true - expect(container.partial_word? 'hig').to be true + it_behaves_like 'a propagating node' do + let(:method) { :partial_word? } end + end - context 'and the root has been compressed' do - before do - container.compress! - end + context 'when word is contained' do + before { add_words container, %w(hello high) } - it 'matches part of the word' do - expect(container.partial_word? 'h').to be true - expect(container.partial_word? 'he').to be true - expect(container.partial_word? 'hell').to be true - expect(container.partial_word? 'hello').to be true - expect(container.partial_word? 'hi').to be true - expect(container.partial_word? 'hig').to be true - expect(container.partial_word? 'high').to be true - end - end - end + it_behaves_like 'a matching container#partial_word' - shared_examples_for 'a non matching tree' do - it 'does not match any part of the word' do - %w(ha hal al).each do |word| - expect(container.partial_word? word).to be false - end + context 'with compressed root' do + before { container.compress! } + + it_behaves_like 'a matching container#partial_word' end end - context 'word is not contained' do - before do - add_word container, 'hello' - end + context 'when word is not contained' do + before { add_word container, 'hello' } - context 'and the root is uncompressed' do - it_behaves_like 'a non matching tree' - end + it_behaves_like 'a non-matching container#partial_word' - context 'and the root has been compressed' do + context 'with compressed root' do before { container.compress! } - it_behaves_like 'a non matching tree' + it_behaves_like 'a non-matching container#partial_word' end end end describe '#scan' do - context 'words that match are not contained' do + context 'when words that match are contained' do before do add_words container, %w(hi hello high hell highlight histerical) end - it 'returns an array with the words that match' do - expect(container.scan 'hi').to eq %w(hi high highlight histerical) - expect(container.scan 'hig').to eq %w(high highlight) - end + it_behaves_like 'a matching container#scan' - context 'and the root has been compressed' do - before do - container.compress! - end + context 'with compressed root' do + before { container.compress! } - it 'returns an array with the words that match' do - expect(container.scan 'hi').to eq %w(hi high highlight histerical) - expect(container.scan 'hig').to eq %w(high highlight) - end + it_behaves_like 'a matching container#scan' end end - context 'words that match are not contained' do - before do - add_word container, 'hello' - end + context 'when words that match are not contained' do + before { add_word container, 'hello' } it 'returns an empty array' do expect(container.scan 'hi').to eq %w() end - context 'and the root has been compressed' do - before do - container.compress! - end + context 'with compressed root' do + before { container.compress! } it 'returns an empty array' do expect(container.scan 'hi').to eq %w() @@ -444,19 +265,15 @@ end describe '#words_within' do - before do - add_words container, %w(one word and other words) - end + before { add_words container, %w(one word and other words) } - context 'phrase does not contain any words' do + context 'when phrase does not contain any words' do it 'returns an empty array' do expect(container.words_within 'xyz').to match_array [] end - context 'and the node is compressed' do - before do - container.compress! - end + context 'with compressed node' do + before { container.compress! } it 'returns an empty array' do expect(container.words_within 'xyz').to match_array [] @@ -464,33 +281,23 @@ end end - context 'phrase contains one word at the start of the phrase' do - it 'returns an array with the word found in the phrase' do - expect(container.words_within 'word').to match_array %w(word) - expect(container.words_within 'wordxyz').to match_array %w(word) - end + context 'when phrase contains one word at the start of the phrase' do + it_behaves_like 'a matching container#words_within' - context 'and the node is compressed' do - before do - container.compress! - end + context 'with compressed node' do + before { container.compress! } - it 'returns an array with the word found in the phrase' do - expect(container.words_within 'word').to match_array %w(word) - expect(container.words_within 'wordxyz').to match_array %w(word) - end + it_behaves_like 'a matching container#words_within' end end - context 'phrase contains one word at the end of the phrase' do + context 'when phrase contains one word at the end of the phrase' do it 'returns an array with the word found in the phrase' do expect(container.words_within 'xyz word').to match_array %w(word) end - context 'and the node is compressed' do - before do - container.compress! - end + context 'with compressed node' do + before { container.compress! } it 'returns an array with the word found in the phrase' do expect(container.words_within 'xyz word').to match_array %w(word) @@ -498,48 +305,33 @@ end end - context 'phrase contains a few words' do - it 'returns an array with all words found in the phrase' do - expect(container.words_within 'xyzword otherzxyone') - .to match_array %w(word other one) - end + context 'when phrase contains a few words' do + it_behaves_like 'a non-matching container#words_within' - context 'and the node is compressed' do - before do - container.compress! - end + context 'with compressed node' do + before { container.compress! } - it 'returns an array with all words found in the phrase' do - expect(container.words_within 'xyzword otherzxyone') - .to match_array %w(word other one) - end + it_behaves_like 'a non-matching container#words_within' end end end describe '#words_within?' do - before do - add_words container, %w(one word and other words) - end + before { add_words container, %w(one word and other words) } - context 'phrase does not contain any words' do - it 'returns false' do - expect(container.words_within? 'xyz').to be false - end - end + it_behaves_like 'a matching container#words_within?' - context 'phrase contains any word' do - it 'returns true' do - expect(container.words_within? 'xyz words').to be true - expect(container.words_within? 'xyzone word').to be true - end + context 'with compressed node' do + before { container.compress! } + + it_behaves_like 'a matching container#words_within?' end end describe '#==' do context 'when the root nodes are the same' do let(:other_container) do - Rambling::Trie::Container.new container.root, compressor + described_class.new container.root, compressor end it 'returns true' do @@ -550,12 +342,10 @@ context 'when the root nodes are not the same' do let(:other_root) { Rambling::Trie::Nodes::Raw.new } let(:other_container) do - Rambling::Trie::Container.new other_root, compressor + described_class.new other_root, compressor end - before do - add_word other_container, 'hola' - end + before { add_word other_container, 'hola' } it 'returns false' do expect(container).not_to eq other_container @@ -564,9 +354,7 @@ end describe '#each' do - before do - add_words container, %w(yes no why) - end + before { add_words container, %w(yes no why) } it 'returns an enumerator when no block is given' do expect(container.each).to be_instance_of Enumerator @@ -578,9 +366,7 @@ end describe '#inspect' do - before do - add_words container, %w(a few words hello hell) - end + before { add_words container, %w(a few words hello hell) } it 'returns the container class name plus the root inspection' do expect(container.inspect).to eq one_line <<~CONTAINER @@ -590,4 +376,92 @@ CONTAINER end end + + describe 'delegates and aliases' do + before do + allow(root).to receive_messages( + :[] => nil, + add: nil, + as_word: nil, + children: nil, + children_tree: nil, + compressed?: nil, + each: nil, + key?: nil, + inspect: nil, + letter: nil, + parent: nil, + partial_word?: nil, + scan: nil, + size: nil, + to_s: nil, + word?: nil, + ) + end + + it 'aliases `#include?` to `#word?`' do + container.include? 'words' + expect(root).to have_received(:word?).with %w(w o r d s) + end + + it 'aliases `#match?` to `#partial_word?`' do + container.match? 'words' + expect(root).to have_received(:partial_word?).with %w(w o r d s) + end + + it 'aliases `#words` to `#scan`' do + container.words 'hig' + expect(root).to have_received(:scan).with %w(h i g) + end + + it 'aliases `#<<` to `#add`' do + container << 'words' + expect(root).to have_received(:add).with %i(s d r o w) + end + + it 'delegates `#[]` to the root node' do + container[:yep] + expect(root).to have_received(:[]).with :yep + end + + it 'delegates `#children` to the root node' do + container.children + expect(root).to have_received :children + end + + it 'delegates `#children_tree` to the root node' do + container.children_tree + expect(root).to have_received :children_tree + end + + it 'delegates `#compressed?` to the root node' do + container.compressed? + expect(root).to have_received :compressed? + end + + it 'delegates `#key?` to the root node' do + container.key? :yup + expect(root).to have_received(:key?).with :yup + end + + it 'aliases `#has_key?` to `#key?`' do + container.has_key? :yup + expect(root).to have_received(:key?).with :yup + end + + it 'aliases `#has_letter?` to `#has_key?`' do + container.has_letter? :yup + expect(root).to have_received(:key?).with :yup + end + + it 'delegates `#inspect` to the root node' do + container.inspect + expect(root).to have_received :inspect + end + + it 'delegates `#size` to the root node' do + container.size + expect(root).to have_received :size + end + end end diff --git a/spec/lib/rambling/trie/enumerable_spec.rb b/spec/lib/rambling/trie/enumerable_spec.rb index ce338e27..e8b4360e 100644 --- a/spec/lib/rambling/trie/enumerable_spec.rb +++ b/spec/lib/rambling/trie/enumerable_spec.rb @@ -8,22 +8,20 @@ module Trie let(:node) { Rambling::Trie::Nodes::Raw.new } let(:words) { %w(add some words and another word) } - before do - add_words node, words - end + before { add_words node, words } describe '#each' do it 'returns an enumerator' do expect(node.each).to be_a Enumerator end - it 'includes every word contained in the trie' do - node.each do |word| - expect(words).to include word - end - + it 'has the same word count as the trie' do expect(node.count).to eq words.count end + + it 'includes every word contained in the trie' do + node.each { |word| expect(words).to include word } + end end describe '#size' do @@ -32,9 +30,15 @@ module Trie end end - it 'includes the core Enumerable module' do + it 'includes #all? from the core Enumerable module' do expect(node.all? { |word| words.include? word }).to be true + end + + it 'includes #any? from the core Enumerable module' do expect(node.any? { |word| word.start_with? 's' }).to be true + end + + it 'includes #to_a from the core Enumerable module' do expect(node.to_a).to match_array words end end diff --git a/spec/lib/rambling/trie/inspectable_spec.rb b/spec/lib/rambling/trie/inspectable_spec.rb index fd5f0300..b380b163 100644 --- a/spec/lib/rambling/trie/inspectable_spec.rb +++ b/spec/lib/rambling/trie/inspectable_spec.rb @@ -13,19 +13,23 @@ let(:child) { node[:o] } let(:terminal_node) { node[:o][:n][:l][:y] } - it 'returns a pretty printed version of the node' do + it 'returns a pretty printed version of the parent node' do expect(node.inspect).to eq one_line <<~RAW # RAW + end + it 'returns a pretty printed version of the child node' do expect(child.inspect).to eq one_line <<~CHILD # CHILD + end + it 'returns a pretty printed version of the terminal node' do expect(terminal_node.inspect).to eq one_line <<~TERMINAL # COMPRESSED + end + it 'returns a pretty printed version of the compressed child node' do expect(compressed_child.inspect).to eq one_line <<~CHILD # #{expected})" do + expect(compressed_node[key].as_word).to eq expected + end end - it 'raise an error for non terminal nodes' do + it 'raises an error for non terminal nodes' do expect { compressed_node.as_word } .to raise_error Rambling::Trie::InvalidOperation end diff --git a/spec/lib/rambling/trie_spec.rb b/spec/lib/rambling/trie_spec.rb index 202ea69d..45879335 100644 --- a/spec/lib/rambling/trie_spec.rb +++ b/spec/lib/rambling/trie_spec.rb @@ -15,20 +15,22 @@ end it 'returns a new instance of the trie container' do - expect(Rambling::Trie.create).to eq container + expect(described_class.create).to eq container end context 'with a block' do it 'yields the new container' do yielded = nil - Rambling::Trie.create { |trie| yielded = trie } + described_class.create { |trie| yielded = trie } expect(yielded).to eq container end end context 'with a filepath' do let(:filepath) { 'a test filepath' } - let(:reader) { double :reader } + let(:reader) do + instance_double 'Rambling::Trie::Readers::PlainText', :reader + end let(:words) { %w(a couple of test words over here) } before do @@ -42,7 +44,7 @@ end it 'loads every word' do - Rambling::Trie.create filepath, reader + described_class.create filepath, reader words.each do |word| expect(container).to have_received(:<<).with word @@ -52,17 +54,23 @@ context 'without any reader' do let(:filepath) { 'a test filepath' } - let(:reader) { double :reader, each_word: nil } + let(:reader) do + instance_double( + 'Rambling::Trie::Readers::PlainText', + :reader, + each_word: nil, + ) + end before do - Rambling::Trie.config do |c| + described_class.config do |c| c.readers.add :default, reader c.readers.default = reader end end it 'defaults to a plain text reader' do - Rambling::Trie.create filepath, nil + described_class.create filepath, nil expect(reader).to have_received(:each_word).with filepath end @@ -70,29 +78,53 @@ end describe '.load' do + let(:filepath) { 'a path to a file' } let(:root) { Rambling::Trie::Nodes::Raw.new } let(:compressor) { Rambling::Trie::Compressor.new } let(:container) { Rambling::Trie::Container.new root, compressor } - let(:serializer) { double :serializer, load: root } - let(:filepath) { 'a path to a file' } + let(:serializer) do + instance_double( + 'Rambling::True::Serializers::File', + :serializer, + load: root, + ) + end it 'returns a new container with the loaded root node' do - trie = Rambling::Trie.load filepath, serializer + trie = described_class.load filepath, serializer expect(trie).to eq container end it 'uses the serializer to load the root node from the given filepath' do - Rambling::Trie.load filepath, serializer + described_class.load filepath, serializer expect(serializer).to have_received(:load).with filepath end context 'without a serializer' do - let(:marshal_serializer) { double :marshal_serializer, load: nil } - let(:default_serializer) { double :default_serializer, load: nil } - let(:yaml_serializer) { double :yaml_serializer, load: nil } + let(:marshal_serializer) do + instance_double( + 'Rambling::Trie::Serializers::Marshal', + :marshal_serializer, + load: nil, + ) + end + let(:default_serializer) do + instance_double( + 'Rambling::Trie::Serializers::File', + :default_serializer, + load: nil, + ) + end + let(:yaml_serializer) do + instance_double( + 'Rambling::Trie::Serializers::Yaml', + :yaml_serializer, + load: nil, + ) + end before do - Rambling::Trie.config do |c| + described_class.config do |c| c.serializers.add :default, default_serializer c.serializers.add :marshal, marshal_serializer c.serializers.add :yml, yaml_serializer @@ -102,18 +134,21 @@ end end - it 'determines the serializer based on the file extension' do - Rambling::Trie.load 'test.marshal' - expect(marshal_serializer).to have_received(:load).with 'test.marshal' + [ + ['.marshal', :marshal_serializer], + ['.yml', :yaml_serializer], + ['.yaml', :yaml_serializer], + ['', :default_serializer], + ].each do |test_params| + extension, serializer = test_params + filepath = "test#{extension}" - Rambling::Trie.load 'test.yml' - expect(yaml_serializer).to have_received(:load).with 'test.yml' + it "uses extension-based serializer (#{filepath} -> #{serializer})" do + serializer_instance = public_send serializer - Rambling::Trie.load 'test.yaml' - expect(yaml_serializer).to have_received(:load).with 'test.yaml' - - Rambling::Trie.load 'test' - expect(default_serializer).to have_received(:load).with 'test' + described_class.load filepath + expect(serializer_instance).to have_received(:load).with filepath + end end end @@ -121,7 +156,7 @@ it 'yields the new container' do yielded = nil - Rambling::Trie.load filepath, serializer do |trie| + described_class.load filepath, serializer do |trie| yielded = trie end @@ -132,16 +167,36 @@ describe '.dump' do let(:filename) { 'a trie' } - let(:root) { double :root } - let(:compressor) { double :compressor } + let(:root) { instance_double 'Rambling::Trie::Serializers::Marshal', :root } + let(:compressor) do + instance_double 'Rambling::Trie::Serializers::Marshal', :compressor + end let(:trie) { Rambling::Trie::Container.new root, compressor } - let(:marshal_serializer) { double :marshal_serializer, dump: nil } - let(:yaml_serializer) { double :yaml_serializer, dump: nil } - let(:default_serializer) { double :default_serializer, dump: nil } + let(:marshal_serializer) do + instance_double( + 'Rambling::Trie::Serializers::Marshal', + :marshal_serializer, + dump: nil, + ) + end + let(:yaml_serializer) do + instance_double( + 'Rambling::Trie::Serializers::Yaml', + :yaml_serializer, + dump: nil, + ) + end + let(:default_serializer) do + instance_double( + 'Rambling::Trie::Serializers::File', + :default_serializer, + dump: nil, + ) + end before do - Rambling::Trie.config do |c| + described_class.config do |c| c.serializers.add :default, default_serializer c.serializers.add :marshal, marshal_serializer c.serializers.add :yml, yaml_serializer @@ -151,32 +206,39 @@ end it 'uses the configured default serializer by default' do - Rambling::Trie.dump trie, filename + described_class.dump trie, filename expect(default_serializer).to have_received(:dump).with root, filename end context 'when provided with a format' do - it 'uses the corresponding serializer' do - Rambling::Trie.dump trie, "#{filename}.marshal" - expect(marshal_serializer).to have_received(:dump) - .with root, "#{filename}.marshal" - - Rambling::Trie.dump trie, "#{filename}.yml" - expect(yaml_serializer).to have_received(:dump) - .with root, "#{filename}.yml" + [ + ['.marshal', :marshal_serializer], + ['.yml', :yaml_serializer], + ['', :default_serializer], + ].each do |test_params| + extension, serializer = test_params + + it 'uses the corresponding serializer' do + filepath = "#{filename}#{extension}" + serializer_instance = public_send serializer + + described_class.dump trie, filepath + expect(serializer_instance).to have_received(:dump) + .with root, filepath + end end end end describe '.config' do it 'returns the properties' do - expect(Rambling::Trie.config).to eq Rambling::Trie.send :properties + expect(described_class.config).to eq described_class.send :properties end it 'yields the properties' do yielded = nil - Rambling::Trie.config { |c| yielded = c } - expect(yielded).to eq Rambling::Trie.send :properties + described_class.config { |c| yielded = c } + expect(yielded).to eq described_class.send :properties end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3cd5d364..6bcd7948 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -29,7 +29,8 @@ %w( a_compressible_trie a_serializable_trie a_serializer a_trie_data_structure - a_trie_node a_trie_node_implementation + a_trie_node a_trie_node_implementation a_container_scan a_container_word + a_container_partial_word a_container_words_within ).each do |name| require File.join('support', 'shared_examples', name) end diff --git a/spec/support/shared_examples/a_compressible_trie.rb b/spec/support/shared_examples/a_compressible_trie.rb index 02be510b..e8096591 100644 --- a/spec/support/shared_examples/a_compressible_trie.rb +++ b/spec/support/shared_examples/a_compressible_trie.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true shared_examples_for 'a compressible trie' do - context 'and the trie is not compressed' do + context 'with an uncompressed trie' do it_behaves_like 'a trie data structure' it 'does not alter the input' do @@ -16,7 +16,7 @@ end end - context 'and the trie is compressed' do + context 'with an compressed trie' do let!(:original_root) { trie.root } let!(:original_keys) { original_root.children_tree.keys } let!(:original_values) { original_root.children_tree.values } @@ -31,9 +31,15 @@ expect(trie).to be_compressed end - it 'leaves the original root intact' do + it 'leaves the original root keys intact' do expect(original_root.children_tree.keys).to eq original_keys + end + + it 'leaves the original trie keys intact' do expect(trie.children_tree.keys).to eq original_keys + end + + it 'leaves the original trie values intact' do expect(trie.children_tree.values).not_to eq original_values end end diff --git a/spec/support/shared_examples/a_container_partial_word.rb b/spec/support/shared_examples/a_container_partial_word.rb new file mode 100644 index 00000000..f23cd5db --- /dev/null +++ b/spec/support/shared_examples/a_container_partial_word.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +shared_examples_for 'a matching container#partial_word' do + %w(h he hell hello hi hig high).each do |prefix| + it 'matches part of the word' do + expect(container.partial_word? prefix).to be true + end + end +end + +shared_examples_for 'a non-matching container#partial_word' do + it 'does not match any part of the word' do + %w(ha hal al).each do |word| + expect(container.partial_word? word).to be false + end + end +end + diff --git a/spec/support/shared_examples/a_container_scan.rb b/spec/support/shared_examples/a_container_scan.rb new file mode 100644 index 00000000..73a97e56 --- /dev/null +++ b/spec/support/shared_examples/a_container_scan.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +shared_examples_for 'a matching container#scan' do + [ + ['hi', %w(hi high highlight histerical)], + ['hig', %w(high highlight)], + ].each do |test_params| + prefix, expected = test_params + + it "returns an array with the words that match '#{prefix}'" do + expect(container.scan prefix).to eq expected + end + end +end diff --git a/spec/support/shared_examples/a_container_word.rb b/spec/support/shared_examples/a_container_word.rb new file mode 100644 index 00000000..f0176869 --- /dev/null +++ b/spec/support/shared_examples/a_container_word.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +shared_examples_for 'a matching container#word' do + %w(hello high).each do |word| + it 'matches the whole word' do + expect(container.word? word).to be true + end + end +end + +shared_examples_for 'a non-matching container#word' do + %w(halt al).each do |word| + it 'does not match the whole word' do + expect(container.word? word).to be false + end + end +end + +shared_examples_for 'a propagating node' do + [ + [true, 'Rambling::Trie::Nodes::Compressed'], + [false, 'Rambling::Trie::Nodes::Raw'], + ].each do |test_params| + compressed_value, instance_double_class = test_params + + context "when root has compressed=#{compressed_value}" do + let(:root) do + instance_double( + instance_double_class, + :root, + compressed?: compressed_value, + word?: nil, + partial_word?: nil, + ) + end + + it 'calls the root with the word characters' do + container.public_send method, 'words' + expect(root).to have_received(method).with %w(w o r d s) + end + end + end + +end diff --git a/spec/support/shared_examples/a_container_words_within.rb b/spec/support/shared_examples/a_container_words_within.rb new file mode 100644 index 00000000..7b34f01a --- /dev/null +++ b/spec/support/shared_examples/a_container_words_within.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +shared_examples_for 'a matching container#words_within' do + [ + ['word', %w(word)], + ['wordxyz', %w(word)], + ].each do |test_params| + phrase, expected = test_params + + it "returns an array with the word found in the phrase '#{phrase}'" do + expect(container.words_within phrase).to match_array expected + end + end +end + +shared_examples_for 'a non-matching container#words_within' do + it 'returns an array with all words found in the phrase' do + expect(container.words_within 'xyzword otherzxyone') + .to match_array %w(word other one) + end +end + +shared_examples_for 'a matching container#words_within?' do + context 'when phrase does not contain any words' do + it 'returns false' do + expect(container.words_within? 'xyz').to be false + end + end + + context 'when phrase contains any word' do + ['xyz words', 'xyzone word'].each do |phrase| + it "returns true for '#{phrase}'" do + expect(container.words_within? phrase).to be true + end + end + end +end + +shared_examples_for 'a non-matching container#words_within?' do + it 'returns an array with all words found in the phrase' do + expect(container.words_within 'xyzword otherzxyone') + .to match_array %w(word other one) + end +end diff --git a/spec/support/shared_examples/a_serializable_trie.rb b/spec/support/shared_examples/a_serializable_trie.rb index bc1e3292..031523c8 100644 --- a/spec/support/shared_examples/a_serializable_trie.rb +++ b/spec/support/shared_examples/a_serializable_trie.rb @@ -4,22 +4,18 @@ let(:tmp_path) { File.join ::SPEC_ROOT, 'tmp' } let(:filepath) { File.join tmp_path, "trie-root.#{format}" } - context 'and the trie is not compressed' do - before do - Rambling::Trie.dump trie_to_serialize, filepath - end + context 'with an uncompressed trie' do + before { Rambling::Trie.dump trie_to_serialize, filepath } it_behaves_like 'a compressible trie' do let(:trie) { Rambling::Trie.load filepath } end end - context 'and the trie is compressed' do + context 'with an compressed trie' do let(:trie) { Rambling::Trie.load filepath } - before do - Rambling::Trie.dump trie_to_serialize.compress!, filepath - end + before { Rambling::Trie.dump trie_to_serialize.compress!, filepath } it_behaves_like 'a trie data structure' diff --git a/spec/support/shared_examples/a_serializer.rb b/spec/support/shared_examples/a_serializer.rb index 2f2000ce..9e60b5e3 100644 --- a/spec/support/shared_examples/a_serializer.rb +++ b/spec/support/shared_examples/a_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true shared_examples_for 'a serializer' do + subject(:serializer) { described_class.new } + let(:trie) { Rambling::Trie.create } let(:tmp_path) { File.join ::SPEC_ROOT, 'tmp' } let(:filepath) { File.join tmp_path, "trie-root.#{format}" } diff --git a/spec/support/shared_examples/a_trie_data_structure.rb b/spec/support/shared_examples/a_trie_data_structure.rb index 7330d6a7..a43589da 100644 --- a/spec/support/shared_examples/a_trie_data_structure.rb +++ b/spec/support/shared_examples/a_trie_data_structure.rb @@ -2,25 +2,39 @@ shared_examples_for 'a trie data structure' do it 'contains all the words previously provided' do - words.each do |word| - expect(trie).to include word - expect(trie.word? word).to be true - end + words.each { |word| expect(trie).to include word } + end + + it 'returns true for #word? for all words previously provided' do + words.each { |word| expect(trie.word? word).to be true } + end + + it 'matches the full word for all words in file' do + words.each { |word| expect(trie.match? word).to be true } + end + + it 'matches the start of all the words in file' do + words.each { |word| expect(trie.match? word[0..-2]).to be true } end - it 'matches the start of all the words from the file' do + it 'returns true for #partial_word? with full word for all words in file' do + words.each { |word| expect(trie.partial_word? word).to be true } + end + + it 'returns true for #partial_word? with the start of all words in file' do + words.each { |word| expect(trie.partial_word? word[0..-2]).to be true } + end + + it 'extracts words within larger strings' do words.each do |word| - expect(trie.match? word).to be true - expect(trie.match? word[0..-2]).to be true - expect(trie.partial_word? word).to be true - expect(trie.partial_word? word[0..-2]).to be true + phrase = "x#{word}y" + expect(trie.words_within phrase).to include word end end it 'identifies words within larger strings' do words.each do |word| phrase = "x#{word}y" - expect(trie.words_within phrase).to include word expect(trie.words_within? phrase).to be true end end diff --git a/spec/support/shared_examples/a_trie_node.rb b/spec/support/shared_examples/a_trie_node.rb index d6030304..8179ed49 100644 --- a/spec/support/shared_examples/a_trie_node.rb +++ b/spec/support/shared_examples/a_trie_node.rb @@ -40,9 +40,7 @@ describe '#root?' do context 'when the node has a parent' do - before do - node.parent = node - end + before { node.parent = node } it 'returns false' do expect(node).not_to be_root @@ -50,9 +48,7 @@ end context 'when the node does not have a parent' do - before do - node.parent = nil - end + before { node.parent = nil } it 'returns true' do expect(node).to be_root @@ -61,12 +57,13 @@ end describe '#terminal!' do + # rubocop:disable RSpec/MultipleExpectations it 'forces the node to be terminal' do expect(node).not_to be_terminal node.terminal! - expect(node).to be_terminal end + # rubocop:enable RSpec/MultipleExpectations it 'returns the node' do expect(node.terminal!).to eq node @@ -75,7 +72,8 @@ describe 'delegates and aliases' do let(:children_tree) do - double( + instance_double( + 'Hash', :children_tree, :[] => 'value', :[]= => nil, @@ -84,20 +82,21 @@ ) end - before do - node.children_tree = children_tree - end + before { node.children_tree = children_tree } + # rubocop:disable RSpec/MultipleExpectations it 'delegates `#[]` to its children tree' do expect(node[:key]).to eq 'value' expect(children_tree).to have_received(:[]).with :key end + # rubocop:enable RSpec/MultipleExpectations it 'delegates `#[]=` to its children tree' do node[:key] = 'value' expect(children_tree).to have_received(:[]=).with(:key, 'value') end + # rubocop:disable RSpec/MultipleExpectations it 'delegates `#key?` to its children tree' do allow(children_tree).to receive(:key?) .with(:present_key) @@ -106,18 +105,26 @@ expect(node).to have_key(:present_key) expect(node).not_to have_key(:absent_key) end + # rubocop:enable RSpec/MultipleExpectations + # rubocop:disable RSpec/MultipleExpectations it 'delegates `#delete` to its children tree' do expect(node.delete :key).to be true expect(children_tree).to have_received(:delete).with :key end + # rubocop:enable RSpec/MultipleExpectations + # rubocop:disable RSpec/ExampleLength it 'delegates `#children` to its children tree values' do - children = [double(:child_1), double(:child_2)] + children = [ + instance_double('Rambling::Trie::Nodes::Node', :child_one), + instance_double('Rambling::Trie::Nodes::Node', :child_two), + ] allow(children_tree).to receive(:values).and_return children expect(node.children).to eq children end + # rubocop:enable RSpec/ExampleLength it 'aliases `#has_key?` to `#key?`' do node.has_key? :nope diff --git a/spec/support/shared_examples/a_trie_node_implementation.rb b/spec/support/shared_examples/a_trie_node_implementation.rb index 25d236e8..d24b1410 100644 --- a/spec/support/shared_examples/a_trie_node_implementation.rb +++ b/spec/support/shared_examples/a_trie_node_implementation.rb @@ -12,26 +12,22 @@ context 'when the chars array is not empty' do context 'when the node has a tree that matches the characters' do - before do - add_word_to_tree 'abc' - end + before { add_word_to_tree 'abc' } - it 'returns true' do - expect(node.partial_word? %w(a)).to be true - expect(node.partial_word? %w(a b)).to be true - expect(node.partial_word? %w(a b c)).to be true + [%w(a), %w(a b), %w(a b c)].each do |letters| + it "returns true for '#{letters}'" do + expect(node.partial_word? letters).to be true + end end end context 'when the node has a tree that does not match the characters' do - before do - add_word_to_tree 'cba' - end + before { add_word_to_tree 'cba' } - it 'returns false' do - expect(node.partial_word? %w(a)).to be false - expect(node.partial_word? %w(a b)).to be false - expect(node.partial_word? %w(a b c)).to be false + [%w(a), %w(a b), %w(a b c)].each do |letters| + it "returns false for '#{letters}'" do + expect(node.partial_word? letters).to be false + end end end end @@ -40,9 +36,7 @@ describe '#word?' do context 'when the chars array is empty' do context 'when the node is terminal' do - before do - node.terminal! - end + before { node.terminal! } it 'returns true' do expect(node.word? []).to be true @@ -58,9 +52,7 @@ context 'when the chars array is not empty' do context 'when the node has a tree that matches all the characters' do - before do - add_word_to_tree 'abc' - end + before { add_word_to_tree 'abc' } it 'returns true' do expect(node.word? %w(a b c).map(&:dup)).to be true @@ -68,13 +60,12 @@ end context 'when the node subtree does not match all the characters' do - before do - add_word_to_tree 'abc' - end + before { add_word_to_tree 'abc' } - it 'returns false' do - expect(node.word? %w(a).map(&:dup)).to be false - expect(node.word? %w(a b).map(&:dup)).to be false + [%w(a), %w(a b)].each do |letters| + it "returns false for '#{letters}'" do + expect(node.word? letters.map(&:dup)).to be false + end end end end @@ -88,26 +79,34 @@ end context 'when the chars array is not empty' do - before do - add_words_to_tree %w(cba ccab) - end + before { add_words_to_tree %w(cba ccab) } context 'when the chars are found' do - it 'returns the found child' do - expect(node.scan %w(c)).to match_array %w(cba ccab) - expect(node.scan %w(c b)).to match_array %w(cba) - expect(node.scan %w(c b a)).to match_array %w(cba) + [ + [%w(c), %w(cba ccab)], + [%w(c b), %w(cba)], + [%w(c b a), %w(cba)], + ].each do |test_params| + letters, expected = test_params + + it "returns the corresponding children (#{letters} => #{expected})" do + expect(node.scan letters).to match_array expected + end end end context 'when the chars are not found' do - it 'returns a Nodes::Missing' do - expect(node.scan %w(a)).to be_a Rambling::Trie::Nodes::Missing - expect(node.scan %w(a b)).to be_a Rambling::Trie::Nodes::Missing - expect(node.scan %w(a b c)).to be_a Rambling::Trie::Nodes::Missing - expect(node.scan %w(c a)).to be_a Rambling::Trie::Nodes::Missing - expect(node.scan %w(c c b)).to be_a Rambling::Trie::Nodes::Missing - expect(node.scan %w(c b a d)).to be_a Rambling::Trie::Nodes::Missing + [ + %w(a), + %w(a b), + %w(a b c), + %w(c a), + %w(c c b), + %w(c b a d), + ].each do |letters| + it "returns a Nodes::Missing for '#{letters}'" do + expect(node.scan letters).to be_a Rambling::Trie::Nodes::Missing + end end end end @@ -120,9 +119,7 @@ end context 'when the node is terminal' do - before do - node.terminal! - end + before { node.terminal! } it 'adds itself to the words' do expect(node.match_prefix %w(g n i t e)).to include 'i' diff --git a/tasks/ips.rb b/tasks/ips.rb index 881123d5..7c5e6078 100644 --- a/tasks/ips.rb +++ b/tasks/ips.rb @@ -144,7 +144,7 @@ class TestDelegate require 'forwardable' extend ::Forwardable - delegate [:[]] => :hash + delegate %i([]) => :hash attr_reader :hash @@ -168,7 +168,7 @@ def delegate methods_to_target extend TestMyForwardable::Forwardable - delegate [:[]] => :hash + delegate %i([]) => :hash attr_reader :hash diff --git a/tasks/performance.rb b/tasks/performance.rb index efcc922a..5d06fd23 100644 --- a/tasks/performance.rb +++ b/tasks/performance.rb @@ -14,7 +14,7 @@ configuration = Performance::Configuration.new task = Performance::Task.new configuration - task.run **args + task.run(**args) end namespace :performance do diff --git a/tasks/performance/configuration.rb b/tasks/performance/configuration.rb index 59f9a3e4..686f7886 100644 --- a/tasks/performance/configuration.rb +++ b/tasks/performance/configuration.rb @@ -13,9 +13,9 @@ def get type, method type ||= 'all' method ||= 'all' - if type == 'all' + if 'all' == type get_all_types method - elsif method == 'all' + elsif 'all' == method get_all_methods type else tasks[type][method] @@ -165,7 +165,7 @@ def lookups_partial_word_compressed def lookups_scan_raw lambda do |iterations| - if iterations.nil? || iterations == 200_000 + if iterations.nil? || 200_000 == iterations Performance::SubTasks::Lookups::Scan::Raw.new else Performance::SubTasks::Lookups::Scan::Raw.new( @@ -181,7 +181,7 @@ def lookups_scan_raw def lookups_scan_compressed _ = nil lambda do |iterations| - if iterations.nil? || iterations == 200_000 + if iterations.nil? || 200_000 == iterations Performance::SubTasks::Lookups::Scan::Compressed.new else Performance::SubTasks::Lookups::Scan::Compressed.new( diff --git a/tasks/performance/reporters/benchmark.rb b/tasks/performance/reporters/benchmark.rb index 32872dbf..145adbe1 100644 --- a/tasks/performance/reporters/benchmark.rb +++ b/tasks/performance/reporters/benchmark.rb @@ -7,6 +7,7 @@ module Performance module Reporters class Benchmark < Performance::Reporters::Reporter def initialize _ = nil, output = $stdout.dup + super() @output = output end diff --git a/tasks/performance/reporters/call_tree_profile.rb b/tasks/performance/reporters/call_tree_profile.rb index 0abf1366..bd102a77 100644 --- a/tasks/performance/reporters/call_tree_profile.rb +++ b/tasks/performance/reporters/call_tree_profile.rb @@ -6,6 +6,7 @@ module Performance module Reporters class CallTreeProfile < Performance::Reporters::Reporter def initialize dirname + super() @dirname = dirname end diff --git a/tasks/performance/reporters/flamegraph.rb b/tasks/performance/reporters/flamegraph.rb index 69d2db21..9b88565f 100644 --- a/tasks/performance/reporters/flamegraph.rb +++ b/tasks/performance/reporters/flamegraph.rb @@ -6,6 +6,7 @@ module Performance module Reporters class Flamegraph < Performance::Reporters::Reporter def initialize filename + super() @filename = filename end diff --git a/tasks/performance/reporters/memory_profile.rb b/tasks/performance/reporters/memory_profile.rb index cb3543ec..0e35be54 100644 --- a/tasks/performance/reporters/memory_profile.rb +++ b/tasks/performance/reporters/memory_profile.rb @@ -6,6 +6,7 @@ module Performance module Reporters class MemoryProfile < Performance::Reporters::Reporter def initialize filename + super() @filename = filename end diff --git a/tasks/performance/reporters/reporter.rb b/tasks/performance/reporters/reporter.rb index fc2c2138..c5ec1e92 100644 --- a/tasks/performance/reporters/reporter.rb +++ b/tasks/performance/reporters/reporter.rb @@ -12,13 +12,11 @@ class Reporter include Helpers::Path include Helpers::Time - def report iterations = 1, params = nil + def report iterations = 1, params = nil, &block params = Array params params << nil unless params.any? - do_report iterations, params do |param| - yield param - end + do_report iterations, params, &block end end end diff --git a/tasks/performance/sub_tasks/initialization.rb b/tasks/performance/sub_tasks/initialization.rb index fc026942..53ca23ef 100644 --- a/tasks/performance/sub_tasks/initialization.rb +++ b/tasks/performance/sub_tasks/initialization.rb @@ -8,6 +8,7 @@ class Initialization < Performance::SubTasks::SubTask include Helpers::Path def initialize iterations = 5 + super() @iterations = iterations end diff --git a/tasks/performance/sub_tasks/lookups/lookup.rb b/tasks/performance/sub_tasks/lookups/lookup.rb index 84c2177c..9fba5fdb 100644 --- a/tasks/performance/sub_tasks/lookups/lookup.rb +++ b/tasks/performance/sub_tasks/lookups/lookup.rb @@ -9,6 +9,7 @@ class Lookup < Performance::SubTasks::SubTask include Helpers::Trie def initialize iterations = 200_000 + super() @iterations = iterations end diff --git a/tasks/performance/sub_tasks/lookups/scan/compressed.rb b/tasks/performance/sub_tasks/lookups/scan/compressed.rb index 45cfa961..4d238054 100644 --- a/tasks/performance/sub_tasks/lookups/scan/compressed.rb +++ b/tasks/performance/sub_tasks/lookups/scan/compressed.rb @@ -10,6 +10,7 @@ class Compressed < Performance::SubTasks::Lookups::Lookup include Helpers::Trie def initialize params_to_iterations = default_params + super() @params_to_iterations = params_to_iterations end diff --git a/tasks/performance/sub_tasks/lookups/scan/raw.rb b/tasks/performance/sub_tasks/lookups/scan/raw.rb index fdf0cb74..930f2378 100644 --- a/tasks/performance/sub_tasks/lookups/scan/raw.rb +++ b/tasks/performance/sub_tasks/lookups/scan/raw.rb @@ -10,6 +10,7 @@ class Raw < Performance::SubTasks::Lookups::Lookup include Helpers::Trie def initialize params_to_iterations = default_params + super() @params_to_iterations = params_to_iterations end From e4bcc5ed1a0ecef761c062640527bdb083bf8598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Fri, 5 May 2023 13:26:45 -0400 Subject: [PATCH 32/58] Rubocop part 2: indentation and spaces on new tests (#27) --- spec/lib/rambling/trie/container_spec.rb | 5 ++--- .../a_container_partial_word.rb | 1 - .../shared_examples/a_container_word.rb | 1 - .../a_container_words_within.rb | 18 +++++++++--------- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/spec/lib/rambling/trie/container_spec.rb b/spec/lib/rambling/trie/container_spec.rb index a7b288b0..534ad113 100644 --- a/spec/lib/rambling/trie/container_spec.rb +++ b/spec/lib/rambling/trie/container_spec.rb @@ -201,7 +201,6 @@ describe '#partial_word?' do context 'with underlying node' do - it_behaves_like 'a propagating node' do let(:method) { :partial_word? } end @@ -322,9 +321,9 @@ it_behaves_like 'a matching container#words_within?' context 'with compressed node' do - before { container.compress! } + before { container.compress! } - it_behaves_like 'a matching container#words_within?' + it_behaves_like 'a matching container#words_within?' end end diff --git a/spec/support/shared_examples/a_container_partial_word.rb b/spec/support/shared_examples/a_container_partial_word.rb index f23cd5db..ebf0e267 100644 --- a/spec/support/shared_examples/a_container_partial_word.rb +++ b/spec/support/shared_examples/a_container_partial_word.rb @@ -15,4 +15,3 @@ end end end - diff --git a/spec/support/shared_examples/a_container_word.rb b/spec/support/shared_examples/a_container_word.rb index f0176869..de4a2d58 100644 --- a/spec/support/shared_examples/a_container_word.rb +++ b/spec/support/shared_examples/a_container_word.rb @@ -40,5 +40,4 @@ end end end - end diff --git a/spec/support/shared_examples/a_container_words_within.rb b/spec/support/shared_examples/a_container_words_within.rb index 7b34f01a..6f66a27f 100644 --- a/spec/support/shared_examples/a_container_words_within.rb +++ b/spec/support/shared_examples/a_container_words_within.rb @@ -21,19 +21,19 @@ end shared_examples_for 'a matching container#words_within?' do - context 'when phrase does not contain any words' do - it 'returns false' do - expect(container.words_within? 'xyz').to be false - end + context 'when phrase does not contain any words' do + it 'returns false' do + expect(container.words_within? 'xyz').to be false end + end - context 'when phrase contains any word' do - ['xyz words', 'xyzone word'].each do |phrase| - it "returns true for '#{phrase}'" do - expect(container.words_within? phrase).to be true - end + context 'when phrase contains any word' do + ['xyz words', 'xyzone word'].each do |phrase| + it "returns true for '#{phrase}'" do + expect(container.words_within? phrase).to be true end end + end end shared_examples_for 'a non-matching container#words_within?' do From 143b18314ec24eb8086d62a6a06470cfdee42b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 11:31:52 -0400 Subject: [PATCH 33/58] More thorough serializer tests (#28) Realized that, except for one integration test, we were not testing compressed tries being serialized so added some more specific use cases. Also took the chance to expand the zip serializer spec to handle all formats. --- .../rambling/trie/serializers/file_spec.rb | 2 +- .../rambling/trie/serializers/marshal_spec.rb | 2 +- .../rambling/trie/serializers/yaml_spec.rb | 2 +- .../lib/rambling/trie/serializers/zip_spec.rb | 40 +++++++++------ spec/support/shared_examples/a_serializer.rb | 49 ++++++++++++------- 5 files changed, 59 insertions(+), 36 deletions(-) diff --git a/spec/lib/rambling/trie/serializers/file_spec.rb b/spec/lib/rambling/trie/serializers/file_spec.rb index 1f899925..d813b0b0 100644 --- a/spec/lib/rambling/trie/serializers/file_spec.rb +++ b/spec/lib/rambling/trie/serializers/file_spec.rb @@ -6,6 +6,6 @@ it_behaves_like 'a serializer' do let(:format) { :file } let(:content) { trie.to_a.join ' ' } - let(:formatted_content) { content } + let(:format_content) { ->(content) { content } } end end diff --git a/spec/lib/rambling/trie/serializers/marshal_spec.rb b/spec/lib/rambling/trie/serializers/marshal_spec.rb index f3501322..e462ba39 100644 --- a/spec/lib/rambling/trie/serializers/marshal_spec.rb +++ b/spec/lib/rambling/trie/serializers/marshal_spec.rb @@ -5,6 +5,6 @@ describe Rambling::Trie::Serializers::Marshal do it_behaves_like 'a serializer' do let(:format) { :marshal } - let(:formatted_content) { Marshal.dump content } + let(:format_content) { Marshal.method(:dump) } end end diff --git a/spec/lib/rambling/trie/serializers/yaml_spec.rb b/spec/lib/rambling/trie/serializers/yaml_spec.rb index 00aeb9de..a1c7ee59 100644 --- a/spec/lib/rambling/trie/serializers/yaml_spec.rb +++ b/spec/lib/rambling/trie/serializers/yaml_spec.rb @@ -5,6 +5,6 @@ describe Rambling::Trie::Serializers::Yaml do it_behaves_like 'a serializer' do let(:format) { :yml } - let(:formatted_content) { YAML.dump content } + let(:format_content) { YAML.method(:dump) } end end diff --git a/spec/lib/rambling/trie/serializers/zip_spec.rb b/spec/lib/rambling/trie/serializers/zip_spec.rb index 5953957a..0833e9c4 100644 --- a/spec/lib/rambling/trie/serializers/zip_spec.rb +++ b/spec/lib/rambling/trie/serializers/zip_spec.rb @@ -3,26 +3,34 @@ require 'spec_helper' describe Rambling::Trie::Serializers::Zip do - it_behaves_like 'a serializer' do - let(:properties) { Rambling::Trie::Configuration::Properties.new } - let(:serializer) { described_class.new properties } - let(:format) { :zip } + { + yaml: YAML.method(:dump), + yml: YAML.method(:dump), + marshal: Marshal.method(:dump), + file: Marshal.method(:dump), + }.each do |format, dump_method| + context "with '.#{format}'" do + it_behaves_like 'a serializer' do + let(:properties) { Rambling::Trie::Configuration::Properties.new } + let(:serializer) { described_class.new properties } + let(:format) { :zip } - before do - properties.tmp_path = tmp_path - end - - let(:filename) { File.basename(filepath).gsub %r{\.zip}, '' } - let(:formatted_content) { zip Marshal.dump content } + let(:filepath) { File.join tmp_path, "trie-root.#{format}.zip" } + let(:format_content) { ->(content) { zip dump_method.call content } } + let(:filename) { File.basename(filepath).gsub %r{\.zip}, '' } - def zip content - cursor = Zip::OutputStream.write_buffer do |io| - io.put_next_entry filename - io.write content + before { properties.tmp_path = tmp_path } end + end + end - cursor.rewind - cursor.read + def zip content + cursor = Zip::OutputStream.write_buffer do |io| + io.put_next_entry filename + io.write content end + + cursor.rewind + cursor.read end end diff --git a/spec/support/shared_examples/a_serializer.rb b/spec/support/shared_examples/a_serializer.rb index 9e60b5e3..71a046d0 100644 --- a/spec/support/shared_examples/a_serializer.rb +++ b/spec/support/shared_examples/a_serializer.rb @@ -14,27 +14,42 @@ end describe '#dump' do - before do - serializer.dump content, filepath - end - - it 'creates the file with the provided path' do - expect(File.exist? filepath).to be true - end - - it 'converts the contents to the appropriate format' do - file = File.read(filepath) - expect(file.size).to be_within(15).of formatted_content.size + [true, false].each do |compress_value| + context "with compressed=#{compress_value} trie" do + before do + trie.compress! if compress_value + serializer.dump content, filepath + end + + it 'creates the file with the provided path' do + expect(File.exist? filepath).to be true + end + + it 'converts the contents to the appropriate format' do + formatted_content = format_content.call content + expect(File.size filepath).to be_within(20).of formatted_content.size + end + end end end describe '#load' do - before do - serializer.dump content, filepath - end - - it 'loads the dumped object back into memory' do - expect(serializer.load filepath).to eq content + [true, false].each do |compress_value| + context "with compressed=#{compress_value} trie" do + before do + trie.compress! if compress_value + serializer.dump content, filepath + end + + it 'loads the dumped object back into memory' do + expect(serializer.load filepath).to eq content + end + + it "loads a compressed=#{compress_value} object" do + loaded = serializer.load filepath + expect(loaded.compressed?).to be compress_value if :file != format + end + end end end end From abb0ac6c9bc4e83714264fa7abb54d9f2245a95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 17:05:14 -0400 Subject: [PATCH 34/58] Update badges, CI and coveralls reporting (#29) * Update `.coveralls.yml` to point to `semaphore` * On `.semaphore/semaphore.yml`: * Rename pipeline to `Run specs in all supported rubies' * Extract `checkout` command to `global_job_config.prologue` * Add `3.2.2`, `3.1.4`, `3.0.6`, `2.7.8` tasks * Correctly configure main `3.2.2` task to publish test report, now being picked up by Semaphore ![Screenshot 2023-05-09 at 4 55 13 PM](https://github.com/gonzedge/rambling-trie/assets/218312/de876e83-f569-48b9-b2f1-4a33c8c166c5) * Remove unnecessary formatters from non-`3.2.2` tasks * On badges: * Change `README.md` to have one badge per line instead of all in one giant line * Add RubyGems downloads badge * Add CodeClimate issues badge * Update docs badge to point directly to [rubydoc.info/gems/rambling-trie](http://rubydoc.info/gems/rambling-trie) * Update license badge to one from shields.io --- .coveralls.yml | 2 +- .semaphore/semaphore.yml | 116 ++++++++++++++++++++++++--------------- README.md | 18 ++++-- 3 files changed, 87 insertions(+), 49 deletions(-) diff --git a/.coveralls.yml b/.coveralls.yml index 91600595..29f1af09 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1 +1 @@ -service_name: travis-ci +service_name: semaphore diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 179d0ebd..025462db 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -1,254 +1,282 @@ version: v1.0 -name: ruby +name: Run specs in all supported rubies agent: machine: type: e1-standard-2 os_image: ubuntu2004 +global_job_config: + prologue: + commands: + - checkout blocks: - - name: 3.2.1 + - name: 3.2.2 dependencies: [] task: prologue: commands: - - checkout - - sem-version ruby 3.2.1 + - sem-version ruby 3.2.2 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec --format RspecJunitFormatter --out report.xml epilogue: always: commands: - - test-results publish junit.xml + - '[[ -f report.xml ]] && test-results publish report.xml' + - name: 3.2.1 + dependencies: [] + task: + prologue: + commands: + - sem-version ruby 3.2.1 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec - name: 3.2.0 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.2.0 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec + - name: 3.1.4 + dependencies: [] + task: + prologue: + commands: + - sem-version ruby 3.1.4 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec - name: 3.1.3 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.1.3 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.1.2 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.1.2 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.1.1 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.1.1 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.1.0 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.1.0 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec + - name: 3.0.6 + dependencies: [] + task: + prologue: + commands: + - sem-version ruby 3.0.6 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec - name: 3.0.5 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.0.5 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.0.4 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.0.4 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.0.3 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.0.3 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.0.2 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.0.2 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.0.1 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.0.1 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 3.0.0 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 3.0.0 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec + - name: 2.7.8 + dependencies: [] + task: + prologue: + commands: + - sem-version ruby 2.7.8 + - bundle install + jobs: + - name: bundle exec rspec + commands: + - bundle exec rspec - name: 2.7.7 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.7 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 2.7.6 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.6 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 2.7.5 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.5 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 2.7.4 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.4 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 2.7.3 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.3 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 2.7.2 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.2 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 2.7.1 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.1 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec - name: 2.7.0 dependencies: [] task: prologue: commands: - - checkout - sem-version ruby 2.7.0 - bundle install jobs: - name: bundle exec rspec commands: - - bundle exec rspec --format RspecJunitFormatter --out junit.xml --format documentation + - bundle exec rspec after_pipeline: task: jobs: diff --git a/README.md b/README.md index ec291937..a57e069c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ # Rambling Trie -[![Gem Version][badge_fury_badge]][badge_fury_link] [![Build Status][semaphore_ci_badge]][semaphore_ci_link] [![Code Climate][code_climate_badge]][code_climage_link] [![Coverage Status][coveralls_badge]][coveralls_link] [![Documentation Status][inch_ci_badge]][inch_ci_link] [![License][license_badge]][license_link] +[![Gem Version][badge_fury_badge]][badge_fury_link] +[![Downloads][downloads_badge]][downloads_link] +[![Build Status][semaphore_ci_badge]][semaphore_ci_link] +[![Coverage Status][coveralls_badge]][coveralls_link] +[![Code Climate][code_climate_badge]][code_climate_link] +[![Issue Count][code_climate_issues_badge]][code_climate_link] +[![Documentation Status][inch_ci_badge]][inch_ci_link] +[![License][license_badge]][license_link] The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse. @@ -278,16 +285,19 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.3.0 [badge_fury_link]: https://badge.fury.io/rb/rambling-trie [chruby]: https://github.com/postmodern/chruby -[code_climage_link]: https://codeclimate.com/github/gonzedge/rambling-trie [code_climate_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg +[code_climate_issues_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/issue_count.svg +[code_climate_link]: https://codeclimate.com/github/gonzedge/rambling-trie [coveralls_badge]: https://img.shields.io/coveralls/gonzedge/rambling-trie.svg [coveralls_link]: https://coveralls.io/r/gonzedge/rambling-trie +[downloads_badge]: https://img.shields.io/gem/dt/rambling-trie.svg +[downloads_link]: https://rubygems.org/gems/rambling-trie [gemnasium_badge]: https://gemnasium.com/gonzedge/rambling-trie.svg [gemnasium_link]: https://gemnasium.com/gonzedge/rambling-trie [github_user_gonzedge]: https://github.com/gonzedge [inch_ci_badge]: https://inch-ci.org/github/gonzedge/rambling-trie.svg?branch=master -[inch_ci_link]: https://inch-ci.org/github/gonzedge/rambling-trie -[license_badge]: https://badges.frapsoft.com/os/mit/mit.svg?v=103 +[inch_ci_link]: http://rubydoc.info/gems/rambling-trie +[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg [license_link]: https://opensource.org/licenses/mit-license.php [marshal]: https://ruby-doc.org/core-2.7.0/Marshal.html [rambling_trie_configuration]: https://github.com/gonzedge/rambling-trie#configuration From 310ac54fb28936b1702363da8cd1afff0232c373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 17:35:48 -0400 Subject: [PATCH 35/58] GH Actions: ruby, codeql, dependency-review (#30) Include rspec, coveralls and rubocop in ruby action. --- .github/workflows/codeql.yml | 72 +++++++++++++++++++++++++ .github/workflows/dependency-review.yml | 21 ++++++++ .github/workflows/ruby.yml | 54 +++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/ruby.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..84eda52f --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: CodeQL + +on: + push: + branches: [ $default-branch ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ $default-branch ] + schedule: + - cron: '45 10 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'ruby' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: /language:${{matrix.language}} diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..b51fee1f --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,21 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: Dependency Review +on: + - pull_request + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Dependency Review + uses: actions/dependency-review-action@v2 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 00000000..94d46ba1 --- /dev/null +++ b/.github/workflows/ruby.yml @@ -0,0 +1,54 @@ +name: Ruby + +on: + push: + branches: [ $default-branch ] + pull_request: + branches: [ $default-branch ] + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: + - 3.2.2 + - 3.2.1 + - 3.2.0 + - 3.1.4 + - 3.1.3 + - 3.1.2 + - 3.1.1 + - 3.1.0 + - 3.0.6 + - 3.0.5 + - 3.0.4 + - 3.0.3 + - 3.0.2 + - 3.0.1 + - 3.0.0 + - 2.7.8 + - 2.7.7 + - 2.7.6 + - 2.7.5 + - 2.7.4 + - 2.7.3 + - 2.7.2 + - 2.7.1 + - 2.7.0 + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + - name: Lint + run: rubocop + - name: Run tests + run: bundle exec rspec + - name: Report coverage + uses: coverallsapp/github-action@v1 From cd200b6eaa34f90a2507900e9819b76df8347eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 18:15:25 -0400 Subject: [PATCH 36/58] GH Actions: Actually specify the main branch (#31) And split rubocop and coveralls into own job tasks: `lint` and `coverage`. --- .github/workflows/codeql.yml | 7 +++-- .github/workflows/dependency-review.yml | 7 ++++- .github/workflows/ruby.yml | 32 +++++++++++++++---- .rubocop.yml | 1 + .travis.yml | 41 ------------------------- 5 files changed, 37 insertions(+), 51 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 84eda52f..095f579e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,10 +13,11 @@ name: CodeQL on: push: - branches: [ $default-branch ] + branches: + - master pull_request: - # The branches below must be a subset of the branches above - branches: [ $default-branch ] + branches: + - master schedule: - cron: '45 10 * * 6' diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index b51fee1f..c08fb8e3 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -6,7 +6,12 @@ # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement name: Dependency Review on: - - pull_request + push: + branches: + - master + pull_request: + branches: + - master permissions: contents: read diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 94d46ba1..8c71c976 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -2,14 +2,27 @@ name: Ruby on: push: - branches: [ $default-branch ] + branches: + - master pull_request: - branches: [ $default-branch ] + branches: + - master permissions: contents: read jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2.2 + bundler-cache: true + - name: Lint + run: bundle exec rubocop test: runs-on: ubuntu-latest strategy: @@ -46,9 +59,16 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - - name: Lint - run: rubocop - name: Run tests run: bundle exec rspec - - name: Report coverage - uses: coverallsapp/github-action@v1 + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2.2 + bundler-cache: true + - name: Run tests and report test coverage + run: COVERALLS_REPO_TOKEN=${{ secrets.COVERALLS_REPO_TOKEN }} bundle exec rspec diff --git a/.rubocop.yml b/.rubocop.yml index 49e8b479..c07e7f66 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -17,6 +17,7 @@ AllCops: - 'pkg/**/*' - 'reports/**/*' - 'tmp/**/*' + - 'vendor/**/*' TargetRubyVersion: 2.7.0 #################### Layout ########################### diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5e78ea79..00000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -env: - global: - - CC_TEST_REPORTER_ID=6f07a33d1bf4060910c8b97cb9bf97230bbf1fad75765fef98f3cca9f29cd6b0 -language: ruby -before_install: - - gem install bundler -install: - - bundle install --without local -rvm: - - 3.2.2 - - 3.2.1 - - 3.2.0 - - 3.1.4 - - 3.1.3 - - 3.1.2 - - 3.1.1 - - 3.1.0 - - 3.0.6 - - 3.0.5 - - 3.0.4 - - 3.0.3 - - 3.0.2 - - 3.0.1 - - 3.0.0 - - 2.7.8 - - 2.7.7 - - 2.7.6 - - 2.7.5 - - 2.7.4 - - 2.7.3 - - 2.7.2 - - 2.7.1 - - 2.7.0 -before_script: - - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - - chmod +x ./cc-test-reporter - - ./cc-test-reporter before-build -script: - - bundle exec rspec -after_script: - - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT From 0cc13307716cc438f59c421802fe1a87d5bf39f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 18:34:34 -0400 Subject: [PATCH 37/58] GH Actions: only run dependency-review on pull_request event (#32) --- .github/workflows/dependency-review.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index c08fb8e3..5fcd5be4 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -6,9 +6,6 @@ # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement name: Dependency Review on: - push: - branches: - - master pull_request: branches: - master From 6b1892649f72dcc8737f00a70b33dab96dee4909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 18:43:32 -0400 Subject: [PATCH 38/58] Reduce semaphore config to latest ruby (#33) Now, we only care about top-level pass/fail for badge reporting. All other tests are run with GitHub Actions. --- .semaphore/semaphore.yml | 255 +-------------------------------------- 1 file changed, 1 insertion(+), 254 deletions(-) diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 025462db..d36f9f62 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -1,5 +1,5 @@ version: v1.0 -name: Run specs in all supported rubies +name: Run specs in latest ruby agent: machine: type: e1-standard-2 @@ -24,259 +24,6 @@ blocks: always: commands: - '[[ -f report.xml ]] && test-results publish report.xml' - - name: 3.2.1 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.2.1 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.2.0 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.2.0 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.1.4 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.1.4 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.1.3 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.1.3 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.1.2 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.1.2 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.1.1 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.1.1 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.1.0 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.1.0 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.0.6 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.0.6 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.0.5 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.0.5 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.0.4 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.0.4 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.0.3 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.0.3 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.0.2 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.0.2 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.0.1 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.0.1 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 3.0.0 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 3.0.0 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.8 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.8 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.7 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.7 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.6 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.6 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.5 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.5 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.4 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.4 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.3 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.3 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.2 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.2 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.1 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.1 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec - - name: 2.7.0 - dependencies: [] - task: - prologue: - commands: - - sem-version ruby 2.7.0 - - bundle install - jobs: - - name: bundle exec rspec - commands: - - bundle exec rspec after_pipeline: task: jobs: From 2f6d939d84e8335cdee760c3b684cd2462e79e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 19:24:32 -0400 Subject: [PATCH 39/58] Rename GH actions and steps for better badges (#34) Plus reformat badges at top of `README.md`. --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/dependency-review.yml | 2 +- .github/workflows/ruby.yml | 16 ++++++++-------- README.md | 22 +++++++++++++--------- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 095f579e..db3011f2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -9,7 +9,7 @@ # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # -name: CodeQL +name: codeql on: push: @@ -23,7 +23,7 @@ on: jobs: analyze: - name: Analyze + name: analyze runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} permissions: actions: read diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 5fcd5be4..666d2083 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -4,7 +4,7 @@ # # Source repository: https://github.com/actions/dependency-review-action # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement -name: Dependency Review +name: dependency-review on: pull_request: branches: diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 8c71c976..157f699a 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -1,4 +1,4 @@ -name: Ruby +name: build on: push: @@ -16,14 +16,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Ruby + - name: Set up ruby uses: ruby/setup-ruby@v1 with: ruby-version: 3.2.2 bundler-cache: true - - name: Lint + - name: Run rubocop run: bundle exec rubocop - test: + spec: runs-on: ubuntu-latest strategy: matrix: @@ -54,21 +54,21 @@ jobs: - 2.7.0 steps: - uses: actions/checkout@v3 - - name: Set up Ruby + - name: Set up ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - - name: Run tests + - name: Run rspec run: bundle exec rspec coverage: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Ruby + - name: Set up ruby uses: ruby/setup-ruby@v1 with: ruby-version: 3.2.2 bundler-cache: true - - name: Run tests and report test coverage + - name: Report rspec test coverage to coveralls.io run: COVERALLS_REPO_TOKEN=${{ secrets.COVERALLS_REPO_TOKEN }} bundle exec rspec diff --git a/README.md b/README.md index a57e069c..4a3e9959 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,16 @@ [![Gem Version][badge_fury_badge]][badge_fury_link] [![Downloads][downloads_badge]][downloads_link] -[![Build Status][semaphore_ci_badge]][semaphore_ci_link] -[![Coverage Status][coveralls_badge]][coveralls_link] -[![Code Climate][code_climate_badge]][code_climate_link] -[![Issue Count][code_climate_issues_badge]][code_climate_link] -[![Documentation Status][inch_ci_badge]][inch_ci_link] [![License][license_badge]][license_link] +[![Build Status][github_action_build_badge]][github_action_build_link] +[![Coverage Status][coveralls_badge]][coveralls_link] +[![Documentation Status][inch_ci_badge]][rubydoc] +[![CodeQL Status][github_action_codeql_badge]][github_action_codeql_link] + +[![Code Climate Grade][code_climate_grade_badge]][code_climate_link] +[![Code Climate Issue Count][code_climate_issues_badge]][code_climate_link] + The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse. ## Installing the Rambling Trie @@ -285,7 +288,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.3.0 [badge_fury_link]: https://badge.fury.io/rb/rambling-trie [chruby]: https://github.com/postmodern/chruby -[code_climate_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg +[code_climate_grade_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg [code_climate_issues_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/issue_count.svg [code_climate_link]: https://codeclimate.com/github/gonzedge/rambling-trie [coveralls_badge]: https://img.shields.io/coveralls/gonzedge/rambling-trie.svg @@ -294,9 +297,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [downloads_link]: https://rubygems.org/gems/rambling-trie [gemnasium_badge]: https://gemnasium.com/gonzedge/rambling-trie.svg [gemnasium_link]: https://gemnasium.com/gonzedge/rambling-trie +[github_action_build_badge]: https://github.com/gonzedge/rambling-trie/actions/workflows/ruby.yml/badge.svg +[github_action_build_link]: https://github.com/gonzedge/rambling-trie/actions/workflows/ruby.yml +[github_action_codeql_badge]: https://github.com/gonzedge/rambling-trie/actions/workflows/codeql.yml/badge.svg +[github_action_codeql_link]: https://github.com/gonzedge/rambling-trie/actions/workflows/codeql.yml [github_user_gonzedge]: https://github.com/gonzedge [inch_ci_badge]: https://inch-ci.org/github/gonzedge/rambling-trie.svg?branch=master -[inch_ci_link]: http://rubydoc.info/gems/rambling-trie [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg [license_link]: https://opensource.org/licenses/mit-license.php [marshal]: https://ruby-doc.org/core-2.7.0/Marshal.html @@ -308,7 +314,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI [rubydoc_github]: http://rubydoc.info/github/gonzedge/rambling-trie [rubyzip]: https://github.com/rubyzip/rubyzip [rvm]: https://rvm.io -[semaphore_ci_badge]: https://gonzedge.semaphoreci.com/badges/rambling-trie/branches/master.svg?style=shields&key=70cb32ae-6165-4aa1-92c0-1610cc4101ca -[semaphore_ci_link]: https://gonzedge.semaphoreci.com/projects/rambling-trie [trie_wiki]: https://en.wikipedia.org/wiki/Trie [yaml]: https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html From 6d8bba35fbff396f63a0622e82270f44ca2eab19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Tue, 9 May 2023 20:03:23 -0400 Subject: [PATCH 40/58] Add codeclimate coverage step to build GH action (#35) * Add codeclimate coverage step to build GH action * Do things differently for coveralls and code climate * Use correct shared example for `words_within?` on compressed tries --- .github/workflows/ruby.yml | 10 +++++++++- spec/lib/rambling/trie/container_spec.rb | 2 +- spec/spec_helper.rb | 20 +++++++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 157f699a..8ea0c3be 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -71,4 +71,12 @@ jobs: ruby-version: 3.2.2 bundler-cache: true - name: Report rspec test coverage to coveralls.io - run: COVERALLS_REPO_TOKEN=${{ secrets.COVERALLS_REPO_TOKEN }} bundle exec rspec + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + run: bundle exec rspec + - name: Report rspec test coverage to codeclimate.com + uses: paambaati/codeclimate-action@v4.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + with: + coverageCommand: bundle exec rspec diff --git a/spec/lib/rambling/trie/container_spec.rb b/spec/lib/rambling/trie/container_spec.rb index 534ad113..ad8c56d6 100644 --- a/spec/lib/rambling/trie/container_spec.rb +++ b/spec/lib/rambling/trie/container_spec.rb @@ -323,7 +323,7 @@ context 'with compressed node' do before { container.compress! } - it_behaves_like 'a matching container#words_within?' + it_behaves_like 'a non-matching container#words_within?' end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6bcd7948..61cd434b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,15 +1,21 @@ # frozen_string_literal: true +require 'yaml' require 'simplecov' -require 'coveralls' -SimpleCov.formatters = [ - SimpleCov::Formatter::HTMLFormatter, - Coveralls::SimpleCov::Formatter, -] +if ENV.key? 'COVERALLS_REPO_TOKEN' + require 'coveralls' -Coveralls.wear! do - add_filter '/spec/' + SimpleCov.formatters = [ + SimpleCov::Formatter::HTMLFormatter, + Coveralls::SimpleCov::Formatter, + ] + + Coveralls.wear! do + add_filter '/spec/' + end +else + SimpleCov.start end require 'rspec' From 7d7166d7e2acf5c7992c297015acb8972768a477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 13:50:42 -0400 Subject: [PATCH 41/58] Ensure all serializer `#dump` methods return the size of the file (#36) - Add test in `a serializer` shared examples - Implement method for `Rambling::Trie::Serializers::Zip` --- .gitignore | 3 ++- lib/rambling/trie/serializers/zip.rb | 2 ++ spec/support/shared_examples/a_serializer.rb | 13 +++++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index ec8b18a6..1ebba6fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ -# Vim +# Vim / IDEs *.swp *.swo +.idea/ # RVM .rvmrc diff --git a/lib/rambling/trie/serializers/zip.rb b/lib/rambling/trie/serializers/zip.rb index bf8ee68d..3629fc36 100644 --- a/lib/rambling/trie/serializers/zip.rb +++ b/lib/rambling/trie/serializers/zip.rb @@ -50,6 +50,8 @@ def dump contents, filepath zip.add filename, entry_path end + + ::File.size filepath end private diff --git a/spec/support/shared_examples/a_serializer.rb b/spec/support/shared_examples/a_serializer.rb index 71a046d0..c5e3a9d1 100644 --- a/spec/support/shared_examples/a_serializer.rb +++ b/spec/support/shared_examples/a_serializer.rb @@ -16,17 +16,22 @@ describe '#dump' do [true, false].each do |compress_value| context "with compressed=#{compress_value} trie" do - before do - trie.compress! if compress_value - serializer.dump content, filepath + let(:formatted_content) { format_content.call content } + + before { trie.compress! if compress_value } + + it 'returns the size in bytes of the file dumped' do + total_bytes = serializer.dump content, filepath + expect(total_bytes).to be_within(20).of formatted_content.size end it 'creates the file with the provided path' do + serializer.dump content, filepath expect(File.exist? filepath).to be true end it 'converts the contents to the appropriate format' do - formatted_content = format_content.call content + serializer.dump content, filepath expect(File.size filepath).to be_within(20).of formatted_content.size end end From 5afafa4884625e9c9c4001d59c7c91fee91c977b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 13:52:35 -0400 Subject: [PATCH 42/58] Ensure `#each`/`#each_word` return `Enumerator`/`self` (#37) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … depending on whether a block is given or not. --- lib/rambling/trie/enumerable.rb | 2 ++ lib/rambling/trie/readers/plain_text.rb | 6 +++++- spec/lib/rambling/trie/enumerable_spec.rb | 8 ++++++-- spec/lib/rambling/trie/readers/plain_text_spec.rb | 8 ++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/rambling/trie/enumerable.rb b/lib/rambling/trie/enumerable.rb index 64937547..4294e607 100644 --- a/lib/rambling/trie/enumerable.rb +++ b/lib/rambling/trie/enumerable.rb @@ -23,6 +23,8 @@ def each yield word end end + + self end end end diff --git a/lib/rambling/trie/readers/plain_text.rb b/lib/rambling/trie/readers/plain_text.rb index 8ab4142a..48ee263d 100644 --- a/lib/rambling/trie/readers/plain_text.rb +++ b/lib/rambling/trie/readers/plain_text.rb @@ -10,7 +10,11 @@ class PlainText # from. # @yield [String] Each line read from the file. def each_word filepath - File.foreach(filepath) { |line| yield line.chomp! } + return enum_for :each_word unless block_given? + + ::File.foreach(filepath) { |line| yield line.chomp! } + + self end end end diff --git a/spec/lib/rambling/trie/enumerable_spec.rb b/spec/lib/rambling/trie/enumerable_spec.rb index e8b4360e..5f67fbac 100644 --- a/spec/lib/rambling/trie/enumerable_spec.rb +++ b/spec/lib/rambling/trie/enumerable_spec.rb @@ -11,8 +11,8 @@ module Trie before { add_words node, words } describe '#each' do - it 'returns an enumerator' do - expect(node.each).to be_a Enumerator + it 'returns an enumerator when no block is given' do + expect(node.each).to be_an Enumerator end it 'has the same word count as the trie' do @@ -22,6 +22,10 @@ module Trie it 'includes every word contained in the trie' do node.each { |word| expect(words).to include word } end + + it 'returns the enumerable when a block is given' do + expect(node.each { |_| }).to eq node + end end describe '#size' do diff --git a/spec/lib/rambling/trie/readers/plain_text_spec.rb b/spec/lib/rambling/trie/readers/plain_text_spec.rb index 5151776d..55dee373 100644 --- a/spec/lib/rambling/trie/readers/plain_text_spec.rb +++ b/spec/lib/rambling/trie/readers/plain_text_spec.rb @@ -14,5 +14,13 @@ reader.each_word(filepath) { |word| yielded << word } expect(yielded).to eq words end + + it 'returns an enumerator when no block is given' do + expect(reader.each_word filepath).to be_an Enumerator + end + + it 'returns the enumerable when a block is given' do + expect(reader.each_word(filepath) { |_| }).to eq reader + end end end From 2e71b1fa3d127cd6cbd340f043c440c5c4b17e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 14:05:45 -0400 Subject: [PATCH 43/58] Improve API documentation (#38) - Add `Readers::Reader` and `Serializer::Serializer` base classes - Make all readers/serializers extend from their corresponding base classes - Better docs with `Reader`/`Serializer` and generics - Fix all code blocks from `\`` to `+` and add some more - Add `@return [void]` where appropriate - Add `@return [self]` where appropriate - Fix `Nodes::Node` duplicate and broken references - Fix some typos and add some missing periods --- lib/rambling/trie.rb | 20 ++++++----- lib/rambling/trie/comparable.rb | 4 +-- lib/rambling/trie/compressible.rb | 4 +-- lib/rambling/trie/configuration/properties.rb | 19 +++++----- .../trie/configuration/provider_collection.rb | 28 ++++++++------- lib/rambling/trie/container.rb | 35 +++++++++---------- lib/rambling/trie/enumerable.rb | 1 + lib/rambling/trie/nodes/compressed.rb | 6 ++-- lib/rambling/trie/nodes/node.rb | 22 ++++++------ lib/rambling/trie/nodes/raw.rb | 4 +-- lib/rambling/trie/readers.rb | 2 +- lib/rambling/trie/readers/plain_text.rb | 7 ++-- lib/rambling/trie/readers/reader.rb | 21 +++++++++++ lib/rambling/trie/serializers.rb | 2 +- lib/rambling/trie/serializers/file.rb | 2 +- lib/rambling/trie/serializers/marshal.rb | 5 +-- lib/rambling/trie/serializers/serializer.rb | 27 ++++++++++++++ lib/rambling/trie/serializers/yaml.rb | 5 +-- lib/rambling/trie/serializers/zip.rb | 12 ++++--- lib/rambling/trie/stringifyable.rb | 2 +- spec/lib/rambling/trie/readers/reader_spec.rb | 14 ++++++++ .../trie/serializers/serializer_spec.rb | 21 +++++++++++ 22 files changed, 177 insertions(+), 86 deletions(-) create mode 100644 lib/rambling/trie/readers/reader.rb create mode 100644 lib/rambling/trie/serializers/serializer.rb create mode 100644 spec/lib/rambling/trie/readers/reader_spec.rb create mode 100644 spec/lib/rambling/trie/serializers/serializer_spec.rb diff --git a/lib/rambling/trie.rb b/lib/rambling/trie.rb index 6909b157..858a6611 100644 --- a/lib/rambling/trie.rb +++ b/lib/rambling/trie.rb @@ -10,12 +10,12 @@ # General namespace for all Rambling gems. module Rambling - # Entry point for rambling-trie API. + # Entry point for +rambling-trie+ API. module Trie class << self - # Creates a new Rambling::Trie. Entry point for the Rambling::Trie API. + # Creates a new +Rambling::Trie+. Entry point for the +rambling-trie+ API. # @param [String, nil] filepath the file to load the words from. - # @param [Reader, nil] reader the file parser to get each word. + # @param [Readers::Reader, nil] reader the file parser to get each word. # @return [Container] the trie just created. # @yield [Container] the trie just created. # @see Rambling::Trie::Readers Readers. @@ -36,7 +36,7 @@ def create filepath = nil, reader = nil # Loads an existing trie from disk into memory. By default, it will # deduce the correct way to deserialize based on the file extension. - # Available formats are `yml`, `marshal`, and `zip` versions of all the + # Available formats are +yml+, +marshal+, and +zip+ versions of all the # previous formats. You can also define your own. # @param [String] filepath the file to load the words from. # @param [Serializer, nil] serializer the object responsible of loading @@ -46,7 +46,7 @@ def create filepath = nil, reader = nil # @see Rambling::Trie::Serializers Serializers. # @note Use of # {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load - # Marshal.load} is generally discouraged. Only use the `.marshal` + # Marshal.load} is generally discouraged. Only use the +.marshal+ # format with trusted input. def load filepath, serializer = nil serializer ||= serializers.resolve filepath @@ -58,19 +58,21 @@ def load filepath, serializer = nil # Dumps an existing trie from memory into disk. By default, it will # deduce the correct way to serialize based on the file extension. - # Available formats are `yml`, `marshal`, and `zip` versions of all the + # Available formats are +yml+, +marshal+, and +zip+ versions of all the # previous formats. You can also define your own. # @param [Container] trie the trie to dump into disk. # @param [String] filepath the file to dump to serialized trie into. - # @param [Serializer, nil] serializer the object responsible of + # @param [Serializers::Serializer, nil] serializer the object responsible + # for trie serialization. + # @return [void] # serializing and dumping the trie into disk. - # @see Rambling::Trie::Serializers Serializers. + # @see Serializers Serializers. def dump trie, filepath, serializer = nil serializer ||= serializers.resolve filepath serializer.dump trie.root, filepath end - # Provides configuration properties for the Rambling::Trie gem. + # Provides configuration properties for the +Rambling::Trie+ gem. # @return [Configuration::Properties] the configured properties of the # gem. # @yield [Configuration::Properties] the configured properties of the diff --git a/lib/rambling/trie/comparable.rb b/lib/rambling/trie/comparable.rb index 3a3b664d..e337a8a7 100644 --- a/lib/rambling/trie/comparable.rb +++ b/lib/rambling/trie/comparable.rb @@ -6,8 +6,8 @@ module Trie module Comparable # Compares two nodes. # @param [Nodes::Node] other the node to compare against. - # @return [Boolean] `true` if the nodes' {Nodes::Node#letter #letter} and - # {Nodes::Node#children_tree #children_tree} are equal, `false` + # @return [Boolean] +true+ if the nodes' {Nodes::Node#letter #letter} and + # {Nodes::Node#children_tree #children_tree} are equal, +false+ # otherwise. def == other letter == other.letter && diff --git a/lib/rambling/trie/compressible.rb b/lib/rambling/trie/compressible.rb index d685a7e4..463578af 100644 --- a/lib/rambling/trie/compressible.rb +++ b/lib/rambling/trie/compressible.rb @@ -6,8 +6,8 @@ module Trie module Compressible # Indicates if the current {Rambling::Trie::Nodes::Node Node} can be # compressed or not. - # @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} nodes - # with one child, `false` otherwise. + # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} nodes + # with one child, +false+ otherwise. def compressible? !(root? || terminal?) && 1 == children_tree.size end diff --git a/lib/rambling/trie/configuration/properties.rb b/lib/rambling/trie/configuration/properties.rb index 6ea7617a..1de51c90 100644 --- a/lib/rambling/trie/configuration/properties.rb +++ b/lib/rambling/trie/configuration/properties.rb @@ -6,26 +6,26 @@ module Configuration # Provides configurable properties for Rambling::Trie. class Properties # The configured {Readers Readers}. - # @return [ProviderCollection] the mapping of configured {Readers - # Readers}. + # @return [ProviderCollection] the mapping of + # configured {Readers Readers}. attr_reader :readers # The configured {Serializers Serializers}. - # @return [ProviderCollection] the mapping of configured {Serializers - # Serializers}. + # @return [ProviderCollection] the mapping of + # configured {Serializers Serializers}. attr_reader :serializers # The configured {Compressor Compressor}. # @return [Compressor] the configured compressor. attr_accessor :compressor - # The configured root_builder, which should return a {Nodes::Node Node} - # when called. - # @return [Proc] the configured root_builder. + # The configured +root_builder+, which returns a {Nodes::Node Node} + # when called. + # @return [Proc] the configured +root_builder+. attr_accessor :root_builder - # The configured tmp_path, which will be used for throwaway files. - # @return [String] the configured tmp_path. + # The configured +tmp_path+, which will be used for throwaway files. + # @return [String] the configured +tmp_path+. attr_accessor :tmp_path # Returns a new properties instance. @@ -34,6 +34,7 @@ def initialize end # Resets back to default properties. + # @return [void] def reset reset_readers reset_serializers diff --git a/lib/rambling/trie/configuration/provider_collection.rb b/lib/rambling/trie/configuration/provider_collection.rb index 27183c25..c0fcd936 100644 --- a/lib/rambling/trie/configuration/provider_collection.rb +++ b/lib/rambling/trie/configuration/provider_collection.rb @@ -6,7 +6,7 @@ module Configuration # Collection of configurable providers. class ProviderCollection # The name of this provider collection. - # @return [String] the name of this provider collection. + # @return [Symbol] the name of this provider collection. attr_reader :name # @overload default @@ -15,18 +15,18 @@ class ProviderCollection # @overload default=(provider) # Sets the default provider. Needs to be one of the configured # providers. - # @param [Object] provider the provider to use as default. + # @param [TProvider] provider the provider to use as default. # @raise [ArgumentError] when the given provider is not in the # provider collection. - # @note If no providers have been configured, `nil` will be assigned. - # @return [Object, nil] the default provider to use when a provider + # @note If no providers have been configured, +nil+ will be assigned. + # @return [TProvider, nil] the default provider to use when a provider # cannot be resolved in {ProviderCollection#resolve #resolve}. attr_reader :default # Creates a new provider collection. - # @param [String] name the name for this provider collection. - # @param [Hash] providers the configured providers. - # @param [Object] default the configured default provider. + # @param [Symbol] name the name for this provider collection. + # @param [Hash] providers the configured providers. + # @param [TProvider, nil] default the configured default provider. def initialize name, providers = {}, default = nil @name = name @configured_providers = providers @@ -38,8 +38,9 @@ def initialize name, providers = {}, default = nil # Adds a new provider to the provider collection. # @param [Symbol] extension the extension that the provider will # correspond to. - # @param [provider] provider the provider to add to the provider + # @param [TProvider] provider the provider to add to the provider # collection. + # @return [TProvider] the provider just added. def add extension, provider providers[extension] = provider end @@ -54,21 +55,22 @@ def default= provider end # List of configured providers. - # @return [Hash] the mapping of extensions to their corresponding - # providers. + # @return [Hash] the mapping of extensions to their + # corresponding providers. def providers @providers ||= {} end # Resolves the provider from a filepath based on the file extension. # @param [String] filepath the filepath to resolve into a provider. - # @return [Object] the provider corresponding to the file extension in - # this provider collection. {#default} if not found. + # @return [TProvider, nil] the provider for the given file's extension. + # {#default} if not found. def resolve filepath providers[file_format filepath] || default end # Resets the provider collection to the initial values. + # @return [void] def reset providers.clear configured_providers.each { |k, v| self[k] = v } @@ -85,7 +87,7 @@ def formats # Get provider corresponding to a given format. # @param [Symbol] format the format to search for in the collection. - # @return [Object] the provider corresponding to that format. + # @return [TProvider] the provider corresponding to that format. # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D # Hash#[] def [] format diff --git a/lib/rambling/trie/container.rb b/lib/rambling/trie/container.rb index d38801fb..da6c90e0 100644 --- a/lib/rambling/trie/container.rb +++ b/lib/rambling/trie/container.rb @@ -13,7 +13,7 @@ class Container # Creates a new trie. # @param [Nodes::Node] root the root node for the trie # @param [Compressor] compressor responsible for compressing the trie - # @yield [Container] the trie just created. + # @yield [self] the trie just initialized. def initialize root, compressor @root = root @compressor = compressor @@ -44,7 +44,7 @@ def concat words # Compresses the existing trie using redundant node elimination. Marks # the trie as compressed. Does nothing if the trie has already been # compressed. - # @return [Container] self + # @return [self] # @note This method replaces the root {Nodes::Raw Raw} node with a # {Nodes::Compressed Compressed} version of it. def compress! @@ -65,20 +65,18 @@ def compress # Checks if a path for a word or partial word exists in the trie. # @param [String] word the word or partial word to look for in the trie. - # @return [Boolean] `true` if the word or partial word is found, `false` + # @return [Boolean] +true+ if the word or partial word is found, +false+ # otherwise. - # @see Nodes::Raw#partial_word? - # @see Nodes::Compressed#partial_word? + # @see Nodes::Node#partial_word? def partial_word? word = '' root.partial_word? word.chars end # Checks if a whole word exists in the trie. # @param [String] word the word to look for in the trie. - # @return [Boolean] `true` only if the word is found and the last - # character corresponds to a terminal node, `false` otherwise. - # @see Nodes::Raw#word? - # @see Nodes::Compressed#word? + # @return [Boolean] +true+ only if the word is found and the last + # character corresponds to a terminal node, +false+ otherwise. + # @see Nodes::Node#word? def word? word = '' root.word? word.chars end @@ -87,8 +85,7 @@ def word? word = '' # @param [String] word the word to look for in the trie. # @return [Array] all the words contained in the trie that start # with the specified characters. - # @see Nodes::Raw#scan - # @see Nodes::Compressed#scan + # @see Nodes::Node#scan def scan word = '' root.scan(word.chars).to_a end @@ -99,15 +96,14 @@ def scan word = '' # @return [Enumerator] all the words in the given string that # match a word in the trie. # @yield [String] each word found in phrase. - # @see Nodes::Node#words_within def words_within phrase words_within_root(phrase).to_a end # Checks if there are any valid words in a given string. # @param [String] phrase the string to look for matching words in. - # @return [Boolean] `true` if any word within phrase is contained in the - # trie, `false` otherwise. + # @return [Boolean] +true+ if any word within phrase is contained in the + # trie, +false+ otherwise. # @see Container#words_within def words_within? phrase words_within_root(phrase).any? @@ -115,13 +111,14 @@ def words_within? phrase # Compares two trie data structures. # @param [Container] other the trie to compare against. - # @return [Boolean] `true` if the tries are equal, `false` otherwise. + # @return [Boolean] +true+ if the tries are equal, +false+ otherwise. def == other root == other.root end # Iterates over the words contained in the trie. # @yield [String] the words contained in this trie node. + # @return [self] def each return enum_for :each unless block_given? @@ -152,8 +149,8 @@ def children end # Root node's children tree. - # @return [Array] the array of children nodes contained in - # the root node. + # @return [Hash] the children tree hash contained in + # the root node, consisting of +:letter => node+. # @see Nodes::Node#children_tree def children_tree root.children_tree @@ -161,8 +158,8 @@ def children_tree # Indicates if the root {Nodes::Node Node} can be # compressed or not. - # @return [Boolean] `true` for non-{Nodes::Node#terminal? terminal} - # nodes with one child, `false` otherwise. + # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} + # nodes with one child, +false+ otherwise. def compressed? root.compressed? end diff --git a/lib/rambling/trie/enumerable.rb b/lib/rambling/trie/enumerable.rb index 4294e607..514a2bac 100644 --- a/lib/rambling/trie/enumerable.rb +++ b/lib/rambling/trie/enumerable.rb @@ -13,6 +13,7 @@ module Enumerable # Iterates over the words contained in the trie. # @yield [String] the words contained in this trie node. + # @return [self] def each return enum_for :each unless block_given? diff --git a/lib/rambling/trie/nodes/compressed.rb b/lib/rambling/trie/nodes/compressed.rb index 92ebb81b..859dc729 100644 --- a/lib/rambling/trie/nodes/compressed.rb +++ b/lib/rambling/trie/nodes/compressed.rb @@ -9,14 +9,14 @@ class Compressed < Rambling::Trie::Nodes::Node # trying to add a word to the current compressed trie node # @param [String] _ the word to add to the trie. # @raise [InvalidOperation] if the trie is already compressed. - # @return [nil] this never returns as it always raises an exception. + # @return [void] def add _ raise Rambling::Trie::InvalidOperation, 'Cannot add word to compressed trie' end - # Always return `true` for a compressed node. - # @return [Boolean] always `true` for a compressed node. + # Always return +true+ for a compressed node. + # @return [Boolean] always +true+ for a compressed node. def compressed? true end diff --git a/lib/rambling/trie/nodes/node.rb b/lib/rambling/trie/nodes/node.rb index c528dbac..b3f18a07 100644 --- a/lib/rambling/trie/nodes/node.rb +++ b/lib/rambling/trie/nodes/node.rb @@ -22,8 +22,8 @@ class Node attr_reader :letter # Child nodes tree. - # @return [Hash] the children_tree hash, consisting of `:letter => - # node`. + # @return [Hash] the children tree hash, consisting of + # +:letter => node+. attr_accessor :children_tree # Parent node. @@ -31,7 +31,7 @@ class Node attr_accessor :parent # Creates a new node. - # @param [Symbol, nil] letter the Node's letter value + # @param [Symbol, nil] letter the Node's letter value. # @param [Node, nil] parent the parent of the current node. def initialize letter = nil, parent = nil, children_tree = {} @letter = letter @@ -40,7 +40,7 @@ def initialize letter = nil, parent = nil, children_tree = {} end # Child nodes. - # @return [Array] the array of children nodes contained + # @return [Array] the array of child nodes contained # in the current node. def children children_tree.values @@ -57,14 +57,14 @@ def first_child end # Indicates if the current node is the root node. - # @return [Boolean] `true` if the node does not have a parent, `false` + # @return [Boolean] +true+ if the node does not have a parent, +false+ # otherwise. def root? !parent end # Indicates if a {Node Node} is terminal or not. - # @return [Boolean] `true` for terminal nodes, `false` otherwise. + # @return [Boolean] +true+ for terminal nodes, +false+ otherwise. def terminal? !!terminal end @@ -82,7 +82,7 @@ def letter= letter # Checks if a path for a set of characters exists in the trie. # @param [Array] chars the characters to look for in the trie. - # @return [Boolean] `true` if the characters are found, `false` + # @return [Boolean] +true+ if the characters are found, +false+ # otherwise. def partial_word? chars return true if chars.empty? @@ -92,8 +92,8 @@ def partial_word? chars # Checks if a path for set of characters represents a word in the trie. # @param [Array] chars the characters to look for in the trie. - # @return [Boolean] `true` if the characters are found and form a word, - # `false` otherwise. + # @return [Boolean] +true+ if the characters are found and form a word, + # +false+ otherwise. def word? chars = [] return terminal? if chars.empty? @@ -148,7 +148,7 @@ def []= letter, node # Check if a {Node Node}'s children tree contains a given # letter. # @param [Symbol] letter the letter to search for in the node. - # @return [Boolean] `true` if the letter is present, `false` otherwise + # @return [Boolean] +true+ if the letter is present, +false+ otherwise. # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F # Hash#key? def key? letter @@ -156,7 +156,7 @@ def key? letter end # Delete a given letter and its corresponding {Node Node} from - # this {Node Node}'s children tree. + # this {Node Node}'s children tree. # @param [Symbol] letter the letter to delete from the node's children # tree. # @return [Node] the node corresponding to the deleted letter. diff --git a/lib/rambling/trie/nodes/raw.rb b/lib/rambling/trie/nodes/raw.rb index 3a177e75..95f8a984 100644 --- a/lib/rambling/trie/nodes/raw.rb +++ b/lib/rambling/trie/nodes/raw.rb @@ -17,8 +17,8 @@ def add chars end end - # Always return `false` for a raw (uncompressed) node. - # @return [Boolean] always `false` for a raw (uncompressed) node. + # Always return +false+ for a raw (uncompressed) node. + # @return [Boolean] always +false+ for a raw (uncompressed) node. def compressed? false end diff --git a/lib/rambling/trie/readers.rb b/lib/rambling/trie/readers.rb index cd052f25..f5ed5f65 100644 --- a/lib/rambling/trie/readers.rb +++ b/lib/rambling/trie/readers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -%w(plain_text).each do |file| +%w(reader plain_text).each do |file| require File.join('rambling', 'trie', 'readers', file) end diff --git a/lib/rambling/trie/readers/plain_text.rb b/lib/rambling/trie/readers/plain_text.rb index 48ee263d..0ce62969 100644 --- a/lib/rambling/trie/readers/plain_text.rb +++ b/lib/rambling/trie/readers/plain_text.rb @@ -3,12 +3,13 @@ module Rambling module Trie module Readers - # File reader for .txt files. - class PlainText - # Yields each word read from a .txt file. + # File reader for +.txt+ files. + class PlainText < Reader + # Yields each word read from a +.txt+ file. # @param [String] filepath the full path of the file to load the words # from. # @yield [String] Each line read from the file. + # @return [self] def each_word filepath return enum_for :each_word unless block_given? diff --git a/lib/rambling/trie/readers/reader.rb b/lib/rambling/trie/readers/reader.rb new file mode 100644 index 00000000..b08f2ba0 --- /dev/null +++ b/lib/rambling/trie/readers/reader.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Rambling + module Trie + module Readers + # Base class for all readers. + class Reader + # Yields each word read from given file. + # @abstract Subclass and override {#each_word} to fit to a particular + # file format. + # @param [String] filepath the full path of the file to load the words + # from. + # @yield [String] Each line read from the file. + # @return [self] + def each_word filepath + raise NotImplementedError + end + end + end + end +end diff --git a/lib/rambling/trie/serializers.rb b/lib/rambling/trie/serializers.rb index 9c990bd1..bba09e96 100644 --- a/lib/rambling/trie/serializers.rb +++ b/lib/rambling/trie/serializers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -%w(file marshal yaml zip).each do |file| +%w(serializer file marshal yaml zip).each do |file| require File.join('rambling', 'trie', 'serializers', file) end diff --git a/lib/rambling/trie/serializers/file.rb b/lib/rambling/trie/serializers/file.rb index de5a1d8b..5fc6db22 100644 --- a/lib/rambling/trie/serializers/file.rb +++ b/lib/rambling/trie/serializers/file.rb @@ -4,7 +4,7 @@ module Rambling module Trie module Serializers # Basic file serializer. Dumps/loads string contents from files. - class File + class File < Serializer # Loads contents from a specified filepath. # @param [String] filepath the filepath to load contents from. # @return [String] all contents of the file. diff --git a/lib/rambling/trie/serializers/marshal.rb b/lib/rambling/trie/serializers/marshal.rb index 859dce3d..e1fb5d52 100644 --- a/lib/rambling/trie/serializers/marshal.rb +++ b/lib/rambling/trie/serializers/marshal.rb @@ -3,13 +3,14 @@ module Rambling module Trie module Serializers - # Serializer for Ruby marshal format (.marshal) files. - class Marshal + # Serializer for Ruby marshal format (+.marshal+) files. + class Marshal < Serializer # Creates a new Marshal serializer. # @param [Serializer] serializer the serializer responsible to write to # and read from disk. def initialize serializer = nil @serializer = serializer || Rambling::Trie::Serializers::File.new + super() end # Loads marshaled object from contents in filepath and deserializes it diff --git a/lib/rambling/trie/serializers/serializer.rb b/lib/rambling/trie/serializers/serializer.rb new file mode 100644 index 00000000..f9f961d4 --- /dev/null +++ b/lib/rambling/trie/serializers/serializer.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Rambling + module Trie + module Serializers + # Base class for all serializers. + class Serializer + # Loads contents from a specified filepath. + # @abstract Subclass and override {#load} to parse the desired format. + # @param [String] filepath the filepath to load contents from. + # @return [TContents] parsed contents from given file. + def load filepath + raise NotImplementedError + end + + # Dumps contents into a specified filepath. + # @abstract Subclass and override {#dump} to output the desired format. + # @param [TContents] contents the contents to dump into given file. + # @param [String] filepath the filepath to dump the contents to. + # @return [Numeric] number of bytes written to disk. + def dump contents, filepath + raise NotImplementedError + end + end + end + end +end diff --git a/lib/rambling/trie/serializers/yaml.rb b/lib/rambling/trie/serializers/yaml.rb index 28987d4b..cadd4cb2 100644 --- a/lib/rambling/trie/serializers/yaml.rb +++ b/lib/rambling/trie/serializers/yaml.rb @@ -3,13 +3,14 @@ module Rambling module Trie module Serializers - # Serializer for Ruby yaml format (.yaml) files. - class Yaml + # Serializer for Ruby yaml format (+.yaml+, or +.yml+) files. + class Yaml < Serializer # Creates a new Yaml serializer. # @param [Serializer] serializer the serializer responsible to write to # and read from disk. def initialize serializer = nil @serializer = serializer || Rambling::Trie::Serializers::File.new + super() end # Loads serialized object from YAML file in filepath and deserializes diff --git a/lib/rambling/trie/serializers/zip.rb b/lib/rambling/trie/serializers/zip.rb index 3629fc36..8c01f96b 100644 --- a/lib/rambling/trie/serializers/zip.rb +++ b/lib/rambling/trie/serializers/zip.rb @@ -3,20 +3,22 @@ module Rambling module Trie module Serializers - # Zip file serializer. Dumps/loads contents from zip files. Automatically - # detects if zip file contains `.marshal` or `.yml` file - class Zip + # Zip file serializer. Dumps/loads contents from +.zip+ files. + # Automatically detects if zip file contains a +.marshal+ or +.yml+ file, + # or any other registered +:format => serializer+ combo. + class Zip < Serializer # Creates a new Zip serializer. # @param [Configuration::Properties] properties the configuration # properties set up so far. def initialize properties @properties = properties + super() end # Unzip contents from specified filepath and load in contents from # unzipped files. # @param [String] filepath the filepath to load contents from. - # @return [String] all contents of the unzipped loaded file. + # @return [TContents] all contents of the unzipped loaded file. # @see https://github.com/rubyzip/rubyzip#reading-a-zip-file Zip # reading a file def load filepath @@ -35,7 +37,7 @@ def load filepath # Dumps contents and zips into a specified filepath. # @param [String] contents the contents to dump. # @param [String] filepath the filepath to dump the contents to. - # @return [Numeric] number of bytes written to disk. + # @return [TContents] number of bytes written to disk. # @see https://github.com/rubyzip/rubyzip#basic-zip-archive-creation # Zip archive creation def dump contents, filepath diff --git a/lib/rambling/trie/stringifyable.rb b/lib/rambling/trie/stringifyable.rb index 41aae797..0fb8d82f 100644 --- a/lib/rambling/trie/stringifyable.rb +++ b/lib/rambling/trie/stringifyable.rb @@ -2,7 +2,7 @@ module Rambling module Trie - # Provides the String representation behavior for the trie data structure. + # Provides the +String+ representation behavior for the trie data structure. module Stringifyable # String representation of the current node, if it is a terminal node. # @return [String] the string representation of the current node. diff --git a/spec/lib/rambling/trie/readers/reader_spec.rb b/spec/lib/rambling/trie/readers/reader_spec.rb new file mode 100644 index 00000000..14855b36 --- /dev/null +++ b/spec/lib/rambling/trie/readers/reader_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Rambling::Trie::Readers::Reader do + subject(:reader) { described_class.new } + + describe '#load' do + it 'is an abstract method that raises NotImplementedError' do + expect { reader.each_word('any-file.zip') } + .to raise_exception NotImplementedError + end + end +end diff --git a/spec/lib/rambling/trie/serializers/serializer_spec.rb b/spec/lib/rambling/trie/serializers/serializer_spec.rb new file mode 100644 index 00000000..3d547dd0 --- /dev/null +++ b/spec/lib/rambling/trie/serializers/serializer_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Rambling::Trie::Serializers::Serializer do + subject(:serializer) { described_class.new } + + describe '#load' do + it 'is an abstract method that raises NotImplementedError' do + expect { serializer.load('any-file.zip') } + .to raise_exception NotImplementedError + end + end + + describe '#dump' do + it 'is an abstract method that raises NotImplementedError' do + expect { serializer.dump('any contents', 'any-file.zip') } + .to raise_exception NotImplementedError + end + end +end From 8aea44544f66d2126669bc4d26f0726c4bc28368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 14:55:41 -0400 Subject: [PATCH 44/58] Add explicit changelog and docs urls to `.gemspec` (#39) Update `CHANGELOG.md` with latest changes. --- CHANGELOG.md | 93 ++++++++++++++++++++++++++++++++++++++++++- LICENSE | 2 +- rambling-trie.gemspec | 4 ++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba18ebf..8a22e6b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,71 @@ ## 2.3.1 [compare][compare_v2_3_0_and_master] +- Fix `Rambling::Trie.load` docs in README by [@gonzedge][github_user_gonzedge] +- Destructure args hash before passing to performance rake task by [@gonzedge][github_user_gonzedge] +- Update copyright years by [@gonzedge][github_user_gonzedge] +- Attempt to clear gem version badge being cached by GitHub (?) by [@gonzedge][github_user_gonzedge] +- Migrate from TravisCI to SemaphoreCI by [@gonzedge][github_user_gonzedge] +- Be more lax with file size tests ([#26][github_pull_26]) by [@gonzedge][github_user_gonzedge] +- Add missing `compress!` in container spec ([#25][github_pull_25]) by [@gonzedge][github_user_gonzedge] + - To actually test the non-matching tree shared example for compressed tries. +- Upgrade RuboCop and apply new rules ([#24][github_pull_24]) by [@gonzedge][github_user_gonzedge] + - Issues found in `lib/` and `tasks/` + 1. Explicitly disable `Style/ExplicitBlockArgument` due to resulting performance hits + 2. Add missing `super`s + 3. Yoda-style conditionals + 4. Bump target ruby required version to current min supported (`2.7.0`) + - Issues found in `spec/` + 1. Use `instance_double` instead of `double` + 2. Split tests into single-assertion specs when parameterization is possible; disable otherwise + 3. Use `let!` instead of instance variables + 4. Remove duplicate test groups + 5. Use `when` at the start of `context` block descriptions + 6. Use `described_class`, `subject` in specs where possible + 7. Single-line `before` where possible + - Other + 1. Explicitly add `rubocop-performance`, `rubocop-rake`, `rubocop-rspec` plugins + 2. Remove unused `Rails` rules + 3. Remove unused/deprecated `RSpec`/`Layout`/`Style`/`Lint` rules +- More thorough serializer tests ([#28][github_pull_28]) by [@gonzedge][github_user_gonzedge] + - Realized that, except for one integration test, we were not testing compressed tries being serialized so added some + more specific use cases. Also took the chance to expand the zip serializer spec to handle all formats. +- Update badges, CI and test/coverage reporting ([#29][github_pull_29]) by [@gonzedge][github_user_gonzedge] + - Correctly configure main task to publish test report, now being picked up by Semaphore + - On badges: + - Change `README.md` to have one badge per line instead of all in one giant line + - Add RubyGems downloads badge + - Add CodeClimate issues badge + - Update docs badge to point directly to [rubydoc.info/gems/rambling-trie][rubydoc] + - Update license badge to one from shields.io +- Use GitHub Actions for main branch and PR checks ([#30][github_pull_30], [#31][github_pull_31], [#32][github_pull_32]) + by [@gonzedge][github_user_gonzedge] + - Run `build` action with `lint` for `rubocop`, `spec` for `rspec`, `coverage` for `coveralls` + - Run `codeql` action + - Run `dependency-review` action only on pull requests +- Reduce semaphore config to latest ruby ([#33][github_pull_33]) by [@gonzedge][github_user_gonzedge] + - Now, we only care about top-level pass/fail for badge reporting. All other tests are run with GitHub Actions. +- Rename GitHub Actions and steps for better badges ([#34][github_pull_34]) by [@gonzedge][github_user_gonzedge] + - Plus reformat badges at top of `README.md`. +- Add CodeClimate coverage step to build GH action ([#35][github_pull_35]) by [@gonzedge][github_user_gonzedge] + - Do things differently for coveralls and code climate + - Use correct shared example for `words_within?` on compressed tries +- Ensure all serializer `#dump` methods return the size of the file ([#36][github_pull_36]) by [@gonzedge][github_user_gonzedge] + - Add test in `a serializer` shared examples + - Implement method for `Rambling::Trie::Serializers::Zip` +- Ensure `#each`/`#each_word` return `Enumerator`/`self` ([#37][github_pull_37]) by [@gonzedge][github_user_gonzedge] + - … depending on whether a block is given or not. +- Improve API documentation ([#38][github_pull_38]) by [@gonzedge][github_user_gonzedge] + - Add `Readers::Reader` and `Serializer::Serializer` base classes + - Make all readers/serializers extend from their corresponding base classes + - Better docs with `Reader`/`Serializer` and generics + - Fix all code blocks from `\`` to `+` and add some more + - Add `@return [void]` where appropriate + - Add `@return [self]` where appropriate + - Fix `Nodes::Node` duplicate and broken references + - Fix some typos and add some missing periods +- Add explicit changelog and docs urls to `.gemspec` ([#39][github_pull_39]) by [@gonzedge][github_user_gonzedge] + - Update `CHANGELOG.md` with latest changes + ## 2.3.0 [compare][compare_v2_2_1_and_v2_3_0] - Don't use `YAML.safe_load`'s legacy API by [@KitaitiMakoto][github_user_kitaitimakoto] @@ -25,7 +91,7 @@ ## 2.1.1 [compare][compare_v2_1_0_and_v2_1_1] -- Change `slice!` to `shift` by [@shinjiikeda][github_user_shinjiikeda] +- Change `slice!` to `shift` (#16) by [@shinjiikeda][github_user_shinjiikeda] - Frozen string issue fix by [@godsent][github_user_godsent] - Drop Ruby 2.4.x; add 2.7 and updated 2.6.x/2.5.x support by [@gonzedge][github_user_gonzedge] - Be more flexible with file sizes for zip file test by [@gonzedge][github_user_gonzedge] @@ -869,6 +935,30 @@ Most of these help with the gem's overall performance. [github_issue_09]: https://github.com/gonzedge/rambling-trie/issues/9 [github_issue_10]: https://github.com/gonzedge/rambling-trie/issues/10 [github_issue_11]: https://github.com/gonzedge/rambling-trie/issues/11 +[github_pull_16]: https://github.com/gonzedge/rambling-trie/pull/16 +[github_pull_17]: https://github.com/gonzedge/rambling-trie/pull/17 +[github_pull_18]: https://github.com/gonzedge/rambling-trie/pull/18 +[github_pull_19]: https://github.com/gonzedge/rambling-trie/pull/19 +[github_pull_20]: https://github.com/gonzedge/rambling-trie/pull/20 +[github_pull_21]: https://github.com/gonzedge/rambling-trie/pull/21 +[github_pull_22]: https://github.com/gonzedge/rambling-trie/pull/22 +[github_pull_23]: https://github.com/gonzedge/rambling-trie/pull/23 +[github_pull_24]: https://github.com/gonzedge/rambling-trie/pull/24 +[github_pull_25]: https://github.com/gonzedge/rambling-trie/pull/25 +[github_pull_26]: https://github.com/gonzedge/rambling-trie/pull/26 +[github_pull_27]: https://github.com/gonzedge/rambling-trie/pull/27 +[github_pull_28]: https://github.com/gonzedge/rambling-trie/pull/28 +[github_pull_29]: https://github.com/gonzedge/rambling-trie/pull/29 +[github_pull_30]: https://github.com/gonzedge/rambling-trie/pull/30 +[github_pull_31]: https://github.com/gonzedge/rambling-trie/pull/31 +[github_pull_32]: https://github.com/gonzedge/rambling-trie/pull/32 +[github_pull_33]: https://github.com/gonzedge/rambling-trie/pull/33 +[github_pull_34]: https://github.com/gonzedge/rambling-trie/pull/34 +[github_pull_35]: https://github.com/gonzedge/rambling-trie/pull/35 +[github_pull_36]: https://github.com/gonzedge/rambling-trie/pull/36 +[github_pull_37]: https://github.com/gonzedge/rambling-trie/pull/37 +[github_pull_38]: https://github.com/gonzedge/rambling-trie/pull/38 +[github_pull_39]: https://github.com/gonzedge/rambling-trie/pull/39 [github_user_agate]: https://github.com/agate [github_user_as181920]: https://github.com/as181920 [github_user_godsent]: https://github.com/godsent @@ -877,3 +967,4 @@ Most of these help with the gem's overall performance. [github_user_lilibethdlc]: https://github.com/lilibethdlc [github_user_shinjiikeda]: https://github.com/shinjiikeda [ruby_bug_13111]: https://bugs.ruby-lang.org/issues/13111 +[rubydoc]: http://rubydoc.info/gems/rambling-trie diff --git a/LICENSE b/LICENSE index c66251ce..00e7e519 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2017 Edgar Gonzalez +Copyright (c) 2012-2023 Edgar Gonzalez MIT License diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index b1e710be..0995a160 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -15,6 +15,10 @@ Gem::Specification.new do |gem| gem.summary = 'A Ruby implementation of the trie data structure.' gem.homepage = 'http://github.com/gonzedge/rambling-trie' gem.date = Time.now.strftime '%Y-%m-%d' + gem.metadata = { + 'changelog_uri' => 'https://github.com/gonzedge/rambling-trie/blob/master/CHANGELOG.md', + 'documentation_uri' => 'https://www.rubydoc.info/gems/rambling-trie', + } executables = `git ls-files -- bin/*`.split "\n" files = `git ls-files -- {lib,*file,*.gemspec,LICENSE*,README*}`.split "\n" From d4163ed2f93442acce2cfba3dcd62c45ebe988c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 15:09:24 -0400 Subject: [PATCH 45/58] Bump version to `2.3.1` for release (#40) --- CHANGELOG.md | 7 +++++-- lib/rambling/trie/version.rb | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a22e6b3..61c547eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -## 2.3.1 [compare][compare_v2_3_0_and_master] +## 2.3.2 [compare][compare_v2_3_1_and_master] + +## 2.3.1 [compare][compare_v2_3_0_and_v2_3_1] - Fix `Rambling::Trie.load` docs in README by [@gonzedge][github_user_gonzedge] - Destructure args hash before passing to performance rake task by [@gonzedge][github_user_gonzedge] @@ -921,7 +923,8 @@ Most of these help with the gem's overall performance. [compare_v2_1_1_and_v2_2_0]: https://github.com/gonzedge/rambling-trie/compare/v2.1.1...v2.2.0 [compare_v2_2_0_and_v2_2_1]: https://github.com/gonzedge/rambling-trie/compare/v2.2.0...v2.2.1 [compare_v2_2_1_and_v2_3_0]: https://github.com/gonzedge/rambling-trie/compare/v2.2.1...v2.3.0 -[compare_v2_3_0_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.3.0...master +[compare_v2_3_0_and_v2_3_1]: https://github.com/gonzedge/rambling-trie/compare/v2.3.0...v2.3.1 +[compare_v2_3_1_and_master]: https://github.com/gonzedge/rambling-trie/compare/v2.3.1...master [design_patterns_null_object]: http://wiki.c2.com/?NullObject [github_commit_current_key_less_memory]: https://github.com/gonzedge/rambling-trie/commit/218fac218a77e70ba04a3672ff5abfddf6544f57 [github_commit_reduced_memory_footprint]: https://github.com/gonzedge/rambling-trie/commit/aa8c0262f888e88df6a2f1e1351d8f14b21e43c4 diff --git a/lib/rambling/trie/version.rb b/lib/rambling/trie/version.rb index eab526e6..f112efb6 100644 --- a/lib/rambling/trie/version.rb +++ b/lib/rambling/trie/version.rb @@ -3,6 +3,6 @@ module Rambling module Trie # Current version of the rambling-trie. - VERSION = '2.3.0' + VERSION = '2.3.1' end end From 0e79ca8435c31a5e806742b1784116ea4970895d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 18:31:28 -0400 Subject: [PATCH 46/58] Bump badge URL to version 2.3.1 (#41) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a3e9959..d56ac401 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.3.0 +[badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.3.1 [badge_fury_link]: https://badge.fury.io/rb/rambling-trie [chruby]: https://github.com/postmodern/chruby [code_climate_grade_badge]: https://codeclimate.com/github/gonzedge/rambling-trie/badges/gpa.svg From e98dfbb4d96ddc52ec59977014aadcfa6245bbf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 23:07:43 -0400 Subject: [PATCH 47/58] Code inspections in `lib/` - use `%w` and `https` in gemspec (#45) And add explicit RubyMine `noinspection` comments for things that RuboCop already takes care of. --- lib/rambling/trie.rb | 3 +++ rambling-trie.gemspec | 4 ++-- spec/support/shared_examples/a_trie_node.rb | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/rambling/trie.rb b/lib/rambling/trie.rb index 858a6611..ddef6274 100644 --- a/lib/rambling/trie.rb +++ b/lib/rambling/trie.rb @@ -23,8 +23,10 @@ def create filepath = nil, reader = nil root = root_builder.call Rambling::Trie::Container.new root, compressor do |container| + # noinspection RubyMismatchedArgumentType if filepath reader ||= readers.resolve filepath + # noinspection RubyMismatchedArgumentType,RubyNilAnalysis reader.each_word filepath do |word| container << word end @@ -69,6 +71,7 @@ def load filepath, serializer = nil # @see Serializers Serializers. def dump trie, filepath, serializer = nil serializer ||= serializers.resolve filepath + # noinspection RubyNilAnalysis serializer.dump trie.root, filepath end diff --git a/rambling-trie.gemspec b/rambling-trie.gemspec index 0995a160..bb7f83e0 100644 --- a/rambling-trie.gemspec +++ b/rambling-trie.gemspec @@ -5,7 +5,7 @@ require 'rambling/trie/version' Gem::Specification.new do |gem| gem.authors = ['Edgar Gonzalez', 'Lilibeth De La Cruz'] - gem.email = ['edggonzalezg@gmail.com', 'lilibethdlc@gmail.com'] + gem.email = %w(edggonzalezg@gmail.com lilibethdlc@gmail.com) gem.description = <<~DESCRIPTION.gsub(%r{\s+}, ' ') The Rambling Trie is a Ruby implementation of the trie data structure, which @@ -13,7 +13,7 @@ Gem::Specification.new do |gem| DESCRIPTION gem.summary = 'A Ruby implementation of the trie data structure.' - gem.homepage = 'http://github.com/gonzedge/rambling-trie' + gem.homepage = 'https://github.com/gonzedge/rambling-trie' gem.date = Time.now.strftime '%Y-%m-%d' gem.metadata = { 'changelog_uri' => 'https://github.com/gonzedge/rambling-trie/blob/master/CHANGELOG.md', diff --git a/spec/support/shared_examples/a_trie_node.rb b/spec/support/shared_examples/a_trie_node.rb index 8179ed49..f008d30c 100644 --- a/spec/support/shared_examples/a_trie_node.rb +++ b/spec/support/shared_examples/a_trie_node.rb @@ -21,7 +21,8 @@ end context 'with a letter and a parent' do - let(:parent) { node.class.new } + let(:parent) { node_class.new } + # noinspection RubyArgCount let(:node_with_parent) { node_class.new :a, parent } it 'does not have any letter' do From 4ad3908a8bfe73cf994fd7cc87c59531ab77bf21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 23:25:47 -0400 Subject: [PATCH 48/58] Handle code inspections in `tasks/` (#44) - Rename `Helpers::{GC => GarbageCollection}` (and corresponding files) - Use symbols for hash `key?`/`has_key?`/`!![]` ips benchmark comparison --- tasks/helpers/{gc.rb => garbage_collection.rb} | 2 +- tasks/ips.rb | 12 ++++++------ tasks/performance/configuration.rb | 4 ++-- tasks/performance/reporters/reporter.rb | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) rename tasks/helpers/{gc.rb => garbage_collection.rb} (90%) diff --git a/tasks/helpers/gc.rb b/tasks/helpers/garbage_collection.rb similarity index 90% rename from tasks/helpers/gc.rb rename to tasks/helpers/garbage_collection.rb index 550402e6..da141a69 100644 --- a/tasks/helpers/gc.rb +++ b/tasks/helpers/garbage_collection.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Helpers - module GC + module GarbageCollection def with_gc_stats name = nil puts "Live objects before #{name} - #{::GC.stat[:heap_live_slots]}" yield diff --git a/tasks/ips.rb b/tasks/ips.rb index 7c5e6078..53ef5d3f 100644 --- a/tasks/ips.rb +++ b/tasks/ips.rb @@ -12,7 +12,7 @@ end task :hash_has_key_or_direct do - compare_hash_has_key_with_square_brackets + compare_has_key_with_square_brackets end task :attr_accessor_vs_def_method do @@ -83,20 +83,20 @@ def compare_symbols_with_array_hash_keys end end -def compare_hash_has_key_with_square_brackets +def compare_has_key_with_square_brackets compare do |bm| - hash = { 'thing' => 'gniht' } + hash = { thing: 'gniht' } bm.report 'key?' do - hash.key? 'thing' + hash.key? :thing end bm.report 'has_key?' do - hash.has_key? 'thing' + hash.has_key? :thing end bm.report '[]' do - !!hash['thing'] + !!hash[:thing] end end end diff --git a/tasks/performance/configuration.rb b/tasks/performance/configuration.rb index 686f7886..c4320470 100644 --- a/tasks/performance/configuration.rb +++ b/tasks/performance/configuration.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true require_relative '../helpers/trie' -require_relative '../helpers/gc' +require_relative '../helpers/garbage_collection' require_relative 'sub_tasks' require_relative 'reporters' module Performance class Configuration - include Helpers::GC + include Helpers::GarbageCollection def get type, method type ||= 'all' diff --git a/tasks/performance/reporters/reporter.rb b/tasks/performance/reporters/reporter.rb index c5ec1e92..958e26a0 100644 --- a/tasks/performance/reporters/reporter.rb +++ b/tasks/performance/reporters/reporter.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative '../../helpers/gc' +require_relative '../../helpers/garbage_collection' require_relative '../../helpers/path' require_relative '../../helpers/time' require_relative '../../helpers/trie' @@ -8,7 +8,7 @@ module Performance module Reporters class Reporter - include Helpers::GC + include Helpers::GarbageCollection include Helpers::Path include Helpers::Time From 57f58330d91bf12b4fc0572ee0e522d472b49ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 23:26:26 -0400 Subject: [PATCH 49/58] Use `RSpec::Config`'s `filter_run_when_matching` (#43) ... instead of deprecated `run_all_when_everything_filtered`. Also: - Use non-reserved words for file format and method name so that we are not accidentally shadowing important built-ins (`:format` => `:file_format`, `:method` => `:method_name`) - Explicitly assert any new `Node` is not a `#word?` by default after initialization - Remove unnecessary parens from let definitions in specs --- spec/integration/rambling/trie_spec.rb | 8 +++---- .../configuration/provider_collection_spec.rb | 14 ++++++------ spec/lib/rambling/trie/container_spec.rb | 8 +++---- .../rambling/trie/nodes/compressed_spec.rb | 6 +++++ spec/lib/rambling/trie/nodes/raw_spec.rb | 10 +++++---- .../rambling/trie/serializers/file_spec.rb | 2 +- .../rambling/trie/serializers/marshal_spec.rb | 2 +- .../rambling/trie/serializers/yaml_spec.rb | 2 +- .../lib/rambling/trie/serializers/zip_spec.rb | 8 +++---- spec/lib/rambling/trie_spec.rb | 22 +++++++++---------- spec/spec_helper.rb | 2 +- .../shared_examples/a_container_word.rb | 6 ++--- .../shared_examples/a_serializable_trie.rb | 2 +- spec/support/shared_examples/a_serializer.rb | 6 +++-- spec/support/shared_examples/a_trie_node.rb | 2 +- 15 files changed, 55 insertions(+), 45 deletions(-) diff --git a/spec/integration/rambling/trie_spec.rb b/spec/integration/rambling/trie_spec.rb index 7b162f5f..998a078e 100644 --- a/spec/integration/rambling/trie_spec.rb +++ b/spec/integration/rambling/trie_spec.rb @@ -18,7 +18,7 @@ context 'when provided with words with unicode characters' do it_behaves_like 'a compressible trie' do let(:trie) { described_class.create } - let(:words) do + let :words do %w(poquísimas palabras para nuestra prueba de integración completa 🙃) end @@ -50,14 +50,14 @@ context 'when serialized with Ruby marshal format (default)' do it_behaves_like 'a serializable trie' do let(:trie_to_serialize) { described_class.create words_filepath } - let(:format) { :marshal } + let(:file_format) { :marshal } end end context 'when serialized with YAML' do it_behaves_like 'a serializable trie' do let(:trie_to_serialize) { described_class.create words_filepath } - let(:format) { :yml } + let(:file_format) { :yml } end end @@ -77,7 +77,7 @@ it_behaves_like 'a serializable trie' do let(:trie_to_serialize) { described_class.create words_filepath } - let(:format) { 'marshal.zip' } + let(:file_format) { 'marshal.zip' } end end end diff --git a/spec/lib/rambling/trie/configuration/provider_collection_spec.rb b/spec/lib/rambling/trie/configuration/provider_collection_spec.rb index f725febc..cc1d6e6b 100644 --- a/spec/lib/rambling/trie/configuration/provider_collection_spec.rb +++ b/spec/lib/rambling/trie/configuration/provider_collection_spec.rb @@ -4,18 +4,18 @@ describe Rambling::Trie::Configuration::ProviderCollection do let(:configured_default) { nil } - let(:configured_providers) do + let :configured_providers do { one: first_provider, two: second_provider } end - let(:first_provider) do + let :first_provider do instance_double 'Rambling::Trie::Serializers::Marshal', :first_provider end - let(:second_provider) do + let :second_provider do instance_double 'Rambling::Trie::Serializers::Marshal', :second_provider end - let(:provider_collection) do + let :provider_collection do described_class.new( :provider, configured_providers, @@ -72,7 +72,7 @@ end describe '#add' do - let(:provider) do + let :provider do instance_double 'Rambling::Trie::Serializers::Marshal', :provider end @@ -86,7 +86,7 @@ end describe '#default=' do - let(:other_provider) do + let :other_provider do instance_double 'Rambling::Trie::Serializers::Marshal', :other_provider end @@ -155,7 +155,7 @@ describe '#reset' do let(:configured_default) { second_provider } - let(:provider) do + let :provider do instance_double 'Rambling::Trie::Serializers::Marshal', :provider end diff --git a/spec/lib/rambling/trie/container_spec.rb b/spec/lib/rambling/trie/container_spec.rb index ad8c56d6..71677268 100644 --- a/spec/lib/rambling/trie/container_spec.rb +++ b/spec/lib/rambling/trie/container_spec.rb @@ -171,7 +171,7 @@ describe '#word?' do it_behaves_like 'a propagating node' do - let(:method) { :word? } + let(:method_name) { :word? } end context 'when word is contained' do @@ -202,7 +202,7 @@ describe '#partial_word?' do context 'with underlying node' do it_behaves_like 'a propagating node' do - let(:method) { :partial_word? } + let(:method_name) { :partial_word? } end end @@ -329,7 +329,7 @@ describe '#==' do context 'when the root nodes are the same' do - let(:other_container) do + let :other_container do described_class.new container.root, compressor end @@ -340,7 +340,7 @@ context 'when the root nodes are not the same' do let(:other_root) { Rambling::Trie::Nodes::Raw.new } - let(:other_container) do + let :other_container do described_class.new other_root, compressor end diff --git a/spec/lib/rambling/trie/nodes/compressed_spec.rb b/spec/lib/rambling/trie/nodes/compressed_spec.rb index 4be02140..593a74bd 100644 --- a/spec/lib/rambling/trie/nodes/compressed_spec.rb +++ b/spec/lib/rambling/trie/nodes/compressed_spec.rb @@ -7,6 +7,12 @@ let(:compressor) { Rambling::Trie::Compressor.new } let(:node) { compressor.compress raw_node } + describe '#new' do + it 'is not a word' do + expect(node).not_to be_word + end + end + it_behaves_like 'a trie node implementation' do def add_word_to_tree word add_word raw_node, word diff --git a/spec/lib/rambling/trie/nodes/raw_spec.rb b/spec/lib/rambling/trie/nodes/raw_spec.rb index 74ea13b3..a4610bb6 100644 --- a/spec/lib/rambling/trie/nodes/raw_spec.rb +++ b/spec/lib/rambling/trie/nodes/raw_spec.rb @@ -5,6 +5,12 @@ describe Rambling::Trie::Nodes::Raw do let(:node) { described_class.new } + describe '#new' do + it 'is not a word' do + expect(node).not_to be_word + end + end + it_behaves_like 'a trie node implementation' do def add_word_to_tree word add_word node, word @@ -17,10 +23,6 @@ def add_words_to_tree words def assign_letter letter node.letter = letter end - - it 'is not a word' do - expect(node).not_to be_word - end end describe '#compressed?' do diff --git a/spec/lib/rambling/trie/serializers/file_spec.rb b/spec/lib/rambling/trie/serializers/file_spec.rb index d813b0b0..052442f0 100644 --- a/spec/lib/rambling/trie/serializers/file_spec.rb +++ b/spec/lib/rambling/trie/serializers/file_spec.rb @@ -4,7 +4,7 @@ describe Rambling::Trie::Serializers::File do it_behaves_like 'a serializer' do - let(:format) { :file } + let(:file_format) { :file } let(:content) { trie.to_a.join ' ' } let(:format_content) { ->(content) { content } } end diff --git a/spec/lib/rambling/trie/serializers/marshal_spec.rb b/spec/lib/rambling/trie/serializers/marshal_spec.rb index e462ba39..c8fcaf6f 100644 --- a/spec/lib/rambling/trie/serializers/marshal_spec.rb +++ b/spec/lib/rambling/trie/serializers/marshal_spec.rb @@ -4,7 +4,7 @@ describe Rambling::Trie::Serializers::Marshal do it_behaves_like 'a serializer' do - let(:format) { :marshal } + let(:file_format) { :marshal } let(:format_content) { Marshal.method(:dump) } end end diff --git a/spec/lib/rambling/trie/serializers/yaml_spec.rb b/spec/lib/rambling/trie/serializers/yaml_spec.rb index a1c7ee59..0cedcb17 100644 --- a/spec/lib/rambling/trie/serializers/yaml_spec.rb +++ b/spec/lib/rambling/trie/serializers/yaml_spec.rb @@ -4,7 +4,7 @@ describe Rambling::Trie::Serializers::Yaml do it_behaves_like 'a serializer' do - let(:format) { :yml } + let(:file_format) { :yml } let(:format_content) { YAML.method(:dump) } end end diff --git a/spec/lib/rambling/trie/serializers/zip_spec.rb b/spec/lib/rambling/trie/serializers/zip_spec.rb index 0833e9c4..71cc915e 100644 --- a/spec/lib/rambling/trie/serializers/zip_spec.rb +++ b/spec/lib/rambling/trie/serializers/zip_spec.rb @@ -8,14 +8,14 @@ yml: YAML.method(:dump), marshal: Marshal.method(:dump), file: Marshal.method(:dump), - }.each do |format, dump_method| - context "with '.#{format}'" do + }.each do |file_format, dump_method| + context "with '.#{file_format}'" do it_behaves_like 'a serializer' do let(:properties) { Rambling::Trie::Configuration::Properties.new } let(:serializer) { described_class.new properties } - let(:format) { :zip } + let(:file_format) { :zip } - let(:filepath) { File.join tmp_path, "trie-root.#{format}.zip" } + let(:filepath) { File.join tmp_path, "trie-root.#{file_format}.zip" } let(:format_content) { ->(content) { zip dump_method.call content } } let(:filename) { File.basename(filepath).gsub %r{\.zip}, '' } diff --git a/spec/lib/rambling/trie_spec.rb b/spec/lib/rambling/trie_spec.rb index 45879335..84068672 100644 --- a/spec/lib/rambling/trie_spec.rb +++ b/spec/lib/rambling/trie_spec.rb @@ -28,14 +28,14 @@ context 'with a filepath' do let(:filepath) { 'a test filepath' } - let(:reader) do + let :reader do instance_double 'Rambling::Trie::Readers::PlainText', :reader end let(:words) { %w(a couple of test words over here) } before do receive_and_yield = receive(:each_word) - words.inject(receive_and_yield) do |yielder, word| + words.inject receive_and_yield do |yielder, word| yielder.and_yield word end @@ -54,7 +54,7 @@ context 'without any reader' do let(:filepath) { 'a test filepath' } - let(:reader) do + let :reader do instance_double( 'Rambling::Trie::Readers::PlainText', :reader, @@ -82,7 +82,7 @@ let(:root) { Rambling::Trie::Nodes::Raw.new } let(:compressor) { Rambling::Trie::Compressor.new } let(:container) { Rambling::Trie::Container.new root, compressor } - let(:serializer) do + let :serializer do instance_double( 'Rambling::True::Serializers::File', :serializer, @@ -101,21 +101,21 @@ end context 'without a serializer' do - let(:marshal_serializer) do + let :marshal_serializer do instance_double( 'Rambling::Trie::Serializers::Marshal', :marshal_serializer, load: nil, ) end - let(:default_serializer) do + let :default_serializer do instance_double( 'Rambling::Trie::Serializers::File', :default_serializer, load: nil, ) end - let(:yaml_serializer) do + let :yaml_serializer do instance_double( 'Rambling::Trie::Serializers::Yaml', :yaml_serializer, @@ -168,26 +168,26 @@ describe '.dump' do let(:filename) { 'a trie' } let(:root) { instance_double 'Rambling::Trie::Serializers::Marshal', :root } - let(:compressor) do + let :compressor do instance_double 'Rambling::Trie::Serializers::Marshal', :compressor end let(:trie) { Rambling::Trie::Container.new root, compressor } - let(:marshal_serializer) do + let :marshal_serializer do instance_double( 'Rambling::Trie::Serializers::Marshal', :marshal_serializer, dump: nil, ) end - let(:yaml_serializer) do + let :yaml_serializer do instance_double( 'Rambling::Trie::Serializers::Yaml', :yaml_serializer, dump: nil, ) end - let(:default_serializer) do + let :default_serializer do instance_double( 'Rambling::Trie::Serializers::File', :default_serializer, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 61cd434b..79c37e65 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -27,7 +27,7 @@ config.tty = true config.formatter = :documentation config.order = :random - config.run_all_when_everything_filtered = true + config.filter_run_when_matching :focus config.raise_errors_for_deprecations! end diff --git a/spec/support/shared_examples/a_container_word.rb b/spec/support/shared_examples/a_container_word.rb index de4a2d58..fb33bfc0 100644 --- a/spec/support/shared_examples/a_container_word.rb +++ b/spec/support/shared_examples/a_container_word.rb @@ -24,7 +24,7 @@ compressed_value, instance_double_class = test_params context "when root has compressed=#{compressed_value}" do - let(:root) do + let :root do instance_double( instance_double_class, :root, @@ -35,8 +35,8 @@ end it 'calls the root with the word characters' do - container.public_send method, 'words' - expect(root).to have_received(method).with %w(w o r d s) + container.public_send method_name, 'words' + expect(root).to have_received(method_name).with %w(w o r d s) end end end diff --git a/spec/support/shared_examples/a_serializable_trie.rb b/spec/support/shared_examples/a_serializable_trie.rb index 031523c8..838cb3af 100644 --- a/spec/support/shared_examples/a_serializable_trie.rb +++ b/spec/support/shared_examples/a_serializable_trie.rb @@ -2,7 +2,7 @@ shared_examples_for 'a serializable trie' do let(:tmp_path) { File.join ::SPEC_ROOT, 'tmp' } - let(:filepath) { File.join tmp_path, "trie-root.#{format}" } + let(:filepath) { File.join tmp_path, "trie-root.#{file_format}" } context 'with an uncompressed trie' do before { Rambling::Trie.dump trie_to_serialize, filepath } diff --git a/spec/support/shared_examples/a_serializer.rb b/spec/support/shared_examples/a_serializer.rb index c5e3a9d1..4b7882fd 100644 --- a/spec/support/shared_examples/a_serializer.rb +++ b/spec/support/shared_examples/a_serializer.rb @@ -5,7 +5,7 @@ let(:trie) { Rambling::Trie.create } let(:tmp_path) { File.join ::SPEC_ROOT, 'tmp' } - let(:filepath) { File.join tmp_path, "trie-root.#{format}" } + let(:filepath) { File.join tmp_path, "trie-root.#{file_format}" } let(:content) { trie.root } before do @@ -52,7 +52,9 @@ it "loads a compressed=#{compress_value} object" do loaded = serializer.load filepath - expect(loaded.compressed?).to be compress_value if :file != format + if :file != file_format + expect(loaded.compressed?).to be compress_value + end end end end diff --git a/spec/support/shared_examples/a_trie_node.rb b/spec/support/shared_examples/a_trie_node.rb index f008d30c..c6a867c5 100644 --- a/spec/support/shared_examples/a_trie_node.rb +++ b/spec/support/shared_examples/a_trie_node.rb @@ -72,7 +72,7 @@ end describe 'delegates and aliases' do - let(:children_tree) do + let :children_tree do instance_double( 'Hash', :children_tree, From 91da3442ff6e451181bd7c41a3bba830fd0c6951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 23:26:52 -0400 Subject: [PATCH 50/58] Use `@return [self]` in `Node#terminal!` rubydoc (#42) Follow-up to #38. Also fixes typos in `CHANGELOG.md` and `CONTRIBUTING.md`. --- CHANGELOG.md | 6 +++--- CONTRIBUTING.md | 8 ++++---- lib/rambling/trie/nodes/node.rb | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61c547eb..6c5300c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -171,7 +171,7 @@ Most of these help with the gem's overall performance. - Define delegate methods explicitly and remove dependency on `Forwardable` by [@gonzedge][github_user_gonzedge] - Reverse char array and use `#pop` instead of slice when adding a word by [@gonzedge][github_user_gonzedge] - Pull `#scan` up to `Node` by [@gonzedge][github_user_gonzedge] -- Slightly reduce memeory for `Properties` and `ProviderCollection` classes by [@gonzedge][github_user_gonzedge] +- Slightly reduce memory for `Properties` and `ProviderCollection` classes by [@gonzedge][github_user_gonzedge] - Use `#children_tree` instead of `#children` when possible by [@gonzedge][github_user_gonzedge] - Remove unnecessary assignment in `#letter=` by [@gonzedge][github_user_gonzedge] - Use `#each_value` instead of `#values`.`#each` in `Enumerable#each` by [@gonzedge][github_user_gonzedge] @@ -345,7 +345,7 @@ Most of these help with the gem's overall performance. [@gonzedge][github_user_gonzedge] - Add missing docs by [@gonzedge][github_user_gonzedge] - Improvements on TravisCI setup by [@gonzedge][github_user_gonzedge] -- Add codeclimate test coverage integration by +- Add CodeClimate test coverage integration by [@gonzedge][github_user_gonzedge] - Move rspec config from .rspec to spec_helper by [@gonzedge][github_user_gonzedge] @@ -727,7 +727,7 @@ Most of these help with the gem's overall performance. - Add guard to Gemfile by [@gonzedge][github_user_gonzedge] - Add simplecov for code coverage by [@gonzedge][github_user_gonzedge] - Refactor rambling-trie requires by [@gonzedge][github_user_gonzedge] -- Remov unnecessary internal `#trie_node` by [@gonzedge][github_user_gonzedge] +- Remove unnecessary internal `#trie_node` by [@gonzedge][github_user_gonzedge] - Refactor specs to "The RSpec Way" by [@gonzedge][github_user_gonzedge] - Add new benchmarking report info by [@gonzedge][github_user_gonzedge] - Update RubyDoc.info link and compression info by [@gonzedge][github_user_gonzedge] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb7a8aa8..56220ef8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,16 @@ ## Contributing to Rambling Trie 1. If you have found a bug or have a feature request, please [search through the issues][github_issues_all] to see if it has already been reported. If that's not the case, then [create a new one][github_issues_new] with a full description of what you have found or what you need. -1. If you have bug fix or a feature implementation in mind, then [fork Rambling Trie][github_fork] and create a branch with a descriptive name. -1. Get the gem up and running locally (tests are written in RSpec): +2. If you have bug fix or a feature implementation in mind, then [fork Rambling Trie][github_fork] and create a branch with a descriptive name. +3. Get the gem up and running locally (tests are written in RSpec): ```sh bundle install rake ``` -1. Implement your bug fix or feature - ***make sure to add tests!*** -1. [Make a Pull Request][github_pull_request] +4. Implement your bug fix or feature - ***make sure to add tests!*** +5. [Make a Pull Request][github_pull_request] Before doing so: diff --git a/lib/rambling/trie/nodes/node.rb b/lib/rambling/trie/nodes/node.rb index b3f18a07..46cfef54 100644 --- a/lib/rambling/trie/nodes/node.rb +++ b/lib/rambling/trie/nodes/node.rb @@ -70,7 +70,7 @@ def terminal? end # Mark {Node Node} as terminal. - # @return [Node] the modified node. + # @return [self] the modified node. def terminal! self.terminal = true self From 3eba897a4dc21c1b146bd79d387d607551c3a3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Thu, 11 May 2023 23:52:53 -0400 Subject: [PATCH 51/58] Update `CallTreeProfiler` to use new `RubyProf::Profiler` format (#46) Plus: - More accurate `pop`/`shift`/`slice!` reporting - Only require `benchmark/ips` when necessary - One-liner blocks --- tasks/ips.rb | 22 ++++++------------- tasks/performance.rb | 2 -- tasks/performance/reporters/benchmark.rb | 4 +--- .../reporters/call_tree_profile.rb | 14 +++++------- tasks/performance/reporters/flamegraph.rb | 6 +---- tasks/performance/reporters/memory_profile.rb | 6 +---- 6 files changed, 15 insertions(+), 39 deletions(-) diff --git a/tasks/ips.rb b/tasks/ips.rb index 53ef5d3f..5ea1142c 100644 --- a/tasks/ips.rb +++ b/tasks/ips.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'benchmark/ips' - namespace :ips do task :pop_shift_slice do compare_pop_shift_slice @@ -33,6 +31,7 @@ end def compare + require 'benchmark/ips' Benchmark.ips do |bm| yield bm @@ -43,21 +42,14 @@ def compare def compare_pop_shift_slice compare do |bm| a = [] + bm.report('push') { a.push 1 } + bm.report('pop') { a.pop } - bm.report 'push/pop' do - a.push 1 - a.pop - end + bm.report('unshift') { a.unshift 1 } + bm.report('shift') { a.shift } - bm.report 'unshift/shift' do - a.unshift 1 - a.shift - end - - bm.report 'shovel(<<)/slice!(0)' do - a << 1 - a.slice! 0 - end + bm.report('shovel(<<)') { a << 1 } + bm.report('slice!(0)') { a.slice! 0 } end end diff --git a/tasks/performance.rb b/tasks/performance.rb index 5d06fd23..da5d375f 100644 --- a/tasks/performance.rb +++ b/tasks/performance.rb @@ -10,8 +10,6 @@ dependencies = %i(serialization:regenerate performance:directory) task :performance, arg_names => dependencies do |_, args| - require 'benchmark/ips' - configuration = Performance::Configuration.new task = Performance::Task.new configuration task.run(**args) diff --git a/tasks/performance/reporters/benchmark.rb b/tasks/performance/reporters/benchmark.rb index 145adbe1..4d3f1c53 100644 --- a/tasks/performance/reporters/benchmark.rb +++ b/tasks/performance/reporters/benchmark.rb @@ -30,9 +30,7 @@ def measure iterations, param require 'benchmark' measure = ::Benchmark.measure do - iterations.times do - result = yield param - end + iterations.times { result = yield param } end output.puts result.to_s.ljust 10 diff --git a/tasks/performance/reporters/call_tree_profile.rb b/tasks/performance/reporters/call_tree_profile.rb index bd102a77..b7d4c0c5 100644 --- a/tasks/performance/reporters/call_tree_profile.rb +++ b/tasks/performance/reporters/call_tree_profile.rb @@ -14,15 +14,11 @@ def do_report iterations, params FileUtils.mkdir_p dirpath require 'ruby-prof' - result = RubyProf.profile merge_fibers: true do - params.each do |param| - iterations.times do - yield param - end - end - end - - printer = RubyProf::CallTreePrinter.new result + profile = RubyProf::Profile.new + profile.profile { params.each { |p| iterations.times { yield p } } } + profile.merge! + + printer = RubyProf::CallTreePrinter.new profile printer.print path: dirpath end diff --git a/tasks/performance/reporters/flamegraph.rb b/tasks/performance/reporters/flamegraph.rb index 9b88565f..9493eac7 100644 --- a/tasks/performance/reporters/flamegraph.rb +++ b/tasks/performance/reporters/flamegraph.rb @@ -15,11 +15,7 @@ def do_report iterations, params require 'flamegraph' ::Flamegraph.generate filepath do - params.each do |param| - iterations.times do - yield param - end - end + params.each { |p| iterations.times { yield p } } end end diff --git a/tasks/performance/reporters/memory_profile.rb b/tasks/performance/reporters/memory_profile.rb index 0e35be54..e191f967 100644 --- a/tasks/performance/reporters/memory_profile.rb +++ b/tasks/performance/reporters/memory_profile.rb @@ -19,11 +19,7 @@ def do_report iterations, params ignore_files: 'lib/rambling/trie/tasks', ) do with_gc_stats "performing #{filename}" do - params.each do |param| - iterations.times do - yield param - end - end + params.each { |p| iterations.times { yield p } } end end From 91ee8b2a098bcf1f9721c700b7c408b515dc11d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Fri, 12 May 2023 00:23:01 -0400 Subject: [PATCH 52/58] Add version specs to ensure `README/CHANGELOG` update before release (#47) --- spec/integration/rambling/trie_spec.rb | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spec/integration/rambling/trie_spec.rb b/spec/integration/rambling/trie_spec.rb index 998a078e..df07afbe 100644 --- a/spec/integration/rambling/trie_spec.rb +++ b/spec/integration/rambling/trie_spec.rb @@ -6,6 +6,34 @@ describe Rambling::Trie do let(:assets_path) { File.join ::SPEC_ROOT, 'assets' } + describe '::VERSION' do + let(:root_path) { File.join ::SPEC_ROOT, '..' } + let(:readme_path) { File.join root_path, 'README.md' } + let(:readme) { File.read readme_path } + let(:changelog_path) { File.join root_path, 'CHANGELOG.md' } + let(:changelog) { File.read changelog_path } + + it 'matches with the version in the README badge' do + match = %r{\?version=(?.*)$}.match readme + expect(match['version']).to eq Rambling::Trie::VERSION + end + + it 'is the version before the one at the top of the CHANGELOG' do + match = %r{## (?\d+\.\d+\.\d+)}.match changelog.split("\n")[0] + changelog_version = Gem::Version.new match['version'] + lib_version = Gem::Version.new "#{Rambling::Trie::VERSION}.0" + expect(changelog_version).to eq lib_version.bump + end + + it 'is included in the CHANGELOG diffs' do + matches = Set.new + changelog.scan %r{^## (\d+\.\d+\.\d+)} do |match| + matches << match[0] + end + expect(matches).to include Rambling::Trie::VERSION + end + end + context 'when providing words directly' do it_behaves_like 'a compressible trie' do let(:trie) { described_class.create } From dc7cb1744969a1acced44e6909cfd876c2c62aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Fri, 12 May 2023 00:35:57 -0400 Subject: [PATCH 53/58] Exclude `spec/` from `simplecov` coverage (#48) ... by using the same filter as we use for `Coveralls.wear!` --- spec/spec_helper.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 79c37e65..7a4dd7e1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,8 @@ require 'yaml' require 'simplecov' +COVERAGE_FILTER = %r{/spec/}.freeze + if ENV.key? 'COVERALLS_REPO_TOKEN' require 'coveralls' @@ -11,11 +13,9 @@ Coveralls::SimpleCov::Formatter, ] - Coveralls.wear! do - add_filter '/spec/' - end + Coveralls.wear! { add_filter COVERAGE_FILTER } else - SimpleCov.start + SimpleCov.start { add_filter COVERAGE_FILTER } end require 'rspec' From e93c75550809befb0fcfcf05c0c5a3e08ff2c3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Mon, 15 May 2023 13:47:34 -0400 Subject: [PATCH 54/58] Add CodeClimate plugin: fixme (#50) And exclude `rubocop` files. --- .codeclimate.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index f871444b..8c6bc9de 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,2 +1,8 @@ -exclude_paths: +exclude_patterns: - 'tasks/' +plugins: + # No to-dos or similar + fixme: + enabled: true + exclude_patterns: + - '.rubocop.*' From 7741c132729f8a0d0e6aece8471df45ed4e5d985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Mon, 15 May 2023 14:19:34 -0400 Subject: [PATCH 55/58] Add CodeClimate plugin: markdownlint (#51) - Max line length is 120 (`MD013`) - Ordered list style is `ordered` (`MD029`) - Add titles to `CHANGELOG.md` and `CONTRIBUTING.md` - Apply lint rules - Fix corresponding tests --- .codeclimate.yml | 3 ++ .mdl_style.rb | 4 ++ .mdlrc | 1 + CHANGELOG.md | 25 ++++------- CONTRIBUTING.md | 11 +++-- Gemfile | 1 + README.md | 60 ++++++++++++++++++-------- spec/integration/rambling/trie_spec.rb | 18 +++++--- 8 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 .mdl_style.rb create mode 100644 .mdlrc diff --git a/.codeclimate.yml b/.codeclimate.yml index 8c6bc9de..b4bd17fe 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -6,3 +6,6 @@ plugins: enabled: true exclude_patterns: - '.rubocop.*' + # Markdown lint with rules from https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md + markdownlint: + enabled: true diff --git a/.mdl_style.rb b/.mdl_style.rb new file mode 100644 index 00000000..60636ece --- /dev/null +++ b/.mdl_style.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +rule 'MD013', line_length: 120 +rule 'MD029', style: 'ordered' diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 00000000..1f82ca2c --- /dev/null +++ b/.mdlrc @@ -0,0 +1 @@ +style '.mdl_style.rb' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c5300c0..276f98fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +# CHANGELOG + ## 2.3.2 [compare][compare_v2_3_1_and_master] ## 2.3.1 [compare][compare_v2_3_0_and_v2_3_1] @@ -60,7 +62,7 @@ - Add `Readers::Reader` and `Serializer::Serializer` base classes - Make all readers/serializers extend from their corresponding base classes - Better docs with `Reader`/`Serializer` and generics - - Fix all code blocks from `\`` to `+` and add some more + - Fix all code blocks from backtick to `+` and add some more - Add `@return [void]` where appropriate - Add `@return [self]` where appropriate - Fix `Nodes::Node` duplicate and broken references @@ -319,20 +321,15 @@ Most of these help with the gem's overall performance. - Add Ruby 2.4 to supported versions by [@gonzedge][github_user_gonzedge] - Drastically reduce size of gem by [@gonzedge][github_user_gonzedge] - - By excluding unnecessary `assets/` and `reports/` when building the gem. - **Size reduction**: from ~472KB to ~21KB. - + - By excluding unnecessary `assets/` and `reports/` when building the gem. + - **Size reduction**: from ~472KB to ~21KB. - Make root node accessible via container by [@gonzedge][github_user_gonzedge] - - So that anyone using rambling-trie can develop their custom algorithms - + - So that anyone using rambling-trie can develop their custom algorithms - Expose root node's `#to_a` method through `Container` by [@gonzedge][github_user_gonzedge] - Add own `Forwardable#delegate` because of [Ruby 2.4 performance degradation][ruby_bug_13111] by [@gonzedge][github_user_gonzedge] - - Was able to take Creation and Compression benchmarks (~8.8s and ~1.5s + - Was able to take Creation and Compression benchmarks (~8.8s and ~1.5s respectively) back down to the Ruby 2.3.3 levels by adding own definition of `Forwardable#delegate`. @@ -411,16 +408,12 @@ Most of these help with the gem's overall performance. - `Rambling::Trie.create` now returns a `Container` instead of a `Root` by [@gonzedge][github_user_gonzedge] - - `Container` exposes these API entry points: - + - `Container` exposes these API entry points: - `#partial_word?` and its alias `#match?` - `#word?` and its alias `#include?` - `#add` and its alias `#<<` - yield the constructed `Container` on `#initialize` - - `Rambling::Trie::Node` and its subclasses no longer expose: - + - `Rambling::Trie::Node` and its subclasses no longer expose: - `#match?` - `#include?` - `#<<` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56220ef8..cd209722 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,12 +1,15 @@ -## Contributing to Rambling Trie +# Contributing to Rambling Trie -1. If you have found a bug or have a feature request, please [search through the issues][github_issues_all] to see if it has already been reported. If that's not the case, then [create a new one][github_issues_new] with a full description of what you have found or what you need. -2. If you have bug fix or a feature implementation in mind, then [fork Rambling Trie][github_fork] and create a branch with a descriptive name. +1. If you have found a bug or have a feature request, please [search through the issues][github_issues_all] to see if it + has already been reported. If that's not the case, then [create a new one][github_issues_new] with a full description + of what you have found or what you need. +2. If you have bug fix or a feature implementation in mind, then [fork Rambling Trie][github_fork] and create a branch + with a descriptive name. 3. Get the gem up and running locally (tests are written in RSpec): ```sh bundle install - rake + bundle exec rake ``` 4. Implement your bug fix or feature - ***make sure to add tests!*** diff --git a/Gemfile b/Gemfile index f37dc915..f4628b49 100644 --- a/Gemfile +++ b/Gemfile @@ -23,6 +23,7 @@ end group :local do gem 'guard-rspec' + gem 'mdl', require: false gem 'rubocop', require: false gem 'rubocop-performance', require: false gem 'rubocop-rake', require: false diff --git a/README.md b/README.md index d56ac401..5acf6b46 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ [![Code Climate Grade][code_climate_grade_badge]][code_climate_link] [![Code Climate Issue Count][code_climate_issues_badge]][code_climate_link] -The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities and is designed to be very fast to traverse. +The Rambling Trie is a Ruby implementation of the [trie data structure][trie_wiki], which includes compression abilities +and is designed to be very fast to traverse. ## Installing the Rambling Trie @@ -57,7 +58,8 @@ Rambling::Trie.create do |trie| end ``` -Additionally, you can provide the path to a file that contains all the words to be added to the trie, and it will read the file and create the complete structure for you, like this: +Additionally, you can provide the path to a file that contains all the words to be added to the trie, and it will read +the file and create the complete structure for you, like this: ``` ruby trie = Rambling::Trie.create '/path/to/file' @@ -74,7 +76,10 @@ the trie ``` -If you want to use a custom file format, you will need to provide a custom file reader that defines an `#each_word` method that yields each word contained in the file. Look at the [`PlainText` reader][rambling_trie_plain_text_reader] class for an example, and at the [Configuration section][rambling_trie_configuration] to see how to add your own custom file readers. +If you want to use a custom file format, you will need to provide a custom `Reader` that defines an `#each_word` method +that yields each word contained in the file. Look at the [`PlainText` reader][rambling_trie_plain_text_reader] class for +an example, and at the [Configuration section][rambling_trie_configuration] to see how to add your own custom file +readers. ### Operations @@ -98,7 +103,8 @@ trie.word? 'word' trie.include? 'word' ``` -If you wish to find if part of a word exists in the trie instance, you should call `#partial_word?` or its alias `#match?`: +If you wish to find if part of a word exists in the trie instance, you should call `#partial_word?` or its +alias `#match?`: ``` ruby trie.partial_word? 'partial_word' @@ -119,7 +125,8 @@ trie.words_within 'ifdxawesome45someword3' # => ['if', 'aw', 'awe', ...] trie.words_within 'tktktktk' # => [] ``` -Or, if you're just interested in knowing whether a given string contains any valid words or not, you can use `#words_within?`: +Or, if you're just interested in knowing whether a given string contains any valid words or not, you can +use `#words_within?`: ``` ruby trie.words_within? 'ifdxawesome45someword3' # => true @@ -128,13 +135,15 @@ trie.words_within? 'tktktktk' # => false ### Compression -By default, the Rambling Trie works as a standard trie. Starting from version 0.1.0, you can obtain a compressed trie from the standard one, by using the compression feature. Just call the `#compress!` method on the trie instance: +By default, the Rambling Trie works as a standard trie. Starting from version 0.1.0, you can obtain a compressed trie +from the standard one, by using the compression feature. Just call the `#compress!` method on the trie instance: ``` ruby trie.compress! ``` -This will reduce the size of the trie by using redundant node elimination (redundant nodes are the only-child non-terminal nodes). +This will reduce the size of the trie by using redundant node elimination (redundant nodes are the only-child +non-terminal nodes). > _**Note**: The `#compress!` method acts over the trie instance it belongs to > and replaces the root `Node`. Also, adding words after compression (with `#add` or @@ -155,7 +164,8 @@ compressed_trie.compressed? # => true ### Enumeration -Starting from version 0.4.2, you can use any `Enumerable` method over a trie instance, and it will iterate over each word contained in the trie. You can now do things like: +Starting from version 0.4.2, you can use any `Enumerable` method over a trie instance, and it will iterate over each +word contained in the trie. You can now do things like: ``` ruby trie.each { |word| puts word } @@ -166,7 +176,10 @@ trie.all? { |word| word.include? 'x' } ### Serialization -Starting from version 1.0.0, you can store a full trie instance on disk and retrieve/use it later on. Loading a trie from disk takes less time, less cpu and less memory than loading every word into the trie every time. This is particularly useful for production applications, when you have word lists that you know are going to be static, or that change with little frequency. +Starting from version 1.0.0, you can store a full trie instance on disk and retrieve/use it later on. Loading a trie +from disk takes less time, less cpu and less memory than loading every word into the trie every time. This is +particularly useful for production applications, when you have word lists that you know are going to be static, or that +change with little frequency. To store a trie on disk, you can use `.dump` like this: @@ -174,7 +187,8 @@ To store a trie on disk, you can use `.dump` like this: Rambling::Trie.dump trie, '/path/to/file' ``` -Then, when you need to use a trie next time, you don't have to create a new one with all the necessary words. Rather, you can retrieve a previously stored one with `.load` like this: +Then, when you need to use a trie next time, you don't have to create a new one with all the necessary words. Rather, +you can retrieve a previously stored one with `.load` like this: ``` ruby trie = Rambling::Trie.load '/path/to/file' @@ -184,14 +198,15 @@ trie = Rambling::Trie.load '/path/to/file' Currently, these formats are supported to store tries on disk: -- Ruby's [binary (Marshal)][marshal] format -- [YAML][yaml] +* Ruby's [binary (Marshal)][marshal] format +* [YAML][yaml] > When dumping into or loading from disk, the format is determined > automatically based on the file extension, so `.yml` or `.yaml` files will be > handled through `YAML` and `.marshal` files through `Marshal`. -Optionally, you can use a `.zip` version of the supported formats. In order to do so, you'll have to install the [`rubyzip`][rubyzip] gem: +Optionally, you can use a `.zip` version of the supported formats. In order to do so, you'll have to install +the [`rubyzip`][rubyzip] gem: ``` bash gem install rubyzip @@ -246,7 +261,8 @@ end ### Further Documentation -You can find further API documentation on the autogenerated [rambling-trie gem RubyDoc.info page][rubydoc] or if you want edge documentation, you can go the [GitHub project RubyDoc.info page][rubydoc_github]. +You can find further API documentation on the autogenerated [rambling-trie gem RubyDoc.info page][rubydoc] or if you +want edge documentation, you can go the [GitHub project RubyDoc.info page][rubydoc_github]. ## Compatible Ruby and Rails versions @@ -271,7 +287,8 @@ The Rambling Trie has been tested with the following Ruby versions: ## Contributing to Rambling Trie -Take a look at the [contributing guide][rambling_trie_contributing_guide] to get started, or fire a question to [@gonzedge][github_user_gonzedge]. +Take a look at the [contributing guide][rambling_trie_contributing_guide] to get started, or fire a question +to [@gonzedge][github_user_gonzedge]. ## License and copyright @@ -279,11 +296,18 @@ Copyright (c) 2012-2023 Edgar González MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [badge_fury_badge]: https://badge.fury.io/rb/rambling-trie.svg?version=2.3.1 [badge_fury_link]: https://badge.fury.io/rb/rambling-trie diff --git a/spec/integration/rambling/trie_spec.rb b/spec/integration/rambling/trie_spec.rb index df07afbe..c578c5a3 100644 --- a/spec/integration/rambling/trie_spec.rb +++ b/spec/integration/rambling/trie_spec.rb @@ -13,24 +13,28 @@ let(:changelog_path) { File.join root_path, 'CHANGELOG.md' } let(:changelog) { File.read changelog_path } + let(:changelog_versions) do + matches = [] + changelog.scan %r{^## (\d+\.\d+\.\d+)} do |match| + matches << match[0] + end + matches + end + it 'matches with the version in the README badge' do match = %r{\?version=(?.*)$}.match readme expect(match['version']).to eq Rambling::Trie::VERSION end it 'is the version before the one at the top of the CHANGELOG' do - match = %r{## (?\d+\.\d+\.\d+)}.match changelog.split("\n")[0] - changelog_version = Gem::Version.new match['version'] + changelog_version = Gem::Version.new changelog_versions.first lib_version = Gem::Version.new "#{Rambling::Trie::VERSION}.0" expect(changelog_version).to eq lib_version.bump end it 'is included in the CHANGELOG diffs' do - matches = Set.new - changelog.scan %r{^## (\d+\.\d+\.\d+)} do |match| - matches << match[0] - end - expect(matches).to include Rambling::Trie::VERSION + changelog_versions.shift + expect(changelog_versions.first).to eq Rambling::Trie::VERSION end end From ff8aecd98812b5af02797e15e25bf9b13c000e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Mon, 15 May 2023 21:39:55 -0400 Subject: [PATCH 56/58] Add CodeClimate plugin: rubocop (#53) - Allow up to 5 params to be optional (same as max total params) - Change max line length to 120. --- .codeclimate.yml | 4 + .rubocop.yml | 98 ++++++++++--------- lib/rambling/trie.rb | 24 ++--- lib/rambling/trie/comparable.rb | 3 +- lib/rambling/trie/compressible.rb | 6 +- lib/rambling/trie/compressor.rb | 14 +-- lib/rambling/trie/configuration/properties.rb | 15 +-- .../trie/configuration/provider_collection.rb | 30 ++---- lib/rambling/trie/container.rb | 52 ++++------ lib/rambling/trie/enumerable.rb | 3 +- lib/rambling/trie/nodes/compressed.rb | 3 +- lib/rambling/trie/nodes/missing.rb | 3 +- lib/rambling/trie/nodes/node.rb | 39 +++----- lib/rambling/trie/readers/plain_text.rb | 3 +- lib/rambling/trie/readers/reader.rb | 6 +- lib/rambling/trie/serializers/marshal.rb | 29 ++---- lib/rambling/trie/serializers/yaml.rb | 23 ++--- lib/rambling/trie/serializers/zip.rb | 2 +- spec/support/shared_examples/a_serializer.rb | 4 +- 19 files changed, 140 insertions(+), 221 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index b4bd17fe..95efb8ae 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -9,3 +9,7 @@ plugins: # Markdown lint with rules from https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md markdownlint: enabled: true + # Ruby lint + rubocop: + enabled: true + channel: rubocop-1-50-2 diff --git a/.rubocop.yml b/.rubocop.yml index c07e7f66..293c7a06 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -29,6 +29,37 @@ Layout/AccessModifierIndentation: Layout/ArgumentAlignment: EnforcedStyle: with_fixed_indentation +# checks whether the end keywords are aligned properly for `do` `end` blocks. +Layout/BlockAlignment: + # The value `start_of_block` means that the `end` should be aligned with line + # where the `do` keyword appears. + # The value `start_of_line` means it should be aligned with the whole + # expression's starting line. + # The value `either` means both are allowed. + EnforcedStyleAlignWith: start_of_line + +Layout/DefEndAlignment: + # The value `def` means that `end` should be aligned with the def keyword. + # The value `start_of_line` means that `end` should be aligned with method + # calls like `private`, `public`, etc, if present in front of the `def` + # keyword on the same line. + EnforcedStyleAlignWith: start_of_line + # AutoCorrect: false + Severity: warning + +# Align ends correctly. +Layout/EndAlignment: + # The value `keyword` means that `end` should be aligned with the matching + # keyword (`if`, `while`, etc.). + # The value `variable` means that in assignments, `end` should be aligned + # with the start of the variable on the left hand side of `=`. In all other + # situations, `end` should still be aligned with the keyword. + # The value `start_of_line` means that `end` should be aligned with the start + # of the line which the matching keyword appears on. + EnforcedStyleAlignWith: start_of_line + # AutoCorrect: false + Severity: warning + # Align the elements of a hash literal if they span more than one line. Layout/HashAlignment: # Alignment of entries using colon as separator. Valid values are: @@ -76,6 +107,23 @@ Layout/HashAlignment: # b: 2) EnforcedLastArgumentHashStyle: ignore_implicit +Layout/LineLength: + Max: 120 + # To make it possible to copy or click on URIs in the code, we allow lines + # containing a URI to be longer than Max. + AllowHeredoc: true + AllowURI: true + URISchemes: + - http + - https + # The IgnoreCopDirectives option causes the LineLength rule to ignore cop + # directives like '# rubocop: enable ...' when calculating a line's length. + IgnoreCopDirectives: false + # The IgnoredPatterns option is a list of !ruby/regexp and/or string + # elements. Strings will be converted to Regexp objects. A line that matches + # any regular expression listed in this option will be ignored by LineLength. + IgnoredPatterns: [] + Layout/ParameterAlignment: # Alignment of parameters in multi-line method calls. # @@ -1288,6 +1336,7 @@ Metrics/BlockLength: Exclude: - 'test/**/*' - 'spec/**/*' + - 'tasks/ips.rb' Metrics/BlockNesting: CountBlocks: false @@ -1304,23 +1353,6 @@ Metrics/ClassLength: Metrics/CyclomaticComplexity: Max: 6 -Layout/LineLength: - Max: 80 - # To make it possible to copy or click on URIs in the code, we allow lines - # containing a URI to be longer than Max. - AllowHeredoc: true - AllowURI: true - URISchemes: - - http - - https - # The IgnoreCopDirectives option causes the LineLength rule to ignore cop - # directives like '# rubocop: enable ...' when calculating a line's length. - IgnoreCopDirectives: false - # The IgnoredPatterns option is a list of !ruby/regexp and/or string - # elements. Strings will be converted to Regexp objects. A line that matches - # any regular expression listed in this option will be ignored by LineLength. - IgnoredPatterns: [] - Metrics/MethodLength: CountComments: false # count full line comments? Max: 20 @@ -1331,6 +1363,7 @@ Metrics/ModuleLength: Metrics/ParameterLists: Max: 5 + MaxOptionalParameters: 5 CountKeywordArgs: true Metrics/PerceivedComplexity: @@ -1342,37 +1375,6 @@ Metrics/PerceivedComplexity: Lint/AssignmentInCondition: AllowSafeAssignment: true -# checks whether the end keywords are aligned properly for `do` `end` blocks. -Layout/BlockAlignment: - # The value `start_of_block` means that the `end` should be aligned with line - # where the `do` keyword appears. - # The value `start_of_line` means it should be aligned with the whole - # expression's starting line. - # The value `either` means both are allowed. - EnforcedStyleAlignWith: start_of_line - -Layout/DefEndAlignment: - # The value `def` means that `end` should be aligned with the def keyword. - # The value `start_of_line` means that `end` should be aligned with method - # calls like `private`, `public`, etc, if present in front of the `def` - # keyword on the same line. - EnforcedStyleAlignWith: start_of_line - # AutoCorrect: false - Severity: warning - -# Align ends correctly. -Layout/EndAlignment: - # The value `keyword` means that `end` should be aligned with the matching - # keyword (`if`, `while`, etc.). - # The value `variable` means that in assignments, `end` should be aligned - # with the start of the variable on the left hand side of `=`. In all other - # situations, `end` should still be aligned with the keyword. - # The value `start_of_line` means that `end` should be aligned with the start - # of the line which the matching keyword appears on. - EnforcedStyleAlignWith: start_of_line - # AutoCorrect: false - Severity: warning - Lint/SuppressedException: Exclude: - 'spec/**/*' diff --git a/lib/rambling/trie.rb b/lib/rambling/trie.rb index ddef6274..04c8fe23 100644 --- a/lib/rambling/trie.rb +++ b/lib/rambling/trie.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true %w( - comparable compressible compressor configuration container enumerable - inspectable invalid_operation readers serializers stringifyable nodes - version + comparable compressible compressor configuration container enumerable inspectable invalid_operation + readers serializers stringifyable nodes version ).each do |file| require File.join('rambling', 'trie', file) end @@ -41,15 +40,12 @@ def create filepath = nil, reader = nil # Available formats are +yml+, +marshal+, and +zip+ versions of all the # previous formats. You can also define your own. # @param [String] filepath the file to load the words from. - # @param [Serializer, nil] serializer the object responsible of loading - # the trie from disk + # @param [Serializer, nil] serializer the object responsible of loading the trie from disk. # @return [Container] the trie just loaded. # @yield [Container] the trie just loaded. # @see Rambling::Trie::Serializers Serializers. - # @note Use of - # {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load - # Marshal.load} is generally discouraged. Only use the +.marshal+ - # format with trusted input. + # @note Use of # {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load Marshal.load} is generally + # discouraged. Only use the +.marshal+ format with trusted input. def load filepath, serializer = nil serializer ||= serializers.resolve filepath root = serializer.load filepath @@ -64,10 +60,8 @@ def load filepath, serializer = nil # previous formats. You can also define your own. # @param [Container] trie the trie to dump into disk. # @param [String] filepath the file to dump to serialized trie into. - # @param [Serializers::Serializer, nil] serializer the object responsible - # for trie serialization. + # @param [Serializers::Serializer, nil] serializer the object responsible for trie serialization. # @return [void] - # serializing and dumping the trie into disk. # @see Serializers Serializers. def dump trie, filepath, serializer = nil serializer ||= serializers.resolve filepath @@ -76,10 +70,8 @@ def dump trie, filepath, serializer = nil end # Provides configuration properties for the +Rambling::Trie+ gem. - # @return [Configuration::Properties] the configured properties of the - # gem. - # @yield [Configuration::Properties] the configured properties of the - # gem. + # @return [Configuration::Properties] the configured properties of the gem. + # @yield [Configuration::Properties] the configured properties of the gem. def config yield properties if block_given? properties diff --git a/lib/rambling/trie/comparable.rb b/lib/rambling/trie/comparable.rb index e337a8a7..a5678b80 100644 --- a/lib/rambling/trie/comparable.rb +++ b/lib/rambling/trie/comparable.rb @@ -7,8 +7,7 @@ module Comparable # Compares two nodes. # @param [Nodes::Node] other the node to compare against. # @return [Boolean] +true+ if the nodes' {Nodes::Node#letter #letter} and - # {Nodes::Node#children_tree #children_tree} are equal, +false+ - # otherwise. + # {Nodes::Node#children_tree #children_tree} are equal, +false+ otherwise. def == other letter == other.letter && terminal? == other.terminal? && diff --git a/lib/rambling/trie/compressible.rb b/lib/rambling/trie/compressible.rb index 463578af..40324efe 100644 --- a/lib/rambling/trie/compressible.rb +++ b/lib/rambling/trie/compressible.rb @@ -4,10 +4,8 @@ module Rambling module Trie # Provides the compressible behavior for the trie data structure. module Compressible - # Indicates if the current {Rambling::Trie::Nodes::Node Node} can be - # compressed or not. - # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} nodes - # with one child, +false+ otherwise. + # Indicates if the current {Rambling::Trie::Nodes::Node Node} can be compressed or not. + # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} nodes with one child, +false+ otherwise. def compressible? !(root? || terminal?) && 1 == children_tree.size end diff --git a/lib/rambling/trie/compressor.rb b/lib/rambling/trie/compressor.rb index 810442a3..9bced889 100644 --- a/lib/rambling/trie/compressor.rb +++ b/lib/rambling/trie/compressor.rb @@ -24,21 +24,11 @@ def compress_child_and_merge node def merge node, other letter = node.letter.to_s << other.letter.to_s - new_compressed_node( - letter.to_sym, - node.parent, - other.children_tree, - other.terminal?, - ) + new_compressed_node letter.to_sym, node.parent, other.children_tree, other.terminal? end def compress_children_and_copy node - new_compressed_node( - node.letter, - node.parent, - compress_children(node.children_tree), - node.terminal?, - ) + new_compressed_node node.letter, node.parent, compress_children(node.children_tree), node.terminal? end def compress_children tree diff --git a/lib/rambling/trie/configuration/properties.rb b/lib/rambling/trie/configuration/properties.rb index 1de51c90..a40e45db 100644 --- a/lib/rambling/trie/configuration/properties.rb +++ b/lib/rambling/trie/configuration/properties.rb @@ -6,21 +6,18 @@ module Configuration # Provides configurable properties for Rambling::Trie. class Properties # The configured {Readers Readers}. - # @return [ProviderCollection] the mapping of - # configured {Readers Readers}. + # @return [ProviderCollection] the mapping of configured {Readers Readers}. attr_reader :readers # The configured {Serializers Serializers}. - # @return [ProviderCollection] the mapping of - # configured {Serializers Serializers}. + # @return [ProviderCollection] the mapping of configured {Serializers Serializers}. attr_reader :serializers # The configured {Compressor Compressor}. # @return [Compressor] the configured compressor. attr_accessor :compressor - # The configured +root_builder+, which returns a {Nodes::Node Node} - # when called. + # The configured +root_builder+, which returns a {Nodes::Node Node} when called. # @return [Proc] the configured +root_builder+. attr_accessor :root_builder @@ -50,11 +47,7 @@ def reset def reset_readers plain_text_reader = Rambling::Trie::Readers::PlainText.new - - @readers = Rambling::Trie::Configuration::ProviderCollection.new( - :reader, - txt: plain_text_reader, - ) + @readers = Rambling::Trie::Configuration::ProviderCollection.new :reader, txt: plain_text_reader end def reset_serializers diff --git a/lib/rambling/trie/configuration/provider_collection.rb b/lib/rambling/trie/configuration/provider_collection.rb index c0fcd936..7e827433 100644 --- a/lib/rambling/trie/configuration/provider_collection.rb +++ b/lib/rambling/trie/configuration/provider_collection.rb @@ -16,11 +16,10 @@ class ProviderCollection # Sets the default provider. Needs to be one of the configured # providers. # @param [TProvider] provider the provider to use as default. - # @raise [ArgumentError] when the given provider is not in the - # provider collection. + # @raise [ArgumentError] when the given provider is not in the provider collection. # @note If no providers have been configured, +nil+ will be assigned. - # @return [TProvider, nil] the default provider to use when a provider - # cannot be resolved in {ProviderCollection#resolve #resolve}. + # @return [TProvider, nil] the default provider to use when a provider cannot be resolved in + # {ProviderCollection#resolve #resolve}. attr_reader :default # Creates a new provider collection. @@ -36,35 +35,28 @@ def initialize name, providers = {}, default = nil end # Adds a new provider to the provider collection. - # @param [Symbol] extension the extension that the provider will - # correspond to. - # @param [TProvider] provider the provider to add to the provider - # collection. + # @param [Symbol] extension the extension that the provider will correspond to. + # @param [TProvider] provider the provider to add to the provider collection. # @return [TProvider] the provider just added. def add extension, provider providers[extension] = provider end def default= provider - unless contains? provider - raise ArgumentError, - "default #{name} should be part of configured #{name}s" - end + raise ArgumentError, "default #{name} should be part of configured #{name}s" unless contains? provider @default = provider end # List of configured providers. - # @return [Hash] the mapping of extensions to their - # corresponding providers. + # @return [Hash] the mapping of extensions to their corresponding providers. def providers @providers ||= {} end # Resolves the provider from a filepath based on the file extension. # @param [String] filepath the filepath to resolve into a provider. - # @return [TProvider, nil] the provider for the given file's extension. - # {#default} if not found. + # @return [TProvider, nil] the provider for the given file's extension. {#default} if not found. def resolve filepath providers[file_format filepath] || default end @@ -88,8 +80,7 @@ def formats # Get provider corresponding to a given format. # @param [Symbol] format the format to search for in the collection. # @return [TProvider] the provider corresponding to that format. - # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D - # Hash#[] + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[] def [] format providers[format] end @@ -113,8 +104,7 @@ def file_format filepath end def contains? provider - provider.nil? || - (providers.any? && provider_instances.include?(provider)) + provider.nil? || (providers.any? && provider_instances.include?(provider)) end alias_method :provider_instances, :values diff --git a/lib/rambling/trie/container.rb b/lib/rambling/trie/container.rb index da6c90e0..85700496 100644 --- a/lib/rambling/trie/container.rb +++ b/lib/rambling/trie/container.rb @@ -41,22 +41,19 @@ def concat words words.map { |word| add word } end - # Compresses the existing trie using redundant node elimination. Marks - # the trie as compressed. Does nothing if the trie has already been - # compressed. + # Compresses the existing trie using redundant node elimination. + # Marks the trie as compressed. + # Does nothing if the trie has already been compressed. # @return [self] - # @note This method replaces the root {Nodes::Raw Raw} node with a - # {Nodes::Compressed Compressed} version of it. + # @note This method replaces the root {Nodes::Raw Raw} node with a {Nodes::Compressed Compressed} version of it. def compress! self.root = compress_root unless root.compressed? self end - # Compresses the existing trie using redundant node elimination. Returns - # a new trie with the compressed root. - # @return [Container] A new {Container} with the {Nodes::Compressed - # Compressed} root node or self if the trie has already been - # compressed. + # Compresses the existing trie using redundant node elimination. Returns a new trie with the compressed root. + # @return [Container] A new {Container} with the {Nodes::Compressed Compressed} root node + # or self if the trie has already been compressed. def compress return self if root.compressed? @@ -65,8 +62,7 @@ def compress # Checks if a path for a word or partial word exists in the trie. # @param [String] word the word or partial word to look for in the trie. - # @return [Boolean] +true+ if the word or partial word is found, +false+ - # otherwise. + # @return [Boolean] +true+ if the word or partial word is found, +false+ otherwise. # @see Nodes::Node#partial_word? def partial_word? word = '' root.partial_word? word.chars @@ -74,8 +70,8 @@ def partial_word? word = '' # Checks if a whole word exists in the trie. # @param [String] word the word to look for in the trie. - # @return [Boolean] +true+ only if the word is found and the last - # character corresponds to a terminal node, +false+ otherwise. + # @return [Boolean] +true+ only if the word is found and the last character corresponds to a terminal node, + # +false+ otherwise. # @see Nodes::Node#word? def word? word = '' root.word? word.chars @@ -83,18 +79,15 @@ def word? word = '' # Returns all words that start with the specified characters. # @param [String] word the word to look for in the trie. - # @return [Array] all the words contained in the trie that start - # with the specified characters. + # @return [Array] all the words contained in the trie that start with the specified characters. # @see Nodes::Node#scan def scan word = '' root.scan(word.chars).to_a end - # Returns all words within a string that match a word contained in the - # trie. + # Returns all words within a string that match a word contained in the trie. # @param [String] phrase the string to look for matching words in. - # @return [Enumerator] all the words in the given string that - # match a word in the trie. + # @return [Enumerator] all the words in the given string that match a word in the trie. # @yield [String] each word found in phrase. def words_within phrase words_within_root(phrase).to_a @@ -102,8 +95,7 @@ def words_within phrase # Checks if there are any valid words in a given string. # @param [String] phrase the string to look for matching words in. - # @return [Boolean] +true+ if any word within phrase is contained in the - # trie, +false+ otherwise. + # @return [Boolean] +true+ if any word within phrase is contained in the trie, +false+ otherwise. # @see Container#words_within def words_within? phrase words_within_root(phrase).any? @@ -141,33 +133,29 @@ def [] letter end # Root node's child nodes. - # @return [Array] the array of children nodes contained in - # the root node. + # @return [Array] the array of children nodes contained in the root node. # @see Nodes::Node#children def children root.children end # Root node's children tree. - # @return [Hash] the children tree hash contained in - # the root node, consisting of +:letter => node+. + # @return [Hash] the children tree hash contained in the root node, consisting of + # +:letter => node+. # @see Nodes::Node#children_tree def children_tree root.children_tree end - # Indicates if the root {Nodes::Node Node} can be - # compressed or not. - # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} - # nodes with one child, +false+ otherwise. + # Indicates if the root {Nodes::Node Node} can be compressed or not. + # @return [Boolean] +true+ for non-{Nodes::Node#terminal? terminal} nodes with one child, +false+ otherwise. def compressed? root.compressed? end # Array of words contained in the root {Nodes::Node Node}. # @return [Array] all words contained in this trie. - # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a - # Enumerable#to_a + # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-to_a Enumerable#to_a def to_a root.to_a end diff --git a/lib/rambling/trie/enumerable.rb b/lib/rambling/trie/enumerable.rb index 514a2bac..b3ca64f4 100644 --- a/lib/rambling/trie/enumerable.rb +++ b/lib/rambling/trie/enumerable.rb @@ -7,8 +7,7 @@ module Enumerable include ::Enumerable # Returns number of words contained in the trie - # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-count - # Enumerable#count + # @see https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-count Enumerable#count alias_method :size, :count # Iterates over the words contained in the trie. diff --git a/lib/rambling/trie/nodes/compressed.rb b/lib/rambling/trie/nodes/compressed.rb index 859dc729..5c901c22 100644 --- a/lib/rambling/trie/nodes/compressed.rb +++ b/lib/rambling/trie/nodes/compressed.rb @@ -11,8 +11,7 @@ class Compressed < Rambling::Trie::Nodes::Node # @raise [InvalidOperation] if the trie is already compressed. # @return [void] def add _ - raise Rambling::Trie::InvalidOperation, - 'Cannot add word to compressed trie' + raise Rambling::Trie::InvalidOperation, 'Cannot add word to compressed trie' end # Always return +true+ for a compressed node. diff --git a/lib/rambling/trie/nodes/missing.rb b/lib/rambling/trie/nodes/missing.rb index 17c3bb1e..b0892e61 100644 --- a/lib/rambling/trie/nodes/missing.rb +++ b/lib/rambling/trie/nodes/missing.rb @@ -3,8 +3,7 @@ module Rambling module Trie module Nodes - # A representation of a missing node in the trie data structure. Returned - # when a node is not found. + # A representation of a missing node in the trie data structure. Returned when a node is not found. class Missing < Rambling::Trie::Nodes::Node end end diff --git a/lib/rambling/trie/nodes/node.rb b/lib/rambling/trie/nodes/node.rb index 46cfef54..4163e9d5 100644 --- a/lib/rambling/trie/nodes/node.rb +++ b/lib/rambling/trie/nodes/node.rb @@ -22,8 +22,7 @@ class Node attr_reader :letter # Child nodes tree. - # @return [Hash] the children tree hash, consisting of - # +:letter => node+. + # @return [Hash] the children tree hash, consisting of +:letter => node+. attr_accessor :children_tree # Parent node. @@ -40,8 +39,7 @@ def initialize letter = nil, parent = nil, children_tree = {} end # Child nodes. - # @return [Array] the array of child nodes contained - # in the current node. + # @return [Array] the array of child nodes contained in the current node. def children children_tree.values end @@ -57,8 +55,7 @@ def first_child end # Indicates if the current node is the root node. - # @return [Boolean] +true+ if the node does not have a parent, +false+ - # otherwise. + # @return [Boolean] +true+ if the node does not have a parent, +false+ otherwise. def root? !parent end @@ -82,8 +79,7 @@ def letter= letter # Checks if a path for a set of characters exists in the trie. # @param [Array] chars the characters to look for in the trie. - # @return [Boolean] +true+ if the characters are found, +false+ - # otherwise. + # @return [Boolean] +true+ if the characters are found, +false+ otherwise. def partial_word? chars return true if chars.empty? @@ -92,8 +88,7 @@ def partial_word? chars # Checks if a path for set of characters represents a word in the trie. # @param [Array] chars the characters to look for in the trie. - # @return [Boolean] +true+ if the characters are found and form a word, - # +false+ otherwise. + # @return [Boolean] +true+ if the characters are found and form a word, +false+ otherwise. def word? chars = [] return terminal? if chars.empty? @@ -112,8 +107,7 @@ def scan chars # Returns all words that match a prefix of any length within chars. # @param [String] chars the chars to base the prefix on. - # @return [Enumerator] all the words that match a prefix given - # by chars. + # @return [Enumerator] all the words that match a prefix by chars. # @yield [String] each word found. def match_prefix chars return enum_for :match_prefix, chars unless block_given? @@ -128,8 +122,7 @@ def match_prefix chars # Get {Node Node} corresponding to a given letter. # @param [Symbol] letter the letter to search for in the node. # @return [Node] the node corresponding to that letter. - # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D - # Hash#[] + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[] def [] letter children_tree[letter] end @@ -137,31 +130,25 @@ def [] letter # Set the {Node Node} that corresponds to a given letter. # @param [Symbol] letter the letter to insert or update in the node's # @param [Node] node the {Node Node} to assign to that letter. - # @return [Node] the node corresponding to the inserted or - # updated letter. - # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D - # Hash#[] + # @return [Node] the node corresponding to the inserted or updated letter. + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-5B-5D Hash#[] def []= letter, node children_tree[letter] = node end - # Check if a {Node Node}'s children tree contains a given - # letter. + # Check if a {Node Node}'s children tree contains a given letter. # @param [Symbol] letter the letter to search for in the node. # @return [Boolean] +true+ if the letter is present, +false+ otherwise. - # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F - # Hash#key? + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-has_key-3F Hash#key? def key? letter children_tree.key? letter end # Delete a given letter and its corresponding {Node Node} from # this {Node Node}'s children tree. - # @param [Symbol] letter the letter to delete from the node's children - # tree. + # @param [Symbol] letter the letter to delete from the node's children tree. # @return [Node] the node corresponding to the deleted letter. - # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-delete - # Hash#delete + # @see https://ruby-doc.org/core-2.7.0/Hash.html#method-i-delete Hash#delete def delete letter children_tree.delete letter end diff --git a/lib/rambling/trie/readers/plain_text.rb b/lib/rambling/trie/readers/plain_text.rb index 0ce62969..29869766 100644 --- a/lib/rambling/trie/readers/plain_text.rb +++ b/lib/rambling/trie/readers/plain_text.rb @@ -6,8 +6,7 @@ module Readers # File reader for +.txt+ files. class PlainText < Reader # Yields each word read from a +.txt+ file. - # @param [String] filepath the full path of the file to load the words - # from. + # @param [String] filepath the full path of the file to load the words from. # @yield [String] Each line read from the file. # @return [self] def each_word filepath diff --git a/lib/rambling/trie/readers/reader.rb b/lib/rambling/trie/readers/reader.rb index b08f2ba0..727d6770 100644 --- a/lib/rambling/trie/readers/reader.rb +++ b/lib/rambling/trie/readers/reader.rb @@ -6,10 +6,8 @@ module Readers # Base class for all readers. class Reader # Yields each word read from given file. - # @abstract Subclass and override {#each_word} to fit to a particular - # file format. - # @param [String] filepath the full path of the file to load the words - # from. + # @abstract Subclass and override {#each_word} to fit to a particular file format. + # @param [String] filepath the full path of the file to load the words from. # @yield [String] Each line read from the file. # @return [self] def each_word filepath diff --git a/lib/rambling/trie/serializers/marshal.rb b/lib/rambling/trie/serializers/marshal.rb index e1fb5d52..758ad099 100644 --- a/lib/rambling/trie/serializers/marshal.rb +++ b/lib/rambling/trie/serializers/marshal.rb @@ -6,36 +6,27 @@ module Serializers # Serializer for Ruby marshal format (+.marshal+) files. class Marshal < Serializer # Creates a new Marshal serializer. - # @param [Serializer] serializer the serializer responsible to write to - # and read from disk. + # @param [Serializer] serializer the serializer responsible to write to and read from disk. def initialize serializer = nil - @serializer = serializer || Rambling::Trie::Serializers::File.new super() + @serializer = serializer || Rambling::Trie::Serializers::File.new end - # Loads marshaled object from contents in filepath and deserializes it - # into a {Nodes::Node Node}. - # @param [String] filepath the full path of the file to load the - # marshaled object from. + # Loads marshaled object from contents in filepath and deserializes it into a {Nodes::Node Node}. + # @param [String] filepath the full path of the file to load the marshaled object from. # @return [Nodes::Node] The deserialized {Nodes::Node Node}. - # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load - # Marshal.load - # @note Use of - # {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load - # Marshal.load} is generally discouraged. Only use this with trusted - # input. + # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load Marshal.load + # @note Use of {https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-load Marshal.load} is generally + # discouraged. Only use this with trusted input. def load filepath ::Marshal.load serializer.load filepath end - # Serializes a {Nodes::Node Node} and dumps it as a marshaled object - # into filepath. + # Serializes a {Nodes::Node Node} and dumps it as a marshaled object into filepath. # @param [Nodes::Node] node the node to serialize - # @param [String] filepath the full path of the file to dump the - # marshaled object into. + # @param [String] filepath the full path of the file to dump the marshaled object into. # @return [Numeric] number of bytes written to disk. - # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-dump - # Marshal.dump + # @see https://ruby-doc.org/core-2.7.0/Marshal.html#method-c-dump Marshal.dump def dump node, filepath serializer.dump ::Marshal.dump(node), filepath end diff --git a/lib/rambling/trie/serializers/yaml.rb b/lib/rambling/trie/serializers/yaml.rb index cadd4cb2..fc0a8862 100644 --- a/lib/rambling/trie/serializers/yaml.rb +++ b/lib/rambling/trie/serializers/yaml.rb @@ -6,20 +6,16 @@ module Serializers # Serializer for Ruby yaml format (+.yaml+, or +.yml+) files. class Yaml < Serializer # Creates a new Yaml serializer. - # @param [Serializer] serializer the serializer responsible to write to - # and read from disk. + # @param [Serializer] serializer the serializer responsible to write to and read from disk. def initialize serializer = nil - @serializer = serializer || Rambling::Trie::Serializers::File.new super() + @serializer = serializer || Rambling::Trie::Serializers::File.new end - # Loads serialized object from YAML file in filepath and deserializes - # it into a {Nodes::Node Node}. - # @param [String] filepath the full path of the file to load the - # serialized YAML object from. + # Loads serialized object from YAML file in filepath and deserializes it into a {Nodes::Node Node}. + # @param [String] filepath the full path of the file to load the serialized YAML object from. # @return [Nodes::Node] The deserialized {Nodes::Node Node}. - # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-safe_load - # Psych.safe_load + # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-safe_load Psych.safe_load def load filepath require 'yaml' ::YAML.safe_load( @@ -33,14 +29,11 @@ def load filepath ) end - # Serializes a {Nodes::Node Node} and dumps it as a YAML object into - # filepath. + # Serializes a {Nodes::Node Node} and dumps it as a YAML object into filepath. # @param [Nodes::Node] node the node to serialize - # @param [String] filepath the full path of the file to dump the YAML - # object into. + # @param [String] filepath the full path of the file to dump the YAML object into. # @return [Numeric] number of bytes written to disk. - # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-dump - # Psych.dump + # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/psych/rdoc/Psych.html#method-c-dump Psych.dump def dump node, filepath require 'yaml' serializer.dump ::YAML.dump(node), filepath diff --git a/lib/rambling/trie/serializers/zip.rb b/lib/rambling/trie/serializers/zip.rb index 8c01f96b..2f01886c 100644 --- a/lib/rambling/trie/serializers/zip.rb +++ b/lib/rambling/trie/serializers/zip.rb @@ -11,8 +11,8 @@ class Zip < Serializer # @param [Configuration::Properties] properties the configuration # properties set up so far. def initialize properties - @properties = properties super() + @properties = properties end # Unzip contents from specified filepath and load in contents from diff --git a/spec/support/shared_examples/a_serializer.rb b/spec/support/shared_examples/a_serializer.rb index 4b7882fd..b5029d77 100644 --- a/spec/support/shared_examples/a_serializer.rb +++ b/spec/support/shared_examples/a_serializer.rb @@ -52,9 +52,7 @@ it "loads a compressed=#{compress_value} object" do loaded = serializer.load filepath - if :file != file_format - expect(loaded.compressed?).to be compress_value - end + expect(loaded.compressed?).to be compress_value unless :file == file_format end end end From bd058ad95882b7dc221cd1239d471d8b22aea235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Mon, 15 May 2023 21:43:42 -0400 Subject: [PATCH 57/58] Add CodeClimate plugin: flog (#52) --- .codeclimate.yml | 7 +++++++ Gemfile | 1 + 2 files changed, 8 insertions(+) diff --git a/.codeclimate.yml b/.codeclimate.yml index 95efb8ae..f16a69c4 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -6,6 +6,13 @@ plugins: enabled: true exclude_patterns: - '.rubocop.*' + # ABC-complexity + flog: + enabled: true + config: + score_threshold: 25.0 + exclude_patterns: + - 'spec/' # Markdown lint with rules from https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md markdownlint: enabled: true diff --git a/Gemfile b/Gemfile index f4628b49..d0a2acf1 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,7 @@ group :test do end group :local do + gem 'flog', require: false gem 'guard-rspec' gem 'mdl', require: false gem 'rubocop', require: false From 978717b222cc1940825ba67ab45ba972b46b3518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Gonz=C3=A1lez?= Date: Mon, 15 May 2023 22:16:56 -0400 Subject: [PATCH 58/58] GitHub Action: semgrep (#54) --- .github/workflows/semgrep.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/semgrep.yml diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml new file mode 100644 index 00000000..5b0c0c33 --- /dev/null +++ b/.github/workflows/semgrep.yml @@ -0,0 +1,25 @@ +name: semgrep +on: + workflow_dispatch: {} + pull_request: {} + push: + branches: + - main + - master + paths: + - .github/workflows/semgrep.yml + schedule: + # random HH:MM to avoid a load spike on GitHub Actions at 00:00 + - cron: '42 4 * * *' +jobs: + semgrep: + name: semgrep + runs-on: ubuntu-20.04 + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + container: + image: returntocorp/semgrep + if: (github.actor != 'dependabot[bot]') + steps: + - uses: actions/checkout@v3 + - run: semgrep ci