edn 1.0.3 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +1,23 @@
1
1
  module EDN
2
2
  class Reader
3
- include Enumerable
4
3
 
5
- def initialize(text)
6
- @parser = Parser.new
7
- @transform = Transform.new
8
- @original_text = text
9
- @text = text
4
+ def initialize(source)
5
+ @parser = Parser.new(source)
10
6
  end
11
7
 
12
- def eof?
13
- @text.nil? || @text.empty?
8
+ def read(eof_value = NOTHING)
9
+ result = @parser.read
10
+ if result == EOF
11
+ raise "Unexpected end of file" if eof_value == NOTHING
12
+ return eof_value
13
+ end
14
+ result
14
15
  end
15
16
 
16
17
  def each
17
- reset!
18
- return enum_for(:select) unless block_given?
19
-
20
- until eof?
21
- yield read
18
+ until (result = @parser.read) == EOF
19
+ yield result
22
20
  end
23
21
  end
24
-
25
- def reset!
26
- @text = @original_text
27
- end
28
-
29
- def read
30
- raise "EDN::Reader is out of string!" if eof?
31
- element, rest = @parser.parse_prefix(@text)
32
- @text = rest
33
- @transform.apply(element)
34
- end
35
22
  end
36
23
  end
@@ -1,3 +1,3 @@
1
1
  module EDN
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ describe EDN::CharStream do
4
+ it "reads a stream in order" do
5
+ s = EDN::CharStream.new(io_for("abc"))
6
+ s.current.should == "a"
7
+ s.advance.should == "b"
8
+ s.advance.should == "c"
9
+ s.advance.should == :eof
10
+ s.current.should == :eof
11
+ end
12
+
13
+ it "keeps returning the current until your advance" do
14
+ s = EDN::CharStream.new(io_for("abc"))
15
+ s.current.should == "a"
16
+ s.current.should == "a"
17
+ s.advance.should == "b"
18
+ end
19
+
20
+ it "knows if the current char is a digit" do
21
+ s = EDN::CharStream.new(io_for("4f"))
22
+ s.digit?.should be_true
23
+ s.advance
24
+ s.digit?.should be_false
25
+ end
26
+
27
+ it "knows if the current char is an alpha" do
28
+ s = EDN::CharStream.new(io_for("a9"))
29
+ s.alpha?.should be_true
30
+ s.advance
31
+ s.alpha?.should be_false
32
+ end
33
+
34
+ it "knows if the current char is whitespace" do
35
+ s = EDN::CharStream.new(io_for("a b\nc\td,"))
36
+ s.ws?.should be_false # a
37
+
38
+ s.advance
39
+ s.ws?.should be_true # " "
40
+
41
+ s.advance
42
+ s.ws?.should be_false # b
43
+
44
+ s.advance
45
+ s.ws?.should be_true # \n
46
+
47
+ s.advance
48
+ s.ws?.should be_false # c
49
+
50
+ s.advance
51
+ s.ws?.should be_true # \t
52
+
53
+ s.advance
54
+ s.ws?.should be_false # d
55
+
56
+ s.advance
57
+ s.ws?.should be_true # ,
58
+ end
59
+
60
+ it "knows if the current char is a newline" do
61
+ s = EDN::CharStream.new(io_for("a\nb\rc"))
62
+ s.newline?.should be_false # a
63
+
64
+ s.advance
65
+ s.newline?.should be_true # \n
66
+
67
+ s.advance
68
+ s.newline?.should be_false # b
69
+
70
+ s.advance
71
+ s.newline?.should be_true # \r
72
+
73
+ s.advance
74
+ s.newline?.should be_false # c
75
+ end
76
+
77
+ it "knows if it is at the eof" do
78
+ s = EDN::CharStream.new(io_for("abc"))
79
+ s.eof?.should be_false # a
80
+ s.advance
81
+ s.eof?.should be_false # b
82
+ s.advance
83
+ s.eof?.should be_false # c
84
+ s.advance
85
+ s.eof?.should be_true
86
+ end
87
+
88
+ it "knows how to skip past a char" do
89
+ s = EDN::CharStream.new(io_for("abc"))
90
+ s.skip_past("a").should == "a"
91
+ s.current.should == "b"
92
+ end
93
+
94
+ it "knows how not to skip a char" do
95
+ s = EDN::CharStream.new(io_for("abc"))
96
+ s.skip_past("X").should be_nil
97
+ end
98
+
99
+ it "knows how skip to the end of a line" do
100
+ s = EDN::CharStream.new(io_for("abc\ndef"))
101
+ s.skip_to_eol
102
+ s.current.should == "\n"
103
+ s.advance.should == "d"
104
+ end
105
+
106
+ it "knows how skip whitespace" do
107
+ s = EDN::CharStream.new(io_for(" \n \t,,,,abc"))
108
+ s.skip_ws
109
+ s.current.should == "a"
110
+ end
111
+ end
@@ -7,60 +7,32 @@ describe EDN::Parser do
7
7
 
8
8
  it "can contain comments" do
9
9
  edn = ";; This is some sample data\n[1 2 ;; the first two values\n3]"
10
- parser.should parse(edn)
11
- parser.parse(edn).should ==
12
- {:vector=>[{:integer=>"1", :precision=>nil},
13
- {:integer=>"2", :precision=>nil},
14
- {:integer=>"3", :precision=>nil}]}
10
+ EDN.read(edn).should == [1, 2, 3]
15
11
  end
16
12
 
17
13
  it "can discard using the discard reader macro" do
18
- edn = "[1 2 #_3 {:foo #_bar baz}]"
19
- parser.should parse(edn)
20
- parser.parse(edn).should ==
21
- {:vector=>[{:integer=>"1", :precision=>nil},
22
- {:integer=>"2", :precision=>nil},
23
- {:map => [{:key=>{:keyword=>{:symbol=>"foo"}}, :value=>{:symbol=>"baz"}}]}]}
14
+ edn = "[1 2 #_3 {:foo #_bar :baz}]"
15
+ EDN.read(edn).should == [1, 2, {:foo => :baz}]
24
16
  end
25
17
 
26
18
  context "element" do
27
- it "should consume nil" do
28
- parser.element.should parse("nil")
29
- end
30
-
31
19
  it "should consume metadata with the element" do
32
- parser.element.should parse('^{:doc "test"} [1 2]')
33
- end
34
- end
35
-
36
- context "comment" do
37
- it "should consume and throw away comments" do
38
- comment = "; this is a comment"
39
- parser.comment.should parse(comment)
40
- parser.comment.parse(comment).should == "; this is a comment"
41
- end
42
- end
43
-
44
- context "boolean" do
45
- it "should consume true" do
46
- parser.boolean.should parse("true")
47
- end
48
-
49
- it "should consume false" do
50
- parser.boolean.should parse("false")
20
+ x = EDN.read('^{:doc "test"} [1 2]')
21
+ x.should == [1, 2]
22
+ x.metadata.should == {doc: "test"}
51
23
  end
52
24
  end
53
25
 
54
26
  context "integer" do
55
27
  it "should consume integers" do
56
28
  rant(RantlyHelpers::INTEGER).each do |int|
57
- parser.integer.should parse(int)
29
+ (EDN.read int.to_s).should == int.to_i
58
30
  end
59
31
  end
60
32
 
61
33
  it "should consume integers prefixed with a +" do
62
34
  rant(RantlyHelpers::INTEGER).each do |int|
63
- parser.integer.should parse("+#{int.to_i.abs.to_s}")
35
+ (EDN.read "+#{int.to_i.abs.to_s}").should == int.to_i.abs
64
36
  end
65
37
  end
66
38
  end
@@ -68,41 +40,35 @@ describe EDN::Parser do
68
40
  context "float" do
69
41
  it "should consume simple floats" do
70
42
  rant(RantlyHelpers::FLOAT).each do |float|
71
- parser.float.should parse(float)
43
+ EDN.read(float.to_s).should == float.to_f
72
44
  end
73
45
  end
74
46
 
75
47
  it "should consume floats with exponents" do
76
48
  rant(RantlyHelpers::FLOAT_WITH_EXP).each do |float|
77
- parser.float.should parse(float)
49
+ EDN.read(float.to_s).should == float.to_f
78
50
  end
79
51
  end
80
52
 
81
53
  it "should consume floats prefixed with a +" do
82
54
  rant(RantlyHelpers::FLOAT).each do |float|
83
- parser.float.should parse("+#{float.to_f.abs.to_s}")
55
+ EDN.read("+#{float.to_f.abs.to_s}").should == float.to_f.abs
84
56
  end
85
57
  end
86
58
  end
87
59
 
88
60
  context "symbol" do
89
- it "should consume any symbols" do
90
- rant(RantlyHelpers::SYMBOL).each do |symbol|
91
- parser.symbol.should parse("#{symbol}")
92
- end
93
- end
94
-
95
61
  context "special cases" do
96
62
  it "should consume '/'" do
97
- parser.symbol.should parse('/')
63
+ EDN.read('/').should == EDN::Type::Symbol.new(:"/")
98
64
  end
99
65
 
100
66
  it "should consume '.'" do
101
- parser.symbol.should parse('.')
67
+ EDN.read('.').should == EDN::Type::Symbol.new(:".")
102
68
  end
103
69
 
104
70
  it "should consume '-'" do
105
- parser.symbol.should parse('-')
71
+ EDN.read('-').should == EDN::Type::Symbol.new(:"-")
106
72
  end
107
73
  end
108
74
  end
@@ -110,84 +76,70 @@ describe EDN::Parser do
110
76
  context "keyword" do
111
77
  it "should consume any keywords" do
112
78
  rant(RantlyHelpers::SYMBOL).each do |symbol|
113
- parser.keyword.should parse(":#{symbol}")
114
- end
115
- end
116
- end
117
-
118
- context "tag" do
119
- it "should consume any tags" do
120
- rant(RantlyHelpers::TAG).each do |tag|
121
- parser.tag.should parse(tag)
79
+ EDN.read(":#{symbol}").should == symbol.to_sym
122
80
  end
123
81
  end
124
82
  end
125
83
 
126
84
  context "string" do
127
85
  it "should consume any string" do
128
- rant(RantlyHelpers::STRING).each do |string|
129
- parser.string.should parse(string)
86
+ rant(RantlyHelpers::RUBY_STRING).each do |string|
87
+ EDN.read(string.to_edn).should == string
130
88
  end
131
89
  end
132
90
  end
133
91
 
134
92
  context "character" do
135
93
  it "should consume any character" do
136
- rant(RantlyHelpers::CHARACTER).each do |char|
137
- parser.character.should parse(char)
94
+ rant(RantlyHelpers::RUBY_CHAR).each do |char|
95
+ EDN.read(char.to_edn).should == char
138
96
  end
139
97
  end
140
98
  end
141
99
 
142
100
  context "vector" do
143
101
  it "should consume an empty vector" do
144
- parser.vector.should parse('[]')
145
- parser.vector.should parse('[ ]')
102
+ EDN.read('[]').should == []
103
+ EDN.read('[ ]').should == []
146
104
  end
147
105
 
148
106
  it "should consume vectors of mixed elements" do
149
107
  rant(RantlyHelpers::VECTOR).each do |vector|
150
- parser.vector.should parse(vector)
108
+ expect { EDN.read(vector) }.to_not raise_error
151
109
  end
152
110
  end
153
111
  end
154
112
 
155
113
  context "list" do
156
114
  it "should consume an empty list" do
157
- parser.list.should parse('()')
158
- parser.list.should parse('( )')
115
+ EDN.read('()').should == []
116
+ EDN.read('( )').should == []
159
117
  end
160
118
 
161
119
  it "should consume lists of mixed elements" do
162
120
  rant(RantlyHelpers::LIST).each do |list|
163
- parser.list.should parse(list)
121
+ expect { EDN.read(list) }.to_not raise_error
164
122
  end
165
123
  end
166
124
  end
167
125
 
168
126
  context "set" do
169
127
  it "should consume an empty set" do
170
- parser.set.parse_with_debug('#{}')
171
- parser.set.should parse('#{}')
172
- parser.set.should parse('#{ }')
128
+ EDN.read('#{}').should == Set.new
129
+ EDN.read('#{ }').should == Set.new
173
130
  end
174
131
 
175
132
  it "should consume sets of mixed elements" do
176
133
  rant(RantlyHelpers::SET).each do |set|
177
- parser.set.should parse(set)
134
+ EDN.read(set)
178
135
  end
179
136
  end
180
137
  end
181
138
 
182
139
  context "map" do
183
- it "should consume an empty map" do
184
- parser.map.should parse('{}')
185
- parser.map.should parse('{ }')
186
- end
187
-
188
140
  it "should consume maps of mixed elements" do
189
141
  rant(RantlyHelpers::MAP).each do |map|
190
- parser.map.should parse(map)
142
+ expect { EDN.read(map) }.not_to raise_error
191
143
  end
192
144
  end
193
145
  end
@@ -196,14 +148,14 @@ describe EDN::Parser do
196
148
  context "#inst" do
197
149
  it "should consume #inst" do
198
150
  rant(RantlyHelpers::INST).each do |element|
199
- parser.tagged_element.should parse(element)
151
+ expect { EDN.read(element) }.not_to raise_error
200
152
  end
201
153
  end
202
154
  end
203
155
 
204
156
  it "should consume tagged elements" do
205
157
  rant(RantlyHelpers::TAGGED_ELEMENT).each do |element|
206
- parser.tagged_element.should parse(element)
158
+ expect { EDN.read(element) }.not_to raise_error
207
159
  end
208
160
  end
209
161
  end
@@ -1,10 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe EDN::Reader do
4
- let(:reader) { EDN::Reader.new("[1 2] 3 :a {:b c}") }
4
+ let(:reader) { EDN::Reader.new("[1 2] 3 :a {:b c} ") }
5
5
 
6
- it "should respond to count" do
7
- reader.count.should == 4
6
+ it "should read each value" do
7
+ reader.read.should == [1, 2]
8
+ reader.read.should == 3
9
+ reader.read.should == :a
10
+ reader.read.should == {:b => ~"c"}
8
11
  end
9
12
 
10
13
  it "should respond to each" do
@@ -13,11 +16,8 @@ describe EDN::Reader do
13
16
  end
14
17
  end
15
18
 
16
- it "should return an Enumerator from each if no block given" do
17
- reader.each.should be_a(Enumerator)
18
- end
19
-
20
- it "should respond to map" do
21
- reader.map { |x| x }.should == [[1, 2], 3, :a, {:b => ~"c"}]
19
+ it "returns a special end of file value if asked" do
20
+ 4.times { reader.read(:the_end).should_not == :the_end }
21
+ reader.read(:no_more).should == :no_more
22
22
  end
23
23
  end
@@ -1,9 +1,39 @@
1
1
  require 'spec_helper'
2
+ require 'stringio'
2
3
 
3
4
  describe EDN do
4
5
  include RantlyHelpers
5
6
 
6
7
  context "#read" do
8
+ it "reads from a stream" do
9
+ io = StringIO.new("123")
10
+ EDN.read(io).should == 123
11
+ end
12
+
13
+ it "reads mutiple values from a stream" do
14
+ io = StringIO.new("123 456 789")
15
+ EDN.read(io).should == 123
16
+ EDN.read(io).should == 456
17
+ EDN.read(io).should == 789
18
+ end
19
+
20
+ it "raises an exception on eof by default" do
21
+ expect { EDN.read('') }.to raise_error
22
+ end
23
+
24
+ it "allows you to specify an eof value" do
25
+ io = StringIO.new("123 456")
26
+ EDN.read(io, :my_eof).should == 123
27
+ EDN.read(io, :my_eof).should == 456
28
+ EDN.read(io, :my_eof).should == :my_eof
29
+ end
30
+
31
+ it "allows you to specify nil as an eof value" do
32
+ EDN.read("", nil).should == nil
33
+ end
34
+ end
35
+
36
+ context "reading data" do
7
37
  it "reads single elements" do
8
38
  EDN.read(%q{""}).should == ""
9
39
  EDN.read("1").should == 1
@@ -20,24 +50,27 @@ describe EDN do
20
50
  EDN.read('\c').should == "c"
21
51
  end
22
52
 
23
- it "should support M suffix without decimals" do
53
+ it "should support M suffix without decimals" do
24
54
  EDN.read(123412341231212121241234.to_edn).should == 123412341231212121241234
25
55
  EDN.read("123412341231212121241234M").should == 123412341231212121241234
26
56
  end
27
57
 
28
- it "reads #inst tagged elements" do
29
- EDN.read('#inst "2012-09-10T16:16:03-04:00"').should == DateTime.new(2012, 9, 10, 16, 16, 3, '-04:00')
30
- end
31
-
32
58
  it "reads vectors" do
33
59
  EDN.read('[]').should == []
60
+ EDN.read('()').should be_a(Array)
34
61
  EDN.read('[1]').should == [1]
35
62
  EDN.read('["hello" 1 2]').should == ['hello', 1, 2]
36
63
  EDN.read('[[1 [:hi]]]').should == [[1, [:hi]]]
37
64
  end
38
65
 
66
+ it "reads tagged elements" do
67
+ EDN.read('#inst "2012-09-10T16:16:03-04:00"').should == DateTime.rfc3339("2012-09-10T16:16:03-04:00")
68
+ EDN.read('#uuid "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"').should == "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
69
+ end
70
+
39
71
  it "reads lists" do
40
72
  EDN.read('()').should == []
73
+ EDN.read('()').should be_a(EDN::Type::List)
41
74
  EDN.read('(1)').should == [1]
42
75
  EDN.read('("hello" 1 2)').should == ['hello', 1, 2]
43
76
  EDN.read('((1 (:hi)))').should == [[1, [:hi]]]
@@ -45,6 +78,7 @@ describe EDN do
45
78
 
46
79
  it "reads maps" do
47
80
  EDN.read('{}').should == {}
81
+ EDN.read('{}').should be_a(Hash)
48
82
  EDN.read('{:a :b}').should == {:a => :b}
49
83
  EDN.read('{:a 1, :b 2}').should == {:a => 1, :b => 2}
50
84
  EDN.read('{:a {:b :c}}').should == {:a => {:b => :c}}