facter 1.6.1 → 1.6.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of facter might be problematic. Click here for more details.
- data/CHANGELOG +31 -0
- data/Rakefile +41 -36
- data/conf/redhat/facter.spec +11 -4
- data/conf/solaris/pkginfo +1 -1
- data/install.rb +286 -286
- data/lib/facter.rb +211 -211
- data/lib/facter/Cfkey.rb +24 -24
- data/lib/facter/application.rb +1 -0
- data/lib/facter/architecture.rb +21 -29
- data/lib/facter/domain.rb +34 -34
- data/lib/facter/facterversion.rb +1 -1
- data/lib/facter/fqdn.rb +8 -8
- data/lib/facter/hardwareisa.rb +2 -2
- data/lib/facter/hardwaremodel.rb +12 -12
- data/lib/facter/hostname.rb +14 -14
- data/lib/facter/id.rb +3 -3
- data/lib/facter/interfaces.rb +13 -13
- data/lib/facter/ipaddress.rb +101 -101
- data/lib/facter/iphostnumber.rb +12 -12
- data/lib/facter/kernel.rb +7 -7
- data/lib/facter/kernelmajversion.rb +3 -3
- data/lib/facter/kernelrelease.rb +12 -12
- data/lib/facter/kernelversion.rb +5 -5
- data/lib/facter/lsb.rb +14 -14
- data/lib/facter/lsbmajdistrelease.rb +8 -8
- data/lib/facter/macaddress.rb +44 -44
- data/lib/facter/macosx.rb +21 -21
- data/lib/facter/manufacturer.rb +28 -28
- data/lib/facter/memory.rb +143 -115
- data/lib/facter/netmask.rb +4 -4
- data/lib/facter/network.rb +4 -4
- data/lib/facter/operatingsystem.rb +73 -69
- data/lib/facter/operatingsystemrelease.rb +85 -79
- data/lib/facter/osfamily.rb +31 -0
- data/lib/facter/path.rb +3 -3
- data/lib/facter/physicalprocessorcount.rb +8 -0
- data/lib/facter/processor.rb +91 -72
- data/lib/facter/ps.rb +3 -3
- data/lib/facter/puppetversion.rb +7 -7
- data/lib/facter/rubysitedir.rb +5 -5
- data/lib/facter/rubyversion.rb +1 -1
- data/lib/facter/ssh.rb +16 -16
- data/lib/facter/timezone.rb +3 -3
- data/lib/facter/uniqueid.rb +2 -2
- data/lib/facter/util/collection.rb +96 -96
- data/lib/facter/util/confine.rb +30 -30
- data/lib/facter/util/fact.rb +95 -95
- data/lib/facter/util/ip.rb +173 -173
- data/lib/facter/util/loader.rb +88 -88
- data/lib/facter/util/macosx.rb +46 -46
- data/lib/facter/util/manufacturer.rb +78 -78
- data/lib/facter/util/memory.rb +63 -63
- data/lib/facter/util/netmask.rb +34 -34
- data/lib/facter/util/plist.rb +1 -1
- data/lib/facter/util/plist/generator.rb +177 -177
- data/lib/facter/util/plist/parser.rb +166 -166
- data/lib/facter/util/processor.rb +88 -0
- data/lib/facter/util/resolution.rb +154 -154
- data/lib/facter/util/uptime.rb +42 -42
- data/lib/facter/util/values.rb +9 -9
- data/lib/facter/util/virtual.rb +68 -58
- data/lib/facter/util/vlans.rb +17 -17
- data/lib/facter/virtual.rb +105 -110
- data/lib/facter/vlans.rb +6 -6
- data/spec/fixtures/cpuinfo/amd64dual +57 -0
- data/spec/fixtures/cpuinfo/amd64quad +79 -0
- data/spec/fixtures/cpuinfo/amd64solo +23 -0
- data/spec/fixtures/cpuinfo/amd64tri +86 -0
- data/spec/fixtures/cpuinfo/bbg3-armel +12 -0
- data/spec/fixtures/cpuinfo/beaglexm-armel +12 -0
- data/spec/fixtures/cpuinfo/panda-armel +17 -0
- data/spec/fixtures/cpuinfo/ppc64 +19 -0
- data/spec/fixtures/cpuinfo/sparc +10 -0
- data/spec/fixtures/processorcount/solaris-sparc-kstat-cpu-info +1216 -0
- data/spec/fixtures/processorcount/solaris-x86_64-kstat-cpu-info +225 -0
- data/spec/integration/facter_spec.rb +18 -18
- data/spec/spec_helper.rb +10 -1
- data/spec/unit/architecture_spec.rb +54 -0
- data/spec/unit/domain_spec.rb +23 -0
- data/spec/unit/memory_spec.rb +78 -1
- data/spec/unit/physicalprocessorcount_spec.rb +41 -35
- data/spec/unit/processor_spec.rb +183 -2
- data/spec/unit/util/processor_spec.rb +62 -0
- data/spec/unit/util/uptime_spec.rb +4 -4
- data/spec/unit/util/virtual_spec.rb +26 -5
- data/spec/unit/virtual_spec.rb +47 -2
- data/spec/watchr.rb +125 -0
- metadata +20 -4
data/lib/facter/util/memory.rb
CHANGED
@@ -3,83 +3,83 @@
|
|
3
3
|
##
|
4
4
|
|
5
5
|
module Facter::Memory
|
6
|
-
|
6
|
+
require 'thread'
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
21
|
-
memsize = scale_number(size, scale)
|
8
|
+
def self.meminfo_number(tag)
|
9
|
+
memsize = ""
|
10
|
+
Thread::exclusive do
|
11
|
+
size, scale = [0, ""]
|
12
|
+
File.readlines("/proc/meminfo").each do |l|
|
13
|
+
size, scale = [$1.to_f, $2] if l =~ /^#{tag}:\s+(\d+)\s+(\S+)/
|
14
|
+
# MemoryFree == memfree + cached + buffers
|
15
|
+
# (assume scales are all the same as memfree)
|
16
|
+
if tag == "MemFree" &&
|
17
|
+
l =~ /^(?:Buffers|Cached):\s+(\d+)\s+(?:\S+)/
|
18
|
+
size += $1.to_f
|
22
19
|
end
|
23
|
-
|
24
|
-
|
20
|
+
end
|
21
|
+
memsize = scale_number(size, scale)
|
25
22
|
end
|
26
23
|
|
27
|
-
|
28
|
-
|
24
|
+
memsize
|
25
|
+
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
s = suffixes.shift
|
33
|
-
end
|
27
|
+
def self.scale_number(size, multiplier)
|
28
|
+
suffixes = ['', 'kB', 'MB', 'GB', 'TB']
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
s = suffixes.shift
|
31
|
+
while s != multiplier
|
32
|
+
s = suffixes.shift
|
33
|
+
end
|
39
34
|
|
40
|
-
|
35
|
+
while size > 1024.0
|
36
|
+
size /= 1024.0
|
37
|
+
s = suffixes.shift
|
41
38
|
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
return "%.2f %s" % [size, s]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.vmstat_find_free_memory()
|
44
|
+
row = Facter::Util::Resolution.exec('vmstat').split("\n")[-1]
|
45
|
+
if row =~ /^\s*\d+\s*\d+\s*\d+\s*\d+\s*(\d+)/
|
46
|
+
Facter.add("MemoryFree") do
|
47
|
+
memfree = $1
|
48
|
+
setcode do
|
49
|
+
Facter::Memory.scale_number(memfree.to_f, "kB")
|
52
50
|
end
|
51
|
+
end
|
53
52
|
end
|
53
|
+
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
55
|
+
# Darwin had to be different. It's generally opaque with how much RAM it is
|
56
|
+
# using, and this figure could be improved upon too I fear.
|
57
|
+
# Parses the output of "vm_stat", takes the pages free & pages speculative
|
58
|
+
# and multiples that by the page size (also given in output). Ties in with
|
59
|
+
# what activity monitor outputs for free memory.
|
60
|
+
def self.vmstat_darwin_find_free_memory()
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
memfree = 0
|
63
|
+
pagesize = 0
|
64
|
+
memspecfree = 0
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
66
|
+
vmstats = Facter::Util::Resolution.exec('vm_stat')
|
67
|
+
vmstats.each_line do |vmline|
|
68
|
+
case
|
69
|
+
when vmline =~ /page\ssize\sof\s(\d+)\sbytes/
|
70
|
+
pagesize = $1.to_i
|
71
|
+
when vmline =~ /^Pages\sfree:\s+(\d+)\./
|
72
|
+
memfree = $1.to_i
|
73
|
+
when vmline =~ /^Pages\sspeculative:\s+(\d+)\./
|
74
|
+
memspecfree = $1.to_i
|
75
|
+
end
|
76
|
+
end
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
78
|
+
freemem = ( memfree + memspecfree ) * pagesize
|
79
|
+
Facter.add("MemoryFree") do
|
80
|
+
setcode do
|
81
|
+
Facter::Memory.scale_number(freemem.to_f, "")
|
82
|
+
end
|
84
83
|
end
|
84
|
+
end
|
85
85
|
end
|
data/lib/facter/util/netmask.rb
CHANGED
@@ -1,40 +1,40 @@
|
|
1
1
|
module Facter::NetMask
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
def self.get_netmask
|
3
|
+
netmask = nil;
|
4
|
+
ipregex = %r{(\d{1,3}\.){3}\d{1,3}}
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
6
|
+
ops = nil
|
7
|
+
case Facter.value(:kernel)
|
8
|
+
when 'Linux'
|
9
|
+
ops = {
|
10
|
+
:ifconfig => '/sbin/ifconfig',
|
11
|
+
:regex => %r{\s+ inet\saddr: #{Facter.ipaddress} .*? Mask: (#{ipregex})}x,
|
12
|
+
:munge => nil,
|
13
|
+
}
|
14
|
+
when 'SunOS'
|
15
|
+
ops = {
|
16
|
+
:ifconfig => '/usr/sbin/ifconfig -a',
|
17
|
+
:regex => %r{\s+ inet \s #{Facter.ipaddress} \s netmask \s (\w{8})}x,
|
18
|
+
:munge => Proc.new { |mask| mask.scan(/../).collect do |byte| byte.to_i(16) end.join('.') }
|
19
|
+
}
|
20
|
+
when 'FreeBSD','NetBSD','OpenBSD', 'Darwin', 'GNU/kFreeBSD', 'DragonFly'
|
21
|
+
ops = {
|
22
|
+
:ifconfig => '/sbin/ifconfig -a',
|
23
|
+
:regex => %r{\s+ inet \s #{Facter.ipaddress} \s netmask \s 0x(\w{8})}x,
|
24
|
+
:munge => Proc.new { |mask| mask.scan(/../).collect do |byte| byte.to_i(16) end.join('.') }
|
25
|
+
}
|
26
|
+
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
28
|
+
%x{#{ops[:ifconfig]}}.split(/\n/).collect do |line|
|
29
|
+
matches = line.match(ops[:regex])
|
30
|
+
if !matches.nil?
|
31
|
+
if ops[:munge].nil?
|
32
|
+
netmask = matches[1]
|
33
|
+
else
|
34
|
+
netmask = ops[:munge].call(matches[1])
|
37
35
|
end
|
38
|
-
|
36
|
+
end
|
39
37
|
end
|
38
|
+
netmask
|
39
|
+
end
|
40
40
|
end
|
data/lib/facter/util/plist.rb
CHANGED
@@ -1,228 +1,228 @@
|
|
1
1
|
#--###########################################################
|
2
|
-
# Copyright 2006, Ben Bleything <ben@bleything.net> and
|
3
|
-
# Patrick May <patrick@hexane.org>
|
4
|
-
#
|
5
|
-
# Distributed under the MIT license.
|
2
|
+
# Copyright 2006, Ben Bleything <ben@bleything.net> and #
|
3
|
+
# Patrick May <patrick@hexane.org> #
|
4
|
+
# #
|
5
|
+
# Distributed under the MIT license. #
|
6
6
|
##############################################################
|
7
7
|
#++
|
8
8
|
# See Plist::Emit.
|
9
9
|
module Plist
|
10
|
-
|
11
|
-
|
10
|
+
# === Create a plist
|
11
|
+
# You can dump an object to a plist in one of two ways:
|
12
|
+
#
|
13
|
+
# * <tt>Plist::Emit.dump(obj)</tt>
|
14
|
+
# * <tt>obj.to_plist</tt>
|
15
|
+
# * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
|
16
|
+
#
|
17
|
+
# The following Ruby classes are converted into native plist types:
|
18
|
+
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
|
19
|
+
# * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
|
20
|
+
# * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
|
21
|
+
# * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to <tt>Marshal.dump</tt> and the result placed in a <data> element.
|
22
|
+
#
|
23
|
+
# For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below.
|
24
|
+
module Emit
|
25
|
+
# Helper method for injecting into classes. Calls <tt>Plist::Emit.dump</tt> with +self+.
|
26
|
+
def to_plist(envelope = true)
|
27
|
+
return Plist::Emit.dump(self, envelope)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
|
31
|
+
def save_plist(filename)
|
32
|
+
Plist::Emit.save_plist(self, filename)
|
33
|
+
end
|
34
|
+
|
35
|
+
# The following Ruby classes are converted into native plist types:
|
36
|
+
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
|
12
37
|
#
|
13
|
-
#
|
14
|
-
# * <tt>obj.to_plist</tt>
|
15
|
-
# * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
|
38
|
+
# Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes.
|
16
39
|
#
|
17
|
-
#
|
18
|
-
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
|
19
|
-
# * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
|
20
|
-
# * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
|
21
|
-
# * User classes may implement +to_plist_node+ to dictate how they should be serialized; otherwise the object will be passed to <tt>Marshal.dump</tt> and the result placed in a <data> element.
|
40
|
+
# +IO+ and +StringIO+ objects are encoded and placed in <data> elements; other objects are <tt>Marshal.dump</tt>'ed unless they implement +to_plist_node+.
|
22
41
|
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
def to_plist(envelope = true)
|
27
|
-
return Plist::Emit.dump(self, envelope)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
|
31
|
-
def save_plist(filename)
|
32
|
-
Plist::Emit.save_plist(self, filename)
|
33
|
-
end
|
42
|
+
# The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment.
|
43
|
+
def self.dump(obj, envelope = true)
|
44
|
+
output = plist_node(obj)
|
34
45
|
|
35
|
-
|
36
|
-
# Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
|
37
|
-
#
|
38
|
-
# Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes.
|
39
|
-
#
|
40
|
-
# +IO+ and +StringIO+ objects are encoded and placed in <data> elements; other objects are <tt>Marshal.dump</tt>'ed unless they implement +to_plist_node+.
|
41
|
-
#
|
42
|
-
# The +envelope+ parameters dictates whether or not the resultant plist fragment is wrapped in the normal XML/plist header and footer. Set it to false if you only want the fragment.
|
43
|
-
def self.dump(obj, envelope = true)
|
44
|
-
output = plist_node(obj)
|
46
|
+
output = wrap(output) if envelope
|
45
47
|
|
46
|
-
|
48
|
+
return output
|
49
|
+
end
|
47
50
|
|
48
|
-
|
49
|
-
|
51
|
+
# Writes the serialized object's plist to the specified filename.
|
52
|
+
def self.save_plist(obj, filename)
|
53
|
+
File.open(filename, 'wb') do |f|
|
54
|
+
f.write(obj.to_plist)
|
55
|
+
end
|
56
|
+
end
|
50
57
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
private
|
59
|
+
def self.plist_node(element)
|
60
|
+
output = ''
|
61
|
+
|
62
|
+
if element.respond_to? :to_plist_node
|
63
|
+
output << element.to_plist_node
|
64
|
+
else
|
65
|
+
case element
|
66
|
+
when Array
|
67
|
+
if element.empty?
|
68
|
+
output << "<array/>\n"
|
69
|
+
else
|
70
|
+
output << tag('array') {
|
71
|
+
element.collect {|e| plist_node(e)}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
when Hash
|
75
|
+
if element.empty?
|
76
|
+
output << "<dict/>\n"
|
77
|
+
else
|
78
|
+
inner_tags = []
|
79
|
+
|
80
|
+
element.keys.sort.each do |k|
|
81
|
+
v = element[k]
|
82
|
+
inner_tags << tag('key', CGI::escapeHTML(k.to_s))
|
83
|
+
inner_tags << plist_node(v)
|
55
84
|
end
|
85
|
+
|
86
|
+
output << tag('dict') {
|
87
|
+
inner_tags
|
88
|
+
}
|
89
|
+
end
|
90
|
+
when true, false
|
91
|
+
output << "<#{element}/>\n"
|
92
|
+
when Time
|
93
|
+
output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
94
|
+
when Date # also catches DateTime
|
95
|
+
output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
96
|
+
when String, Symbol, Fixnum, Bignum, Integer, Float
|
97
|
+
output << tag(element_type(element), CGI::escapeHTML(element.to_s))
|
98
|
+
when IO, StringIO
|
99
|
+
element.rewind
|
100
|
+
contents = element.read
|
101
|
+
# note that apple plists are wrapped at a different length then
|
102
|
+
# what ruby's base64 wraps by default.
|
103
|
+
# I used #encode64 instead of #b64encode (which allows a length arg)
|
104
|
+
# because b64encode is b0rked and ignores the length arg.
|
105
|
+
data = "\n"
|
106
|
+
Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
107
|
+
output << tag('data', data)
|
108
|
+
else
|
109
|
+
output << comment( 'The <data> element below contains a Ruby object which has been serialized with Marshal.dump.' )
|
110
|
+
data = "\n"
|
111
|
+
Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
112
|
+
output << tag('data', data )
|
56
113
|
end
|
114
|
+
end
|
57
115
|
|
58
|
-
|
59
|
-
|
60
|
-
output = ''
|
61
|
-
|
62
|
-
if element.respond_to? :to_plist_node
|
63
|
-
output << element.to_plist_node
|
64
|
-
else
|
65
|
-
case element
|
66
|
-
when Array
|
67
|
-
if element.empty?
|
68
|
-
output << "<array/>\n"
|
69
|
-
else
|
70
|
-
output << tag('array') {
|
71
|
-
element.collect {|e| plist_node(e)}
|
72
|
-
}
|
73
|
-
end
|
74
|
-
when Hash
|
75
|
-
if element.empty?
|
76
|
-
output << "<dict/>\n"
|
77
|
-
else
|
78
|
-
inner_tags = []
|
79
|
-
|
80
|
-
element.keys.sort.each do |k|
|
81
|
-
v = element[k]
|
82
|
-
inner_tags << tag('key', CGI::escapeHTML(k.to_s))
|
83
|
-
inner_tags << plist_node(v)
|
84
|
-
end
|
85
|
-
|
86
|
-
output << tag('dict') {
|
87
|
-
inner_tags
|
88
|
-
}
|
89
|
-
end
|
90
|
-
when true, false
|
91
|
-
output << "<#{element}/>\n"
|
92
|
-
when Time
|
93
|
-
output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
94
|
-
when Date # also catches DateTime
|
95
|
-
output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
|
96
|
-
when String, Symbol, Fixnum, Bignum, Integer, Float
|
97
|
-
output << tag(element_type(element), CGI::escapeHTML(element.to_s))
|
98
|
-
when IO, StringIO
|
99
|
-
element.rewind
|
100
|
-
contents = element.read
|
101
|
-
# note that apple plists are wrapped at a different length then
|
102
|
-
# what ruby's base64 wraps by default.
|
103
|
-
# I used #encode64 instead of #b64encode (which allows a length arg)
|
104
|
-
# because b64encode is b0rked and ignores the length arg.
|
105
|
-
data = "\n"
|
106
|
-
Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
107
|
-
output << tag('data', data)
|
108
|
-
else
|
109
|
-
output << comment( 'The <data> element below contains a Ruby object which has been serialized with Marshal.dump.' )
|
110
|
-
data = "\n"
|
111
|
-
Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
|
112
|
-
output << tag('data', data )
|
113
|
-
end
|
114
|
-
end
|
116
|
+
return output
|
117
|
+
end
|
115
118
|
|
116
|
-
|
117
|
-
|
119
|
+
def self.comment(content)
|
120
|
+
return "<!-- #{content} -->\n"
|
121
|
+
end
|
118
122
|
|
119
|
-
|
120
|
-
|
121
|
-
end
|
123
|
+
def self.tag(type, contents = '', &block)
|
124
|
+
out = nil
|
122
125
|
|
123
|
-
|
124
|
-
|
126
|
+
if block_given?
|
127
|
+
out = IndentedString.new
|
128
|
+
out << "<#{type}>"
|
129
|
+
out.raise_indent
|
125
130
|
|
126
|
-
|
127
|
-
out = IndentedString.new
|
128
|
-
out << "<#{type}>"
|
129
|
-
out.raise_indent
|
131
|
+
out << block.call
|
130
132
|
|
131
|
-
|
133
|
+
out.lower_indent
|
134
|
+
out << "</#{type}>"
|
135
|
+
else
|
136
|
+
out = "<#{type}>#{contents.to_s}</#{type}>\n"
|
137
|
+
end
|
132
138
|
|
133
|
-
|
134
|
-
|
135
|
-
else
|
136
|
-
out = "<#{type}>#{contents.to_s}</#{type}>\n"
|
137
|
-
end
|
139
|
+
return out.to_s
|
140
|
+
end
|
138
141
|
|
139
|
-
|
140
|
-
|
142
|
+
def self.wrap(contents)
|
143
|
+
output = ''
|
141
144
|
|
142
|
-
|
143
|
-
|
145
|
+
output << '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
|
146
|
+
output << '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
|
147
|
+
output << '<plist version="1.0">' + "\n"
|
144
148
|
|
145
|
-
|
146
|
-
output << '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
|
147
|
-
output << '<plist version="1.0">' + "\n"
|
149
|
+
output << contents
|
148
150
|
|
149
|
-
|
151
|
+
output << '</plist>' + "\n"
|
150
152
|
|
151
|
-
|
153
|
+
return output
|
154
|
+
end
|
152
155
|
|
153
|
-
|
154
|
-
|
156
|
+
def self.element_type(item)
|
157
|
+
return case item
|
158
|
+
when String, Symbol; 'string'
|
159
|
+
when Fixnum, Bignum, Integer; 'integer'
|
160
|
+
when Float; 'real'
|
161
|
+
else
|
162
|
+
raise "Don't know about this data type... something must be wrong!"
|
163
|
+
end
|
164
|
+
end
|
155
165
|
|
156
|
-
|
157
|
-
return case item
|
158
|
-
when String, Symbol; 'string'
|
159
|
-
when Fixnum, Bignum, Integer; 'integer'
|
160
|
-
when Float; 'real'
|
161
|
-
else
|
162
|
-
raise "Don't know about this data type... something must be wrong!"
|
163
|
-
end
|
164
|
-
end
|
166
|
+
private
|
165
167
|
|
166
|
-
|
168
|
+
class IndentedString #:nodoc:
|
169
|
+
attr_accessor :indent_string
|
167
170
|
|
168
|
-
|
169
|
-
attr_accessor :indent_string
|
171
|
+
@@indent_level = 0
|
170
172
|
|
171
|
-
|
173
|
+
def initialize(str = "\t")
|
174
|
+
@indent_string = str
|
175
|
+
@contents = ''
|
176
|
+
end
|
172
177
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
end
|
178
|
+
def to_s
|
179
|
+
return @contents
|
180
|
+
end
|
177
181
|
|
178
|
-
|
179
|
-
|
180
|
-
|
182
|
+
def raise_indent
|
183
|
+
@@indent_level += 1
|
184
|
+
end
|
181
185
|
|
182
|
-
|
183
|
-
|
184
|
-
|
186
|
+
def lower_indent
|
187
|
+
@@indent_level -= 1 if @@indent_level > 0
|
188
|
+
end
|
185
189
|
|
186
|
-
|
187
|
-
|
188
|
-
|
190
|
+
def <<(val)
|
191
|
+
if val.is_a? Array
|
192
|
+
val.each do |f|
|
193
|
+
self << f
|
194
|
+
end
|
195
|
+
else
|
196
|
+
# if it's already indented, don't bother indenting further
|
197
|
+
unless val =~ /\A#{@indent_string}/
|
198
|
+
indent = @indent_string * @@indent_level
|
189
199
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
unless val =~ /\A#{@indent_string}/
|
198
|
-
indent = @indent_string * @@indent_level
|
199
|
-
|
200
|
-
@contents << val.gsub(/^/, indent)
|
201
|
-
else
|
202
|
-
@contents << val
|
203
|
-
end
|
204
|
-
|
205
|
-
# it already has a newline, don't add another
|
206
|
-
@contents << "\n" unless val =~ /\n$/
|
207
|
-
end
|
208
|
-
end
|
200
|
+
@contents << val.gsub(/^/, indent)
|
201
|
+
else
|
202
|
+
@contents << val
|
203
|
+
end
|
204
|
+
|
205
|
+
# it already has a newline, don't add another
|
206
|
+
@contents << "\n" unless val =~ /\n$/
|
209
207
|
end
|
208
|
+
end
|
210
209
|
end
|
210
|
+
end
|
211
211
|
end
|
212
212
|
|
213
213
|
# we need to add this so sorting hash keys works properly
|
214
214
|
class Symbol #:nodoc:
|
215
|
-
|
216
|
-
|
217
|
-
|
215
|
+
def <=> (other)
|
216
|
+
self.to_s <=> other.to_s
|
217
|
+
end
|
218
218
|
end
|
219
219
|
|
220
220
|
class Array #:nodoc:
|
221
|
-
|
221
|
+
include Plist::Emit
|
222
222
|
end
|
223
223
|
|
224
224
|
class Hash #:nodoc:
|
225
|
-
|
225
|
+
include Plist::Emit
|
226
226
|
end
|
227
227
|
|
228
228
|
# $Id: generator.rb 1781 2006-10-16 01:01:35Z luke $
|