edn 1.0.3 → 1.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.
@@ -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}}