collapsium 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 380030070f1838be3f5a7955fcd6e146398653f7
4
+ data.tar.gz: 18862980c22abb357b61c26d867a21d397c4faef
5
+ SHA512:
6
+ metadata.gz: c5be77bf133c4042d193a4f10c4dafbbc2805da3dc4497b29e11802d33a4b34726a2af79642d9f6423f9de14746a46d2a3acc7ff655d1e14d1ba11ca68ba3055
7
+ data.tar.gz: 55fa9036b582b1cb8f708c1d384e006b2bf822253ed213eff8204fbeae2e4a159b578ac6a1330ac380ab75b875f637e8cf4385ed8c57760ce0888e3e10d8d29c
@@ -0,0 +1,34 @@
1
+ ---
2
+ engines:
3
+ bundler-audit:
4
+ enabled: true
5
+ duplication:
6
+ enabled: true
7
+ exclude_fingerprints:
8
+ - d85d6f12c93d79ccd43868b8315d8816
9
+ - a8e2b4ccb258f16eda697c5f98e21823
10
+ - 442a316695836b4f4693fe3786cd3396
11
+ - 1c24bb5da72323796b645814cc006684
12
+ - 4ff1112a73f7be30ecefa7bd90fdbf5a
13
+ config:
14
+ languages:
15
+ - ruby
16
+ - javascript
17
+ - python
18
+ - php
19
+ fixme:
20
+ enabled: true
21
+ rubocop:
22
+ enabled: true
23
+ ratings:
24
+ paths:
25
+ - Gemfile.lock
26
+ - "**.inc"
27
+ - "**.js"
28
+ - "**.jsx"
29
+ - "**.module"
30
+ - "**.php"
31
+ - "**.py"
32
+ - "**.rb"
33
+ exclude_paths:
34
+ - spec/
@@ -0,0 +1,39 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ ## Specific to RubyMotion:
14
+ .dat*
15
+ .repl_history
16
+ build/
17
+
18
+ ## Documentation cache and generated files:
19
+ /.yardoc/
20
+ /_yardoc/
21
+ /doc/
22
+ /rdoc/
23
+
24
+ ## Environment normalization:
25
+ /.bundle/
26
+ /vendor/bundle
27
+ /lib/bundler/man/
28
+
29
+ # for a library or gem, you might want to ignore these files since the code is
30
+ # intended to run in multiple environments; otherwise, check them in:
31
+ # Gemfile.lock
32
+ # .ruby-version
33
+ # .ruby-gemset
34
+
35
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
36
+ .rvmrc
37
+
38
+ # Editor files
39
+ .*.sw*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,75 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.2
3
+
4
+ # Metrics
5
+
6
+ Metrics/LineLength:
7
+ Max: 83
8
+ Details: >-
9
+ Line length of 80 is ideal for readability and compatibility; we'll accept
10
+ an extra 3 for minor edge cases.
11
+
12
+ Metrics/MethodLength:
13
+ Max: 35
14
+
15
+ Metrics/BlockNesting:
16
+ Max: 5
17
+
18
+ Metrics/AbcSize:
19
+ Max: 50
20
+
21
+ Metrics/PerceivedComplexity:
22
+ Max: 15
23
+
24
+ Metrics/CyclomaticComplexity:
25
+ Max: 15
26
+
27
+ Metrics/ClassLength:
28
+ Max: 300
29
+
30
+ Metrics/ModuleLength:
31
+ Max: 300
32
+
33
+ # Style
34
+
35
+ Style/StringLiterals:
36
+ Enabled: false
37
+
38
+ Style/ConditionalAssignment:
39
+ Enabled: false
40
+
41
+ Style/EmptyLinesAroundModuleBody:
42
+ Enabled: false
43
+
44
+ Style/AndOr:
45
+ Enabled: false
46
+
47
+ Style/Not:
48
+ Enabled: false
49
+
50
+ Style/NegatedIf:
51
+ Enabled: false
52
+
53
+ Style/RedundantReturn:
54
+ Enabled: false
55
+
56
+ Style/IfUnlessModifier:
57
+ Enabled: false
58
+
59
+ Style/TrailingCommaInLiteral:
60
+ Enabled: false
61
+
62
+ Style/FirstParameterIndentation:
63
+ Enabled: false
64
+
65
+ Style/TrailingUnderscoreVariable:
66
+ Enabled: false
67
+
68
+ Style/NumericLiterals:
69
+ Enabled: false
70
+
71
+ Style/FileName:
72
+ Enabled: false
73
+
74
+ Style/SpaceAfterNot:
75
+ Enabled: false
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
6
+ addons:
7
+ code_climate:
8
+ repo_token: 56724b4322c0a98f681db40ccfa92d1a9fd4755a18daf82683f95fcaa058499d
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in collapsium.gemspec
4
+ gemspec
5
+
6
+ gem "codeclimate-test-reporter", group: :test, require: nil
@@ -0,0 +1,62 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ collapsium (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.2.0)
10
+ codeclimate-test-reporter (0.5.0)
11
+ simplecov (>= 0.7.1, < 1.0.0)
12
+ diff-lcs (1.2.5)
13
+ docile (1.1.5)
14
+ json (1.8.3)
15
+ parser (2.3.1.0)
16
+ ast (~> 2.2)
17
+ powerpack (0.1.1)
18
+ rainbow (2.1.0)
19
+ rake (11.1.2)
20
+ rspec (3.4.0)
21
+ rspec-core (~> 3.4.0)
22
+ rspec-expectations (~> 3.4.0)
23
+ rspec-mocks (~> 3.4.0)
24
+ rspec-core (3.4.4)
25
+ rspec-support (~> 3.4.0)
26
+ rspec-expectations (3.4.0)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.4.0)
29
+ rspec-mocks (3.4.1)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.4.0)
32
+ rspec-support (3.4.1)
33
+ rubocop (0.40.0)
34
+ parser (>= 2.3.1.0, < 3.0)
35
+ powerpack (~> 0.1)
36
+ rainbow (>= 1.99.1, < 3.0)
37
+ ruby-progressbar (~> 1.7)
38
+ unicode-display_width (~> 1.0, >= 1.0.1)
39
+ ruby-progressbar (1.8.0)
40
+ simplecov (0.11.2)
41
+ docile (~> 1.1.0)
42
+ json (~> 1.8)
43
+ simplecov-html (~> 0.10.0)
44
+ simplecov-html (0.10.0)
45
+ unicode-display_width (1.0.5)
46
+ yard (0.8.7.6)
47
+
48
+ PLATFORMS
49
+ ruby
50
+
51
+ DEPENDENCIES
52
+ bundler (~> 1.12)
53
+ codeclimate-test-reporter
54
+ collapsium!
55
+ rake (~> 11.1)
56
+ rspec (~> 3.4)
57
+ rubocop (~> 0.40)
58
+ simplecov (~> 0.11)
59
+ yard (~> 0.8)
60
+
61
+ BUNDLED WITH
62
+ 1.12.3
data/LICENSE ADDED
@@ -0,0 +1,30 @@
1
+ Copyright (c) Jens Finkhaeuser (http://finkhaeuser.de/) and other collapsium
2
+ contributors. All rights not covered below are reserved.
3
+
4
+ The MIT +no-false-attribs License (MITNFA)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to
8
+ deal in the Software without restriction, including without limitation the
9
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
+ sell copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ Distributions of all or part of the Software intended to be used by the
17
+ recipients as they would use the unmodified Software, containing modifications
18
+ that substantially alter, remove, or disable functionality of the Software,
19
+ outside of the documented configuration mechanisms provided by the Software,
20
+ shall be modified such that the Original Author's bug reporting email addresses
21
+ and urls are either replaced with the contact information of the parties
22
+ responsible for the changes, or removed entirely.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30
+ IN THE SOFTWARE.
@@ -0,0 +1,48 @@
1
+ # collapsium
2
+ *Provides various Hash extensions, and an UberHash class that uses them all.*
3
+
4
+ Ruby's Hash is a pretty nice class, but various extensions are commonly (or not
5
+ so commonly) used to make it even more convenient. The most notable would
6
+ probably be [ActiveSupport::HashWithIndifferentAccess](http://apidock.com/rails/ActiveSupport/HashWithIndifferentAccess).
7
+
8
+ That example, unfortunately, has all the problems of requring the kitchen sink
9
+ that is ActiveSupport...
10
+
11
+ [![Gem Version](https://badge.fury.io/rb/collapsium.svg)](https://badge.fury.io/rb/collapsium)
12
+ [![Build status](https://travis-ci.org/jfinkhaeuser/collapsium.svg?branch=master)](https://travis-ci.org/jfinkhaeuser/collapsium)
13
+ [![Code Climate](https://codeclimate.com/github/jfinkhaeuser/collapsium/badges/gpa.svg)](https://codeclimate.com/github/jfinkhaeuser/collapsium)
14
+ [![Test Coverage](https://codeclimate.com/github/jfinkhaeuser/collapsium/badges/coverage.svg)](https://codeclimate.com/github/jfinkhaeuser/collapsium/coverage)
15
+
16
+ # Functionality
17
+
18
+ - The `IndifferentAccess` module provides support for indifferent access via a
19
+ `#default_proc`:
20
+
21
+ ```ruby
22
+ x = { foo: 42 }
23
+ x.default_proc = ::Collapsium::IndifferentAccess::DEFAULT_PROC
24
+ x['foo'] # => 42
25
+ ```
26
+ - The `RecursiveMerge` module provides a `#recursive_merge` function which merges
27
+ Hashes recursively:
28
+
29
+ ```ruby
30
+ x = { foo: { bar: 42 } }
31
+ x.extend(::Collapsium::RecursiveMerge)
32
+ x.recursive_merge(foo: { baz: 'quux' })
33
+ # => {
34
+ # foo: {
35
+ # bar: 42,
36
+ # baz: 'quux',
37
+ # },
38
+ # }
39
+ ```
40
+ - The `PathedAccess` module provides a pathed access method to nested Hashes:
41
+
42
+ ```ruby
43
+ x = { "foo" => { "bar" => 42 } }
44
+ x.extend(::Collapsium::PathedAccess)
45
+ x["foo.bar"] # => 42
46
+ ```
47
+
48
+ Finally, the `UberHash` class just includes all of the above.
@@ -0,0 +1,25 @@
1
+ # Rubocop
2
+ require 'rubocop/rake_task'
3
+ RuboCop::RakeTask.new(:rubocop)
4
+
5
+ # Rspec
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new(:rspec)
8
+
9
+ # Documentation
10
+ require 'yard'
11
+ YARD::Rake::YardocTask.new do |t|
12
+ t.files = ['lib/**/*.rb']
13
+ t.options = ['-m', 'markdown']
14
+ t.stats_options = ['--list-undoc']
15
+ end
16
+
17
+ # Combined test task
18
+ desc "Test all the things!"
19
+ task :test do
20
+ Rake::Task[:rubocop].invoke
21
+ Rake::Task[:rspec].invoke
22
+ end
23
+
24
+ # Default is the test task
25
+ task default: :test
@@ -0,0 +1,45 @@
1
+ # coding: utf-8
2
+ #
3
+ # collapsium
4
+ # https://github.com/jfinkhaeuser/collapsium
5
+ #
6
+ # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
7
+ # All rights reserved.
8
+ #
9
+
10
+ lib = File.expand_path('../lib', __FILE__)
11
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
12
+ require 'collapsium/version'
13
+
14
+ # rubocop:disable Style/UnneededPercentQ
15
+ # rubocop:disable Style/SpaceAroundOperators
16
+ Gem::Specification.new do |spec|
17
+ spec.name = "collapsium"
18
+ spec.version = Collapsium::VERSION
19
+ spec.authors = ["Jens Finkhaeuser"]
20
+ spec.email = ["jens@finkhaeuser.de"]
21
+ spec.description = %q(
22
+ Provides IndifferentAccess, RecursiveMerge, PathedAccess, etc.
23
+ )
24
+ spec.summary = %q(
25
+ Provides various Hash extensions, and an UberHash class that uses them all.
26
+ )
27
+ spec.homepage = "https://github.com/jfinkhaeuser/collapsium"
28
+ spec.license = "MITNFA"
29
+
30
+ spec.files = `git ls-files -z`.split("\x0")
31
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
32
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
33
+ spec.require_paths = ["lib"]
34
+
35
+ spec.required_ruby_version = '>= 2.0'
36
+
37
+ spec.add_development_dependency "bundler", "~> 1.12"
38
+ spec.add_development_dependency "rubocop", "~> 0.40"
39
+ spec.add_development_dependency "rake", "~> 11.1"
40
+ spec.add_development_dependency "rspec", "~> 3.4"
41
+ spec.add_development_dependency "simplecov", "~> 0.11"
42
+ spec.add_development_dependency "yard", "~> 0.8"
43
+ end
44
+ # rubocop:enable Style/SpaceAroundOperators
45
+ # rubocop:enable Style/UnneededPercentQ
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+ #
3
+ # collapsium
4
+ # https://github.com/jfinkhaeuser/collapsium
5
+ #
6
+ # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
7
+ # All rights reserved.
8
+ #
9
+
10
+ require 'collapsium/version'
11
+
12
+ require 'collapsium/recursive_merge'
13
+ require 'collapsium/indifferent_access'
14
+ require 'collapsium/pathed_access'
15
+
16
+ require 'collapsium/uber_hash'
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ #
3
+ # collapsium
4
+ # https://github.com/jfinkhaeuser/collapsium
5
+ #
6
+ # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
7
+ # All rights reserved.
8
+ #
9
+
10
+ module Collapsium
11
+
12
+ ##
13
+ # Provides indifferent access to string/symbol keys in a Hash. That is,
14
+ # if your hash contains a string key, you can also access it via a symbol
15
+ # and vice versa.
16
+ module IndifferentAccess
17
+
18
+ ##
19
+ # Set your Hash's #default_proc to DEFAULT_PROC, and you've got indifferent
20
+ # access.
21
+ DEFAULT_PROC = proc do |hash, key|
22
+ case key
23
+ when String
24
+ sym = key.to_sym
25
+ hash[sym] if hash.key?(sym)
26
+ when Symbol
27
+ str = key.to_s
28
+ hash[str] if hash.key?(str)
29
+ end
30
+ end.freeze
31
+
32
+ end # module IndifferentAccess
33
+
34
+ end # module Collapsium
@@ -0,0 +1,139 @@
1
+ # coding: utf-8
2
+ #
3
+ # collapsium
4
+ # https://github.com/jfinkhaeuser/collapsium
5
+ #
6
+ # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
7
+ # All rights reserved.
8
+ #
9
+
10
+ module Collapsium
11
+
12
+ ##
13
+ # The PathedAccess module can be used to extend Hash with pathed access
14
+ # on top of regular access, i.e. instead of `h["first"]["second"]` you can
15
+ # write `h["first.second"]`.
16
+ #
17
+ # The main benefit is much simpler code for accessing nested structured.
18
+ # For any given path, PathedAccess will return nil from `[]` if *any* of
19
+ # the path components do not exist.
20
+ #
21
+ # Similarly, intermediate nodes will be created when you write a value
22
+ # for a path.
23
+ module PathedAccess
24
+
25
+ # @return [String] the separator is the character or pattern splitting paths.
26
+ def separator
27
+ @separator ||= DEFAULT_SEPARATOR
28
+ return @separator
29
+ end
30
+
31
+ # @api private
32
+ # Methods redefined to support pathed read access.
33
+ READ_METHODS = [
34
+ :[], :default, :delete, :fetch, :has_key?, :include?, :key?, :member?,
35
+ ].freeze
36
+
37
+ # @api private
38
+ # Methods redefined to support pathed write access.
39
+ WRITE_METHODS = [
40
+ :[]=, :store,
41
+ ].freeze
42
+
43
+ # @api private
44
+ # Default path separator
45
+ DEFAULT_SEPARATOR = '.'.freeze
46
+
47
+ ##
48
+ # @return [RegExp] the pattern to split paths at; based on `separator`
49
+ def split_pattern
50
+ /(?<!\\)#{Regexp.escape(separator)}/
51
+ end
52
+
53
+ (READ_METHODS + WRITE_METHODS).each do |method|
54
+ # Wrap all accessor functions to deal with paths
55
+ define_method(method) do |*args, &block|
56
+ # If there are no arguments, there's nothing to do with paths. Just
57
+ # delegate to the hash.
58
+ if args.empty?
59
+ return super(*args, &block)
60
+ end
61
+
62
+ # With any of the dispatch methods, we know that the first argument has
63
+ # to be a key. We'll try to split it by the path separator.
64
+ components = args[0].to_s.split(split_pattern)
65
+ loop do
66
+ if components.empty? or not components[0].empty?
67
+ break
68
+ end
69
+ components.shift
70
+ end
71
+
72
+ # If there are no components, return self/the root
73
+ if components.empty?
74
+ return self
75
+ end
76
+
77
+ # This is already the leaf-most Hash
78
+ if components.length == 1
79
+ # Weird edge case: if we didn't have to shift anything, then it's
80
+ # possible we inadvertently changed a symbol key into a string key,
81
+ # which could mean looking fails.
82
+ # We can detect that by comparing copy[0] to a symbolized version of
83
+ # components[0].
84
+ copy = args.dup
85
+ if copy[0] != components[0].to_sym
86
+ copy[0] = components[0]
87
+ end
88
+ return super(*copy, &block)
89
+ end
90
+
91
+ # Deal with other paths. The frustrating part here is that for nested
92
+ # hashes, only this outermost one is guaranteed to know anything about
93
+ # path splitting, so we'll have to recurse down to the leaf here.
94
+ #
95
+ # For write methods, we need to create intermediary hashes.
96
+ leaf = recursive_fetch(components, self,
97
+ create: WRITE_METHODS.include?(method))
98
+ if leaf.is_a? Hash
99
+ leaf.default_proc = default_proc
100
+ end
101
+ if leaf.nil?
102
+ leaf = self
103
+ end
104
+
105
+ # If we have a leaf, we want to send the requested method to that
106
+ # leaf.
107
+ copy = args.dup
108
+ copy[0] = components.last
109
+ return leaf.send(method, *copy, &block)
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ ##
116
+ # Given the path components, recursively fetch any but the last key.
117
+ def recursive_fetch(path, data, options = {})
118
+ # For the leaf element, we do nothing because that's where we want to
119
+ # dispatch to.
120
+ if path.length == 1
121
+ return data
122
+ end
123
+
124
+ # Split path into head and tail; for the next iteration, we'll look use only
125
+ # head, and pass tail on recursively.
126
+ head = path[0]
127
+ tail = path.slice(1, path.length)
128
+
129
+ # If we're a write function, then we need to create intermediary objects,
130
+ # i.e. what's at head if nothing is there.
131
+ if options[:create] and data[head].nil?
132
+ data[head] = {}
133
+ end
134
+
135
+ # Ok, recurse.
136
+ return recursive_fetch(tail, data[head], options)
137
+ end
138
+ end # module PathedAccess
139
+ end # module Collapsium
@@ -0,0 +1,57 @@
1
+ # coding: utf-8
2
+ #
3
+ # collapsium
4
+ # https://github.com/jfinkhaeuser/collapsium
5
+ #
6
+ # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
7
+ # All rights reserved.
8
+ #
9
+
10
+ module Collapsium
11
+ ##
12
+ # Provides recursive merge functions for hashes. Used in PathedHash.
13
+ module RecursiveMerge
14
+ ##
15
+ # Recursively merge `:other` into this Hash.
16
+ #
17
+ # This starts by merging the leaf-most Hash entries. Arrays are merged
18
+ # by addition.
19
+ #
20
+ # For everything that's neither Hash or Array, if the `:overwrite`
21
+ # parameter is true, the entry from `:other` is used. Otherwise the entry
22
+ # from `:self` is used.
23
+ #
24
+ # @param other [Hash] the hash to merge into `:self`
25
+ # @param overwrite [Boolean] see method description.
26
+ def recursive_merge!(other, overwrite = true)
27
+ if other.nil?
28
+ return self
29
+ end
30
+
31
+ merger = proc do |_, v1, v2|
32
+ # rubocop:disable Style/GuardClause
33
+ if v1.is_a? Hash and v2.is_a? Hash
34
+ next v1.merge(v2, &merger)
35
+ elsif v1.is_a? Array and v2.is_a? Array
36
+ next v1 + v2
37
+ end
38
+ if overwrite
39
+ next v2
40
+ else
41
+ next v1
42
+ end
43
+ # rubocop:enable Style/GuardClause
44
+ end
45
+ merge!(other, &merger)
46
+ end
47
+
48
+ ##
49
+ # Same as `dup.recursive_merge!`
50
+ # @param (see #recursive_merge!)
51
+ def recursive_merge(other, overwrite = true)
52
+ copy = dup
53
+ copy.extend(RecursiveMerge)
54
+ return copy.recursive_merge!(other, overwrite)
55
+ end
56
+ end # module RecursiveMerge
57
+ end # module Collapsium
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ #
3
+ # collapsium
4
+ # https://github.com/jfinkhaeuser/collapsium
5
+ #
6
+ # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
7
+ # All rights reserved.
8
+ #
9
+
10
+ require 'collapsium/recursive_merge'
11
+ require 'collapsium/indifferent_access'
12
+ require 'collapsium/pathed_access'
13
+
14
+ module Collapsium
15
+
16
+ # A Hash that includes all the different Hash extensions in collapsium
17
+ class UberHash < Hash
18
+ include RecursiveMerge
19
+ include PathedAccess
20
+
21
+ def initialize(*args)
22
+ super
23
+
24
+ # Activate IndifferentAccess
25
+ self.default_proc = IndifferentAccess::DEFAULT_PROC
26
+
27
+ # Extra functionality: allow being initialized by a Hash
28
+ if args.empty? or not args[0].is_a?(Hash)
29
+ return
30
+ end
31
+
32
+ merge!(args[0])
33
+ end
34
+ end
35
+
36
+ end # module Collapsium
@@ -0,0 +1,12 @@
1
+ # coding: utf-8
2
+ #
3
+ # collapsium
4
+ # https://github.com/jfinkhaeuser/collapsium
5
+ #
6
+ # Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
7
+ # All rights reserved.
8
+ #
9
+ module Collapsium
10
+ # The current release version
11
+ VERSION = "0.1.0".freeze
12
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/collapsium/indifferent_access'
3
+
4
+ describe ::Collapsium::IndifferentAccess do
5
+ before :each do
6
+ @tester = {}
7
+ @tester.default_proc = ::Collapsium::IndifferentAccess::DEFAULT_PROC
8
+ end
9
+
10
+ it "allows accessing string keys via symbol" do
11
+ @tester["foo"] = 42
12
+ expect(@tester["foo"]).to eql 42
13
+ expect(@tester[:foo]).to eql 42
14
+ end
15
+
16
+ it "allows accessing symbol keys via strings" do
17
+ @tester[:foo] = 42
18
+ expect(@tester[:foo]).to eql 42
19
+ expect(@tester["foo"]).to eql 42
20
+ end
21
+
22
+ it "still works with other keys" do
23
+ @tester[42] = "foo"
24
+ expect(@tester[42]).to eql "foo"
25
+ end
26
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/collapsium/pathed_access'
3
+
4
+ describe ::Collapsium::PathedAccess do
5
+ before :each do
6
+ @tester = {}
7
+ @tester.extend(::Collapsium::PathedAccess)
8
+ end
9
+
10
+ describe "Hash-like" do
11
+ it "responds to Hash functions" do
12
+ [:invert, :delete, :fetch].each do |meth|
13
+ expect(@tester.respond_to?(meth)).to eql true
14
+ end
15
+ end
16
+
17
+ it "can be used like a Hash" do
18
+ @tester[:foo] = 42
19
+ inverted = @tester.invert
20
+ expect(inverted.empty?).to eql false
21
+ expect(inverted[42]).to eql :foo
22
+ end
23
+
24
+ it "delegates to Hash if it's nothing to do with paths" do
25
+ expect(@tester.default).to be_nil
26
+ end
27
+ end
28
+
29
+ describe "pathed access" do
30
+ it "can recursively read entries via a path" do
31
+ @tester["foo"] = 42
32
+ @tester["bar"] = {
33
+ "baz" => "quux",
34
+ "blah" => [1, 2],
35
+ }
36
+
37
+ expect(@tester["foo"]).to eql 42
38
+ expect(@tester["bar.baz"]).to eql "quux"
39
+ expect(@tester["bar.blah"]).to eql [1, 2]
40
+
41
+ expect(@tester["nope"]).to eql nil
42
+ expect(@tester["bar.nope"]).to eql nil
43
+ end
44
+
45
+ it "behaves consistently if in a path the first node cannot be found" do
46
+ @tester["foo"] = 42
47
+
48
+ expect(@tester["nope.bar"]).to eql nil
49
+ end
50
+
51
+ it "treats a single separator as the root" do
52
+ @tester["foo"] = 42
53
+
54
+ expect(@tester[@tester.separator]["foo"]).to eql 42
55
+ end
56
+
57
+ it "treats an empty path as the root" do
58
+ @tester["foo"] = 42
59
+
60
+ expect(@tester[""]["foo"]).to eql 42
61
+ end
62
+
63
+ it "can recursively write entries via a path" do
64
+ @tester["foo.bar"] = 42
65
+ expect(@tester["foo.bar"]).to eql 42
66
+ end
67
+
68
+ it "understands absolute paths (starting with separator)" do
69
+ @tester["foo"] = 42
70
+ @tester["bar"] = {
71
+ "baz" => "quux",
72
+ "blah" => [1, 2],
73
+ }
74
+
75
+ expect(@tester["bar.baz"]).to eql "quux"
76
+ expect(@tester[".bar.baz"]).to eql "quux"
77
+ end
78
+ end
79
+
80
+ describe "with indifferent access" do
81
+ before do
82
+ require_relative '../lib/collapsium/indifferent_access'
83
+ end
84
+
85
+ it "can write with indifferent access without overwriting" do
86
+ @tester[:foo] = {
87
+ bar: 42,
88
+ baz: 'quux',
89
+ }
90
+ @tester.default_proc = ::Collapsium::IndifferentAccess::DEFAULT_PROC
91
+
92
+ expect(@tester['foo.bar']).to eql 42
93
+ expect(@tester['foo.baz']).to eql 'quux'
94
+
95
+ @tester['foo.bar'] = 123
96
+ expect(@tester['foo.bar']).to eql 123
97
+ expect(@tester['foo.baz']).to eql 'quux'
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/collapsium/recursive_merge'
3
+
4
+ describe ::Collapsium::RecursiveMerge do
5
+ before :each do
6
+ @tester = {}
7
+ @tester.extend(::Collapsium::RecursiveMerge)
8
+ end
9
+
10
+ it "handles a nil parameter well" do
11
+ x = @tester.recursive_merge(nil)
12
+
13
+ expect(x.is_a?(Hash)).to be_truthy
14
+ expect(x).to be_empty
15
+ end
16
+
17
+ it "merges simple values by overwriting by default" do
18
+ @tester[:foo] = 'old'
19
+ x = @tester.recursive_merge(foo: 'new')
20
+
21
+ expect(x[:foo]).to eql 'new'
22
+ end
23
+
24
+ it "merges simple values by using the old value if requested" do
25
+ @tester[:foo] = 'old'
26
+ x = @tester.recursive_merge({ foo: 'new' }, false)
27
+
28
+ expect(x[:foo]).to eql 'old'
29
+ end
30
+
31
+ it "merges arrays by concatenation" do
32
+ @tester[:foo] = ['old']
33
+ x = @tester.recursive_merge(foo: ['new'])
34
+
35
+ expect(x[:foo].length).to eql 2
36
+ expect(x[:foo][0]).to eql 'old'
37
+ expect(x[:foo][1]).to eql 'new'
38
+ end
39
+
40
+ it "merges objects by recursing" do
41
+ @tester[:foo] = {
42
+ bar: 42,
43
+ baz: ['old'],
44
+ quux: {
45
+ something: 42,
46
+ }
47
+ }
48
+ @tester[:bar] = [1]
49
+
50
+ to_merge = {
51
+ foo: {
52
+ bar: 123, # should overwrite
53
+ baz: ['new'], # should concatenate
54
+ quux: { # should merge
55
+ another: 123,
56
+ },
57
+ },
58
+ bar: [2],
59
+ }
60
+
61
+ x = @tester.recursive_merge(to_merge)
62
+
63
+ expect(x[:foo][:bar]).to eql 123
64
+ expect(x[:foo][:baz].length).to eql 2
65
+ expect(x[:foo][:quux][:something]).to eql 42
66
+ expect(x[:foo][:quux][:another]).to eql 123
67
+
68
+ expect(x[:bar].length).to eql 2
69
+ end
70
+ end
@@ -0,0 +1,9 @@
1
+ # Only start CodeClimate from travis
2
+ if ENV['CODECLIMATE_REPO_TOKEN']
3
+ require 'codeclimate-test-reporter'
4
+ CodeClimate::TestReporter.start
5
+ end
6
+
7
+ # Always start SimpleCov
8
+ require 'simplecov'
9
+ SimpleCov.start
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/collapsium/uber_hash'
3
+
4
+ describe Collapsium::UberHash do
5
+ it "has recursive_merge support" do
6
+ x = ::Collapsium::UberHash.new(foo: [1])
7
+
8
+ # Interface expecations
9
+ expect(x.respond_to?(:recursive_merge)).to be_truthy
10
+ expect(x.respond_to?(:recursive_merge!)).to be_truthy
11
+
12
+ # Behaviour expectations
13
+ x.recursive_merge!(foo: [2])
14
+ expect(x[:foo].length).to eql 2
15
+ end
16
+
17
+ it "has pathed access" do
18
+ x = ::Collapsium::UberHash.new(
19
+ "foo" => {
20
+ "bar" => 42,
21
+ }
22
+ )
23
+
24
+ # Interface expecations
25
+ expect(x.respond_to?(:separator)).to be_truthy
26
+ expect(x.respond_to?(:split_pattern)).to be_truthy
27
+
28
+ # Behaviour expectations
29
+ expect(x["foo.bar"]).to eql 42
30
+ end
31
+
32
+ it "has indifferent access" do
33
+ x = ::Collapsium::UberHash.new(foo: 42)
34
+ expect(x['foo']).to eql 42
35
+
36
+ x = ::Collapsium::UberHash.new('foo' => 42)
37
+ expect(x[:foo]).to eql 42
38
+ end
39
+
40
+ it "can be initialized without arguments" do
41
+ x = ::Collapsium::UberHash.new
42
+ expect(x.empty?).to be_truthy
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: collapsium
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jens Finkhaeuser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.40'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.40'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '11.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '11.1'
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.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.11'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.8'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.8'
97
+ description: "\n Provides IndifferentAccess, RecursiveMerge, PathedAccess, etc.\n
98
+ \ "
99
+ email:
100
+ - jens@finkhaeuser.de
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".codeclimate.yml"
106
+ - ".gitignore"
107
+ - ".rspec"
108
+ - ".rubocop.yml"
109
+ - ".travis.yml"
110
+ - Gemfile
111
+ - Gemfile.lock
112
+ - LICENSE
113
+ - README.md
114
+ - Rakefile
115
+ - collapsium.gemspec
116
+ - lib/collapsium.rb
117
+ - lib/collapsium/indifferent_access.rb
118
+ - lib/collapsium/pathed_access.rb
119
+ - lib/collapsium/recursive_merge.rb
120
+ - lib/collapsium/uber_hash.rb
121
+ - lib/collapsium/version.rb
122
+ - spec/indifferent_access_spec.rb
123
+ - spec/pathed_access_spec.rb
124
+ - spec/recursive_merge_spec.rb
125
+ - spec/spec_helper.rb
126
+ - spec/uber_hash_spec.rb
127
+ homepage: https://github.com/jfinkhaeuser/collapsium
128
+ licenses:
129
+ - MITNFA
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '2.0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.4.5.1
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Provides various Hash extensions, and an UberHash class that uses them all.
151
+ test_files:
152
+ - spec/indifferent_access_spec.rb
153
+ - spec/pathed_access_spec.rb
154
+ - spec/recursive_merge_spec.rb
155
+ - spec/spec_helper.rb
156
+ - spec/uber_hash_spec.rb
157
+ has_rdoc: