Class: Plist4r::Plist

Defined in:
lib/plist4r/plist.rb

Instance Methods

Overview

See README and InfoPlistExample for usage examples. Also see EditingPlistFiles

Constant Summary

OptionsHash =

Recognised keys of the options hash. Passed when instantiating a new Plist Object

%w[filename path file_format plist_type strict_keys backends from_string]
FileFormats =

The plist file formats, written as symbols.

See Also:

%w[binary xml gnustep]

Constructor Details

- (Plist4r::Plist) initialize(*args) { ... }

Instantiate a new Plist4r::Plist object. We usually set our per-application defaults in Plist4r::Config beforehand.

Examples:

Create new, empty plist

Plist4r::Plist.new => #<Plist4r::Plist:0x111546c @file_format=nil, ...>

Load from file

Plist4r::Plist.new("example.plist") => #<Plist4r::Plist:0x1152d1c @file_format="xml", ...>

Load from string

plist_string = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }"
Plist4r::Plist.new({ :from_string => plist_string })
=> #<Plist4r::Plist:0x11e161c @file_format="xml", ...>

Advanced options

plist_working_dir = `pwd`.strip
Plist4r::Plist.new({ :filename => "example.plist", :path => plist_working_dir, :backends => ["libxml4r","ruby_cocoa"]})
=> #<Plist4r::Plist:0x111546c @file_format=nil, ...>

Parameters:

  • (String) filename
  • (Hash) options
    • for advanced usage

Yields:

  • An optional block to instance_eval &blk, and apply an edit on creation



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/plist4r/plist.rb', line 39

def initialize *args, &blk
  @hash             = ::Plist4r::OrderedHash.new
  plist_type :plist

  @strict_keys = Config[:strict_keys]
  @backends         = Config[:backends]

  @from_string      = nil
  @filename         = nil
  @file_format      = nil
  @path             = Config[:default_path]

  case args.first
  when Hash
    parse_opts args.first

  when String, Symbol
    @filename = args.first.to_s
  when nil
  else
    raise "Unrecognized first argument: #{args.first.inspect}"
  end
  
  @plist_cache ||= PlistCache.new self

  edit(&blk) if block_given?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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

Pass down unknown method calls to the selected plist_type, to set or return plist keys. All plist data manipulation API is called through method_missing -> PlistType -> DataMethods.

Examples:

This will actually call Plist4r::DataMethods#method_missing

plist.store "CFBundleVersion" "0.1.0"

See Also:



337
338
339
# File 'lib/plist4r/plist.rb', line 337

def method_missing method_sym, *args, &blk
  eval "@plist_type.#{method_sym} *args, &blk"
end

Instance Method Details

- (Object) <<(*args, &blk)

An alias of #edit

Examples:

plist.<< do
  store "PFReleaseVersion" "0.1.1"
end

See Also:



304
305
306
# File 'lib/plist4r/plist.rb', line 304

def << *args, &blk
  edit *args, &blk
end

- (Object) [](key)

Element Reference — Retrieve the value object corresponding to the key object. If not found, returns nil

Examples:

plist["CFBundleIdentifier"]   # => "com.apple.myapp"

plist[:c_f_bundle_identifier] # => "com.apple.myapp"

Parameters:

  • (Symbol, String) key

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

Returns:

  • The value associated with the plist key



363
364
365
# File 'lib/plist4r/plist.rb', line 363

def [] key
  @plist_type.set_or_return key
end

- (Object) []=(key, value)

Element Assignment — Assign a value to the given plist key

Examples:

plist["CFBundleIdentifier"]   = "com.apple.myapp"

plist[:c_f_bundle_identifier] = "com.apple.myapp"

Parameters:

  • (Symbol, String) key

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

  • value

    The value to store under the plist key name



375
376
377
# File 'lib/plist4r/plist.rb', line 375

def []= key, value
  store key, value
end

- (Array <Symbol>) backends(backends = nil)

An array of strings, symbols or class names which correspond to the active Plist4r::Backends for this object. The priority order in which backends are executed is determined by the in sequence array order.

Examples:

plist.backends [:haml, :ruby_cocoa]

Parameters:

  • (Array <Symbol,String>) A

    new list of backends to use, in Priority order

Returns:

  • (Array <Symbol>)

    The plist’s backends, each written as a symbol. Must be a sublcass of Plist4r::Backend Defaults to Plist4r::Config[:backends]

See Also:



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/plist4r/plist.rb', line 252

def backends backends=nil
  case backends
  when Array
    @backends = backends.collect do |b| 
      case b
      when Symbol, String
        eval "Plist4r::Backend::#{b.to_s.camelcase}"
        b.to_sym
      when nil
      else
        raise "Backend #{b.inspect} is of unsupported type: #{b.class}"
      end
    end
  when nil
    @backends
  else
    raise "Please specify an array of valid Plist4r Backends"
  end
end

- (Object) clear

Clears all plist keys and their contents

Examples:

plist.clear
plist.size # => 0


477
478
479
# File 'lib/plist4r/plist.rb', line 477

def clear
  @plist_type.array_dict :unselect_all
end

- (Object) collect(&blk)

Alias for #map



440
441
442
# File 'lib/plist4r/plist.rb', line 440

def collect &blk
  map &blk
end

- (Object) delete(*keys)

Delete plist keys from the object.

Examples:

plist.delete :c_f_bundle_identifier

Parameters:

  • (Array, *args) keys

    The list of Plist Keys to delete unconditionally. Can be an array, or argument list Key names can be given as either snake_case’d Symbol or camelcased String



454
455
456
# File 'lib/plist4r/plist.rb', line 454

def delete *keys
  @plist_type.array_dict :unselect, *keys
end

- (Object) delete_if(*keys) { ... }

Conditionally delete plist keys from the object.

Examples:

plist.delete_if "CFBundleIdentifier"

plist.delete_if { |k,v| k.length > 20 }

plist.delete_if { |k,v| k =~ /Identifier/ }

Parameters:

  • (Array, *args) keys

    The list of Plist Keys to delete unconditionally. Can be an array, or argument list

Yields:

  • Delete a key-value pair if block evaluates to true.



467
468
469
470
471
# File 'lib/plist4r/plist.rb', line 467

def delete_if *keys, &blk
  delete *keys
  @hash.delete_if &blk
  @plist_type.to_hash @hash
end

- (Object) detect_plist_type

Called automatically on plist load / instantiation. This method detects the “Plist Type”, using an algorithm that stats the plist data. The plist types with the highest stat (score) is chosen to be the object’s “Plist Type”.

Returns:

  • The plist’s known type, written as a symbol. Will be a sublcass of Plist4r::PlistType. Defaults to :plist

See Also:



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/plist4r/plist.rb', line 166

def detect_plist_type
  stat_m = {}
  stat_r = {}
  Config[:types].each do |t|
    case t
    when String, Symbol
      t = eval "::Plist4r::PlistType::#{t.to_s.camelcase}"
    when Class
      t = t
    when nil
    else
      raise "Unrecognized plist type: #{t.inspect}"
    end
    t_sym = t.to_s.gsub(/.*:/,"").snake_case.to_sym
    stat_t = t.match_stat @hash.keys

    stat_m.store stat_t[:matches], t_sym
    stat_r.store stat_t[:ratio], t_sym
  end

  most_matches = stat_m.keys.sort.last      
  if most_matches == 0
    plist_type :plist
  elsif stat_m.keys.select{ |m| m == most_matches }.size > 1
    most_matches = stat_r.keys.sort.last          
    if stat_r.keys.select{ |m| m == most_matches }.size > 1
      plist_type :plist
    else
      plist_type stat_r[most_matches]
    end
  else
    plist_type stat_m[most_matches]
  end
end

- (Object) each { ... }

This is equivalent to the ruby core classes method Hash#each

Examples:

plist.each do |k,v|
  puts "key = #{k.inspect}, value = #{v.inspect}"
end

Yields:

  • A block to execute for each key, value pair in plist



523
524
525
# File 'lib/plist4r/plist.rb', line 523

def each &blk
  @hash.each &blk
end

- (Object) edit(*args, &blk)

Edit a plist object. Set or return plist keys. Add or remove a selection of keys. Plist key accessor methods are snake-cased versions of the key string.

Examples:

Edit some keys and values with #[] and #store

plist.edit do
  store "PFInstance" "4982394823"
  store "PFReleaseVersion" "0.1.1"
end

plist.edit do
  new_ver = self["PFReleaseVersion"] + 0.1
  store "PFReleaseVersion" new_ver
end

Edit with implicit methods. Calls method_missing()

plist.edit do
  new_ver = p_f_release_version + 0.1
  p_f_release_version(new_ver)
end


325
326
327
328
329
# File 'lib/plist4r/plist.rb', line 325

def edit *args, &blk
  @plist_type.to_hash @hash
  instance_eval *args, &blk
  detect_plist_type if plist_type == :plist
end

- (Boolean) empty?

This is equivalent to the ruby core classes method Array#empty?

Returns:

  • (Boolean)


513
514
515
# File 'lib/plist4r/plist.rb', line 513

def empty?
  @hash.empty?
end

- (Object) file_format(file_format = nil)

The file format of the plist file we are loading / saving. Written as a symbol. One of FileFormats. Defaults to :xml

Parameters:

  • (Symbol, String) file_format (defaults to: nil)

    Can be :binary, :xml, :gnustep

Returns:

  • The file format associated to this current plist object

See Also:



146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/plist4r/plist.rb', line 146

def file_format file_format=nil
  case file_format
  when Symbol, String
    if FileFormats.include? file_format.to_s.snake_case
      @file_format = file_format.to_s.snake_case
    else
      raise "Unrecognized plist file format: \"#{file_format.inspect}\". Please specify a valid plist file format, #{FileFormats.inspect}"
    end
  when nil
    @file_format
  else
    raise "Please specify a valid plist file format, #{FileFormats.inspect}"
  end
end

- (Object) filename(filename = nil)

Set or return the filename attribute of the plist object. Used in cojunction with the #path attribute

Parameters:

  • (String) filename (defaults to: nil)

    either a relative path or absolute

Returns:

  • The plist’s filename

See Also:



97
98
99
100
101
102
103
104
105
106
# File 'lib/plist4r/plist.rb', line 97

def filename filename=nil
  case filename
  when String
    @filename = filename
  when nil
    @filename
  else
    raise "Please specify a filename"
  end
end

- (Object) filename_path(filename_path = nil)

Set or return the combined filename+path. We use this method in the backends api as the full path to load / save

Parameters:

  • (String) filename_path (defaults to: nil)

    concactenation of both filename and path elements. Also sets the @filename and @path attributes

Returns:

  • the full, expanded path to the plist file

See Also:

  • filename
  • path


129
130
131
132
133
134
135
136
137
138
139
# File 'lib/plist4r/plist.rb', line 129

def filename_path filename_path=nil
  case filename_path
  when String
    @filename = File.basename filename_path
    @path     = File.dirname  filename_path
  when nil
    File.expand_path @filename, @path    
  else
    raise "Please specify directory + filename"
  end
end

- (Object) from_string(string = nil)

Reinitialize plist object from string (overwrites the current contents). Usually called from #initialize plist.from_string “{ \“key1\” = \“value1\”; \“key2\” = \“value2\”; }“

 => #<Plist4r::Plist:0x11e161c @file_format="gnustep", ...>

Examples:

Load from string

plist = Plist4r::Plist.new
=> #<Plist4r::Plist:0x11e161c @file_format=nil, ...>


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/plist4r/plist.rb', line 73

def from_string string=nil
  case string
  when String
    plist_format = Plist4r.string_detect_format(string)
    if plist_format
      @from_string = string
      @plist_cache ||= PlistCache.new self
      @plist_cache.from_string
    else
      raise "Unknown plist format for string: #{string}"
    end
  when nil
    @from_string
  else
    raise "Please specify a string of plist data"
  end
end

- (true, false) has_key?(key)

Alias of #include?

Parameters:

  • (String, Symbol) key

    The plist key name

Returns:

  • (true, false)

    True if the plist has the specified key



507
508
509
510
# File 'lib/plist4r/plist.rb', line 507

def has_key? key
  key.to_s.camelcase if key.class == Symbol
  @hash.has_key? key
end

- (Object) import_hash(hash = nil)

Backend method to set or return all new plist data resulting from a backend API. Used in load operations.

Parameters:

  • (Plist4r::OrderedHash, nil) hash (defaults to: nil)

    sets the new root object. Replaces all previous plist data.

Returns:

  • If no argument given, then clears all plist data, returning the new @hash root object

See Also:



345
346
347
348
349
350
351
352
353
354
# File 'lib/plist4r/plist.rb', line 345

def import_hash hash=nil
  case hash
  when Plist4r::OrderedHash
    @hash = hash
  when nil
    @hash = ::Plist4r::OrderedHash.new
  else
    raise "Please use Plist4r::OrderedHash.new for your hashes"
  end
end

- (true, false) include?(key)

Check if key exists in plist This is equivalent to the ruby core classes method Hash#include?

Parameters:

  • (String, Symbol) key

    The plist key name

Returns:

  • (true, false)

    True if the plist has the specified key



499
500
501
502
# File 'lib/plist4r/plist.rb', line 499

def include? key
  key.to_s.camelcase if key.class == Symbol
  @hash.include? key
end

- (Array <String, Symbol>) keys

This is equivalent to the ruby core classes method Hash#keys

Examples:

plist.keys # => ["Key1", "Key2", "Key3", "etc.."]

Returns:



544
545
546
# File 'lib/plist4r/plist.rb', line 544

def keys
  @hash.keys
end

- (Object) length

This is equivalent to the ruby core classes method Array#length

Examples:

plist.length # => 14


530
531
532
# File 'lib/plist4r/plist.rb', line 530

def length
  @hash.length
end

- (Object) map { ... }

Invokes block &blk once for each key-value pair in plist. Similar to the ruby core classes Array#map. Replaces the plist keys and values with the [key,value] pairs returned by &blk.

Yields:

  • For each iteration of the block, must return a 2-element Array which is a [key,value] pair to replace the original [key,value] pair from the plist. Key names can be given as either snake_case’d Symbol or camelcased String



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
# File 'lib/plist4r/plist.rb', line 419

def map &blk
  if block_given?
    old_hash = @hash.deep_clone
    clear

    old_hash.each do |k,v|
      pair = yield k,v
      case pair
      when Array
        store pair[0], pair[1]
      when nil
      else
        raise "The supplied block must return plist [key, value] pairs, or nil"
      end
    end
  else
    raise "No block given"
  end
end

- (Object) merge!(other_plist)

Merge together plist objects. Adds the contents of other_plist to the current object, overwriting any entries of the same key name with those from other_plist. Other attributes (filename, plist_type, file_format, etc) remain unaffected

Parameters:



485
486
487
488
489
490
491
492
493
# File 'lib/plist4r/plist.rb', line 485

def merge! other_plist
  if plist_type == other_plist.plist_type
    @hash.merge! other_plist.to_hash
    @plist_type.to_hash @hash
  else
    raise "plist_type differs, one is #{plist_type.inspect}, and the other is #{plist.plist_type.inspect}"
  end
  self
end

- (Plist4r::Plist) open(filename = nil)

Opens a plist file

Examples:

Load from file

plist = Plist4r.new
plist.open("example.plist") => #<Plist4r::Plist:0x1152d1c @file_format="xml", ...>

Parameters:

  • (String) filename (defaults to: nil)

    plist file to load. Uses the #filename attribute when nil

Returns:



292
293
294
295
296
# File 'lib/plist4r/plist.rb', line 292

def open filename=nil
  @filename = filename if filename
  raise "No filename specified" unless @filename
  @plist_cache.open
end

- (Object) parse_opts(opts)

Sets up those valid (settable) plist attributes as found the options hash. Normally we dont call this method directly. Called from #initialize.

Parameters:

See Also:



276
277
278
279
280
281
282
283
# File 'lib/plist4r/plist.rb', line 276

def parse_opts opts
  OptionsHash.each do |opt|
    if opts[opt.to_sym]
      value = opts[opt.to_sym]
      self.send opt, value
    end
  end
end

- (Object) path(path = nil)

Set or return the path attribute of the plist object. Pre-pended to the plist’s filename (if filename is path-relative)

Parameters:

  • (String) path (defaults to: nil)

    (must be an absolute pathname)

Returns:

  • The plist’s working path

See Also:



112
113
114
115
116
117
118
119
120
121
# File 'lib/plist4r/plist.rb', line 112

def path path=nil
  case path
  when String
    @path = path
  when nil
    @path
  else
    raise "Please specify a directory"
  end
end

- (Object) plist_type(plist_type = nil)

Set or return the plist_type of the current object. We can use this to override the automatic type detection.

Parameters:

  • (Symbol, String) plist_type.

    Must be a sublcass of Type

Returns:

  • The plist’s known type, written as a symbol. Will be a sublcass of Plist4r::PlistType. Defaults to :plist

See Also:



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/plist4r/plist.rb', line 206

def plist_type plist_type=nil
  begin
    case plist_type
    when Class
      # unless plist_type.is_a? ::Plist4r::PlistType # .is_a? returns false in spec
      unless plist_type.ancestors.include? Plist4r::PlistType
        raise "Unrecognized Plist type. Class #{plist_type.inspect} isnt inherited from ::Plist4r::PlistType"
      end
    when Symbol, String
      plist_type = eval "::Plist4r::PlistType::#{plist_type.to_s.camelcase}"
    when nil
      return @plist_type.to_sym
    else
      raise "Please specify a valid plist class name, eg ::Plist4r::PlistType::ClassName, \"class_name\" or :class_name"
    end
    @plist_type = plist_type.new self
    return @plist_type.to_sym
  rescue
    raise "Please specify a valid plist class name, eg ::Plist4r::PlistType::ClassName, \"class_name\" or :class_name"
  end
end

- (Object) save

Save plist to #filename_path

Raises:

  • (RuntimeError)

    if the #filename attribute is nil

See Also:



607
608
609
610
# File 'lib/plist4r/plist.rb', line 607

def save
  raise "No filename specified" unless @filename
  @plist_cache.save
end

- (Object) save_as(filename)

Save the plist under a new filename

Parameters:

  • (String) filename

    The new file name to save as. If relative, will be appended to #path

See Also:



615
616
617
618
# File 'lib/plist4r/plist.rb', line 615

def save_as filename
  @filename = filename
  save
end

- (Object) select(*keys) { ... }

Element selection - Keep selected plist keys and discard others.

Parameters:

  • (Array, *args) keys

    List of Plist Keys to keep. Can be an array, or method argument list

Yields:

  • Keep every key-value pair for which the passed block evaluates to true. Works as per the ruby core classes Hash#select method



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/plist4r/plist.rb', line 393

def select *keys, &blk
  if block_given?
    selection = @hash.select &blk
    old_hash = @hash.deep_clone
    clear
    if RUBY_VERSION >= '1.9'
      selection.each do |key,value|
        store key, value
      end
    else
      selection.each do |pair|
        store pair[0], pair[1]
      end
    end
    keys.each do |k|
      store k, old_hash[k]
    end
  else
    @plist_type.array_dict :select, *keys
  end
end

- (Object) size

This is equivalent to the ruby core classes method Array#size

  plist.size # => 14


536
537
538
# File 'lib/plist4r/plist.rb', line 536

def size
  @hash.size
end

- (Object) store(key, value)

Element Assignment — Assign a value to the given plist key

Examples:

plist.store "CFBundleIdentifier",   "com.apple.myapp"

plist.store :c_f_bundle_identifier, "com.apple.myapp"

Parameters:

  • (Symbol, String) key

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

  • value

    The value to store under the plist key name



386
387
388
# File 'lib/plist4r/plist.rb', line 386

def store key, value
  @plist_type.set_or_return key, value
end

- (Object) strict_keys(bool = nil)

Set or return strict_keys mode

Parameters:

  • (true, false) bool (defaults to: nil)

    If true, then raise an error for any unrecognized keys that dont belong to the #plist_type

Returns:

  • The strict_keys setting for this object

See Also:



232
233
234
235
236
237
238
239
240
241
# File 'lib/plist4r/plist.rb', line 232

def strict_keys bool=nil
  case bool
  when true,false
    @strict_keys = bool
  when nil
    @strict_keys
  else
    raise "Please specify true or false to enable / disable this option"
  end
end

- (Object) to_binary

Write out a binary string representation of the plist

Looking for how to store a bytestream in CFData / NSData? See EditingPlistFiles

Examples:

plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
plist.to_binary
=> "bplist00\322\001\002\003\004Tkey2Tkey1Vvalue2Vvalue1\b\r\022\027\036\000\000\000\000\000\000\001\001\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000%"


595
596
597
# File 'lib/plist4r/plist.rb', line 595

def to_binary
  @plist_cache.to_binary
end

- (Object) to_gnustep

We are missing a backend for writing out plist strings in Gnustep / Nextstep / Openstep format. Contributions appreciated.



600
601
602
# File 'lib/plist4r/plist.rb', line 600

def to_gnustep
  @plist_cache.to_gnustep
end

- (Plist4r::OrderedHash) to_hash

The internal data storage object for the plist data

This is a pretty standard (either ActiveSupport or Ruby 1.9) ordered hash. Key names - regular ruby strings of arbitrary length.

Values - Must only store generic Ruby objects data such as TrueClass, FalseClass, Integer, Float, String, Time, Array, Hash, and Data

Data (NSData / CFData) - see EditingPlistFiles

Examples:

plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
plist.to_hash => {"key1"=>"value1", "key2"=>"value2"}

Returns:

See Also:



562
563
564
# File 'lib/plist4r/plist.rb', line 562

def to_hash
  @hash
end

- (String) to_xml

Export the plist to xml string representation. Calls through the plist cache

Examples:

plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
plist.to_xml 
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>key1</key>\n\t<string>value1</string>\n\t<key>key2</key>\n\t<string>value2</string>\n</dict>\n</plist>"

Returns:

  • (String)

    An xml string which represents the entire plist, as would be the plist xml file



583
584
585
# File 'lib/plist4r/plist.rb', line 583

def to_xml
  @plist_cache.to_xml
end

- (Object) unselect(*keys)

Alias for #delete



445
446
447
# File 'lib/plist4r/plist.rb', line 445

def unselect *keys
  delete *keys
end