rouge-lang 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'rouge'
4
+
5
+ describe Rouge::Metadata do
6
+ before do
7
+ @class = Class.new do
8
+ include Rouge::Metadata
9
+ end
10
+ end
11
+
12
+ describe "the metadata accessors" do
13
+ it "should be present on class instances" do
14
+ @class.new.should respond_to(:meta).with(0).arguments
15
+ @class.new.should respond_to(:meta=).with(1).argument
16
+ end
17
+
18
+ it "should default to nil" do
19
+ @class.new.meta.should be_nil
20
+ end
21
+
22
+ it "should return the new value when set" do
23
+ i = @class.new
24
+ i.meta = {:x => 4}
25
+ i.meta.to_s.should eq({:x => 4}.to_s)
26
+ end
27
+
28
+ it "should not allow being set to anything other than a Hash or nil" do
29
+ lambda {
30
+ @class.new.meta = {:a => 1}
31
+ @class.new.meta = {}
32
+ @class.new.meta = {1 => 2, 3 => 4, 5 => {}}
33
+ @class.new.meta = nil
34
+ }.should_not raise_exception
35
+
36
+ lambda {
37
+ @class.new.meta = 4
38
+ }.should raise_exception(Rouge::Metadata::InvalidMetadataError)
39
+
40
+ lambda {
41
+ @class.new.meta = true
42
+ }.should raise_exception(Rouge::Metadata::InvalidMetadataError)
43
+
44
+ lambda {
45
+ @class.new.meta = Rouge::Symbol[:blah]
46
+ }.should raise_exception(Rouge::Metadata::InvalidMetadataError)
47
+
48
+ lambda {
49
+ @class.new.meta = []
50
+ }.should raise_exception(Rouge::Metadata::InvalidMetadataError)
51
+
52
+ lambda {
53
+ @class.new.meta = Rouge::Seq::Cons["what"]
54
+ }.should raise_exception(Rouge::Metadata::InvalidMetadataError)
55
+ end
56
+ end
57
+ end
58
+
59
+ # vim: set sw=2 et cc=80:
@@ -0,0 +1,125 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'rouge'
4
+
5
+ describe Rouge::Namespace do
6
+ describe "the [] method" do
7
+ it "should vivify non-extant namespaces" do
8
+ Rouge::Namespace.exists?(:vivify_test).should eq false
9
+ Rouge::Namespace[:vivify_test].should be_an_instance_of Rouge::Namespace
10
+ Rouge::Namespace.exists?(:vivify_test).should eq true
11
+ end
12
+ end
13
+
14
+ describe "the Rouge[] shortcut" do
15
+ it "should directly call the [] method" do
16
+ Rouge::Namespace.should_receive(:[]).with(:trazzle)
17
+ Rouge[:trazzle]
18
+ end
19
+ end
20
+
21
+ describe "the set_here method" do
22
+ it "should create a var for the name, assigning the root to the value" do
23
+ w = Rouge::Namespace.new :w
24
+ w.set_here :waldorf, "Yes!"
25
+ w[:waldorf].should eq Rouge::Var.new(:w, :waldorf, "Yes!")
26
+ end
27
+ end
28
+
29
+ describe "the intern method" do
30
+ it "should create an unbound var for the name if it doesn't exist" do
31
+ m = Rouge::Namespace.new :m
32
+ m.intern :connor
33
+ m[:connor].should eq Rouge::Var.new(:m, :connor)
34
+ end
35
+
36
+ it "should do nothing if the var already exists" do
37
+ q = Rouge::Namespace.new :q
38
+ q.set_here :matthias, 50
39
+ q.intern :matthias
40
+ q[:matthias].should eq Rouge::Var.new(:q, :matthias, 50)
41
+ end
42
+ end
43
+
44
+ describe "the refer method" do
45
+ it "should cause items in one namespace to be locatable from the other" do
46
+ abc = Rouge::Namespace.new :abc
47
+ xyz = Rouge::Namespace.new :xyz
48
+
49
+ xyz.refer abc
50
+
51
+ abc.set_here :hello, :wow
52
+ xyz[:hello].deref.should eq :wow
53
+ end
54
+
55
+ it "may not be used to refer namespaces to themselves" do
56
+ lambda {
57
+ Rouge[:user].refer Rouge[:user]
58
+ }.should raise_exception(Rouge::Namespace::RecursiveNamespaceError)
59
+ end
60
+ end
61
+
62
+ describe "the destroy method" do
63
+ it "should obliterate a namespace" do
64
+ Rouge[:"user.spec2"].set_here :nope, :ok
65
+ Rouge::Namespace.destroy :"user.spec2"
66
+ lambda {
67
+ Rouge[:"user.spec2"][:nope]
68
+ }.should raise_exception(Rouge::Namespace::VarNotFoundError)
69
+ end
70
+ end
71
+
72
+ describe "the rouge.builtin namespace" do
73
+ before do
74
+ @ns = Rouge[:"rouge.builtin"]
75
+ end
76
+
77
+ it "should contain elements from Rouge::Builtins" do
78
+ @ns[:let].deref.should be_an_instance_of Rouge::Builtin
79
+ @ns[:quote].deref.should be_an_instance_of Rouge::Builtin
80
+ end
81
+
82
+ it "should not find objects from ruby" do
83
+ lambda {
84
+ @ns[:Float]
85
+ }.should raise_exception(Rouge::Namespace::VarNotFoundError)
86
+ lambda {
87
+ @ns[:String]
88
+ }.should raise_exception(Rouge::Namespace::VarNotFoundError)
89
+ end
90
+
91
+ it "should have a name" do
92
+ @ns.name.should eq :"rouge.builtin"
93
+ end
94
+ end
95
+
96
+ describe "the ruby namespace" do
97
+ before do
98
+ @ns = Rouge::Namespace[:ruby]
99
+ end
100
+
101
+ it "should contain elements from Kernel" do
102
+ @ns[:Hash].should eq Rouge::Var.new(:ruby, :Hash, Hash)
103
+ @ns[:Fixnum].should eq Rouge::Var.new(:ruby, :Fixnum, Fixnum)
104
+ end
105
+
106
+ it "should contain global variables" do
107
+ @ns[:"$LOAD_PATH"].
108
+ should eq Rouge::Var.new(:ruby, :$LOAD_PATH, $LOAD_PATH)
109
+ end
110
+
111
+ it "should have a name" do
112
+ @ns.name.should eq :ruby
113
+ end
114
+ end
115
+
116
+ describe "the read method" do
117
+ it "should read input in this namespace" do
118
+ Rouge::Namespace[:xyz].read("`ham").
119
+ should eq Rouge::Seq::Cons[Rouge::Symbol[:quote],
120
+ Rouge::Symbol[:"xyz/ham"]]
121
+ end
122
+ end
123
+ end
124
+
125
+ # vim: set sw=2 et cc=80:
@@ -0,0 +1,191 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'rouge'
4
+
5
+ describe Rouge::Printer do
6
+ describe ".print" do
7
+ context "numbers" do
8
+ it { Rouge.print(12755, "").should eq "12755" }
9
+ end
10
+
11
+ context "symbols" do
12
+ it { Rouge.print(Rouge::Symbol[:loki], "").should eq "loki" }
13
+ it { Rouge.print(Rouge::Symbol[:/], "").should eq "/" }
14
+ it { Rouge.print(Rouge::Symbol[:wah?], "").should eq "wah?" }
15
+ it { Rouge.print(Rouge::Symbol[:"!ruby!"], "").should eq "!ruby!" }
16
+ it { Rouge.print(Rouge::Symbol[:nil], "").should eq "nil" }
17
+ it { Rouge.print(Rouge::Symbol[:true], "").should eq "true" }
18
+ it { Rouge.print(Rouge::Symbol[:false], "").should eq "false" }
19
+ end
20
+
21
+ context "keywords" do
22
+ context "plain keywords" do
23
+ it { Rouge.print(:loki, "").should eq ":loki" }
24
+ it { Rouge.print(:/, "").should eq ":/" }
25
+ it { Rouge.print(:wah?, "").should eq ":wah?" }
26
+ it { Rouge.print(:nil, "").should eq ":nil" }
27
+ it { Rouge.print(:true, "").should eq ":true" }
28
+ it { Rouge.print(:false, "").should eq ":false" }
29
+ end
30
+
31
+ context "string-symbols" do
32
+ it { Rouge.print(:"!ruby!", "").should eq ":\"!ruby!\"" }
33
+ end
34
+ end
35
+
36
+ context "strings" do
37
+ context "plain strings" do
38
+ it { Rouge.print("akashi yo", "").should eq "\"akashi yo\"" }
39
+ it { Rouge.print("akashi\nwoah!", "").should eq "\"akashi\\nwoah!\"" }
40
+ end
41
+
42
+ context "escape sequences" do
43
+ it { Rouge.print("here \" goes", "").should eq "\"here \\\" goes\"" }
44
+ it { Rouge.print("here \\ goes", "").should eq "\"here \\\\ goes\"" }
45
+ it { Rouge.print("\a\b\e\f\n", "").should eq "\"\\a\\b\\e\\f\\n\"" }
46
+ it { Rouge.print("\r\t\v", "").should eq "\"\\r\\t\\v\"" }
47
+ end
48
+ end
49
+
50
+ context "lists" do
51
+ context "empty list" do
52
+ it { Rouge.print(Rouge::Seq::Cons[], "").should eq "()" }
53
+ end
54
+
55
+ context "one-element lists" do
56
+ it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:tiffany]], "").
57
+ should eq "(tiffany)" }
58
+ it { Rouge.print(Rouge::Seq::Cons[:raaaaash], "").
59
+ should eq "(:raaaaash)" }
60
+ end
61
+
62
+ context "multiple-element lists" do
63
+ it { Rouge.print(Rouge::Seq::Cons[1, 2, 3], "").should eq "(1 2 3)" }
64
+ it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:true],
65
+ Rouge::Seq::Cons[], [], "no"], "").
66
+ should eq "(true () [] \"no\")" }
67
+ end
68
+
69
+ context "nested lists" do
70
+ it { Rouge.print(
71
+ Rouge::Seq::Cons[
72
+ Rouge::Seq::Cons[Rouge::Seq::Cons[3],
73
+ Rouge::Seq::Cons[Rouge::Seq::Cons[]]],
74
+ 9,
75
+ Rouge::Seq::Cons[Rouge::Seq::Cons[8],
76
+ Rouge::Seq::Cons[8]]],
77
+ "").
78
+ should eq "(((3) (())) 9 ((8) (8)))" }
79
+ end
80
+ end
81
+
82
+ context "vectors" do
83
+ context "the empty vector" do
84
+ it { Rouge.print([], "").should eq "[]" }
85
+ end
86
+
87
+ context "one-element vectors" do
88
+ it { Rouge.print([Rouge::Symbol[:tiffany]], "").should eq "[tiffany]" }
89
+ it { Rouge.print([:raaaaash], "").should eq "[:raaaaash]" }
90
+ end
91
+
92
+ context "multiple-element vectors" do
93
+ it { Rouge.print([1, 2, 3], "").should eq "[1 2 3]" }
94
+ it { Rouge.print([Rouge::Symbol[:true], Rouge::Seq::Cons[], [], "no"], "").
95
+ should eq "[true () [] \"no\"]" }
96
+ end
97
+
98
+ context "nested vectors" do
99
+ it { Rouge.print([[[3], [[]]], 9, [[8], [8]]], "").
100
+ should eq "[[[3] [[]]] 9 [[8] [8]]]" }
101
+ end
102
+ end
103
+
104
+ context "quotations" do
105
+ it { Rouge.print(
106
+ Rouge::Seq::Cons[Rouge::Symbol[:quote], Rouge::Symbol[:x]],
107
+ "").
108
+ should eq "'x" }
109
+ it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:quote],
110
+ Rouge::Seq::Cons[Rouge::Symbol[:quote],
111
+ Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:quote],
112
+ Rouge::Symbol[:x]]]]], "").
113
+ should eq "''('x)" }
114
+ end
115
+
116
+ context "vars" do
117
+ it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:var],
118
+ Rouge::Symbol[:"x/y"]], "").
119
+ should eq "#'x/y" }
120
+
121
+ it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:var],
122
+ Rouge::Seq::Cons[Rouge::Symbol[:var],
123
+ Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:var],
124
+ Rouge::Symbol[:"x/y"]]]]], "").
125
+ should eq "#'#'(#'x/y)" }
126
+
127
+ it { Rouge.print(Rouge::Var.new(:x, :y), "").should eq "#'x/y" }
128
+ end
129
+
130
+ context "maps" do
131
+ context "the empty map" do
132
+ it { Rouge.print({}, "").should eq "{}" }
133
+ end
134
+
135
+ context "one-element maps" do
136
+ it { Rouge.print({Rouge::Symbol[:a] => 1}, "").should eq "{a 1}" }
137
+ it { Rouge.print({"quux" => [Rouge::Symbol[:lambast]]}, "").
138
+ should eq "{\"quux\" [lambast]}" }
139
+ end
140
+
141
+ context "multiple-element maps" do
142
+ # XXX(arlen): these tests rely on stable-ish Hash order
143
+ it { Rouge.print({:a => 1, :b => 2}, "").should eq "{:a 1, :b 2}" }
144
+ it { Rouge.print({:f => :f, :y => :y, :z => :z}, "").
145
+ should eq "{:f :f, :y :y, :z :z}" }
146
+ end
147
+
148
+ context "nested maps" do
149
+ # XXX(arlen): this test relies on stable-ish Hash order
150
+ it { Rouge.print({:a => {:z => 9},
151
+ :b => {:q => Rouge::Symbol[:q]}}, "").
152
+ should eq "{:a {:z 9}, :b {:q q}}" }
153
+ it { Rouge.print({{9 => 7} => 5}, "").should eq "{{9 7} 5}" }
154
+ end
155
+ end
156
+
157
+ context "fundamental objects" do
158
+ it { Rouge.print(nil, "").should eq "nil" }
159
+ it { Rouge.print(true, "").should eq "true" }
160
+ it { Rouge.print(false, "").should eq "false" }
161
+ end
162
+
163
+ context "Ruby classes" do
164
+ it { Rouge.print(Object, "").should eq "ruby/Object" }
165
+ it { Rouge.print(Class, "").should eq "ruby/Class" }
166
+ it { Rouge.print(Rouge::Context, "").should eq "ruby/Rouge.Context" }
167
+
168
+ let(:anon) { Class.new }
169
+ it { Rouge.print(anon, "").should eq anon.inspect }
170
+ end
171
+
172
+ context "builtin forms" do
173
+ it { Rouge.print(Rouge::Builtin[Rouge::Builtins.method(:let)], "").
174
+ should eq "rouge.builtin/let" }
175
+ it { Rouge.print(Rouge::Builtin[Rouge::Builtins.method(:def)], "").
176
+ should eq "rouge.builtin/def" }
177
+ end
178
+
179
+ context "unknown forms" do
180
+ let(:l) { lambda {} }
181
+ it { Rouge.print(l, "").should eq l.inspect }
182
+ end
183
+
184
+ context "regexp" do
185
+ let(:rx) { Regexp.new("abc") }
186
+ it { Rouge.print(rx, "").should eq "#\"abc\"" }
187
+ end
188
+ end
189
+ end
190
+
191
+ # vim: set sw=2 et cc=80:
@@ -0,0 +1,422 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'rouge'
4
+
5
+ describe Rouge::Reader do
6
+ before do
7
+ @ns = Rouge[:"user.spec"].clear
8
+ @ns.refer Rouge[:"rouge.builtin"]
9
+ end
10
+
11
+ describe "reading numbers" do
12
+ it { @ns.read("12755").should eq 12755 }
13
+ it { @ns.read("2_50_9").should eq 2509 }
14
+ it { @ns.read("-999").should eq(-999) }
15
+ it { @ns.read("+1704").should eq(1704) }
16
+
17
+ context "floats" do
18
+ it { @ns.read("23.0").should be_an_instance_of Float }
19
+ it { @ns.read("23.0").should eq 23.0 }
20
+ it { @ns.read("23.1").should eq 23.1 }
21
+ it { @ns.read("-23.1").should eq(-23.1) }
22
+ it { @ns.read("+17.04").should eq(17.04) }
23
+ it { @ns.read("+1_000e-3").should eq(1.0) }
24
+ it { @ns.read("+1E+3").should eq(1000) }
25
+ end
26
+
27
+ context "binary" do
28
+ it { @ns.read("+0b10").should eq(2) }
29
+ it { @ns.read("-0b10").should eq(-2) }
30
+ end
31
+
32
+ context "hexadecimal" do
33
+ it { @ns.read("+0xf").should eq(15) }
34
+ it { @ns.read("-0xf").should eq(-15) }
35
+ end
36
+
37
+ context "octal" do
38
+ it { @ns.read("+0333").should eq(219) }
39
+ it { @ns.read("-0333").should eq(-219) }
40
+ end
41
+
42
+ it "should fail on invalid numbers" do
43
+ lambda { @ns.read("1.2.3") }.should raise_exception(Rouge::Reader::UnexpectedCharacterError)
44
+ lambda { @ns.read("12..") }.should raise_exception(Rouge::Reader::UnexpectedCharacterError)
45
+ end
46
+ end
47
+
48
+ it "should read symbols" do
49
+ @ns.read("loki").should eq Rouge::Symbol[:loki]
50
+ @ns.read("wah?").should eq Rouge::Symbol[:wah?]
51
+ @ns.read("!ruby!").should eq Rouge::Symbol[:"!ruby!"]
52
+ @ns.read("nil").should eq Rouge::Symbol[:nil]
53
+ @ns.read("nil").should eq nil
54
+ @ns.read("true").should eq Rouge::Symbol[:true]
55
+ @ns.read("true").should eq true
56
+ @ns.read("false").should eq Rouge::Symbol[:false]
57
+ @ns.read("false").should eq false
58
+ @ns.read("&").should eq Rouge::Symbol[:&]
59
+ @ns.read("*").should eq Rouge::Symbol[:*]
60
+ @ns.read("-").should eq Rouge::Symbol[:-]
61
+ @ns.read("+").should eq Rouge::Symbol[:+]
62
+ @ns.read("/").should eq Rouge::Symbol[:/]
63
+ @ns.read("|").should eq Rouge::Symbol[:|]
64
+ @ns.read("$").should eq Rouge::Symbol[:"$"]
65
+ @ns.read(".").should eq Rouge::Symbol[:"."]
66
+ @ns.read(".[]").should eq Rouge::Symbol[:".[]"]
67
+ @ns.read("=").should eq Rouge::Symbol[:"="]
68
+ @ns.read("%").should eq Rouge::Symbol[:"%"]
69
+ @ns.read(">").should eq Rouge::Symbol[:">"]
70
+ @ns.read("<").should eq Rouge::Symbol[:"<"]
71
+ @ns.read("%50").should eq Rouge::Symbol[:"%50"]
72
+ @ns.read("xyz#").should eq Rouge::Symbol[:"xyz#"]
73
+ end
74
+
75
+ describe "keywords" do
76
+ it "should read plain keywords" do
77
+ @ns.read(":loki").should eq :loki
78
+ @ns.read(":/").should eq :/
79
+ @ns.read(":wah?").should eq :wah?
80
+ @ns.read(":nil").should eq :nil
81
+ @ns.read(":true").should eq :true
82
+ @ns.read(":false").should eq :false
83
+ end
84
+
85
+ it "should read string-symbols" do
86
+ @ns.read(":\"!ruby!\"").should eq :"!ruby!"
87
+ end
88
+ end
89
+
90
+ describe "strings" do
91
+ it "should read plain strings" do
92
+ @ns.read("\"akashi yo\"").should eq "akashi yo"
93
+ @ns.read("\"akashi \n woah!\"").should eq "akashi \n woah!"
94
+ end
95
+
96
+ it "should read escape sequences" do
97
+ @ns.read("\"here \\\" goes\"").should eq "here \" goes"
98
+ @ns.read("\"here \\\\ goes\"").should eq "here \\ goes"
99
+ @ns.read("\"\\a\\b\\e\\f\\n\\r\"").should eq "\a\b\e\f\n\r"
100
+ @ns.read("\"\\s\\t\\v\"").should eq "\s\t\v"
101
+ end
102
+
103
+ it "should read strings as frozen" do
104
+ @ns.read("\"bah\"").should be_frozen
105
+ end
106
+ end
107
+
108
+ describe "lists" do
109
+ it "should read the empty list" do
110
+ @ns.read("()").should eq Rouge::Seq::Cons[]
111
+ end
112
+
113
+ it "should read one-element lists" do
114
+ @ns.read("(tiffany)").should eq Rouge::Seq::Cons[Rouge::Symbol[:tiffany]]
115
+ @ns.read("(:raaaaash)").
116
+ should eq Rouge::Seq::Cons[:raaaaash]
117
+ end
118
+
119
+ it "should read multiple-element lists" do
120
+ @ns.read("(1 2 3)").should eq Rouge::Seq::Cons[1, 2, 3]
121
+ @ns.read("(true () [] \"no\")").
122
+ should eq Rouge::Seq::Cons[Rouge::Symbol[:true], Rouge::Seq::Cons[], [], "no"]
123
+ end
124
+
125
+ it "should read nested lists" do
126
+ @ns.read("(((3) (())) 9 ((8) (8)))").
127
+ should eq Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Seq::Cons[3],
128
+ Rouge::Seq::Cons[Rouge::Seq::Cons[]]], 9,
129
+ Rouge::Seq::Cons[Rouge::Seq::Cons[8], Rouge::Seq::Cons[8]]]
130
+ end
131
+
132
+ it "should read lists as frozen" do
133
+ @ns.read("()").should be_frozen
134
+ @ns.read("(1)").should be_frozen
135
+ @ns.read("(1 2)").should be_frozen
136
+ end
137
+ end
138
+
139
+ describe "vectors" do
140
+ it "should read the empty vector" do
141
+ @ns.read("[]").should eq []
142
+ end
143
+
144
+ it "should read one-element vectors" do
145
+ @ns.read("[tiffany]").should eq [Rouge::Symbol[:tiffany]]
146
+ @ns.read("[:raaaaash]").should eq [:raaaaash]
147
+ end
148
+
149
+ it "should read multiple-element vectors" do
150
+ @ns.read("[1 2 3]").should eq [1, 2, 3]
151
+ @ns.read("[true () [] \"no\"]").
152
+ should eq [Rouge::Symbol[:true], Rouge::Seq::Cons[], [], "no"]
153
+ end
154
+
155
+ it "should read nested vectors" do
156
+ @ns.read("[[[3] [[]]] 9 [[8] [8]]]").
157
+ should eq [[[3], [[]]], 9, [[8], [8]]]
158
+ end
159
+
160
+ it "should read vectors as frozen" do
161
+ @ns.read("[]").should be_frozen
162
+ @ns.read("[1]").should be_frozen
163
+ @ns.read("[1 2]").should be_frozen
164
+ end
165
+ end
166
+
167
+ describe "quotations" do
168
+ it "should read 'X as (QUOTE X)" do
169
+ @ns.read("'x").
170
+ should eq Rouge::Seq::Cons[Rouge::Symbol[:quote], Rouge::Symbol[:x]]
171
+ end
172
+
173
+ it "should read ''('X) as (QUOTE (QUOTE ((QUOTE X))))" do
174
+ @ns.read("''('x)").
175
+ should eq Rouge::Seq::Cons[Rouge::Symbol[:quote],
176
+ Rouge::Seq::Cons[Rouge::Symbol[:quote],
177
+ Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:quote],
178
+ Rouge::Symbol[:x]]]]]
179
+ end
180
+ end
181
+
182
+ describe "vars" do
183
+ it "should read #'X as (VAR X)" do
184
+ @ns.read("#'x").
185
+ should eq Rouge::Seq::Cons[Rouge::Symbol[:var], Rouge::Symbol[:x]]
186
+ end
187
+
188
+ it "should read #'#'(#'X) as (VAR (VAR ((VAR X))))" do
189
+ @ns.read("#'#'(#'x)").
190
+ should eq Rouge::Seq::Cons[Rouge::Symbol[:var],
191
+ Rouge::Seq::Cons[Rouge::Symbol[:var],
192
+ Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:var],
193
+ Rouge::Symbol[:x]]]]]
194
+ end
195
+ end
196
+
197
+ describe "maps" do
198
+ it "should read the empty map" do
199
+ @ns.read("{}").should eq({})
200
+ end
201
+
202
+ it "should read one-element maps" do
203
+ @ns.read("{a 1}").to_s.should eq({Rouge::Symbol[:a] => 1}.to_s)
204
+ @ns.read("{\"quux\" [lambast]}").
205
+ should eq({"quux" => [Rouge::Symbol[:lambast]]})
206
+ end
207
+
208
+ it "should read multiple-element maps" do
209
+ @ns.read("{:a 1 :b 2}").should eq({:a => 1, :b => 2})
210
+ @ns.read("{:f :f, :y :y\n:z :z}").
211
+ should eq({:f => :f, :y => :y, :z => :z})
212
+ end
213
+
214
+ it "should read nested maps" do
215
+ @ns.read("{:a {:z 9} :b {:q q}}").should eq(
216
+ {:a => {:z => 9}, :b => {:q => Rouge::Symbol[:q]}})
217
+ @ns.read("{{9 7} 5}").should eq({{9 => 7} => 5})
218
+ end
219
+
220
+ it "should read maps as frozen" do
221
+ @ns.read("{}").should be_frozen
222
+ @ns.read("{:a 1}").should be_frozen
223
+ end
224
+ end
225
+
226
+ describe "whitespace behaviour" do
227
+ it "should not fail with trailing whitespace" do
228
+ lambda {
229
+ @ns.read(":hello \n\n\t\t ").should eq :hello
230
+ }.should_not raise_exception
231
+ end
232
+
233
+ it "should deal with whitespace in strange places" do
234
+ lambda {
235
+ @ns.read("[1 ]").should eq [1]
236
+ @ns.read(" [ 2 ] ").should eq [2]
237
+ }.should_not raise_exception
238
+ end
239
+ end
240
+
241
+ describe "empty reads" do
242
+ it "should fail on empty reads" do
243
+ lambda {
244
+ @ns.read("")
245
+ }.should raise_exception(Rouge::Reader::EndOfDataError)
246
+
247
+ lambda {
248
+ @ns.read(" \n ")
249
+ }.should raise_exception(Rouge::Reader::EndOfDataError)
250
+ end
251
+ end
252
+
253
+ describe "comments" do
254
+ it "should ignore comments" do
255
+ @ns.read("42 ;what!").should eq 42
256
+ @ns.read("[42 ;what!\n15]").should eq [42, 15]
257
+
258
+ lambda {
259
+ @ns.read(";what!")
260
+ }.should raise_exception(Rouge::Reader::EndOfDataError)
261
+
262
+ @ns.read(";what!\nhmm").should eq Rouge::Symbol[:hmm]
263
+ end
264
+ end
265
+
266
+ describe "syntax-quoting" do
267
+ describe "non-cons lists" do
268
+ it "should quote non-cons lists" do
269
+ @ns.read('`3').should eq @ns.read("'3")
270
+ @ns.read('`"my my my"').should eq @ns.read(%{'"my my my"})
271
+ end
272
+
273
+ it "should dequote within non-cons lists" do
274
+ @ns.read('`~3').should eq @ns.read("3")
275
+ @ns.read('``~3').should eq @ns.read("'3")
276
+ @ns.read('``~~3').should eq @ns.read("3")
277
+ end
278
+
279
+ it "should qualify symbols" do
280
+ @ns.read('`a').should eq @ns.read("'user.spec/a")
281
+ end
282
+
283
+ it "should not qualify special symbols" do
284
+ @ns.read('`.a').should eq @ns.read("'.a")
285
+ @ns.read('`&').should eq @ns.read("'&")
286
+ @ns.read('`|').should eq @ns.read("'|")
287
+ end
288
+ end
289
+
290
+ describe "cons-lists" do
291
+ it "should quote cons lists" do
292
+ @ns.read('`(1 2)').should eq @ns.read("(list '1 '2)")
293
+ @ns.read('`(a b)').
294
+ should eq @ns.read("(list 'user.spec/a 'user.spec/b)")
295
+ end
296
+
297
+ it "should dequote within cons lists" do
298
+ @ns.read('`(a ~b)').should eq @ns.read("(list 'user.spec/a b)")
299
+ @ns.read('`(a ~(b `(c ~d)))').
300
+ should eq @ns.read("(list 'user.spec/a (b (list 'user.spec/c d)))")
301
+ @ns.read('`(a `(b ~c))').
302
+ should eq @ns.read("(list 'user.spec/a (list 'user.spec/list " \
303
+ "(list 'quote 'user.spec/b) 'user.spec/c))")
304
+ @ns.read('`~`(x)').should eq @ns.read("(list 'user.spec/x)")
305
+ end
306
+
307
+ it "should dequote within maps" do
308
+ @ns.read('`{a ~b}').to_s.should eq @ns.read("{'user.spec/a b}").to_s
309
+ end
310
+
311
+ it "should splice within seqs and vectors" do
312
+ @ns.read('`(a ~@b c)').
313
+ should eq @ns.read("(seq (concat (list 'user.spec/a) b " \
314
+ "(list 'user.spec/c)))")
315
+ @ns.read('`(~@(a b) ~c)').
316
+ should eq @ns.read("(seq (concat (a b) (list c)))")
317
+ @ns.read('`[a ~@b c]').should eq @ns.read(<<-ROUGE)
318
+ (apply vector (concat (list 'user.spec/a) b (list 'user.spec/c)))
319
+ ROUGE
320
+ @ns.read('`[~@(a b) ~c]').
321
+ should eq @ns.read("(apply vector (concat (a b) (list c)))")
322
+ end
323
+ end
324
+
325
+ describe "gensyms" do
326
+ it "should read as unique in each invocation" do
327
+ a1 = @ns.read('`a#')
328
+ a2 = @ns.read('`a#')
329
+ a1.to_s.should_not eq a2.to_s
330
+ end
331
+
332
+ it "should read identically within each invocation" do
333
+ as = @ns.read('`(a# a# `(a# a#))')
334
+ as = as
335
+ .map {|e| e.respond_to?(:to_a) ? e.to_a : e}.to_a.flatten
336
+ .flat_map {|e| e.respond_to?(:to_a) ? e.to_a : e}
337
+ .flat_map {|e| e.respond_to?(:to_a) ? e.to_a : e}
338
+ .find_all {|e|
339
+ e.is_a?(Rouge::Symbol) and e.name.to_s =~ /^a/
340
+ }
341
+ as.length.should eq 4
342
+ as[0].should eq as[1]
343
+ as[2].should eq as[3]
344
+ as[0].should_not eq as[2]
345
+ end
346
+ end
347
+ end
348
+
349
+ describe "anonymous functions" do
350
+ it "should read anonymous functions" do
351
+ @ns.read('#(1)').should eq @ns.read('(fn [] (1))')
352
+ @ns.read('#(do 1)').should eq @ns.read('(fn [] (do 1))')
353
+ @ns.read('#(%)').should eq @ns.read('(fn [%1] (%1))')
354
+ @ns.read('#(%2)').should eq @ns.read('(fn [%1 %2] (%2))')
355
+ @ns.read('#(%5)').should eq @ns.read('(fn [%1 %2 %3 %4 %5] (%5))')
356
+ @ns.read('#(%2 %)').should eq @ns.read('(fn [%1 %2] (%2 %1))')
357
+ end
358
+ end
359
+
360
+ describe "metadata" do
361
+ it "should read metadata" do
362
+ y = @ns.read('^{:x 1} y')
363
+ y.should eq Rouge::Symbol[:y]
364
+ y.meta.to_s.should eq({:x => 1}.to_s)
365
+ end
366
+
367
+ it "should stack metadata" do
368
+ y = @ns.read('^{:y 2} ^{:y 3 :z 2} y')
369
+ y.should eq Rouge::Symbol[:y]
370
+ y.meta.should include({:y => 2, :z => 2})
371
+ end
372
+
373
+ it "should assign tags" do
374
+ y = @ns.read('^"xyz" y')
375
+ y.should eq Rouge::Symbol[:y]
376
+ y.meta.should include({:tag => "xyz"})
377
+ end
378
+
379
+ it "should assign symbol markers" do
380
+ y = @ns.read('^:blargh y')
381
+ y.should eq Rouge::Symbol[:y]
382
+ y.meta.should include({:blargh => true})
383
+ end
384
+ end
385
+
386
+ describe "deref" do
387
+ it "should read derefs" do
388
+ @ns.read('@(boo)').should eq @ns.read('(rouge.core/deref (boo))')
389
+ end
390
+ end
391
+
392
+ describe "multiple reading" do
393
+ it "should read multiple forms in turn" do
394
+ r = Rouge::Reader.new(@ns, "a b c")
395
+ r.lex.should eq Rouge::Symbol[:a]
396
+ r.lex.should eq Rouge::Symbol[:b]
397
+ r.lex.should eq Rouge::Symbol[:c]
398
+
399
+ lambda {
400
+ r.lex
401
+ }.should raise_exception(Rouge::Reader::EndOfDataError)
402
+ end
403
+ end
404
+
405
+ describe "the ns property" do
406
+ it "should return the ns the reader is in" do
407
+ Rouge::Reader.new(@ns, "").ns.should be @ns
408
+ end
409
+ end
410
+
411
+ describe "the comment dispatch" do
412
+ it "should be completely ignored" do
413
+ @ns.read('#_(xyz abc) :f').should eq :f
414
+ end
415
+ end
416
+
417
+ describe "regexp" do
418
+ it { @ns.read('#"abc"').should be_an_instance_of Regexp }
419
+ end
420
+ end
421
+
422
+ # vim: set sw=2 et cc=80: