sxp 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="