xcodeproj 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+