llsd 0.1.0

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/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: []