rouge-lang 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -10
- data/lib/boot.rg +89 -6
- data/lib/rouge.rb +11 -9
- data/lib/rouge/seq.rb +59 -29
- data/lib/rouge/version.rb +1 -1
- data/spec/core_spec.rg +29 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -8,19 +8,14 @@ Why?
|
|
8
8
|
* Quick boot time (currently around 0.1s).
|
9
9
|
* Ruby's gems tend to be modern with decent APIs.
|
10
10
|
|
11
|
-
You can try a Rouge REPL online at **[Try Rouge](http://try.rouge.io)
|
12
|
-
|
13
|
-
Rouge is not yet mature enough to have an installer or distributions. Just
|
14
|
-
clone the source and run the `rouge` script to start:
|
11
|
+
You can try a Rouge REPL online at **[Try Rouge](http://try.rouge.io)**, or install the gem to get the local REPL:
|
15
12
|
|
16
13
|
``` bash
|
17
|
-
|
18
|
-
|
19
|
-
bundle install
|
20
|
-
bin/rouge
|
14
|
+
gem install rouge-lang
|
15
|
+
rouge
|
21
16
|
```
|
22
17
|
|
23
|
-
You'll see the `user=>` prompt. Enjoy!
|
18
|
+
You'll see the `user=>` prompt. Enjoy!
|
24
19
|
|
25
20
|
You can discuss on Google Groups' [rouge-talk](https://groups.google.com/forum/#!forum/rouge-talk),
|
26
21
|
or on `#rouge` on Freenode.
|
@@ -54,7 +49,7 @@ salient features:
|
|
54
49
|
What about in Rails?
|
55
50
|
|
56
51
|
```
|
57
|
-
$
|
52
|
+
$ rails console -- -rrouge
|
58
53
|
Loading development environment (Rails 3.2.6)
|
59
54
|
1.9.3p194 :002 > Rouge::REPL.repl []
|
60
55
|
user=> (.where ruby/Content {:id 1})
|
data/lib/boot.rg
CHANGED
@@ -31,7 +31,7 @@
|
|
31
31
|
`(Rouge.Seq.Lazy. (fn [] ~@body)))
|
32
32
|
|
33
33
|
(defn reduce [f coll]
|
34
|
-
(.inject (.to_a coll) | f))
|
34
|
+
(.inject (.to_a (seq coll)) | f))
|
35
35
|
|
36
36
|
(defmacro when [cond & body]
|
37
37
|
`(if ~cond
|
@@ -42,7 +42,8 @@
|
|
42
42
|
(Rouge.Seq.Cons. head tail))
|
43
43
|
|
44
44
|
(defn count [coll]
|
45
|
-
(
|
45
|
+
(let [s (seq coll)]
|
46
|
+
(if s (.count s) 0)))
|
46
47
|
|
47
48
|
(defn = [a b]
|
48
49
|
(.== a b))
|
@@ -72,10 +73,11 @@
|
|
72
73
|
|
73
74
|
(defn map [f coll]
|
74
75
|
(lazy-seq
|
75
|
-
(
|
76
|
-
|
77
|
-
|
78
|
-
(
|
76
|
+
(let [s (seq coll)]
|
77
|
+
(if (empty? s)
|
78
|
+
nil
|
79
|
+
(let [[hd & tl] s]
|
80
|
+
(cons (f hd) (map f tl)))))))
|
79
81
|
|
80
82
|
(defn str [& args]
|
81
83
|
(let [args (.to_a (map .to_s args))]
|
@@ -94,6 +96,9 @@
|
|
94
96
|
(defn class [object]
|
95
97
|
(.class object))
|
96
98
|
|
99
|
+
(defn class? [obj class]
|
100
|
+
(.is_a? obj class))
|
101
|
+
|
97
102
|
(defn sequential? [coll]
|
98
103
|
(or (.is_a? coll Rouge.Seq.ISeq)
|
99
104
|
(.is_a? coll Array)))
|
@@ -363,6 +368,84 @@
|
|
363
368
|
.to_a
|
364
369
|
(.sort_by | keyfn)))
|
365
370
|
|
371
|
+
(defn to-array [coll]
|
372
|
+
"Returns an array of (seq coll)."
|
373
|
+
(.to_a (seq coll)))
|
374
|
+
|
375
|
+
(defmacro cond
|
376
|
+
([])
|
377
|
+
([test result & rest]
|
378
|
+
`(if ~test ~result (cond ~@rest))))
|
379
|
+
|
380
|
+
(ns ^{:doc "Implemenations of functions from clojure.string."}
|
381
|
+
rouge.string
|
382
|
+
(:use rouge.core ruby))
|
383
|
+
|
384
|
+
(defn blank? [s]
|
385
|
+
"Returns true if s is falsy, empty, or contains only whitespace."
|
386
|
+
(if s
|
387
|
+
(if (or (= (.length s) 0)
|
388
|
+
true
|
389
|
+
(if (.all? (to-array s) | #(.match #"\s" %))
|
390
|
+
true
|
391
|
+
false))
|
392
|
+
false)))
|
393
|
+
|
394
|
+
(defn lower-case [s]
|
395
|
+
"Converts the characters in string s to all lower-case."
|
396
|
+
(.downcase s))
|
397
|
+
|
398
|
+
(defn upper-case [s]
|
399
|
+
"Converts the string s to all upper-case."
|
400
|
+
(.upcase s))
|
401
|
+
|
402
|
+
(defn capitalize [s]
|
403
|
+
"Converts a string to all lower-case with the first character capitalized"
|
404
|
+
(-> s .downcase .capitalize))
|
405
|
+
|
406
|
+
(defn trim [s]
|
407
|
+
"Removes all leading and trailing whitespace characters from the string s."
|
408
|
+
(.strip s))
|
409
|
+
|
410
|
+
(defn ltrim [s]
|
411
|
+
"Removes all leading whitespace characters from the string s."
|
412
|
+
(.lstrip s))
|
413
|
+
|
414
|
+
(defn rtrim [s]
|
415
|
+
"Removes all trailing whitespace characters from the string s."
|
416
|
+
(.rstrip s))
|
417
|
+
|
418
|
+
(defn trim-newline [s]
|
419
|
+
"Removes all trailing newline characters from the string s."
|
420
|
+
(.sub s #"(\n|\r)*$" ""))
|
421
|
+
|
422
|
+
(defn split [s delimiter]
|
423
|
+
"Splits a string s in to substrings based on delimiter. The delimiter may be
|
424
|
+
either another string or regular expression."
|
425
|
+
(.split s delimiter))
|
426
|
+
|
427
|
+
(defn split-lines [s]
|
428
|
+
"Split the string s in to substrings at new lines."
|
429
|
+
(.split s #"\n|\r"))
|
430
|
+
|
431
|
+
(defn join [separator coll]
|
432
|
+
"Returns a string in which all elements in coll are joined by the separator."
|
433
|
+
(.join (to-array coll) separator))
|
434
|
+
|
435
|
+
(defn reverse [s]
|
436
|
+
"Returns the string s with it's characters in reverse order."
|
437
|
+
(.reverse s))
|
438
|
+
|
439
|
+
;; TODO
|
440
|
+
#_(defn escape [s cmap])
|
441
|
+
|
442
|
+
;; TODO
|
443
|
+
#_(defn replace [s match replacement])
|
444
|
+
|
445
|
+
;; TODO
|
446
|
+
#_(defn replace-first [s match replacement])
|
447
|
+
|
448
|
+
|
366
449
|
(ns rouge.test
|
367
450
|
(:use rouge.core ruby))
|
368
451
|
|
data/lib/rouge.rb
CHANGED
@@ -9,7 +9,7 @@ module Rouge; end
|
|
9
9
|
start = Time.now
|
10
10
|
Rouge.define_singleton_method :start, lambda {start}
|
11
11
|
|
12
|
-
|
12
|
+
module Rouge
|
13
13
|
require 'rouge/version'
|
14
14
|
require 'rouge/wrappers'
|
15
15
|
require 'rouge/symbol'
|
@@ -19,36 +19,38 @@ class << Rouge
|
|
19
19
|
require 'rouge/context'
|
20
20
|
require 'rouge/repl'
|
21
21
|
|
22
|
-
def print(form, out)
|
22
|
+
def self.print(form, out)
|
23
23
|
Rouge::Printer.print form, out
|
24
24
|
end
|
25
25
|
|
26
|
-
def [](ns)
|
26
|
+
def self.[](ns)
|
27
27
|
Rouge::Namespace[ns]
|
28
28
|
end
|
29
29
|
|
30
|
-
def boot!
|
30
|
+
def self.boot!
|
31
31
|
return if @booted
|
32
32
|
@booted = true
|
33
33
|
|
34
|
+
builtin = Rouge[:"rouge.builtin"]
|
35
|
+
|
34
36
|
core = Rouge[:"rouge.core"]
|
35
|
-
core.refer
|
37
|
+
core.refer builtin
|
36
38
|
|
37
39
|
user = Rouge[:user]
|
38
|
-
user.refer
|
39
|
-
user.refer
|
40
|
+
user.refer builtin
|
41
|
+
user.refer core
|
40
42
|
user.refer Rouge[:ruby]
|
41
43
|
|
42
44
|
Rouge::Context.new(user).readeval(
|
43
45
|
File.read(Rouge.relative_to_lib('boot.rg')))
|
44
46
|
end
|
45
47
|
|
46
|
-
def repl(argv)
|
48
|
+
def self.repl(argv)
|
47
49
|
boot!
|
48
50
|
Rouge::REPL.repl(argv)
|
49
51
|
end
|
50
52
|
|
51
|
-
def relative_to_lib name
|
53
|
+
def self.relative_to_lib name
|
52
54
|
File.join(File.dirname(File.absolute_path(__FILE__)), name)
|
53
55
|
end
|
54
56
|
end
|
data/lib/rouge/seq.rb
CHANGED
@@ -1,12 +1,30 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
# Functions, clases and modules concerning the `seq' sequence abstraction.
|
3
4
|
module Rouge::Seq
|
5
|
+
# An empty seq.
|
4
6
|
Empty = Object.new
|
5
7
|
|
8
|
+
# A sequence consisting of a head (element) and tail (another sequence).
|
9
|
+
# Filled out below after ASeq's definition.
|
6
10
|
class Cons; end
|
7
11
|
|
12
|
+
# A module purely to indicate that this is a seqable type. Any class
|
13
|
+
# including ISeq should define a #seq method.
|
8
14
|
module ISeq; end
|
9
15
|
|
16
|
+
# A partial implementation of ISeq. You supply #first and #next, it gives:
|
17
|
+
#
|
18
|
+
# - #cons
|
19
|
+
# - #inspect
|
20
|
+
# - #to_s
|
21
|
+
# - #seq
|
22
|
+
# - #length (#count)
|
23
|
+
# - #[]
|
24
|
+
# - #==
|
25
|
+
# - #each
|
26
|
+
# - #map
|
27
|
+
# - #to_a
|
10
28
|
module ASeq
|
11
29
|
include ISeq
|
12
30
|
|
@@ -22,41 +40,41 @@ module Rouge::Seq
|
|
22
40
|
def next; raise NotImplementedError; end
|
23
41
|
|
24
42
|
def more
|
25
|
-
|
26
|
-
if
|
43
|
+
nseq = self.next
|
44
|
+
if nseq.nil?
|
27
45
|
Empty
|
28
46
|
else
|
29
|
-
|
47
|
+
nseq
|
30
48
|
end
|
31
49
|
end
|
32
50
|
|
33
|
-
def cons(
|
34
|
-
Cons.new(
|
51
|
+
def cons(head)
|
52
|
+
Cons.new(head, self)
|
35
53
|
end
|
36
54
|
|
37
55
|
def length
|
38
|
-
|
56
|
+
len = 0
|
39
57
|
cursor = self
|
40
58
|
|
41
59
|
while cursor != Empty
|
42
|
-
|
60
|
+
len += 1
|
43
61
|
cursor = cursor.more
|
44
62
|
end
|
45
63
|
|
46
|
-
|
64
|
+
len
|
47
65
|
end
|
48
66
|
|
49
67
|
alias count length
|
50
68
|
|
51
|
-
def [](
|
52
|
-
return to_a[
|
69
|
+
def [](idx)
|
70
|
+
return to_a[idx] if idx.is_a? Range
|
53
71
|
|
54
72
|
cursor = self
|
55
73
|
|
56
|
-
|
74
|
+
idx += self.length if idx < 0
|
57
75
|
|
58
|
-
while
|
59
|
-
|
76
|
+
while idx > 0
|
77
|
+
idx -= 1
|
60
78
|
cursor = cursor.more
|
61
79
|
return nil if cursor == Empty
|
62
80
|
end
|
@@ -65,8 +83,15 @@ module Rouge::Seq
|
|
65
83
|
end
|
66
84
|
|
67
85
|
def ==(seq)
|
68
|
-
|
69
|
-
|
86
|
+
if seq.is_a?(ISeq)
|
87
|
+
return self.to_a == seq.to_a
|
88
|
+
end
|
89
|
+
|
90
|
+
if seq.is_a?(::Array)
|
91
|
+
return self.to_a == seq
|
92
|
+
end
|
93
|
+
|
94
|
+
false
|
70
95
|
end
|
71
96
|
|
72
97
|
def each(&block)
|
@@ -86,9 +111,9 @@ module Rouge::Seq
|
|
86
111
|
def map(&block)
|
87
112
|
return self.enum_for(:map) if block.nil?
|
88
113
|
|
89
|
-
|
90
|
-
self.each {|
|
91
|
-
|
114
|
+
result = []
|
115
|
+
self.each {|elem| result << block.call(elem)}
|
116
|
+
result
|
92
117
|
end
|
93
118
|
|
94
119
|
def to_a
|
@@ -96,10 +121,6 @@ module Rouge::Seq
|
|
96
121
|
self.each {|e| r << e}
|
97
122
|
r
|
98
123
|
end
|
99
|
-
|
100
|
-
def map(&block)
|
101
|
-
Cons[*to_a.map(&block)]
|
102
|
-
end
|
103
124
|
end
|
104
125
|
|
105
126
|
class << Empty
|
@@ -135,10 +156,11 @@ module Rouge::Seq
|
|
135
156
|
def next; Rouge::Seq.seq @tail; end
|
136
157
|
|
137
158
|
def self.[](*elements)
|
138
|
-
|
159
|
+
length = elements.length
|
160
|
+
return Empty if length.zero?
|
139
161
|
|
140
162
|
head = nil
|
141
|
-
(
|
163
|
+
(length - 1).downto(0).each do |i|
|
142
164
|
head = new(elements[i], head.freeze)
|
143
165
|
end
|
144
166
|
|
@@ -148,24 +170,27 @@ module Rouge::Seq
|
|
148
170
|
attr_reader :head, :tail
|
149
171
|
end
|
150
172
|
|
173
|
+
# A seq over a Ruby Array.
|
151
174
|
class Array
|
152
175
|
include ASeq
|
153
176
|
|
154
|
-
def initialize(array,
|
155
|
-
@array, @
|
177
|
+
def initialize(array, idx)
|
178
|
+
@array, @idx = array, idx
|
156
179
|
end
|
157
180
|
|
158
181
|
def first
|
159
|
-
@array[@
|
182
|
+
@array[@idx]
|
160
183
|
end
|
161
184
|
|
162
185
|
def next
|
163
|
-
if @
|
164
|
-
Array.new(@array, @
|
186
|
+
if @idx + 1 < @array.length
|
187
|
+
Array.new(@array, @idx + 1)
|
165
188
|
end
|
166
189
|
end
|
167
190
|
end
|
168
191
|
|
192
|
+
# A lazy seq; contains the body (thunk) which is a lambda to get the "real"
|
193
|
+
# seq. Once evaluated (realised), the result is cached.
|
169
194
|
class Lazy
|
170
195
|
include ISeq
|
171
196
|
|
@@ -179,6 +204,7 @@ module Rouge::Seq
|
|
179
204
|
@result
|
180
205
|
else
|
181
206
|
@result = Rouge::Seq.seq(@body.call) || Empty
|
207
|
+
@body = nil
|
182
208
|
@realized = true
|
183
209
|
@result
|
184
210
|
end
|
@@ -196,6 +222,8 @@ module Rouge::Seq
|
|
196
222
|
def to_s; seq.to_s; end
|
197
223
|
end
|
198
224
|
|
225
|
+
# An error thrown when we try to do a seq operation on something that's not
|
226
|
+
# seqable.
|
199
227
|
UnknownSeqError = Class.new(StandardError)
|
200
228
|
|
201
229
|
def self.seq(form)
|
@@ -212,6 +240,8 @@ module Rouge::Seq
|
|
212
240
|
end
|
213
241
|
when Enumerator
|
214
242
|
seq(form.to_a)
|
243
|
+
when String
|
244
|
+
seq(form.chars)
|
215
245
|
else
|
216
246
|
raise UnknownSeqError, form.inspect
|
217
247
|
end
|
data/lib/rouge/version.rb
CHANGED
data/spec/core_spec.rg
CHANGED
@@ -37,7 +37,8 @@
|
|
37
37
|
(testing "seq"
|
38
38
|
(is (.nil? (seq ())))
|
39
39
|
(is (.nil? (seq nil)))
|
40
|
-
(is (.nil? (seq [])))
|
40
|
+
(is (.nil? (seq [])))
|
41
|
+
(is (.nil? (seq ""))))
|
41
42
|
|
42
43
|
(testing "first"
|
43
44
|
(is (.nil? (first nil)))
|
@@ -90,6 +91,7 @@
|
|
90
91
|
(testing "map"
|
91
92
|
(is (= Rouge.Seq.Lazy (class (map inc [1 2 3]))))
|
92
93
|
(is (= '(2 3 4) (map inc [1 2 3])))
|
94
|
+
(is (= '("A" "B" "C") (map .upcase "abc")))
|
93
95
|
(is (= 1
|
94
96
|
(let [q (atom 0)
|
95
97
|
lazy (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
@@ -123,4 +125,30 @@
|
|
123
125
|
[hd & tl] (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
124
126
|
@q)))))
|
125
127
|
|
128
|
+
(testing "cond"
|
129
|
+
(is (= 1 (cond
|
130
|
+
:else 1)))
|
131
|
+
(is (= 1 (cond
|
132
|
+
false 2
|
133
|
+
nil 3
|
134
|
+
true 1)))
|
135
|
+
(is (nil? (cond)))
|
136
|
+
(is (nil? (cond
|
137
|
+
false 1
|
138
|
+
nil 2)))
|
139
|
+
(is (= 1 (let [q (atom 0)]
|
140
|
+
(is (= :ok (cond
|
141
|
+
(swap! q inc) :ok
|
142
|
+
(swap! q inc) :bad
|
143
|
+
(swap! q inc) :very_bad)))
|
144
|
+
@q)))
|
145
|
+
(is (= 2 (let [q (atom 0)]
|
146
|
+
(is (= :ok (cond
|
147
|
+
(do
|
148
|
+
(swap! q inc)
|
149
|
+
nil) :bad
|
150
|
+
(swap! q inc) :ok
|
151
|
+
(swap! q inc) :very_bad)))
|
152
|
+
@q))))
|
153
|
+
|
126
154
|
; vim: set ft=clojure:
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rouge-lang
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|