bus-scheme 0.7.5 → 0.7.6

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,116 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require 'test_helper'
3
+ require 'open-uri'
4
+
5
+ module BusScheme
6
+ module_function
7
+ def web_server # need to expose this for MockRequest
8
+ @web_server
9
+ end
10
+ end
11
+
12
+ if defined? BusScheme::Resource
13
+ class WebTest < Test::Unit::TestCase
14
+ def setup
15
+ @response = nil
16
+
17
+ @die_roboter = "User-agent: *\nAllow: *"
18
+ eval "(resource \"/robots.txt\" \"#{@die_roboter}\")"
19
+
20
+ eval '(define concourse-splash (quote (html
21
+ (head
22
+ (title "Concourse"))
23
+ (body
24
+ (div id "container"
25
+ (h1 "Welcome to Concourse!")
26
+ (p "Concourse is ...")
27
+ (form action "/login"
28
+ (input type "text" name "email")
29
+ (input type "password" name "password")
30
+ (input type "submit" value "Log in")))))))'
31
+ eval '(resource "/" concourse-splash)'
32
+ end
33
+
34
+ def test_serves_string_resource
35
+ get '/robots.txt'
36
+ assert_response_code 200
37
+ assert_response @die_roboter
38
+ end
39
+
40
+ def test_serves_list_resource
41
+ get '/'
42
+ assert_response_code 200
43
+ assert_response "<html>
44
+ <head>
45
+ <title>
46
+ Concourse </title>
47
+ </head>
48
+ <body>
49
+ <div id=\"container\">
50
+ <h1>
51
+ Welcome to Concourse! </h1>
52
+ <p>
53
+ Concourse is ... </p>
54
+ <form action=\"/login\">
55
+ <input type=\"text\" name=\"email\">
56
+ </input>
57
+ <input type=\"password\" name=\"password\">
58
+ </input>
59
+ <input type=\"submit\" value=\"Log in\">
60
+ </input>
61
+ </form>
62
+ </div>
63
+ </body>
64
+ </html>
65
+ "
66
+ end
67
+
68
+ def test_serves_404
69
+ get '/404'
70
+ assert_response_code 404
71
+ assert_response_match(/not found/i)
72
+ end
73
+
74
+ def test_serves_collection_of_resources
75
+ eval '(collection "/numbers" (list ' +
76
+ '(resource "/1" "1")' +
77
+ '(resource "/2" "2")' +
78
+ '(resource "/3" "3")' +
79
+ '))'
80
+
81
+ get '/numbers'
82
+ assert_response_code 200
83
+ assert_response_match(/<ul>\s*<li>\s*1\s*<\/li>/)
84
+ end
85
+
86
+ def test_link_to_resource
87
+ r = Resource.new('/foobar', "foo bar baz")
88
+ # TODO: this whitespace is getting old
89
+ assert_equal "<a href=\"/foobar\">\nbaz</a>\n", r.link_to('baz')
90
+ end
91
+
92
+ def test_serves_collection_of_resources_by_regex
93
+ end
94
+
95
+ private
96
+ def get path
97
+ @response = Rack::MockRequest.new(BusScheme.web_server).get(path)
98
+ end
99
+
100
+ def assert_response expected, message = nil
101
+ raise "No request has been made!" if @response.nil?
102
+ # TODO: make this a little less picky about whitespace etc.
103
+ assert_equal expected, @response.body, message
104
+ end
105
+
106
+ def assert_response_match expected, message = nil
107
+ raise "No request has been made!" if @response.nil?
108
+ assert_match expected, @response.body, message
109
+ end
110
+
111
+ def assert_response_code expected, message = nil
112
+ raise "No request has been made!" if @response.nil?
113
+ assert_equal expected, @response.status, message
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,69 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require 'test_helper'
3
+ require 'open-uri'
4
+
5
+ begin
6
+ require 'hpricot'
7
+
8
+ class XmlTest < Test::Unit::TestCase
9
+ def test_single_cons
10
+ assert_equal_xml "<html> </html>", eval("(xml (html))")
11
+ end
12
+
13
+ def test_singly_nested_list
14
+ assert_equal_xml("<html> <title> </title> </html>",
15
+ eval("(xml (html (title)))"))
16
+ end
17
+
18
+ def test_list_with_string
19
+ assert_equal_xml("<html> <title> Hello </title> </html>",
20
+ eval("(xml (html (title \"Hello\")))"))
21
+
22
+ end
23
+
24
+ def test_list_with_symbol
25
+ assert_equal_xml("<a href=\"http://bus-scheme.rubyforge.org\"> Bus Scheme</a>",
26
+ eval("(xml (a href \"http://bus-scheme.rubyforge.org\" \"Bus Scheme\"))"))
27
+ end
28
+
29
+ # TODO: NFI why this explodes!
30
+ def test_list_with_symbol_and_child
31
+ assert_equal_xml("<div id=\"container\"> <p> hi </p> </div>",
32
+ eval("(xml (div id \"container\" (p \"hi\")))"))
33
+ end
34
+
35
+ # TODO: no idea why this puts {} on stdout
36
+ def test_splash_page_generation
37
+ sexp = '(html
38
+ (head
39
+ (title "Concourse"))
40
+ (body
41
+ (div id "container"
42
+ (h1 "Welcome to Concourse!")
43
+ (p "Concourse is ...")
44
+ (form action "/login"
45
+ (input type "text" name "email")
46
+ (input type "password" name "password")
47
+ (input type "submit" value "Log in")))))'
48
+ xml_text = "<html> <head> <title> Concourse </title> </head>
49
+ <body> <div id=\"container\"> <h1> Welcome to Concourse! </h1>
50
+ <p> Concourse is ... </p>
51
+ <form action=\"/login\">
52
+ <input name=\"email\" type=\"text\" />
53
+ <input name=\"password\" type=\"password\" />
54
+ <input type=\"submit\" value=\"Log in\" />
55
+ </form>
56
+ </div> </body> </html>"
57
+ assert_equal_xml xml_text, eval("(xml #{sexp})")
58
+ end
59
+
60
+ private
61
+ def assert_equal_xml(expected, actual, message = nil)
62
+ # TODO: whitespace handling could be better
63
+ assert_equal Hpricot(expected).to_s.gsub(/\s+/, ' ').strip, Hpricot(actual).to_s.gsub(/\s+/, ' ').strip, message
64
+ end
65
+ end
66
+
67
+ rescue LoadError
68
+ puts "Can't test XML generation without Hpricot; sorry."
69
+ end
@@ -0,0 +1,4 @@
1
+ (define f (lambda () (stacktrace)))
2
+
3
+ (define g (lambda ()
4
+ (f)))
@@ -0,0 +1,204 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
6
+ <head>
7
+ <title>Getting Started with Bus Scheme</title>
8
+ <style type='text/css'>
9
+ body { font-family "Garuda", Sans; }
10
+ tt { font-family: "Nimbus Mono L", Serif; background-color: #ddd; }
11
+ pre { color: #222; font-family: "Nimbus Mono L", Serif; }
12
+ </style>
13
+ </head>
14
+ <body>
15
+
16
+ <h2>Getting Started with Bus Scheme</h2>
17
+ <div id="index" style="width: 60em;">
18
+
19
+ <p>So a number of folks have asked me how they should get started with
20
+ Bus Scheme.[<a href='#fn1'>1</a>]. I've mostly just said silly things
21
+ like, \"Umm... good question. Maybe read/watch <a
22
+ href='http://mitpress.mit.edu/sicp/'>SICP</a>?\", which is silly
23
+ because it doesn't have much to do with the <i>Bus</i> part of Bus
24
+ Scheme, not because <i>The Structure and Interpretation of Computer
25
+ Programs</i> is silly.</p>
26
+
27
+ <p>There's a poster in <a href='http://www.powells.com/'>my favourite
28
+ bookstore</a> that has Dante's <i>Comedy</i>, the <i>Iliad</i>, and a
29
+ few other classics captioned with something like \"Might as well start
30
+ them now; you're going to have to read them eventually anyway.\" I hold
31
+ the same notion regarding SICP and perhaps <i>The Little Schemer</i>,
32
+ but I could see how it'd be helpful to have an introduction to Scheme
33
+ from a Rubyist's perspective since reading a book like that can be
34
+ large-ish mental investment.</p>
35
+
36
+ <p>Scheme is a programming language directly descended from Lisp. It's
37
+ most often compared to Common Lisp, which is in some senses its big
38
+ brother. Scheme is usually considered less \"kitchen-sink\"-ish than
39
+ Common Lisp in that it only defines an extremely clean small core
40
+ language and allows developers to extend it seamlessly to do what they
41
+ need. In the words of the creators of Scheme:</p>
42
+
43
+ <blockquote>
44
+ Programming languages should be designed not by piling feature on top
45
+ of feature, but by removing the weaknesses and restrictions that make
46
+ additional features appear necessary.
47
+ </blockquote>
48
+
49
+ <p>(As a potential student of Scheme, you should be encouraged by this
50
+ notion as it directly translates into fewer concepts to learn.)</p>
51
+
52
+ <p>Ruby draws a lot of its heritage from Scheme, though Matz does not
53
+ share the idea that a language should be limited to a very small
54
+ number of core axioms from which everything else can be defined. [<a
55
+ href='#fn2'>2</a>] Destructive method names ending in \"!\" and
56
+ predicates ending in \"?\" were inspired by Scheme. Matz himself has
57
+ even lightheartedly referred to Ruby as \"MatzLisp\". So this is a
58
+ language that at the core should not feel too foreign to a Rubyist,
59
+ even if the syntax looks quite different.</p>
60
+
61
+ <p>Let's dive in. <tt>sudo gem install bus-scheme</tt> if you haven't
62
+ got it installed. Go ahead and launch Bus Scheme with the <tt>bus</tt>
63
+ executable. Like <tt>irb</tt>, it drops you into a REPL, or
64
+ Read-Eval-Print Loop. Scheme programs are made up of
65
+ <b>expressions</b>. When you enter expressions into the REPL, they get
66
+ evaluated and their value is shown. There are only a few simple rules
67
+ for how expressions get evaluated that we'll address below. Feel free
68
+ to experiment with entering expressions and seeing what gets
69
+ returned.</p>
70
+
71
+ <p>The simplest expressions are just <b>atoms</b>, which are simple
72
+ \"indivisible\" values, like symbols, numeric values, and strings. Some
73
+ atoms evaluate to themselves just like in Ruby, so entering
74
+ <tt>12</tt> into the REPL returns (and echoes) 12. <tt>\"foo\"</tt>
75
+ works the same way. Symbols are a little different. Ruby uses a colon
76
+ before the symbol's name, but in Scheme you refer to a symbol just
77
+ using its name. So <tt>baz</tt> refers to the symbol with the name
78
+ \"baz\". But if you enter <tt>baz</tt> into the REPL, Bus Scheme
79
+ complains:</p>
80
+
81
+ <pre class='code'>&gt; baz
82
+ Error: Undefined symbol: baz</pre>
83
+
84
+ <p>This is because symbols aren't considered <b>literals</b>; that is, they
85
+ don't evaluate to themselves like they do in Ruby. When Bus Scheme
86
+ encounters a symbol in this context, it treats it as a variable and
87
+ tries to return the value that's bound to it, which doesn't work when
88
+ it's not bound. So let's see what happens with a symbol that already
89
+ has a value bound to it:</p>
90
+
91
+ <pre class='code'>&gt; +
92
+ #&lt;Proc:0xb7c4b2a8@./bin/../lib/primitives.rb:16&gt;</pre>
93
+
94
+ <p>This is the way Bus Scheme represents a built-in (primitive)
95
+ <b>function</b>. In Scheme, functions are first-class values, so you
96
+ can bind them to variables, like you can with the <tt>lambda</tt>
97
+ keyword in Ruby. But in Scheme this the primary way you refer to
98
+ functions when you want to call them or pass them to other
99
+ functions.</p>
100
+
101
+ <p>Speaking of calling functions, it works something like this:</p>
102
+
103
+ <pre class='code'>&gt; (+ 3 4)
104
+ 7</pre>
105
+
106
+ <p>This is a <b>list</b>, which is Scheme's compound expression. This list is
107
+ made up of three elements, in this case all atoms: the symbol
108
+ <tt>+</tt>, the number 3, and the number 4. In normal contexts, when
109
+ Scheme sees a list it treats it as a function call. First the first
110
+ item in the list is evaluated, which evaluates to a Ruby Proc
111
+ object. Then each of the remaining list elements are evaluated. Since
112
+ they're all literals here, they evaluate to themselves. Then the
113
+ arguments get passed to the function. Behind the scenes, this
114
+ translates rougly into <tt>Proc.new{|*args| args.sum}.call(3,
115
+ 4)</tt>. Let's see something a bit more complicated:</p>
116
+
117
+ <pre class='code'>&gt; (+ (+ 1 2) (+ 3 4))
118
+ 10</pre>
119
+
120
+ <p>In this case, the first <tt>+</tt> gets evaluated, and Bus Scheme sees
121
+ that it's a function. So it looks at its arguments: <tt>(+ 1 2)</tt>
122
+ gets evaluated to 3, and <tt>(+ 3 4)</tt> gets evaluated to 7. Then
123
+ those two arguments get passed to <tt>+</tt> and the result becomes
124
+ the value of the whole expression.
125
+ </p>
126
+
127
+ <p>That's the basics of how program execution happens, but you won't
128
+ get far without having a few more functions under your belt. Here are
129
+ a some to get you rolling:</p>
130
+
131
+ <dl>
132
+ <dt>+, -, *, and /</dt>
133
+ <dd>You've been introduced to + above, but I'm sure you recognize
134
+ your other old friends from grade-school days. + and * support any
135
+ number of arguments, but - and / take two. In regular Scheme these
136
+ all only work for numerical types, but Bus Scheme borrows Ruby's
137
+ methods and lets you pass strings and other objects to + and *.</dd>
138
+
139
+ <dt>&lt;, &gt;, and =</dt>
140
+ <dd>These are comparison functions. They work like they do in any
141
+ language, but in Scheme you invoke them as <tt>(&gt; 3 7)</tt>
142
+ etc. Again, Bus Scheme uses Ruby's underlying methods, so you can
143
+ pass strings and other objects in, unlike in regular Scheme.</dd>
144
+
145
+ <dt>list</dt>
146
+ <dd>If you want a list of numbers, you may think you get this by
147
+ entering <tt>(1 2 3)</tt>. The problem with this is that in normal
148
+ contexts it gets treated like a function call, and it will complain
149
+ that 1 is not a function. What you can do instead is <tt>(list 1 2
150
+ 3)</tt>, which evaluates to (1 2 3).</dd>
151
+
152
+ <dt>map</dt>
153
+ <dd>This works like Ruby's map, but it's a free-standing function
154
+ instead of a method. So instead of <tt>[1, 2, 3].map {|x| x +
155
+ 3}</tt> you would do <tt>(map (lambda (x) (+ x 3)) (list 1 2
156
+ 3)</tt>, which would return <tt>(4 5 6)</tt>.</dd>
157
+
158
+ <dt>substring</dt>
159
+ <dd>Bus Scheme's <tt>(substring \"foobar\" 3 5)</tt> translates into
160
+ <tt>\"foobar\"[3 .. 5]</tt> in Ruby.</dd>
161
+
162
+ <dt>if</dt>
163
+ <dd>The most basic conditional is <tt>if</tt>. Use it like this:
164
+ <tt>(if x \"x is true\" \"x is false\")</tt>. <tt>if</tt> evaluates its
165
+ first argument, which in this case is x. If it evaluates to a true
166
+ value [<a href='#fn3'>3</a>] then its second argument gets evaluated
167
+ and returned. If it's false then the remaining arguments (if any)
168
+ are evaluated and the last one is returned.[<a
169
+ href='#fn4'>4</a>]</dd>
170
+ </dl>
171
+
172
+ <p>Well, that's enough for now. You may not know enough to be
173
+ dangerous, but I hope you know enough to explore. Tune in next time
174
+ when I uncover the true Secrets of Lisp&trade; by explaining
175
+ <tt>cons</tt>, <tt>lambda</tt>, and special forms.</p>
176
+
177
+ <hr />
178
+
179
+ <p><a name='fn1'>1</a> - I didn't say it was a large number.</p>
180
+
181
+ <p><a name='fn2'>2</a> - I imagine this causes <a
182
+ href='http://blog.fallingsnow.net'>Evan</a> and <a
183
+ href='http://headius.blogspot.com/'>Charles</a> some varying amounts
184
+ of distress.</p>
185
+
186
+ <p><a name='fn3'>3</a> - In Scheme every value is true except
187
+ <tt>#f</tt>, which is equivalent to Ruby's <tt>false</tt>.</p>
188
+
189
+ <p><a name='fn4'>4</a> - Observant readers will note that this does
190
+ not follow the evaluation rule for functions given above which states
191
+ that every argument is evaluated before the function is called. This
192
+ is because <tt>if</tt> is not technically a function, but rather a
193
+ <b>special form</b>, and different rules apply for the evaluation of a
194
+ special form's arguments. There's more to this than I can cover in
195
+ this article, but these rules allow for great syntactic
196
+ flexibility.</p>
197
+
198
+ <hr />
199
+
200
+ <p>&copy; 2008 <a href='http://technomancy.us'>Phil
201
+ Hagelberg</a>.</p>
202
+
203
+ </div>
204
+ </body></html>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bus-scheme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.5
4
+ version: 0.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phil Hagelberg
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-01-30 00:00:00 -08:00
12
+ date: 2008-03-16 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -19,9 +19,9 @@ dependencies:
19
19
  requirements:
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 1.4.0
22
+ version: 1.5.1
23
23
  version:
24
- description: Bus Scheme is a Scheme written in Ruby, but implemented on the bus! Every programmer must implement Scheme as a rite of passage; this is mine. Note that all the implementation of Bus Scheme must be written while on a bus. Documentation, tests, and administrivia may be accomplished elsewhere, but all actual implementation code is strictly bus-driven. Patches are welcome as long as they were written while riding a bus. (If your daily commute does not involve a bus but you want to submit a patch, we may be able to work something out regarding code written on trains, ferries, or perhaps even carpool lanes.) Bus Scheme is primarily a toy; using it for anything serious is (right now) ill-advised. Bus Scheme aims for general Scheme usefulness optimized for learning and fun. It's not targeting R5RS or anything like that. == Install * sudo gem install bus-scheme
24
+ description: "Bus Scheme is a Scheme written in Ruby, but implemented on the bus! Every programmer must implement Scheme as a rite of passage; this is mine. Note that at least half of the implementation of Bus Scheme must be written while on a bus. Documentation, tests, and administrivia may be accomplished elsewhere, but the majority of actual implementation code is strictly bus-driven. Bus Scheme is primarily a toy; using it for anything serious is (right now) ill-advised. Bus Scheme aims for general Scheme usefulness optimized for learning and fun. It's loosely targeting R5RS, but varies in huge ways. (For the purposes of this project we pretend that R6RS never happened.) See the file R5RS.diff for ways in which Bus Scheme differs from the standard, both things that are yet unimplemented and things that are intentionally different. == Usage $ bus # drop into the REPL"
25
25
  email: technomancy@gmail.com
26
26
  executables:
27
27
  - bus
@@ -33,9 +33,11 @@ extra_rdoc_files:
33
33
  files:
34
34
  - COPYING
35
35
  - Manifest.txt
36
+ - R5RS.diff
36
37
  - README.txt
37
38
  - Rakefile
38
39
  - bin/bus
40
+ - examples/fib.scm
39
41
  - lib/array_extensions.rb
40
42
  - lib/bus_scheme.rb
41
43
  - lib/cons.rb
@@ -45,15 +47,25 @@ files:
45
47
  - lib/parser.rb
46
48
  - lib/primitives.rb
47
49
  - lib/scheme/core.scm
50
+ - lib/scheme/list.scm
51
+ - lib/scheme/predicates.scm
52
+ - lib/scheme/test.scm
53
+ - lib/stack_frame.rb
48
54
  - test/foo.scm
49
55
  - test/test_core.rb
50
56
  - test/test_eval.rb
51
57
  - test/test_helper.rb
52
58
  - test/test_lambda.rb
59
+ - test/test_list_functions.scm
53
60
  - test/test_parser.rb
61
+ - test/test_predicates.scm
54
62
  - test/test_primitives.rb
63
+ - test/test_primitives.scm
64
+ - test/test_stack_frame.rb
65
+ - test/tracer.scm
66
+ - tutorials/getting_started.html
55
67
  has_rdoc: true
56
- homepage: " by Phil Hagelberg (c) 2007 - 2008"
68
+ homepage: http://bus-scheme.rubyforge.org
57
69
  post_install_message:
58
70
  rdoc_options:
59
71
  - --main
@@ -75,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
87
  requirements: []
76
88
 
77
89
  rubyforge_project: bus-scheme
78
- rubygems_version: 1.0.0
90
+ rubygems_version: 1.0.1
79
91
  signing_key:
80
92
  specification_version: 2
81
93
  summary: Bus Scheme is a Scheme in Ruby, imlemented on the bus.
@@ -84,5 +96,8 @@ test_files:
84
96
  - test/test_core.rb
85
97
  - test/test_primitives.rb
86
98
  - test/test_parser.rb
99
+ - test/test_xml.rb
87
100
  - test/test_eval.rb
101
+ - test/test_web.rb
102
+ - test/test_stack_frame.rb
88
103
  - test/test_helper.rb