diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 0000000..327ba5d --- /dev/null +++ b/.github/workflows/ruby.yml @@ -0,0 +1,20 @@ +# Build and test the RubyTree library. +# +# This runs as a Github Action. + +name: Build and Test +on: [push, pull_request] +jobs: + test: + strategy: + fail-fast: false + matrix: + ruby: ["2.6", "2.7", "3.0"] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - run: bundle exec rake clobber test:all gem:package diff --git a/.gitignore b/.gitignore index 3c32160..3663129 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ tmp/ .bundle/ vendor/ .idea/ - +Gemfile.lock diff --git a/.ruby-version b/.ruby-version index 1effb00..2eb2fe9 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7 +ruby-2.7.2 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ad23eba..0000000 --- a/.travis.yml +++ /dev/null @@ -1,32 +0,0 @@ -language: ruby -before_install: - - gem install bundler - - 'echo "gem: --no-ri --no-rdoc" > ~/.gemrc' - - bundle --version - - gem --version -bundler_args: --without development - -rvm: - - 2.4 - - 2.5 - - 2.6 - - 2.7 - -matrix: - allow_failures: - - rvm: rbx # rbx is still troublesome. - include: - - rvm: rbx - gemfile: gemfiles/Gemfile.rbx - # - rvm: 2.4.3 # - # env: COVERAGE=true # - exclude: - - rvm: rbx - gemfile: Gemfile - -# blacklist -branches: - except: - - develop - - rt-site - - gh-pages diff --git a/API-CHANGES.rdoc b/API-CHANGES.rdoc index b63932c..49df347 100644 --- a/API-CHANGES.rdoc +++ b/API-CHANGES.rdoc @@ -9,6 +9,22 @@ Note: API level changes are expected to reduce dramatically after the 1.x release. In most cases, an alternative will be provided to ensure relatively smooth transition to the new APIs. +== Release 2.0.0 Changes + +- The minimum required Ruby version is now '2.6.x' (and higher). + +- The long-broken 'Tree::TreeNode#depth' method has been finally removed. Use + {Tree::TreeNode#node_depth}[rdoc-ref:Tree::Utils::TreeMetricsHandler#node_depth] instead. + +- Support for 'CamelCase' methods has been removed. This was a legacy shim that + has hopefully outlived its usefulness. + +- Use of integers as node-names now no longer requires the optional + 'num_as_name' flag. + +- 'structured_warnings' has been removed from the code-base and is no longer a + dependency. This was a long-standing point of friction for many users. + == Release 0.9.5 Changes - The {Tree::TreeNode#add} method now provides 'move' semantics, if a child @@ -95,5 +111,4 @@ smooth transition to the new APIs. # Local Variables: # mode: rdoc -# coding: utf-8-unix # End: diff --git a/Gemfile b/Gemfile index 5f4d94f..bb94df8 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,4 @@ -source 'https://rubygems.org' +# frozen_string_literal: true -# Specify your gem's dependencies in rubytree.gemspec +source "https://rubygems.org" gemspec - -# Local Variables: -# mode: ruby -# End: diff --git a/Gemfile.lock b/Gemfile.lock index bd2b87e..b9d16be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,28 +1,20 @@ PATH remote: . specs: - rubytree (1.0.2) - json (~> 2.6.1) - structured_warnings (~> 0.4.0) + rubytree (2.0.0.pre) + json (> 2.3.1) GEM remote: https://rubygems.org/ specs: ast (2.4.2) - coveralls (0.8.23) - json (>= 1.8, < 3) - simplecov (~> 0.16.1) - term-ansicolor (~> 1.3) - thor (>= 0.19.4, < 2.0) - tins (~> 1.6) diff-lcs (1.5.0) - docile (1.4.0) - json (2.6.1) + json (2.6.2) parallel (1.21.0) parser (3.0.3.2) ast (~> 2.4.1) power_assert (2.0.1) - psych (4.0.3) + psych (4.0.4) stringio rainbow (3.0.0) rake (13.0.6) @@ -30,19 +22,19 @@ GEM psych (>= 4.0.0) regexp_parser (2.2.0) rexml (3.2.5) - rspec (3.10.0) - rspec-core (~> 3.10.0) - rspec-expectations (~> 3.10.0) - rspec-mocks (~> 3.10.0) - rspec-core (3.10.1) - rspec-support (~> 3.10.0) - rspec-expectations (3.10.1) + rspec (3.11.0) + rspec-core (~> 3.11.0) + rspec-expectations (~> 3.11.0) + rspec-mocks (~> 3.11.0) + rspec-core (3.11.0) + rspec-support (~> 3.11.0) + rspec-expectations (3.11.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-mocks (3.10.2) + rspec-support (~> 3.11.0) + rspec-mocks (3.11.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-support (3.10.3) + rspec-support (~> 3.11.0) + rspec-support (3.11.0) rtags (0.97) rtagstask (0.0.4) rtags (> 0.0.0) @@ -57,41 +49,34 @@ GEM unicode-display_width (>= 1.4.0, < 3.0) rubocop-ast (1.15.1) parser (>= 3.0.1.1) + rubocop-rake (0.6.0) + rubocop (~> 1.0) + rubocop-rspec (2.11.1) + rubocop (~> 1.19) ruby-progressbar (1.11.0) - simplecov (0.16.1) - docile (~> 1.1) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - stringio (3.0.1) - structured_warnings (0.4.0) - sync (0.5.0) - term-ansicolor (1.7.1) - tins (~> 1.0) + stringio (3.0.2) test-unit (3.5.3) power_assert - thor (1.1.0) - tins (1.30.0) - sync unicode-display_width (2.1.0) webrick (1.7.0) - yard (0.9.27) + yard (0.9.28) webrick (~> 1.7.0) PLATFORMS ruby DEPENDENCIES - bundler (~> 2.3.4) - coveralls (>= 0.8.23) - rake (>= 13.0.6) - rdoc (>= 6.4.0) - rspec (~> 3.10.0) - rtagstask (~> 0.0.4) - rubocop (>= 1.24.0) + bundler + rake + rdoc + rspec + rtagstask + rubocop + rubocop-rake + rubocop-rspec rubytree! - test-unit (>= 3.5.3) - yard (~> 0.9.27) + test-unit + yard BUNDLED WITH 2.3.4 diff --git a/History.rdoc b/History.rdoc index e9e0f68..a0cb18a 100644 --- a/History.rdoc +++ b/History.rdoc @@ -1,9 +1,25 @@ = History of Changes +=== 2.0.0 / 2022-06-21 + +* A major release with significant modernization to the code base and removal of + legacy cruft, thanks to {https://github.com/jmortlock jmortlock}. + +* The long deprecated {Tree::TreeNode#depth} method has finally been removed. + Use {Tree::TreeNode#node_depth} instead. + +* Support for CamelCase methods has been dropped. + +* RubyTree now supports MRI Ruby versions 2.6.x, 2,7,x, and 3.0,x. + +* Explicit support for rbx Ruby has been removed. + +* RubyTree now uses Github Actions for its CI pipeline. + === 1.0.2 / 2021-12-29 * A minor maintenance version to address a minor but annoying warning for -circular dependencies. + circular dependencies. === 1.0.1 / 2021-12-29 diff --git a/LICENSE.md b/LICENSE.md index 8fcac8e..0a872aa 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ [RubyTree][] is licensed under the [BSD][] license. -Copyright (c) 2006-2021 Anupam Sengupta (). +Copyright (c) 2006-2022 Anupam Sengupta (). All rights reserved. diff --git a/README.md b/README.md index 2ec0fe0..ce5ab75 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # **RubyTree** # @@ -54,7 +54,7 @@ See the [API][rt_doc] documentation for more details. # # example_basic.rb:: Basic usage of the tree library. # -# Copyright (C) 2013-2021 Anupam Sengupta +# Copyright (C) 2013-2022 Anupam Sengupta # # The following example implements this tree structure: # @@ -117,11 +117,10 @@ This example can also be found at ## REQUIREMENTS: ## -* [Ruby][] 2.7.x+ +* [Ruby][] 2.6.x and above. * Run-time Dependencies: - * [structured_warnings][] * [JSON][] for converting to/from the JSON format @@ -130,6 +129,7 @@ This example can also be found at * [Rake][] for building the package * [Yard][] for the documentation * [RSpec][] for additional Ruby Spec test files + * [Rubocop][] for linting the code. ## INSTALL: ## @@ -193,9 +193,9 @@ After checking out the source, run: $ gem install bundler $ bundle install - $ rake test - $ rake doc:yard - $ rake gem:package + $ bundle exec rake test:all + $ bundle exec rake doc:yard + $ bundle exec rake gem:package These steps will install any missing dependencies, run the tests/specs, generate the documentation, and finally generate the gem file. @@ -223,6 +223,8 @@ A big thanks to the following contributors for helping improve **RubyTree**: to `is_root?` and `node_depth`. 10. [Marco Ziccadi](https://github.com/MZic) for adding the `path_as_string` and `path_as_array` methods. +11. [John Mortlock](https://github.com/jmortlock) for significant modernization + of the library code and addition of Github `workflows`. ## LICENSE: ## @@ -259,8 +261,8 @@ A big thanks to the following contributors for helping improve **RubyTree**: [rt_doc]: http://rubytree.anupamsg.me/rdoc "RubyTree Documentation" [rt_gem]: http://rubygems.org/gems/rubytree "RubyTree Gem" [rt_site]: http://rubytree.anupamsg.me "RubyTree Site" -[structured_warnings]: http://github.com/schmidt/structured_warnings "structured_warnings" [tree_data_structure]: http://en.wikipedia.org/wiki/Tree_data_structure "Tree Data Structure" [RSpec]: https://relishapp.com/rspec/ +[Rubocop]: https://rubocop.org [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/evolve75/rubytree/trend.png)](https://bitdeli.com/free "Bitdeli Badge") diff --git a/Rakefile b/Rakefile index d49bbd2..b54e3d6 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ # # Rakefile - This file is part of the RubyTree package. # -# Copyright (c) 2006-2021 Anupam Sengupta +# Copyright (c) 2006-2022 Anupam Sengupta # # All rights reserved. # @@ -95,10 +95,13 @@ namespace :doc do # ................................ Documentation end end -desc 'Run the test cases' -task test: 'test:unit' +desc 'Run the unit tests' +task test: %w[test:unit] namespace :test do # ................................ Test related + desc 'Run all the tests' + task all: %w[test:unit test:spec test:examples] + require 'rake/testtask' Rake::TestTask.new(:unit) do |test| test.libs << 'lib' << 'test' @@ -106,6 +109,17 @@ namespace :test do # ................................ Test related test.verbose = false end + begin # ................................ rspec tests + require 'rspec/core/rake_task' + + RSpec::Core::RakeTask.new(:spec) do |t| + t.fail_on_error = false + t.rspec_opts = ['--color', '--format doc'] + end + rescue LoadError + # Cannot load rspec. + end + desc 'Run the examples' Rake::TestTask.new(:examples) do |example| example.libs << 'lib' << 'examples' @@ -132,17 +146,6 @@ namespace :test do # ................................ Test related end end -begin # ................................ rspec tests - require 'rspec/core/rake_task' - - RSpec::Core::RakeTask.new(:spec) do |t| - t.fail_on_error = false - t.rspec_opts = ['--color', '--format doc'] - end -rescue LoadError - # Cannot load rspec. -end - namespace :tag do # ................................ Emacs Tags require 'rtagstask' RTagsTask.new(:tags) do |rd| @@ -165,3 +168,11 @@ namespace :gem do # ................................ Gem related sh "gem push pkg/#{GEM_NAME}" end end + +require 'rubocop/rake_task' # ................................ Ruby linting + +RuboCop::RakeTask.new(:rubocop) do |t| + t.options = ['--display-cop-names'] + t.requires << 'rubocop-rake' + t.requires << 'rubocop-rspec' +end diff --git a/TODO.org b/TODO.org index 1f039c4..938f3dc 100644 --- a/TODO.org +++ b/TODO.org @@ -183,10 +183,7 @@ This proposed change does make sense at one level (since the root node does not have any parent), but returning root as root's root (no pun intended) makes accessing the root from anywhere in the tree much easier. - - - -* R0.9.5 +* R0.9.5 :ARCHIVE: ** DONE Add the `#get_path_as_string` method from feature request #48 :ARCHIVE: CLOSED: [2015-05-30 Sat 15:55] ** DONE Fix [[Issue:32][Issue #32]] and enable move semantics on the TreeNode#add method. :ARCHIVE: @@ -202,11 +199,20 @@ CLOSED: [2014-11-01 Sat 20:11] +* R2.0.0 + + This is primarily a *modernization* of the library, with removal of deprecated methods, the much-hated dependency on + ~structured_warnings~, and cleanup of other cruft. + + In addition, the CI pipeline has been moved from to ~Github Actions~. +- [X] Merge the modernization PR from @jmortlock (multiple changes). +- [X] Update the documentation to reflect the modernization changes. -* Next Release - DEADLINE: <2014-12-01 Mon> -** STARTED [#A] Resolve the infinite loop bug if a node is added to itself as a child :Partial: + +* Unplanned / Not assigned to any release +*** STARTED Convert all documentation to markdown mode. +*** STARTED [#A] Resolve the infinite loop bug if a node is added to itself as a child :Partial: [[Issue:5][Issue #5.]] This is a subtle problem to resolve. The specific case of a node @@ -237,15 +243,8 @@ duplicates). This needs to be a hash (to allow O(1) access), and will sacrifice memory. There might be a need to restructure the internals to make better use of memory. -** STARTED Convert all documentation to markdown mode. -** TODO Expand the examples section, and add supporting documentation +*** TODO Expand the examples section, and add supporting documentation -* Unplanned / Not assigned to any release -*** DONE [#A] Migrate the website and references from http://rubyforge.org/ :ARCHIVE: - CLOSED: [2014-07-04 Fri 22:18] -*** DONE Revert the forced install of rubygem 2.1.11 from [[file:.travis.yml][.travis.yml]] :ARCHIVE: - CLOSED: [2014-01-12 Sun 19:06] - The issue seems to have been resolved with the 2.2.1 release of Rubygems. *** TODO Create a cycle-detection/validation mechanism to prevent cyclic graphs of nodes. *** TODO Create a generic validation method to check for various issues in the created tree. *** TODO Add a FAQ document to the project. @@ -258,6 +257,11 @@ *** TODO Add a YAML export method to the TreeNode class. *** TODO marshal_load method probably should be a class method. It currently clobbers self. +*** DONE Revert the forced install of rubygem 2.1.11 from [[file:.travis.yml][.travis.yml]] :ARCHIVE: + CLOSED: [2014-01-12 Sun 19:06] + The issue seems to have been resolved with the 2.2.1 release of Rubygems. +*** DONE [#A] Migrate the website and references from http://rubyforge.org/ :ARCHIVE: + CLOSED: [2014-07-04 Fri 22:18] *** DONE Fix bug # [[http://rubyforge.org/tracker/index.php%3Ffunc%3Ddetail&aid%3D22535&group_id%3D1215&atid%3D4793][22535]]: The method Tree::TreeNode#depth is a misnomer. The current definition actually provides the height function. :ARCHIVE: DEADLINE: <2010-01-09 Sat> CLOSED: [2010-01-03 Sun 22:15] diff --git a/gemfiles/Gemfile.rbx b/gemfiles/Gemfile.rbx deleted file mode 100644 index 732d40d..0000000 --- a/gemfiles/Gemfile.rbx +++ /dev/null @@ -1,17 +0,0 @@ -source 'https://rubygems.org' - -# Specify your gem's dependencies in rubytree.gemspec -gemspec path: '..' - -platforms :rbx do - gem 'rubysl' - gem 'rubysl-test-unit' -end - -group :development, :test do - gem 'rake', '~> 10.1' -end - -# Local Variables: -# mode: ruby -# End: diff --git a/lib/tree.rb b/lib/tree.rb index afe1712..923e089 100644 --- a/lib/tree.rb +++ b/lib/tree.rb @@ -9,7 +9,7 @@ # Author:: Anupam Sengupta (anupamsg@gmail.com) # -# Copyright (c) 2006-2021 Anupam Sengupta +# Copyright (c) 2006-2022 Anupam Sengupta # # All rights reserved. # @@ -88,7 +88,6 @@ class TreeNode include Comparable include Tree::Utils::TreeMetricsHandler include Tree::Utils::TreePathHandler - include Tree::Utils::CamelCaseMethodHandler include Tree::Utils::JSONConverter include Tree::Utils::TreeMergeHandler include Tree::Utils::HashConverter @@ -215,17 +214,10 @@ def has_children? # # @see #[] def initialize(name, content = nil) - raise ArgumentError, 'Node name HAS to be provided!' if name.nil? + raise ArgumentError, 'Node name HAS to be provided!' if name == nil - @name = name - @content = content - - if name.is_a?(Integer) - warn StructuredWarnings::StandardWarning, - 'Using integer as node name.'\ - ' Semantics of TreeNode[] may not be what you expect!'\ - " #{name} #{content}" - end + name = name.to_s if name.kind_of?(Integer) + @name, @content = name, content set_as_root! @children_hash = {} @@ -560,45 +552,32 @@ def freeze_tree! # # - If the +name+ argument is an _Integer_, then the in-sequence # array of children is accessed using the argument as the - # *index* (zero-based). However, if the second _optional_ - # +num_as_name+ argument is +true+, then the +name+ is used - # literally as a name, and *NOT* as an *index* + # *index* (zero-based). # # - If the +name+ argument is *NOT* an _Integer_, then it is taken to # be the *name* of the child node to be returned. # - # If a non-+Integer+ +name+ is passed, and the +num_as_name+ - # parameter is also +true+, then a warning is thrown (as this is a - # redundant use of the +num_as_name+ flag.) + # - To use an _Integer_ as the name, convert it to a _String_ first using + # +.to_s+. # # @param [String|Number] name_or_index Name of the child, or its # positional index in the array of child nodes. # - # @param [Boolean] num_as_name Whether to treat the +Integer+ - # +name+ argument as an actual name, and *NOT* as an _index_ to - # the children array. - # # @return [Tree::TreeNode] the requested child node. If the index # in not in range, or the name is not present, then a +nil+ # is returned. # - # @note The use of +Integer+ names is allowed by using the optional - # +num_as_name+ flag. - # # @raise [ArgumentError] Raised if the +name_or_index+ argument is +nil+. # # @see #add # @see #initialize - def [](name_or_index, num_as_name = false) - raise ArgumentError, 'Name_or_index needs to be provided!' if name_or_index.nil? + def [](name_or_index) + raise ArgumentError, + 'Name_or_index needs to be provided!' if name_or_index == nil - if name_or_index.is_a?(Integer) && !num_as_name + if name_or_index.kind_of?(Integer) @children[name_or_index] else - if num_as_name && !name_or_index.is_a?(Integer) - warn StructuredWarnings::StandardWarning, - 'Redundant use of the `num_as_name` flag for non-integer node name' - end @children_hash[name_or_index] end end diff --git a/lib/tree/tree_deps.rb b/lib/tree/tree_deps.rb index 8f05d8e..385df56 100644 --- a/lib/tree/tree_deps.rb +++ b/lib/tree/tree_deps.rb @@ -37,13 +37,11 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -require 'structured_warnings' require 'json' require_relative '../tree/version' require_relative '../tree/utils/metrics_methods' require_relative '../tree/utils/path_methods' -require_relative '../tree/utils/camel_case_method_handler' require_relative '../tree/utils/json_converter' require_relative '../tree/utils/tree_merge_handler' require_relative '../tree/utils/hash_converter' diff --git a/lib/tree/utils/camel_case_method_handler.rb b/lib/tree/utils/camel_case_method_handler.rb deleted file mode 100644 index dd7315a..0000000 --- a/lib/tree/utils/camel_case_method_handler.rb +++ /dev/null @@ -1,77 +0,0 @@ -# camel_case_methods.rb - This file is part of the RubyTree package. -# -# = camel_case_methods.rb - Provides conversion from CamelCase to snake_case. -# -# Author:: Anupam Sengupta (anupamsg@gmail.com) -# -# Time-stamp: <2021-12-29 13:02:04 anupam> -# -# Copyright (C) 2012, 2013, 2015, 2017, 2021 Anupam Sengupta -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# - Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# - Neither the name of the organization nor the names of its contributors may -# be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -require 'structured_warnings' - -module Tree::Utils - # Provides utility functions to handle CamelCase methods, and redirect - # invocation of such methods to the snake_case equivalents. - module CamelCaseMethodHandler - def self.included(_base) - # @!visibility private - # Allow the deprecated CamelCase method names. Display a warning. - # :nodoc: - def method_missing(meth, *args, &blk) - if respond_to?((new_method_name = to_snake_case(meth))) - warn StructuredWarnings::DeprecatedMethodWarning, - 'The camelCased methods are deprecated. ' + - "Please use #{new_method_name} instead of #{meth}" - send(new_method_name, *args, &blk) - else - super - end - end - - # @!visibility private - # Convert a CamelCasedWord to a underscore separated camel_cased_word. - # - # @param [String] camel_cased_word The word to be converted to snake_case. - # @return [String] the snake_cased_word. - def to_snake_case(camel_cased_word) - word = camel_cased_word.to_s - word.gsub!(/::/, '/') - word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') - word.gsub!(/([a-z\d])([A-Z])/, '\1_\2') - word.tr!('-', '_') - word.downcase! - word - end - protected :to_snake_case - end # self.included - end -end diff --git a/lib/tree/utils/hash_converter.rb b/lib/tree/utils/hash_converter.rb index 719027e..568325a 100644 --- a/lib/tree/utils/hash_converter.rb +++ b/lib/tree/utils/hash_converter.rb @@ -37,8 +37,6 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -require_relative '../../../lib/tree/utils/utils' - module Tree::Utils::HashConverter def self.included(base) base.extend(ClassMethods) diff --git a/lib/tree/utils/json_converter.rb b/lib/tree/utils/json_converter.rb index e05b928..d4a6ea7 100644 --- a/lib/tree/utils/json_converter.rb +++ b/lib/tree/utils/json_converter.rb @@ -35,7 +35,6 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -require_relative '../utils/utils' require 'json' # Provides utility methods to convert a {Tree::TreeNode} to and from diff --git a/lib/tree/utils/metrics_methods.rb b/lib/tree/utils/metrics_methods.rb index c0618c5..d5e6628 100644 --- a/lib/tree/utils/metrics_methods.rb +++ b/lib/tree/utils/metrics_methods.rb @@ -4,9 +4,9 @@ # # Author:: Anupam Sengupta (anupamsg@gmail.com) # -# Time-stamp: <2021-12-29 13:01:54 anupam> +# Time-stamp: <2022-06-13 21:23:46 anupam> # -# Copyright (C) 2013, 2015, 2017, 2021 Anupam Sengupta +# Copyright (C) 2013, 2015, 2017, 2021, 2022 Anupam Sengupta # # All rights reserved. # @@ -36,8 +36,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -require 'structured_warnings' - module Tree::Utils # Provides utility functions to measure various tree metrics. module TreeMetricsHandler @@ -111,33 +109,6 @@ def level node_depth end - # @!attribute [r] depth - # Depth of the tree from this node. A single leaf node has a depth of 1. - # - # This method is *DEPRECATED* and may be removed in the subsequent - # releases. Note that the value returned by this method is actually the: - # - # _height_ + 1 of the node, *NOT* the _depth_. - # - # For correct and conventional behavior, please use {#node_depth} and - # {#node_height} methods instead. - # - # @return [Integer] depth of the node. - # - # @deprecated This method returns an incorrect value. Use the - # {#node_depth} method instead. - # - # @see #node_depth - def depth - warn StructuredWarnings::DeprecatedMethodWarning, - 'This method is deprecated. '\ - 'Please use node_depth() or node_height() instead (bug # 22535)' - - return 1 if is_leaf? - - 1 + @children.collect { |child| child.depth }.max - end - # @!attribute [r] breadth # Breadth of the tree at this node's level. # A single node without siblings has a breadth of 1. diff --git a/lib/tree/utils/tree_merge_handler.rb b/lib/tree/utils/tree_merge_handler.rb index 3548987..28b2ddb 100755 --- a/lib/tree/utils/tree_merge_handler.rb +++ b/lib/tree/utils/tree_merge_handler.rb @@ -35,8 +35,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -require_relative '../../../lib/tree/utils/utils' - # Provides utility methods to merge two {Tree::TreeNode} based trees. # @since 0.9.0 module Tree::Utils::TreeMergeHandler diff --git a/lib/tree/version.rb b/lib/tree/version.rb index 6c8ac29..a8d2937 100644 --- a/lib/tree/version.rb +++ b/lib/tree/version.rb @@ -4,9 +4,7 @@ # # Author:: Anupam Sengupta (anupamsg@gmail.com) # -# Copyright (c) 2012, 2013, 2014, 2015, 2017, 2020, 2021 Anupam Sengupta -# -# All rights reserved. +# Copyright (c) 2012-2022 Anupam Sengupta. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -36,5 +34,5 @@ module Tree # Rubytree Package Version - VERSION = '1.0.2'.freeze + VERSION = '2.0.0.pre'.freeze end diff --git a/rubytree.gemspec b/rubytree.gemspec index 078bc2d..d54a743 100644 --- a/rubytree.gemspec +++ b/rubytree.gemspec @@ -3,14 +3,13 @@ # # Author:: Anupam Sengupta (anupamsg@gmail.com) # -# Copyright (c) 2012, 2013, 2014, 2015, 2017, 2020, 2021 Anupam Sengupta -# All rights reserved. +# Copyright (c) 2012-2022 Anupam Sengupta. All rights reserved. require './lib/tree/version' Gem::Specification.new do |s| s.name = 'rubytree' - s.date = '2021-12-29' + s.date = '2022-06-21' s.version = Tree::VERSION s.license = 'BSD-3-Clause-Clear' @@ -19,10 +18,11 @@ Gem::Specification.new do |s| s.email = 'anupamsg@gmail.com' s.homepage = 'http://rubytree.anupamsg.me' - s.required_ruby_version = '>=2.7' + s.required_ruby_version = '>=2.6' s.summary = 'A generic tree data structure.' - s.description = <<-END_OF_TEXT + # @todo: Check if this can be formatted in Markdown or RD. + s.description = <<-EOF RubyTree is a pure Ruby implementation of the generic tree data structure. It provides a node-based model to store named nodes in the tree, and provides @@ -47,7 +47,7 @@ Gem::Specification.new do |s| The home page for RubyTree is at http://rubytree.anupamsg.me. - END_OF_TEXT + EOF s.files = Dir['lib/**/*.rb'] # The actual code s.files += Dir['[A-Z]*'] # Various documentation files @@ -55,6 +55,7 @@ Gem::Specification.new do |s| s.files += Dir['spec/**/*.rb'] # Rspec Test cases s.files += Dir['examples/**/*.rb'] # Examples + # @todo: Check if this is really needed. s.files += ['.gemtest'] # Support for gem-test s.require_paths = ['lib'] @@ -64,27 +65,40 @@ Gem::Specification.new do |s| s.extra_rdoc_files = %w[README.md LICENSE.md API-CHANGES.rdoc History.rdoc] s.rdoc_options = ['--title', 'Rubytree Documentation', '--quiet'] - s.add_runtime_dependency 'json', '~> 2.6.1' - s.add_runtime_dependency 'structured_warnings', '~> 0.4.0' - - # Development dependencies. - s.add_development_dependency 'bundler', '~> 2.3.4' - s.add_development_dependency 'coveralls', '>= 0.8.23' - s.add_development_dependency 'rake', '>= 13.0.6' - s.add_development_dependency 'rdoc', '>= 6.4.0' - s.add_development_dependency 'rspec', '~> 3.10.0' - s.add_development_dependency 'rtagstask', '~> 0.0.4' - s.add_development_dependency 'rubocop', '>= 1.24.0' - s.add_development_dependency 'test-unit', '>= 3.5.3' - s.add_development_dependency 'yard', '~> 0.9.27' - - s.post_install_message = <<-END_OF_TEXT + s.add_runtime_dependency 'json', '> 2.3.1' + + # Note: Rake is added as a development and test dependency in the Gemfile. + s.add_development_dependency 'bundler' + s.add_development_dependency 'rdoc' + s.add_development_dependency 'yard' + s.add_development_dependency 'rtagstask' + s.add_development_dependency 'rspec' + s.add_development_dependency "rake" + s.add_development_dependency "test-unit" + s.add_development_dependency "rubocop" + s.add_development_dependency "rubocop-rake" + s.add_development_dependency "rubocop-rspec" + + s.post_install_message = <<-EOF ======================================================================== Thank you for installing RubyTree. - Note:: As of 1.0.1, RubyTree can only support MRI Ruby >= 2.7.x + Note:: + + - 2.0.0 is a major release with BREAKING API changes. + See `API-CHANGES.rdoc` for details. + + - `Tree::TreeNode#depth` method has been removed (it was broken). + + - Support for `CamelCase` methods names has bee removed. + + - Use of integers as node names does not require the optional + `num_as_name` flag. + + - `structured_warnings` is no longer a dependency. + + - Explicit support for rbx Ruby has been removed. - Details of the API changes are documented in the API-CHANGES file. ======================================================================== - END_OF_TEXT + EOF end diff --git a/setup.rb b/setup.rb deleted file mode 100644 index e97af80..0000000 --- a/setup.rb +++ /dev/null @@ -1,1565 +0,0 @@ -# -# setup.rb -# -# Copyright (c) 2000-2005 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU LGPL, Lesser General Public License version 2.1. -# - -unless Enumerable.method_defined?(:map) # Ruby 1.4.6 - module Enumerable - alias map collect - end -end - -unless File.respond_to?(:read) # Ruby 1.6 - def File.read(fname) - open(fname) do |f| - return f.read - end - end -end - -unless Errno.const_defined?(:ENOTEMPTY) # Windows? - module Errno - class ENOTEMPTY - # We do not raise this exception, implementation is not needed. - end - end -end - -def File.binread(fname) - open(fname, 'rb') do |f| - return f.read - end -end - -# for corrupted Windows' stat(2) -def File.dir?(path) - File.directory?(path[-1, 1] == '/' ? path : path + '/') -end - -class ConfigTable - include Enumerable - - def initialize(rbconfig) - @rbconfig = rbconfig - @items = [] - @table = {} - # options - @install_prefix = nil - @config_opt = nil - @verbose = true - @no_harm = false - end - - attr_accessor :install_prefix, :config_opt - - attr_writer :verbose, :no_harm - - def verbose? - @verbose - end - - def no_harm? - @no_harm - end - - def [](key) - lookup(key).resolve(self) - end - - def []=(key, val) - lookup(key).set val - end - - def names - @items.map { |i| i.name } - end - - def each(&block) - @items.each(&block) - end - - def key?(name) - @table.key?(name) - end - - def lookup(name) - @table[name] or setup_rb_error "no such config item: #{name}" - end - - def add(item) - @items.push item - @table[item.name] = item - end - - def remove(name) - item = lookup(name) - @items.delete_if { |i| i.name == name } - @table.delete_if { |name, i| i.name == name } - item - end - - def load_script(path, inst = nil) - MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path if File.file?(path) - end - - def savefile - '.config' - end - - def load_savefile - File.foreach(savefile) do |line| - k, v = *line.split(/=/, 2) - self[k] = v.strip - end - rescue Errno::ENOENT - setup_rb_error $!.message + "\n#{File.basename($0)} config first" - end - - def save - @items.each { |i| i.value } - File.open(savefile, 'w') do |f| - @items.each do |i| - f.printf "%s=%s\n", i.name, i.value if i.value? and i.value - end - end - end - - def load_standard_entries - standard_entries(@rbconfig).each do |ent| - add ent - end - end - - def standard_entries(rbconfig) - c = rbconfig - - rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) - - major = c['MAJOR'].to_i - minor = c['MINOR'].to_i - teeny = c['TEENY'].to_i - version = "#{major}.#{minor}" - - # ruby ver. >= 1.4.4? - newpath_p = ((major >= 2) or - ((major == 1) and - ((minor >= 5) or - ((minor == 4) and (teeny >= 4))))) - - if c['rubylibdir'] - # V > 1.6.3 - libruby = "#{c['prefix']}/lib/ruby" - librubyver = c['rubylibdir'] - librubyverarch = c['archdir'] - siteruby = c['sitedir'] - siterubyver = c['sitelibdir'] - siterubyverarch = c['sitearchdir'] - elsif newpath_p - # 1.4.4 <= V <= 1.6.3 - libruby = "#{c['prefix']}/lib/ruby" - librubyver = "#{c['prefix']}/lib/ruby/#{version}" - librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" - siteruby = c['sitedir'] - siterubyver = "$siteruby/#{version}" - siterubyverarch = "$siterubyver/#{c['arch']}" - else - # V < 1.4.4 - libruby = "#{c['prefix']}/lib/ruby" - librubyver = "#{c['prefix']}/lib/ruby/#{version}" - librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" - siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" - siterubyver = siteruby - siterubyverarch = "$siterubyver/#{c['arch']}" - end - parameterize = lambda { |path| - path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') - } - - makeprog = if arg = c['configure_args'].split.detect { |arg| /--with-make-prog=/ =~ arg } - arg.sub(/'/, '').split(/=/, 2)[1] - else - 'make' - end - - [ - ExecItem.new('installdirs', 'std/site/home', - 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ - do |val, table| - case val - when 'std' - table['rbdir'] = '$librubyver' - table['sodir'] = '$librubyverarch' - when 'site' - table['rbdir'] = '$siterubyver' - table['sodir'] = '$siterubyverarch' - when 'home' - setup_rb_error '$HOME was not set' unless ENV['HOME'] - table['prefix'] = ENV['HOME'] - table['rbdir'] = '$libdir/ruby' - table['sodir'] = '$libdir/ruby' - end - end, - PathItem.new('prefix', 'path', c['prefix'], - 'path prefix of target environment'), - PathItem.new('bindir', 'path', parameterize.call(c['bindir']), - 'the directory for commands'), - PathItem.new('libdir', 'path', parameterize.call(c['libdir']), - 'the directory for libraries'), - PathItem.new('datadir', 'path', parameterize.call(c['datadir']), - 'the directory for shared data'), - PathItem.new('mandir', 'path', parameterize.call(c['mandir']), - 'the directory for man pages'), - PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), - 'the directory for system configuration files'), - PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), - 'the directory for local state data'), - PathItem.new('libruby', 'path', libruby, - 'the directory for ruby libraries'), - PathItem.new('librubyver', 'path', librubyver, - 'the directory for standard ruby libraries'), - PathItem.new('librubyverarch', 'path', librubyverarch, - 'the directory for standard ruby extensions'), - PathItem.new('siteruby', 'path', siteruby, - 'the directory for version-independent aux ruby libraries'), - PathItem.new('siterubyver', 'path', siterubyver, - 'the directory for aux ruby libraries'), - PathItem.new('siterubyverarch', 'path', siterubyverarch, - 'the directory for aux ruby binaries'), - PathItem.new('rbdir', 'path', '$siterubyver', - 'the directory for ruby scripts'), - PathItem.new('sodir', 'path', '$siterubyverarch', - 'the directory for ruby extentions'), - PathItem.new('rubypath', 'path', rubypath, - 'the path to set to #! line'), - ProgramItem.new('rubyprog', 'name', rubypath, - 'the ruby program using for installation'), - ProgramItem.new('makeprog', 'name', makeprog, - 'the make program to compile ruby extentions'), - SelectItem.new('shebang', 'all/ruby/never', 'ruby', - 'shebang line (#!) editing mode'), - BoolItem.new('without-ext', 'yes/no', 'no', - 'does not compile/install ruby extentions') - ] - end - private :standard_entries - - def load_multipackage_entries - multipackage_entries.each do |ent| - add ent - end - end - - def multipackage_entries - [ - PackageSelectionItem.new('with', 'name,name...', '', 'ALL', - 'package names that you want to install'), - PackageSelectionItem.new('without', 'name,name...', '', 'NONE', - 'package names that you do not want to install') - ] - end - private :multipackage_entries - - ALIASES = { - 'std-ruby' => 'librubyver', - 'stdruby' => 'librubyver', - 'rubylibdir' => 'librubyver', - 'archdir' => 'librubyverarch', - 'site-ruby-common' => 'siteruby', # For backward compatibility - 'site-ruby' => 'siterubyver', # For backward compatibility - 'bin-dir' => 'bindir', - 'rb-dir' => 'rbdir', - 'so-dir' => 'sodir', - 'data-dir' => 'datadir', - 'ruby-path' => 'rubypath', - 'ruby-prog' => 'rubyprog', - 'ruby' => 'rubyprog', - 'make-prog' => 'makeprog', - 'make' => 'makeprog' - } - - def fixup - ALIASES.each do |ali, name| - @table[ali] = @table[name] - end - @items.freeze - @table.freeze - @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ - end - - def parse_opt(opt) - m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" - m.to_a[1, 2] - end - - def dllext - @rbconfig['DLEXT'] - end - - def value_config?(name) - lookup(name).value? - end - - class Item - def initialize(name, template, default, desc) - @name = name.freeze - @template = template - @value = default - @default = default - @description = desc - end - - attr_reader :name, :description, :value - - attr_accessor :default - alias help_default default - - def help_opt - "--#{@name}=#{@template}" - end - - def value? - true - end - - def resolve(table) - @value.gsub(%r{\$([^/]+)}) { table[Regexp.last_match(1)] } - end - - def set(val) - @value = check(val) - end - - private - - def check(val) - setup_rb_error "config: --#{name} requires argument" unless val - val - end - end - - class BoolItem < Item - def config_type - 'bool' - end - - def help_opt - "--#{@name}" - end - - private - - def check(val) - return 'yes' unless val - - case val - when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' - when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' - else - setup_rb_error "config: --#{@name} accepts only yes/no for argument" - end - end - end - - class PathItem < Item - def config_type - 'path' - end - - private - - def check(path) - setup_rb_error "config: --#{@name} requires argument" unless path - path[0, 1] == '$' ? path : File.expand_path(path) - end - end - - class ProgramItem < Item - def config_type - 'program' - end - end - - class SelectItem < Item - def initialize(name, selection, default, desc) - super - @ok = selection.split('/') - end - - def config_type - 'select' - end - - private - - def check(val) - setup_rb_error "config: use --#{@name}=#{@template} (#{val})" unless @ok.include?(val.strip) - val.strip - end - end - - class ExecItem < Item - def initialize(name, selection, desc, &block) - super name, selection, nil, desc - @ok = selection.split('/') - @action = block - end - - def config_type - 'exec' - end - - def value? - false - end - - def resolve(_table) - setup_rb_error "$#{name} wrongly used as option value" - end - - undef set - - def evaluate(val, table) - v = val.strip.downcase - setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" unless @ok.include?(v) - @action.call v, table - end - end - - class PackageSelectionItem < Item - def initialize(name, template, default, help_default, desc) - super name, template, default, desc - @help_default = help_default - end - - attr_reader :help_default - - def config_type - 'package' - end - - private - - def check(val) - setup_rb_error "config: no such package: #{val}" unless File.dir?("packages/#{val}") - val - end - end - - class MetaConfigEnvironment - def initialize(config, installer) - @config = config - @installer = installer - end - - def config_names - @config.names - end - - def config?(name) - @config.key?(name) - end - - def bool_config?(name) - @config.lookup(name).config_type == 'bool' - end - - def path_config?(name) - @config.lookup(name).config_type == 'path' - end - - def value_config?(name) - @config.lookup(name).config_type != 'exec' - end - - def add_config(item) - @config.add item - end - - def add_bool_config(name, default, desc) - @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) - end - - def add_path_config(name, default, desc) - @config.add PathItem.new(name, 'path', default, desc) - end - - def set_config_default(name, default) - @config.lookup(name).default = default - end - - def remove_config(name) - @config.remove(name) - end - - # For only multipackage - def packages - unless @installer - raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' - end - - @installer.packages - end - - # For only multipackage - def declare_packages(list) - unless @installer - raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' - end - - @installer.packages = list - end - end -end # class ConfigTable - -# This module requires: #verbose?, #no_harm? -module FileOperations - def mkdir_p(dirname, prefix = nil) - dirname = prefix + File.expand_path(dirname) if prefix - warn "mkdir -p #{dirname}" if verbose? - return if no_harm? - - # Does not check '/', it's too abnormal. - dirs = File.expand_path(dirname).split(%r{(?=/)}) - if /\A[a-z]:\z/i =~ dirs[0] - disk = dirs.shift - dirs[0] = disk + dirs[0] - end - dirs.each_index do |idx| - path = dirs[0..idx].join('') - Dir.mkdir path unless File.dir?(path) - end - end - - def rm_f(path) - warn "rm -f #{path}" if verbose? - return if no_harm? - - force_remove_file path - end - - def rm_rf(path) - warn "rm -rf #{path}" if verbose? - return if no_harm? - - remove_tree path - end - - def remove_tree(path) - if File.symlink?(path) - remove_file path - elsif File.dir?(path) - remove_tree0 path - else - force_remove_file path - end - end - - def remove_tree0(path) - Dir.foreach(path) do |ent| - next if ent == '.' - next if ent == '..' - - entpath = "#{path}/#{ent}" - if File.symlink?(entpath) - remove_file entpath - elsif File.dir?(entpath) - remove_tree0 entpath - else - force_remove_file entpath - end - end - begin - Dir.rmdir path - rescue Errno::ENOTEMPTY - # directory may not be empty - end - end - - def move_file(src, dest) - force_remove_file dest - begin - File.rename src, dest - rescue StandardError - File.open(dest, 'wb') do |f| - f.write File.binread(src) - end - File.chmod File.stat(src).mode, dest - File.unlink src - end - end - - def force_remove_file(path) - remove_file path - rescue StandardError - end - - def remove_file(path) - File.chmod 0o777, path - File.unlink path - end - - def install(from, dest, mode, prefix = nil) - warn "install #{from} #{dest}" if verbose? - return if no_harm? - - realdest = prefix ? prefix + File.expand_path(dest) : dest - realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) - str = File.binread(from) - if diff?(str, realdest) - verbose_off do - rm_f realdest if File.exist?(realdest) - end - File.open(realdest, 'wb') do |f| - f.write str - end - File.chmod mode, realdest - - File.open("#{objdir_root}/InstalledFiles", 'a') do |f| - if prefix - f.puts realdest.sub(prefix, '') - else - f.puts realdest - end - end - end - end - - def diff?(new_content, path) - return true unless File.exist?(path) - - new_content != File.binread(path) - end - - def command(*args) - warn args.join(' ') if verbose? - system(*args) or raise "system(#{args.map { |a| a.inspect }.join(' ')}) failed" - end - - def ruby(*args) - command config('rubyprog'), *args - end - - def make(task = nil) - command(*[config('makeprog'), task].compact) - end - - def extdir?(dir) - File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") - end - - def files_of(dir) - Dir.open(dir) do |d| - return d.select { |ent| File.file?("#{dir}/#{ent}") } - end - end - - DIR_REJECT = %w[. .. CVS SCCS RCS CVS.adm .svn] - - def directories_of(dir) - Dir.open(dir) do |d| - return d.select { |ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT - end - end -end - -# This module requires: #srcdir_root, #objdir_root, #relpath -module HookScriptAPI - def get_config(key) - @config[key] - end - - alias config get_config - - # obsolete: use metaconfig to change configuration - def set_config(key, val) - @config[key] = val - end - - # - # srcdir/objdir (works only in the package directory) - # - - def curr_srcdir - "#{srcdir_root}/#{relpath}" - end - - def curr_objdir - "#{objdir_root}/#{relpath}" - end - - def srcfile(path) - "#{curr_srcdir}/#{path}" - end - - def srcexist?(path) - File.exist?(srcfile(path)) - end - - def srcdirectory?(path) - File.dir?(srcfile(path)) - end - - def srcfile?(path) - File.file?(srcfile(path)) - end - - def srcentries(path = '.') - Dir.open("#{curr_srcdir}/#{path}") do |d| - return d.to_a - %w[. ..] - end - end - - def srcfiles(path = '.') - srcentries(path).select do |fname| - File.file?(File.join(curr_srcdir, path, fname)) - end - end - - def srcdirectories(path = '.') - srcentries(path).select do |fname| - File.dir?(File.join(curr_srcdir, path, fname)) - end - end -end - -class ToplevelInstaller - Version = '3.4.1' - Copyright = 'Copyright (c) 2000-2005 Minero Aoki' - - TASKS = [ - ['all', 'do config, setup, then install'], - ['config', 'saves your configurations'], - ['show', 'shows current configuration'], - ['setup', 'compiles ruby extentions and others'], - ['install', 'installs files'], - ['test', 'run all tests in test/'], - ['clean', "does `make clean' for each extention"], - ['distclean', "does `make distclean' for each extention"] - ] - - def self.invoke - config = ConfigTable.new(load_rbconfig) - config.load_standard_entries - config.load_multipackage_entries if multipackage? - config.fixup - klass = (multipackage? ? ToplevelInstallerMulti : ToplevelInstaller) - klass.new(File.dirname($0), config).invoke - end - - def self.multipackage? - File.dir?(File.dirname($0) + '/packages') - end - - def self.load_rbconfig - if arg = ARGV.detect { |arg| /\A--rbconfig=/ =~ arg } - ARGV.delete(arg) - load File.expand_path(arg.split(/=/, 2)[1]) - $".push 'rbconfig.rb' - else - require 'rbconfig' - end - ::Config::CONFIG - end - - def initialize(ardir_root, config) - @ardir = File.expand_path(ardir_root) - @config = config - # cache - @valid_task_re = nil - end - - def config(key) - @config[key] - end - - def inspect - "#<#{self.class} #{__id__}>" - end - - def invoke - run_metaconfigs - case task = parsearg_global - when nil, 'all' - parsearg_config - init_installers - exec_config - exec_setup - exec_install - else - case task - when 'config', 'test' - - when 'clean', 'distclean' - @config.load_savefile if File.exist?(@config.savefile) - else - @config.load_savefile - end - __send__ "parsearg_#{task}" - init_installers - __send__ "exec_#{task}" - end - end - - def run_metaconfigs - @config.load_script "#{@ardir}/metaconfig" - end - - def init_installers - @installer = Installer.new(@config, @ardir, File.expand_path('.')) - end - - # - # Hook Script API bases - # - - def srcdir_root - @ardir - end - - def objdir_root - '.' - end - - def relpath - '.' - end - - # - # Option Parsing - # - - def parsearg_global - while arg = ARGV.shift - case arg - when /\A\w+\z/ - setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) - return arg - when '-q', '--quiet' - @config.verbose = false - when '--verbose' - @config.verbose = true - when '--help' - print_usage $stdout - exit 0 - when '--version' - puts "#{File.basename($0)} version #{Version}" - exit 0 - when '--copyright' - puts Copyright - exit 0 - else - setup_rb_error "unknown global option '#{arg}'" - end - end - nil - end - - def valid_task?(t) - valid_task_re =~ t - end - - def valid_task_re - @valid_task_re ||= /\A(?:#{TASKS.map { |task, _desc| task }.join('|')})\z/ - end - - def parsearg_no_options - unless ARGV.empty? - task = caller(0).first.slice(/`parsearg_(\w+)'/, 1) - setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" - end - end - - alias parsearg_show parsearg_no_options - alias parsearg_setup parsearg_no_options - alias parsearg_test parsearg_no_options - alias parsearg_clean parsearg_no_options - alias parsearg_distclean parsearg_no_options - - def parsearg_config - evalopt = [] - set = [] - @config.config_opt = [] - while i = ARGV.shift - if /\A--?\z/ =~ i - @config.config_opt = ARGV.dup - break - end - name, value = *@config.parse_opt(i) - if @config.value_config?(name) - @config[name] = value - else - evalopt.push [name, value] - end - set.push name - end - evalopt.each do |name, value| - @config.lookup(name).evaluate value, @config - end - # Check if configuration is valid - set.each do |n| - @config[n] if @config.value_config?(n) - end - end - - def parsearg_install - @config.no_harm = false - @config.install_prefix = '' - while a = ARGV.shift - case a - when '--no-harm' - @config.no_harm = true - when /\A--prefix=/ - path = a.split(/=/, 2)[1] - path = File.expand_path(path) unless path[0, 1] == '/' - @config.install_prefix = path - else - setup_rb_error "install: unknown option #{a}" - end - end - end - - def print_usage(out) - out.puts 'Typical Installation Procedure:' - out.puts " $ ruby #{File.basename $0} config" - out.puts " $ ruby #{File.basename $0} setup" - out.puts " # ruby #{File.basename $0} install (may require root privilege)" - out.puts - out.puts 'Detailed Usage:' - out.puts " ruby #{File.basename $0} " - out.puts " ruby #{File.basename $0} [] []" - - fmt = " %-24s %s\n" - out.puts - out.puts 'Global options:' - out.printf fmt, '-q,--quiet', 'suppress message outputs' - out.printf fmt, ' --verbose', 'output messages verbosely' - out.printf fmt, ' --help', 'print this message' - out.printf fmt, ' --version', 'print version and quit' - out.printf fmt, ' --copyright', 'print copyright and quit' - out.puts - out.puts 'Tasks:' - TASKS.each do |name, desc| - out.printf fmt, name, desc - end - - fmt = " %-24s %s [%s]\n" - out.puts - out.puts 'Options for CONFIG or ALL:' - @config.each do |item| - out.printf fmt, item.help_opt, item.description, item.help_default - end - out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load', "running ruby's" - out.puts - out.puts 'Options for INSTALL:' - out.printf fmt, '--no-harm', 'only display what to do if given', 'off' - out.printf fmt, '--prefix=path', 'install path prefix', '' - out.puts - end - - # - # Task Handlers - # - - def exec_config - @installer.exec_config - @config.save # must be final - end - - def exec_setup - @installer.exec_setup - end - - def exec_install - @installer.exec_install - end - - def exec_test - @installer.exec_test - end - - def exec_show - @config.each do |i| - printf "%-20s %s\n", i.name, i.value if i.value? - end - end - - def exec_clean - @installer.exec_clean - end - - def exec_distclean - @installer.exec_distclean - end -end # class ToplevelInstaller - -class ToplevelInstallerMulti < ToplevelInstaller - include FileOperations - - def initialize(ardir_root, config) - super - @packages = directories_of("#{@ardir}/packages") - raise 'no package exists' if @packages.empty? - - @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) - end - - def run_metaconfigs - @config.load_script "#{@ardir}/metaconfig", self - @packages.each do |name| - @config.load_script "#{@ardir}/packages/#{name}/metaconfig" - end - end - - attr_reader :packages - - def packages=(list) - raise 'package list is empty' if list.empty? - - list.each do |name| - raise "directory packages/#{name} does not exist"\ - unless File.dir?("#{@ardir}/packages/#{name}") - end - @packages = list - end - - def init_installers - @installers = {} - @packages.each do |pack| - @installers[pack] = Installer.new(@config, - "#{@ardir}/packages/#{pack}", - "packages/#{pack}") - end - with = extract_selection(config('with')) - without = extract_selection(config('without')) - @selected = @installers.keys.select do |name| - (with.empty? or with.include?(name)) \ - and !without.include?(name) - end - end - - def extract_selection(list) - a = list.split(/,/) - a.each do |name| - setup_rb_error "no such package: #{name}" unless @installers.key?(name) - end - a - end - - def print_usage(f) - super - f.puts 'Inluded packages:' - f.puts ' ' + @packages.sort.join(' ') - f.puts - end - - # - # Task Handlers - # - - def exec_config - run_hook 'pre-config' - each_selected_installers { |inst| inst.exec_config } - run_hook 'post-config' - @config.save # must be final - end - - def exec_setup - run_hook 'pre-setup' - each_selected_installers { |inst| inst.exec_setup } - run_hook 'post-setup' - end - - def exec_install - run_hook 'pre-install' - each_selected_installers { |inst| inst.exec_install } - run_hook 'post-install' - end - - def exec_test - run_hook 'pre-test' - each_selected_installers { |inst| inst.exec_test } - run_hook 'post-test' - end - - def exec_clean - rm_f @config.savefile - run_hook 'pre-clean' - each_selected_installers { |inst| inst.exec_clean } - run_hook 'post-clean' - end - - def exec_distclean - rm_f @config.savefile - run_hook 'pre-distclean' - each_selected_installers { |inst| inst.exec_distclean } - run_hook 'post-distclean' - end - - # - # lib - # - - def each_selected_installers - Dir.mkdir 'packages' unless File.dir?('packages') - @selected.each do |pack| - warn "Processing the package `#{pack}' ..." if verbose? - Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") - Dir.chdir "packages/#{pack}" - yield @installers[pack] - Dir.chdir '../..' - end - end - - def run_hook(id) - @root_installer.run_hook id - end - - # module FileOperations requires this - def verbose? - @config.verbose? - end - - # module FileOperations requires this - def no_harm? - @config.no_harm? - end -end # class ToplevelInstallerMulti - -class Installer - FILETYPES = %w[bin lib ext data conf man] - - include FileOperations - include HookScriptAPI - - def initialize(config, srcroot, objroot) - @config = config - @srcdir = File.expand_path(srcroot) - @objdir = File.expand_path(objroot) - @currdir = '.' - end - - def inspect - "#<#{self.class} #{File.basename(@srcdir)}>" - end - - def noop(rel); end - - # - # Hook Script API base methods - # - - def srcdir_root - @srcdir - end - - def objdir_root - @objdir - end - - def relpath - @currdir - end - - # - # Config Access - # - - # module FileOperations requires this - def verbose? - @config.verbose? - end - - # module FileOperations requires this - def no_harm? - @config.no_harm? - end - - def verbose_off - save = @config.verbose? - @config.verbose = false - yield - ensure - @config.verbose = save - end - - # - # TASK config - # - - def exec_config - exec_task_traverse 'config' - end - - alias config_dir_bin noop - alias config_dir_lib noop - - def config_dir_ext(_rel) - extconf if extdir?(curr_srcdir) - end - - alias config_dir_data noop - alias config_dir_conf noop - alias config_dir_man noop - - def extconf - ruby "#{curr_srcdir}/extconf.rb", *@config.config_opt - end - - # - # TASK setup - # - - def exec_setup - exec_task_traverse 'setup' - end - - def setup_dir_bin(_rel) - files_of(curr_srcdir).each do |fname| - update_shebang_line "#{curr_srcdir}/#{fname}" - end - end - - alias setup_dir_lib noop - - def setup_dir_ext(_rel) - make if extdir?(curr_srcdir) - end - - alias setup_dir_data noop - alias setup_dir_conf noop - alias setup_dir_man noop - - def update_shebang_line(path) - return if no_harm? - return if config('shebang') == 'never' - - old = Shebang.load(path) - if old - if old.args.size > 1 - warn "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." - end - new = new_shebang(old) - return if new.to_s == old.to_s - else - return unless config('shebang') == 'all' - - new = Shebang.new(config('rubypath')) - end - warn "updating shebang: #{File.basename(path)}" if verbose? - open_atomic_writer(path) do |output| - File.open(path, 'rb') do |f| - f.gets if old # discard - output.puts new.to_s - output.print f.read - end - end - end - - def new_shebang(old) - if /\Aruby/ =~ File.basename(old.cmd) - Shebang.new(config('rubypath'), old.args) - elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' - Shebang.new(config('rubypath'), old.args[1..-1]) - else - return old unless config('shebang') == 'all' - - Shebang.new(config('rubypath')) - end - end - - def open_atomic_writer(path, &block) - tmpfile = File.basename(path) + '.tmp' - begin - File.open(tmpfile, 'wb', &block) - File.rename tmpfile, File.basename(path) - ensure - File.unlink tmpfile if File.exist?(tmpfile) - end - end - - class Shebang - def self.load(path) - line = nil - File.open(path) do |f| - line = f.gets - end - return nil unless /\A#!/ =~ line - - parse(line) - end - - def self.parse(line) - cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') - new(cmd, args) - end - - def initialize(cmd, args = []) - @cmd = cmd - @args = args - end - - attr_reader :cmd, :args - - def to_s - "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") - end - end - - # - # TASK install - # - - def exec_install - rm_f 'InstalledFiles' - exec_task_traverse 'install' - end - - def install_dir_bin(rel) - install_files targetfiles, "#{config('bindir')}/#{rel}", 0o755 - end - - def install_dir_lib(rel) - install_files libfiles, "#{config('rbdir')}/#{rel}", 0o644 - end - - def install_dir_ext(rel) - return unless extdir?(curr_srcdir) - - install_files rubyextentions('.'), - "#{config('sodir')}/#{File.dirname(rel)}", - 0o555 - end - - def install_dir_data(rel) - install_files targetfiles, "#{config('datadir')}/#{rel}", 0o644 - end - - def install_dir_conf(rel) - # FIXME: should not remove current config files - # (rename previous file to .old/.org) - install_files targetfiles, "#{config('sysconfdir')}/#{rel}", 0o644 - end - - def install_dir_man(rel) - install_files targetfiles, "#{config('mandir')}/#{rel}", 0o644 - end - - def install_files(list, dest, mode) - mkdir_p dest, @config.install_prefix - list.each do |fname| - install fname, dest, mode, @config.install_prefix - end - end - - def libfiles - glob_reject(%w[*.y *.output], targetfiles) - end - - def rubyextentions(_dir) - ents = glob_select("*.#{@config.dllext}", targetfiles) - setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" if ents.empty? - ents - end - - def targetfiles - mapdir(existfiles - hookfiles) - end - - def mapdir(ents) - ents.map do |ent| - if File.exist?(ent) - then ent # objdir - else - "#{curr_srcdir}/#{ent}" # srcdir - end - end - end - - # picked up many entries from cvs-1.11.1/src/ignore.c - JUNK_FILES = %w[ - core RCSLOG tags TAGS .make.state - .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb - *~ *.old *.bak *.BAK *.orig *.rej _$* *$ - - *.org *.in .* - ] - - def existfiles - glob_reject(JUNK_FILES, (files_of(curr_srcdir) | files_of('.'))) - end - - def hookfiles - %w[pre-%s post-%s pre-%s.rb post-%s.rb].map do |fmt| - %w[config setup install clean].map { |t| format(fmt, t) } - end.flatten - end - - def glob_select(pat, ents) - re = globs2re([pat]) - ents.select { |ent| re =~ ent } - end - - def glob_reject(pats, ents) - re = globs2re(pats) - ents.reject { |ent| re =~ ent } - end - - GLOB2REGEX = { - '.' => '\.', - '$' => '\$', - '#' => '\#', - '*' => '.*' - } - - def globs2re(pats) - /\A(?:#{ - pats.map { |pat| pat.gsub(/[.$\#*]/) { |ch| GLOB2REGEX[ch] } }.join('|') - })\z/ - end - - # - # TASK test - # - - TESTDIR = 'test' - - def exec_test - unless File.directory?('test') - warn 'no test in this package' if verbose? - return - end - warn 'Running tests...' if verbose? - begin - require 'test/unit' - rescue LoadError - setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' - end - runner = Test::Unit::AutoRunner.new(true) - runner.to_run << TESTDIR - runner.run - end - - # - # TASK clean - # - - def exec_clean - exec_task_traverse 'clean' - rm_f @config.savefile - rm_f 'InstalledFiles' - end - - alias clean_dir_bin noop - alias clean_dir_lib noop - alias clean_dir_data noop - alias clean_dir_conf noop - alias clean_dir_man noop - - def clean_dir_ext(_rel) - return unless extdir?(curr_srcdir) - - make 'clean' if File.file?('Makefile') - end - - # - # TASK distclean - # - - def exec_distclean - exec_task_traverse 'distclean' - rm_f @config.savefile - rm_f 'InstalledFiles' - end - - alias distclean_dir_bin noop - alias distclean_dir_lib noop - - def distclean_dir_ext(_rel) - return unless extdir?(curr_srcdir) - - make 'distclean' if File.file?('Makefile') - end - - alias distclean_dir_data noop - alias distclean_dir_conf noop - alias distclean_dir_man noop - - # - # Traversing - # - - def exec_task_traverse(task) - run_hook "pre-#{task}" - FILETYPES.each do |type| - if type == 'ext' and config('without-ext') == 'yes' - warn 'skipping ext/* by user option' if verbose? - next - end - traverse task, type, "#{task}_dir_#{type}" - end - run_hook "post-#{task}" - end - - def traverse(task, rel, mid) - dive_into(rel) do - run_hook "pre-#{task}" - __send__ mid, rel.sub(%r{\A.*?(?:/|\z)}, '') - directories_of(curr_srcdir).each do |d| - traverse task, "#{rel}/#{d}", mid - end - run_hook "post-#{task}" - end - end - - def dive_into(rel) - return unless File.dir?("#{@srcdir}/#{rel}") - - dir = File.basename(rel) - Dir.mkdir dir unless File.dir?(dir) - prevdir = Dir.pwd - Dir.chdir dir - warn '---> ' + rel if verbose? - @currdir = rel - yield - Dir.chdir prevdir - warn '<--- ' + rel if verbose? - @currdir = File.dirname(rel) - end - - def run_hook(id) - path = ["#{curr_srcdir}/#{id}", - "#{curr_srcdir}/#{id}.rb"].detect { |cand| File.file?(cand) } - return unless path - - begin - instance_eval File.read(path), path, 1 - rescue StandardError - raise if $DEBUG - - setup_rb_error "hook #{path} failed:\n" + $!.message - end - end -end # class Installer - -class SetupError < StandardError; end - -def setup_rb_error(msg) - raise SetupError, msg -end - -if $0 == __FILE__ - begin - ToplevelInstaller.invoke - rescue SetupError - raise if $DEBUG - - warn $!.message - warn "Try 'ruby #{$0} --help' for detailed usage." - exit 1 - end -end diff --git a/test/test_binarytree.rb b/test/test_binarytree.rb index c494606..64d3bb7 100755 --- a/test/test_binarytree.rb +++ b/test/test_binarytree.rb @@ -3,7 +3,7 @@ # test_binarytree.rb - This file is part of the RubyTree package. # # -# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2012, 2013, 2015, 2017 Anupam Sengupta +# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2012, 2013, 2015, 2017, 2022 Anupam Sengupta # # All rights reserved. # @@ -297,25 +297,5 @@ def test_swap_children assert_equal(@right_child1, @root[0], 'right_child1 should now be the first child') assert_equal(@left_child1, @root[1], 'left_child1 should now be the last child') end - - # Test the old CamelCase method names - def test_old_camel_case_names - @left_child2 = Tree::BinaryTreeNode.new('A Child at Left', 'Child Node @ left') - @right_child2 = Tree::BinaryTreeNode.new('B Child at Right', 'Child Node @ right') - - require 'structured_warnings' - - meth_names_for_test = %w[leftChild isLeftChild? rightChild isRightChild?] - - meth_names_for_test.each do |meth_name| - assert_warn(StructuredWarnings::DeprecatedMethodWarning) { @root.send(meth_name) } - end - - # noinspection RubyResolve - assert_warn(StructuredWarnings::DeprecatedMethodWarning) { @root.leftChild = @left_child2 } - # noinspection RubyResolve - assert_warn(StructuredWarnings::DeprecatedMethodWarning) { @root.rightChild = @right_child2 } - assert_raise(NoMethodError) { @root.DummyMethodDoesNotExist } # Make sure the right method is visible - end end end diff --git a/test/test_subclassed_node.rb b/test/test_subclassed_node.rb index b17ef8a..2b8ec61 100755 --- a/test/test_subclassed_node.rb +++ b/test/test_subclassed_node.rb @@ -2,7 +2,7 @@ # test_subclassed_node.rb - This file is part of the RubyTree package. # -# Copyright (c) 2012, 2017 Anupam Sengupta +# Copyright (c) 2012, 2017, 2022 Anupam Sengupta # # All rights reserved. # @@ -41,25 +41,6 @@ module TestTree class TestSubclassedTreeNode < Test::Unit::TestCase # A subclassed node to test various inheritance related features. class MyNode < Tree::TreeNode - # A dummy method to test the camelCasedMethod resolution - def my_dummy_method - 'Hello' - end - end - - def test_camelcase_methods - root = MyNode.new('Root') - - assert_equal('Hello', root.my_dummy_method) - - # We should get a warning as we are invoking the camelCase version of the dummy method. - assert_warn(StructuredWarnings::DeprecatedMethodWarning) { root.send('MyDummyMethod') } - - # Test if the structured_warnings can be disabled to call the CamelCase methods. - StructuredWarnings::DeprecatedMethodWarning.disable do - # noinspection RubyResolve - assert_equal('Hello', root.myDummyMethod) - end end def test_detached_copy_same_clz diff --git a/test/test_tree.rb b/test/test_tree.rb index d7ab5b5..bb2ea63 100755 --- a/test/test_tree.rb +++ b/test/test_tree.rb @@ -2,7 +2,7 @@ # test_tree.rb - This file is part of the RubyTree package. # -# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017, 2020, 2020 Anupam Sengupta +# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2017, 2020, 2020, 2022 Anupam Sengupta # # All rights reserved. # @@ -33,7 +33,6 @@ # require 'test/unit' -require 'structured_warnings' require 'json' require_relative '../lib/tree/tree_deps' @@ -110,7 +109,7 @@ def test_root_setup def test_root setup_test_tree - # TODO: Should probably change this logic. Root's root should + # @todo: Should probably change this logic. Root's root should # return nil so that the possibility of a recursive error does not exist # at all. assert_same(@root, @root.root, "Root's root is self") @@ -298,17 +297,8 @@ def test_has_content_eh assert(a_node.has_content?, 'The node should now have content') end - # Test the equivalence of size and length methods. - def test_length_is_size - setup_test_tree - assert_equal(@root.size, @root.length, 'Length and size methods should return the same result') - end - # Test the <=> operator. def test_spaceship - require 'structured_warnings' - StructuredWarnings::StandardWarning.disable # Disable the warnings for using integers as node names - first_node = Tree::TreeNode.new(1) second_node = Tree::TreeNode.new(2) @@ -326,8 +316,6 @@ def test_spaceship second_node = Tree::TreeNode.new('ABC') assert_equal(0, first_node <=> second_node) - - StructuredWarnings::StandardWarning.enable end # Test the inclusion of Comparable @@ -382,7 +370,7 @@ def test_to_s def test_first_sibling setup_test_tree - # TODO: Need to fix the first_sibling method to return nil for nodes with no siblings. + # @todo: Need to fix the first_sibling method to return nil for nodes with no siblings. assert_same(@root, @root.first_sibling, "Root's first sibling is itself") assert_same(@child1, @child1.first_sibling, "Child1's first sibling is itself") assert_same(@child1, @child2.first_sibling, "Child2's first sibling should be child1") @@ -948,34 +936,6 @@ def test_content assert_same(person, @root.content, 'Content should be the same') end - # Test the depth computation algorithm. Note that this is an incorrect computation and actually returns height+1 - # instead of depth. This method has been deprecated in this release and may be removed in the future. - def test_depth - require 'structured_warnings' - assert_warn(StructuredWarnings::DeprecatedMethodWarning) { do_deprecated_depth } - rescue LoadError - # Since the structured_warnings package is not present, we revert to good old Kernel#warn behavior. - do_deprecated_depth - end - - # Run the assertions for the deprecated depth method. - def do_deprecated_depth - assert_equal(1, @root.depth, "A single node's depth is 1") - - @root << @child1 - assert_equal(2, @root.depth, 'This should be of depth 2') - - @root << @child2 - assert_equal(2, @root.depth, 'This should be of depth 2') - - @child2 << @child3 - assert_equal(3, @root.depth, 'This should be of depth 3') - assert_equal(2, @child2.depth, 'This should be of depth 2') - - @child3 << @child4 - assert_equal(4, @root.depth, 'This should be of depth 4') - end - # Test the height computation algorithm def test_node_height assert_equal(0, @root.node_height, "A single node's height is 0") @@ -1000,8 +960,7 @@ def test_node_height assert_equal(0, @child4.node_height, 'This should be of height 0') end - # Test the depth computation algorithm. Note that this is the correct depth computation. The original - # Tree::TreeNode#depth was incorrectly computing the height of the node - instead of its depth. + # Test the depth computation algorithm. def test_node_depth assert_equal(0, @root.node_depth, "A root node's depth is 0") @@ -1407,46 +1366,13 @@ def test_json_round_trip assert_equal(k[1].name, root_node[1].name, 'Child 2 should be returned') end - # Test the old CamelCase method names - def test_old_camel_case_names - setup_test_tree - - meth_names_to_test = %w[isRoot? isLeaf? hasContent? - hasChildren? firstChild lastChild - firstSibling isFirstSibling? lastSibling isLastSibling? - isOnlyChild? nextSibling previousSibling nodeHeight nodeDepth - removeFromParent! removeAll! freezeTree! ] - - require 'structured_warnings' - - StructuredWarnings::DeprecatedMethodWarning.disable do - # noinspection RubyResolve - assert(@root.isRoot?) # Test if the original method is really called - end - - meth_names_to_test.each do |meth_name| - assert_warn(StructuredWarnings::DeprecatedMethodWarning) { @root.send(meth_name) } - end - - # Special Case for printTree to avoid putting stuff on the STDOUT during the unit test. - begin - require 'stringio' - $stdout = StringIO.new - assert_warn(StructuredWarnings::DeprecatedMethodWarning) { @root.send('printTree') } - ensure - $stdout = STDOUT - end - end - # Test usage of integers as node names def test_integer_node_names - require 'structured_warnings' - assert_warn(StructuredWarnings::StandardWarning) do - @n_root = Tree::TreeNode.new(0, 'Root Node') - @n_child1 = Tree::TreeNode.new(1, 'Child Node 1') - @n_child2 = Tree::TreeNode.new(2, 'Child Node 2') - @n_child3 = Tree::TreeNode.new('three', 'Child Node 3') - end + + @n_root = Tree::TreeNode.new(0, 'Root Node') + @n_child1 = Tree::TreeNode.new(1, 'Child Node 1') + @n_child2 = Tree::TreeNode.new(2, 'Child Node 2') + @n_child3 = Tree::TreeNode.new('three', 'Child Node 3') @n_root << @n_child1 @n_root << @n_child2 @@ -1454,18 +1380,11 @@ def test_integer_node_names # Node[n] is really accessing the nth child with a zero-base assert_not_equal(@n_root[1].name, 1) # This is really the second child - assert_equal(@n_root[0].name, 1) # This will work, as it is the first child - assert_equal(@n_root[1, true].name, 1) # This will work, as the flag is now enabled + assert_equal(@n_root[0].name, "1") # This will work, as it is the first child + assert_equal(@n_root[1].name, "2") # This will work, as the flag is now enabled # Sanity check for the "normal" string name cases. Both cases should work. - assert_equal(@n_root['three', false].name, 'three') - - StructuredWarnings::StandardWarning.disable - assert_equal(@n_root['three', true].name, 'three') - - # Also ensure that the warning is actually being thrown - StructuredWarnings::StandardWarning.enable - assert_warn(StructuredWarnings::StandardWarning) { assert_equal(@n_root['three', true].name, 'three') } + assert_equal(@n_root['three'].name, 'three') end # Test the addition of a node to itself as a child