sxp 0.0.1

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