key_set 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 19b39d7fc11b72e1276d84da44d947775f5e9acf845c4aba7315123ac62c9c6f
4
+ data.tar.gz: b9947bc238a8d186bacb4cbcf1ba1b9884ddc7d43e86d0faee90fbf66308c953
5
+ SHA512:
6
+ metadata.gz: aa0b11f3bb468889a750c344758494a6ac765da00e6861dad29e828300a53d464ee2aea11621319607ec5642d49560e6e1e34759b2ea416dceda25cd95e3d512
7
+ data.tar.gz: b9b2284b2da74bddd52253d76a44a9701ea4c60a22a4b0ffb77b6b3419ae32c8a3747daa12fce6c13b73f4935530c83d266d3760aa60da2194615163ed027f71
data/.gitignore ADDED
@@ -0,0 +1,33 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.idea
9
+ /.bundle
10
+
11
+ # Ignore all logfiles and tempfiles.
12
+ /log/*
13
+ /tmp/*
14
+ !/log/.keep
15
+ !/tmp/.keep
16
+
17
+ # Ignore Byebug command history file.
18
+ .byebug_history
19
+ /coverage
20
+ /manual_sandbox.json
21
+ /brakeman.out.json
22
+ .DS_Store
23
+
24
+ # gem
25
+ /.yardoc
26
+ /_yardoc/
27
+ /coverage/
28
+ /doc/
29
+ /pkg/
30
+ /spec/reports/
31
+
32
+ # rspec failure tracking
33
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,45 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ Exclude:
6
+ - 'bin/**/*'
7
+ - 'vendor/**/*'
8
+ - 'spec/fixtures/**/*'
9
+ - 'tmp/**/*'
10
+ - 'db/schema.rb'
11
+ TargetRubyVersion: 2.5
12
+
13
+ Rails:
14
+ Enabled: true
15
+
16
+ Metrics/LineLength:
17
+ Max: 140
18
+ IgnoredPatterns: ['^[\s]*#']
19
+
20
+ Metrics/MethodLength:
21
+ Max: 15
22
+
23
+ Style/SymbolArray:
24
+ Enabled: false
25
+
26
+ Style/Documentation:
27
+ Enabled: false
28
+
29
+ RSpec/MultipleExpectations:
30
+ Enabled: false
31
+
32
+ RSpec/ExampleLength:
33
+ Enabled: false
34
+
35
+ RSpec/ContextWording:
36
+ Enabled: false
37
+
38
+ RSpec/HookArgument:
39
+ Enabled: false
40
+
41
+ Style/TrailingCommaInArrayLiteral:
42
+ EnforcedStyleForMultiline: comma
43
+
44
+ Style/TrailingCommaInHashLiteral:
45
+ EnforcedStyleForMultiline: comma
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ ---
2
+ env:
3
+ global:
4
+ - CC_TEST_REPORTER_ID=1eec0569f37168d92ce0fbdecced22b50ba2e3425c309ed67b8e8685864acf6c
5
+ language: ruby
6
+ sudo: false
7
+ cache: bundler
8
+ rvm:
9
+ - 2.5.3
10
+ before_install: gem install bundler -v 1.17.1
11
+ before_script:
12
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
13
+ - chmod +x ./cc-test-reporter
14
+ - ./cc-test-reporter before-build
15
+ script:
16
+ - bundle exec rspec
17
+ after_script:
18
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at eturino@eturino.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in key_set.gemspec
8
+ gemspec
9
+
10
+ gem 'simplecov', require: false, group: :test
data/Gemfile.lock ADDED
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ key_set (1.0.0)
5
+ activesupport (>= 4)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (5.2.1)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (>= 0.7, < 2)
13
+ minitest (~> 5.1)
14
+ tzinfo (~> 1.1)
15
+ concurrent-ruby (1.0.5)
16
+ diff-lcs (1.3)
17
+ docile (1.3.1)
18
+ i18n (1.1.1)
19
+ concurrent-ruby (~> 1.0)
20
+ json (2.1.0)
21
+ minitest (5.11.3)
22
+ rake (10.5.0)
23
+ rspec (3.8.0)
24
+ rspec-core (~> 3.8.0)
25
+ rspec-expectations (~> 3.8.0)
26
+ rspec-mocks (~> 3.8.0)
27
+ rspec-core (3.8.0)
28
+ rspec-support (~> 3.8.0)
29
+ rspec-expectations (3.8.2)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.8.0)
32
+ rspec-mocks (3.8.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.8.0)
35
+ rspec-support (3.8.0)
36
+ simplecov (0.16.1)
37
+ docile (~> 1.1)
38
+ json (>= 1.8, < 3)
39
+ simplecov-html (~> 0.10.0)
40
+ simplecov-html (0.10.2)
41
+ thread_safe (0.3.6)
42
+ tzinfo (1.2.5)
43
+ thread_safe (~> 0.1)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ bundler (~> 1.17)
50
+ key_set!
51
+ rake (~> 10.0)
52
+ rspec (~> 3.0)
53
+ simplecov
54
+
55
+ BUNDLED WITH
56
+ 1.17.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Eduardo Turiño
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # KeySet
2
+
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/eea7d889d4f13fbf45c7/maintainability)](https://codeclimate.com/github/eturino/ruby_key_set/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/eea7d889d4f13fbf45c7/test_coverage)](https://codeclimate.com/github/eturino/ruby_key_set/test_coverage)
5
+ [![Build Status](https://travis-ci.org/eturino/ruby_key_set.svg?branch=master)](https://travis-ci.org/eturino/ruby_key_set)
6
+ [![Gem Version](https://badge.fury.io/rb/key_set.svg)](https://badge.fury.io/rb/key_set)
7
+
8
+ KeySet allows you to represent the 4 possible sets of elements:
9
+
10
+ - All elements (`KeySet.all # => KeySet::All`)
11
+ - No elements (`KeySet.non # => KeySet::None`)
12
+ - Some elements (`KeySet.some(['k1', 'k2']) # => KeySet::Some`)
13
+ - All except some elements (`KeySet.all_except_some(['k1', 'k2']) # => KeySet::AllExceptSome`)
14
+
15
+ and do some operations on them, like:
16
+ - calculate inverse KeySet (`key_set.invert`)
17
+ - remove a KeySet from another KeySet (`key_set.remove(other)`)
18
+ - intersect 2 KeySets (`key_set.intersect(other)`)
19
+
20
+ The keys in the `Some` and `AllExceptSome` key sets are stored in a `SortedSet`, so they are sorted and without duplicates.
21
+
22
+ ### Creation
23
+
24
+ ```ruby
25
+ KeySet.all # => new KeySet of KeySet::All
26
+
27
+ KeySet.none # => new KeySet of KeySet::None
28
+
29
+ KeySet.some(['k1', 'k2']) # => new KeySet of KeySet::Some with keys ['k1', 'k2']
30
+ KeySet.some([]) # => same as KeySet.none => returns new KeySet::None
31
+
32
+ KeySet.all_except_some(['k1', 'k2']) # => new KeySet of KeySet::AllExceptSome with keys ['k1', 'k2']
33
+ KeySet.all_except_some([]) # => same as KeySet.all => returns new KeySet::All
34
+ ```
35
+
36
+ ### Checks
37
+
38
+ ```ruby
39
+ key_set.represents_all? # => true if the key set is a KeySet::All
40
+ key_set.represents_none? # => true if the key set is a KeySet::None
41
+ ```
42
+
43
+ ### `.invert`
44
+
45
+ ```ruby
46
+ KeySet.all.invert # => KeySet::None
47
+ KeySet.none.invert # => KeySet::None
48
+ KeySet.some(['k1', 'k2']).invert # => KeySet::AllExceptSome with keys 'k1' and 'k2'
49
+ KeySet.all_except_some(['k1', 'k2']).invert # => KeySet::Some with keys 'k1' and 'k2'
50
+ ```
51
+
52
+ ### `.intersect`
53
+
54
+ ```
55
+ #intersect
56
+ All
57
+ KeySet.all.intersect(KeySet.all)
58
+ we have everything, we intersect everything => we have everything
59
+ KeySet.all.intersect(KeySet.none)
60
+ we have everything, we intersect nothing => we have nothing
61
+ KeySet.all.intersect(KeySet.some [key1, key2])
62
+ we have everything, we intersect some => we have some
63
+ KeySet.all.intersect(KeySet.all_except_some [key1, key2])
64
+ we have everything, we intersect all except some => we have all except some
65
+ None
66
+ KeySet.none.intersect(KeySet.all)
67
+ we have nothing, we intersect everything => we have nothing
68
+ KeySet.none.intersect(KeySet.none)
69
+ we have nothing, we intersect nothing => we have nothing
70
+ KeySet.none.intersect(KeySet.some [key1, key2])
71
+ we have nothing, we intersect some => we have nothing
72
+ KeySet.none.intersect(KeySet.all_except_some [key1, key2])
73
+ we have nothing, we intersect all except some => we have nothing
74
+ Some
75
+ KeySet.some([key1, key3]).intersect(KeySet.all)
76
+ we have some, we intersect everything => we have the same some
77
+ KeySet.some([key1, key3]).intersect(KeySet.none)
78
+ we have some, we intersect nothing => we have nothing
79
+ KeySet.some([key1, key3]).intersect(KeySet.some [key1, key2])
80
+ we have some, we intersect some others (that does not include our entire set) => we have the common keys
81
+ KeySet.some([key1, key3]).intersect(KeySet.some [key1, key2, key3])
82
+ we have some, we intersect some others that includes our entire set => we have the common keys, so our former set
83
+ KeySet.some([key1, key3]).intersect(KeySet.all_except_some [key1, key2])
84
+ we have some, we intersect all except others, which includes some of ours => we have the former keys that are not in the other keys
85
+ KeySet.some([key1, key3]).intersect(KeySet.all_except_some [key1, key2, key3])
86
+ we have some, we intersect all except others, which include all our keys => we have nothing
87
+ KeySet.some([key1, key3]).intersect(KeySet.all_except_some [key2, key4])
88
+ we have some, we intersect all except others, none of them are in our keys => we have the same set
89
+ AllExceptSome
90
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.all)
91
+ we have all except some, we intersect everything => we have the same
92
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.none)
93
+ we have all except some, we intersect nothing => we have none
94
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.some [key1, key2])
95
+ we have all except some, we intersect some others => we have the keys in the second that area not in the keys of the first
96
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.some [key1, key3])
97
+ we have all except some, we intersect some of the same keys => we have nothing
98
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.some [key1, key2, key3])
99
+ we have all except some, we intersect some others that includes our entire set => we have the keys in the second that area not in the keys of the first
100
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.all_except_some [key1, key2])
101
+ we have all except some, we intersect all except others (that includes some of the current set) => we get all except the union of keys in the first and in the second
102
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.all_except_some [key1, key2, key3])
103
+ we have all except some, we intersect all except others (that includes the entire of the current set) => we get all except the union of keys in the first and in the second
104
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.all_except_some [key2, key4])
105
+ we have all except some, we intersect all except others (that includes none of the current set) => we get all except the union of keys in the first and in the second
106
+ KeySet.all_except_some([key1, key3]).intersect(KeySet.all_except_some [key1, key3])
107
+ we have all except some, we intersect all except others (that has the same set) => we get the same
108
+ ```
109
+
110
+ ### `.intersect`
111
+
112
+ ```
113
+ #remove
114
+ All
115
+ KeySet.all.remove(KeySet.all)
116
+ we have everything, we remove everything => we have nothing
117
+ KeySet.all.remove(KeySet.none)
118
+ we have everything, we remove nothing => we have everything
119
+ KeySet.all.remove(KeySet.some [key1, key2])
120
+ we have everything, we remove some => we have all except those
121
+ KeySet.all.remove(KeySet.all_except_some [key1, key2])
122
+ we have everything, we remove all except some => we have only those
123
+ None
124
+ KeySet.none.remove(KeySet.all)
125
+ we have nothing, we remove everything => we have nothing
126
+ KeySet.none.remove(KeySet.none)
127
+ we have nothing, we remove nothing => we have nothing
128
+ KeySet.none.remove(KeySet.some [key1, key2])
129
+ we have nothing, we remove some => we have nothing
130
+ KeySet.none.remove(KeySet.all_except_some [key1, key2])
131
+ we have nothing, we remove all except some => we have nothing
132
+ Some
133
+ KeySet.some([key1, key3]).remove(KeySet.all)
134
+ we have some, we remove everything => we have nothing
135
+ KeySet.some([key1, key3]).remove(KeySet.none)
136
+ we have some, we remove nothing => we have the same set
137
+ KeySet.some([key1, key3]).remove(KeySet.some [key1, key2])
138
+ we have some, we remove some others (that does not include our entire set) => we have the keys that we have not been removed
139
+ KeySet.some([key1, key3]).remove(KeySet.some [key1, key2, key3])
140
+ we have some, we remove some others that includes our entire set => we have nothing
141
+ KeySet.some([key1, key3]).remove(KeySet.all_except_some [key1, key2])
142
+ we have some, we remove all except others => we have only the keys that we had and they were excluded from the removal
143
+ KeySet.some([key1, key3]).remove(KeySet.all_except_some [key1, key2, key3])
144
+ we have some, we remove all except others, which include all our keys => we have the same keys
145
+ KeySet.some([key1, key3]).remove(KeySet.all_except_some [key2, key4])
146
+ we have some, we remove all except others, none of them are in our keys => we have nothing
147
+ AllExceptSome
148
+ KeySet.all_except_some([key1, key3]).remove(KeySet.all)
149
+ we have all except some, we remove everything => we have nothing
150
+ KeySet.all_except_some([key1, key3]).remove(KeySet.none)
151
+ we have all except some, we remove nothing => we have the same (all but these keys)
152
+ KeySet.all_except_some([key1, key3]).remove(KeySet.some [key1, key2])
153
+ we have all except some, we remove some others => we have all except the ones that we didn't have before and the ones that we don't have now
154
+ KeySet.all_except_some([key1, key3]).remove(KeySet.some [key1, key2, key3])
155
+ we have all except some, we remove some others that includes our entire set => we have all except the new set (that includes the old set)
156
+ KeySet.all_except_some([key1, key3]).remove(KeySet.all_except_some [key1, key2])
157
+ we have all except some, we remove all except others (that includes some of the current set) => we have only the ones that OTHER did not remove, except the ones that THIS was excluding
158
+ KeySet.all_except_some([key1, key3]).remove(KeySet.all_except_some [key1, key2, key3])
159
+ we have all except some, we remove all except others (that includes the entire of the current set) => we have only the ones that OTHER did not remove, except the ones that THIS was excluding
160
+ KeySet.all_except_some([key1, key3]).remove(KeySet.all_except_some [key2, key4])
161
+ we have all except some, we remove all except others (that includes none of the current set) => we get only the ones that the other is not excluding
162
+ KeySet.all_except_some([key1, key3]).remove(KeySet.all_except_some [key1, key3])
163
+ we have all except some, we remove all except others (that has the same set) => we get nothing
164
+ ```
165
+
166
+ Note that removing a AllExceptSome logs a warning, since it is probably not what you want to do.
167
+
168
+ ## Installation
169
+
170
+ Add this line to your application's Gemfile:
171
+
172
+ ```ruby
173
+ gem 'key_set'
174
+ ```
175
+
176
+ And then execute:
177
+
178
+ $ bundle
179
+
180
+ Or install it yourself as:
181
+
182
+ $ gem install key_set
183
+
184
+ ## Usage
185
+
186
+ ## Development
187
+
188
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
189
+
190
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
191
+
192
+ ## Contributing
193
+
194
+ Bug reports and pull requests are welcome on GitHub at https://github.com/eturino/ruby_key_set. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
195
+
196
+ ## License
197
+
198
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
199
+
200
+ ## Code of Conduct
201
+
202
+ Everyone interacting in the KeySet project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/eturino/ruby_key_set/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "key_set"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/rake ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rake", "rake")
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/key_set.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'key_set/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'key_set'
9
+ spec.version = KeySet::VERSION
10
+ spec.authors = ['Eduardo Turiño']
11
+ spec.email = ['eturino@eturino.com']
12
+
13
+ spec.summary = <<~TXT
14
+ KeySet with 4 classes to represent concepts of All, None, Some, and AllExceptSome, the last 2 with a sorted uniq list of keys
15
+ TXT
16
+ spec.homepage = 'https://github.com/eturino/ruby_key_set'
17
+ spec.license = 'MIT'
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ end
24
+ spec.bindir = 'exe'
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ['lib']
27
+
28
+ spec.add_dependency 'activesupport', '>= 4'
29
+
30
+ spec.add_development_dependency 'bundler', '~> 1.17'
31
+ spec.add_development_dependency 'rake', '~> 10.0'
32
+ spec.add_development_dependency 'rspec', '~> 3.0'
33
+ end
data/lib/key_set.rb ADDED
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/all'
4
+ class KeySet
5
+ class Error < StandardError
6
+ end
7
+
8
+ def self.logger
9
+ @logger ||= default_logger
10
+ end
11
+
12
+ def self.default_logger
13
+ require 'logger'
14
+ ::Logger.new($stdout)
15
+ end
16
+
17
+ def self.all
18
+ All.new
19
+ end
20
+
21
+ def self.none
22
+ None.new
23
+ end
24
+
25
+ def self.some(keys)
26
+ return none if keys.blank?
27
+
28
+ Some.new keys
29
+ end
30
+
31
+ def self.all_except_some(keys)
32
+ return all if keys.blank?
33
+
34
+ AllExceptSome.new keys
35
+ end
36
+
37
+ # COMMON
38
+
39
+ def represents_all?
40
+ false
41
+ end
42
+
43
+ def represents_none?
44
+ false
45
+ end
46
+
47
+ # :nocov:
48
+ # @param other [KeySet]
49
+ # @return [KeySet]
50
+ def remove(_other)
51
+ raise NotImplementedError
52
+ end
53
+
54
+ # @param other [KeySet]
55
+ # @return [KeySet]
56
+ def intersect(_other)
57
+ raise NotImplementedError
58
+ end
59
+
60
+ # @return [KeySet]
61
+ def invert
62
+ raise NotImplementedError
63
+ end
64
+ # :nocov:
65
+
66
+ # EQUALITY AND COMPARISON
67
+ def hash
68
+ if respond_to? :keys
69
+ [self.class.to_s, keys.map(&:hash)].hash
70
+ else
71
+ self.class.to_s.hash
72
+ end
73
+ end
74
+
75
+ def <=>(other)
76
+ if self.class.class_sort_index == other.class.class_sort_index
77
+ if respond_to? :keys_array
78
+ keys_array <=> other.keys_array
79
+ else
80
+ 0
81
+ end
82
+ else
83
+ self.class.class_sort_index <=> other.class.class_sort_index
84
+ end
85
+ end
86
+
87
+ def ===(other)
88
+ self.class == other.class && try(:keys_array) === other.try(:keys_array) # rubocop:disable Style/CaseEquality
89
+ end
90
+
91
+ def ==(other)
92
+ self.class == other.class && try(:keys_array) == other.try(:keys_array)
93
+ end
94
+
95
+ def eql?(other)
96
+ self.class == other.class && try(:keys_array) == other.try(:keys_array)
97
+ end
98
+ end
99
+
100
+ require 'key_set/based_on_keys'
101
+
102
+ require 'key_set/all'
103
+ require 'key_set/none'
104
+ require 'key_set/some'
105
+ require 'key_set/all_except_some'
106
+
107
+ require 'key_set/version'
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KeySet
4
+ class All < KeySet
5
+ def self.class_sort_index
6
+ 3
7
+ end
8
+
9
+ def represents_all?
10
+ true
11
+ end
12
+
13
+ def invert
14
+ KeySet.none
15
+ end
16
+
17
+ def remove(other)
18
+ case other
19
+ when All
20
+ # we have everything, we remove everything => we have nothing
21
+ KeySet.none
22
+ when None
23
+ # we have everything, we remove nothing => we have everything
24
+ KeySet.all
25
+ when Some
26
+ # we have everything, we remove some => we have all except those
27
+ KeySet.all_except_some other.keys
28
+ when AllExceptSome
29
+ # we have everything, we remove all except some => we have only those
30
+ KeySet.logger.warn "KeySet removing AllButSome, probably a mistake. this: ALL, removing keys: #{other.keys.inspect}"
31
+ KeySet.some other.keys
32
+ else
33
+ raise ArgumentError, 'it needs a valid KeySet'
34
+ end
35
+ end
36
+
37
+ def intersect(other)
38
+ case other
39
+ when All
40
+ KeySet.all
41
+ when None
42
+ KeySet.none
43
+ when Some
44
+ KeySet.some other.keys
45
+ when AllExceptSome
46
+ KeySet.all_except_some other.keys
47
+ else
48
+ raise ArgumentError, 'it needs a valid KeySet'
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KeySet
4
+ class AllExceptSome < KeySet
5
+ include BasedOnKeys
6
+
7
+ def self.class_sort_index
8
+ 2
9
+ end
10
+
11
+ def invert
12
+ KeySet.some(keys_array)
13
+ end
14
+
15
+ def remove(other)
16
+ case other
17
+ when All
18
+ # we have all except some, we remove everything => we have nothing
19
+ KeySet.none
20
+ when None
21
+ # we have all except some, we remove nothing => we have the same (all but these keys)
22
+ KeySet.all_except_some keys.deep_dup
23
+ when Some
24
+ # we have all except some, we remove some others => we have all except the ones that we didn't have before and the ones that we don't have now
25
+ remove_some(other)
26
+ when AllExceptSome
27
+ # we have all except some, we remove all except others => we have only the ones that OTHER did not remove, except the ones that THIS was removing
28
+ KeySet.logger.warn "KeySet removing AllButSome, probably a mistake. this: ALL_BUT_SOME, removing keys: #{other.keys.inspect}"
29
+ remove_all_except_some(other)
30
+ else
31
+ raise ArgumentError, 'it needs a valid KeySet'
32
+ end
33
+ end
34
+
35
+ def intersect(other)
36
+ case other
37
+ when All
38
+ KeySet.all_except_some keys.deep_dup
39
+ when None
40
+ KeySet.none
41
+ when Some
42
+ # we have all except some, we remove some others => we have all except the ones that we didn't have before and the ones that we don't have now
43
+ intersect_some(other)
44
+ when AllExceptSome
45
+ intersect_all_except_some(other)
46
+ else
47
+ raise ArgumentError, 'it needs a valid KeySet'
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def remove_some(other)
54
+ k = keys.deep_dup + other.keys.deep_dup
55
+ KeySet.all_except_some k
56
+ end
57
+
58
+ def remove_all_except_some(other)
59
+ k = other.keys.deep_dup - keys.deep_dup
60
+ KeySet.some k
61
+ end
62
+
63
+ def intersect_some(other)
64
+ k = other.keys.deep_dup - keys.deep_dup
65
+ KeySet.some k
66
+ end
67
+
68
+ def intersect_all_except_some(other)
69
+ k = other.keys.deep_dup + keys.deep_dup
70
+ KeySet.all_except_some k
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KeySet
4
+ module BasedOnKeys
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include Enumerable
9
+
10
+ attr_reader :keys
11
+
12
+ def initialize(keys)
13
+ @keys = SortedSet.new(keys.to_a)
14
+ end
15
+
16
+ delegate :each, to: :keys
17
+ end
18
+
19
+ def keys_array
20
+ keys.to_a
21
+ end
22
+
23
+ def represents_all?
24
+ false
25
+ end
26
+
27
+ def represents_none?
28
+ false
29
+ end
30
+
31
+ def clone
32
+ self.class.new keys.deep_dup
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KeySet
4
+ class None < KeySet
5
+ def self.class_sort_index
6
+ 0
7
+ end
8
+
9
+ def represents_none?
10
+ true
11
+ end
12
+
13
+ def invert
14
+ KeySet.all
15
+ end
16
+
17
+ def remove(other)
18
+ case other
19
+ when All
20
+ # we have nothing, we remove everything => we have nothing
21
+ KeySet.none
22
+ when None
23
+ # we have nothing, we remove nothing => we have nothing
24
+ KeySet.none
25
+ when Some
26
+ # we have nothing, we remove some => we have nothing
27
+ KeySet.none
28
+ when AllExceptSome
29
+ # we have nothing, we remove all except some => we have nothing
30
+ KeySet.logger.warn "KeySet removing AllButSome, probably a mistake. this: NONE, removing keys: #{other.keys.inspect}"
31
+ KeySet.none
32
+ else
33
+ raise ArgumentError, 'it needs a valid KeySet'
34
+ end
35
+ end
36
+
37
+ def intersect(other)
38
+ case other
39
+ when All
40
+ KeySet.none
41
+ when None
42
+ KeySet.none
43
+ when Some
44
+ KeySet.none
45
+ when AllExceptSome
46
+ KeySet.none
47
+ else
48
+ raise ArgumentError, 'it needs a valid KeySet'
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KeySet
4
+ class Some < KeySet
5
+ include BasedOnKeys
6
+
7
+ def self.class_sort_index
8
+ 1
9
+ end
10
+
11
+ def invert
12
+ KeySet.all_except_some(keys_array)
13
+ end
14
+
15
+ def remove(other)
16
+ case other
17
+ when All
18
+ # we have some, we remove everything => we have nothing
19
+ KeySet.none
20
+ when None
21
+ # we have some, we remove nothing => we have the same set
22
+ KeySet.some keys.deep_dup
23
+ when Some
24
+ # we have some, we remove some others => we have some with another set (or maybe none)
25
+ remove_some(other)
26
+ when AllExceptSome
27
+ # we have some, we remove all except others => we remove all except the intersection
28
+ KeySet.logger.warn "KeySet removing AllButSome, probably a mistake. this: SOME, removing keys: #{other.keys.inspect}"
29
+ remove_all_except_some(other)
30
+ else
31
+ raise ArgumentError, 'it needs a valid KeySet'
32
+ end
33
+ end
34
+
35
+ def intersect(other)
36
+ case other
37
+ when All
38
+ KeySet.some keys.deep_dup
39
+ when None
40
+ KeySet.none
41
+ when Some
42
+ intersect_with_some(other)
43
+ when AllExceptSome
44
+ intersect_with_all_except_some(other)
45
+ else
46
+ raise ArgumentError, 'it needs a valid KeySet'
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def remove_some(other)
53
+ k = keys.deep_dup - other.keys.deep_dup
54
+ KeySet.some k
55
+ end
56
+
57
+ def remove_all_except_some(other)
58
+ k = keys.deep_dup & other.keys.deep_dup
59
+ KeySet.some k
60
+ end
61
+
62
+ def intersect_with_all_except_some(other)
63
+ k = keys.deep_dup - other.keys.deep_dup
64
+ KeySet.some k
65
+ end
66
+
67
+ def intersect_with_some(other)
68
+ k = keys.deep_dup & other.keys.deep_dup
69
+ KeySet.some k
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KeySet
4
+ VERSION = '1.0.0'
5
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: key_set
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Eduardo Turiño
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-10-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.17'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.17'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description:
70
+ email:
71
+ - eturino@eturino.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".rubocop.yml"
79
+ - ".travis.yml"
80
+ - CODE_OF_CONDUCT.md
81
+ - Gemfile
82
+ - Gemfile.lock
83
+ - LICENSE.txt
84
+ - README.md
85
+ - Rakefile
86
+ - bin/console
87
+ - bin/rake
88
+ - bin/setup
89
+ - key_set.gemspec
90
+ - lib/key_set.rb
91
+ - lib/key_set/all.rb
92
+ - lib/key_set/all_except_some.rb
93
+ - lib/key_set/based_on_keys.rb
94
+ - lib/key_set/none.rb
95
+ - lib/key_set/some.rb
96
+ - lib/key_set/version.rb
97
+ homepage: https://github.com/eturino/ruby_key_set
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.7.6
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: KeySet with 4 classes to represent concepts of All, None, Some, and AllExceptSome,
121
+ the last 2 with a sorted uniq list of keys
122
+ test_files: []