yaml_extend 0.2.3 → 1.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
2
  SHA256:
3
- metadata.gz: 805447b25c0ac209e4c59d10d8c9f5dc2432a7271aafd0e9d9f16ccd984e6522
4
- data.tar.gz: 654ad7daaec70841729bcef0131f4e29108456a8fdd17fc9898eedbd89f69e4f
3
+ metadata.gz: b056650bc04768e6d55177c1125ef048d7f02d4764e8cecdd851f75e07b816c5
4
+ data.tar.gz: bc70a195072c63c7af2116b619f8ea5677b7fae0925128f9cfbedb8d216d7d9c
5
5
  SHA512:
6
- metadata.gz: 5af7d94d3783ffdb7a3c28fe5e2459d2c3423197f25939bfe3d5f2e88da1db044e94e38d08e8751ca165d4c89b656adc1f6a2104f5065eade9d2d6c34e59cb07
7
- data.tar.gz: ebd14878f223d0bdb4f6c2a480e1a3d9ac91131f98db8202d4a4dda35347ad24457e0b86cc57765b48bb8a1ce02742280207bd882e1516a6d80728234d4b28df
6
+ metadata.gz: 6f3588a3e5a0a07d4102e19ed7d0c87af68f0638037d141df85c4d24c7791743b3fd449fc77a6316d44f602e157297c6560dba9dabc304ee46c36f3ccb8d9155
7
+ data.tar.gz: 7ff4beefad210bd1a503a8cfc4563042c53751099441beb04d2ad1680eebad697b87db82e10421c4ca958439bda4c850770729211db8f0f67e3e8a5b6feecc05
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
55
55
  ## Enforcement
56
56
 
57
57
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at m.beyrle@walz.de. All
58
+ reported by contacting the project team at yaml_extend.gemspec@mail.magynhard.de. All
59
59
  complaints will be reviewed and investigated and will result in a response that
60
60
  is deemed necessary and appropriate to the circumstances. The project team is
61
61
  obligated to maintain confidentiality with regard to the reporter of an incident.
data/README.md CHANGED
@@ -22,11 +22,20 @@ Or install it yourself as:
22
22
 
23
23
  ## Common information
24
24
 
25
- It is possible to build inheritance trees like
25
+ It is possible to build inheritance trees like:
26
26
  ```
27
- default.yml english.yml default.yml german.yml de.yml
28
- \ / \ / |
29
- uk.yml de.yml at.yml
27
+ defaults.yml
28
+ ________\_________
29
+ \ \ \
30
+ dev.yml int.yml prod.yml
31
+ ```
32
+ or like this:
33
+ ```
34
+ fruits.yml vegetables.yml default.yml extensions.yml
35
+ \ / \ /
36
+ food.yml merged.yml
37
+ |
38
+ another_extended.yml
30
39
  ```
31
40
 
32
41
  A file can inherit from as many as you want. Trees can be nested as deep as you want.
@@ -39,9 +48,9 @@ That key can be customized if you prefer another one.
39
48
  See the examples below.
40
49
 
41
50
  ## Usage
42
- yaml_extend adds the method YAML#ext_load_file to YAML.
51
+ yaml_extend adds the method YAML.ext_load_file to YAML.
43
52
 
44
- This method works like the original YAML#load_file, by extending it with file inheritance.
53
+ This method works like the original YAML.load_file, by extending it with file inheritance.
45
54
 
46
55
  ### Examples
47
56
 
@@ -68,10 +77,10 @@ data:
68
77
  - 'Apples'
69
78
  ```
70
79
 
71
- When you then call #ext_load_file
80
+ When you then call `ext_load_file`
72
81
 
73
82
  ```ruby
74
- YAML.ext_load_file 'start.yml'
83
+ config = YAML.ext_load_file 'start.yml'
75
84
  ```
76
85
 
77
86
  the returned YAML value results in
@@ -111,19 +120,18 @@ foo: 'bar'
111
120
  ...
112
121
  ```
113
122
  ##### 1. Specify by parameter
114
- You can specify the key by parameter, this is the way to go if you want to use the different key only once or you use the #ext_load_file method only once in your application.
123
+ You can specify the key by parameter, this is the way to go if you want to use the different key only once or you use the `ext_load_file` method only once in your application.
115
124
  ```ruby
116
- YAML.ext_load_file 'custom1.yml', 'inherit_from'
125
+ config = YAML.ext_load_file 'custom1.yml', 'inherit_from'
117
126
  ```
118
127
  ##### 2. Global configuration of the key
119
128
  You can specify the key by configuration globally. So you only need to set the key once and not as parameter anymore
120
129
  ```ruby
121
130
  YAML.ext_load_key = 'inherit_from'
122
- YAML.ext_load_file 'custom1.yml'
123
- YAML.ext_load_file 'custom2.yml'
131
+ config = YAML.ext_load_file 'custom1.yml'
124
132
  ```
125
133
  ##### Reset the global key
126
- To reset the global inheritance key, you can either set it to nil or call the #reset_load_key method.
134
+ To reset the global inheritance key, you can either set it to nil or call the `reset_load_key` method.
127
135
  ```ruby
128
136
  YAML.reset_load_key # more readable
129
137
  YAML.ext_load_key = nil # more explicit
@@ -139,16 +147,30 @@ foo: 'bar'
139
147
  ```
140
148
 
141
149
  ```ruby
142
- YAML.ext_load_file 'custom2.yml', ['options','extend_file']
150
+ config = YAML.ext_load_file 'custom2.yml', ['options','extend_file']
143
151
  ```
144
152
 
145
153
  ## Documentation
146
- YAML#ext_load_file(yaml_path, inheritance_key='extends', extend_existing_arrays=true, config = {})
147
-
148
- - *yaml_path* relative or absolute path to yaml file to inherit from
149
- - *inheritance_key* you can overwrite the default key, if you use the default 'extends' already as part of your configuration. The inheritance_key is NOT included, that means it will be deleted, in the final merged file. Default: 'extends'
150
- - *extend_existing_arrays* Extends existing arrays in yaml structure instead of replacing them. Default: true
151
- - *config* only intended to be used by the method itself due recursive algorithm
154
+ ```ruby
155
+ YAML.ext_load_file(yaml_path, inheritance_key='extends', options = {})
156
+ ```
157
+ - `yaml_path` (String) relative or absolute path to yaml file to inherit from
158
+ - `inheritance_key` (String) you can overwrite the default key, if you use the default 'extends' already as part of your configuration. The inheritance_key is NOT included, that means it will be deleted, in the final merged file. Default: `'extends'`
159
+ - `options` (Hash) collection of optional options, including all options of the based `deep_merge` gem
160
+ - `:preserve_inheritance_key` (Boolean) Preserve inheritance key(s) from resulting yaml, does most time not make sense especially in multiple inheritance - DEFAULT: false
161
+ - The following options are deep merge options that can be passed by - but the defaults differ from original
162
+ https://github.com/danielsdeleo/deep_merge#options
163
+ - `:preserve_unmergeables` (Boolean) Set to true to skip any unmergeable elements from source - DEFAULT: false
164
+ - `:knockout_prefix` (String) Set to string value to signify prefix which deletes elements from existing element - DEFAULT: nil
165
+ - `:overwrite_arrays` (Boolean) Set to true if you want to avoid merging arrays - DEFAULT: false
166
+ - `:sort_merged_arrays` (Boolean) Set to true to sort all arrays that are merged together - DEFAULT: false
167
+ - `:unpack_arrays` (String) Set to string value to run "Array::join" then "String::split" against all arrays - DEFAULT: nil
168
+ - `:merge_hash_arrays` (Boolean) Set to true to merge hashes within arrays - DEFAULT: false
169
+ - `:extend_existing_arrays` (Boolean) Set to true to extend existing arrays, instead of overwriting them - DEFAULT: true
170
+ - `:merge_nil_values` (Boolean) Set to true to merge nil hash values, overwriting a possibly non-nil value - DEFAULT: false
171
+ - `:merge_debug` (Boolean) Set to true to get console output of merge process for debugging - DEFAULT: false
172
+
173
+ See also rubydoc at [https://www.rubydoc.info/gems/yaml_extend](https://www.rubydoc.info/gems/yaml_extend)
152
174
 
153
175
  ## Contributing
154
176
 
@@ -3,8 +3,6 @@ require 'yaml_extend/version'
3
3
  require 'yaml'
4
4
  require 'deep_merge/rails_compat'
5
5
 
6
- require_relative 'yaml_extend/yaml_extend_helper'
7
-
8
6
  require_relative 'custom_errors/invalid_key_type_error'
9
7
 
10
8
  #
@@ -15,6 +13,19 @@ module YAML
15
13
  # default path in the yaml file where the files to inherit from are defined
16
14
  DEFAULT_INHERITANCE_KEY = 'extends'
17
15
  @@ext_load_key = nil
16
+
17
+ DEEP_MERGE_OPTIONS = [
18
+ :preserve_unmergeables,
19
+ :knockout_prefix,
20
+ :overwrite_arrays,
21
+ :sort_merged_arrays,
22
+ :unpack_arrays,
23
+ :merge_hash_arrays,
24
+ :extend_existing_arrays,
25
+ :merge_nil_values,
26
+ :merge_debug,
27
+ ]
28
+
18
29
  #
19
30
  # Set a custom inheritance key globally once.
20
31
  # So you don't need to specify it on every call of ext_load_file()
@@ -34,48 +45,99 @@ module YAML
34
45
  def self.reset_load_key()
35
46
  @@ext_load_key = nil
36
47
  end
48
+
37
49
  #
38
- # Extended variant of the #load_file method by providing the
50
+ # Extended variant of the YAML.load_file method by providing the
39
51
  # ability to inherit from other YAML file(s)
40
52
  #
41
- # @param yaml_path [String] the path to the yaml file to be loaded
42
- # @param inheritance_key [String|Array] The key used in the yaml file to extend from another YAML file. Use an Array if you want to use a tree structure key like "options.extends" => ['options','extends']
43
- # @param extend_existing_arrays [Boolean] extend existing arrays instead of replacing them
44
- # @param config [Hash] a hash to be merged into the result, usually only recursivly called by the method itself
53
+ # @param [String] yaml_path the path to the yaml file to be loaded
54
+ # @param [String|Array] inheritance_key The key used in the yaml file to extend from another YAML file. Use an Array if you want to use a tree structure key like "options.extends" => ['options','extends']
55
+ # @param [Hash] options to pass, including deep_merge options as well as
56
+ # @option options [Boolean] :preserve_inheritance_key Preserve inheritance key(s) from resulting yaml, does most time not make sense especially in multiple inheritance - DEFAULT: false
57
+ #
58
+ # deep merge options that can be passed by - but the defaults differ from original
59
+ # https://github.com/danielsdeleo/deep_merge#options
45
60
  #
61
+ # @option options [Boolean] :preserve_unmergeables Set to true to skip any unmergeable elements from source - DEFAULT: false
62
+ # @option options [String] :knockout_prefix Set to string value to signify prefix which deletes elements from existing element - DEFAULT: nil
63
+ # @option options [Boolean] :overwrite_arrays Set to true if you want to avoid merging arrays - DEFAULT: false
64
+ # @option options [Boolean] :sort_merged_arrays Set to true to sort all arrays that are merged together - DEFAULT: false
65
+ # @option options [String] :unpack_arrays Set to string value to run "Array::join" then "String::split" against all arrays - DEFAULT: nil
66
+ # @option options [Boolean] :merge_hash_arrays Set to true to merge hashes within arrays - DEFAULT: false
67
+ # @option options [Boolean] :extend_existing_arrays Set to true to extend existing arrays, instead of overwriting them - DEFAULT: true
68
+ # @option options [Boolean] :merge_nil_values Set to true to merge nil hash values, overwriting a possibly non-nil value - DEFAULT: false
69
+ # @option options [Boolean] :merge_debug Set to true to get console output of merge process for debugging - DEFAULT: false
70
+ #
71
+ # @param [Boolean] options Fallback for backward compatiblity: extend existing arrays instead of replacing them (deep_merge)
46
72
  # @return [Hash] the resulting yaml config
47
73
  #
48
- def self.ext_load_file(yaml_path, inheritance_key=nil, extend_existing_arrays=true, config = {})
74
+ def self.ext_load_file(yaml_path, inheritance_key = nil, options = {})
75
+ YAML.ext_load_file_recursive(yaml_path, inheritance_key, options, {})
76
+ end
77
+
78
+ private
79
+
80
+ #
81
+ # @param config [Hash] a hash to be merged into the result, usually only recursivly called by the method itself
82
+ #
83
+ def self.ext_load_file_recursive(yaml_path, inheritance_key, options = {}, config)
84
+ # backward compatibility to 1.0.1
85
+ if options == true || options == false
86
+ options = {extend_existing_arrays: options}
87
+ end
88
+ default_options = {
89
+ preserve_inheritance_key: false,
90
+ preserve_unmergeables: false,
91
+ knockout_prefix: nil,
92
+ overwrite_arrays: false,
93
+ sort_merged_arrays: false,
94
+ unpack_arrays: nil,
95
+ merge_hash_arrays: false,
96
+ extend_existing_arrays: true,
97
+ merge_nil_values: false,
98
+ merge_debug: false,
99
+ }
100
+ options = default_options.merge options
101
+ private_class_method
49
102
  if inheritance_key.nil?
50
103
  inheritance_key = @@ext_load_key || DEFAULT_INHERITANCE_KEY
51
104
  end
52
- total_config ||= {}
105
+ total_config = config.clone
106
+
53
107
  yaml_path = YAML.make_absolute_path yaml_path
54
- super_config = YamlExtendHelper.encode_booleans YAML.load_file(File.open(yaml_path))
108
+ super_config = YAML.load_file(File.open(yaml_path))
55
109
  super_inheritance_files = yaml_value_by_key inheritance_key, super_config
56
- delete_yaml_key inheritance_key, super_config # we don't merge the super inheritance keys into the base yaml
57
- merged_config = config.clone.deeper_merge(super_config, extend_existing_arrays: extend_existing_arrays)
110
+ unless options[:preserve_inheritance_key]
111
+ delete_yaml_key inheritance_key, super_config # we don't merge the super inheritance keys into the base yaml
112
+ end
113
+
58
114
  if super_inheritance_files && super_inheritance_files != ''
59
115
  super_inheritance_files = [super_inheritance_files] unless super_inheritance_files.is_a? Array # we support strings as well as arrays of type string to extend from
60
116
  super_inheritance_files.each_with_index do |super_inheritance_file, index|
61
- super_config_path = File.dirname(yaml_path) + '/' + super_inheritance_file
62
- total_config = YamlExtendHelper.encode_booleans YAML.ext_load_file(super_config_path, inheritance_key, extend_existing_arrays, total_config.deeper_merge(merged_config, extend_existing_arrays: extend_existing_arrays))
117
+ # Extend a YAML path in an absolute directory
118
+ if YAML.absolute_path?(super_inheritance_file)
119
+ super_config_path = YAML.make_absolute_path(super_inheritance_file)
120
+ # Extend a YAML path in a relative directory
121
+ else
122
+ super_config_path = File.dirname(yaml_path) + '/' + super_inheritance_file
123
+ end
124
+ total_config = YAML.ext_load_file_recursive(super_config_path, inheritance_key, options, total_config)
63
125
  end
64
- YamlExtendHelper.decode_booleans total_config
65
- else
66
- delete_yaml_key inheritance_key, merged_config
67
- YamlExtendHelper.decode_booleans merged_config
68
126
  end
127
+ deep_merge_options = options.select { |k, v| DEEP_MERGE_OPTIONS.include? k }
128
+ total_config.deeper_merge!(super_config, deep_merge_options)
69
129
  end
70
130
 
71
- private
72
-
73
131
  # some logic to ensure absolute file inheritance as well as
74
132
  # relative file inheritance in yaml files
75
133
  def self.make_absolute_path(file_path)
76
134
  private_class_method
77
135
  return file_path if YAML.absolute_path?(file_path) && File.exist?(file_path)
78
- base_path = File.dirname(caller_locations[1].path)
136
+ # caller_locations returns the current execution stack
137
+ # [0] is the call from ext_load_file_recursive,
138
+ # [1] is inside ext_load_file,
139
+ # [2] is the exteranl caller of YAML.ext_load_file
140
+ base_path = File.dirname(caller_locations[2].path)
79
141
  return base_path + '/' + file_path if File.exist? base_path + '/' + file_path # relative path from yaml file
80
142
  return Dir.pwd + '/' + file_path if File.exist? Dir.pwd + '/' + file_path # relative path from project
81
143
  error_message = "Can not find absolute path of '#{file_path}'"
@@ -89,7 +151,7 @@ module YAML
89
151
  def self.absolute_path?(path)
90
152
  private_class_method
91
153
  path.start_with?('/') || # unix like
92
- (path.length >= 3 && path[1] == ':') # ms windows
154
+ (path.length >= 3 && path[1] == ':') # ms windows
93
155
  end
94
156
 
95
157
  # Return the value of the corresponding key
@@ -111,7 +173,7 @@ module YAML
111
173
 
112
174
  def self.valid_key_type?(key)
113
175
  key.is_a?(Array) || key.is_a?(String) ||
114
- raise(InvalidKeyTypeError,"Invalid key of type '#{key.class.name}'. Valid types are String and Array.")
176
+ raise(InvalidKeyTypeError, "Invalid key of type '#{key.class.name}'. Valid types are String and Array.")
115
177
  end
116
178
 
117
179
  def self.delete_yaml_key(key, config)
@@ -1,3 +1,3 @@
1
1
  module YamlExtend
2
- VERSION = '0.2.3'.freeze
2
+ VERSION = '1.0.2'.freeze
3
3
  end
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.add_dependency 'deep_merge', '~> 1.1'
33
33
 
34
- spec.add_development_dependency 'bundler', '~> 1.14'
35
- spec.add_development_dependency 'rake', '~> 10.0'
36
- spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'bundler', '>= 1.14'
35
+ spec.add_development_dependency 'rake', '>= 10.0'
36
+ spec.add_development_dependency 'rspec', '>= 3.0'
37
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yaml_extend
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthäus Beyrle
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-04 00:00:00.000000000 Z
11
+ date: 2020-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deep_merge
@@ -28,45 +28,45 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.14'
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
40
  version: '1.14'
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
47
  version: '10.0'
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
54
  version: '10.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '3.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
- description:
69
+ description:
70
70
  email:
71
71
  - yaml_extend.gemspec@mail.magynhard.de
72
72
  executables: []
@@ -86,14 +86,13 @@ files:
86
86
  - lib/custom_errors/invalid_key_type_error.rb
87
87
  - lib/yaml_extend.rb
88
88
  - lib/yaml_extend/version.rb
89
- - lib/yaml_extend/yaml_extend_helper.rb
90
89
  - yaml_extend.gemspec
91
90
  homepage: https://github.com/magynhard/yaml_extend
92
91
  licenses:
93
92
  - MIT
94
93
  metadata:
95
94
  allowed_push_host: https://rubygems.org
96
- post_install_message:
95
+ post_install_message:
97
96
  rdoc_options: []
98
97
  require_paths:
99
98
  - lib
@@ -108,9 +107,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
107
  - !ruby/object:Gem::Version
109
108
  version: '0'
110
109
  requirements: []
111
- rubyforge_project:
112
- rubygems_version: 2.7.7
113
- signing_key:
110
+ rubygems_version: 3.0.8
111
+ signing_key:
114
112
  specification_version: 4
115
113
  summary: Extends YAML to support file based inheritance
116
114
  test_files: []
@@ -1,68 +0,0 @@
1
-
2
- #
3
- # This class includes a workaround patch, providing a solution of the unaccepted pull request
4
- # 'false is not overriden by true if preserve_unmergeables'
5
- # https://github.com/danielsdeleo/deep_merge/pull/28
6
- #
7
- # It ensures, that booleans can be merged correctly, by en- and decoding them to strings, before and after merging
8
- # see #encode_boolens and #decode_booleans
9
- #
10
-
11
- class YamlExtendHelper
12
-
13
- TRUE_CLASS_ENCODED = '#={TrueClass}=#'
14
- FALSE_CLASS_ENCODED = '#={FalseClass}=#'
15
-
16
- def self.encode_booleans(hash)
17
- hash.each_with_object({}) do |(k,v),g|
18
- g[k] = if v.is_a? Hash
19
- YamlExtendHelper.encode_booleans(v)
20
- elsif v.is_a? Array
21
- v.each_with_index do |av, ai|
22
- v[ai] = if av.is_a? Hash
23
- YamlExtendHelper.encode_booleans(av)
24
- elsif av.is_a? TrueClass
25
- TRUE_CLASS_ENCODED
26
- elsif av.is_a? FalseClass
27
- FALSE_CLASS_ENCODED
28
- else
29
- av
30
- end
31
- end
32
- elsif v.is_a? TrueClass
33
- TRUE_CLASS_ENCODED
34
- elsif v.is_a? FalseClass
35
- FALSE_CLASS_ENCODED
36
- else
37
- v
38
- end
39
- end
40
- end
41
-
42
- def self.decode_booleans(hash)
43
- hash.each_with_object({}) do |(k,v),g|
44
- g[k] = if v.is_a? Hash
45
- YamlExtendHelper.decode_booleans(v)
46
- elsif v.is_a? Array
47
- v.each_with_index do |av, ai|
48
- v[ai] = if av.is_a? Hash
49
- YamlExtendHelper.decode_booleans(av)
50
- elsif av === TRUE_CLASS_ENCODED
51
- true
52
- elsif av === FALSE_CLASS_ENCODED
53
- false
54
- else
55
- av
56
- end
57
- end
58
- elsif v === TRUE_CLASS_ENCODED
59
- true
60
- elsif v === FALSE_CLASS_ENCODED
61
- false
62
- else
63
- v
64
- end
65
- end
66
- end
67
-
68
- end