Module: Plist4r::DataMethods

Included in:
ArrayDict, PlistType
Defined in:
lib/plist4r/mixin/data_methods.rb

Instance Methods

Constant Summary

ClassesForKeyType =

Return those Class constants which the value of a Plist Key must conform to. This is class-based data validation.

{
  :string => [String], 
  :bool => [TrueClass,FalseClass],
  :bool_or_string => [TrueClass,FalseClass,String],
  :integer => [Fixnum], 
  :array_of_strings => [Array],
  :array_of_hashes => [Array],
  :array => [Array],
  :array_or_integer => [Array,Fixnum],
  :array_or_hash => [Array, Hash],
  :hash_of_bools => [Hash],
  :hash_of_strings => [Hash],
  :hash_of_arrays => [Hash],
  :hash_of_arrays_of_strings => [Hash],
  :hash => [Hash],
  :bool_or_hash_of_bools => [TrueClass,FalseClass,Hash],
  :bool_or_string_or_array_of_strings => [TrueClass,FalseClass,String,Array]
}
ValidKeys =

A Hash Array of the supported plist keys for this type. These are only those plist keys recognized as belonging to a specific plist datatype. Used in validation, part of DataMethods. We usually overload this method in subclasses. To see how to use these Plist Keys, go to PlistKeyNames

Examples:

class Plist4r::PlistType::MyPlistType < PlistType
  ValidKeys =
  {
     :string => %w[PlistKeyS1 PlistKeyS2 ...],
     :bool => %w[PlistKeyB1 PlistKeyB2 ...],
     :integer => %w[PlistKeyI1 PlistKeyI2 ...],
     :method_defined => %w[CustomPlistKey1 CustomPlistKey2 ...]
  }
end

plist.plist_type :my_plist_type
plist.plist_key_s1 "some string"
plist.plist_key_b1 true
plist.plist_key_i1 08
plist.custom_plist_key1 MyClass.new(opts)

See Also:

{}
ValidKeysTemplate =

A template for creating new plist types

{
  :string => %w[
    
    ],
  :bool => %w[
    
    ],
  :integer => %w[
    
    ],
  :array_of_strings => %w[
    
    ],
  :array_of_hashes => %w[
    
    ],
  :array => %w[
    
    ],
  :hash_of_bools => %w[
    
    ],
  :hash_of_strings => %w[
    
    ],
  :hash_of_arrays => %w[
    
    ],
  :hash_of_arrays_of_strings => %w[
    
    ],
  :hash => %w[
    
    ],
  :could_be_method_defined   => %w[
    
    ]
}

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

- (Object) method_missing(method_symbol, *args, &blk)

Call #set_or_return with the appropriate arguments. If Plist4r::Plist#strict_keys is enabled, then raise an error on any unrecognised Plist Keys.



102
103
104
# File 'lib/plist4r/mixin/data_methods.rb', line 102

def method_missing method_symbol, *args, &blk
  set_or_return method_symbol.to_s.camelcase, *args, &blk
end

Instance Method Details

- (Boolean) _respond_to?(method_sym)

Defining respond_to? conflicts with rspec 1.3.0. @object.stub() blows up. To as a consequence we dont implement respond_to? for method_missing()

Returns:

  • (Boolean)

    true



96
97
98
# File 'lib/plist4r/mixin/data_methods.rb', line 96

def _respond_to? method_sym
  true
end

- (Object) set_or_return(key, value = nil)

Set or return value data

Parameters:

  • (Symbol, String) key

    The plist key name, either a snake-cased symbol, or literal string

  • (nil, Object) value (defaults to: nil)

    If present, store Object under the plist key “key”. If nil, return the stored object

Returns:

  • The Object stored under key



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/plist4r/mixin/data_methods.rb', line 110

def set_or_return key, value=nil
  key = key.to_s.camelcase if key.class == Symbol

  self.class::ValidKeys.each do |key_type, valid_keys_of_those_type|
    if valid_keys_of_those_type.include?(key)
      return set_or_return_of_type key_type, key, value
    end
  end

  unless @plist.strict_keys
    key_type = nil
    return set_or_return_of_type key_type, key, value
  else
    raise "Unrecognized key for class: #{self.class.inspect}. Tried to set_or_return #{key.inspect}, with: #{value.inspect}"
  end
end

- (Object) set_or_return_of_type(key_type, key, value = nil)

Set or return a plist key, value pair, and verify the value type

Examples:

plist.set_or_return_of_type :string, "CFBundleIdentifier", "com.apple.myapp"

plist.set_or_return_of_type nil, "SomeUnknownKey", [[0],1,2,{ 3 => true}]
# Skips validation

Parameters:

  • (Symbol, nil) key_type

    The type of class which the value of the key must belong to. Used for validity check. If key_type is set to nil, then skip value data check

Returns:

  • the key’s value

See Also:



218
219
220
221
222
223
224
225
226
# File 'lib/plist4r/mixin/data_methods.rb', line 218

def set_or_return_of_type key_type, key, value=nil
  case value
  when nil
    @orig[key]
  else
    validate_value key_type, key, value if ClassesForKeyType.keys.include?(key_type)
    @hash[key] = value
  end
end

- (Object) validate_value(key_type, key, value)

This method is called when setting a value to a plist key. (or some value within a nested plist sub-structure).

Examples:

plist.validate_value :string, "CFBundleIdentifier", "com.apple.myapp"
# => Okay, no error raised
plist.validate_value :string, "CFBundleIdentifier", ["com.apple.myapp"]
# => Raises Class mismatch. Value is of type Array, should be String

Parameters:

  • (Symbol) key_type

    This Symbol is resolved to a class constant, by looking it up in ClassesForKeyType

  • value

    The value to validate. We just check that the value conforms to key_type.

Raises:

  • Class mistmatch

See Also:



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/plist4r/mixin/data_methods.rb', line 137

def validate_value key_type, key, value
  unless ClassesForKeyType[key_type].include?(value.class)
    raise "Key: #{key}, value: #{value.inspect} is of type #{value.class}. Should be: #{ClassesForKeyType[key_type].join ", "}"
  end
  case key_type
  when :array_of_strings, :bool_or_string_or_array_of_strings
    if value.class == Array
      value.each_index do |i|
        unless value[i].class == String
          raise "Element: #{key}[#{i}], value: #{value[i].inspect} is of type #{value[i].class}. Should be: #{ClassesForKeyType[:string].join ", "}"
        end
      end
    end
  when :array_of_hashes
    value.each_index do |i|
      unless value[i].class == Hash
        raise "Element: #{key}[#{i}], value: #{value[i].inspect} is of type #{value[i].class}. Should be: #{ClassesForKeyType[:hash].join ", "}"
      end
    end
  when :hash_of_bools
    value.each do |k,v|
      unless [TrueClass,FalseClass].include? v.class
        raise "Key: #{key}[#{k}], value: #{v.inspect} is of type #{v.class}. Should be: #{ClassesForKeyType[:bool].join ", "}"
      end
    end
  when :hash_of_strings
    value.each do |k,v|
      unless v.class == String
        raise "Key: #{key}[#{k}], value: #{v.inspect} is of type #{v.class}. Should be: #{ClassesForKeyType[:string].join ", "}"
      end
    end
  when :hash_of_arrays
    value.each do |k,v|
      unless v.class == Array
        raise "Key: #{key}[#{k}], value: #{v.inspect} is of type #{v.class}. Should be: #{ClassesForKeyType[:array].join ", "}"
      end
    end
  when :hash_of_arrays_of_strings
    value.each do |k,v|
      unless v.class == Array
        raise "Key: #{key}[#{k}], value: #{v.inspect} is of type #{v.class}. Should be: #{ClassesForKeyType[:array].join ", "}"
      end
      v.each_index do |i|
        unless v[i].class == String
          raise "Element: #{key}[#{k}][#{i}], value: #{v[i].inspect} is of type #{v[i].class}. Should be: #{ClassesForKeyType[:string].join ", "}"
        end
      end
    end
  end
end