binary_plist 0.0.1 → 0.0.3

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/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