sxp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS ADDED
@@ -0,0 +1 @@
1
+ * Arto Bendiken <arto.bendiken@gmail.com> (Lead developer)
data/README ADDED
@@ -0,0 +1,93 @@
1
+ SXP.rb: SXP for Ruby
2
+ ====================
3
+
4
+ This is the Ruby reference implementation of the SXP data interchange
5
+ format.
6
+
7
+ * <http://sxp.rubyforge.org/>
8
+ * <http://github.com/bendiken/sxp-ruby>
9
+
10
+ ### About SXP
11
+
12
+ SXP is a data interchange format based on S-expressions, the simplest and
13
+ most versatile known means of representing complex data structures such as
14
+ lists, trees and graphs.
15
+
16
+ * <http://sxp.cc/>
17
+ * <http://en.wikipedia.org/wiki/S-expression>
18
+
19
+ Features
20
+ --------
21
+
22
+ * Parses S-expressions in SXP format.
23
+ * Adds a `#to_sxp` method to Ruby objects.
24
+
25
+ Examples
26
+ --------
27
+
28
+ require 'sxp'
29
+
30
+ ### Parsing S-expressions
31
+
32
+ SXP.read "(+ 1 2)"
33
+
34
+ => [:+, 1, 2]
35
+
36
+
37
+ SXP.read <<-EOF
38
+ (define (fact n)
39
+ (if (= n 0)
40
+ 1
41
+ (* n (fact (- n 1)))))
42
+ EOF
43
+
44
+ => [:define, [:fact, :n],
45
+ [:if, [:"=", :n, 0],
46
+ 1,
47
+ [:*, :n, [:fact, [:-, :n, 1]]]]]
48
+
49
+ Documentation
50
+ -------------
51
+
52
+ * <http://sxp.rubyforge.org/>
53
+
54
+ Download
55
+ --------
56
+
57
+ To get a local working copy of the development repository, do:
58
+
59
+ % git clone git://github.com/bendiken/sxp-ruby.git
60
+
61
+ Alternatively, you can download the latest development version as a tarball
62
+ as follows:
63
+
64
+ % wget http://github.com/bendiken/sxp-ruby/tarball/master
65
+
66
+ Installation
67
+ ------------
68
+
69
+ The recommended installation method is via RubyGems. To install the latest
70
+ official release from Gemcutter, do:
71
+
72
+ % [sudo] gem install sxp
73
+
74
+ Resources
75
+ ---------
76
+
77
+ * <http://sxp.rubyforge.org/>
78
+ * <http://github.com/bendiken/sxp>
79
+ * <http://github.com/bendiken/sxp-ruby>
80
+ * <http://gemcutter.org/gems/sxp>
81
+ * <http://rubyforge.org/projects/sxp/>
82
+ * <http://raa.ruby-lang.org/project/sxp>
83
+
84
+ Author
85
+ ------
86
+
87
+ * [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
88
+
89
+ License
90
+ -------
91
+
92
+ SXP.rb is free and unencumbered public domain software. For more
93
+ information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'lib')))
3
+ require 'rubygems'
4
+ begin
5
+ require 'rakefile' # http://github.com/bendiken/rakefile
6
+ rescue LoadError => e
7
+ end
8
+ require 'sxp'
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/sxp2json ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby -rubygems
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
3
+ require 'sxp'
4
+
5
+ abort "Usage: #{File.basename($0)} input.sxp > output.json" if ARGV.empty?
data/bin/sxp2rdf ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby -rubygems
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
3
+ require 'sxp'
4
+
5
+ abort "Usage: #{File.basename($0)} input.sxp > output.rdf" if ARGV.empty?
data/bin/sxp2xml ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby -rubygems
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
3
+ require 'sxp'
4
+
5
+ abort "Usage: #{File.basename($0)} input.sxp > output.xml" if ARGV.empty?
data/bin/sxp2yaml ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby -rubygems
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
3
+ require 'sxp'
4
+
5
+ abort "Usage: #{File.basename($0)} input.sxp > output.yaml" if ARGV.empty?
@@ -0,0 +1,7 @@
1
+ class Symbol
2
+ ##
3
+ # Returns +true+ if this is a keyword symbol.
4
+ def keyword?
5
+ to_s[-1] == ?:
6
+ end
7
+ end
@@ -0,0 +1,62 @@
1
+ module SXP
2
+ class Generator
3
+ def self.string(*sxps)
4
+ require 'stringio' unless defined?(StringIO)
5
+ write(StringIO.new, *sxps).instance_variable_get('@buffer').string
6
+ end
7
+
8
+ def self.print(*sxps)
9
+ write($stdout, *sxps)
10
+ end
11
+
12
+ def self.write(out, *sxps)
13
+ generator = self.new(out)
14
+ sxps.each do |sxp|
15
+ generator.send((op = sxp.shift).to_sym, *sxp)
16
+ end
17
+ generator
18
+ end
19
+
20
+ def initialize(buffer)
21
+ @output = [@buffer = buffer]
22
+ @indent = 0
23
+ end
24
+
25
+ protected
26
+
27
+ def emit(text, options = {})
28
+ if out = @output.last
29
+ out.print(' ' * (indent * 2)) if options[:indent]
30
+ out.print(text)
31
+ end
32
+ end
33
+
34
+ def captured(&block)
35
+ require 'stringio' unless defined?(StringIO)
36
+ begin
37
+ @output.push(buffer = StringIO.new)
38
+ block.call
39
+ ensure
40
+ @output.pop
41
+ end
42
+ buffer.string
43
+ end
44
+
45
+ def indented(&block)
46
+ begin
47
+ increase_indent!
48
+ block.call
49
+ ensure
50
+ decrease_indent!
51
+ end
52
+ end
53
+
54
+ def increase_indent!()
55
+ @indent += 1
56
+ end
57
+
58
+ def decrease_indent!()
59
+ @indent -= 1
60
+ end
61
+ end
62
+ end
data/lib/sxp/list.rb ADDED
@@ -0,0 +1,327 @@
1
+ require 'sxp/pair'
2
+
3
+ module SXP
4
+ class List < Pair
5
+ include Enumerable
6
+
7
+ def self.[](*elements)
8
+ self.new(elements)
9
+ end
10
+
11
+ def initialize(elements = [], &block)
12
+ @pair = nil
13
+ unshift(*elements) unless elements.empty?
14
+ block.call(self) if block_given?
15
+ end
16
+
17
+ def inspect
18
+ "(" << map { |value| value.inspect }.join(' ') << ")"
19
+ end
20
+
21
+ def head() first end
22
+ def tail() rest end
23
+
24
+ def rest
25
+ empty? ? false : @pair.tail
26
+ end
27
+
28
+ # Array interface
29
+
30
+ def &(other)
31
+ self.class.new(self.to_a & other.to_a)
32
+ end
33
+
34
+ def |(other)
35
+ self.class.new(self.to_a | other.to_a)
36
+ end
37
+
38
+ def *(times)
39
+ result = (self.to_a * times)
40
+ result.is_a?(Array) ? self.class.new(result) : result
41
+ end
42
+
43
+ def +(other)
44
+ self.class.new(self.to_a + other.to_a)
45
+ end
46
+
47
+ def -(other)
48
+ self.class.new(self.to_a - other.to_a)
49
+ end
50
+
51
+ def <<(object)
52
+ push(object)
53
+ self
54
+ end
55
+
56
+ def <=>(other)
57
+ to_a <=> other.to_a
58
+ end
59
+
60
+ def ==(other)
61
+ case other
62
+ when List
63
+ self.length == other.length && to_a == other.to_a
64
+ when other.respond_to?(:to_list)
65
+ other.to_list == self
66
+ else
67
+ false
68
+ end
69
+ end
70
+
71
+ def [](*args)
72
+ result = to_a[*args]
73
+ result.is_a?(Array) ? self.class.new(result) : result # FIXME
74
+ end
75
+
76
+ def []=(*args)
77
+ raise NotImplementedError # TODO
78
+ end
79
+
80
+ def assoc(object)
81
+ raise NotImplementedError # TODO
82
+ end
83
+
84
+ def at(index)
85
+ to_a.at(index)
86
+ end
87
+
88
+ def clear
89
+ @pair = nil
90
+ self
91
+ end
92
+
93
+ def collect!(&block)
94
+ raise NotImplementedError # TODO
95
+ end
96
+
97
+ def compact
98
+ self.class.new(to_a.compact)
99
+ end
100
+
101
+ def compact!
102
+ raise NotImplementedError # TODO
103
+ end
104
+
105
+ def concat(other)
106
+ raise NotImplementedError # TODO
107
+ end
108
+
109
+ def delete(object, &block)
110
+ raise NotImplementedError # TODO
111
+ end
112
+
113
+ def delete_at(index)
114
+ raise NotImplementedError # TODO
115
+ end
116
+
117
+ def delete_if(&block)
118
+ raise NotImplementedError # TODO
119
+ end
120
+
121
+ def each(&block)
122
+ pair = @pair
123
+ while pair != nil
124
+ block.call(pair.head)
125
+ pair = pair.tail
126
+ end
127
+ self
128
+ end
129
+
130
+ def each_index(&block)
131
+ index = 0
132
+ each do
133
+ block.call(index)
134
+ index += 1
135
+ end
136
+ self
137
+ end
138
+
139
+ def empty?
140
+ @pair.nil?
141
+ end
142
+
143
+ def eql?(other)
144
+ case other
145
+ when self then true
146
+ when List
147
+ self.length == other.length && to_a.eql?(other.to_a)
148
+ end
149
+ end
150
+
151
+ def fetch(*args, &block)
152
+ to_a.fetch(*args, &block)
153
+ end
154
+
155
+ def fill(*args, &block)
156
+ raise NotImplementedError # TODO
157
+ end
158
+
159
+ def first(count = nil)
160
+ case
161
+ when count.nil?
162
+ @pair.head unless empty?
163
+ when count == 1
164
+ empty? ? [] : [first]
165
+ when count > 1
166
+ empty? ? [] : to_a.first(count)
167
+ end
168
+ end
169
+
170
+ def flatten
171
+ raise NotImplementedError # TODO
172
+ end
173
+
174
+ def flatten!
175
+ raise NotImplementedError # TODO
176
+ end
177
+
178
+ def include?(object)
179
+ to_a.include?(object)
180
+ end
181
+
182
+ def index(object)
183
+ to_a.index(object)
184
+ end
185
+
186
+ def insert(index, *objects)
187
+ raise NotImplementedError # TODO
188
+ end
189
+
190
+ def join(separator = $,)
191
+ to_a.join(separator)
192
+ end
193
+
194
+ def last(count = nil)
195
+ case
196
+ when count.nil?
197
+ to_a.last
198
+ else
199
+ to_a.last(count)
200
+ end
201
+ end
202
+
203
+ def length
204
+ @length ||= to_a.length
205
+ end
206
+
207
+ def map!(&block)
208
+ collect!(&block)
209
+ end
210
+
211
+ def nitems
212
+ to_a.nitems
213
+ end
214
+
215
+ def pack(template)
216
+ to_a.pack(template)
217
+ end
218
+
219
+ def pop
220
+ raise NotImplementedError # TODO
221
+ end
222
+
223
+ def push(*objects)
224
+ raise NotImplementedError # TODO
225
+ end
226
+
227
+ def rassoc(key)
228
+ raise NotImplementedError # TODO
229
+ end
230
+
231
+ def reject!(&block)
232
+ raise NotImplementedError # TODO
233
+ end
234
+
235
+ def replace(other_list)
236
+ case other_list
237
+ when Pair
238
+ @pair = other_list
239
+ when List
240
+ @pair = other_list.to_pair
241
+ when Array
242
+ @pair = nil
243
+ unshift(*other_list)
244
+ else
245
+ # TODO
246
+ end
247
+ self
248
+ end
249
+
250
+ def reverse
251
+ self.class.new(to_a.reverse)
252
+ end
253
+
254
+ def reverse!
255
+ raise NotImplementedError # TODO
256
+ end
257
+
258
+ def reverse_each(&block)
259
+ to_a.reverse_each(&block)
260
+ self
261
+ end
262
+
263
+ def rindex(object)
264
+ to_a.rindex(object)
265
+ end
266
+
267
+ def shift
268
+ raise NotImplementedError # TODO
269
+ end
270
+
271
+ def size
272
+ length
273
+ end
274
+
275
+ def slice(*args)
276
+ self[*args]
277
+ end
278
+
279
+ def slice!(*args)
280
+ raise NotImplementedError # TODO
281
+ end
282
+
283
+ def sort(&block)
284
+ (array = to_a).sort!(&block)
285
+ self.class.new(array)
286
+ end
287
+
288
+ def sort!
289
+ raise NotImplementedError # TODO
290
+ end
291
+
292
+ def to_list
293
+ self
294
+ end
295
+
296
+ def to_pair
297
+ @pair
298
+ end
299
+
300
+ def to_s
301
+ join
302
+ end
303
+
304
+ def transpose
305
+ self.class.new(to_a.transpose)
306
+ end
307
+
308
+ def uniq
309
+ self.class.new(to_a.uniq)
310
+ end
311
+
312
+ def uniq!
313
+ raise NotImplementedError # TODO
314
+ end
315
+
316
+ def unshift(*objects)
317
+ objects.reverse_each do |object|
318
+ @pair = Pair.new(object, @pair)
319
+ end
320
+ self
321
+ end
322
+
323
+ def values_at(*selector)
324
+ self.class.new(to_a.values_at(*selector))
325
+ end
326
+ end
327
+ end
data/lib/sxp/pair.rb ADDED
@@ -0,0 +1,39 @@
1
+ module SXP
2
+ class Pair
3
+ attr_accessor :head
4
+ attr_accessor :tail
5
+
6
+ def initialize(head = nil, tail = nil)
7
+ @head, @tail = head, tail
8
+ end
9
+
10
+ def inspect
11
+ case
12
+ when tail.nil?
13
+ "(#{head.inspect})"
14
+ else
15
+ "(#{head.inspect} . #{tail.inspect})"
16
+ end
17
+ end
18
+
19
+ def empty?
20
+ head.nil? && tail.nil?
21
+ end
22
+
23
+ ##
24
+ # @see http://srfi.schemers.org/srfi-1/srfi-1.html#ImproperLists
25
+ def dotted?
26
+ !proper?
27
+ end
28
+
29
+ ##
30
+ # @see http://srfi.schemers.org/srfi-1/srfi-1.html#ImproperLists
31
+ def proper?
32
+ tail.nil? || tail.is_a?(Pair)
33
+ end
34
+
35
+ def to_a
36
+ [head, tail]
37
+ end
38
+ end
39
+ end
data/lib/sxp/reader.rb ADDED
@@ -0,0 +1,210 @@
1
+ module SXP
2
+
3
+ # Reads one S-expression from the given input stream.
4
+ def self.read(input)
5
+ Reader.new(input).read
6
+ end
7
+
8
+ # Reads all S-expressions from the given input stream.
9
+ def self.read_all(input)
10
+ Reader.new(input).read_all
11
+ end
12
+
13
+ # Reads all S-expressions from the given input files.
14
+ def self.read_files(*filenames)
15
+ filenames.map { |filename| read_file(filename) }.inject { |sxps, sxp| sxps + sxp }
16
+ end
17
+
18
+ # Reads all S-expressions from a given input file.
19
+ def self.read_file(filename)
20
+ File.open(filename, 'rb') { |io| read_all(io) }
21
+ end
22
+
23
+ # Reads all S-expressions from a given input URI using the HTTP or FTP protocols.
24
+ def self.read_uri(uri, options = {})
25
+ require 'openuri'
26
+ open(uri, 'rb', nil, options) { |io| read_all(io) }
27
+ end
28
+
29
+ class << self
30
+ alias_method :parse, :read
31
+ alias_method :parse_all, :read_all
32
+ alias_method :parse_files, :read_files
33
+ alias_method :parse_file, :read_file
34
+ alias_method :parse_uri, :read_uri
35
+ end
36
+
37
+ class Reader
38
+ include Enumerable
39
+
40
+ class Error < StandardError; end
41
+ class EOF < Error; end
42
+
43
+ FLOAT = /^[+-]?(?:\d+)?\.\d*$/
44
+ INTEGER_BASE_2 = /^[+-]?[01]+$/
45
+ INTEGER_BASE_8 = /^[+-]?[0-7]+$/
46
+ INTEGER_BASE_10 = /^[+-]?\d+$/
47
+ INTEGER_BASE_16 = /^[+-]?[\da-z]+$/i
48
+ RATIONAL = /^([+-]?\d+)\/(\d+)$/
49
+ ATOM = /^[^\s()]+/
50
+
51
+ attr_reader :input
52
+
53
+ def initialize(input)
54
+ case
55
+ when [:getc, :ungetc, :eof?].all? { |x| input.respond_to?(x) }
56
+ @input = input
57
+ when input.respond_to?(:to_str)
58
+ require 'stringio'
59
+ @input = StringIO.new(input.to_str)
60
+ else
61
+ raise ArgumentError, "expected an IO or String input stream: #{input.inspect}"
62
+ end
63
+ end
64
+
65
+ def each(&block)
66
+ block.call(read)
67
+ end
68
+
69
+ def read_all(options = {})
70
+ list = []
71
+ catch (:eof) { list << read(:eof => :throw, *options) until eof? }
72
+ list
73
+ end
74
+
75
+ def read(options = {})
76
+ token, value = read_token
77
+ case token
78
+ when :eof
79
+ throw :eof if options[:eof] == :throw
80
+ raise EOF, 'unexpected end of input'
81
+ when :list
82
+ if value == ?(
83
+ read_list
84
+ else
85
+ throw :eol if options[:eol] == :throw
86
+ raise Error, 'unexpected list terminator: ?)'
87
+ end
88
+ else value
89
+ end
90
+ end
91
+
92
+ alias skip read
93
+
94
+ def read_token
95
+ skip_comments
96
+ case peek_char
97
+ when nil then :eof
98
+ when ?(, ?) then [:list, read_char]
99
+ when ?# then [:atom, read_sharp]
100
+ when ?" then [:atom, read_string]
101
+ else [:atom, read_atom]
102
+ end
103
+ end
104
+
105
+ def read_list
106
+ list = []
107
+ catch (:eol) { list << read(:eol => :throw) while true }
108
+ list
109
+ end
110
+
111
+ def read_sharp
112
+ skip_char # '#'
113
+ case char = read_char
114
+ when ?n then nil
115
+ when ?f then false
116
+ when ?t then true
117
+ when ?b then read_integer(2)
118
+ when ?o then read_integer(8)
119
+ when ?d then read_integer(10)
120
+ when ?x then read_integer(16)
121
+ when ?\\ then read_character
122
+ when ?; then skip; read
123
+ else raise Error, "invalid sharp-sign read syntax: ##{char.chr}"
124
+ end
125
+ end
126
+
127
+ def read_integer(base = 10)
128
+ case buffer = read_literal
129
+ when self.class.const_get(:"INTEGER_BASE_#{base}")
130
+ buffer.to_i(base)
131
+ else raise Error, "illegal base-#{base} number syntax: #{buffer}"
132
+ end
133
+ end
134
+
135
+ def read_atom
136
+ case buffer = read_literal
137
+ when FLOAT then buffer.to_f
138
+ when INTEGER_BASE_10 then buffer.to_i
139
+ when RATIONAL then Rational($1.to_i, $2.to_i)
140
+ else buffer.to_sym
141
+ end
142
+ end
143
+
144
+ def read_string
145
+ buffer = String.new
146
+ skip_char # '"'
147
+ until peek_char == ?"
148
+ buffer <<
149
+ case char = read_char
150
+ when ?\\ then read_character
151
+ else char
152
+ end
153
+ end
154
+ skip_char # '"'
155
+ buffer
156
+ end
157
+
158
+ def read_character
159
+ case char = read_char
160
+ when ?b then ?\b
161
+ when ?f then ?\f
162
+ when ?n then ?\n
163
+ when ?r then ?\r
164
+ when ?t then ?\t
165
+ when ?u then read_chars(4).to_i(16).chr
166
+ when ?U then read_chars(8).to_i(16).chr
167
+ else char
168
+ end
169
+ end
170
+
171
+ def read_literal
172
+ buffer = String.new
173
+ buffer << read_char while !eof? && peek_char.chr =~ ATOM
174
+ buffer
175
+ end
176
+
177
+ def skip_comments
178
+ until eof?
179
+ case (char = peek_char).chr
180
+ when /;/ then loop { break if eof? || read_char.chr == $/ }
181
+ when /\s+/ then skip_char
182
+ else break
183
+ end
184
+ end
185
+ end
186
+
187
+ def read_chars(count = 1)
188
+ buffer = ''
189
+ count.times { buffer << read_char.chr }
190
+ buffer
191
+ end
192
+
193
+ def read_char
194
+ char = @input.getc
195
+ raise EOF, 'unexpected end of input' if char.nil?
196
+ char
197
+ end
198
+
199
+ alias skip_char read_char
200
+
201
+ def peek_char
202
+ char = @input.getc
203
+ @input.ungetc char unless char.nil?
204
+ char
205
+ end
206
+
207
+ def eof?() @input.eof? end
208
+ end
209
+
210
+ end
@@ -0,0 +1,14 @@
1
+ module SXP
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+ EXTRA = nil
7
+
8
+ STRING = [MAJOR, MINOR, TINY].join('.')
9
+ STRING << "-#{EXTRA}" if EXTRA
10
+
11
+ def self.to_s() STRING end
12
+ def self.to_str() STRING end
13
+ end
14
+ end
data/lib/sxp/writer.rb ADDED
@@ -0,0 +1,57 @@
1
+ class Object
2
+ def to_sxp
3
+ to_s.to_json
4
+ end
5
+ end
6
+
7
+ class NilClass
8
+ def to_sxp; '#n'; end
9
+ end
10
+
11
+ class FalseClass
12
+ def to_sxp; '#f'; end
13
+ end
14
+
15
+ class TrueClass
16
+ def to_sxp; '#t'; end
17
+ end
18
+
19
+ class String
20
+ def to_sxp; inspect; end
21
+ end
22
+
23
+ class Symbol
24
+ def to_sxp; to_s; end
25
+ end
26
+
27
+ class Integer
28
+ def to_sxp; to_s; end
29
+ end
30
+
31
+ class Float
32
+ def to_sxp
33
+ case
34
+ when nan? then 'nan.'
35
+ when infinite? then (infinite? > 0 ? '+inf.' : '-inf.')
36
+ else to_s
37
+ end
38
+ end
39
+ end
40
+
41
+ class Array
42
+ def to_sxp
43
+ '(' << map { |x| x.to_sxp }.join(' ') << ')'
44
+ end
45
+ end
46
+
47
+ class Time
48
+ def to_sxp
49
+ '#@' << (respond_to?(:xmlschema) ? xmlschema : to_i).to_s
50
+ end
51
+ end
52
+
53
+ class Regexp
54
+ def to_sxp
55
+ '#' << inspect
56
+ end
57
+ end
data/lib/sxp.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'sxp/version'
2
+ require 'sxp/extensions'
3
+ require 'sxp/pair'
4
+ require 'sxp/list'
5
+ require 'sxp/reader'
6
+ require 'sxp/writer'
7
+ require 'sxp/generator'
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sxp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Arto Bendiken
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-21 00:00:00 +01:00
13
+ default_executable: sxp2json
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ description: " SXP is a data interchange format based on S-expressions, the simplest and\n most versatile known means of representing complex data structures such as\n lists, trees and graphs.\n"
26
+ email: arto.bendiken@gmail.com
27
+ executables:
28
+ - sxp2json
29
+ - sxp2rdf
30
+ - sxp2xml
31
+ - sxp2yaml
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - AUTHORS
38
+ - README
39
+ - Rakefile
40
+ - UNLICENSE
41
+ - VERSION
42
+ - lib/sxp/extensions.rb
43
+ - lib/sxp/generator.rb
44
+ - lib/sxp/list.rb
45
+ - lib/sxp/pair.rb
46
+ - lib/sxp/reader.rb
47
+ - lib/sxp/version.rb
48
+ - lib/sxp/writer.rb
49
+ - lib/sxp.rb
50
+ has_rdoc: false
51
+ homepage: http://sxp.rubyforge.org/
52
+ licenses:
53
+ - Public Domain
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.8.2
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project: sxp
74
+ rubygems_version: 1.3.5
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: A pure-Ruby implementation of the SXP data interchange format.
78
+ test_files: []
79
+