deeply_enumerable 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1c7178af253c0b681770ebf17fd86e9f5d8772f6
4
+ data.tar.gz: 8d11d2165f7375a08cb708be8d74df017f578030
5
+ SHA512:
6
+ metadata.gz: 1312ce00f3013e42096bdf5f3d6c02dce1a85388be8eed0357f5fa1cff32e170eb5f9aea8ba16379f07f944587671e33aac81e7360af109858ab35bafb410af5
7
+ data.tar.gz: 0226e8013d0cb9a753f39827b00588502e215a08c4efdb57b089e570c4fee43892d47866e3d6f75dd1fcc919473997a9f6810a6f7db1c25776748c0d8c2a388c
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 chaunce
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.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # DeeplyEnumerable
2
+ Extend Enumerable objects with recursive methods
3
+
4
+ ## Usage
5
+ Provides the following methods
6
+ ```ruby
7
+ $ DeeplyEnumerable::Hash#reverse_deep_merge(DeeplyEnumerable::Hash)
8
+ $ DeeplyEnumerable::Hash#reverse_deep_merge!(DeeplyEnumerable::Hash)
9
+ $ DeeplyEnumerable::Hash#deep_compact
10
+ $ DeeplyEnumerable::Hash#deep_compact!
11
+
12
+ $ DeeplyEnumerable::Array#deep_compact
13
+ $ DeeplyEnumerable::Array#deep_compact!
14
+ ```
15
+
16
+ Nested `Enumerable` objects will be converted into `DeeplyEnumerable` type objects during merge or compact operations to allow recursive method calls
17
+
18
+ Class methods may be used for base ruby enumerable objects, such as `Hash` or `Array` objects
19
+ ```ruby
20
+ $ DeeplyEnumerable::Hash.deep_compact(Hash)
21
+ $ DeeplyEnumerable::Array.deep_compact(Array)
22
+ ```
23
+
24
+ These methos will retrun a `DeeplyEnumerable` type object matching the object passed, e.g: `Array` will return a `DeeplyEnumerable::Array`
25
+
26
+ You may also extend base classes if you `require: 'base_extensions'` as described in *Installation*
27
+ ```ruby
28
+ $ Hash#reverse_deep_merge(DeeplyEnumerable::Hash)
29
+ $ Hash#reverse_deep_merge!(DeeplyEnumerable::Hash)
30
+ $ Hash#deep_compact
31
+ $ Hash#deep_compact!
32
+
33
+ $ Array#deep_compact
34
+ $ Array#deep_compact!
35
+ ```
36
+
37
+ ## Installation
38
+ Add this line to your application's Gemfile:
39
+ ```ruby
40
+ gem 'deeply_enumerable'
41
+ ```
42
+
43
+ or this line to extend the base `Enumerable` classes:
44
+ ```ruby
45
+ gem 'deeply_enumerable', require: 'base_extensions'
46
+ ```
47
+
48
+ And then execute:
49
+ ```bash
50
+ $ bundle
51
+ ```
52
+
53
+ Or install it yourself as:
54
+ ```bash
55
+ $ gem install deeply_enumerable
56
+ ```
57
+
58
+ ## License
59
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'DeeplyEnumerable'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+
33
+ task default: :test
@@ -0,0 +1,4 @@
1
+ require 'deeply_enumerable'
2
+
3
+ Hash.send(:include, DeeplyEnumerable::HashExtension)
4
+ Array.send(:include, DeeplyEnumerable::ArrayExtension)
@@ -0,0 +1,40 @@
1
+ require_relative 'enumerable'
2
+
3
+ module DeeplyEnumerable
4
+ module ArrayExtension
5
+ def self.included klass
6
+ klass.class_eval do
7
+ include DeeplyEnumerable::Enumerable
8
+ end
9
+ end
10
+
11
+ def deep_compact!(remove_emptied_elements = true, remove_empty_elements = remove_emptied_elements)
12
+ each.with_index do |value, index|
13
+ value = rebuild(value) unless value.respond_to?(:reverse_deep_merge)
14
+ compact_method = %i[deep_compact! deep_compact compact! compact].detect{ |m| value.respond_to?(m) }
15
+ next unless compact_method
16
+
17
+ original_empty = value.respond_to?(:empty?) ? value.empty? : value.respond_to?(:none?) ? value.none? : false
18
+ compact_value = value.send(*[compact_method].concat(value.method(compact_method).parameters.collect { |_,param| binding.local_variable_get(param) } ).compact) || value
19
+ compact_empty = compact_value.respond_to?(:empty?) ? compact_value.empty? : compact_value.respond_to?(:none?) ? compact_value.none? : false
20
+
21
+ if (original_empty && remove_empty_elements) || (!original_empty && compact_empty && remove_emptied_elements)
22
+ self.delete_at(index)
23
+ else
24
+ self[index] = compact_value
25
+ end
26
+ end
27
+ compact!
28
+
29
+ self
30
+ end
31
+
32
+ def deep_compact(remove_emptied_elements = true, remove_empty_elements = remove_emptied_elements)
33
+ dup.deep_compact!(remove_emptied_elements, remove_empty_elements)
34
+ end
35
+ end
36
+
37
+ class Array < ::Array
38
+ include DeeplyEnumerable::ArrayExtension
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module DeeplyEnumerable
2
+ module Enumerable
3
+ def self.included(klass)
4
+ klass.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def rebuild(object)
9
+ deeply_enumerable_class_name = DeeplyEnumerable.constants(false).detect do |const|
10
+ deeply_enumerable_const = DeeplyEnumerable.const_get(const)
11
+ deeply_enumerable_const.respond_to?(:superclass) ? !!object.is_a?(deeply_enumerable_const.superclass) : false
12
+ end
13
+
14
+ return object if deeply_enumerable_class_name.nil?
15
+
16
+ deeply_enumerable_class = DeeplyEnumerable.const_get(deeply_enumerable_class_name)
17
+ deeply_enumerable_class.respond_to?(:deep_rebuild) ? deeply_enumerable_class.deep_rebuild(object) : object
18
+ end
19
+
20
+ def deep_rebuild(object)
21
+ check_object_class(object)
22
+ new.tap { |deeply_enumerable_object| object.each { |value| deeply_enumerable_object.push(rebuild(value)) } }
23
+ end
24
+
25
+ def deep_compact(object, remove_emptied_elements = true, remove_empty_elements = remove_emptied_elements)
26
+ check_object_class(object)
27
+ deep_rebuild(object).deep_compact(remove_emptied_elements, remove_empty_elements)
28
+ end
29
+
30
+ private
31
+
32
+ def check_object_class(object)
33
+ raise TypeError, "object must be a #{superclass.name}" unless object.kind_of?(superclass)
34
+ end
35
+ end
36
+
37
+ def rebuild(object)
38
+ self.class.rebuild(object)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,72 @@
1
+ require_relative 'enumerable'
2
+
3
+ module DeeplyEnumerable
4
+ module HashExtension
5
+ def self.included klass
6
+ klass.class_eval do
7
+ include DeeplyEnumerable::Enumerable
8
+ end
9
+ end
10
+
11
+ def reverse_deep_merge!(other_hash)
12
+ other_hash.each_pair do |current_key, other_value|
13
+ this_value = self[current_key]
14
+
15
+ self[current_key] = if this_value.is_a?(::Hash) && other_value.is_a?(::Hash)
16
+ this_value = ebuild(this_value) unless this_value.respond_to?(:reverse_deep_merge)
17
+ this_value.reverse_deep_merge(other_value)
18
+ else
19
+ key?(current_key) ? this_value : other_value
20
+ end
21
+ end
22
+
23
+ self
24
+ end
25
+ alias_method :deep_reverse_merge!, :reverse_deep_merge!
26
+
27
+ def reverse_deep_merge(other_hash)
28
+ dup.reverse_deep_merge!(other_hash)
29
+ end
30
+ alias_method :deep_reverse_merge, :reverse_deep_merge
31
+
32
+ def deep_compact!(remove_emptied_elements = true, remove_empty_elements = remove_emptied_elements)
33
+ each do |key, value|
34
+ value = rebuild(value) unless value.respond_to?(:reverse_deep_merge)
35
+ compact_method = %i[deep_compact! deep_compact compact! compact].detect{ |m| value.respond_to?(m) }
36
+ next unless compact_method
37
+
38
+ original_empty = value.respond_to?(:empty?) ? value.empty? : value.respond_to?(:none?) ? value.none? : false
39
+ compact_value = value.send(*[compact_method].concat(value.method(compact_method).parameters.collect { |_,param| binding.local_variable_get(param) } ).compact) || value
40
+ compact_empty = compact_value.respond_to?(:empty?) ? compact_value.empty? : compact_value.respond_to?(:none?) ? compact_value.none? : false
41
+
42
+ self[key] = (original_empty && remove_empty_elements) || (!original_empty && compact_empty && remove_emptied_elements) ? nil : compact_value
43
+ end
44
+ compact!
45
+
46
+ self
47
+ end
48
+
49
+ def deep_compact(remove_emptied_elements = true, remove_empty_elements = remove_emptied_elements)
50
+ dup.deep_compact!(remove_emptied_elements, remove_empty_elements)
51
+ end
52
+ end
53
+
54
+ class Hash < ::Hash
55
+ include DeeplyEnumerable::HashExtension
56
+
57
+ class << self
58
+ def deep_rebuild(object)
59
+ check_object_class(object)
60
+ new.tap { |deeply_enumerable_object| object.each { |key, value| deeply_enumerable_object[key] = rebuild(value) } }
61
+ end
62
+
63
+ def reverse_deep_merge(object)
64
+ check_object_class(object)
65
+ deep_rebuild(object).reverse_deep_merge
66
+ end
67
+ alias_method :deep_reverse_merge, :reverse_deep_merge
68
+ end
69
+ end
70
+ end
71
+
72
+
@@ -0,0 +1,3 @@
1
+ module DeeplyEnumerable
2
+ VERSION = '0.9.0'
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'deeply_enumerable/array'
2
+ require 'deeply_enumerable/hash'
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deeply_enumerable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - chaunce
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-10-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: recusrive support for enumerable operations
28
+ email:
29
+ - chaunce.slc@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - MIT-LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - lib/base_extensions.rb
38
+ - lib/deeply_enumerable.rb
39
+ - lib/deeply_enumerable/array.rb
40
+ - lib/deeply_enumerable/enumerable.rb
41
+ - lib/deeply_enumerable/hash.rb
42
+ - lib/deeply_enumerable/version.rb
43
+ homepage: https://github.com/chaunce/deeply_enumerable
44
+ licenses:
45
+ - MIT
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 2.6.14
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: recusrive support for enumerable operations
67
+ test_files: []