llsd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007-2011, Linden Research, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |test|
5
+ test.libs << 'test'
6
+ test.test_files = FileList['test/**/*_test.rb']
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,186 @@
1
+ require 'rexml/document'
2
+ require 'date'
3
+
4
+ # Class for parsing and generating llsd xml
5
+ class LLSD
6
+ class SerializationError < StandardError; end
7
+
8
+ LLSD_ELEMENT = 'llsd'
9
+
10
+ BOOLEAN_ELEMENT = 'boolean'
11
+ INTEGER_ELEMENT = 'integer'
12
+ REAL_ELEMENT = 'real'
13
+ UUID_ELEMENT = 'uuid'
14
+ STRING_ELEMENT = 'string'
15
+ BINARY_ELEMENT = 'binary'
16
+ DATE_ELEMENT = 'date'
17
+ URI_ELEMENT = 'uri'
18
+ KEY_ELEMENT = 'key'
19
+ UNDEF_ELEMENT = 'undef'
20
+
21
+ ARRAY_ELEMENT = 'array'
22
+ MAP_ELEMENT = 'map'
23
+
24
+ # PARSING AND ENCODING FUNCTIONS
25
+
26
+ def self.to_xml(obj)
27
+ llsd_element = REXML::Element.new LLSD_ELEMENT
28
+ llsd_element.add_element(serialize_ruby_obj(obj))
29
+
30
+ doc = REXML::Document.new
31
+ doc << llsd_element
32
+ doc.to_s
33
+ end
34
+
35
+ def self.parse(xml_string)
36
+ # turn message into dom element
37
+ doc = REXML::Document.new xml_string
38
+
39
+ # get the first element inside the llsd element
40
+ # if there is more than one element then return nil
41
+
42
+ # return parse dom element on first element
43
+ parse_dom_element doc.root.elements[1]
44
+ end
45
+
46
+ private
47
+
48
+ def self.serialize_ruby_obj(obj)
49
+ # if its a container (hash or map)
50
+
51
+ case obj
52
+ when Hash
53
+ map_element = REXML::Element.new(MAP_ELEMENT)
54
+ obj.each do |key, value|
55
+ key_element = REXML::Element.new(KEY_ELEMENT)
56
+ key_element.text = key.to_s
57
+ value_element = serialize_ruby_obj value
58
+
59
+ map_element.add_element key_element
60
+ map_element.add_element value_element
61
+ end
62
+
63
+ map_element
64
+
65
+ when Array
66
+ array_element = REXML::Element.new(ARRAY_ELEMENT)
67
+ obj.each { |o| array_element.add_element(serialize_ruby_obj(o)) }
68
+ array_element
69
+
70
+ when Fixnum, Integer
71
+ integer_element = REXML::Element.new(INTEGER_ELEMENT)
72
+ integer_element.text = obj.to_s
73
+ integer_element
74
+
75
+ when TrueClass, FalseClass
76
+ boolean_element = REXML::Element.new(BOOLEAN_ELEMENT)
77
+
78
+ if obj
79
+ boolean_element.text = 'true'
80
+ else
81
+ boolean_element.text = 'false'
82
+ end
83
+
84
+ boolean_element
85
+
86
+ when Float
87
+ real_element = REXML::Element.new(REAL_ELEMENT)
88
+ real_element.text = obj.to_s
89
+ real_element
90
+
91
+ when Date
92
+ date_element = REXML::Element.new(DATE_ELEMENT)
93
+ date_element.text = obj.new_offset(of=0).strftime('%Y-%m-%dT%H:%M:%SZ')
94
+ date_element
95
+
96
+ when String
97
+ if !obj.empty?
98
+ string_element = REXML::Element.new(STRING_ELEMENT)
99
+ string_element.text = obj.to_s
100
+ string_element
101
+ else
102
+ STRING_ELEMENT
103
+ end
104
+
105
+ when NilClass
106
+ UNDEF_ELEMENT
107
+
108
+ else
109
+ raise SerializationError, "#{obj.class.to_s} class cannot be serialized into llsd xml - please serialize into a string first"
110
+ end
111
+ end
112
+
113
+ def self.parse_dom_element(element)
114
+ # pseudocode:
115
+
116
+ # if it is a container
117
+ # if its an array
118
+ # collect parse_dom_element applied to each child into an array
119
+ # else (its a map)
120
+ # collect parse_dom_element applied to each child into an hash
121
+ # else (its an atomic element)
122
+ # then extract the value to a native type
123
+ #
124
+ # return the value
125
+
126
+ case element.name
127
+ when ARRAY_ELEMENT
128
+ element_value = []
129
+ element.elements.each {|child| element_value << (parse_dom_element child) }
130
+
131
+ when MAP_ELEMENT
132
+ element_value = {}
133
+ element.elements.each do |child|
134
+ if child.name == 'key'
135
+ element_value[child.text] = parse_dom_element child.next_element
136
+ end
137
+ end
138
+
139
+ else
140
+ element_value = convert_to_native_type(element.name, element.text, element.attributes)
141
+ end
142
+
143
+ element_value
144
+ end
145
+
146
+ def self.convert_to_native_type(element_type, unconverted_value, attributes)
147
+ case element_type
148
+ when INTEGER_ELEMENT
149
+ unconverted_value.to_i
150
+
151
+ when REAL_ELEMENT
152
+ unconverted_value.to_f
153
+
154
+ when BOOLEAN_ELEMENT
155
+ if unconverted_value == 'false' or unconverted_value.nil? # <boolean />
156
+ false
157
+ else
158
+ true
159
+ end
160
+
161
+ when STRING_ELEMENT
162
+ if unconverted_value.nil? # <string />
163
+ ''
164
+ else
165
+ unconverted_value
166
+ end
167
+
168
+ when DATE_ELEMENT
169
+ if unconverted_value.nil?
170
+ DateTime.strptime('1970-01-01T00:00:00Z')
171
+ else
172
+ DateTime.strptime(unconverted_value)
173
+ end
174
+
175
+ when UUID_ELEMENT
176
+ if unconverted_value.nil?
177
+ '00000000-0000-0000-0000-000000000000'
178
+ else
179
+ unconverted_value
180
+ end
181
+
182
+ else
183
+ unconverted_value
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,3 @@
1
+ class LLSD
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,284 @@
1
+ require 'test_helper'
2
+
3
+ class LLSDUnitTest < Test::Unit::TestCase
4
+ def test_map
5
+ map_xml = <<EOF
6
+ <llsd>
7
+ <map>
8
+ <key>foo</key>
9
+ <string>bar</string>
10
+ </map>
11
+ </llsd>
12
+ EOF
13
+
14
+ map_within_map_xml = <<EOF
15
+ <llsd>
16
+ <map>
17
+ <key>doo</key>
18
+ <map>
19
+ <key>goo</key>
20
+ <string>poo</string>
21
+ </map>
22
+ </map>
23
+ </llsd>
24
+ EOF
25
+
26
+ blank_map_xml = <<EOF
27
+ <llsd>
28
+ <map/>
29
+ </llsd>
30
+ EOF
31
+
32
+ ruby_map = {'foo' => 'bar'}
33
+ ruby_map_within_map = {'doo' => {'goo' => 'poo'}}
34
+ ruby_blank_map = {}
35
+
36
+ assert_equal ruby_map, LLSD.parse(map_xml)
37
+ assert_equal ruby_map_within_map, LLSD.parse(map_within_map_xml)
38
+ assert_equal ruby_blank_map, LLSD.parse(blank_map_xml)
39
+
40
+ assert_equal strip(map_xml), LLSD.to_xml(ruby_map)
41
+ assert_equal strip(map_within_map_xml), LLSD.to_xml(ruby_map_within_map)
42
+ end
43
+
44
+ def test_array
45
+ array_xml = <<EOF
46
+ <llsd>
47
+ <array>
48
+ <string>foo</string>
49
+ <string>bar</string>
50
+ </array>
51
+ </llsd>
52
+ EOF
53
+
54
+ array_within_array_xml = <<EOF
55
+ <llsd>
56
+ <array>
57
+ <string>foo</string>
58
+ <string>bar</string>
59
+ <array>
60
+ <string>foo</string>
61
+ <string>bar</string>
62
+ </array>
63
+ </array>
64
+ </llsd>
65
+ EOF
66
+
67
+ blank_array_xml = <<EOF
68
+ <llsd>
69
+ <array/>
70
+ </llsd>
71
+ EOF
72
+
73
+ ruby_array = ['foo', 'bar']
74
+ ruby_array_within_array = ['foo', 'bar', ['foo', 'bar']]
75
+ ruby_blank_array = []
76
+
77
+ assert_equal ruby_array, LLSD.parse(array_xml)
78
+ assert_equal ruby_array_within_array, LLSD.parse(array_within_array_xml)
79
+ assert_equal ruby_blank_array, LLSD.parse(blank_array_xml)
80
+
81
+ assert_equal strip(array_xml), LLSD.to_xml(ruby_array)
82
+ assert_equal strip(array_within_array_xml), LLSD.to_xml(ruby_array_within_array)
83
+ end
84
+
85
+ def test_string
86
+ normal_xml = <<EOF
87
+ <llsd>
88
+ <string>foo</string>
89
+ </llsd>
90
+ EOF
91
+
92
+ blank_xml = <<EOF
93
+ <llsd>
94
+ <string/>
95
+ </llsd>
96
+ EOF
97
+
98
+ assert_equal 'foo', LLSD.parse(normal_xml)
99
+ assert_equal '', LLSD.parse(blank_xml)
100
+
101
+ assert_equal strip(normal_xml), LLSD.to_xml('foo')
102
+ assert_equal strip(blank_xml), LLSD.to_xml('')
103
+ end
104
+
105
+ def test_integer
106
+ pos_int_xml = <<EOF
107
+ <llsd>
108
+ <integer>289343</integer>
109
+ </llsd>
110
+ EOF
111
+
112
+ neg_int_xml = <<EOF
113
+ <llsd>
114
+ <integer>-289343</integer>
115
+ </llsd>
116
+ EOF
117
+
118
+ blank_int_xml = <<EOF
119
+ <llsd>
120
+ <integer/>
121
+ </llsd>
122
+ EOF
123
+
124
+ ruby_pos_int = 289343
125
+ ruby_neg_int = -289343
126
+
127
+ assert_equal ruby_pos_int, LLSD.parse(pos_int_xml)
128
+ assert_equal ruby_neg_int, LLSD.parse(neg_int_xml)
129
+ assert_equal 0, LLSD.parse(blank_int_xml)
130
+
131
+ assert_equal strip(pos_int_xml), LLSD.to_xml(ruby_pos_int)
132
+ assert_equal strip(neg_int_xml), LLSD.to_xml(ruby_neg_int)
133
+ end
134
+
135
+ def test_real
136
+ pos_real_xml = <<EOF
137
+ <llsd>
138
+ <real>2983287453.38483</real>
139
+ </llsd>
140
+ EOF
141
+
142
+ neg_real_xml = <<EOF
143
+ <llsd>
144
+ <real>-2983287453.38483</real>
145
+ </llsd>
146
+ EOF
147
+
148
+ blank_real_xml = <<EOF
149
+ <llsd>
150
+ <real/>
151
+ </llsd>
152
+ EOF
153
+ ruby_pos_real = 2983287453.38483
154
+ ruby_neg_real = -2983287453.38483
155
+
156
+ assert_equal ruby_pos_real, LLSD.parse(pos_real_xml)
157
+ assert_equal ruby_neg_real, LLSD.parse(neg_real_xml)
158
+ assert_equal 0, LLSD.parse(blank_real_xml)
159
+
160
+ assert_equal strip(pos_real_xml), LLSD.to_xml(ruby_pos_real)
161
+ assert_equal strip(neg_real_xml), LLSD.to_xml(ruby_neg_real)
162
+ end
163
+
164
+ def test_boolean
165
+ true_xml = <<EOF
166
+ <llsd>
167
+ <boolean>true</boolean>
168
+ </llsd>
169
+ EOF
170
+
171
+ false_xml = <<EOF
172
+ <llsd>
173
+ <boolean>false</boolean>
174
+ </llsd>
175
+ EOF
176
+
177
+ blank_xml = <<EOF
178
+ <llsd>
179
+ <boolean/>
180
+ </llsd>
181
+ EOF
182
+
183
+ assert_equal true, LLSD.parse(true_xml)
184
+ assert_equal false, LLSD.parse(false_xml)
185
+ assert_equal false, LLSD.parse(blank_xml)
186
+
187
+ assert_equal strip(true_xml), LLSD.to_xml(true)
188
+ assert_equal strip(false_xml), LLSD.to_xml(false)
189
+ end
190
+
191
+ def test_date
192
+ valid_date_xml = <<EOF
193
+ <llsd>
194
+ <date>2006-02-01T14:29:53Z</date>
195
+ </llsd>
196
+ EOF
197
+
198
+ blank_date_xml = <<EOF
199
+ <llsd>
200
+ <date/>
201
+ </llsd>
202
+ EOF
203
+
204
+ ruby_valid_date = DateTime.strptime('2006-02-01T14:29:53Z')
205
+ ruby_blank_date = DateTime.strptime('1970-01-01T00:00:00Z')
206
+
207
+ assert_equal ruby_valid_date, LLSD.parse(valid_date_xml)
208
+ assert_equal ruby_blank_date, LLSD.parse(blank_date_xml)
209
+
210
+ assert_equal strip(valid_date_xml), LLSD.to_xml(ruby_valid_date)
211
+ end
212
+
213
+ # because the following types dont have "native" types in ruby, they convert to string
214
+
215
+ def test_binary
216
+ base64_binary_xml = <<EOF
217
+ <llsd>
218
+ <binary>dGhlIHF1aWNrIGJyb3duIGZveA==</binary>
219
+ </llsd>
220
+ EOF
221
+
222
+ # <binary/> should return blank binary blob... in ruby I guess this is just nil
223
+
224
+ assert_equal 'dGhlIHF1aWNrIGJyb3duIGZveA==', LLSD.parse(base64_binary_xml)
225
+ end
226
+
227
+ def test_uuid
228
+ valid_uuid_xml = <<EOF
229
+ <llsd>
230
+ <uuid>d7f4aeca-88f1-42a1-b385-b9db18abb255</uuid>
231
+ </llsd>
232
+ EOF
233
+
234
+ blank_uuid_xml = <<EOF
235
+ <llsd>
236
+ <uuid/>
237
+ </llsd>
238
+ EOF
239
+
240
+ assert_equal 'd7f4aeca-88f1-42a1-b385-b9db18abb255', LLSD.parse(valid_uuid_xml)
241
+ assert_equal '00000000-0000-0000-0000-000000000000', LLSD.parse(blank_uuid_xml)
242
+ end
243
+
244
+ def test_uri
245
+ valid_uri_xml = <<EOF
246
+ <llsd>
247
+ <uri>http://www.example.com:4201/agents</uri>
248
+ </llsd>
249
+ EOF
250
+
251
+ blank_uri_xml = <<EOF
252
+ <llsd>
253
+ <uri/>
254
+ </llsd>
255
+ EOF
256
+
257
+ # <uri/> should return an empty link, which in ruby I guess is just nil
258
+ assert_equal 'http://www.example.com:4201/agents', LLSD.parse(valid_uri_xml)
259
+ assert_equal nil, LLSD.parse(blank_uri_xml)
260
+ end
261
+
262
+ def test_undefined
263
+ undef_xml = <<EOF
264
+ <llsd>
265
+ <undef/>
266
+ </llsd>
267
+ EOF
268
+
269
+ assert_equal nil, LLSD.parse(undef_xml)
270
+ assert_equal strip(undef_xml), LLSD.to_xml(nil)
271
+ end
272
+
273
+ def test_llsd_serialization_exception
274
+ # make an object not supported by llsd
275
+ ruby_range = Range.new 1, 2
276
+
277
+ # assert than an exception is raised
278
+ assert_raise(LLSD::SerializationError) { LLSD.to_xml(ruby_range) }
279
+ end
280
+
281
+ def strip(str)
282
+ str.delete "\n "
283
+ end
284
+ end
@@ -0,0 +1,4 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'test/unit'
4
+ require 'llsd'
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: llsd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Beck Linden
9
+ - Joshua Linden
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-09-28 00:00:00.000000000 Z
14
+ dependencies: []
15
+ description:
16
+ email: beck@lindenlab.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - Rakefile
23
+ - lib/llsd.rb
24
+ - lib/llsd/version.rb
25
+ - test/llsd_test.rb
26
+ - test/test_helper.rb
27
+ homepage: https://github.com/becklinden/llsd
28
+ licenses: []
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubyforge_project:
47
+ rubygems_version: 1.8.10
48
+ signing_key:
49
+ specification_version: 3
50
+ summary: An implementation of LLSD (Linden lab Structured Data) in Ruby
51
+ test_files: []