ultra_pow_list 0.1.0 → 0.1.1

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/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  source :rubygems
2
2
 
3
+ gem 'plist'
4
+
3
5
  group :dev do # not development <-> would add unneeded development dependencies in gemspec
4
6
  gem 'oniguruma', :platform => :ruby_18
5
7
  gem 'rake'
@@ -8,6 +8,7 @@ GEM
8
8
  git (>= 1.2.5)
9
9
  rake
10
10
  oniguruma (1.1.0)
11
+ plist (3.1.0)
11
12
  rake (0.9.2)
12
13
  rspec (2.6.0)
13
14
  rspec-core (~> 2.6.0)
@@ -24,5 +25,6 @@ PLATFORMS
24
25
  DEPENDENCIES
25
26
  jeweler
26
27
  oniguruma
28
+ plist
27
29
  rake
28
30
  rspec (~> 2)
data/Readme.md CHANGED
@@ -1,6 +1,9 @@
1
- Ultraviolet + TextPow + PList for Ruby 1.8 and 1.9
1
+ Ultraviolet + TextPow for Ruby 1.8 and 1.9
2
2
  Because all these libs are kind of broken and dont work well on either platform.
3
3
 
4
+ If you only need ruby 1.9, simply go with `spox-ultraviolet`.</br>
5
+ (which will load spox-plist, a slightly outdated plist flavor)
6
+
4
7
  Install
5
8
  =======
6
9
  gem install ultra_pow_list
@@ -23,8 +26,21 @@ Usage
23
26
  # or separate
24
27
  UltraPowList.make_loadable 'plist'
25
28
 
29
+ # ... whatever you want to do with these libs ...
30
+
31
+ # to html
32
+ require 'textpow'
26
33
  require 'uv'
27
- ... whatever you want to do with these libs ...
34
+ puts Uv.syntaxes.join( ", " )
35
+
36
+ # analyse syntax
37
+ language = 'ruby'
38
+ syntax = File.join(Uv.path.first,'uv', 'syntax',"#{language}.syntax")
39
+ syntax = Textpow::SyntaxNode.load(syntax)
40
+ processor = Textpow::DebugProcessor.new
41
+ puts result = syntax.parse( "class Foo\n def xxx;end\nend", processor )
42
+
43
+
28
44
 
29
45
  TODO
30
46
  ====
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -1,7 +1,7 @@
1
1
  class UltraPowList
2
2
  VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
3
3
 
4
- def self.make_loadable(libs=['plist','uv','textpow'])
4
+ def self.make_loadable(libs=['uv','textpow'])
5
5
  vendor = File.dirname(__FILE__) + "/ultra_pow_list/vendor/"
6
6
 
7
7
  dir = RUBY_VERSION =~ /^1.9/ ? "ruby1.9" : "ruby1.8"
@@ -7,7 +7,6 @@ describe UltraPowList do
7
7
 
8
8
  it "makes stuff loadable" do
9
9
  UltraPowList.make_loadable
10
- require 'plist'
11
10
  require 'textpow'
12
11
  require 'uv'
13
12
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ultra_pow_list}
8
- s.version = "0.1.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Grosser"]
12
- s.date = %q{2011-09-11}
12
+ s.date = %q{2011-09-12}
13
13
  s.email = %q{michael@grosser.it}
14
14
  s.files = [
15
15
  "Gemfile",
@@ -18,9 +18,6 @@ Gem::Specification.new do |s|
18
18
  "Readme.md",
19
19
  "VERSION",
20
20
  "lib/ultra_pow_list.rb",
21
- "lib/ultra_pow_list/vendor/ruby1.8/plist/plist.rb",
22
- "lib/ultra_pow_list/vendor/ruby1.8/plist/plist/generator.rb",
23
- "lib/ultra_pow_list/vendor/ruby1.8/plist/plist/parser.rb",
24
21
  "lib/ultra_pow_list/vendor/ruby1.8/textpow/textpow.rb",
25
22
  "lib/ultra_pow_list/vendor/ruby1.8/textpow/textpow/debug_processor.rb",
26
23
  "lib/ultra_pow_list/vendor/ruby1.8/textpow/textpow/score_manager.rb",
@@ -231,9 +228,6 @@ Gem::Specification.new do |s|
231
228
  "lib/ultra_pow_list/vendor/ruby1.8/uv/uv.rb",
232
229
  "lib/ultra_pow_list/vendor/ruby1.8/uv/uv/render_processor.rb",
233
230
  "lib/ultra_pow_list/vendor/ruby1.8/uv/uv/utility.rb",
234
- "lib/ultra_pow_list/vendor/ruby1.9/plist/plist.rb",
235
- "lib/ultra_pow_list/vendor/ruby1.9/plist/plist/generator.rb",
236
- "lib/ultra_pow_list/vendor/ruby1.9/plist/plist/parser.rb",
237
231
  "lib/ultra_pow_list/vendor/ruby1.9/textpow/textpow.rb",
238
232
  "lib/ultra_pow_list/vendor/ruby1.9/textpow/textpow/debug_processor.rb",
239
233
  "lib/ultra_pow_list/vendor/ruby1.9/textpow/textpow/score_manager.rb",
@@ -444,9 +438,12 @@ Gem::Specification.new do |s|
444
438
  s.specification_version = 3
445
439
 
446
440
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
441
+ s.add_runtime_dependency(%q<plist>, [">= 0"])
447
442
  else
443
+ s.add_dependency(%q<plist>, [">= 0"])
448
444
  end
449
445
  else
446
+ s.add_dependency(%q<plist>, [">= 0"])
450
447
  end
451
448
  end
452
449
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ultra_pow_list
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Michael Grosser
@@ -15,10 +15,23 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-11 00:00:00 +02:00
18
+ date: 2011-09-12 00:00:00 +02:00
19
19
  default_executable:
20
- dependencies: []
21
-
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ name: plist
33
+ version_requirements: *id001
34
+ prerelease: false
22
35
  description:
23
36
  email: michael@grosser.it
24
37
  executables: []
@@ -34,9 +47,6 @@ files:
34
47
  - Readme.md
35
48
  - VERSION
36
49
  - lib/ultra_pow_list.rb
37
- - lib/ultra_pow_list/vendor/ruby1.8/plist/plist.rb
38
- - lib/ultra_pow_list/vendor/ruby1.8/plist/plist/generator.rb
39
- - lib/ultra_pow_list/vendor/ruby1.8/plist/plist/parser.rb
40
50
  - lib/ultra_pow_list/vendor/ruby1.8/textpow/textpow.rb
41
51
  - lib/ultra_pow_list/vendor/ruby1.8/textpow/textpow/debug_processor.rb
42
52
  - lib/ultra_pow_list/vendor/ruby1.8/textpow/textpow/score_manager.rb
@@ -247,9 +257,6 @@ files:
247
257
  - lib/ultra_pow_list/vendor/ruby1.8/uv/uv.rb
248
258
  - lib/ultra_pow_list/vendor/ruby1.8/uv/uv/render_processor.rb
249
259
  - lib/ultra_pow_list/vendor/ruby1.8/uv/uv/utility.rb
250
- - lib/ultra_pow_list/vendor/ruby1.9/plist/plist.rb
251
- - lib/ultra_pow_list/vendor/ruby1.9/plist/plist/generator.rb
252
- - lib/ultra_pow_list/vendor/ruby1.9/plist/plist/parser.rb
253
260
  - lib/ultra_pow_list/vendor/ruby1.9/textpow/textpow.rb
254
261
  - lib/ultra_pow_list/vendor/ruby1.9/textpow/textpow/debug_processor.rb
255
262
  - lib/ultra_pow_list/vendor/ruby1.9/textpow/textpow/score_manager.rb
@@ -1,22 +0,0 @@
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
@@ -1,224 +0,0 @@
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: '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
165
- private
166
- class IndentedString #:nodoc:
167
- attr_accessor :indent_string
168
-
169
- @@indent_level = 0
170
-
171
- def initialize(str = "\t")
172
- @indent_string = str
173
- @contents = ''
174
- end
175
-
176
- def to_s
177
- return @contents
178
- end
179
-
180
- def raise_indent
181
- @@indent_level += 1
182
- end
183
-
184
- def lower_indent
185
- @@indent_level -= 1 if @@indent_level > 0
186
- end
187
-
188
- def <<(val)
189
- if val.is_a? Array
190
- val.each do |f|
191
- self << f
192
- end
193
- else
194
- # if it's already indented, don't bother indenting further
195
- unless val =~ /\A#{@indent_string}/
196
- indent = @indent_string * @@indent_level
197
-
198
- @contents << val.gsub(/^/, indent)
199
- else
200
- @contents << val
201
- end
202
-
203
- # it already has a newline, don't add another
204
- @contents << "\n" unless val =~ /\n$/
205
- end
206
- end
207
- end
208
- end
209
- end
210
-
211
- # we need to add this so sorting hash keys works properly
212
- class Symbol #:nodoc:
213
- def <=> (other)
214
- self.to_s <=> other.to_s
215
- end
216
- end
217
-
218
- class Array #:nodoc:
219
- include Plist::Emit
220
- end
221
-
222
- class Hash #:nodoc:
223
- include Plist::Emit
224
- end
@@ -1,224 +0,0 @@
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
@@ -1,23 +0,0 @@
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
- # encoding: utf-8
14
- require 'base64'
15
- require 'cgi'
16
- require 'stringio'
17
-
18
- require 'plist/generator'
19
- require 'plist/parser'
20
-
21
- module Plist
22
- VERSION = '3.0.0'
23
- end
@@ -1,228 +0,0 @@
1
- # encoding: utf-8
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
- # See Plist::Emit.
10
- module Plist
11
- # === Create a plist
12
- # You can dump an object to a plist in one of two ways:
13
- #
14
- # * <tt>Plist::Emit.dump(obj)</tt>
15
- # * <tt>obj.to_plist</tt>
16
- # * This requires that you mixin the <tt>Plist::Emit</tt> module, which is already done for +Array+ and +Hash+.
17
- #
18
- # The following Ruby classes are converted into native plist types:
19
- # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time, true, false
20
- # * +Array+ and +Hash+ are both recursive; their elements will be converted into plist nodes inside the <array> and <dict> containers (respectively).
21
- # * +IO+ (and its descendants) and +StringIO+ objects are read from and their contents placed in a <data> element.
22
- # * 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.
23
- #
24
- # For detailed usage instructions, refer to USAGE[link:files/docs/USAGE.html] and the methods documented below.
25
- module Emit
26
- # Helper method for injecting into classes. Calls <tt>Plist::Emit.dump</tt> with +self+.
27
- def to_plist(envelope = true)
28
- return Plist::Emit.dump(self, envelope)
29
- end
30
-
31
- # Helper method for injecting into classes. Calls <tt>Plist::Emit.save_plist</tt> with +self+.
32
- def save_plist(filename)
33
- Plist::Emit.save_plist(self, filename)
34
- end
35
-
36
- # The following Ruby classes are converted into native plist types:
37
- # Array, Bignum, Date, DateTime, Fixnum, Float, Hash, Integer, String, Symbol, Time
38
- #
39
- # Write us (via RubyForge) if you think another class can be coerced safely into one of the expected plist classes.
40
- #
41
- # +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+.
42
- #
43
- # 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.
44
- def self.dump(obj, envelope = true)
45
- output = plist_node(obj)
46
-
47
- output = wrap(output) if envelope
48
-
49
- return output
50
- end
51
-
52
- # Writes the serialized object's plist to the specified filename.
53
- def self.save_plist(obj, filename)
54
- File.open(filename, 'wb') do |f|
55
- f.write(obj.to_plist)
56
- end
57
- end
58
-
59
- private
60
- def self.plist_node(element)
61
- output = ''
62
-
63
- if element.respond_to? :to_plist_node
64
- output << element.to_plist_node
65
- else
66
- case element
67
- when Array
68
- if element.empty?
69
- output << "<array/>\n"
70
- else
71
- output << tag('array') {
72
- element.collect {|e| plist_node(e)}
73
- }
74
- end
75
- when Hash
76
- if element.empty?
77
- output << "<dict/>\n"
78
- else
79
- inner_tags = []
80
-
81
- element.keys.sort.each do |k|
82
- v = element[k]
83
- inner_tags << tag('key', CGI::escapeHTML(k.to_s))
84
- inner_tags << plist_node(v)
85
- end
86
-
87
- output << tag('dict') {
88
- inner_tags
89
- }
90
- end
91
- when true, false
92
- output << "<#{element}/>\n"
93
- when Time
94
- output << tag('date', element.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
95
- when Date # also catches DateTime
96
- output << tag('date', element.strftime('%Y-%m-%dT%H:%M:%SZ'))
97
- when String, Symbol, Fixnum, Bignum, Integer, Float
98
- output << tag(element_type(element), CGI::escapeHTML(element.to_s))
99
- when IO, StringIO
100
- element.rewind
101
- contents = element.read
102
- # note that apple plists are wrapped at a different length then
103
- # what ruby's base64 wraps by default.
104
- # I used #encode64 instead of #b64encode (which allows a length arg)
105
- # because b64encode is b0rked and ignores the length arg.
106
- data = "\n"
107
- Base64::encode64(contents).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
108
- output << tag('data', data)
109
- else
110
- output << comment( 'The <data> element below contains a Ruby object which has been serialized with Marshal.dump.' )
111
- data = "\n"
112
- Base64::encode64(Marshal.dump(element)).gsub(/\s+/, '').scan(/.{1,68}/o) { data << $& << "\n" }
113
- output << tag('data', data )
114
- end
115
- end
116
-
117
- return output
118
- end
119
-
120
- def self.comment(content)
121
- return "<!-- #{content} -->\n"
122
- end
123
-
124
- def self.tag(type, contents = '', &block)
125
- out = nil
126
-
127
- if block_given?
128
- out = IndentedString.new
129
- out << "<#{type}>"
130
- out.raise_indent
131
-
132
- out << block.call
133
-
134
- out.lower_indent
135
- out << "</#{type}>"
136
- else
137
- out = "<#{type}>#{contents.to_s}</#{type}>\n"
138
- end
139
-
140
- return out.to_s
141
- end
142
-
143
- def self.wrap(contents)
144
- output = ''
145
-
146
- output << '<?xml version="1.0" encoding="UTF-8"?>' + "\n"
147
- output << '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">' + "\n"
148
- output << '<plist version="1.0">' + "\n"
149
-
150
- output << contents
151
-
152
- output << '</plist>' + "\n"
153
-
154
- return output
155
- end
156
-
157
- def self.element_type(item)
158
- return case item
159
- when String, Symbol
160
- 'string'
161
- when Fixnum, Bignum, Integer
162
- 'integer'
163
- when Float
164
- 'real'
165
- else
166
- raise "Don't know about this data type... something must be wrong!"
167
- end
168
- end
169
- private
170
- class IndentedString #:nodoc:
171
- attr_accessor :indent_string
172
-
173
- @@indent_level = 0
174
-
175
- def initialize(str = "\t")
176
- @indent_string = str
177
- @contents = ''
178
- end
179
-
180
- def to_s
181
- return @contents
182
- end
183
-
184
- def raise_indent
185
- @@indent_level += 1
186
- end
187
-
188
- def lower_indent
189
- @@indent_level -= 1 if @@indent_level > 0
190
- end
191
-
192
- def <<(val)
193
- if val.is_a? Array
194
- val.each do |f|
195
- self << f
196
- end
197
- else
198
- # if it's already indented, don't bother indenting further
199
- unless val =~ /\A#{@indent_string}/
200
- indent = @indent_string * @@indent_level
201
-
202
- @contents << val.gsub(/^/, indent)
203
- else
204
- @contents << val
205
- end
206
-
207
- # it already has a newline, don't add another
208
- @contents << "\n" unless val =~ /\n$/
209
- end
210
- end
211
- end
212
- end
213
- end
214
-
215
- # we need to add this so sorting hash keys works properly
216
- class Symbol #:nodoc:
217
- def <=> (other)
218
- self.to_s <=> other.to_s
219
- end
220
- end
221
-
222
- class Array #:nodoc:
223
- include Plist::Emit
224
- end
225
-
226
- class Hash #:nodoc:
227
- include Plist::Emit
228
- end
@@ -1,225 +0,0 @@
1
- # encoding: utf-8
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 parses Mac OS X xml property list files into ruby data structures.
10
- #
11
- # === Load a plist file
12
- # This is the main point of the library:
13
- #
14
- # r = Plist::parse_xml( filename_or_xml )
15
- module Plist
16
- # Note that I don't use these two elements much:
17
- #
18
- # + Date elements are returned as DateTime objects.
19
- # + Data elements are implemented as Tempfiles
20
- #
21
- # Plist::parse_xml will blow up if it encounters a data element.
22
- # If you encounter such an error, or if you have a Date element which
23
- # can't be parsed into a Time object, please send your plist file to
24
- # plist@hexane.org so that I can implement the proper support.
25
- def Plist::parse_xml( filename_or_xml )
26
- listener = Listener.new
27
- #parser = REXML::Parsers::StreamParser.new(File.new(filename), listener)
28
- parser = StreamParser.new(filename_or_xml, listener)
29
- parser.parse
30
- listener.result
31
- end
32
-
33
- class Listener
34
- #include REXML::StreamListener
35
-
36
- attr_accessor :result, :open
37
-
38
- def initialize
39
- @result = nil
40
- @open = Array.new
41
- end
42
-
43
-
44
- def tag_start(name, attributes)
45
- @open.push PTag::mappings[name].new
46
- end
47
-
48
- def text( contents )
49
- @open.last.text = contents if @open.last
50
- end
51
-
52
- def tag_end(name)
53
- last = @open.pop
54
- if @open.empty?
55
- @result = last.to_ruby
56
- else
57
- @open.last.children.push last
58
- end
59
- end
60
- end
61
-
62
- class StreamParser
63
- def initialize( plist_data_or_file, listener )
64
- if plist_data_or_file.respond_to? :read
65
- @xml = plist_data_or_file.read
66
- elsif File.exists? plist_data_or_file
67
- @xml = File.read( plist_data_or_file )
68
- else
69
- @xml = plist_data_or_file
70
- end
71
-
72
- @listener = listener
73
- end
74
-
75
- TEXT = /([^<]+)/
76
- XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>*/um
77
- DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
78
- COMMENT_START = /\A<!--/u
79
- COMMENT_END = /.*?-->/um
80
-
81
-
82
- def parse
83
- plist_tags = PTag::mappings.keys.join('|')
84
- start_tag = /<(#{plist_tags})([^>]*)>/i
85
- end_tag = /<\/(#{plist_tags})[^>]*>/i
86
-
87
- require 'strscan'
88
-
89
- @scanner = StringScanner.new( @xml )
90
- until @scanner.eos?
91
- if @scanner.scan(COMMENT_START)
92
- @scanner.scan(COMMENT_END)
93
- elsif @scanner.scan(XMLDECL_PATTERN)
94
- elsif @scanner.scan(DOCTYPE_PATTERN)
95
- elsif @scanner.scan(start_tag)
96
- @listener.tag_start(@scanner[1], nil)
97
- if (@scanner[2] =~ /\/$/)
98
- @listener.tag_end(@scanner[1])
99
- end
100
- elsif @scanner.scan(TEXT)
101
- @listener.text(@scanner[1])
102
- elsif @scanner.scan(end_tag)
103
- @listener.tag_end(@scanner[1])
104
- else
105
- raise "Unimplemented element"
106
- end
107
- end
108
- end
109
- end
110
-
111
- class PTag
112
- @@mappings = { }
113
- def PTag::mappings
114
- @@mappings
115
- end
116
-
117
- def PTag::inherited( sub_class )
118
- key = sub_class.to_s.downcase
119
- key.gsub!(/^plist::/, '' )
120
- key.gsub!(/^p/, '') unless key == "plist"
121
-
122
- @@mappings[key] = sub_class
123
- end
124
-
125
- attr_accessor :text, :children
126
- def initialize
127
- @children = Array.new
128
- end
129
-
130
- def to_ruby
131
- raise "Unimplemented: " + self.class.to_s + "#to_ruby on #{self.inspect}"
132
- end
133
- end
134
-
135
- class PList < PTag
136
- def to_ruby
137
- children.first.to_ruby if children.first
138
- end
139
- end
140
-
141
- class PDict < PTag
142
- def to_ruby
143
- dict = Hash.new
144
- key = nil
145
-
146
- children.each do |c|
147
- if key.nil?
148
- key = c.to_ruby
149
- else
150
- dict[key] = c.to_ruby
151
- key = nil
152
- end
153
- end
154
-
155
- dict
156
- end
157
- end
158
-
159
- class PKey < PTag
160
- def to_ruby
161
- CGI::unescapeHTML(text || '')
162
- end
163
- end
164
-
165
- class PString < PTag
166
- def to_ruby
167
- CGI::unescapeHTML(text || '')
168
- end
169
- end
170
-
171
- class PArray < PTag
172
- def to_ruby
173
- children.collect do |c|
174
- c.to_ruby
175
- end
176
- end
177
- end
178
-
179
- class PInteger < PTag
180
- def to_ruby
181
- text.to_i
182
- end
183
- end
184
-
185
- class PTrue < PTag
186
- def to_ruby
187
- true
188
- end
189
- end
190
-
191
- class PFalse < PTag
192
- def to_ruby
193
- false
194
- end
195
- end
196
-
197
- class PReal < PTag
198
- def to_ruby
199
- text.to_f
200
- end
201
- end
202
-
203
- require 'date'
204
- class PDate < PTag
205
- def to_ruby
206
- DateTime.parse(text)
207
- end
208
- end
209
-
210
- require 'base64'
211
- class PData < PTag
212
- def to_ruby
213
- data = Base64.decode64(text.gsub(/\s+/, ''))
214
-
215
- begin
216
- return Marshal.load(data)
217
- rescue Exception => e
218
- io = StringIO.new
219
- io.write data
220
- io.rewind
221
- return io
222
- end
223
- end
224
- end
225
- end