xcodeproj 0.4.3 → 0.5.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.
@@ -168,7 +168,7 @@ str_to_url(VALUE path) {
168
168
  #else
169
169
  VALUE p = rb_String(path);
170
170
  #endif
171
- CFURLRef fileURL = CFURLCreateFromFileSystemRepresentation(NULL, RSTRING_PTR(p), RSTRING_LEN(p), false);
171
+ CFURLRef fileURL = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)RSTRING_PTR(p), RSTRING_LEN(p), false);
172
172
  if (!fileURL) {
173
173
  rb_raise(rb_eArgError, "Unable to create CFURL from `%s'.", RSTRING_PTR(rb_inspect(path)));
174
174
  }
data/lib/xcodeproj.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Xcodeproj
2
- VERSION = '0.4.3'
2
+ VERSION = '0.5.0' unless defined? Xcodeproj::VERSION
3
3
 
4
4
  class PlainInformative < StandardError
5
5
  end
@@ -10,10 +10,12 @@ module Xcodeproj
10
10
  end
11
11
  end
12
12
 
13
- autoload :Config, 'xcodeproj/config'
14
- autoload :Command, 'xcodeproj/command'
15
- autoload :Constants, 'xcodeproj/constants'
16
- autoload :Helper, 'xcodeproj/helper'
17
- autoload :Project, 'xcodeproj/project'
18
- autoload :Workspace, 'xcodeproj/workspace'
13
+ autoload :Command, 'xcodeproj/command'
14
+ autoload :Config, 'xcodeproj/config'
15
+ autoload :Constants, 'xcodeproj/constants'
16
+ autoload :Differ, 'xcodeproj/differ'
17
+ autoload :Helper, 'xcodeproj/helper'
18
+ autoload :Project, 'xcodeproj/project'
19
+ autoload :UI, 'xcodeproj/user_interface'
20
+ autoload :Workspace, 'xcodeproj/workspace'
19
21
  end
@@ -32,20 +32,20 @@ module Xcodeproj
32
32
 
33
33
 
34
34
  def run
35
- hash_1 = Project.new(@path_project1).to_tree_hash
36
- hash_2 = Project.new(@path_project2).to_tree_hash
37
- (@keys_to_ignore).each do |key|
38
- hash_1.recursive_delete(key)
39
- hash_2.recursive_delete(key)
35
+ hash_1 = Project.new(@path_project1).to_tree_hash.dup
36
+ hash_2 = Project.new(@path_project2).to_tree_hash.dup
37
+ @keys_to_ignore.each do |key|
38
+ Differ.clean_hash!(hash_1, key)
39
+ Differ.clean_hash!(hash_2, key)
40
40
  end
41
41
 
42
- diff = hash_1.recursive_diff(hash_2, @path_project1, @path_project2)
43
- diff.recursive_delete('displayName')
42
+ diff = Differ.project_diff(hash_1, hash_2, @path_project1, @path_project2)
44
43
 
45
44
  require 'yaml'
46
45
  yaml = diff.to_yaml
47
46
  yaml = yaml.gsub(@path_project1, @path_project1.cyan)
48
47
  yaml = yaml.gsub(@path_project2, @path_project2.magenta)
48
+ yaml = yaml.gsub(":diff:", "diff:".yellow)
49
49
  puts yaml
50
50
  end
51
51
  end
@@ -18,8 +18,17 @@ module Xcodeproj
18
18
 
19
19
  def run
20
20
  require 'yaml'
21
- yaml = xcodeproj.to_tree_hash.to_yaml
22
- puts yaml
21
+ pretty_print = xcodeproj.pretty_print
22
+ sections = []
23
+ pretty_print.each do |key, value|
24
+ section = key.green
25
+ yaml = value.to_yaml
26
+ yaml.gsub!(/^---$/,'')
27
+ yaml.gsub!(/^-/,"\n-")
28
+ section << yaml
29
+ sections << section
30
+ end
31
+ puts sections * "\n\n"
23
32
  end
24
33
  end
25
34
  end
@@ -1,40 +1,39 @@
1
1
  module Xcodeproj
2
2
 
3
3
  # This class holds the data for a Xcode build settings file (xcconfig) and
4
- # serializes it.
4
+ # provides support for serialization.
5
5
  #
6
6
  class Config
7
7
 
8
8
  require 'set'
9
9
 
10
10
  # @return [Hash{String => String}] The attributes of the settings file
11
- # excluding frameworks, weak_framework and libraries.
11
+ # excluding frameworks, weak_framework and libraries.
12
12
  #
13
13
  attr_accessor :attributes
14
14
 
15
15
  # @return [Set<String>] The list of the frameworks required by this
16
- # settings file.
16
+ # settings file.
17
17
  #
18
18
  attr_accessor :frameworks
19
19
 
20
20
  # @return [Set<String>] The list of the *weak* frameworks required by
21
- # this settings file.
21
+ # this settings file.
22
22
  #
23
23
  attr_accessor :weak_frameworks
24
24
 
25
25
  # @return [Set<String>] The list of the libraries required by this
26
- # settings file.
26
+ # settings file.
27
27
  #
28
28
  attr_accessor :libraries
29
29
 
30
30
  # @return [Array] The list of the configuration files included by this
31
- # configuration file (`#include "SomeConfig"`).
31
+ # configuration file (`#include "SomeConfig"`).
32
32
  #
33
33
  attr_accessor :includes
34
34
 
35
- # Returns a new instance of Config
36
- #
37
- # @param [Hash, File, String] xcconfig_hash_or_file Initial data.
35
+ # @param [Hash, File, String] xcconfig_hash_or_file
36
+ # The initial data.
38
37
  #
39
38
  def initialize(xcconfig_hash_or_file = {})
40
39
  @attributes = {}
@@ -43,8 +42,18 @@ module Xcodeproj
43
42
  merge!(extract_hash(xcconfig_hash_or_file))
44
43
  end
45
44
 
45
+ def inspect
46
+ to_hash.inspect
47
+ end
48
+
49
+ def ==(other)
50
+ other.respond_to?(:to_hash) && other.to_hash == self.to_hash
51
+ end
52
+
46
53
  #-------------------------------------------------------------------------#
47
54
 
55
+ public
56
+
48
57
  # @!group Serialization
49
58
 
50
59
  # Sorts the internal data by setting name and serializes it in the xcconfig
@@ -55,23 +64,32 @@ module Xcodeproj
55
64
  # config = Config.new('PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2')
56
65
  # config.to_s # => "OTHER_LDFLAGS = -lxml2\nPODS_ROOT = \"$(SRCROOT)/Pods\""
57
66
  #
58
- # @return [String] The serialized internal data.
67
+ # @return [String] The serialized internal data.
68
+ #
59
69
  def to_s
60
70
  to_hash.sort_by(&:first).map { |k, v| "#{k} = #{v}" }.join("\n")
61
71
  end
62
72
 
63
- # @return [void] Writes the serialized representation of the internal data
64
- # to the given path.
73
+ # Writes the serialized representation of the internal data to the given
74
+ # path.
65
75
  #
66
- # @param [Pathname] pathname The file that the data should be written to.
76
+ # @param [Pathname] pathname
77
+ # The file where the data should be written to.
78
+ #
79
+ # @return [void]
67
80
  #
68
81
  def save_as(pathname)
69
82
  pathname.open('w') { |file| file << to_s }
70
83
  end
71
84
 
72
- # @return [Hash] The hash reppresentation of the framework. The hash
73
- # includes the frameworks, the weak frameworks and the libraries in the
74
- # `Other Linker Flags` (`OTHER_LDFLAGS`).
85
+ # The hash representation of the xcconfig. The hash includes the
86
+ # frameworks, the weak frameworks and the libraries in the `Other Linker
87
+ # Flags` (`OTHER_LDFLAGS`).
88
+ #
89
+ # @note All the values are sorted to have a consistent output in Ruby
90
+ # 1.8.7.
91
+ #
92
+ # @return [Hash] The hash representation
75
93
  #
76
94
  def to_hash
77
95
  hash = @attributes.dup
@@ -87,12 +105,11 @@ module Xcodeproj
87
105
 
88
106
  #-------------------------------------------------------------------------#
89
107
 
108
+ public
109
+
90
110
  # @!group Merging
91
111
 
92
- # Merges the given xcconfig hash or Config into the internal data.
93
- #
94
- # If a key in the given hash already exists in the internal data then its
95
- # value is appended to the value in the internal data.
112
+ # Merges the given xcconfig representation in the receiver.
96
113
  #
97
114
  # @example
98
115
  #
@@ -100,7 +117,16 @@ module Xcodeproj
100
117
  # config.merge!('OTHER_LDFLAGS' => '-lz', 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers"')
101
118
  # config.to_hash # => { 'PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2 -lz', 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers"' }
102
119
  #
103
- # @param [Hash, Config] xcconfig The data to merge into the internal data.
120
+ # @note If a key in the given hash already exists in the internal data
121
+ # then its value is appended.
122
+ #
123
+ # @param [Hash, Config] config
124
+ # The xcconfig representation to merge.
125
+ #
126
+ # @todo The logic to normalize an hash should be extracted and the
127
+ # initializer should not call this method.
128
+ #
129
+ # @return [void]
104
130
  #
105
131
  def merge!(xcconfig)
106
132
  if xcconfig.is_a? Config
@@ -110,7 +136,8 @@ module Xcodeproj
110
136
  @weak_frameworks.merge(xcconfig.weak_frameworks)
111
137
  else
112
138
  @attributes.merge!(xcconfig.to_hash) { |key, v1, v2| "#{v1} #{v2}" }
113
- # Parse frameworks and libraries. Then remove the from the linker flags
139
+ # Parse frameworks and libraries. Then remove them from the linker
140
+ # flags
114
141
  flags = @attributes['OTHER_LDFLAGS']
115
142
  return unless flags
116
143
 
@@ -130,45 +157,57 @@ module Xcodeproj
130
157
  end
131
158
  alias_method :<<, :merge!
132
159
 
160
+ # Creates a new #{Config} with the data of the receiver merged with the
161
+ # given xcconfig representation.
162
+ #
163
+ # @param [Hash, Config] config
164
+ # The xcconfig representation to merge.
165
+ #
166
+ # @return [Config] the new xcconfig.
167
+ #
133
168
  def merge(config)
134
169
  self.dup.tap { |x| x.merge!(config) }
135
170
  end
136
171
 
172
+ # @return [Config] A copy of the receiver.
173
+ #
137
174
  def dup
138
175
  Xcodeproj::Config.new(self.to_hash.dup)
139
176
  end
140
177
 
141
178
  #-------------------------------------------------------------------------#
142
179
 
143
- # @!group Object methods
144
-
145
- def inspect
146
- to_hash.inspect
147
- end
148
-
149
- def ==(other)
150
- other.respond_to?(:to_hash) && other.to_hash == self.to_hash
151
- end
152
-
153
- #-------------------------------------------------------------------------#
180
+ private
154
181
 
155
182
  # @!group Private Helpers
156
183
 
157
- private
158
-
184
+ # Returns a hash from the given argument reading it from disk if necessary.
185
+ #
186
+ # @param [String, Pathname, Hash] argument
187
+ # The source from where the hash should be extracted.
188
+ #
189
+ # @return [Hash]
190
+ #
159
191
  def extract_hash(argument)
160
192
  if argument.respond_to? :read
161
193
  hash_from_file_content(argument.read)
162
- elsif File.readable? argument.to_s
194
+ elsif File.readable?(argument.to_s)
163
195
  hash_from_file_content(File.read(argument))
164
196
  else
165
197
  argument
166
198
  end
167
199
  end
168
200
 
169
- def hash_from_file_content(raw_string)
201
+ # Returns a hash from the string representation of an Xcconfig file.
202
+ #
203
+ # @param [String] string
204
+ # The string representation of an xcconfig file.
205
+ #
206
+ # @return [Hash] the hash containing the xcconfig data.
207
+ #
208
+ def hash_from_file_content(string)
170
209
  hash = {}
171
- raw_string.split("\n").each do |line|
210
+ string.split("\n").each do |line|
172
211
  uncommented_line = strip_comment(line)
173
212
  if include = extract_include(uncommented_line)
174
213
  @includes.push include
@@ -180,16 +219,39 @@ module Xcodeproj
180
219
  hash
181
220
  end
182
221
 
222
+ # Strips the comments from a line of an xcconfig string.
223
+ #
224
+ # @param [String] line
225
+ # the line to process.
226
+ #
227
+ # @return [String] the uncommented line.
228
+ #
183
229
  def strip_comment(line)
184
230
  line.partition('//').first
185
231
  end
186
232
 
233
+ # Returns the file included by a line of an xcconfig string if present.
234
+ #
235
+ # @param [String] line
236
+ # the line to process.
237
+ #
238
+ # @return [String] the included file.
239
+ # @return [Nil] if no include was found in the line.
240
+ #
187
241
  def extract_include(line)
188
242
  regexp = /#include\s*"(.+)"/
189
243
  match = line.match(regexp)
190
244
  match[1] if match
191
245
  end
192
246
 
247
+ # Returns the key and the value described by the given line of an xcconfig.
248
+ #
249
+ # @param [String] line
250
+ # the line to process.
251
+ #
252
+ # @return [Array] A tuple where the first entry is the key and the second
253
+ # entry is the value.
254
+ #
193
255
  def extract_key_value(line)
194
256
  key, value = line.split('=', 2)
195
257
  if key && value
@@ -199,5 +261,7 @@ module Xcodeproj
199
261
  end
200
262
  end
201
263
 
264
+ #-------------------------------------------------------------------------#
265
+
202
266
  end
203
267
  end
@@ -4,23 +4,23 @@ module Xcodeproj
4
4
  #
5
5
  module Constants
6
6
 
7
- # The last known iOS SDK (stable).
7
+ # @return [String] The last known iOS SDK (stable).
8
8
  #
9
- LAST_KNOWN_IOS_SDK = '6.0'
9
+ LAST_KNOWN_IOS_SDK = '6.1'
10
10
 
11
- # The last known OS X SDK (stable).
11
+ # @return [String] The last known OS X SDK (stable).
12
12
  #
13
13
  LAST_KNOWN_OSX_SDK = '10.8'
14
14
 
15
- # The last known archive version to Xcodeproj.
15
+ # @return [String] The last known archive version to Xcodeproj.
16
16
  #
17
17
  LAST_KNOWN_ARCHIVE_VERSION = 1
18
18
 
19
- # The last known object version to Xcodeproj.
19
+ # @return [String] The last known object version to Xcodeproj.
20
20
  #
21
21
  LAST_KNOWN_OBJECT_VERSION = 46
22
22
 
23
- # The all the known ISAs grouped by superclass.
23
+ # @return [Hash] The all the known ISAs grouped by superclass.
24
24
  #
25
25
  KNOWN_ISAS = {
26
26
  'AbstractObject' => %w[
@@ -58,11 +58,11 @@ module Xcodeproj
58
58
  ]
59
59
  }.freeze
60
60
 
61
- # The list of the super classes for each ISA.
61
+ # @return [Array] The list of the super classes for each ISA.
62
62
  #
63
63
  ISAS_SUPER_CLASSES = %w[ AbstractObject AbstractBuildPhase PBXGroup ]
64
64
 
65
- # The known file types corresponding to each extension.
65
+ # @return [Hash] The known file types corresponding to each extension.
66
66
  #
67
67
  FILE_TYPES_BY_EXTENSION = {
68
68
  'a' => 'archive.ar',
@@ -75,7 +75,7 @@ module Xcodeproj
75
75
  'xcdatamodel' => 'wrapper.xcdatamodel',
76
76
  }.freeze
77
77
 
78
- # The uniform type identifier of various product types.
78
+ # @return [Hash] The uniform type identifier of various product types.
79
79
  #
80
80
  PRODUCT_TYPE_UTI = {
81
81
  :application => 'com.apple.product-type.application',
@@ -83,8 +83,8 @@ module Xcodeproj
83
83
  :static_library => 'com.apple.product-type.library.static',
84
84
  }.freeze
85
85
 
86
- # The common build settings grouped by platform, and build configuration
87
- # name.
86
+ # @return [Hash] The common build settings grouped by platform, and build
87
+ # configuration name.
88
88
  #
89
89
  COMMON_BUILD_SETTINGS = {
90
90
  :all => {
@@ -107,7 +107,8 @@ module Xcodeproj
107
107
  'COPY_PHASE_STRIP' => 'NO',
108
108
  }.freeze,
109
109
  :release => {
110
- # Empty?
110
+ 'OTHER_CFLAGS' => '-DNS_BLOCK_ASSERTIONS=1',
111
+ 'OTHER_CPLUSPLUSFLAGS' => '-DNS_BLOCK_ASSERTIONS=1',
111
112
  }.freeze,
112
113
  :ios => {
113
114
  'ARCHS' => "$(ARCHS_STANDARD_32_BIT)",
@@ -137,7 +138,8 @@ module Xcodeproj
137
138
  }.freeze,
138
139
  }.freeze
139
140
 
140
- # The corresponding numeric value of each copy build phase destination.
141
+ # @return [Hash] The corresponding numeric value of each copy build phase
142
+ # destination.
141
143
  #
142
144
  COPY_FILES_BUILD_PHASE_DESTINATIONS = {
143
145
  :absolute_path => '0',
@@ -152,7 +154,7 @@ module Xcodeproj
152
154
  :plug_ins => '13'
153
155
  }.freeze
154
156
 
155
- # The extensions which are associated with header files
157
+ # @return [Hash] The extensions which are associated with header files.
156
158
  #
157
159
  HEADER_FILES_EXTENSIONS = %w| .h .hh .hpp |.freeze
158
160
 
@@ -0,0 +1,243 @@
1
+ module Xcodeproj
2
+
3
+ # Computes the recursive diff of Hashes, Array and other objects.
4
+ #
5
+ # Useful to compare two projects. Inspired from
6
+ # 'active_support/core_ext/hash/diff'.
7
+ #
8
+ # @example
9
+ # h1 = { :common => 'value', :changed => 'v1' }
10
+ # h2 = { :common => 'value', :changed => 'v2', :addition => 'new_value' }
11
+ # h1.recursive_diff(h2) == {
12
+ # :changed => {
13
+ # :self => 'v1',
14
+ # :other => 'v2'
15
+ # },
16
+ # :addition => {
17
+ # :self => nil,
18
+ # :other => 'new_value'
19
+ # }
20
+ # } #=> true
21
+ #
22
+ #
23
+ #
24
+ #
25
+ module Differ
26
+
27
+ # Computes the recursive difference of two given values.
28
+ #
29
+ # @param [Object] value_1
30
+ # The first value to compare.
31
+ #
32
+ # @param [Object] value_2
33
+ # The second value to compare.
34
+ #
35
+ # @param [Object] key_1
36
+ # The key for the diff of value_1.
37
+ #
38
+ # @param [Object] key_2
39
+ # The key for the diff of value_2.
40
+ #
41
+ # @param [Object] id_key
42
+ # The key used to identify correspondent hashes in an array.
43
+ #
44
+ # @return [Hash] The diff
45
+ # @return [Nil] if the given values are equal.
46
+ #
47
+ def self.diff(value_1, value_2, options = {})
48
+ options[:key_1] ||= 'value_1'
49
+ options[:key_2] ||= 'value_2'
50
+ options[:id_key] ||= nil
51
+
52
+ if value_1.class == value_2.class
53
+ method = case value_1
54
+ when Hash then :hash_diff
55
+ when Array then :array_diff
56
+ else :generic_diff
57
+ end
58
+ else
59
+ method = :generic_diff
60
+ end
61
+ self.send(method, value_1, value_2, options)
62
+ end
63
+
64
+ # Optimized for reducing the noise from the tree hash of projects
65
+ #
66
+ def self.project_diff(project_1, project_2, key_1 = 'project_1', key_2 = 'project_2')
67
+ project_1 = project_1.to_tree_hash unless project_1.is_a?(Hash)
68
+ project_2 = project_2.to_tree_hash unless project_2.is_a?(Hash)
69
+ options = {
70
+ :key_1 => key_1,
71
+ :key_2 => key_2,
72
+ :id_key => 'displayName',
73
+ }
74
+ diff(project_1, project_2, options)
75
+ end
76
+
77
+ #-------------------------------------------------------------------------#
78
+
79
+ public
80
+
81
+ # @!group Type specific handlers
82
+
83
+ # Computes the recursive difference of two hashes.
84
+ #
85
+ # @see diff
86
+ #
87
+ def self.hash_diff(value_1, value_2, options)
88
+ ensure_class(value_1, Hash)
89
+ ensure_class(value_2, Hash)
90
+ return nil if value_1 == value_2
91
+
92
+ result = {}
93
+ all_keys = (value_1.keys + value_2.keys).uniq
94
+ all_keys.each do |key|
95
+ key_value_1 = value_1[key]
96
+ key_value_2 = value_2[key]
97
+ diff = diff(key_value_1, key_value_2, options)
98
+ if diff
99
+ result[key] = diff if diff
100
+ end
101
+ end
102
+ if result.empty?
103
+ nil
104
+ else
105
+ result
106
+ end
107
+ end
108
+
109
+ # Returns the recursive diff of two arrays.
110
+ #
111
+ # @see diff
112
+ #
113
+ def self.array_diff(value_1, value_2, options)
114
+ ensure_class(value_1, Array)
115
+ ensure_class(value_2, Array)
116
+ return nil if value_1 == value_2
117
+
118
+ new_objects_value_1 = (value_1 - value_2)
119
+ new_objects_value_2 = (value_2 - value_1)
120
+ return nil if value_1.empty? && value_2.empty?
121
+
122
+ matched_diff = {}
123
+ if id_key = options[:id_key]
124
+ matched_value_1 = []
125
+ matched_value_2 = []
126
+ new_objects_value_1.each do |entry_value_1|
127
+ if entry_value_1.is_a?(Hash)
128
+ id_value = entry_value_1[id_key]
129
+ entry_value_2 = new_objects_value_2.find do |entry|
130
+ entry[id_key] == id_value
131
+ end
132
+ if entry_value_2
133
+ matched_value_1 << entry_value_1
134
+ matched_value_2 << entry_value_2
135
+ diff = diff(entry_value_1, entry_value_2, options)
136
+ matched_diff[id_value] = diff if diff
137
+ end
138
+ end
139
+ end
140
+
141
+ new_objects_value_1 = new_objects_value_1 - matched_value_1
142
+ new_objects_value_2 = new_objects_value_2 - matched_value_2
143
+ end
144
+
145
+ if new_objects_value_1.empty? && new_objects_value_2.empty?
146
+ if matched_diff.empty?
147
+ nil
148
+ else
149
+ matched_diff
150
+ end
151
+ else
152
+ result = {}
153
+ result[options[:key_1]] = new_objects_value_1 unless new_objects_value_1.empty?
154
+ result[options[:key_2]] = new_objects_value_2 unless new_objects_value_2.empty?
155
+ result[:diff] = matched_diff unless matched_diff.empty?
156
+ result
157
+ end
158
+ end
159
+
160
+ # Returns the diff of two generic objects.
161
+ #
162
+ # @see diff
163
+ #
164
+ def self.generic_diff(value_1, value_2, options)
165
+ return nil if value_1 == value_2
166
+
167
+ {
168
+ options[:key_1] => value_1,
169
+ options[:key_2] => value_2
170
+ }
171
+ end
172
+
173
+ #-------------------------------------------------------------------------#
174
+
175
+ public
176
+
177
+ # @!group Cleaning
178
+
179
+ # Returns a copy of the hash where the given key is removed recursively.
180
+ #
181
+ # @param [Hash] hash
182
+ # The hash to clean
183
+ #
184
+ # @param [Object] key
185
+ # The key to remove.
186
+ #
187
+ # @return [Hash] A copy of the hash without the key.
188
+ #
189
+ def self.clean_hash(hash, key)
190
+ new_hash = hash.dup
191
+ self.clean_hash!(new_hash, key)
192
+ new_hash
193
+ end
194
+
195
+ # Recursively cleans a key from the given hash.
196
+ #
197
+ # @param [Hash] hash
198
+ # The hash to clean
199
+ #
200
+ # @param [Object] key
201
+ # The key to remove.
202
+ #
203
+ # @return [void]
204
+ #
205
+ def self.clean_hash!(hash, key)
206
+ hash.delete(key)
207
+ hash.each do |_, value|
208
+ case value
209
+ when Hash
210
+ clean_hash!(value, key)
211
+ when Array
212
+ value.each { |entry| clean_hash!(entry, key) if entry.is_a?(Hash)}
213
+ end
214
+ end
215
+ end
216
+
217
+ #-------------------------------------------------------------------------#
218
+
219
+ private
220
+
221
+ # @! Helpers
222
+
223
+ # Ensures that the given object belongs to the given class.
224
+ #
225
+ # @param [Object] object
226
+ # The object to check.
227
+ #
228
+ # @param [Class] klass
229
+ # the expected class of the object.
230
+ #
231
+ # @raise If the object doesn't belong to the given class.
232
+ #
233
+ # @return [void]
234
+ #
235
+ def self.ensure_class(object, klass)
236
+ raise "Wrong type `#{object.inspect}`" unless object.is_a?(klass)
237
+ end
238
+
239
+ #-------------------------------------------------------------------------#
240
+
241
+ end
242
+ end
243
+