plist4r 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|