range_list 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60084bab9a2a689bd360d45fbd94f6915159f20779edfa4137758f5c29bb6e89
4
- data.tar.gz: 897265da656540c840314e498cc4bb792f0a384c54cc3f27f62a42506a8d5b1b
3
+ metadata.gz: f27b8cd8551942e4ff09f2cc32c525e7fd5724cdbea8e322203cd01df681fb46
4
+ data.tar.gz: c24ffbe52e439561c2010fccdf67f68d9700703b23c4ed45d34c143ba5e6de46
5
5
  SHA512:
6
- metadata.gz: db4e3df7dc8e9be8da2c490050d3fd8b9f4b0b58f88581a32ca788d54b53fdef9f2d4a1d1d4bacacc22f7bdcdf095e4749240afe8b6b25e69b5963f45cc76d2e
7
- data.tar.gz: b8d0050152b5ac4221b41fc9223a845be3c8636d70a85a204c9e7bad455f155f3aa119ea0e635eb71982015918449de1da062d89ad8c8f30acf7e845769a3502
6
+ metadata.gz: 62a1a66f4607c3e17424d8bd76cd8371626e8ff0d64961f189f09534fb33cc6e60537e821b3bb743389057db0c76a4e5e83cd7cbe8d3a6872c6c808891237f16
7
+ data.tar.gz: 9fb515423d8048f124e15a88cb3c5b718e7d273694bb8e9fe128ce2e37ebda636ba1da330af406abfc57d8566686fa71eff91d88c7af1eee55cd9b5b4ad75ad1
data/Gemfile CHANGED
@@ -8,3 +8,11 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
+
12
+ gem "standard", "~> 1.7"
13
+
14
+ gem "yard", "~> 0.9.27"
15
+
16
+ gem "simplecov", "~> 0.21.2"
17
+
18
+ gem "simplecov-cobertura", "~> 2.1"
data/Gemfile.lock ADDED
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ range_list (1.0.0)
5
+ treemap (~> 1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ docile (1.4.0)
12
+ minitest (5.15.0)
13
+ parallel (1.21.0)
14
+ parser (3.1.1.0)
15
+ ast (~> 2.4.1)
16
+ rainbow (3.1.1)
17
+ rake (13.0.6)
18
+ regexp_parser (2.2.1)
19
+ rexml (3.2.5)
20
+ rubocop (1.25.1)
21
+ parallel (~> 1.10)
22
+ parser (>= 3.1.0.0)
23
+ rainbow (>= 2.2.2, < 4.0)
24
+ regexp_parser (>= 1.8, < 3.0)
25
+ rexml
26
+ rubocop-ast (>= 1.15.1, < 2.0)
27
+ ruby-progressbar (~> 1.7)
28
+ unicode-display_width (>= 1.4.0, < 3.0)
29
+ rubocop-ast (1.16.0)
30
+ parser (>= 3.1.1.0)
31
+ rubocop-performance (1.13.2)
32
+ rubocop (>= 1.7.0, < 2.0)
33
+ rubocop-ast (>= 0.4.0)
34
+ ruby-progressbar (1.11.0)
35
+ simplecov (0.21.2)
36
+ docile (~> 1.1)
37
+ simplecov-html (~> 0.11)
38
+ simplecov_json_formatter (~> 0.1)
39
+ simplecov-cobertura (2.1.0)
40
+ rexml
41
+ simplecov (~> 0.19)
42
+ simplecov-html (0.12.3)
43
+ simplecov_json_formatter (0.1.4)
44
+ standard (1.7.2)
45
+ rubocop (= 1.25.1)
46
+ rubocop-performance (= 1.13.2)
47
+ treemap (1.0.3)
48
+ unicode-display_width (2.1.0)
49
+ webrick (1.7.0)
50
+ yard (0.9.27)
51
+ webrick (~> 1.7.0)
52
+
53
+ PLATFORMS
54
+ ruby
55
+ x86_64-darwin-19
56
+
57
+ DEPENDENCIES
58
+ minitest (~> 5.0)
59
+ rake (~> 13.0)
60
+ range_list!
61
+ simplecov (~> 0.21.2)
62
+ simplecov-cobertura (~> 2.1)
63
+ standard (~> 1.7)
64
+ yard (~> 0.9.27)
65
+
66
+ BUNDLED WITH
67
+ 2.3.8
data/README.md CHANGED
@@ -1,28 +1,57 @@
1
1
  # RangeList
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/range_list`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ A pair of integers define a range, for example: [1, 5), this range includes integers: 1, 2, 3, and 4.
4
+ A range list is an aggregate of these ranges: [1, 5), [10, 11), [100, 201).
4
5
 
5
- TODO: Delete this and the text above, and describe your gem
6
+ RangeList offers `add`, `remove`, `print`, `containsAll?`, `containsAny?` methods, and offers the `Enumerable` ability,
7
+ you can handle ranges more easily.
8
+
9
+ [![Gem Version](https://badge.fury.io/rb/range_list.svg)](https://rubygems.org/gems/range_list)
10
+ [![Documentation](https://img.shields.io/badge/docs-YARD-blue.svg)](https://rubydoc.info/gems/range_list)
11
+ [![pipeline status](https://gitlab.com/songhuangcn/range_list/badges/main/pipeline.svg)](https://gitlab.com/songhuangcn/range_list/-/commits/main)
12
+ [![coverage report](https://gitlab.com/songhuangcn/range_list/badges/main/coverage.svg)](https://gitlab.com/songhuangcn/range_list/-/commits/main)
6
13
 
7
14
  ## Installation
8
15
 
9
- Add this line to your application's Gemfile:
16
+ Add gem to your application's Gemfile:
10
17
 
11
- ```ruby
12
- gem 'range_list'
18
+ ```shell
19
+ bundle add range_list
13
20
  ```
14
21
 
15
- And then execute:
16
-
17
- $ bundle install
18
-
19
22
  Or install it yourself as:
20
23
 
21
- $ gem install range_list
24
+ ```shell
25
+ gem install range_list
26
+ ```
22
27
 
23
28
  ## Usage
24
29
 
25
- TODO: Write usage instructions here
30
+ ```shell
31
+ range_list = RangeList.new
32
+ range_list.add([1, 5]).add([10, 20])
33
+ range_list.print # [1, 5) [10, 20)
34
+
35
+ range_list.add([20, 20])
36
+ range_list.print # [1, 5) [10, 20)
37
+
38
+ range_list.add([15, 21])
39
+ range_list.print # [1, 5) [10, 21)
40
+
41
+ range_list.remove([15, 21])
42
+ range_list.print # [1, 5) [10, 15)
43
+
44
+ range_list.contains_any?([8, 10]) # false
45
+ range_list.contains_any?([8, 11]) # true
46
+ range_list.contains_all?([8, 11]) # false
47
+ range_list.contains_all?([10, 11]) # true
48
+
49
+ range_list.each { |range_start, range_end| puts "#{range_start} <= x < #{range_end}" } # print all range in order
50
+
51
+ range_list.remove([0, 100])
52
+ range_list.print #
53
+ range_list.to_a # []
54
+ ```
26
55
 
27
56
  ## Development
28
57
 
@@ -32,7 +61,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
61
 
33
62
  ## Contributing
34
63
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/range_list.
64
+ Bug reports and Merge requests are welcome on GitLab at https://gitlab.com/songhuangcn/range_list.
36
65
 
37
66
  ## License
38
67
 
@@ -0,0 +1,7 @@
1
+ class RangeList
2
+ # RangeList base error.
3
+ class Error < StandardError; end
4
+
5
+ # When the error raised, you should see the doc and check your argument.
6
+ class ArgumentError < Error; end
7
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module RangeList
4
- VERSION = "0.1.0"
3
+ class RangeList
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/range_list.rb CHANGED
@@ -1,8 +1,142 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "treemap"
3
4
  require_relative "range_list/version"
5
+ require_relative "range_list/errors"
4
6
 
5
- module RangeList
6
- class Error < StandardError; end
7
- # Your code goes here...
7
+ class RangeList
8
+ include Enumerable
9
+
10
+ def initialize
11
+ @tree = TreeMap.new
12
+ end
13
+
14
+ # Add range into current range list.
15
+ # @param range [Array<Integer>] the range, first element is range start, second is range end.
16
+ # Range end need be greater or equal than range start.
17
+ # @return [RangeList]
18
+ def add(range)
19
+ validate_range!(range)
20
+
21
+ # Return when range is empty.
22
+ return self if empty_range?(range)
23
+
24
+ # Get real range start.
25
+ start_floor_entry = tree.floor_entry(range[0])
26
+ range_start = if !start_floor_entry.nil? && start_floor_entry.value >= range[0]
27
+ start_floor_entry.key
28
+ else
29
+ range[0]
30
+ end
31
+
32
+ # Get real range end.
33
+ end_floor_entry = tree.floor_entry(range[1])
34
+ range_end = if !end_floor_entry.nil? && end_floor_entry.value >= range[1]
35
+ end_floor_entry.value
36
+ else
37
+ range[1]
38
+ end
39
+
40
+ # Insert or replace new range.
41
+ tree.put(range_start, range_end)
42
+
43
+ # Remove keys between range, exclude start, include end.
44
+ between_maps = tree.sub_map(range[0], false, range[1], true)
45
+ between_maps.keys.each { |key| tree.remove(key) }
46
+
47
+ self
48
+ end
49
+
50
+ # Remove range from current range list.
51
+ # @param (see #add)
52
+ # @return [RangeList]
53
+ def remove(range)
54
+ validate_range!(range)
55
+
56
+ # Return when range is empty.
57
+ return self if empty_range?(range)
58
+
59
+ # Insert end lower entry
60
+ end_lower_entry = tree.lower_entry(range[1])
61
+ if !end_lower_entry.nil? && end_lower_entry.value > range[1]
62
+ tree.put(range[1], end_lower_entry.value)
63
+ end
64
+
65
+ # Relace start lower entry
66
+ start_lower_entry = tree.lower_entry(range[0])
67
+ if !start_lower_entry.nil? && start_lower_entry.value > range[0]
68
+ tree.put(start_lower_entry.key, range[0])
69
+ end
70
+
71
+ # Remove keys between range, include start, exclude end
72
+ between_maps = tree.sub_map(range[0], true, range[1], false)
73
+ between_maps.keys.each { |key| tree.remove(key) }
74
+
75
+ self
76
+ end
77
+
78
+ # Print current range list.
79
+ # @return [void]
80
+ def print
81
+ puts to_a.map { |k, v| "[#{k}, #{v})" }.join(" ")
82
+ end
83
+
84
+ # Returns true if this set contains all elements of the range.
85
+ # @param (see #add)
86
+ # @return [Boolean]
87
+ # @note return false if the argument range is empty
88
+ def contains_all?(range)
89
+ return false if empty_range?(range)
90
+
91
+ start_floor_entry = tree.floor_entry(range[0])
92
+ !start_floor_entry.nil? && start_floor_entry.value >= range[1]
93
+ end
94
+
95
+ # Returns true if this set contains any element of the range.
96
+ # @param (see #add)
97
+ # @return [Boolean]
98
+ # @note return false if the argument range is empty
99
+ def contains_any?(range)
100
+ return false if empty_range?(range)
101
+
102
+ lower_floor_entry = tree.lower_entry(range[1])
103
+ !lower_floor_entry.nil? && lower_floor_entry.value > range[0]
104
+ end
105
+
106
+ # Give RangeList iterative ability.
107
+ # @yield [range_start, range_end] give the range element to the block
108
+ def each(&block)
109
+ if block
110
+ # Iterating an empty tree will raise an error,
111
+ # see https://github.com/davidkellis/treemap/issues/1
112
+ tree.empty? ? self : tree.each(&block)
113
+ else
114
+ enum_for(:each)
115
+ end
116
+ end
117
+
118
+ # @!visibility private
119
+ def inspect
120
+ to_a.inspect
121
+ end
122
+
123
+ # Return the current range as an array.
124
+ # @return [Array]
125
+ def to_a
126
+ tree.empty? ? [] : tree.to_a
127
+ end
128
+
129
+ private
130
+
131
+ attr_reader :tree
132
+
133
+ def validate_range!(range)
134
+ raise ArgumentError, "`range` should be `Array` type." unless range.is_a?(Array)
135
+ raise ArgumentError, "`range` size should be equal to 2." unless range.size == 2
136
+ raise ArgumentError, "All elements of `range` should be `Integer`." unless range.all? { |item| item.is_a?(Integer) }
137
+ end
138
+
139
+ def empty_range?(range)
140
+ range[0] >= range[1]
141
+ end
8
142
  end
data/range_list.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.metadata["homepage_uri"] = spec.homepage
20
20
  spec.metadata["source_code_uri"] = "https://gitlab.com/songhuangcn/range_list"
21
+ spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/range_list"
21
22
  # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
22
23
 
23
24
  # Specify which files should be added to the gem when it is released.
@@ -33,6 +34,7 @@ Gem::Specification.new do |spec|
33
34
 
34
35
  # Uncomment to register a new dependency of your gem
35
36
  # spec.add_dependency "example-gem", "~> 1.0"
37
+ spec.add_dependency "treemap", "~> 1.0"
36
38
 
37
39
  # For more information and examples about making a new gem, check out our
38
40
  # guide at: https://bundler.io/guides/creating_gem.html
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: range_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Song Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-25 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: treemap
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
13
27
  description:
14
28
  email:
15
29
  - songhuangcn@gmail.com
@@ -18,19 +32,21 @@ extensions: []
18
32
  extra_rdoc_files: []
19
33
  files:
20
34
  - Gemfile
35
+ - Gemfile.lock
21
36
  - LICENSE.txt
22
37
  - README.md
23
38
  - Rakefile
24
39
  - lib/range_list.rb
40
+ - lib/range_list/errors.rb
25
41
  - lib/range_list/version.rb
26
42
  - range_list.gemspec
27
- - sig/range_list.rbs
28
43
  homepage: https://gitlab.com/songhuangcn/range_list
29
44
  licenses:
30
45
  - MIT
31
46
  metadata:
32
47
  homepage_uri: https://gitlab.com/songhuangcn/range_list
33
48
  source_code_uri: https://gitlab.com/songhuangcn/range_list
49
+ documentation_uri: https://rubydoc.info/gems/range_list
34
50
  post_install_message:
35
51
  rdoc_options: []
36
52
  require_paths:
data/sig/range_list.rbs DELETED
@@ -1,4 +0,0 @@
1
- module RangeList
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end