collapsium 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: