meander 0.1.3 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5a3a8e4229801dbfdbe059575217825508f53cd9
4
- data.tar.gz: 0e3cec51b79e748742755b4d1d64dfefeb9c8653
2
+ SHA256:
3
+ metadata.gz: 4e6b293c17ad768d3896dab4b0efe4a74d2dfd55558debc8126c15ad9be3bcb3
4
+ data.tar.gz: 0f5a82ffc23700aef19c1a4324fba5f2d75d5d2dcc553f70da8150a463b87977
5
5
  SHA512:
6
- metadata.gz: 94e34836c0816f24a00ab83a0c70c89733a34beb5b6036f402a4341e26565c80e49835d9af912b981edebdc731f86de56e90ce8d94ae450bbdb92d403c82f9eb
7
- data.tar.gz: e80f1d6cb38feaa90d2575b1d993727020b11543b764cd0b35a3c5f9c8cfd2855ec81ac7b6e665b8ac445bec96e3ac09983a1464c779caa026074a12feac65e8
6
+ metadata.gz: 398a48194ae2511f88ca7567d2d19f07759cb6e5cffec76c53f7bc5e8678ab0048dba3f16824671b26b74102aaa806d55af8eddee7a1fed4fe3f3fc587a4ac1f
7
+ data.tar.gz: fad6c4adfe5b08f1cdc4a51506b1e69e402758653ab2e7096a0b5ff10ea3f09447f2f148c76fac5c3d02f1f11148cc4b0c304a13fff4a16352176c5c099a54df
data/.gitignore CHANGED
@@ -12,3 +12,4 @@
12
12
  .rspec_status
13
13
  .DS_Store
14
14
  .byebug_history
15
+ coverage
@@ -1,11 +1,15 @@
1
- require: rubocop-rspec
1
+ require:
2
+ - rubocop-rspec
3
+ - rubocop-performance
2
4
  AllCops:
3
5
  RSpec:
4
6
  Patterns:
5
7
  - 'spec/meander/.+.rb$'
6
8
  - 'spec/shared/.+.rb$'
7
9
  Metrics/MethodLength:
8
- Max: 15
10
+ Max: 20
11
+ Metrics/ClassLength:
12
+ Max: 110
9
13
  Metrics/BlockLength:
10
14
  Exclude:
11
15
  - 'spec/**/*.rb'
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.4.1
4
+ - 2.7.1
5
5
  before_install: gem install bundler -v 1.14.6
@@ -1,7 +1,9 @@
1
- require 'meander/version'
2
- require 'meander/common_methods'
3
- require 'meander/plain'
4
- require 'meander/mutable'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'meander/version'
4
+ require_relative 'meander/common_methods'
5
+ require_relative 'meander/plain'
6
+ require_relative 'meander/mutable'
5
7
 
6
8
  module Meander # :nodoc:
7
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Meander
2
4
  module CommonMethods # :nodoc:
3
5
  module ClassMethods # :nodoc:
@@ -8,10 +10,8 @@ module Meander
8
10
 
9
11
  def self.included(base)
10
12
  base.extend ClassMethods
11
- base.instance_eval do
12
- def cover_class=(val)
13
- @cover_class = val
14
- end
13
+ class << base
14
+ attr_writer :cover_class
15
15
 
16
16
  def cover_class
17
17
  @cover_class ||= self
@@ -21,22 +21,8 @@ module Meander
21
21
 
22
22
  private
23
23
 
24
- def define_getter(method)
25
- define_singleton_method method do |&b|
26
- if key?(method)
27
- b.call(self[method]) if block_given?
28
- self[method]
29
- else
30
- instance_eval(method) do |name|
31
- undef_method name
32
- end
33
- send method, &block
34
- end
35
- end
36
- end
37
-
38
- def new_key_method?(method)
39
- method =~ /^([[:word:]]+)\=$/
24
+ def new_key_method?(method_name)
25
+ /=$/.match?(method_name)
40
26
  end
41
27
  end
42
28
  end
@@ -1,7 +1,8 @@
1
- require 'meander/plain'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'plain'
2
4
  require 'delegate'
3
5
  require 'forwardable'
4
-
5
6
  module Meander
6
7
  ##
7
8
  # This class is a mutable version of Meander::Plain
@@ -29,7 +30,7 @@ module Meander
29
30
  # a[:a][:b][:c] = 3
30
31
  # m.a.b.c # => 3
31
32
  # ==== Notice
32
- # Meander::Mutable support only one up to date object reference
33
+ # Meander::Mutable support multiple object references
33
34
  # a = {a: 1}
34
35
  # m = Meander::Mutable.new(a)
35
36
  # b = {b: 2}
@@ -37,8 +38,16 @@ module Meander
37
38
  # a[:a] = 3
38
39
  # b[:b] = 4
39
40
  # m.a # => 3 # Value is up to date
40
- # m.b # => 2 # Attention! Value remains unchanged
41
- class Mutable < Delegator
41
+ # m.b # => 4 # This value is also up to date
42
+ # You can also initialize Meander::Mutable with multiple nested hashes
43
+ # a = {a: 1}
44
+ # b = {b: 2}
45
+ # m = Meander::Mutable.new(a, b)
46
+ # a[:a] = 3
47
+ # b[:b] = 4
48
+ # m.a # => 3 # Value is up to date
49
+ # m.b # => 4 # This value is also up to date
50
+ class Mutable < ::Thor::CoreExt::HashWithIndifferentAccess
42
51
  include CommonMethods
43
52
  include Enumerable
44
53
 
@@ -49,46 +58,42 @@ module Meander
49
58
  end
50
59
  end
51
60
 
52
- def initialize(obj = {})
53
- super
54
- @delegate_sd_obj = obj
61
+ def initialize(required = {}, *args)
62
+ __setobj__(required, *args)
55
63
  @own_keys = self.class.own_keys_cover_class.new
56
64
  end
57
65
 
58
66
  def __getobj__
59
- @delegate_sd_obj
67
+ @delegate
68
+ end
69
+
70
+ def __setobj__(*args)
71
+ @delegate = []
72
+ @delegate += args
73
+ @delegate
60
74
  end
61
75
 
62
- def __setobj__(obj)
63
- @delegate_sd_obj = obj
76
+ def merge!(hsh)
77
+ @delegate ||= []
78
+ @delegate.unshift hsh
64
79
  end
65
80
 
66
81
  def key?(key)
67
- @own_keys.key?(key) ||
68
- begin
69
- obj = __getobj__
70
- obj.key?(key.to_s) || obj.key?(key.to_sym)
71
- end
82
+ @own_keys.key?(key) || delegated_key?(key)
72
83
  end
73
84
 
74
85
  def dup
75
- self.class.new(self)
86
+ self.class.new(*__getobj__)
76
87
  end
77
88
 
78
- def each &block
79
- if block_given?
80
- __getobj__.each{ |i| yield i }
81
- @own_keys.each{ |i| yield i }
82
- else
83
- enum_for :each
84
- end
89
+ def each(*args, &block)
90
+ return enum_for(:each) unless block_given?
91
+
92
+ deep_call.each { |i| i.each(*args, &block) }
85
93
  end
86
94
 
87
95
  def keys
88
- origin = __getobj__
89
- own = @own_keys
90
- [(origin && origin.keys), (own && own.keys)].flatten
91
- .compact.map(&:to_s).uniq
96
+ map { |k, _| convert_key(k) }
92
97
  end
93
98
 
94
99
  def [](key)
@@ -96,7 +101,7 @@ module Meander
96
101
  if @own_keys.key? key
97
102
  val = @own_keys[key]
98
103
  else
99
- val = get_delegated_value key
104
+ val = get_delegated_value(key)
100
105
  if val.is_a?(Hash)
101
106
  val = self.class.new(val)
102
107
  self[key] = val
@@ -105,39 +110,67 @@ module Meander
105
110
  val
106
111
  end
107
112
 
108
- def respond_to_missing?(method, include_private = false)
109
- @own_keys.respond_to?(method) || delegated_key?(method.to_s) || super
113
+ def respond_to_missing?(method_name, include_private = false)
114
+ @own_keys.respond_to?(method_name) || delegated_key?(method_name) || super
110
115
  end
111
116
 
112
- def method_missing(method, *args, &block)
113
- if @own_keys.respond_to?(method) || block_given?
114
- @own_keys.send method, *args, &block
115
- elsif delegated_key? method
116
- define_getter method
117
- send method, *args, &block
117
+ def method_missing(method_name, *args, &block)
118
+ if @own_keys.respond_to?(method_name) || block_given?
119
+ @own_keys.send method_name, *args, &block
120
+ elsif delegated_key?(method_name)
121
+ self[method_name]
118
122
  else
119
123
  super
120
124
  end
121
125
  end
122
126
 
127
+ def kind_of?(klass)
128
+ (self.class.cover_class == klass) || __getobj__.all?(klass)
129
+ end
130
+
131
+ alias is_a? kind_of?
132
+
123
133
  extend Forwardable
124
- def_delegators :@own_keys, :[]=, :is_a?
134
+ def_delegators :@own_keys, :[]=
125
135
 
126
136
  private
127
137
 
138
+ def deep_call(origin: self)
139
+ stack = []
140
+ if origin.is_a?(Array)
141
+ stack.unshift(*origin)
142
+ origin = stack.pop
143
+ end
144
+ Enumerator.new do |yielder|
145
+ while origin
146
+ own_keys = origin.instance_variable_get(:@own_keys)
147
+ if own_keys
148
+ yielder.yield own_keys
149
+ stack.unshift(*origin.__getobj__)
150
+ origin = stack.pop
151
+ else
152
+ yielder.yield origin
153
+ origin = stack.empty? ? nil : stack.pop
154
+ end
155
+ end
156
+ self
157
+ end
158
+ end
159
+
128
160
  def delegated_key?(key)
129
- __getobj__.keys.map(&:to_s).include? key.to_s
161
+ key = convert_key(key)
162
+ deep_call(origin: __getobj__).any? do |i|
163
+ i.keys.any? { |k| convert_key(k) == key }
164
+ end
130
165
  end
131
166
 
132
167
  def get_delegated_value(key)
133
- delegated = __getobj__
134
- if key.respond_to?(:to_s) && delegated.key?(key.to_s)
135
- delegated[key.to_s]
136
- elsif key.respond_to?(:to_sym) && delegated.key?(key.to_sym)
137
- delegated[key.to_sym]
138
- else
139
- delegated[key]
168
+ value = nil
169
+ key = convert_key(key)
170
+ deep_call(origin: __getobj__).detect do |i|
171
+ i.keys.any? { |k| convert_key(k) == key && value = i[k] }
140
172
  end
173
+ value
141
174
  end
142
175
  end
143
176
  end
@@ -1,11 +1,13 @@
1
- require 'thor/core_ext/hash_with_indifferent_access'
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'thor/core_ext/hash_with_indifferent_access'
4
+ require_relative 'common_methods'
3
5
  module Meander
4
6
  ##
5
7
  # == Brief
6
8
  # This class is a sugar filled version of HashWithIndifferentAccess
7
9
  #
8
- # It supports key-based method calling and value block evaluation
10
+ # It supports key-based method_name calling and value block evaluation
9
11
  # == Configuration
10
12
  # You can set class that will be applied to newly assigned values
11
13
  # require 'active_support/core_ext/hash'
@@ -17,7 +19,7 @@ module Meander
17
19
  # m[:a] = {}
18
20
  # m[:a].class # => ActiveSupport::HashWithIndifferentAccess
19
21
  # == Usage
20
- # === Key based method evaluation
22
+ # === Key based method_name evaluation
21
23
  # m = Meander::Plain.new({:a => 1})
22
24
  # m.a # => 1
23
25
  # === New value assignment
@@ -46,26 +48,25 @@ module Meander
46
48
  end
47
49
  end
48
50
 
49
- def method_missing(method, *args, &block)
50
- method = method.to_s
51
- if new_key_method? method
52
- key_name = method.gsub(/\=$/, '')
51
+ def method_missing(method_name, *args, &block)
52
+ method_name = method_name.to_s
53
+ if new_key_method? method_name
54
+ key_name = method_name.gsub(/=$/, '')
53
55
  send :[]=, key_name, *args, &block
54
56
  elsif block_given?
55
- val = self[method]
57
+ val = self[method_name]
56
58
  val = {} unless self.class.hash_or_cover_class?(val)
57
- send :[]=, method, val
58
- yield(self[method])
59
- elsif key?(method)
60
- define_getter(method)
61
- send method, &block
59
+ send :[]=, method_name, val
60
+ yield(self[method_name])
61
+ elsif key?(method_name)
62
+ self[method_name]
62
63
  else
63
64
  super
64
65
  end
65
66
  end
66
67
 
67
- def respond_to_missing?(method, include_private = false)
68
- new_key_method?(method) || key?(method) || super
68
+ def respond_to_missing?(method_name, include_private = false)
69
+ new_key_method?(method_name) || key?(method_name) || super
69
70
  end
70
71
  end
71
72
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Meander
2
- VERSION = '0.1.3'.freeze
4
+ VERSION = '0.2'
3
5
  end
@@ -31,12 +31,14 @@ Gem::Specification.new do |spec|
31
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ['lib']
33
33
 
34
- spec.add_runtime_dependency 'thor', '~> 0.19.4'
34
+ spec.add_runtime_dependency 'thor'
35
35
 
36
- spec.add_development_dependency 'bundler', '~> 1.14'
37
- spec.add_development_dependency 'rake', '~> 10.0'
36
+ spec.add_development_dependency 'bundler'
37
+ spec.add_development_dependency "rake", ">= 12.3.3"
38
38
  spec.add_development_dependency 'rspec', '~> 3.0'
39
39
  spec.add_development_dependency 'rubocop'
40
40
  spec.add_development_dependency 'rubocop-rspec'
41
+ spec.add_development_dependency 'rubocop-performance'
41
42
  spec.add_development_dependency 'hashie'
43
+ spec.add_development_dependency 'simplecov'
42
44
  end
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meander
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: '0.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kostrov Alexander
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-16 00:00:00.000000000 Z
11
+ date: 2020-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.19.4
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.19.4
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.14'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.14'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: 12.3.3
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: 12.3.3
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-performance
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: hashie
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +122,20 @@ dependencies:
108
122
  - - ">="
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
111
139
  description: Hashie clone with a bit more sugar
112
140
  email:
113
141
  - bombazook@gmail.com
@@ -136,7 +164,7 @@ licenses:
136
164
  - MIT
137
165
  metadata:
138
166
  allowed_push_host: https://rubygems.org
139
- post_install_message:
167
+ post_install_message:
140
168
  rdoc_options: []
141
169
  require_paths:
142
170
  - lib
@@ -151,9 +179,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
179
  - !ruby/object:Gem::Version
152
180
  version: '0'
153
181
  requirements: []
154
- rubyforge_project:
155
- rubygems_version: 2.6.11
156
- signing_key:
182
+ rubygems_version: 3.1.4
183
+ signing_key:
157
184
  specification_version: 4
158
185
  summary: Just another ruby Hash extension
159
186
  test_files: []