spox-plist 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,85 @@
1
+ = plist - All-purpose Property List manipulation library
2
+
3
+ 2007-02-22 (r81):
4
+ * make the plist parser accept strings contain XML or any object that responds to #read (File and StringIO being the intended targets here). Test and idea contributed by Chuck Remes.
5
+
6
+ 2006-09-20 (r80):
7
+ * tweak a comment in generator.rb to make it clear that we're not using Base64.b64encode because it's broken.
8
+
9
+ === Release version 3.0.0!
10
+
11
+ 2006-09-20 (r77 - r79):
12
+ * move IndentedString inside Plist::Emit and :nodoc: it
13
+ * Tag 3.0.0! (from rev 78)
14
+
15
+ 2006-09-19 (r73 - r75):
16
+ * Really fix the rakefile this time (apparently I deleted some code that I needed...)
17
+ * alter the fix_whitespace rake task to ignore the assets directory
18
+ * cleanup whitespace
19
+
20
+ 2006-09-18 (r70 - r72):
21
+ * Update this file ;)
22
+ * Fix Rakefile
23
+ * gem install -t now works correctly
24
+ * Remove super-sekr1t rdoc staging area from rdoc publishing task
25
+
26
+ 2006-09-15 (r64 - r69):
27
+ * Change behavior of empty collection elements to match What Apple Does
28
+ * Fix some gem packaging infrastructure
29
+
30
+ 2006-09-13 (r61 - r63):
31
+ * Merge generator injection removal branch into trunk!
32
+
33
+ 2006-09-13 (r52 - r60):
34
+ * Fix indentation/newlines in generator (finally!)
35
+ * Refix indentation to be more faithful to the way Apple emits their plists
36
+ * Remove horrific regex and replace it with proper comment parsing
37
+ * Empty plists return nil when parsed
38
+ * Sort hash keys before emitting (now we can test multi-element hashes!)
39
+ * Inject #<=> into Symbol so that sorting Symbol-keyed hashes won't freak out
40
+
41
+ 2006-09-12 (r47 - r51):
42
+ * More test rejiggering
43
+ * New tests to expose some bugs
44
+
45
+ 2006-09-10 (r33 - r46):
46
+ * Update tests for new generator code
47
+ * Rejigger some tests
48
+ * Make the generator try to call #to_plist_node on any object it tries to serialize, thus allowing class authors to define how their objects will be serialized
49
+ * Marshal.dump unrecognized objects into <data> elements
50
+ * Make the parser strip out comments and Marshal.load <data> elements if possible
51
+ * Update some rdoc
52
+
53
+ === Release version 2.1.1!
54
+
55
+ 2006-09-10 (r31 - r32):
56
+ * Added encoding / decoding for entities (&amp; etc)
57
+ * Changed parsing of <data> elements to return StringIO objects
58
+ * Fixed bug with empty <key> tags
59
+
60
+ 2006-08-24 (r25 - r30):
61
+ * Invert ownership of methods in the generator, allowing us to remove the self.extend(self)
62
+ * New branch to remove method inject from parser
63
+
64
+ 2006-08-23 (r22 - r24):
65
+ * Add rcov task to Rakefile
66
+ * Add some tests
67
+
68
+ 2006-08-20 (r9 - r21):
69
+ * Add a bunch of rdoc and rdoc infrastructure
70
+ * Add rake task to clean up errant whitespace
71
+ * Spin off a branch to remove a bunch of method injection in the generator code
72
+ * Rename some tests for clarity's sake
73
+ * Replace NARF generation code with Ben's generation code
74
+ * Update tests
75
+ * This broke indentation (will be fixed later)
76
+ * Add Plist::Emit.dump, so you can dump objects which don't include Plist::Emit, update tests to match
77
+ * Fix a bug with the method that wraps output in the plist header/footer
78
+
79
+ 2006-08-19 (r1 - r8):
80
+ * The beginnings of merging the plist project into the NARF plist library (under the plist project's name)
81
+ * fancier project infrastructure (more tests, Rakefile, the like)
82
+ * Add/update copyright notices in the source files
83
+ * Move a bunch of documentation out to README
84
+ * Split library into chunks
85
+ * Properly delete files when cleaning up from tests
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2006, Ben Bleything <ben@bleything.net>
2
+ and Patrick May <patrick@hexane.org>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included
13
+ in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16
+ KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,36 @@
1
+ = All-purpose Property List manipulation library
2
+
3
+ Plist is a library to manipulate Property List files, also known as plists. It can parse plist files into native Ruby data structures as well as generating new plist files from your Ruby objects.
4
+
5
+ == Usage
6
+
7
+ See USAGE[link:files/docs/USAGE.html].
8
+
9
+ == Links
10
+
11
+ [<b>Project Page</b>] http://plist.rubyforge.org
12
+ [<b>Subversion repository</b>] svn://rubyforge.org//var/svn/plist
13
+ [<b>RDoc (on RubyForge)</b>] http://plist.rubyforge.org
14
+
15
+ == Credits
16
+
17
+ plist is maintained by Ben Bleything <mailto:ben@bleything.net> and Patrick May <mailto:patrick@hexane.org>. Patrick wrote most of the code; Ben is a recent addition to the project, having merged in his plist generation library.
18
+
19
+ Other folks who have helped along the way:
20
+
21
+ [<b>Martin Dittus</b>] who pointed out that +Time+ wasn't enough for plist <tt>Dates</tt>, especially those in <tt>~/Library/Cookies/Cookies.plist</tt>
22
+ [<b>Chuck Remes</b>] who pushed Patrick towards implementing <tt>#to_plist</tt>
23
+ [<b>Mat Schaffer</b>] who supplied code and test cases for <tt><data></tt> elements
24
+ [<b>Michael Granger</b>] for encouragement and help
25
+
26
+ == License and Copyright
27
+
28
+ plist is released under the MIT License.
29
+
30
+ Portions of the code (notably the Rakefile) contain code pulled and/or adapted from other projects. These files contain a comment at the top describing what was used.
31
+
32
+ === MIT License
33
+
34
+ :include: MIT-LICENSE
35
+
36
+
@@ -0,0 +1,22 @@
1
+ #--
2
+ ##############################################################
3
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
4
+ # Patrick May <patrick@hexane.org> #
5
+ # #
6
+ # Distributed under the MIT license. #
7
+ ##############################################################
8
+ #++
9
+ # = Plist
10
+ #
11
+ # This is the main file for plist. Everything interesting happens in Plist and Plist::Emit.
12
+
13
+ require 'base64'
14
+ require 'cgi'
15
+ require 'stringio'
16
+
17
+ require 'plist/generator'
18
+ require 'plist/parser'
19
+
20
+ module Plist
21
+ VERSION = '3.0.0'
22
+ end
@@ -0,0 +1,227 @@
1
+ #--###########################################################
2
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
3
+ # Patrick May <patrick@hexane.org> #
4
+ # #
5
+ # Distributed under the MIT license. #
6
+ ##############################################################
7
+ #++
8
+ # See Plist::Emit.
9
+ module Plist
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
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)
45
+
46
+ output = wrap(output) if envelope
47
+
48
+ return output
49
+ end
50
+
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
57
+
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)
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
115
+
116
+ return output
117
+ end
118
+
119
+ def self.comment(content)
120
+ return "<!-- #{content} -->\n"
121
+ end
122
+
123
+ def self.tag(type, contents = '', &block)
124
+ out = nil
125
+
126
+ if block_given?
127
+ out = IndentedString.new
128
+ out << "<#{type}>"
129
+ out.raise_indent
130
+
131
+ out << block.call
132
+
133
+ out.lower_indent
134
+ out << "</#{type}>"
135
+ else
136
+ out = "<#{type}>#{contents.to_s}</#{type}>\n"
137
+ end
138
+
139
+ return out.to_s
140
+ end
141
+
142
+ def self.wrap(contents)
143
+ output = ''
144
+
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"
148
+
149
+ output << contents
150
+
151
+ output << '</plist>' + "\n"
152
+
153
+ return output
154
+ end
155
+
156
+ def self.element_type(item)
157
+ return case item
158
+ when String, Symbol
159
+ 'string'
160
+ when Fixnum, Bignum, Integer
161
+ 'integer'
162
+ when Float
163
+ 'real'
164
+ else
165
+ raise "Don't know about this data type... something must be wrong!"
166
+ end
167
+ end
168
+ private
169
+ class IndentedString #:nodoc:
170
+ attr_accessor :indent_string
171
+
172
+ @@indent_level = 0
173
+
174
+ def initialize(str = "\t")
175
+ @indent_string = str
176
+ @contents = ''
177
+ end
178
+
179
+ def to_s
180
+ return @contents
181
+ end
182
+
183
+ def raise_indent
184
+ @@indent_level += 1
185
+ end
186
+
187
+ def lower_indent
188
+ @@indent_level -= 1 if @@indent_level > 0
189
+ end
190
+
191
+ def <<(val)
192
+ if val.is_a? Array
193
+ val.each do |f|
194
+ self << f
195
+ end
196
+ else
197
+ # if it's already indented, don't bother indenting further
198
+ unless val =~ /\A#{@indent_string}/
199
+ indent = @indent_string * @@indent_level
200
+
201
+ @contents << val.gsub(/^/, indent)
202
+ else
203
+ @contents << val
204
+ end
205
+
206
+ # it already has a newline, don't add another
207
+ @contents << "\n" unless val =~ /\n$/
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ # we need to add this so sorting hash keys works properly
215
+ class Symbol #:nodoc:
216
+ def <=> (other)
217
+ self.to_s <=> other.to_s
218
+ end
219
+ end
220
+
221
+ class Array #:nodoc:
222
+ include Plist::Emit
223
+ end
224
+
225
+ class Hash #:nodoc:
226
+ include Plist::Emit
227
+ end
@@ -0,0 +1,224 @@
1
+ #--###########################################################
2
+ # Copyright 2006, Ben Bleything <ben@bleything.net> and #
3
+ # Patrick May <patrick@hexane.org> #
4
+ # #
5
+ # Distributed under the MIT license. #
6
+ ##############################################################
7
+ #++
8
+ # Plist parses Mac OS X xml property list files into ruby data structures.
9
+ #
10
+ # === Load a plist file
11
+ # This is the main point of the library:
12
+ #
13
+ # r = Plist::parse_xml( filename_or_xml )
14
+ module Plist
15
+ # Note that I don't use these two elements much:
16
+ #
17
+ # + Date elements are returned as DateTime objects.
18
+ # + Data elements are implemented as Tempfiles
19
+ #
20
+ # Plist::parse_xml will blow up if it encounters a data element.
21
+ # If you encounter such an error, or if you have a Date element which
22
+ # can't be parsed into a Time object, please send your plist file to
23
+ # plist@hexane.org so that I can implement the proper support.
24
+ def Plist::parse_xml( filename_or_xml )
25
+ listener = Listener.new
26
+ #parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
27
+ parser = StreamParser.new(filename_or_xml, listener)
28
+ parser.parse
29
+ listener.result
30
+ end
31
+
32
+ class Listener
33
+ #include REXML::StreamListener
34
+
35
+ attr_accessor :result, :open
36
+
37
+ def initialize
38
+ @result = nil
39
+ @open = Array.new
40
+ end
41
+
42
+
43
+ def tag_start(name, attributes)
44
+ @open.push PTag::mappings[name].new
45
+ end
46
+
47
+ def text( contents )
48
+ @open.last.text = contents if @open.last
49
+ end
50
+
51
+ def tag_end(name)
52
+ last = @open.pop
53
+ if @open.empty?
54
+ @result = last.to_ruby
55
+ else
56
+ @open.last.children.push last
57
+ end
58
+ end
59
+ end
60
+
61
+ class StreamParser
62
+ def initialize( plist_data_or_file, listener )
63
+ if plist_data_or_file.respond_to? :read
64
+ @xml = plist_data_or_file.read
65
+ elsif File.exists? plist_data_or_file
66
+ @xml = File.read( plist_data_or_file )
67
+ else
68
+ @xml = plist_data_or_file
69
+ end
70
+
71
+ @listener = listener
72
+ end
73
+
74
+ TEXT = /([^<]+)/
75
+ XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/um
76
+ DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
77
+ COMMENT_START = /\A<!--/u
78
+ COMMENT_END = /.*?-->/um
79
+
80
+
81
+ def parse
82
+ plist_tags = PTag::mappings.keys.join('|')
83
+ start_tag = /<(#{plist_tags})([^>]*)>/i
84
+ end_tag = /<\/(#{plist_tags})[^>]*>/i
85
+
86
+ require 'strscan'
87
+
88
+ @scanner = StringScanner.new( @xml )
89
+ until @scanner.eos?
90
+ if @scanner.scan(COMMENT_START)
91
+ @scanner.scan(COMMENT_END)
92
+ elsif @scanner.scan(XMLDECL_PATTERN)
93
+ elsif @scanner.scan(DOCTYPE_PATTERN)
94
+ elsif @scanner.scan(start_tag)
95
+ @listener.tag_start(@scanner[1], nil)
96
+ if (@scanner[2] =~ /\/$/)
97
+ @listener.tag_end(@scanner[1])
98
+ end
99
+ elsif @scanner.scan(TEXT)
100
+ @listener.text(@scanner[1])
101
+ elsif @scanner.scan(end_tag)
102
+ @listener.tag_end(@scanner[1])
103
+ else
104
+ raise "Unimplemented element"
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ class PTag
111
+ @@mappings = { }
112
+ def PTag::mappings
113
+ @@mappings
114
+ end
115
+
116
+ def PTag::inherited( sub_class )
117
+ key = sub_class.to_s.downcase
118
+ key.gsub!(/^plist::/, '' )
119
+ key.gsub!(/^p/, '') unless key == "plist"
120
+
121
+ @@mappings[key] = sub_class
122
+ end
123
+
124
+ attr_accessor :text, :children
125
+ def initialize
126
+ @children = Array.new
127
+ end
128
+
129
+ def to_ruby
130
+ raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}"
131
+ end
132
+ end
133
+
134
+ class PList < PTag
135
+ def to_ruby
136
+ children.first.to_ruby if children.first
137
+ end
138
+ end
139
+
140
+ class PDict < PTag
141
+ def to_ruby
142
+ dict = Hash.new
143
+ key = nil
144
+
145
+ children.each do |c|
146
+ if key.nil?
147
+ key = c.to_ruby
148
+ else
149
+ dict[key] = c.to_ruby
150
+ key = nil
151
+ end
152
+ end
153
+
154
+ dict
155
+ end
156
+ end
157
+
158
+ class PKey < PTag
159
+ def to_ruby
160
+ CGI::unescapeHTML(text || '')
161
+ end
162
+ end
163
+
164
+ class PString < PTag
165
+ def to_ruby
166
+ CGI::unescapeHTML(text || '')
167
+ end
168
+ end
169
+
170
+ class PArray < PTag
171
+ def to_ruby
172
+ children.collect do |c|
173
+ c.to_ruby
174
+ end
175
+ end
176
+ end
177
+
178
+ class PInteger < PTag
179
+ def to_ruby
180
+ text.to_i
181
+ end
182
+ end
183
+
184
+ class PTrue < PTag
185
+ def to_ruby
186
+ true
187
+ end
188
+ end
189
+
190
+ class PFalse < PTag
191
+ def to_ruby
192
+ false
193
+ end
194
+ end
195
+
196
+ class PReal < PTag
197
+ def to_ruby
198
+ text.to_f
199
+ end
200
+ end
201
+
202
+ require 'date'
203
+ class PDate < PTag
204
+ def to_ruby
205
+ DateTime.parse(text)
206
+ end
207
+ end
208
+
209
+ require 'base64'
210
+ class PData < PTag
211
+ def to_ruby
212
+ data = Base64.decode64(text.gsub(/\s+/, ''))
213
+
214
+ begin
215
+ return Marshal.load(data)
216
+ rescue Exception => e
217
+ io = StringIO.new
218
+ io.write data
219
+ io.rewind
220
+ return io
221
+ end
222
+ end
223
+ end
224
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spox-plist
3
+ version: !ruby/object:Gem::Version
4
+ hash: 5
5
+ prerelease: false
6
+ segments:
7
+ - 3
8
+ - 0
9
+ - 1
10
+ version: 3.0.1
11
+ platform: ruby
12
+ authors:
13
+ - spox
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-27 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Ruby plist library
23
+ email: spox@modspox.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README
30
+ files:
31
+ - MIT-LICENSE
32
+ - README
33
+ - CHANGELOG
34
+ - lib/plist.rb
35
+ - lib/plist/generator.rb
36
+ - lib/plist/parser.rb
37
+ has_rdoc: true
38
+ homepage:
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --title
44
+ - plist
45
+ - --main
46
+ - README
47
+ - --line-numbers
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 51
56
+ segments:
57
+ - 1
58
+ - 9
59
+ - 0
60
+ version: 1.9.0
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.7
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: plist
77
+ test_files: []
78
+