hash_tools 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cd2b001e2124881b7b3ceabe56d0970e9d53695a
4
- data.tar.gz: f53e06a41c6affa8959f6d41d93a1483362b142c
2
+ SHA256:
3
+ metadata.gz: c8db57f1a6be7a1864f76da7a2e93ffcf1ec32f855f5feb3749016ec1b7c2cc6
4
+ data.tar.gz: 6d28945cc41f489ef64e9d6908bda5706c5782154edc6416446185d67de76c47
5
5
  SHA512:
6
- metadata.gz: ecc953a68b52a3c1b8a39aa81361f34118a59c4adef6b035f15a75490e8d883a1910a5a6b9535041373aea1e2de1779734337d866e7725b9a79261d927adb744
7
- data.tar.gz: 03d991cdc0e98d252f85b0447d64096037d43876b34eab4dc54824fe933cc0bf040ac2e656c0b2e4076f7ddd0631a4aa03cc8411366e12b71279c175653d8d9f
6
+ metadata.gz: 761b2fd798bebdab23de37c6fea09ac79d19be097f0c227349632518901589f3d3b7228ca6d21b6440b1193178904aac1fe3e2fcd486236e9bda76cdadebfb4b
7
+ data.tar.gz: 6ba40bb275dcdc6fd4a2c8c53f4675f973357bae954f1d0929292f8adb5c352c89e8a6604c0a23f50f443dfceff4a075c37ef600ad6f95540f07a9479e5d1aaa
data/.rspec CHANGED
@@ -1 +1,3 @@
1
+ --format documentation
1
2
  --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,42 @@
1
+ AllCops:
2
+ NewCops: disable
3
+ TargetRubyVersion: 2.6
4
+
5
+ Layout/ArgumentAlignment:
6
+ EnforcedStyle: with_fixed_indentation
7
+
8
+ Layout/MultilineMethodCallIndentation:
9
+ EnforcedStyle: indented
10
+
11
+ Layout/LineLength:
12
+ Max: 120
13
+ Severity: convention
14
+
15
+ Lint/AmbiguousBlockAssociation:
16
+ Exclude:
17
+ - "spec/**/*"
18
+
19
+ Metrics/BlockLength:
20
+ Exclude:
21
+ - "spec/**/*"
22
+
23
+ Metrics/MethodLength:
24
+ Max: 50
25
+
26
+ Style/Documentation:
27
+ Enabled: false
28
+
29
+ Style/FrozenStringLiteralComment:
30
+ Enabled: false
31
+
32
+ Style/IfUnlessModifier:
33
+ Enabled: false
34
+
35
+ Style/StringLiterals:
36
+ EnforcedStyle: double_quotes
37
+
38
+ Style/GuardClause:
39
+ Enabled: false
40
+
41
+ Lint/MissingSuper:
42
+ Enabled: false
@@ -0,0 +1,84 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or
22
+ advances of any kind
23
+ * Trolling, insulting or derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or email
26
+ address, without their explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Enforcement Responsibilities
31
+
32
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
+
34
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
+
36
+ ## Scope
37
+
38
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
+
40
+ ## Enforcement
41
+
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at gerard@wetransfer.com. All complaints will be reviewed and investigated promptly and fairly.
43
+
44
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
+
46
+ ## Enforcement Guidelines
47
+
48
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
+
50
+ ### 1. Correction
51
+
52
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
+
54
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
+
56
+ ### 2. Warning
57
+
58
+ **Community Impact**: A violation through a single incident or series of actions.
59
+
60
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
+
62
+ ### 3. Temporary Ban
63
+
64
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
+
66
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
+
68
+ ### 4. Permanent Ban
69
+
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
+
72
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
73
+
74
+ ## Attribution
75
+
76
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
+ available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
+
79
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
+
81
+ [homepage]: https://www.contributor-covenant.org
82
+
83
+ For answers to common questions about this code of conduct, see the FAQ at
84
+ https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in hash_tools.gemspec
4
6
  gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hash_tools (1.2.4)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ diff-lcs (1.5.0)
11
+ parallel (1.21.0)
12
+ parser (3.1.0.0)
13
+ ast (~> 2.4.1)
14
+ rainbow (3.1.1)
15
+ rake (13.0.6)
16
+ regexp_parser (2.2.0)
17
+ rexml (3.2.5)
18
+ rspec (3.10.0)
19
+ rspec-core (~> 3.10.0)
20
+ rspec-expectations (~> 3.10.0)
21
+ rspec-mocks (~> 3.10.0)
22
+ rspec-core (3.10.1)
23
+ rspec-support (~> 3.10.0)
24
+ rspec-expectations (3.10.2)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.10.0)
27
+ rspec-mocks (3.10.2)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.10.0)
30
+ rspec-support (3.10.3)
31
+ rubocop (1.25.0)
32
+ parallel (~> 1.10)
33
+ parser (>= 3.1.0.0)
34
+ rainbow (>= 2.2.2, < 4.0)
35
+ regexp_parser (>= 1.8, < 3.0)
36
+ rexml
37
+ rubocop-ast (>= 1.15.1, < 2.0)
38
+ ruby-progressbar (~> 1.7)
39
+ unicode-display_width (>= 1.4.0, < 3.0)
40
+ rubocop-ast (1.15.1)
41
+ parser (>= 3.0.1.1)
42
+ ruby-progressbar (1.11.0)
43
+ unicode-display_width (2.1.0)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ bundler (~> 2)
50
+ hash_tools!
51
+ rake (~> 13.0)
52
+ rspec (~> 3.0)
53
+ rubocop (~> 1.21)
54
+
55
+ BUNDLED WITH
56
+ 2.3.4
data/LICENSE.txt CHANGED
@@ -1,20 +1,33 @@
1
- Copyright (c) 2015 Julik Tarkhanov
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright 2022 WeTransfer
2
+
3
+ Hippocratic License Version Number: 2.1.
4
+
5
+ Purpose. The purpose of this License is for the Licensor named above to permit the Licensee (as defined below) broad permission, if consistent with Human Rights Laws and Human Rights Principles (as each is defined below), to use and work with the Software (as defined below) within the full scope of Licensor’s copyright and patent rights, if any, in the Software, while ensuring attribution and protecting the Licensor from liability.
6
+
7
+ Permission and Conditions. The Licensor grants permission by this license (“License”), free of charge, to the extent of Licensor’s rights under applicable copyright and patent law, to any person or entity (the “Licensee”) obtaining a copy of this software and associated documentation files (the Software”), to do everything with the Software that would otherwise infringe (i) the Licensor’s copyright in the Software or (ii) any patent claims to the Software that the Licensor can license or becomes able to license, subject to all of the following terms and conditions:
8
+
9
+ - Acceptance. This License is automatically offered to every person and entity subject to its terms and conditions. Licensee accepts this License and agrees to its terms and conditions by taking any action with the Software that, absent this License, would infringe any intellectual property right held by Licensor.
10
+
11
+ - Notice. Licensee must ensure that everyone who gets a copy of any part of this Software from Licensee, with or without changes, also receives the License and the above copyright notice (and if included by the Licensor, patent, trademark and attribution notice). Licensee must cause any modified versions of the Software to carry prominent notices stating that Licensee changed the Software. For clarity, although Licensee is free to create modifications of the Software and distribute only the modified portion created by Licensee with additional or different terms, the portion of the Software not modified must be distributed pursuant to this License. If anyone notifies Licensee in writing that Licensee has not complied with this Notice section, Licensee can keep this License by taking all practical steps to comply within 30 days after the notice. If Licensee does not do so, Licensee’s License (and all rights licensed hereunder) shall end immediately.
12
+
13
+ - Compliance with Human Rights Principles and Human Rights Laws.
14
+
15
+ 1. Human Rights Principles.
16
+
17
+ (a) Licensee is advised to consult the articles of the United Nations Universal Declaration of Human Rights and the United Nations Global Compact that define recognized principles of international human rights (the “Human Rights Principles”). Licensee shall use the Software in a manner consistent with Human Rights Principles.
18
+
19
+ (b) Unless the Licensor and Licensee agree otherwise, any dispute, controversy, or claim arising out of or relating to (i) Section 1(a) regarding Human Rights Principles, including the breach of Section 1(a), termination of this License for breach of the Human Rights Principles, or invalidity of Section 1(a) or (ii) a determination of whether any Law is consistent or in conflict with Human Rights Principles pursuant to Section 2, below, shall be settled by arbitration in accordance with the Hague Rules on Business and Human Rights Arbitration (the “Rules”); provided, however, that Licensee may elect not to participate in such arbitration, in which event this License (and all rights licensed hereunder) shall end immediately. The number of arbitrators shall be one unless the Rules require otherwise.
20
+
21
+ Unless both the Licensor and Licensee agree to the contrary: (1) All documents and information concerning the arbitration shall be public and may be disclosed by any party; (2) The repository referred to under Article 43 of the Rules shall make available to the public in a timely manner all documents concerning the arbitration which are communicated to it, including all submissions of the parties, all evidence admitted into the record of the proceedings, all transcripts or other recordings of hearings and all orders, decisions and awards of the arbitral tribunal, subject only to the arbitral tribunal's powers to take such measures as may be necessary to safeguard the integrity of the arbitral process pursuant to Articles 18, 33, 41 and 42 of the Rules; and (3) Article 26(6) of the Rules shall not apply.
22
+
23
+ 2. Human Rights Laws. The Software shall not be used by any person or entity for any systems, activities, or other uses that violate any Human Rights Laws. “Human Rights Laws” means any applicable laws, regulations, or rules (collectively, “Laws”) that protect human, civil, labor, privacy, political, environmental, security, economic, due process, or similar rights; provided, however, that such Laws are consistent and not in conflict with Human Rights Principles (a dispute over the consistency or a conflict between Laws and Human Rights Principles shall be determined by arbitration as stated above). Where the Human Rights Laws of more than one jurisdiction are applicable or in conflict with respect to the use of the Software, the Human Rights Laws that are most protective of the individuals or groups harmed shall apply.
24
+
25
+ 3. Indemnity. Licensee shall hold harmless and indemnify Licensor (and any other contributor) against all losses, damages, liabilities, deficiencies, claims, actions, judgments, settlements, interest, awards, penalties, fines, costs, or expenses of whatever kind, including Licensor’s reasonable attorneys’ fees, arising out of or relating to Licensee’s use of the Software in violation of Human Rights Laws or Human Rights Principles.
26
+
27
+ - Failure to Comply. Any failure of Licensee to act according to the terms and conditions of this License is both a breach of the License and an infringement of the intellectual property rights of the Licensor (subject to exceptions under Laws, e.g., fair use). In the event of a breach or infringement, the terms and conditions of this License may be enforced by Licensor under the Laws of any jurisdiction to which Licensee is subject. Licensee also agrees that the Licensor may enforce the terms and conditions of this License against Licensee through specific performance (or similar remedy under Laws) to the extent permitted by Laws. For clarity, except in the event of a breach of this License, infringement, or as otherwise stated in this License, Licensor may not terminate this License with Licensee.
28
+
29
+ - Enforceability and Interpretation. If any term or provision of this License is determined to be invalid, illegal, or unenforceable by a court of competent jurisdiction, then such invalidity, illegality, or unenforceability shall not affect any other term or provision of this License or invalidate or render unenforceable such term or provision in any other jurisdiction; provided, however, subject to a court modification pursuant to the immediately following sentence, if any term or provision of this License pertaining to Human Rights Laws or Human Rights Principles is deemed invalid, illegal, or unenforceable against Licensee by a court of competent jurisdiction, all rights in the Software granted to Licensee shall be deemed null and void as between Licensor and Licensee. Upon a determination that any term or provision is invalid, illegal, or unenforceable, to the extent permitted by Laws, the court may modify this License to affect the original purpose that the Software be used in compliance with Human Rights Principles and Human Rights Laws as closely as possible. The language in this License shall be interpreted as to its fair meaning and not strictly for or against any party.
30
+
31
+ - Disclaimer. TO THE FULL EXTENT ALLOWED BY LAW, THIS SOFTWARE COMES “AS IS,” WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED, AND LICENSOR AND ANY OTHER CONTRIBUTOR SHALL NOT BE LIABLE TO ANYONE FOR ANY DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THIS LICENSE, UNDER ANY KIND OF LEGAL CLAIM.
32
+
33
+ This Hippocratic License is an Ethical Source license (https://ethicalsource.dev) and is offered for use by licensors and licensees at their own risk, on an “AS IS” basis, and with no warranties express or implied, to the maximum extent permitted by Laws.
data/Rakefile CHANGED
@@ -1,6 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "hash_tools"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
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
@@ -1,139 +1,147 @@
1
- require 'delegate'
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
2
4
 
3
5
  # A tiny version of HashWithIndifferentAccess. Works like a wrapper proxy around a Ruby Hash.
4
6
  # Does not support all of the methods for a Ruby Hash object, but nevertheless can be useful
5
7
  # for checking params and for working with parsed JSON.
6
- class HashTools::Indifferent < SimpleDelegator
7
- # Create a new Indifferent by supplying a Ruby Hash object to wrap. The Hash being
8
- # wrapped is not going to be altered or copied.
9
- #
10
- # @param naked_hash [Hash] the Hash object to wrap with an Indifferent
11
- def initialize(naked_hash)
12
- __setobj__(naked_hash)
13
- end
14
-
15
- # Get a value from the Hash, bu supplying a Symbol or a String
16
- # Key presence is verified by first trying a Symbol, and then a String.
17
- #
18
- # @param k the key to fetch
19
- # @return the value, wrapped in {Indifferent} if it is a Hash
20
- def [](k)
21
- v = __getobj__[__transform_key__(k)]
22
- __rewrap__(v)
23
- end
24
-
25
- # Set a value in the Hash, bu supplying a Symbol or a String as a key.
26
- # Key presence is verified by first trying a Symbol, and then a String.
27
- #
28
- # @param k the key to set
29
- # @param v the value to set
30
- # @return v
31
- def []=(k, v)
32
- __getobj__[ __transform_key__(k) ] = v
33
- end
34
-
35
- # Fetch a value, by supplying a Symbol or a String as a key.
36
- # Key presence is verified by first trying a Symbol, and then a String.
37
- #
38
- # @param k the key to set
39
- # @param blk the block for no value
40
- # @return v
41
- def fetch(k, &blk)
42
- v = __getobj__.fetch( __transform_key__(k) , &blk)
43
- __rewrap__(v)
44
- end
45
-
46
- # Get the keys of the Hash. The keys are returned as-is (both Symbols and Strings).
47
- #
48
- # @return [Array] an array of keys
49
- def keys
50
- __getobj__.keys.map{|k| __transform_key__(k) }
51
- end
52
-
53
- # Checks for key presence whether the key is a String or a Symbol
54
- #
55
- # @param k[String,Symbol] the key to check
56
- def key?(k)
57
- __getobj__.has_key?( __transform_key__(k))
58
- end
59
-
60
- # Checks if the value at the given key is non-empty
61
- #
62
- # @param k[String,Symbol] the key to check
63
- def value_present?(k)
64
- return false unless key?(k)
65
- v = self[k]
66
- return false unless v
67
- return !v.to_s.empty?
68
- end
69
-
70
- # Yields each key - value pair of the indifferent.
71
- # If the value is a Hash as well, that hash will be wrapped in an Indifferent before returning
72
- def each(&blk)
73
- __getobj__.each do |k, v|
74
- blk.call([__transform_key__(k), __rewrap__(v)])
8
+ module HashTools
9
+ class Indifferent < SimpleDelegator
10
+ # Create a new Indifferent by supplying a Ruby Hash object to wrap. The Hash being
11
+ # wrapped is not going to be altered or copied.
12
+ #
13
+ # @param naked_hash [Hash] the Hash object to wrap with an Indifferent
14
+ def initialize(naked_hash)
15
+ __setobj__(naked_hash)
75
16
  end
76
- end
77
-
78
- # Yields each key - value pair of the indifferent.
79
- # If the value is a Hash as well, that hash will be wrapped in an Indifferent before returning
80
- def each_pair
81
- o = __getobj__
82
- keys.each do | k |
83
- value = o[__transform_key__(k)]
84
- yield(k, __rewrap__(value))
17
+
18
+ # Get a value from the Hash, bu supplying a Symbol or a String
19
+ # Key presence is verified by first trying a Symbol, and then a String.
20
+ #
21
+ # @param k the key to fetch
22
+ # @return the value, wrapped in {Indifferent} if it is a Hash
23
+ def [](key)
24
+ value = __getobj__[__transform_key__(key)]
25
+ __rewrap__(value)
85
26
  end
86
- end
87
-
88
- # Maps over keys and values of the Hash. The key class will be preserved (i.e. within
89
- # the block the keys will be either Strings or Symbols depending on what is used in the
90
- # underlying Hash).
91
- def map(&blk)
92
- keys.map do |k|
93
- tk = __transform_key__(k)
94
- yield [tk, __rewrap__(__getobj__[tk])]
27
+
28
+ # Set a value in the Hash, bu supplying a Symbol or a String as a key.
29
+ # Key presence is verified by first trying a Symbol, and then a String.
30
+ #
31
+ # @param k the key to set
32
+ # @param v the value to set
33
+ # @return v
34
+ def []=(key, value)
35
+ __getobj__[__transform_key__(key)] = value
95
36
  end
96
- end
97
-
98
- # There is a quirk whereby the delegate library will not pass `to_json` to the
99
- # contained Hash, and the Indifferent would the JSON-serialize as a String.
100
- # We have to forward this method explicitly.
101
- #
102
- # In general, the method will never be called by the user directly but will instead
103
- # be excercised by `JSON.dump()` and friends.
104
- def to_json(*serializer_state)
105
- to_h.to_json(*serializer_state)
106
- end
107
-
108
- def method_missing(method_name, *args)
109
- return self[method_name] if key?(method_name) && args.empty?
110
- super
111
- end
112
-
113
- def respond_to_missing?(method_name, include_private=false)
114
- key?(method_name)
115
- end
116
37
 
117
- def to_hash
118
- __getobj__.to_hash
119
- end
38
+ # Fetch a value, by supplying a Symbol or a String as a key.
39
+ # Key presence is verified by first trying a Symbol, and then a String.
40
+ #
41
+ # @param k the key to set
42
+ # @param blk the block for no value
43
+ # @return v
44
+ def fetch(key, &blk)
45
+ value = __getobj__.fetch(__transform_key__(key), &blk)
46
+ __rewrap__(value)
47
+ end
48
+
49
+ # Get the keys of the Hash. The keys are returned as-is (both Symbols and Strings).
50
+ #
51
+ # @return [Array] an array of keys
52
+ def keys
53
+ __getobj__.keys.map { |key| __transform_key__(key) }
54
+ end
55
+
56
+ # Checks for key presence whether the key is a String or a Symbol
57
+ #
58
+ # @param k[String,Symbol] the key to check
59
+ def key?(key)
60
+ __getobj__.key?(__transform_key__(key))
61
+ end
62
+
63
+ # Checks if the value at the given key is non-empty
64
+ #
65
+ # @param k[String,Symbol] the key to check
66
+ def value_present?(key)
67
+ return false unless key?(key)
68
+
69
+ value = self[key]
70
+ return false unless value
120
71
 
121
- alias_method :has_key?, :key?
122
-
123
- private
124
-
125
- def __transform_key__(k)
126
- if __getobj__.has_key?(k.to_sym)
127
- k.to_sym
128
- else
129
- k.to_s
130
- end
131
- end
132
-
133
- def __rewrap__(v)
134
- return v if v.is_a?(self.class)
135
- return self.class.new(v) if v.is_a?(Hash)
136
- return v.map{|e| __rewrap__(e)} if v.is_a?(Array)
137
- v
72
+ !value.to_s.empty?
73
+ end
74
+
75
+ # Yields each key - value pair of the indifferent.
76
+ # If the value is a Hash as well, that hash will be wrapped in an Indifferent before returning
77
+ def each(&blk)
78
+ __getobj__.each do |key, value|
79
+ blk.call([__transform_key__(key), __rewrap__(value)])
80
+ end
81
+ end
82
+
83
+ # Yields each key - value pair of the indifferent.
84
+ # If the value is a Hash as well, that hash will be wrapped in an Indifferent before returning
85
+ def each_pair
86
+ object = __getobj__
87
+ keys.each do |key|
88
+ value = object[__transform_key__(key)]
89
+ yield(key, __rewrap__(value))
90
+ end
91
+ end
92
+
93
+ # Maps over keys and values of the Hash. The key class will be preserved (i.e. within
94
+ # the block the keys will be either Strings or Symbols depending on what is used in the
95
+ # underlying Hash).
96
+ def map
97
+ keys.map do |key|
98
+ transform_key = __transform_key__(key)
99
+ yield [transform_key, __rewrap__(__getobj__[transform_key])]
100
+ end
101
+ end
102
+
103
+ # There is a quirk whereby the delegate library will not pass `to_json` to the
104
+ # contained Hash, and the Indifferent would the JSON-serialize as a String.
105
+ # We have to forward this method explicitly.
106
+ #
107
+ # In general, the method will never be called by the user directly but will instead
108
+ # be excercised by `JSON.dump()` and friends.
109
+ def to_json(*serializer_state)
110
+ to_h.to_json(*serializer_state)
111
+ end
112
+
113
+ def method_missing(method_name, *args)
114
+ return self[method_name] if key?(method_name) && args.empty?
115
+
116
+ super
117
+ end
118
+
119
+ def respond_to_missing?(method_name, _include_private = false)
120
+ key?(method_name)
121
+ end
122
+
123
+ def to_hash
124
+ __getobj__.to_hash
125
+ end
126
+
127
+ alias has_key? key?
128
+
129
+ private
130
+
131
+ def __transform_key__(key)
132
+ if __getobj__.key?(key.to_sym)
133
+ key.to_sym
134
+ else
135
+ key.to_s
136
+ end
137
+ end
138
+
139
+ def __rewrap__(value)
140
+ return value if value.is_a?(self.class)
141
+ return self.class.new(value) if value.is_a?(Hash)
142
+ return value.map { |e| __rewrap__(e) } if value.is_a?(Array)
143
+
144
+ value
145
+ end
138
146
  end
139
- end
147
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HashTools
4
+ VERSION = "1.2.4"
5
+ end
data/lib/hash_tools.rb CHANGED
@@ -1,11 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module HashTools
2
- VERSION = '1.2.3'
3
-
4
- require_relative 'hash_tools/indifferent'
5
-
6
- FWD_SLASH = '/' # Used as the default separator for deep_fetch
7
- INT_KEY_RE = /^\-?\d+$/ # Regular expression to detect array indices in the path ("phones/0/code")
8
-
4
+ require_relative "hash_tools/indifferent"
5
+
6
+ FWD_SLASH = "/" # Used as the default separator for deep_fetch
7
+ INT_KEY_RE = /^-?\d+$/.freeze # Regular expression to detect array indices in the path ("phones/0/code")
8
+
9
9
  # Fetch a deeply-nested hash key from a hash, using a String representing a path
10
10
  #
11
11
  # deep_fetch({
@@ -15,7 +15,8 @@ module HashTools
15
15
  # }, 'a/b/c') #=> value
16
16
  #
17
17
  # @param hash [Hash] the (potentially deep) string-keyed Hash to fetch the value from
18
- # @param path [String] the path to the item in `hash`. The path may contain numbers for deeply nested arrays ('foo/0/bar')
18
+ # @param path [String] the path to the item in `hash`. The path may contain
19
+ # numbers for deeply nested arrays ('foo/0/bar')
19
20
  # @param separator [String] the path separator, defaults to '/'
20
21
  # @param default_blk The default value block for when there is no value.
21
22
  # @return the fetched value or the value of the default_block
@@ -31,7 +32,7 @@ module HashTools
31
32
  end
32
33
  end
33
34
  end
34
-
35
+
35
36
  # Fetches multiple keys from a deep hash, using a Strings representing paths
36
37
  #
37
38
  # deep_fetch({
@@ -42,13 +43,14 @@ module HashTools
42
43
  # }, 'a/b', 'z') #=> [value, 1]
43
44
  #
44
45
  # @param hash [Hash] the (potentially deep) string-keyed Hash to fetch the value from
45
- # @param key_paths [String] the paths to the items in `hash`. The paths may contain numbers for deeply nested arrays ('foo/0/bar')
46
+ # @param key_paths [String] the paths to the items in `hash`. The paths may
47
+ # contain numbers for deeply nested arrays ('foo/0/bar')
46
48
  # @param separator [String] the path separator, defaults to '/'
47
49
  # @return [Array] the fetched values
48
50
  def deep_fetch_multi(hash, *key_paths, separator: FWD_SLASH)
49
- key_paths.map{|k| deep_fetch(hash, k, separator: separator) }
51
+ key_paths.map { |k| deep_fetch(hash, k, separator: separator) }
50
52
  end
51
-
53
+
52
54
  # Fetches a deeply nested key from each of the Hashes in a given Array.
53
55
  #
54
56
  # arr = [
@@ -62,9 +64,9 @@ module HashTools
62
64
  # @param separator [String] the path separator, defaults to '/'
63
65
  # @return [Array] the fetched values
64
66
  def deep_map_value(enum_of_hashes, path, separator: FWD_SLASH)
65
- enum_of_hashes.map{|h| deep_fetch(h, path, separator: separator)}
67
+ enum_of_hashes.map { |h| deep_fetch(h, path, separator: separator) }
66
68
  end
67
-
69
+
68
70
  # Recursively transform string keys and values of a passed
69
71
  # Hash or Array using the passed transformer
70
72
  #
@@ -74,7 +76,7 @@ module HashTools
74
76
  def transform_string_keys_and_values_of(any, &transformer)
75
77
  transform_string_values_of(transform_keys_of(any, &transformer), &transformer)
76
78
  end
77
-
79
+
78
80
  # Recursively convert string values in nested hashes and
79
81
  # arrays using a passed block. The block will receive the String
80
82
  # to transform and should return a transformed string.
@@ -83,11 +85,12 @@ module HashTools
83
85
  # @param transformer The block applied to each string value, recursively
84
86
  # @return the transformed value
85
87
  def transform_string_values_of(any, &transformer)
86
- if any.is_a?(String)
88
+ case any
89
+ when String
87
90
  transformer.call(any)
88
- elsif any.is_a?(Array)
89
- any.map{|e| transform_string_values_of(e, &transformer) }
90
- elsif any.is_a?(Hash)
91
+ when Array
92
+ any.map { |e| transform_string_values_of(e, &transformer) }
93
+ when Hash
91
94
  h = {}
92
95
  any.each_pair do |k, v|
93
96
  h[k] = transform_string_values_of(v, &transformer)
@@ -97,7 +100,7 @@ module HashTools
97
100
  any
98
101
  end
99
102
  end
100
-
103
+
101
104
  # Recursively convert hash keys using a block.
102
105
  # using a passed block. The block will receive a hash key
103
106
  # to be transformed and should return a transformed key
@@ -110,9 +113,10 @@ module HashTools
110
113
  # @param transformer the block to apply to each key, recursively
111
114
  # @return [Hash] the transformed Hash
112
115
  def transform_keys_of(any, &transformer)
113
- if any.is_a?(Array)
114
- return any.map{|e| transform_keys_of(e, &transformer) }
115
- elsif any.is_a?(Hash)
116
+ case any
117
+ when Array
118
+ any.map { |e| transform_keys_of(e, &transformer) }
119
+ when Hash
116
120
  h = {}
117
121
  any.each_pair do |k, v|
118
122
  h[transformer.call(k.to_s)] = transform_keys_of(v, &transformer)
@@ -122,7 +126,7 @@ module HashTools
122
126
  any
123
127
  end
124
128
  end
125
-
129
+
126
130
  # Returns an {HashTools::Indifferent} wrapper for the given Hash.
127
131
  #
128
132
  # @param hash [Hash] the Hash to wrap
@@ -130,6 +134,4 @@ module HashTools
130
134
  def indifferent(hash)
131
135
  Indifferent.new(hash)
132
136
  end
133
-
134
- extend self
135
137
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash_tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
8
- autorequire:
8
+ - grdw
9
+ autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2017-05-15 00:00:00.000000000 Z
12
+ date: 2022-01-19 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
@@ -16,73 +17,84 @@ dependencies:
16
17
  requirements:
17
18
  - - "~>"
18
19
  - !ruby/object:Gem::Version
19
- version: '1'
20
+ version: '2'
20
21
  type: :development
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
25
  - - "~>"
25
26
  - !ruby/object:Gem::Version
26
- version: '1'
27
+ version: '2'
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: rake
29
30
  requirement: !ruby/object:Gem::Requirement
30
31
  requirements:
31
32
  - - "~>"
32
33
  - !ruby/object:Gem::Version
33
- version: '10.0'
34
+ version: '13.0'
34
35
  type: :development
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
39
  - - "~>"
39
40
  - !ruby/object:Gem::Version
40
- version: '10.0'
41
+ version: '13.0'
41
42
  - !ruby/object:Gem::Dependency
42
43
  name: rspec
43
44
  requirement: !ruby/object:Gem::Requirement
44
45
  requirements:
45
46
  - - "~>"
46
47
  - !ruby/object:Gem::Version
47
- version: 3.2.0
48
- - - "<"
49
- - !ruby/object:Gem::Version
50
- version: '3.3'
48
+ version: '3.0'
51
49
  type: :development
52
50
  prerelease: false
53
51
  version_requirements: !ruby/object:Gem::Requirement
54
52
  requirements:
55
53
  - - "~>"
56
54
  - !ruby/object:Gem::Version
57
- version: 3.2.0
58
- - - "<"
55
+ version: '3.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rubocop
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.21'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
59
68
  - !ruby/object:Gem::Version
60
- version: '3.3'
69
+ version: '1.21'
61
70
  description: Do useful things to Ruby Hashes
62
71
  email:
63
72
  - me@julik.nl
73
+ - gerard@wetransfer.com
64
74
  executables: []
65
75
  extensions: []
66
76
  extra_rdoc_files: []
67
77
  files:
68
- - ".document"
69
- - ".gitignore"
70
78
  - ".rspec"
71
- - ".travis.yml"
72
- - ".yardopts"
79
+ - ".rubocop.yml"
80
+ - CODE_OF_CONDUCT.md
73
81
  - Gemfile
82
+ - Gemfile.lock
74
83
  - LICENSE.txt
75
84
  - README.md
76
85
  - Rakefile
77
- - hash_tools.gemspec
86
+ - bin/console
87
+ - bin/setup
78
88
  - lib/hash_tools.rb
79
89
  - lib/hash_tools/indifferent.rb
90
+ - lib/hash_tools/version.rb
80
91
  homepage: https://github.com/WeTransfer/hash_tools
81
92
  licenses:
82
93
  - MIT
83
94
  metadata:
84
- allowed_push_host: https://rubygems.org
85
- post_install_message:
95
+ homepage_uri: https://github.com/WeTransfer/hash_tools
96
+ source_code_uri: https://github.com/WeTransfer/hash_tools
97
+ post_install_message:
86
98
  rdoc_options: []
87
99
  require_paths:
88
100
  - lib
@@ -90,16 +102,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
102
  requirements:
91
103
  - - ">="
92
104
  - !ruby/object:Gem::Version
93
- version: '0'
105
+ version: 2.6.0
94
106
  required_rubygems_version: !ruby/object:Gem::Requirement
95
107
  requirements:
96
108
  - - ">="
97
109
  - !ruby/object:Gem::Version
98
110
  version: '0'
99
111
  requirements: []
100
- rubyforge_project:
101
- rubygems_version: 2.5.2
102
- signing_key:
112
+ rubygems_version: 3.2.22
113
+ signing_key:
103
114
  specification_version: 4
104
115
  summary: Do useful things to Ruby Hashes
105
116
  test_files: []
data/.document DELETED
@@ -1,5 +0,0 @@
1
- lib/**/*.rb
2
- bin/*
3
- -
4
- features/**/*.feature
5
- LICENSE.txt
data/.gitignore DELETED
@@ -1,53 +0,0 @@
1
- # rcov generated
2
- coverage
3
- coverage.data
4
-
5
- # rdoc generated
6
- rdoc
7
-
8
- # yard generated
9
- doc
10
- .yardoc
11
-
12
- # bundler
13
- .bundle
14
- Gemfile.lock
15
-
16
- # docs
17
- doc
18
-
19
- # jeweler generated
20
- pkg
21
-
22
- # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
23
- #
24
- # * Create a file at ~/.gitignore
25
- # * Include files you want ignored
26
- # * Run: git config --global core.excludesfile ~/.gitignore
27
- #
28
- # After doing this, these files will be ignored in all your git projects,
29
- # saving you from having to 'pollute' every project you touch with them
30
- #
31
- # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
32
- #
33
- # For MacOS:
34
- #
35
- #.DS_Store
36
-
37
- # For TextMate
38
- #*.tmproj
39
- #tmtags
40
-
41
- # For emacs:
42
- #*~
43
- #\#*
44
- #.\#*
45
-
46
- # For vim:
47
- #*.swp
48
-
49
- # For redcar:
50
- #.redcar
51
-
52
- # For rubinius:
53
- #*.rbc
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- rvm:
2
- - 2.0.0
3
- - 2.1.1
4
- - 2.2.0
5
- - 2.3.3
6
- cache: bundler
7
- sudo: false
data/.yardopts DELETED
@@ -1 +0,0 @@
1
- --markup markdown
data/hash_tools.gemspec DELETED
@@ -1,33 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'hash_tools'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "hash_tools"
8
- spec.version = HashTools::VERSION
9
- spec.authors = ["Julik Tarkhanov"]
10
- spec.email = ["me@julik.nl"]
11
-
12
- spec.summary = %Q{Do useful things to Ruby Hashes}
13
- spec.description = %Q{Do useful things to Ruby Hashes}
14
- spec.homepage = "https://github.com/WeTransfer/hash_tools"
15
- spec.license = "MIT"
16
-
17
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
- # to allow pushing to a single host or delete this section to allow pushing to any host.
19
- if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
- else
22
- raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
- end
24
-
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
29
-
30
- spec.add_development_dependency "bundler", "~> 1"
31
- spec.add_development_dependency "rake", "~> 10.0"
32
- spec.add_development_dependency "rspec", "~> 3.2.0", '< 3.3'
33
- end