plist4r 0.2.1 → 0.2.2
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.
- data/.gitignore +2 -0
- data/.nojekyll +0 -0
- data/.yardopts +1 -0
- data/README.rdoc +18 -23
- data/Rakefile +16 -7
- data/VERSION +1 -1
- data/bin/plist4r +8 -0
- data/lib/plist4r.rb +35 -7
- data/lib/plist4r/application.rb +19 -0
- data/lib/plist4r/backend.rb +23 -2
- data/lib/plist4r/backend/example.rb +45 -4
- data/lib/plist4r/backend/haml.rb +1 -0
- data/lib/plist4r/backend/libxml4r.rb +3 -2
- data/lib/plist4r/backend/plutil.rb +4 -1
- data/lib/plist4r/backend/ruby_cocoa.rb +10 -3
- data/lib/plist4r/commands.rb +61 -0
- data/lib/plist4r/config.rb +21 -1
- data/lib/plist4r/mixin/data_methods.rb +23 -3
- data/lib/plist4r/mixin/mixlib_cli.rb +199 -0
- data/lib/plist4r/mixin/mixlib_config.rb +158 -152
- data/lib/plist4r/mixin/ordered_hash.rb +143 -135
- data/lib/plist4r/mixin/popen4.rb +25 -5
- data/lib/plist4r/mixin/ruby_stdlib.rb +13 -1
- data/lib/plist4r/options.rb +44 -0
- data/lib/plist4r/plist.rb +156 -13
- data/lib/plist4r/plist_type.rb +25 -4
- data/lib/plist4r/plist_type/launchd.rb +377 -263
- data/plist4r.gemspec +56 -48
- data/test.rb +2 -2
- metadata +13 -7
- data/lib/plist4r/mixin/class_attributes.rb +0 -128
@@ -1,169 +1,177 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2005 David Hansson,
|
3
|
-
# Copyright (c) 2007 Mauricio Fernandez, Sam Stephenson
|
4
|
-
# Copyright (c) 2008 Steve Purcell, Josh Peek
|
5
|
-
# Copyright (c) 2009 Christoffer Sawicki
|
6
|
-
#
|
7
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
8
|
-
# a copy of this software and associated documentation files (the
|
9
|
-
# "Software"), to deal in the Software without restriction, including
|
10
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
11
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
13
|
-
# the following conditions:
|
14
|
-
#
|
15
|
-
# The above copyright notice and this permission notice shall be
|
16
|
-
# included in all copies or substantial portions of the Software.
|
17
|
-
#
|
18
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
-
#++
|
26
|
-
|
27
|
-
# OrderedHash is namespaced to prevent conflicts with other implementations
|
28
|
-
module ActiveSupport
|
29
|
-
# Hash is ordered in Ruby 1.9!
|
30
|
-
if RUBY_VERSION >= '1.9'
|
31
|
-
class OrderedHash < ::Hash #:nodoc:
|
32
|
-
end
|
33
|
-
else
|
34
|
-
class OrderedHash < Hash #:nodoc:
|
35
|
-
def initialize(*args, &block)
|
36
|
-
super
|
37
|
-
@keys = []
|
38
|
-
end
|
39
1
|
|
40
|
-
|
41
|
-
|
2
|
+
module Plist4r
|
3
|
+
module ActiveSupport
|
4
|
+
# Hash is ordered in Ruby 1.9!
|
5
|
+
unless RUBY_VERSION >= '1.9'
|
6
|
+
# {ActiveSupport::OrderedHash}
|
7
|
+
#
|
8
|
+
# Copyright (c) 2005 David Hansson,
|
9
|
+
# Copyright (c) 2007 Mauricio Fernandez, Sam Stephenson
|
10
|
+
# Copyright (c) 2008 Steve Purcell, Josh Peek
|
11
|
+
# Copyright (c) 2009 Christoffer Sawicki
|
12
|
+
#
|
13
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
14
|
+
# a copy of this software and associated documentation files (the
|
15
|
+
# "Software"), to deal in the Software without restriction, including
|
16
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
17
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
18
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
19
|
+
# the following conditions:
|
20
|
+
#
|
21
|
+
# The above copyright notice and this permission notice shall be
|
22
|
+
# included in all copies or substantial portions of the Software.
|
23
|
+
#
|
24
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
25
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
26
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
27
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
28
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
29
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
30
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
|
+
#
|
32
|
+
class OrderedHash < Hash
|
33
|
+
def initialize(*args, &block)
|
34
|
+
super
|
35
|
+
@keys = []
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.[](*args)
|
39
|
+
ordered_hash = new
|
42
40
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
if (args.length == 1 && args.first.is_a?(Array))
|
42
|
+
args.first.each do |key_value_pair|
|
43
|
+
next unless (key_value_pair.is_a?(Array))
|
44
|
+
ordered_hash[key_value_pair[0]] = key_value_pair[1]
|
45
|
+
end
|
46
|
+
|
47
|
+
return ordered_hash
|
47
48
|
end
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
unless (args.size % 2 == 0)
|
51
|
+
raise ArgumentError.new("odd number of arguments for Hash")
|
52
|
+
end
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
args.each_with_index do |val, ind|
|
55
|
+
next if (ind % 2 != 0)
|
56
|
+
ordered_hash[val] = args[ind + 1]
|
57
|
+
end
|
55
58
|
|
56
|
-
|
57
|
-
next if (ind % 2 != 0)
|
58
|
-
ordered_hash[val] = args[ind + 1]
|
59
|
+
ordered_hash
|
59
60
|
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
# make a deep copy of keys
|
67
|
-
@keys = other.keys
|
68
|
-
end
|
62
|
+
def initialize_copy(other)
|
63
|
+
super
|
64
|
+
# make a deep copy of keys
|
65
|
+
@keys = other.keys
|
66
|
+
end
|
69
67
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
def []=(key, value)
|
69
|
+
@keys << key if !has_key?(key)
|
70
|
+
super
|
71
|
+
end
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
def delete(key)
|
74
|
+
if has_key? key
|
75
|
+
index = @keys.index(key)
|
76
|
+
@keys.delete_at index
|
77
|
+
end
|
78
|
+
super
|
79
79
|
end
|
80
|
-
super
|
81
|
-
end
|
82
80
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
81
|
+
def delete_if
|
82
|
+
super
|
83
|
+
sync_keys!
|
84
|
+
self
|
85
|
+
end
|
88
86
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
def reject!
|
88
|
+
super
|
89
|
+
sync_keys!
|
90
|
+
self
|
91
|
+
end
|
94
92
|
|
95
|
-
|
96
|
-
|
97
|
-
|
93
|
+
def reject(&block)
|
94
|
+
dup.reject!(&block)
|
95
|
+
end
|
98
96
|
|
99
|
-
|
100
|
-
|
101
|
-
|
97
|
+
def keys
|
98
|
+
@keys.dup
|
99
|
+
end
|
102
100
|
|
103
|
-
|
104
|
-
|
105
|
-
|
101
|
+
def values
|
102
|
+
@keys.collect { |key| self[key] }
|
103
|
+
end
|
106
104
|
|
107
|
-
|
108
|
-
|
109
|
-
|
105
|
+
def to_hash
|
106
|
+
self
|
107
|
+
end
|
110
108
|
|
111
|
-
|
112
|
-
|
113
|
-
|
109
|
+
def to_a
|
110
|
+
@keys.map { |key| [ key, self[key] ] }
|
111
|
+
end
|
114
112
|
|
115
|
-
|
116
|
-
|
117
|
-
|
113
|
+
def each_key
|
114
|
+
@keys.each { |key| yield key }
|
115
|
+
end
|
118
116
|
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
def each_value
|
118
|
+
@keys.each { |key| yield self[key]}
|
119
|
+
end
|
122
120
|
|
123
|
-
|
124
|
-
|
125
|
-
|
121
|
+
def each
|
122
|
+
@keys.each {|key| yield [key, self[key]]}
|
123
|
+
end
|
126
124
|
|
127
|
-
|
125
|
+
alias_method :each_pair, :each
|
128
126
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
127
|
+
def clear
|
128
|
+
super
|
129
|
+
@keys.clear
|
130
|
+
self
|
131
|
+
end
|
134
132
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
133
|
+
def shift
|
134
|
+
k = @keys.first
|
135
|
+
v = delete(k)
|
136
|
+
[k, v]
|
137
|
+
end
|
140
138
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
139
|
+
def merge!(other_hash)
|
140
|
+
other_hash.each {|k,v| self[k] = v }
|
141
|
+
self
|
142
|
+
end
|
145
143
|
|
146
|
-
|
147
|
-
|
148
|
-
|
144
|
+
def merge(other_hash)
|
145
|
+
dup.merge!(other_hash)
|
146
|
+
end
|
149
147
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
148
|
+
# When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
|
149
|
+
def replace(other)
|
150
|
+
super
|
151
|
+
@keys = other.keys
|
152
|
+
self
|
153
|
+
end
|
156
154
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
155
|
+
# This breaks passing the Hash through Stdin to RubyCocoa
|
156
|
+
# def inspect
|
157
|
+
# "#<OrderedHash #{super}>"
|
158
|
+
# end
|
161
159
|
|
162
|
-
|
160
|
+
private
|
163
161
|
|
164
|
-
|
165
|
-
|
162
|
+
def sync_keys!
|
163
|
+
@keys.delete_if {|k| !has_key?(k)}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
else
|
167
|
+
class OrderedHash < ::Hash
|
166
168
|
end
|
167
169
|
end
|
168
170
|
end
|
169
171
|
end
|
172
|
+
|
173
|
+
module Plist4r
|
174
|
+
# This is an {ActiveSupport::OrderedHash}
|
175
|
+
class OrderedHash < ActiveSupport::OrderedHash
|
176
|
+
end
|
177
|
+
end
|
data/lib/plist4r/mixin/popen4.rb
CHANGED
@@ -7,12 +7,32 @@ module Plist4r
|
|
7
7
|
module Popen4
|
8
8
|
class << self
|
9
9
|
# This is taken directly from Ara T Howard's Open4 library, and then
|
10
|
-
# modified to suit the needs of Chef.
|
11
|
-
#
|
10
|
+
# modified to suit the needs of the Chef project.
|
11
|
+
#
|
12
|
+
# http://github.com/ahoward/open4
|
13
|
+
#
|
14
|
+
# http://www.ruby-forum.com/topic/54593
|
15
|
+
#
|
16
|
+
# Don't use the "Block form" calling method. It screws up on the pipes IO.
|
17
|
+
#
|
18
|
+
# Use "Simple form", always. Simple form == more robust IO handling.
|
12
19
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
20
|
+
# @example Simple form
|
21
|
+
# def popen4_exec stdin_str, cmd, *args
|
22
|
+
# require 'plist4r/mixin/popen4'
|
23
|
+
#
|
24
|
+
# pid, stdin, stdout, stderr = ::Plist4r::Popen4::popen4 [cmd, *args]
|
25
|
+
#
|
26
|
+
# stdin.puts stdin_str
|
27
|
+
#
|
28
|
+
# stdin.close
|
29
|
+
# ignored, status = Process::waitpid2 pid
|
30
|
+
#
|
31
|
+
# stdout_result = stdout.read.strip
|
32
|
+
# stderr_result = stderr.read.strip
|
33
|
+
#
|
34
|
+
# return [cmd, status, stdout_result, stderr_result]
|
35
|
+
# end
|
16
36
|
def popen4(cmd, args={}, &b)
|
17
37
|
|
18
38
|
# Waitlast - this is magic.
|
@@ -3,6 +3,13 @@
|
|
3
3
|
# we don't want to upset anyone else's code
|
4
4
|
|
5
5
|
class Object
|
6
|
+
# The method name
|
7
|
+
# @return [String] The name of the current method
|
8
|
+
# @example
|
9
|
+
# def my_method
|
10
|
+
# method_name
|
11
|
+
# end
|
12
|
+
# my_method => "my_method"
|
6
13
|
def method_name
|
7
14
|
if /`(.*)'/.match(caller.first)
|
8
15
|
return $1
|
@@ -11,13 +18,18 @@ class Object
|
|
11
18
|
end
|
12
19
|
end
|
13
20
|
|
14
|
-
|
15
21
|
class String
|
22
|
+
# A Camel-ized string. The reverse of {#snake_case}
|
23
|
+
# @example
|
24
|
+
# "my_plist_key".camelcase => "MyPlistKey"
|
16
25
|
def camelcase
|
17
26
|
str = self.dup.capitalize.gsub(/[-_.\s]([a-zA-Z0-9])/) { $1.upcase } \
|
18
27
|
.gsub('+', 'x')
|
19
28
|
end
|
20
29
|
|
30
|
+
# A snake-cased string. The reverse of {#camelcase}
|
31
|
+
# @example
|
32
|
+
# "MyPlistKey".snake_case => "my_plist_key"
|
21
33
|
def snake_case
|
22
34
|
str = self.dup.gsub(/[A-Z]/) {|s| "_" + s}
|
23
35
|
str = str.downcase.sub(/^\_/, "")
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'plist4r/mixin/mixlib_cli'
|
2
|
+
require 'plist4r/mixin/mixlib_config'
|
3
|
+
|
4
|
+
module Plist4r
|
5
|
+
# Defines options for the `plist4r` command line utility
|
6
|
+
class CLI
|
7
|
+
include Plist4r::Mixlib::CLI
|
8
|
+
|
9
|
+
# The Plist4r CLI Options
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# Usage: bin/plist4r (options)
|
13
|
+
# -b, --brew Customize for Brew. Use with --ruby-lib.
|
14
|
+
# -d, --dir DIR The directory to dump files into. Use with --ruby-lib. Defaults to cwd.
|
15
|
+
# -r, --ruby-lib Convert plist4r gem into a ruby lib, and write to the filesystem. (required)
|
16
|
+
# -h, --help Show this message
|
17
|
+
def self.plist4r_cli_options
|
18
|
+
option :ruby_lib, :required => true,
|
19
|
+
:short => "-r", :long => "--ruby-lib", :boolean => true, :default => false,
|
20
|
+
:description => "Convert plist4r gem into a ruby lib, and write to the filesystem."
|
21
|
+
|
22
|
+
option :brew,
|
23
|
+
:short => "-b", :long => "--brew", :boolean => true, :default => false,
|
24
|
+
:description => "Customize for Brew. Use with --ruby-lib."
|
25
|
+
|
26
|
+
option :dir,
|
27
|
+
:short => "-d DIR", :long => "--dir DIR", :default => nil,
|
28
|
+
:description => "The directory to dump files into. Use with --ruby-lib. Defaults to cwd."
|
29
|
+
|
30
|
+
option :help, :short => "-h", :long => "--help", :boolean => true,
|
31
|
+
:description => "Show this message",
|
32
|
+
:on => :tail,
|
33
|
+
:show_options => true,
|
34
|
+
:exit => 0
|
35
|
+
end
|
36
|
+
plist4r_cli_options
|
37
|
+
|
38
|
+
def parse argv=ARGV
|
39
|
+
parse_options(argv)
|
40
|
+
config
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/plist4r/plist.rb
CHANGED
@@ -8,14 +8,36 @@ require 'plist4r/backend'
|
|
8
8
|
|
9
9
|
module Plist4r
|
10
10
|
class Plist
|
11
|
-
|
11
|
+
# Recognised keys of the options hash. Passed when instantiating a new Plist Object
|
12
|
+
# @see #initialize
|
13
|
+
# @see #parse_opts
|
14
|
+
PlistOptionsHash = %w[filename path file_format plist_type strict_keys backends from_string]
|
15
|
+
# The plist file formats, written as symbols.
|
16
|
+
# @see #file_format
|
12
17
|
FileFormats = %w[binary xml next_step]
|
13
|
-
|
18
|
+
|
19
|
+
# Instantiate a new Plist4r::Plist object. We usually set our per-application defaults in {Plist4r::Config} beforehand.
|
20
|
+
#
|
21
|
+
# @param [String] filename
|
22
|
+
# @param [Hash] options - for advanced usage
|
23
|
+
# @example Create new, empty plist
|
24
|
+
# Plist4r::Plist.new => #<Plist4r::Plist:0x111546c @file_format=nil, ...>
|
25
|
+
# @example Load from file
|
26
|
+
# Plist4r::Plist.new("example.plist") => #<Plist4r::Plist:0x1152d1c @file_format="xml", ...>
|
27
|
+
# @example Load from string
|
28
|
+
# plist_string = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }"
|
29
|
+
# Plist4r::Plist.new({ :from_string => plist_string })
|
30
|
+
# => #<Plist4r::Plist:0x11e161c @file_format="xml", ...>
|
31
|
+
# @example Advanced options
|
32
|
+
# plist_working_dir = `pwd`.strip
|
33
|
+
# Plist4r::Plist.new({ :filename => "example.plist", :path => plist_working_dir, :backends => ["libxml4r","ruby_cocoa"]})
|
34
|
+
# => #<Plist4r::Plist:0x111546c @file_format=nil, ...>
|
35
|
+
# @return [Plist4r::Plist] The new Plist object
|
14
36
|
def initialize *args, &blk
|
15
|
-
@hash = ::
|
37
|
+
@hash = ::Plist4r::OrderedHash.new
|
16
38
|
@plist_type = plist_type :plist
|
17
39
|
|
18
|
-
@
|
40
|
+
@strict_keys = Config[:strict_keys]
|
19
41
|
@backends = Config[:backends]
|
20
42
|
|
21
43
|
@from_string = nil
|
@@ -37,6 +59,12 @@ module Plist4r
|
|
37
59
|
@plist_cache ||= PlistCache.new self
|
38
60
|
end
|
39
61
|
|
62
|
+
# Reinitialize plist object from string (overwrites the current contents). Usually called from {Plist#initialize}
|
63
|
+
# @example Load from string
|
64
|
+
# plist = Plist4r::Plist.new
|
65
|
+
# => #<Plist4r::Plist:0x11e161c @file_format=nil, ...>
|
66
|
+
# plist.from_string "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }"
|
67
|
+
# => #<Plist4r::Plist:0x11e161c @file_format="next_step", ...>
|
40
68
|
def from_string string=nil
|
41
69
|
case string
|
42
70
|
when String
|
@@ -55,6 +83,12 @@ module Plist4r
|
|
55
83
|
end
|
56
84
|
end
|
57
85
|
|
86
|
+
# Set or return the filename attribute of the plist object.
|
87
|
+
# @param [String] filename either a relative path or absolute
|
88
|
+
# @return The plist's filename
|
89
|
+
# @see Plist::Plist#open
|
90
|
+
# @see Plist::Plist#save
|
91
|
+
# @see Plist::Plist#save_as
|
58
92
|
def filename filename=nil
|
59
93
|
case filename
|
60
94
|
when String
|
@@ -66,6 +100,10 @@ module Plist4r
|
|
66
100
|
end
|
67
101
|
end
|
68
102
|
|
103
|
+
# Set or return the path attribute of the plist object. Pre-pended to the plist's filename (if filename is path-relative)
|
104
|
+
# @param [String] path (must be an absolute pathname)
|
105
|
+
# @return The plist's working path
|
106
|
+
# @see Plist::Plist#filename_path
|
69
107
|
def path path=nil
|
70
108
|
case path
|
71
109
|
when String
|
@@ -77,6 +115,12 @@ module Plist4r
|
|
77
115
|
end
|
78
116
|
end
|
79
117
|
|
118
|
+
# Set or return the combined filename+path.
|
119
|
+
# We use this method in the backends api as the full path to load / save
|
120
|
+
# @param [String] filename_path concactenation of both filename and path elements. Also sets the @filename and @path attributes
|
121
|
+
# @return the full, expanded path to the plist file
|
122
|
+
# @see filename
|
123
|
+
# @see path
|
80
124
|
def filename_path filename_path=nil
|
81
125
|
case path
|
82
126
|
when String
|
@@ -89,6 +133,11 @@ module Plist4r
|
|
89
133
|
end
|
90
134
|
end
|
91
135
|
|
136
|
+
# The file format of the plist file we are loading / saving. Written as a symbol.
|
137
|
+
# One of {Plist4r::Plist.FileFormats}. Defaults to :xml
|
138
|
+
# @param [Symbol, String] file_format Can be :binary, :xml, :next_step
|
139
|
+
# @return The file format associated to this current plist object
|
140
|
+
# @see Plist4r::Plist.FileFormats
|
92
141
|
def file_format file_format=nil
|
93
142
|
case file_format
|
94
143
|
when Symbol, String
|
@@ -104,6 +153,11 @@ module Plist4r
|
|
104
153
|
end
|
105
154
|
end
|
106
155
|
|
156
|
+
# Called automatically on plist load / instantiation. This method detects the "Plist Type",
|
157
|
+
# using an algorithm that stats the plist data. The plist types with the highest stat (score)
|
158
|
+
# is chosen to be the object's "Plist Type".
|
159
|
+
# @see Plist4r::PlistType
|
160
|
+
# @return [true] always
|
107
161
|
def detect_plist_type
|
108
162
|
stat_m = {}
|
109
163
|
stat_r = {}
|
@@ -139,6 +193,11 @@ module Plist4r
|
|
139
193
|
return true
|
140
194
|
end
|
141
195
|
|
196
|
+
# Set or return the plist_type of the current object. We can use this to override the automatic type detection.
|
197
|
+
# @param [Symbol, String] plist_type. Must be a sublcass of {Plist4r::PlistType}
|
198
|
+
# @return The plist's known type, written as a symbol. Will be a sublcass of Plist4r::PlistType. Defaults to :plist
|
199
|
+
# @see Plist4r::PlistType
|
200
|
+
# @see Plist4r::PlistType::Plist
|
142
201
|
def plist_type plist_type=nil
|
143
202
|
begin
|
144
203
|
case plist_type
|
@@ -160,17 +219,29 @@ module Plist4r
|
|
160
219
|
end
|
161
220
|
end
|
162
221
|
|
163
|
-
|
222
|
+
# Set or return strict_keys mode
|
223
|
+
# @param [true, false] bool If true, then raise an error for any unrecognized keys that dont belong to the {#plist_type}
|
224
|
+
# @return The strict_keys setting for this object
|
225
|
+
# @see Plist4r::Config
|
226
|
+
def strict_keys bool=nil
|
164
227
|
case bool
|
165
228
|
when true,false
|
166
|
-
@
|
229
|
+
@strict_keys = bool
|
167
230
|
when nil
|
168
|
-
@
|
231
|
+
@strict_keys
|
169
232
|
else
|
170
233
|
raise "Please specify true or false to enable / disable this option"
|
171
234
|
end
|
172
235
|
end
|
173
|
-
|
236
|
+
|
237
|
+
# An array of strings, symbols or class names which correspond to the active Plist4r::Backends for this object.
|
238
|
+
# The priority order in which backends are executed is determined by the in sequence array order.
|
239
|
+
# @param [Array] backends Inherited from {Plist4r::Config}[:backends]
|
240
|
+
# @return The backends for this object
|
241
|
+
# @example Execute haml before resorting to RubyCocoa
|
242
|
+
# plist.backends [:haml, :ruby_cocoa]
|
243
|
+
# @see Plist4r::Backend
|
244
|
+
# @see Plist4r::Backend::Example
|
174
245
|
def backends backends=nil
|
175
246
|
case backends
|
176
247
|
when Array
|
@@ -182,6 +253,10 @@ module Plist4r
|
|
182
253
|
end
|
183
254
|
end
|
184
255
|
|
256
|
+
# Sets up those valid (settable) plist attributes as found the options hash.
|
257
|
+
# Normally we dont call this method ourselves. Called from {#initialize}.
|
258
|
+
# @param [Hash <PlistOptionsHash>] opts The options hash, containing keys of {PlistOptionsHash}
|
259
|
+
# @see #initialize
|
185
260
|
def parse_opts opts
|
186
261
|
PlistOptionsHash.each do |opt|
|
187
262
|
if opts[opt.to_sym]
|
@@ -191,16 +266,46 @@ module Plist4r
|
|
191
266
|
end
|
192
267
|
end
|
193
268
|
|
269
|
+
# Opens a plist file
|
270
|
+
#
|
271
|
+
# @param [String] filename plist file to load. Uses the @filename attribute when nil
|
272
|
+
# @return [Plist4r::Plist] The loaded Plist object
|
273
|
+
# @example Load from file
|
274
|
+
# plist = Plist4r.new
|
275
|
+
# plist.open("example.plist") => #<Plist4r::Plist:0x1152d1c @file_format="xml", ...>
|
194
276
|
def open filename=nil
|
195
277
|
@filename = filename if filename
|
196
278
|
raise "No filename specified" unless @filename
|
197
279
|
@plist_cache.open
|
198
280
|
end
|
199
281
|
|
282
|
+
# An alias of {#edit}
|
283
|
+
# @example
|
284
|
+
# plist.<< do
|
285
|
+
# set "PFReleaseVersion" "0.1.1"
|
286
|
+
# end
|
287
|
+
# @see #edit
|
200
288
|
def << *args, &blk
|
201
289
|
edit *args, &blk
|
202
290
|
end
|
203
291
|
|
292
|
+
# Edit a plist object. Set or return plist keys. Add or remove a selection of keys.
|
293
|
+
# Plist key accessor methods are snake-cased versions of the key string.
|
294
|
+
# @example Set some arbitrary keys and values via {DataMethods#set}
|
295
|
+
# plist.edit do
|
296
|
+
# set "PFInstance" "4982394823"
|
297
|
+
# set "PFReleaseVersion" "0.1.1"
|
298
|
+
# end
|
299
|
+
# @example Retrieve, and modify a plist key, value pair, with {DataMethods#set} and {DataMethods#value_of}
|
300
|
+
# plist.edit do
|
301
|
+
# new_ver = value_of("PFReleaseVersion") + 0.1
|
302
|
+
# set "PFReleaseVersion" new_ver
|
303
|
+
# end
|
304
|
+
# @example Modify a Launchd plist, by camel-cased accessor methods
|
305
|
+
# plist.edit do
|
306
|
+
# new_ver = value_of("PFReleaseVersion") + 0.1
|
307
|
+
# set "PFReleaseVersion" new_ver
|
308
|
+
# end
|
204
309
|
def edit *args, &blk
|
205
310
|
@plist_type.hash @hash
|
206
311
|
instance_eval *args, &blk
|
@@ -208,42 +313,79 @@ module Plist4r
|
|
208
313
|
@plist_cache.update_checksum
|
209
314
|
end
|
210
315
|
|
316
|
+
# Pass down unknown method calls to the selected plist_type, to set or return plist keys.
|
317
|
+
# All plist data manipulation API is called through method_missing -> PlistType -> DataMethods.
|
318
|
+
# @example This will actually call {DataMethods#set}
|
319
|
+
# plist.set "CFBundleVersion" "0.1.0"
|
320
|
+
# @see Plist4r::DataMethods#method_missing
|
321
|
+
# @see #plist_type
|
211
322
|
def method_missing method_sym, *args, &blk
|
212
323
|
@plist_type.send method_sym, *args, &blk
|
213
324
|
end
|
214
325
|
|
326
|
+
# Backend method to set or return all new plist data resulting from a backend API. Used in load operations.
|
327
|
+
# @param [Plist4r::OrderedHash, nil] hash sets the new root object. Replaces all previous plist data.
|
328
|
+
# @return If no argument given, then clears all plist data, returning the new @hash root object
|
329
|
+
# @see Backend::Example
|
215
330
|
def import_hash hash=nil
|
216
331
|
case hash
|
217
|
-
when ::
|
332
|
+
when ::Plist4r::OrderedHash
|
218
333
|
@hash = hash
|
219
334
|
when nil
|
220
|
-
@hash = ::
|
335
|
+
@hash = ::Plist4r::OrderedHash.new
|
221
336
|
else
|
222
|
-
raise "Please use ::
|
337
|
+
raise "Please use ::Plist4r::OrderedHash.new for your hashes"
|
223
338
|
end
|
224
339
|
end
|
225
340
|
|
341
|
+
# The primary storage object for plist data
|
342
|
+
#
|
343
|
+
# @return [::Plist4r::OrderedHash] Nested hash of ruby objects. The raw Plist data
|
344
|
+
# @see ::Plist4r::OrderedHash
|
345
|
+
# @example
|
346
|
+
# plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
|
347
|
+
# plist.to_hash => {"key1"=>"value1", "key2"=>"value2"}
|
226
348
|
def to_hash
|
227
349
|
@hash
|
228
350
|
end
|
229
|
-
|
351
|
+
|
352
|
+
# Calls out to the plist cache
|
353
|
+
#
|
354
|
+
# @return [String] An xml string which represents the entire plist, as would be the plist xml file
|
355
|
+
# @example
|
356
|
+
# plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
|
357
|
+
# plist.to_xml
|
358
|
+
# => "<?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>"
|
230
359
|
def to_xml
|
231
360
|
@plist_cache.to_xml
|
232
361
|
end
|
233
362
|
|
363
|
+
# @example
|
364
|
+
# plist = "{ \"key1\" = \"value1\"; \"key2\" = \"value2\"; }".to_plist
|
365
|
+
# plist.to_binary
|
366
|
+
# => "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%"
|
234
367
|
def to_binary
|
235
368
|
@plist_cache.to_binary
|
236
369
|
end
|
237
370
|
|
371
|
+
# @todo Needs a backend
|
372
|
+
# We are missing a backend for writing out :next_step strings and saving :next_step files to disk
|
238
373
|
def to_next_step
|
239
374
|
@plist_cache.to_next_step
|
240
375
|
end
|
241
376
|
|
377
|
+
# Save plist to #filename
|
378
|
+
# @raise [RuntimeError] if the {#filename} attribute is nil
|
379
|
+
# @see #filename
|
380
|
+
# @see #path
|
242
381
|
def save
|
243
382
|
raise "No filename specified" unless @filename
|
244
383
|
@plist_cache.save
|
245
384
|
end
|
246
385
|
|
386
|
+
# Save the plist under a new filename
|
387
|
+
# @param [String] filename The new file name to save as. If a relative path, will be concactenated to plist.path
|
388
|
+
# @see #save
|
247
389
|
def save_as filename
|
248
390
|
@filename = filename
|
249
391
|
save
|
@@ -252,6 +394,7 @@ module Plist4r
|
|
252
394
|
end
|
253
395
|
|
254
396
|
module Plist4r
|
397
|
+
# @private
|
255
398
|
class OldPlist
|
256
399
|
|
257
400
|
def initialize path_prefix, plist_str, &blk
|
@@ -268,7 +411,7 @@ module Plist4r
|
|
268
411
|
@shortname = @filename.match(/^.*\.(.*)$/)[1]
|
269
412
|
|
270
413
|
@block = blk
|
271
|
-
@hash = @orig = ::
|
414
|
+
@hash = @orig = ::Plist4r::OrderedHash.new
|
272
415
|
|
273
416
|
instance_eval(&@block) if @block
|
274
417
|
end
|