intellihash 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 17ac847b242baeffdc96ca1bb5b53c352b151834f69982221d30d73048b0ae35
4
+ data.tar.gz: e1f386d85a69f2af333b1c2c85bba7f66e7d2977bfd0fab69aa19174a8e22cd7
5
+ SHA512:
6
+ metadata.gz: 2dcc030b8a4013d1ed190eafb7ce8ef0c075db1ab77dc254524f7594addcbfad5c717ff8af198fdaa09a07b90548719ffefc40ae1e206d4601f4995215238e26
7
+ data.tar.gz: 8145467934645236a1819456705cc45e1d08d2be75518af8db5a0027849699b94965735b5ab9b1158744ff03de99a1ca9374deeb889280dc2bb848ee660d24f2
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ # byebug history
14
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,17 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+ TargetRubyVersion: 2.6.5
5
+
6
+ Metrics/BlockLength:
7
+ Exclude:
8
+ - spec/*
9
+
10
+ Metrics/MethodLength:
11
+ Max: 15
12
+
13
+ Naming/PredicateName:
14
+ Enabled: false
15
+
16
+ Style/Documentation:
17
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in intellihash.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 12.0'
9
+ gem 'rspec', '~> 3.0'
data/Gemfile.lock ADDED
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ intellihash (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ benchmark-malloc (0.1.0)
11
+ benchmark-perf (0.5.0)
12
+ benchmark-trend (0.3.0)
13
+ byebug (11.1.3)
14
+ diff-lcs (1.4.4)
15
+ parallel (1.20.1)
16
+ parser (3.0.2.0)
17
+ ast (~> 2.4.1)
18
+ rainbow (3.0.0)
19
+ rake (12.3.3)
20
+ regexp_parser (2.1.1)
21
+ rexml (3.2.5)
22
+ rspec (3.10.0)
23
+ rspec-core (~> 3.10.0)
24
+ rspec-expectations (~> 3.10.0)
25
+ rspec-mocks (~> 3.10.0)
26
+ rspec-benchmark (0.5.1)
27
+ benchmark-malloc (~> 0.1.0)
28
+ benchmark-perf (~> 0.5.0)
29
+ benchmark-trend (~> 0.3.0)
30
+ rspec (>= 3.0.0, < 4.0.0)
31
+ rspec-core (3.10.1)
32
+ rspec-support (~> 3.10.0)
33
+ rspec-expectations (3.10.1)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.10.0)
36
+ rspec-mocks (3.10.2)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.10.0)
39
+ rspec-support (3.10.2)
40
+ rubocop (1.18.4)
41
+ parallel (~> 1.10)
42
+ parser (>= 3.0.0.0)
43
+ rainbow (>= 2.2.2, < 4.0)
44
+ regexp_parser (>= 1.8, < 3.0)
45
+ rexml
46
+ rubocop-ast (>= 1.8.0, < 2.0)
47
+ ruby-progressbar (~> 1.7)
48
+ unicode-display_width (>= 1.4.0, < 3.0)
49
+ rubocop-ast (1.8.0)
50
+ parser (>= 3.0.1.1)
51
+ ruby-progressbar (1.11.0)
52
+ unicode-display_width (2.0.0)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ byebug
59
+ intellihash!
60
+ rake (~> 12.0)
61
+ rspec (~> 3.0)
62
+ rspec-benchmark (~> 0.5.0)
63
+ rubocop (~> 1.18)
64
+
65
+ BUNDLED WITH
66
+ 2.1.4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Tyler Porter
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,274 @@
1
+ # Intellihash
2
+
3
+ A fast implementation of hashes as objects, benchmarked against OpenStruct. It allows chaining hash attributes as method calls instead of standard hash syntax.
4
+
5
+ Since an Intellihash extends the native Ruby `Hash`, this means instantiating a new smart hash is just as fast as a normal hash, _and_ you retain the ability to call all the normal instance methods on it.
6
+
7
+ ```ruby
8
+ intellihash = {
9
+ foo: {
10
+ bar: {
11
+ baz: {
12
+ bat: :bam
13
+ }
14
+ }
15
+ }
16
+ }
17
+
18
+ intellihash.foo.bar.baz.bat
19
+
20
+ #=> :bam
21
+ ```
22
+
23
+ You can achieve similar results by converting your hash to an OpenStruct:
24
+
25
+ ```ruby
26
+ hash = {
27
+ foo: {
28
+ bar: {
29
+ baz: {
30
+ bat: :bam
31
+ }
32
+ }
33
+ }
34
+ }
35
+
36
+ open_struct = OpenStruct.new(hash)
37
+ open_struct.foo.bar.baz.bat
38
+
39
+ #=> :bam
40
+ ```
41
+
42
+ But you lose access to your instance methods, and pay a performance penalty to instantiate it!
43
+
44
+ ```ruby
45
+ intellihash.size
46
+ #=> 1
47
+
48
+ open_struct.size
49
+ #=> nil
50
+ ```
51
+
52
+ ## Performance vs. OpenStruct
53
+
54
+ Creating an Intellihash is approximately 5x faster than instantiating an OpenStruct.
55
+
56
+ ```
57
+ user system total real
58
+ OpenStruct: 4.046875 0.906250 4.953125 ( 4.979611)
59
+ Intellihash: 0.828125 0.125000 0.953125 ( 0.956110)
60
+ ```
61
+
62
+ See [Testing Performance](#testing-performance) for details on running benchmarks.
63
+
64
+ ## Installation
65
+
66
+ Add this line to your application's Gemfile:
67
+
68
+ ```ruby
69
+ gem 'intellihash'
70
+ ```
71
+
72
+ And then execute:
73
+
74
+ $ bundle install
75
+
76
+ Or install it yourself as:
77
+
78
+ $ gem install intellihash
79
+
80
+ ## Configuration
81
+
82
+ If you need to customize Intellihash, you may create a configuration:
83
+
84
+ ```ruby
85
+ Intellihash.configure do |config|
86
+ config.enabled = true # (Boolean) Default: false
87
+ config.default_format = :symbol # (Symbol) Default: :symbol
88
+ config.smart_by_default = false # (Boolean) Default: false
89
+ end
90
+ ```
91
+
92
+ ### Options
93
+
94
+ - **enabled**
95
+ - Whether Intellihash is enabled or not
96
+ - You may wish to set this conditionally, such as enabling it only in a test environment
97
+ - i.e. `config.enabled = Rails.env.test?`
98
+ - **NOTE**: Once Intellihash is enabled, it cannot easily be disabled. Enable Intellihash with caution.
99
+ - **default_format**
100
+ - Valid values: `:sym, :symbol, :str, :string, :any`
101
+ - This determines the default storage and retrieval options
102
+ - **smart_by_default**
103
+ - Whether newly created hashes are smart
104
+ - When `false`, new hashes can still be converted to smart hashes via `hash.is_smart = true` or `hash.to_intellihash!`
105
+
106
+ ### Rails
107
+
108
+ Place the above configuration in an initializer (such as `config/initializers/intellihash.rb`)
109
+
110
+ ## Usage
111
+
112
+ ### Instantiating an Intellihash
113
+
114
+ If you've configured Intellihash `smart_by_default = true`, you need to do nothing else as _all_ new hashes are Intellihashes.
115
+
116
+ However, if you prefer not to use this configuration, you can create an Intellihash from any existing hash:
117
+
118
+ ```ruby
119
+ hash = { foo: :bar }
120
+
121
+ hash.is_smart?
122
+ #=> false
123
+
124
+ hash.is_smart = true
125
+ # or
126
+ hash.to_intellihash!
127
+
128
+ hash.is_smart?
129
+ #=> true
130
+ ```
131
+
132
+ ### Methods
133
+
134
+ Intellihash-powered hashes can access values via method chaining:
135
+
136
+ ```ruby
137
+ intellihash = { foo: :bar }
138
+
139
+ intellihash.foo
140
+
141
+ #=> :bar
142
+ ```
143
+
144
+ They can also store values in a similar way:
145
+
146
+ ```ruby
147
+ intellihash.baz = :bat
148
+ intellihash
149
+
150
+ #=> { foo: :bar, baz: :bat }
151
+ ```
152
+
153
+ When configured correctly, they work even when the object contains arrays and other classes:
154
+
155
+ ```ruby
156
+ Intellihash.configure do |config|
157
+ config.enabled = true
158
+ config.smart_by_default = true
159
+ config.default_format = :any
160
+ end
161
+
162
+ intellihash = {
163
+ a: {
164
+ complicated: [
165
+ {
166
+ object: {
167
+ "containing_many" => {
168
+ types_of_things: Also::Works
169
+ }
170
+ }
171
+ }
172
+ ]
173
+ }
174
+ }
175
+
176
+ intellihash.a.complicated.first.object.containing_many.types_of_things
177
+
178
+ #=> Also::Works
179
+ ```
180
+
181
+ ### Ambiguous Keys
182
+
183
+ When using an Intellihash that has an ambiguous key (i.e. the key exists both as a symbol and a string in the same hash), you can define which you would like to return at runtime:
184
+
185
+ ```ruby
186
+ intellihash ={
187
+ foo: :bar
188
+ 'foo' => 'bar'
189
+ }
190
+
191
+ intellihash.foo(from: :symbol) # or from: :sym
192
+ #=> :bar
193
+
194
+ intellihash.foo(from: :string) # or from: :str
195
+ #=> 'bar'
196
+ ```
197
+
198
+ If you prefer, you can use the original hash syntax:
199
+
200
+ ```ruby
201
+ intellihash[:foo]
202
+ #=> :bar
203
+
204
+ intellihash['foo']
205
+ #=> 'bar'
206
+ ```
207
+
208
+ **NOTE**: Intellihashes always **store** values as the configured `default_format`, which defaults to `:symbol`. Override this in the config as needed, or use hash syntax: `intellihash['bar'] = 'bat'`.
209
+
210
+ ### Collisions with Hash Methods
211
+
212
+ A powerful feature of Intellihash is the ability to use Ruby Hash instance methods on Intellihash. This also means that it's possible for some of the keys in the hash to collide with the names of the instance method you're trying to call.
213
+
214
+ For instance, consider `Hash#size`, which returns the number of keys in the hash:
215
+
216
+ ```ruby
217
+ intellihash = { size: 2 }
218
+
219
+ intellihash.size
220
+ #=> 1
221
+ ```
222
+
223
+ For this reason, it's better to use hash syntax to fetch these keys:
224
+
225
+ ```ruby
226
+ # Bad
227
+ intellihash.size
228
+
229
+ # Good
230
+ intellihash[:size]
231
+ intellihash.fetch(:size)
232
+ ```
233
+
234
+ You _can_, however, **set** keys in the hash using these instance methods. This is not recommended as the syntax leads to confusion when attempting to access the key.
235
+
236
+ ```ruby
237
+ intellihash.size = 3
238
+ intellihash
239
+
240
+ #=> { size: 3 }
241
+
242
+ intellihash.size
243
+ #=> 1
244
+ ```
245
+
246
+ ## Development
247
+
248
+ 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.
249
+
250
+ ## Testing
251
+
252
+ ### Unit Tests
253
+
254
+ Run unit tests:
255
+
256
+ ```
257
+ bundle exec rspec
258
+ ```
259
+
260
+ ### Testing Performance
261
+
262
+ Run performance benchmarks:
263
+
264
+ ```
265
+ bundle exec rspec --tag performance:true
266
+ ```
267
+
268
+ ## Contributing
269
+
270
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ty-porter/intellihash.
271
+
272
+ ## License
273
+
274
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
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
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'intellihash'
6
+ require 'byebug'
7
+
8
+ Intellihash.configure do |config|
9
+ config.enabled = true
10
+ config.smart_by_default = true
11
+ end
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/intellihash/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'intellihash'
7
+ spec.version = Intellihash::VERSION
8
+ spec.authors = ['Tyler Porter']
9
+ spec.email = ['tyler.b.porter@gmail.com']
10
+
11
+ spec.summary = 'A fast implementation of hashes as objects'
12
+ spec.description = <<~DESC
13
+ A fast implementation of hashes as objects, benchmarked against OpenStruct.
14
+ It allows chaining hash attributes as method calls instead of standard hash syntax.
15
+ DESC
16
+ spec.homepage = 'https://github.com/ty-porter/intellihash'
17
+ spec.license = 'MIT'
18
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.6.5')
19
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
+
21
+ spec.metadata['homepage_uri'] = spec.homepage
22
+ spec.metadata['source_code_uri'] = 'https://github.com/ty-porter/intellihash'
23
+
24
+ # Specify which files should be added to the gem when it is released.
25
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
26
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
27
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ end
29
+ spec.bindir = 'exe'
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ['lib']
32
+
33
+ spec.add_development_dependency('byebug', ['>= 0'])
34
+ spec.add_development_dependency('rspec-benchmark', ['~> 0.5.0'])
35
+ spec.add_development_dependency('rubocop', ['~> 1.18'])
36
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'intellihash/callbacks'
4
+ require 'intellihash/configuration'
5
+ require 'intellihash/mixins'
6
+ require 'intellihash/version'
7
+
8
+ module Intellihash
9
+ def self.enabled?
10
+ Intellihash.configuration.enabled
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intellihash
4
+ module Callbacks
5
+ # https://ruby-doc.org/core-3.0.1/Hash.html
6
+ #
7
+ # Methods that return a copy of :self: need this callback to populate :smart: from :self:
8
+ AFTER_CALLBACK_TARGETS = %i[
9
+ compact
10
+ invert
11
+ merge
12
+ reject
13
+ select
14
+ slice
15
+ to_h
16
+ transform_keys
17
+ transform_values
18
+ ].freeze
19
+
20
+ # Callback registration happens as soon as Intellihash::Callbacks is prepended
21
+ AFTER_CALLBACK_TARGETS.each do |instance_method|
22
+ define_method(instance_method) do |*args, &block|
23
+ # Call original method
24
+ result = super(*args, &block)
25
+
26
+ # Register :after: callbacks
27
+ result.is_smart = smart if result.respond_to?(:is_smart=) && !result.frozen?
28
+
29
+ result
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intellihash
4
+ class << self
5
+ attr_reader :configuration
6
+
7
+ def configure
8
+ yield(@configuration)
9
+
10
+ inject_dependencies! if Intellihash.enabled?
11
+ end
12
+
13
+ def configuration=(config)
14
+ raise InvalidConfiguration, config.class unless config.is_a?(Intellihash::Configuration)
15
+
16
+ @configuration = config
17
+ end
18
+
19
+ private
20
+
21
+ def inject_dependencies!
22
+ Hash.include Intellihash::Mixins
23
+ Hash.prepend Intellihash::Callbacks
24
+ end
25
+ end
26
+
27
+ class Configuration
28
+ attr_accessor :enabled, :smart_by_default
29
+ attr_reader :default_format
30
+
31
+ def initialize
32
+ @default_format = :symbol
33
+ @enabled = false
34
+ @smart_by_default = false
35
+ end
36
+
37
+ def default_format=(other)
38
+ @default_format = Intellihash::Mixins::FORMATTER.member?(other) ? other : :symbol
39
+ end
40
+ end
41
+
42
+ class InvalidConfiguration < StandardError; end
43
+
44
+ @configuration = Intellihash::Configuration.new
45
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intellihash
4
+ module Mixins
5
+ def smart
6
+ @smart = @smart.nil? ? Intellihash.configuration.smart_by_default : @smart
7
+ end
8
+
9
+ def is_smart=(value)
10
+ # Ensure this is a boolean
11
+ @smart = value == true
12
+ end
13
+
14
+ def to_intellihash
15
+ @smart = true
16
+ self
17
+ end
18
+
19
+ def is_smart?
20
+ smart
21
+ end
22
+
23
+ def default_format
24
+ @default_format ||= Intellihash.configuration.default_format
25
+ end
26
+
27
+ def default_format=(other)
28
+ @default_format = FORMATTER.member?(other) ? other : FORMATTER[:symbol]
29
+ end
30
+
31
+ private
32
+
33
+ FORMATTER = {
34
+ str: :to_s,
35
+ string: :to_s,
36
+ sym: :to_sym,
37
+ symbol: :to_sym,
38
+ any: :any
39
+ }.freeze
40
+
41
+ def method_missing(method_name, *args, **kwargs, &block)
42
+ super unless respond_to?(:is_smart?) && is_smart?
43
+
44
+ if method_name[-1] == '='
45
+ send(:store, method_name[0, method_name.size - 1].send(key_store_as), args.first)
46
+ else
47
+ format_method = key_retrieve_from(kwargs)
48
+ case format_method
49
+ when :any then fetch_where_present(method_name)
50
+ else send(:[], method_name.send(format_method))
51
+ end
52
+ end
53
+ end
54
+
55
+ def respond_to_missing?(*)
56
+ is_smart? ? true : super
57
+ end
58
+
59
+ def key_store_as
60
+ key_format = default_format == :any ? FORMATTER[:symbol] : FORMATTER[default_format]
61
+ key_format || FORMATTER[:symbol]
62
+ end
63
+
64
+ def key_retrieve_from(options)
65
+ from_option = options.fetch(:from) { default_format }
66
+ format(from_option)
67
+ end
68
+
69
+ def format(value)
70
+ FORMATTER.include?(value) ? FORMATTER[value] : FORMATTER[:symbol]
71
+ end
72
+
73
+ def fetch_where_present(method_name)
74
+ return send(:[], method_name.to_sym) if member?(method_name.to_sym)
75
+ return send(:[], method_name.to_s) if member?(method_name.to_s)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intellihash
4
+ VERSION = '0.1.0'
5
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: intellihash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Porter
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-08-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: byebug
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-benchmark
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.18'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.18'
55
+ description: |
56
+ A fast implementation of hashes as objects, benchmarked against OpenStruct.
57
+ It allows chaining hash attributes as method calls instead of standard hash syntax.
58
+ email:
59
+ - tyler.b.porter@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".rspec"
66
+ - ".rubocop.yml"
67
+ - Gemfile
68
+ - Gemfile.lock
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/console
73
+ - bin/setup
74
+ - intellihash.gemspec
75
+ - lib/intellihash.rb
76
+ - lib/intellihash/callbacks.rb
77
+ - lib/intellihash/configuration.rb
78
+ - lib/intellihash/mixins.rb
79
+ - lib/intellihash/version.rb
80
+ homepage: https://github.com/ty-porter/intellihash
81
+ licenses:
82
+ - MIT
83
+ metadata:
84
+ allowed_push_host: https://rubygems.org
85
+ homepage_uri: https://github.com/ty-porter/intellihash
86
+ source_code_uri: https://github.com/ty-porter/intellihash
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 2.6.5
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.0.3
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: A fast implementation of hashes as objects
106
+ test_files: []