sxp 0.0.4 → 0.0.5

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.5
data/lib/sxp.rb CHANGED
@@ -1,3 +1,20 @@
1
+ require 'rational'
2
+ require 'stringio'
3
+
4
+ if RUBY_VERSION < '1.8.7'
5
+ # @see http://rubygems.org/gems/backports
6
+ begin
7
+ require 'backports/1.8.7'
8
+ rescue LoadError
9
+ begin
10
+ require 'rubygems'
11
+ require 'backports/1.8.7'
12
+ rescue LoadError
13
+ abort "SXP.rb requires Ruby 1.8.7 or the Backports gem (hint: `gem install backports')."
14
+ end
15
+ end
16
+ end
17
+
1
18
  require 'sxp/version'
2
19
  require 'sxp/extensions'
3
20
  require 'sxp/writer'
@@ -16,7 +33,7 @@ module SXP
16
33
  # @param [Hash{Symbol => Object}] options
17
34
  # @return [Enumerable<Object>]
18
35
  def self.read_url(url, options = {})
19
- require 'openuri'
36
+ require 'open-uri'
20
37
  open(url.to_s, 'rb', nil, options) { |io| read_all(io, options) }
21
38
  end
22
39
 
@@ -48,7 +65,7 @@ module SXP
48
65
  # @param [Hash{Symbol => Object}] options
49
66
  # @return [Enumerable<Object>]
50
67
  def self.read_all(input, options = {})
51
- Reader.new(input, options).read_all
68
+ Reader::Scheme.new(input, options).read_all
52
69
  end
53
70
 
54
71
  ##
@@ -58,7 +75,7 @@ module SXP
58
75
  # @param [Hash{Symbol => Object}] options
59
76
  # @return [Object]
60
77
  def self.read(input, options = {})
61
- Reader.new(input, options).read
78
+ Reader::Scheme.new(input, options).read
62
79
  end
63
80
 
64
81
  class << self
@@ -2,34 +2,42 @@ module SXP
2
2
  ##
3
3
  # The base class for S-expression parsers.
4
4
  class Reader
5
- include Enumerable
5
+ autoload :Basic, 'sxp/reader/basic'
6
+ autoload :Extended, 'sxp/reader/extended'
7
+ autoload :Scheme, 'sxp/reader/scheme'
6
8
 
7
9
  class Error < StandardError; end
8
10
  class EOF < Error; end
9
11
 
10
- FLOAT = /^[+-]?(\d*)?\.\d*$/
11
- INTEGER_BASE_2 = /^[+-]?[01]+$/
12
- INTEGER_BASE_8 = /^[+-]?[0-7]+$/
13
- INTEGER_BASE_10 = /^[+-]?\d+$/
14
- INTEGER_BASE_16 = /^[+-]?[\da-z]+$/i
15
- RATIONAL = /^([+-]?\d+)\/(\d+)$/
16
- ATOM = /^[^\s()\[\]]+/
12
+ include Enumerable
17
13
 
18
14
  # @return [Object]
19
15
  attr_reader :input
20
16
 
17
+ # @return [Hash{Symbol => Object}]
18
+ attr_reader :options
19
+
21
20
  ##
22
- # @param [Object] input
21
+ # @param [IO, StringIO, String] input
23
22
  # @param [Hash{Symbol => Object}] options
24
- def initialize(input, options = {})
23
+ def initialize(input, options = {}, &block)
24
+ @options = options.dup
25
+
25
26
  case
26
27
  when [:getc, :ungetc, :eof?].all? { |x| input.respond_to?(x) }
27
28
  @input = input
28
29
  when input.respond_to?(:to_str)
29
- require 'stringio'
30
+ require 'stringio' unless defined?(StringIO)
30
31
  @input = StringIO.new(input.to_str)
31
32
  else
32
- raise ArgumentError, "expected an IO or String input stream: #{input.inspect}"
33
+ raise ArgumentError, "expected an IO or String input stream, but got #{input.inspect}"
34
+ end
35
+
36
+ if block_given?
37
+ case block.arity
38
+ when 1 then block.call(self)
39
+ else self.instance_eval(&block)
40
+ end
33
41
  end
34
42
  end
35
43
 
@@ -38,7 +46,11 @@ module SXP
38
46
  # @yieldparam [Object] object
39
47
  # @return [Enumerator]
40
48
  def each(&block)
41
- block.call(read) if block_given? # FIXME
49
+ #block_given? ?
50
+ # to_enum
51
+ #else
52
+ # block.call(read)
53
+ #end
42
54
  end
43
55
 
44
56
  ##
@@ -61,9 +73,9 @@ module SXP
61
73
  case token
62
74
  when :eof
63
75
  throw :eof if options[:eof] == :throw
64
- raise EOF, 'unexpected end of input'
76
+ raise EOF, "unexpected end of input"
65
77
  when :list
66
- if value == ?( || value == ?[
78
+ if self.class.const_get(:LPARENS).include?(value)
67
79
  read_list
68
80
  else
69
81
  throw :eol if options[:eol] == :throw # end of list
@@ -75,19 +87,6 @@ module SXP
75
87
 
76
88
  alias_method :skip, :read
77
89
 
78
- ##
79
- # @return [Object]
80
- def read_token
81
- case peek_char
82
- when nil then :eof
83
- when ?(, ?) then [:list, read_char]
84
- when ?[, ?] then [:list, read_char]
85
- when ?" then [:atom, read_string]
86
- when ?# then [:atom, read_sharp]
87
- else [:atom, read_atom]
88
- end
89
- end
90
-
91
90
  ##
92
91
  # @param [Array]
93
92
  def read_list
@@ -100,23 +99,19 @@ module SXP
100
99
 
101
100
  ##
102
101
  # @return [Object]
103
- def read_sharp
104
- skip_char # '#'
105
- case char = read_char
106
- when ?n then nil
107
- when ?f then false
108
- when ?t then true
109
- when ?b then read_integer(2)
110
- when ?o then read_integer(8)
111
- when ?d then read_integer(10)
112
- when ?x then read_integer(16)
113
- when ?\\ then read_character
114
- when ?; then skip; read
115
- when ?! then skip_line; read # shebang
116
- else raise Error, "invalid sharp-sign read syntax: ##{char.chr}"
102
+ def read_token
103
+ case peek_char
104
+ when nil then :eof
105
+ else [:atom, read_atom]
117
106
  end
118
107
  end
119
108
 
109
+ ##
110
+ # @return [Object]
111
+ def read_sharp
112
+ raise NotImplementedError.new("#{self.class}#read_sharp")
113
+ end
114
+
120
115
  ##
121
116
  # @param [Integer] base
122
117
  # @return [Integer]
@@ -131,66 +126,48 @@ module SXP
131
126
  ##
132
127
  # @return [Object]
133
128
  def read_atom
134
- case buffer = read_literal
135
- when '.' then buffer.to_sym
136
- when FLOAT then buffer.to_f
137
- when INTEGER_BASE_10 then buffer.to_i
138
- when RATIONAL then Rational($1.to_i, $2.to_i)
139
- else buffer.to_sym
140
- end
129
+ raise NotImplementedError.new("#{self.class}#read_atom")
141
130
  end
142
131
 
143
132
  ##
144
133
  # @return [String]
145
134
  def read_string
146
- buffer = String.new
147
- skip_char # '"'
148
- until peek_char == ?"
149
- buffer <<
150
- case char = read_char
151
- when ?\\ then read_character
152
- else char
153
- end
154
- end
155
- skip_char # '"'
156
- buffer
135
+ raise NotImplementedError.new("#{self.class}#read_string")
157
136
  end
158
137
 
159
138
  ##
160
139
  # @return [String]
161
140
  def read_character
162
- case char = read_char
163
- when ?b then ?\b
164
- when ?f then ?\f
165
- when ?n then ?\n
166
- when ?r then ?\r
167
- when ?t then ?\t
168
- when ?u then read_chars(4).to_i(16).chr
169
- when ?U then read_chars(8).to_i(16).chr
170
- else char
171
- end
141
+ raise NotImplementedError.new("#{self.class}#read_character")
172
142
  end
173
143
 
174
144
  ##
175
145
  # @return [String]
176
146
  def read_literal
177
- buffer = String.new
178
- buffer << read_char while !eof? && peek_char.chr =~ ATOM
179
- buffer
147
+ raise NotImplementedError.new("#{self.class}#read_literal")
180
148
  end
181
149
 
150
+ protected
151
+
182
152
  ##
183
153
  # @return [void]
184
154
  def skip_comments
185
155
  until eof?
186
156
  case (char = peek_char).chr
187
- when /;/ then skip_line
188
157
  when /\s+/ then skip_char
189
158
  else break
190
159
  end
191
160
  end
192
161
  end
193
162
 
163
+ ##
164
+ # @return [void]
165
+ def skip_line
166
+ loop do
167
+ break if eof? || read_char.chr == $/
168
+ end
169
+ end
170
+
194
171
  ##
195
172
  # @param [Integer] count
196
173
  # @return [String]
@@ -208,21 +185,13 @@ module SXP
208
185
  char
209
186
  end
210
187
 
211
- ##
212
- # @return [void]
213
- def skip_line
214
- loop do
215
- break if eof? || read_char.chr == $/
216
- end
217
- end
218
-
219
188
  alias_method :skip_char, :read_char
220
189
 
221
190
  ##
222
191
  # @return [String]
223
192
  def peek_char
224
193
  char = @input.getc
225
- @input.ungetc char unless char.nil?
194
+ @input.ungetc(char) unless char.nil?
226
195
  char
227
196
  end
228
197
 
@@ -0,0 +1,76 @@
1
+ module SXP; class Reader
2
+ ##
3
+ # A basic S-expression parser.
4
+ class Basic < Reader
5
+ LPARENS = [?(].freeze
6
+ RPARENS = [?)].freeze
7
+ ATOM = /^[^\s()]+/.freeze
8
+ RATIONAL = /^([+-]?\d+)\/(\d+)$/.freeze
9
+ DECIMAL = /^[+-]?(\d*)?\.\d*$/.freeze
10
+ INTEGER = /^[+-]?\d+$/.freeze
11
+
12
+ ##
13
+ # @return [Object]
14
+ def read_token
15
+ case peek_char
16
+ when ?(, ?) then [:list, read_char]
17
+ when ?" then [:atom, read_string]
18
+ else super
19
+ end
20
+ end
21
+
22
+ ##
23
+ # @return [Object]
24
+ def read_atom
25
+ case buffer = read_literal
26
+ when '.' then buffer.to_sym
27
+ when RATIONAL then Rational($1.to_i, $2.to_i)
28
+ when DECIMAL then Float(buffer) # FIXME?
29
+ when INTEGER then Integer(buffer)
30
+ else buffer.to_sym
31
+ end
32
+ end
33
+
34
+ ##
35
+ # @return [String]
36
+ def read_string
37
+ buffer = String.new
38
+ skip_char # '"'
39
+ until peek_char == ?"
40
+ buffer <<
41
+ case char = read_char
42
+ when ?\\ then read_character
43
+ else char
44
+ end
45
+ end
46
+ skip_char # '"'
47
+ buffer
48
+ end
49
+
50
+ ##
51
+ # @return [String]
52
+ def read_character
53
+ case char = read_char
54
+ when ?b then ?\b
55
+ when ?f then ?\f
56
+ when ?n then ?\n
57
+ when ?r then ?\r
58
+ when ?t then ?\t
59
+ when ?u then read_chars(4).to_i(16).chr
60
+ when ?U then read_chars(8).to_i(16).chr
61
+ when ?" then char
62
+ when ?\\ then char
63
+ else char
64
+ end
65
+ end
66
+
67
+ ##
68
+ # @return [String]
69
+ def read_literal
70
+ grammar = self.class.const_get(:ATOM)
71
+ buffer = String.new
72
+ buffer << read_char while !eof? && peek_char.chr =~ grammar
73
+ buffer
74
+ end
75
+ end # class Reader
76
+ end; end # class SXP::Reader
@@ -0,0 +1,30 @@
1
+ module SXP; class Reader
2
+ ##
3
+ # An extended S-expression parser.
4
+ class Extended < Basic
5
+ LPARENS = [?(, ?[].freeze
6
+ RPARENS = [?), ?]].freeze
7
+ ATOM = /^[^\s()\[\]]+/.freeze
8
+
9
+ ##
10
+ # @return [Object]
11
+ def read_token
12
+ case peek_char
13
+ when ?[, ?] then [:list, read_char]
14
+ else super
15
+ end
16
+ end
17
+
18
+ ##
19
+ # @return [void]
20
+ def skip_comments
21
+ until eof?
22
+ case (char = peek_char).chr
23
+ when /\s+/ then skip_char
24
+ when /;/ then skip_line
25
+ else break
26
+ end
27
+ end
28
+ end
29
+ end # class Reader
30
+ end; end # class SXP::Reader
@@ -0,0 +1,52 @@
1
+ module SXP; class Reader
2
+ ##
3
+ # A Scheme-like S-expression parser.
4
+ class Scheme < Extended
5
+ DECIMAL = /^[+-]?(\d*)?\.\d*$/.freeze
6
+ INTEGER_BASE_2 = /^[+-]?[01]+$/.freeze
7
+ INTEGER_BASE_8 = /^[+-]?[0-7]+$/.freeze
8
+ INTEGER_BASE_10 = /^[+-]?\d+$/.freeze
9
+ INTEGER_BASE_16 = /^[+-]?[\da-z]+$/i.freeze
10
+ RATIONAL = /^([+-]?\d+)\/(\d+)$/.freeze
11
+
12
+ ##
13
+ # @return [Object]
14
+ def read_token
15
+ case peek_char
16
+ when ?# then [:atom, read_sharp]
17
+ else super
18
+ end
19
+ end
20
+
21
+ ##
22
+ # @return [Object]
23
+ def read_atom
24
+ case buffer = read_literal
25
+ when '.' then buffer.to_sym
26
+ when RATIONAL then Rational($1.to_i, $2.to_i)
27
+ when DECIMAL then Float(buffer)
28
+ when INTEGER_BASE_10 then Integer(buffer)
29
+ else buffer.to_sym
30
+ end
31
+ end
32
+
33
+ ##
34
+ # @return [Object]
35
+ def read_sharp
36
+ skip_char # '#'
37
+ case char = read_char
38
+ when ?n then nil # not in Scheme
39
+ when ?f then false
40
+ when ?t then true
41
+ when ?b then read_integer(2)
42
+ when ?o then read_integer(8)
43
+ when ?d then read_integer(10)
44
+ when ?x then read_integer(16)
45
+ when ?\\ then read_character
46
+ when ?; then skip; read
47
+ when ?! then skip_line; read # shebang
48
+ else raise Error, "invalid sharp-sign read syntax: ##{char.chr}"
49
+ end
50
+ end
51
+ end # class Reader
52
+ end; end # class SXP::Reader
@@ -2,11 +2,10 @@ module SXP
2
2
  module VERSION
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 4
5
+ TINY = 5
6
6
  EXTRA = nil
7
7
 
8
- STRING = [MAJOR, MINOR, TINY].join('.')
9
- STRING << ".#{EXTRA}" if EXTRA
8
+ STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
10
9
 
11
10
  ##
12
11
  # @return [String]
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 4
9
- version: 0.0.4
8
+ - 5
9
+ version: 0.0.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Arto Bendiken
@@ -14,35 +14,35 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-25 00:00:00 +02:00
17
+ date: 2010-06-23 00:00:00 +02:00
18
18
  default_executable: sxp2rdf
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: rspec
21
+ name: yard
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
- - 1
29
- - 3
30
28
  - 0
31
- version: 1.3.0
29
+ - 5
30
+ - 8
31
+ version: 0.5.8
32
32
  type: :development
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency
35
- name: yard
35
+ name: rspec
36
36
  prerelease: false
37
37
  requirement: &id002 !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  segments:
42
+ - 1
43
+ - 3
42
44
  - 0
43
- - 5
44
- - 4
45
- version: 0.5.4
45
+ version: 1.3.0
46
46
  type: :development
47
47
  version_requirements: *id002
48
48
  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"
@@ -65,6 +65,9 @@ files:
65
65
  - lib/sxp/generator.rb
66
66
  - lib/sxp/list.rb
67
67
  - lib/sxp/pair.rb
68
+ - lib/sxp/reader/basic.rb
69
+ - lib/sxp/reader/extended.rb
70
+ - lib/sxp/reader/scheme.rb
68
71
  - lib/sxp/reader.rb
69
72
  - lib/sxp/version.rb
70
73
  - lib/sxp/writer.rb
@@ -85,8 +88,8 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
88
  segments:
86
89
  - 1
87
90
  - 8
88
- - 2
89
- version: 1.8.2
91
+ - 1
92
+ version: 1.8.1
90
93
  required_rubygems_version: !ruby/object:Gem::Requirement
91
94
  requirements:
92
95
  - - ">="