binary_plist 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog.markdown CHANGED
@@ -1,3 +1,13 @@
1
- 0.0.1 (Jul 23, 2010)
1
+ ### 0.0.3 (Jul 26, 2010)
2
+
3
+ * Fixed ASCII string encoding - closes #1
4
+
5
+ ### 0.0.2 (Jul 25, 2010)
6
+
7
+ * Cleaned up converter
8
+ * Changed to more standard `.plist` extension
9
+ * Added basic specs
10
+
11
+ ### 0.0.1 (Jul 23, 2010)
2
12
 
3
13
  * Initial release
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "spec/rake/spectask"
4
+
5
+ spec_files = Rake::FileList["spec/*_spec.rb"]
6
+
7
+ desc "Run specs"
8
+ Spec::Rake::SpecTask.new do |t|
9
+ t.spec_files = spec_files
10
+ t.spec_opts = ['--color', '--format=specdoc']
11
+ end
12
+
13
+ task :default => :spec
data/Readme.markdown CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Rails plugin for easily adding a binary plist format. The binary plist format is ideal for transferring data to an Objective-C based application.
4
4
 
5
+ **Note:** This is still a work in progress. It should be ready to use for most applications. The most noticeable issue is the lack of support for large integers.
6
+
5
7
  ## Installation
6
8
 
7
9
  Add the following line to your bundle and run `bundle install`.
@@ -10,13 +12,13 @@ Add the following line to your bundle and run `bundle install`.
10
12
 
11
13
  ## Usage
12
14
 
13
- All you have to do is add the `bplist` format to your `respond_to` block:
15
+ All you have to do is add the `plist` format to your `respond_to` block:
14
16
 
15
17
  def index
16
18
  @posts = Post.all
17
19
  respond_to do |format|
18
20
  format.html
19
- format.bplist { render :bplist => @posts }
21
+ format.plist { render :plist => @posts }
20
22
  end
21
23
  end
22
24
 
@@ -26,7 +28,7 @@ You can do the combined style if you're support multiple formats like `json` or
26
28
  @posts = Post.all
27
29
  respond_to do |format|
28
30
  format.html
29
- format.any(:json, :bplist) { render request.format.to_sym => @posts }
31
+ format.any(:json, :plist) { render request.format.to_sym => @posts }
30
32
  end
31
33
  end
32
34
 
@@ -34,12 +36,12 @@ You can do the combined style if you're support multiple formats like `json` or
34
36
 
35
37
  On the Objective-C side, it's ridiculously easy to consume the plist data.
36
38
 
37
- NSURL *url = [NSURL URLWithString:@"http://localhost:3000/posts.bplist"];
39
+ NSURL *url = [NSURL URLWithString:@"http://localhost:3000/posts.plist"];
38
40
  NSArray *posts = [NSArray arrayWithContentsOfURL:url];
39
41
 
40
42
  You can also use the more flexible syntax:
41
43
 
42
- NSURL *url = [NSURL URLWithString:@"http://localhost:3000/posts.bplist"];
44
+ NSURL *url = [NSURL URLWithString:@"http://localhost:3000/posts.plist"];
43
45
  NSDate *date = [NSData dataWithContentsOfURL:url];
44
46
  id result = [NSPropertyListSerialization propertyListFromData:data
45
47
  mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:nil];
data/Todo.markdown ADDED
@@ -0,0 +1,8 @@
1
+ # Binary Plist To Do List
2
+
3
+ * Fix trailer
4
+ * Support large integers
5
+ * Support `Date`
6
+ * Support `DateTime`
7
+ * Use `NSNull` instead of `@""` for nil
8
+ * Finish specing all parts of the encoder
data/init.rb CHANGED
@@ -7,5 +7,5 @@ ActionController::Renderers.add :bplist do |data, options|
7
7
  data = ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data, options))
8
8
 
9
9
  self.content_type ||= Mime::BPLIST
10
- self.response_body = BinaryPlist::Converter.convert(data)
10
+ self.response_body = BinaryPlist.encode(data)
11
11
  end
data/lib/binary_plist.rb CHANGED
@@ -6,122 +6,117 @@ module BinaryPlist
6
6
  # Very generic type for now
7
7
  MIME_TYPE = 'application/octet-stream'
8
8
 
9
- module Converter
9
+ # Difference between Apple and UNIX timestamps
10
+ DATE_EPOCH_OFFSET_APPLE_UNIX = 978307200
10
11
 
11
- # Difference between Apple and UNIX timestamps
12
- DATE_EPOCH_OFFSET_APPLE_UNIX = 978307200
12
+ # Text encoding
13
+ INPUT_TEXT_ENCODING = 'UTF-8'
14
+ PLIST_TEXT_ENCODING = 'UTF-16BE'
13
15
 
14
- # Text encoding
15
- INPUT_TEXT_ENCODING = 'UTF-8'
16
- PLIST_TEXT_ENCODING = 'UTF-16BE'
16
+ # For marking strings as binary data which will be decoded as a CFData object
17
+ CFData = Struct.new(:data)
18
+
19
+ # Convert a Ruby data structure into a binary property list file.
20
+ # Works as you'd expect. Integers are limited to 4 bytes, even though the format implies longer values can be written.
21
+ # Strings are assumed to be in UTF-8 format. Symbols are written as strings.
22
+ def self.encode object
23
+ write "", object
24
+ end
25
+
26
+ # Alternative interface which writes data to the out object using <<
27
+ def self.write out, object
28
+ # Find out how many objects there are, so we know how big the references are
29
+ count = count_objects(object)
30
+ ref_format, ref_size = int_format_and_size(count)
17
31
 
18
- # For marking strings as binary data which will be decoded as a CFData object
19
- CFData = Struct.new(:data)
32
+ # Now serialize all the objects
33
+ values = Array.new
34
+ append_values(object, values, ref_format)
20
35
 
21
- # Convert a Ruby data structure into an OS X binary property list file. (.plist)
22
- # Works as you'd expect. Integers are limited to 4 bytes, even though the format implies longer values can be written.
23
- # Strings are assumed to be in UTF-8 format. Symbols are written as strings.
24
- def self.convert(data)
25
- write("", data)
36
+ # Write header, then the values, calculating offsets as they're written
37
+ out << 'bplist00'
38
+ offset = 8
39
+ offsets = Array.new
40
+ values.each do |v|
41
+ offsets << offset
42
+ out << v
43
+ offset += v.length
26
44
  end
27
-
28
- # Alternative interface which writes data to the out object using <<
29
- def self.write(out, data)
30
- # Find out how many objects there are, so we know how big the references are
31
- count = count_objects(data)
32
- ref_format, ref_size = int_format_and_size(count)
33
-
34
- # Now serialize all the objects
35
- values = Array.new
36
- append_values(data, values, ref_format)
37
-
38
- # Write header, then the values, calculating offsets as they're written
39
- out << 'bplist00'
40
- offset = 8
41
- offsets = Array.new
42
- values.each do |v|
43
- offsets << offset
44
- out << v
45
- offset += v.length
46
- end
47
45
 
48
- # How big should the offset ints be?
49
- # Decoder gets upset if the size can't fit the entire file, even if it's not strictly needed, so add the length of the last value.
50
- offset_format, offset_size = int_format_and_size(offsets.last + values.last.length)
51
-
52
- # Write the offsets
53
- out << offsets.pack(offset_format)
54
-
55
- # Write trailer
56
- out << [0,0,offset_size,ref_size, 0,values.length, 0,0, 0,offset].pack("NnCCNNNNNN")
57
-
58
- out
59
- end
46
+ # How big should the offset ints be?
47
+ # Decoder gets upset if the size can't fit the entire file, even if it's not strictly needed, so add the length of the last value.
48
+ offset_format, offset_size = int_format_and_size(offsets.last + values.last.length)
60
49
 
61
- private
50
+ # Write the offsets
51
+ out << offsets.pack(offset_format)
62
52
 
63
- def self.count_objects(data)
64
- case data
53
+ # Write trailer
54
+ out << [0, 0, offset_size, ref_size, 0, values.length, 0, 0, 0, offset].pack("NnCCNNNNNN")
55
+ end
56
+
57
+ private
58
+
59
+ def self.count_objects object
60
+ case object
65
61
  when Array
66
- data.inject(1) { |sum,x| sum + count_objects(x) }
62
+ object.inject(1) { |sum, x| sum + count_objects(x) }
63
+
67
64
  when Hash
68
65
  # Note: Assumes that the keys aren't a Hash or Array
69
- data.length + count_objects(data.values)
66
+ object.length + count_objects(object.values)
70
67
  else
71
68
  1
72
- end
73
69
  end
74
-
75
- def self.append_values(data, values, ref_format)
76
- case data
70
+ end
77
71
 
78
- # Constant values
72
+ def self.append_values object, values, ref_format
73
+ case object
79
74
  when nil
80
- # values << "\x00"
81
- # raise "Can't store a nil in a binary plist. While the format supports it, decoders don't like it."
82
- append_values("", values, ref_format)
75
+ # raise "Can't store a nil in a binary plist. While the format supports it, decoders don't like it." # values << "\x00"
76
+ # Instead of storing actual nil, store an empty string
77
+ append_values("", values, ref_format)
78
+
83
79
  when false
84
80
  values << "\x08"
81
+
85
82
  when true
86
83
  values << "\x09"
87
84
 
88
85
  when Integer
89
- raise "Integer out of range to write in binary plist" if data < -2147483648 || data > 0x7FFFFFFF
90
- values << packed_int(data)
86
+ raise "Integer out of range to write in binary plist: #{objet}" if object < -2147483648 || object > 0x7FFFFFFF
87
+ values << packed_int(object)
91
88
 
92
89
  when Float
93
- values << "\x23#{[data].pack("d").reverse}"
90
+ values << "\x23#{[object].pack("d").reverse}"
94
91
 
95
92
  when Symbol
96
- append_values(data.to_s, values, ref_format)
93
+ append_values(object.to_s, values, ref_format)
97
94
 
98
95
  when String
99
- if data =~ /[\x80-\xff]/
96
+ if object =~ /[\x80-\xff]/
100
97
  # Has high bits set, so is UTF-8 and must be reencoded for the plist file
101
- c = Iconv.iconv(PLIST_TEXT_ENCODING, INPUT_TEXT_ENCODING, data).join
102
- values << "#{objhdr_with_length(0x60, c.length / 2)}#{c}"
98
+ c = Iconv.iconv(PLIST_TEXT_ENCODING, INPUT_TEXT_ENCODING, object).join
99
+ values << objhdr_with_length(0x60, c.length / 2) + c
103
100
  else
104
101
  # Just ASCII
105
- o = objhdr_with_length(0x50, data.length)
106
- o << data
107
- values << o
102
+ values << objhdr_with_length(0x50, object.length) + object
108
103
  end
109
104
 
110
105
  when CFData
111
- o = objhdr_with_length(0x40, data.data.length)
112
- o << data.data
106
+ o = objhdr_with_length(0x40, object.data.length)
107
+ o << object.data
113
108
  values << o
114
109
 
115
110
  when Time
116
- v = data.getutc.to_f - DATE_EPOCH_OFFSET_APPLE_UNIX
111
+ v = object.getutc.to_f - DATE_EPOCH_OFFSET_APPLE_UNIX
117
112
  values << "\x33#{[v].pack("d").reverse}"
118
113
 
119
114
  when Hash
120
- o = objhdr_with_length(0xd0, data.length)
115
+ o = objhdr_with_length(0xd0, object.length)
121
116
  values << o # now, so we get the refs of other objects right
122
117
  ks = Array.new
123
118
  vs = Array.new
124
- data.each do |k,v|
119
+ object.each do |k,v|
125
120
  ks << values.length
126
121
  append_values(k, values, ref_format)
127
122
  vs << values.length
@@ -129,12 +124,13 @@ module BinaryPlist
129
124
  end
130
125
  o << ks.pack(ref_format)
131
126
  o << vs.pack(ref_format)
127
+
132
128
 
133
129
  when Array
134
- o = objhdr_with_length(0xa0, data.length)
130
+ o = objhdr_with_length(0xa0, object.length)
135
131
  values << o # now, so we get the refs of other objects right
136
132
  refs = Array.new
137
- data.each do |e|
133
+ object.each do |e|
138
134
  refs << values.length # index in array of object we're about to write
139
135
  append_values(e, values, ref_format)
140
136
  end
@@ -142,38 +138,37 @@ module BinaryPlist
142
138
 
143
139
  else
144
140
  raise "Couldn't serialize value of class #{data.class.name}"
145
- end
146
141
  end
147
-
148
- def self.int_format_and_size(i)
149
- if i > 0xffff
150
- ['N*',4]
151
- elsif i > 0xff
152
- ['n*',2]
153
- else
154
- ['C*',1]
155
- end
142
+ end
143
+
144
+ def self.int_format_and_size(i)
145
+ if i > 0xffff
146
+ ['N*', 4]
147
+ elsif i > 0xff
148
+ ['n*', 2]
149
+ else
150
+ ['C*', 1]
156
151
  end
152
+ end
157
153
 
158
- def self.packed_int(data)
159
- if data < 0
160
- # Need to use 64 bits for negative numbers.
161
- [0x13,0xffffffff,data].pack("CNN")
162
- elsif data > 0xffff
163
- [0x12,data].pack("CN")
164
- elsif data > 0xff
165
- [0x11,data].pack("Cn")
166
- else
167
- [0x10,data].pack("CC")
168
- end
154
+ def self.packed_int integer
155
+ if integer < 0
156
+ # Need to use 64 bits for negative numbers.
157
+ [0x13, 0xffffffff, integer].pack("CNN")
158
+ elsif integer > 0xffff
159
+ [0x12, integer].pack("CN")
160
+ elsif integer > 0xff
161
+ [0x11, integer].pack("Cn")
162
+ else
163
+ [0x10, integer].pack("CC")
169
164
  end
170
-
171
- def self.objhdr_with_length(id, length)
172
- if length < 0xf
173
- (id + length).chr
174
- else
175
- (id + 0xf).chr + packed_int(length)
176
- end
165
+ end
166
+
167
+ def self.objhdr_with_length id, length
168
+ if length < 0xf
169
+ (id + length).chr
170
+ else
171
+ (id + 0xf).chr + packed_int(length)
177
172
  end
178
- end
173
+ end
179
174
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: binary_plist
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sam Soffes
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-23 00:00:00 -05:00
18
+ date: 2010-07-26 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -26,14 +26,30 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- hash: 7
29
+ hash: 3
30
30
  segments:
31
- - 3
31
+ - 2
32
32
  - 0
33
- version: "3.0"
33
+ version: "2.0"
34
34
  type: :runtime
35
35
  version_requirements: *id001
36
- description: Easily add the Apple Binary Plist format to your controllers for transferring data to Objective-C applications.
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - "="
43
+ - !ruby/object:Gem::Version
44
+ hash: 27
45
+ segments:
46
+ - 1
47
+ - 3
48
+ - 0
49
+ version: 1.3.0
50
+ type: :development
51
+ version_requirements: *id002
52
+ description: Easily convert Ruby objects to the Apple Binary Plist format for transferring data to Objective-C applications.
37
53
  email: sam@samsoff.es
38
54
  executables: []
39
55
 
@@ -45,7 +61,9 @@ files:
45
61
  - lib/binary_plist.rb
46
62
  - Changelog.markdown
47
63
  - LICENSE
64
+ - Rakefile
48
65
  - Readme.markdown
66
+ - Todo.markdown
49
67
  - init.rb
50
68
  has_rdoc: true
51
69
  homepage: http://github.com/samsoffes/binary_plist
@@ -80,6 +98,6 @@ rubyforge_project:
80
98
  rubygems_version: 1.3.7
81
99
  signing_key:
82
100
  specification_version: 3
83
- summary: Easily add the Apple Binary Plist format to your controllers.
101
+ summary: Easily convert Ruby objects to the Apple Binary Plist format.
84
102
  test_files: []
85
103