gooddata 1.3.0-java → 1.3.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +2 -0
  3. data/.document +0 -0
  4. data/.yardopts +0 -0
  5. data/CHANGELOG.md +48 -0
  6. data/CLI.md +0 -0
  7. data/CONTRIBUTING.md +19 -12
  8. data/Dockerfile +37 -0
  9. data/Guardfile +0 -0
  10. data/README.md +1 -1
  11. data/Rakefile +17 -1
  12. data/TODO.md +0 -0
  13. data/bin/run_brick.rb +31 -0
  14. data/dependency_decisions.yml +0 -0
  15. data/gooddata.gemspec +1 -0
  16. data/lib/gooddata/bricks/hello_world_brick.rb +21 -0
  17. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +12 -0
  18. data/lib/gooddata/bricks/middleware/logger_middleware.rb +12 -0
  19. data/lib/gooddata/bricks/pipeline.rb +12 -0
  20. data/lib/gooddata/exceptions/filter_maqlization.rb +0 -6
  21. data/lib/gooddata/extensions/class.rb +4 -0
  22. data/lib/gooddata/extensions/enumerable.rb +0 -3
  23. data/lib/gooddata/extensions/extensions.rb +0 -3
  24. data/lib/gooddata/extensions/false.rb +8 -16
  25. data/lib/gooddata/extensions/hash.rb +10 -41
  26. data/lib/gooddata/extensions/integer.rb +9 -3
  27. data/lib/gooddata/extensions/nil.rb +5 -13
  28. data/lib/gooddata/extensions/object.rb +0 -11
  29. data/lib/gooddata/extensions/string.rb +11 -5
  30. data/lib/gooddata/extensions/true.rb +8 -16
  31. data/lib/gooddata/helpers/global_helpers.rb +12 -0
  32. data/lib/gooddata/helpers/global_helpers_params.rb +5 -3
  33. data/lib/gooddata/lcm/actions/apply_custom_maql.rb +6 -0
  34. data/lib/gooddata/lcm/actions/base_action.rb +8 -2
  35. data/lib/gooddata/lcm/actions/collect_multiple_projects_column.rb +46 -0
  36. data/lib/gooddata/lcm/actions/collect_users_brick_users.rb +9 -2
  37. data/lib/gooddata/lcm/actions/execute_schedules.rb +0 -2
  38. data/lib/gooddata/lcm/actions/hello_world.rb +1 -1
  39. data/lib/gooddata/lcm/actions/synchronize_cas.rb +6 -0
  40. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +6 -0
  41. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +70 -107
  42. data/lib/gooddata/lcm/actions/synchronize_users.rb +1 -13
  43. data/lib/gooddata/lcm/brick_logger.rb +26 -0
  44. data/lib/gooddata/lcm/lcm2.rb +46 -7
  45. data/lib/gooddata/lcm/types/base_type.rb +4 -0
  46. data/lib/gooddata/lcm/types/class/class.rb +2 -0
  47. data/lib/gooddata/lcm/types/complex/complex.rb +2 -0
  48. data/lib/gooddata/lcm/types/special/array.rb +2 -0
  49. data/lib/gooddata/mixins/is_folder.rb +0 -0
  50. data/lib/gooddata/mixins/to_json.rb +0 -0
  51. data/lib/gooddata/mixins/uri_getter.rb +0 -0
  52. data/lib/gooddata/models/blueprint/project_blueprint.rb +5 -5
  53. data/lib/gooddata/models/blueprint/to_manifest.rb +0 -2
  54. data/lib/gooddata/models/domain.rb +1 -0
  55. data/lib/gooddata/models/from_wire.rb +0 -2
  56. data/lib/gooddata/models/profile.rb +1 -1
  57. data/lib/gooddata/models/project.rb +5 -0
  58. data/lib/gooddata/models/user_filters/user_filter_builder.rb +49 -32
  59. data/lib/gooddata/models/user_group.rb +3 -0
  60. data/lib/gooddata/rest/README.md +0 -0
  61. data/lib/gooddata/rest/client.rb +4 -4
  62. data/lib/gooddata/rest/object.rb +2 -0
  63. data/lib/gooddata/version.rb +1 -1
  64. data/lib/templates/bricks/brick.rb.erb +0 -0
  65. data/lib/templates/bricks/main.rb.erb +0 -0
  66. data/lib/templates/project/Goodfile.erb +0 -0
  67. data/lib/templates/project/data/commits.csv +0 -0
  68. data/lib/templates/project/data/devs.csv +0 -0
  69. data/lib/templates/project/data/repos.csv +0 -0
  70. data/lib/templates/project/model/model.rb.erb +0 -0
  71. metadata +23 -5
  72. data/lib/gooddata/extensions/big_decimal.rb +0 -17
  73. data/lib/gooddata/extensions/numeric.rb +0 -15
  74. data/lib/gooddata/extensions/symbol.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b48905b795b73128a61f84b07810a685a6805b79
4
- data.tar.gz: 3cf38bc8e8d47ac4e30270ff04ec4792fab29f96
3
+ metadata.gz: 22c2a5fb970353f14e3a452d8e1c096b06bf0be1
4
+ data.tar.gz: 80fb1d4e828e36959649b2e08f85a6ab8433fe55
5
5
  SHA512:
6
- metadata.gz: 5adb48ac0a518affbe50f57e693dfc83c3f254caf543c7c32adc552ccef564b9882c207d541067b5682b89b498faa8a201cb91879c90c2fc0068e09099f2be1c
7
- data.tar.gz: 217f13bdd340f4190e614f5bb28be027ae98bd44f7cb9f70cdd6fbb8392bb09a175c897a7dedd705e090469bf78dcf1a2505912aea04e34deefd557a24fea980
6
+ metadata.gz: 962015ddb685114bcc1ef38232a9e3b1bf1ecf9b8bffc72dc100f244df2dfa81a8fe517dd9d74addf4cc90910a349970e06a14ddf478d3e98beb582be7db60b7
7
+ data.tar.gz: '0946bcf5017327cd839e8cf63a1ca269a53e23234e68b5ad7aa27d5d3139a33d58bec13a50338e892d48b4b738f7482b280179866000418fccb94648a505e3a6'
@@ -0,0 +1,2 @@
1
+ .git
2
+ .gooddata
data/.document CHANGED
File without changes
data/.yardopts CHANGED
File without changes
@@ -1,4 +1,52 @@
1
1
  # GoodData Ruby SDK Changelog
2
+ ## 1.3.1
3
+ - FEATURE: TMA-1030 Raise jruby version used in K8s docker image (#1284)
4
+ - Update README.md
5
+ - TRIVIAL: Correct dockerfile maintainer
6
+ - TMA-1033: show reason of filter composition failure (#1282)
7
+ - TMA-483 && TMA-963 Paralel ufb bug final fix
8
+ - TMA-963 && TMA-483: UFB and UB performance (#1234)
9
+ - TMA-1002 fixed broken tests
10
+ - no vcr (#1277)
11
+ - TMA-1005: Automate rotating credentials
12
+ - TMA-925: Optimize polling intervals
13
+ - Add info about running tests to CONTRIBUTING.md (#1262)
14
+ - Fix rubocop issue
15
+ - Add empty lines between licenses and modules
16
+ - SETI-2180 Updated base image namespace
17
+ - FEATURE: TMA-1030 Dockerize LCM bricks
18
+ - FEATURE: TMA-1030 Write brick outputs to files
19
+ - FEATURE: TMA-1030 Add Hello World brick
20
+ - REFACTOR: TMA-1030 Non functional changes
21
+ - BUGFIX: TMA-1040 Add nil result if action fails
22
+ - TEST: TMA-1040 Add tests for "perform" method in LCM2 module
23
+ - Require ActiveSupport where it's needed
24
+ - Revert Array refinement to Enumerable opening
25
+ - Revert class to reopening
26
+ - Use duplicable? from ActiveSupport
27
+ - Remove object.blank? as ActiveSupport already do it
28
+ - Revert Object to reopening
29
+ - Increase the scope of monkey patchs
30
+ - Fixes tests in CI
31
+ - Patch all places that use '.to_b' with all extensions that implements it
32
+ - Isolate Symbol monkeypatch in SymbolExtensions module
33
+ - Code :lipstick: Insert license header in files where it was missing
34
+ - Isolate String monkeypatch in StringExtensions module
35
+ - Add TrueExtensions and FalseExtensions in missing places
36
+ - Isolate Object monkeypatch in ObjectExtensions module
37
+ - Isolate Numeric monkeypatch in NumericExtensions module
38
+ - Isolate BigDecimal monkeypatch in BigDecimalExtensions module
39
+ - Adds Extensions to Globalhelper, it's the only one calls `duplicable?`
40
+ - Isolate Nil monkeypatch in NilExtensions module
41
+ - Isolate Integer monkeypatch in IntegerExtensions module
42
+ - Isolate Hash monkeypatch in HashExtensions module
43
+ - Isolate True/False monkey patchs in respectives modules
44
+ - Is a good practice to explicit the error in rescue block
45
+ - Isolate Enumerable monkey patch in EnumerableExtensions module
46
+ - Isolate Class monkeypatch in ClassExtensions module
47
+ - TMA-927: handle uppercase email inputs
48
+ - TMA-648 tests not deleting ads instances fixed
49
+
2
50
  ## 1.3.0
3
51
  - Add changelog for 1.2.1
4
52
  - Automate bumping version (#1243)
data/CLI.md CHANGED
File without changes
@@ -1,5 +1,24 @@
1
1
  # Contributing
2
2
 
3
+ ## Tests
4
+ ### Unit tests
5
+ `bundle exec rake test:unit`
6
+ ### Integration tests
7
+ Currently only GoodData employees can run integration tests for security reasons.
8
+
9
+ `GD_SPEC_PASSWORD=*** bundle exec rake test:integration`
10
+
11
+ [Integration tests](spec/integration) can be run against different GoodData [environments](spec/environment) or with
12
+ [VCR](https://relishapp.com/vcr/vcr/docs).
13
+
14
+ #### VCR test setup
15
+ When adding new integration test, always set `:vcr` metadata.
16
+ ```ruby
17
+ describe 'New integration test', :vcr
18
+ ```
19
+ The VCR `record` mode can be set via `VCR_RECORD_MODE` environment variable. Set it to `all` to make a new recording.
20
+ Please check the recorded payloads for possible sensitive data before submitting to github.
21
+
3
22
  ## Static analysis
4
23
  We use [Pronto](https://github.com/prontolabs/pronto) to detect code smells using static analysis. Comments are automatically created on pull requests when code smells are found.
5
24
 
@@ -35,16 +54,4 @@ We use [Pronto](https://github.com/prontolabs/pronto) to detect code smells usin
35
54
  [license](/LICENSE).
36
55
  1. Use `GoodData.logger` for logging instead of `puts`.
37
56
 
38
- ## Integration tests
39
- [Integration tests](spec/integration) can be run against different GoodData [environments](spec/environment) or with
40
- [VCR](https://relishapp.com/vcr/vcr/docs).
41
-
42
- ### VCR test setup
43
- When adding new integration test, always set `:vcr` metadata.
44
- ```ruby
45
- describe 'New integration test', :vcr
46
- ```
47
- The VCR `record` mode can be set via `VCR_RECORD_MODE` environment variable. Set it to `all` to make a new recording.
48
- Please check the recorded payloads for possible sensitive data before submitting to github.
49
-
50
57
  _Based on [GitLab's contribution guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md)._
@@ -0,0 +1,37 @@
1
+ FROM harbor.intgdc.com/tools/gdc-java-8-jre:b057b53
2
+
3
+ MAINTAINER LCM <lcm@gooddata.com>
4
+
5
+ LABEL image_name="GDC LCM Bricks"
6
+ LABEL maintainer="LCM <lcm@gooddata.com>"
7
+ LABEL git_repostiory_url="https://github.com/gooddata/gooddata-ruby/"
8
+ LABEL parent_image="harbor.intgdc.com/tools/gdc-java-8-jre:b057b53"
9
+
10
+ # which is required by RVM
11
+ RUN yum install -y curl which \
12
+ && yum clean all \
13
+ && rm -rf /var/cache/yum
14
+
15
+ RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
16
+ RUN curl -sSL https://get.rvm.io | bash -s stable --ruby=jruby-9.1.14
17
+
18
+ # Switch to directory with sources
19
+ WORKDIR /src
20
+
21
+ # login shell is required by rvm
22
+ RUN /bin/bash -l -c ". /usr/local/rvm/scripts/rvm && gem update --system \
23
+ && gem install bundler rake"
24
+
25
+ ARG SOURCE_COMMIT
26
+ ENV GOODDATA_RUBY_COMMIT=$SOURCE_COMMIT
27
+
28
+ ADD ./bin ./bin
29
+ ADD ./lib ./lib
30
+ ADD ./Gemfile .
31
+ ADD ./gooddata.gemspec .
32
+
33
+ RUN /bin/bash -l -c ". /usr/local/rvm/scripts/rvm && bundle install"
34
+
35
+ ENTRYPOINT ["/bin/bash", "-l", "-c"]
36
+
37
+ CMD [ ". /usr/local/rvm/scripts/rvm && bundle exec ./bin/run_brick.rb" ]
data/Guardfile CHANGED
File without changes
data/README.md CHANGED
@@ -78,4 +78,4 @@ For full contributor info see [contributors page](https://github.com/gooddata/go
78
78
 
79
79
  ## Copyright
80
80
 
81
- Copyright (c) 2010 - 2015 GoodData Corporation and Thomas Watson Steen. See LICENSE for details.
81
+ Copyright (c) 2010 - 2018 GoodData Corporation and Thomas Watson Steen. See [LICENSE](/LICENSE) for details.
data/Rakefile CHANGED
@@ -5,10 +5,11 @@ require 'rubygems'
5
5
  require 'bundler/setup'
6
6
  require 'bundler/cli'
7
7
  require 'bundler/gem_tasks'
8
-
8
+ require 'gooddata'
9
9
  require 'rake/testtask'
10
10
  require 'rspec/core/rake_task'
11
11
 
12
+ require 'yaml'
12
13
  require 'yard'
13
14
 
14
15
  require 'rubocop/rake_task'
@@ -224,3 +225,18 @@ namespace :gitflow do
224
225
  system(file_path) || fail('Initializing git-flow failed!')
225
226
  end
226
227
  end
228
+
229
+ namespace :password do
230
+ task :rotate, [:value, :encryption_key] do |_, args|
231
+ key = 'password'
232
+ value = args[:value]
233
+ encryption_key = args[:encryption_key]
234
+ encrypted_value = GoodData::Helpers.encrypt(value, encryption_key).strip
235
+ secrets_path = File.join(File.dirname(__FILE__), 'spec/environment/secrets.yaml')
236
+ secrets = YAML.load_file(secrets_path)
237
+ secrets.each_value do |env|
238
+ env[key].replace(encrypted_value) if env.key?(key)
239
+ end
240
+ File.write(secrets_path, secrets.to_yaml)
241
+ end
242
+ end
data/TODO.md CHANGED
File without changes
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'remote_syslog_logger'
4
+ require_relative '../lib/gooddata'
5
+
6
+ DEFAULT_BRICK = 'hello_world_brick'
7
+
8
+ brick_type = ENV['BRICK_TYPE'] || DEFAULT_BRICK
9
+
10
+ syslog_node = ENV['NODE_NAME']
11
+ log = RemoteSyslogLogger.new(syslog_node, 514, :program => brick_type)
12
+
13
+ log.info "action=#{brick_type}_execution status=start"
14
+
15
+ begin
16
+ brick_pipeline = GoodData::Bricks::Pipeline.send("#{brick_type}_pipeline")
17
+ params_json = ENV['BRICK_PARAMS_JSON']
18
+ params = params_json.nil? ? {} : JSON.parse(params_json)
19
+
20
+ params['gooddata_ruby_commit'] = ENV['GOODDATA_RUBY_COMMIT'] || '<unknown>'
21
+ params['log_directory'] = ENV['LOG_DIRECTORY'] || '/tmp/'
22
+
23
+ @brick_result = brick_pipeline.call(params)
24
+ log.info "action=#{brick_type}_execution status=finished"
25
+ rescue NoMethodError => e
26
+ log.info "action=#{brick_type}_execution status=error Invalid brick type '#{brick_type}', #{e.message}"
27
+ raise e
28
+ rescue => e
29
+ log.info "action=#{brick_type}_execution status=error #{e.message}"
30
+ raise e
31
+ end
File without changes
@@ -60,6 +60,7 @@ Gem::Specification.new do |s|
60
60
  s.add_dependency 'multi_json', '~> 1.12'
61
61
  s.add_dependency 'parseconfig', '~> 1.0'
62
62
  s.add_dependency 'pmap', '~> 1.1'
63
+ s.add_dependency 'remote_syslog_logger', '~> 1.0.3'
63
64
  s.add_dependency 'restforce', '~> 2.4'
64
65
  s.add_dependency 'rest-client', '~> 2.0'
65
66
  s.add_dependency 'rubyzip', '~> 1.2', '>= 1.2.1'
@@ -0,0 +1,21 @@
1
+ require_relative 'brick'
2
+
3
+ module GoodData
4
+ module Bricks
5
+ # Simple brick used for testing and debug purposes
6
+ class HelloWorldBrick < GoodData::Bricks::Brick
7
+ def version
8
+ '0.0.1'
9
+ end
10
+
11
+ # HelloWorld brick entry-point
12
+ #
13
+ # @param [Hash] params Parameters
14
+ # @option [String] 'message' text to be returned in result, if nill - nothing is returned
15
+ # :reek:UtilityFunction
16
+ def call(params)
17
+ GoodData::LCM2.perform('hello_world', params)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -6,6 +6,18 @@
6
6
 
7
7
  require_relative 'base_middleware'
8
8
 
9
+ require 'gooddata/extensions/true'
10
+ require 'gooddata/extensions/false'
11
+ require 'gooddata/extensions/integer'
12
+ require 'gooddata/extensions/string'
13
+ require 'gooddata/extensions/nil'
14
+
15
+ using TrueExtensions
16
+ using FalseExtensions
17
+ using IntegerExtensions
18
+ using StringExtensions
19
+ using NilExtensions
20
+
9
21
  module GoodData
10
22
  module Bricks
11
23
  # Connects to platform and enriches parameters with GoodData::Client
@@ -6,6 +6,18 @@
6
6
 
7
7
  require 'logger'
8
8
 
9
+ require 'gooddata/extensions/true'
10
+ require 'gooddata/extensions/false'
11
+ require 'gooddata/extensions/integer'
12
+ require 'gooddata/extensions/string'
13
+ require 'gooddata/extensions/nil'
14
+
15
+ using TrueExtensions
16
+ using FalseExtensions
17
+ using IntegerExtensions
18
+ using StringExtensions
19
+ using NilExtensions
20
+
9
21
  require_relative 'base_middleware'
10
22
 
11
23
  module GoodData
@@ -9,6 +9,7 @@ require_relative 'user_filters_brick'
9
9
  require_relative 'release_brick'
10
10
  require_relative 'provisioning_brick'
11
11
  require_relative 'rollout_brick'
12
+ require_relative 'hello_world_brick'
12
13
 
13
14
  module GoodData
14
15
  module Bricks
@@ -87,6 +88,17 @@ module GoodData
87
88
  RolloutBrick
88
89
  ])
89
90
  end
91
+
92
+ def self.hello_world_brick_pipeline
93
+ prepare(
94
+ [
95
+ DecodeParamsMiddleware,
96
+ LoggerMiddleware,
97
+ BenchMiddleware,
98
+ HelloWorldBrick
99
+ ]
100
+ )
101
+ end
90
102
  end
91
103
  end
92
104
  end
@@ -6,11 +6,5 @@
6
6
 
7
7
  module GoodData
8
8
  class FilterMaqlizationError < RuntimeError
9
- attr_accessor :errors
10
-
11
- def initialize(errs = [])
12
- super('Filter MAQLization failed')
13
- @errors = errs
14
- end
15
9
  end
16
10
  end
@@ -1,3 +1,7 @@
1
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
2
+ # This source code is licensed under the BSD-style license found in the
3
+ # LICENSE file in the root directory of this source tree.
4
+
1
5
  class Class
2
6
  def short_name
3
7
  name.split('::').last
@@ -1,9 +1,6 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
6
-
7
4
  module Enumerable
8
5
  def mapcat(initial = [], &block)
9
6
  reduce(initial) do |a, e|
@@ -1,9 +1,6 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
6
-
7
4
  base = Pathname(__FILE__).dirname.expand_path
8
5
  Dir.glob(base + '*.rb').each do |file|
9
6
  require_relative file
@@ -1,23 +1,15 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
6
4
 
7
- class FalseClass
8
- # +false+ is not duplicable:
9
- #
10
- # false.duplicable? # => false
11
- # false.dup # => TypeError: can't dup FalseClass
12
- def duplicable?
13
- false
14
- end
15
-
16
- def to_b
17
- false
18
- end
5
+ module FalseExtensions
6
+ refine FalseClass do
7
+ def to_b
8
+ false
9
+ end
19
10
 
20
- def to_i
21
- 0
11
+ def to_i
12
+ 0
13
+ end
22
14
  end
23
15
  end
@@ -1,48 +1,17 @@
1
- # encoding: UTF-8
2
- #
3
1
  # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
2
  # This source code is licensed under the BSD-style license found in the
5
3
  # LICENSE file in the root directory of this source tree.
6
4
 
7
- class Hash
8
- # Return a hash that includes everything but the given keys. This is useful for
9
- # limiting a set of parameters to everything but a few known toggles:
10
- #
11
- # @person.update_attributes(params[:person].except(:admin))
12
- #
13
- # If the receiver responds to +convert_key+, the method is called on each of the
14
- # arguments. This allows +except+ to play nice with hashes with indifferent access
15
- # for instance:
16
- #
17
- # {:a => 1}.with_indifferent_access.except(:a) # => {}
18
- # {:a => 1}.with_indifferent_access.except("a") # => {}
19
- #
20
- def except(*keys)
21
- dup.except!(*keys)
22
- end
23
-
24
- # Replaces the hash without the given keys.
25
- def except!(*keys)
26
- keys.each { |key| delete(key) }
27
- self
28
- end
29
-
30
- def slice(*keys)
31
- keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
32
- keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if key?(k) }
33
- end
34
-
35
- def compact
36
- select { |_, value| !value.nil? }
37
- end
38
-
39
- def deep_merge(hash)
40
- hash = hash.to_hash
41
- merge(hash) do |_key, old_val, new_val|
42
- if old_val.is_a?(Hash) && new_val.is_a?(Hash)
43
- old_val.deep_merge(new_val)
44
- else
45
- new_val
5
+ module HashExtensions
6
+ refine Hash do
7
+ def deep_merge(hash)
8
+ hash = hash.to_hash
9
+ merge(hash) do |_key, old_val, new_val|
10
+ if old_val.is_a?(Hash) && new_val.is_a?(Hash)
11
+ old_val.deep_merge(new_val)
12
+ else
13
+ new_val
14
+ end
46
15
  end
47
16
  end
48
17
  end