rouge-lang 0.0.1

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.
@@ -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: