swerling-synfeld 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,15 @@
1
+ == 0.0.3 / 2009-09-12
2
+
3
+ * switch from rack-router to rack-mount for routing
4
+
5
+ == 0.0.3 / 2009-09-12
6
+
7
+ * ruby1.9 compat
8
+
9
+ == 0.0.2 / 2009-07-18
10
+
11
+ * Add some static types.
12
+
1
13
  == 0.0.1 / 2009-07-18
2
14
 
3
- * initial release
15
+ * initial releases
@@ -1,57 +1,48 @@
1
- synfeld
1
+ == *Synfeld*
2
2
 
3
3
  by {Steven Swerling}[http://tab-a.slot-z.net]
4
4
 
5
5
  {rdoc}[http://tab-a.slot-z.net] | {github}[http://www.github.com/swerling/synfeld]
6
6
 
7
- == DESCRIPTION:
7
+ == Description
8
8
 
9
9
  Synfeld is a web application framework that does practically nothing.
10
10
 
11
- Basically this is just a tiny wrapper for the Rack::Router (see http://github.com/carllerche/rack-router). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. for help files) and media, Synfeld makes that easy. If you need session variables, a mailer, uploading, etc, look elsewhere.
11
+ Synfeld is little more than a small wrapper for Rack::Mount (see http://github.com/josh/rack-mount). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. help files) and media, Synfeld makes that easy.
12
12
 
13
- The sample app below shows pretty much everything that synfeld can do.
13
+ The sample app below shows pretty much everything there is to know about synfeld, in particular:
14
14
 
15
- Very alpha-ish stuff here. Seems to work though.
15
+ * How to define routes.
16
+ * Simple rendering of erb, haml, html, json, and static files.
17
+ * In the case of erb and haml, passing variables into the template is demonstrated.
18
+ * A dynamic action where the status code, headers, and body are created 'manually' (/my/special/route below)
19
+ * A simple way of creating format sensitive routes (/alphabet.html vs. /alphabet.json)
20
+ * The erb demo link also demos the rendering of a partial (not visible in the code below, you have to look at the template file examples/public/erb_files/erb_test.erb).
16
21
 
17
- == SYNOPSIS:
22
+ == Synopsis/Example
18
23
 
19
24
  Here is an example Synfeld application (foo_app.rb):
20
25
 
26
+ require 'synfeld'
27
+ require 'json'
28
+
21
29
  class FooApp < Synfeld::App
22
30
 
23
- def initialize
24
- super(:root_dir => File.expand_path(File.join(File.dirname(__FILE__), 'public')),
25
- :logger => Logger.new(STDOUT))
26
- end
27
-
28
- def router
29
- return @router ||= Rack::Router.new(nil, {}) do |r|
30
- r.map "/yap/:yap_variable", :get, :to => self, :with => { :action => "yap" }
31
- r.map "/my/special/route", :get, :to => self, :with => { :action => "my_special_route" }
32
- r.map "/html_test", :get, :to => self, :with => { :action => "html_test" }
33
- r.map "/haml_test", :get, :to => self, :with => { :action => "haml_test" }
34
- r.map "/erb_test", :get, :to => self, :with => { :action => "erb_test" }
35
-
36
- # These next 2 have to come last
37
- r.map "/:anything_else", :get, :to => self, :with => { :action => "handle_static" }
38
- r.map "/", :get, :to => self, :with => { :action => "home" }
39
- end
31
+ def add_routes
32
+ add_route "/yap/:yap_variable", :action => "yap"
33
+ add_route "/html_test", :action => "html_test"
34
+ add_route "/haml_test", :action => "haml_test"
35
+ add_route "/erb_test", :action => "erb_test"
36
+ add_route '/alphabet.:format', :action => "alphabet"
37
+ add_route "/my/special/route", :action => "my_special_route",
38
+ :extra_parm1 => 'really',
39
+ :extra_parm2 => 'truly'
40
+ add_route '/', :action => "home"
40
41
  end
41
42
 
42
43
  # files are looked up relative to the root directory specified in initialize
43
44
  def home
44
- serve('haml_files/home.haml')
45
- end
46
-
47
- def my_special_route
48
- self.response[:status_code] = 200
49
- self.response[:headers]['Content-Type'] = 'text/html'
50
- self.response[:body] = <<-HTML
51
- <html>
52
- <body>I'm <i>special</i>.</body>
53
- </html>
54
- HTML
45
+ render_haml('haml_files/home.haml')
55
46
  end
56
47
 
57
48
  def yap
@@ -59,40 +50,82 @@ Here is an example Synfeld application (foo_app.rb):
59
50
  end
60
51
 
61
52
  def html_test
62
- serve('html_files/html_test.html')
53
+ render_html('html_files/html_test.html')
63
54
  end
64
55
 
65
56
  def haml_test
66
- serve('haml_files/haml_test.haml', {:ran100 => Kernel.rand(100) + 1, :time => Time.now})
57
+ render_haml('haml_files/haml_test.haml', :ran100 => Kernel.rand(100) + 1, :time => Time.now)
67
58
  end
68
59
 
69
60
  def erb_test
70
- serve('erb_files/erb_test.erb', {:ran100 => Kernel.rand(100) + 1, :time => Time.now})
61
+ render_erb('erb_files/erb_test.erb', :ran100 => Kernel.rand(100) + 1, :time => Time.now)
71
62
  end
72
63
 
64
+ def alphabet
65
+ alphabet = ('a'..'z').collect{|ch|ch}
66
+ case params[:format]
67
+ when 'html'
68
+ return "<html><body>#{alphabet.join("<br/>")}</body></html>"
69
+ when 'json'
70
+ hash = {:desc => 'here is the alphabet', :alphabet => alphabet}
71
+ render_json hash.to_json
72
+ else
73
+ raise "Format not recognized: #{params[:format]}"
74
+ end
75
+ end
73
76
 
77
+ def my_special_route
78
+ self.response[:status_code] = 200
79
+ self.response[:headers]['Content-Type'] = 'text/html'
80
+ self.response[:body] = <<-HTML
81
+ <html>
82
+ <body>I'm <i>special</i>,
83
+ #{self.params[:extra_parm1]} and #{self.params[:extra_parm2]}</body>
84
+ </html>
85
+ HTML
86
+ end
74
87
  end
75
88
 
76
89
  And here is an example rack config, foo_app.ru:
77
90
 
78
91
  require '/path/to/foo_app.rb'
79
- run FooApp.new.as_rack_app
92
+ use Rack::CommonLogger, logger = Logger.new('/tmp/synfeld.log')
93
+ foo_app = FooApp.new( :logger => logger, :root_dir => '/path/to/root/dir' )
94
+ run foo_app.as_rack_app
80
95
 
81
96
  Run FooApp w/ rackup or shotgun:
82
97
 
83
- rackup --server=thin foo.ru -p 3000
98
+ rackup foo_app.ru -p 3000
84
99
 
85
100
  or
86
101
 
87
- shotgun --server=thin foo.ru -p 3000
102
+ shotgun foo_app.ru -p 3000
103
+
104
+ == Features
105
+
106
+ ==== The Router
107
+
108
+ When a Synfeld application starts up, it will call your app's 'add_routes' method, where you have to create your routes using the #add_route method. Example calls to add_route:
109
+
110
+ 1. add_route %r{/some/path/(?:<somevar>.*)}, :action => "haml_test"
111
+ 2. add_route "/some/otherpath/:somevar", :action => "haml_test"
112
+ 3. add_route "/yet/anotherpath/:var", :action => "haml_test", :method => 'post', :furthermore => 'art is dead'
88
113
 
89
- == FEATURES
114
+ * At minimum, you have to provide the route and the :action to #add_route.
115
+ * When a route is passed as a regex (the 1st add_route line above), it is passed straight through to rackmount as is, so rackmount's rules apply.
116
+ * When using the convenience notation of the second add_route line above, the '/some/path/:somevar' is converted to a rackmount regex route under the covers, and :somevar will be passed to your app as a param (this is shown in the example code's #yap and #my_special_route methods).
117
+ * The 3rd add_route example shows how you can set any additional parameters on the route by adding associations onto the end of the route (this is also shown in #my_special_route in the example application above).
118
+ * If you happen to have a parameter called ':method', it will determine the request method required for the route (eg. 'get', 'put', 'post'). If the :method is not passed in, 'get' is assumed.
119
+
120
+ Note that rack-mount is an evolving project, so the examples above may have to be tweaked a bit in the future.
121
+
122
+ ==== The Response
90
123
 
91
124
  When a Synfeld application handles a rack request, it
92
125
 
93
- 1. Duplicates self (so it's thread safe)
94
- 2. Sets @response, @params, @env (the rack env)
95
- 3. Calls the action that Rack::Router route that matched. If the action returns a String, that is used for the @response[:body]
126
+ 1. Duplicates itself (so it's thread safe)
127
+ 2. Sets @response, @params, @env (@env is just the rack env)
128
+ 3. Calls the action that the route that matched.
96
129
 
97
130
  The @response is a hash used to return the rack status code, headers hash, and body. Actions may do what they please with the response. Default response:
98
131
 
@@ -103,47 +136,52 @@ The @response is a hash used to return the rack status code, headers hash, and b
103
136
  }
104
137
 
105
138
 
106
- Actions are expected to side-effect the :status_code, :headers, and :body if the defaults are not appropriate. As a convenience, if an action returns a string, it is assumed that that string is the :body. An exception is thrown if the :body is not set to something.
107
-
108
- As the example app above shows, you can "serve" templated content in the form of 'haml' or 'erb' files.
139
+ Actions are expected to side-effect the :status_code, :headers, and :body if the defaults are not appropriate. As a convenience, if an action returns a string, it is assumed that that string is to be used as the response[:body]. An exception is thrown if the :body is not set to something. The 'Content-Length' header will be derived from the body's size.
109
140
 
110
- Requests are bound to the first matching route. The 'handle_static' action considers the request path to be a path to a file relative to the 'root_dir' specified in initialize (see example app below).
141
+ As the example app above shows, you can serve templated content in the form of 'haml' or 'erb' files (the #erb_test and #haml_test methods in the code above).
111
142
 
112
- Can currenty serve up the following types of static files:
143
+ Synfeld can currenty serve up the following types of static files:
113
144
 
114
145
  js, css, png, gif, jpg, jpeg, html
115
146
 
116
- Can currently render the following dynamic content:
147
+ Synfeld can currently render the following dynamic content:
148
+
149
+ erb, haml, json
150
+
151
+ Additional file types can be added upon request. Or you can just look at the synfeld code, which is tiny, then roll your own render method.
117
152
 
118
- erb, haml
153
+ You can pass local variables to erb and haml.
119
154
 
120
- Synfeld does not do partials, but you can set local variables for dynamic content.
155
+ Rendering 'partials' is trivial and is demonstrated in the included sample application file examples/public/erb_files/erb_test.erb.
121
156
 
122
- That's it. Really not much to see here. Just gives you a thread-safe rack-based web framework that consists of little more than a router.
157
+ ==== That's It
123
158
 
124
- == PROBLEMS
159
+ Synfeld just gives you a thread-safe rack-based web framework that consists of just a little more than a router. There's really not much to see. If you want caching, security, session access, etc, it is assumed you will add those as Rack middleware.
160
+
161
+ == Problems
125
162
 
126
163
  None known.
127
164
 
128
- == REQUIREMENTS:
165
+ == Requirements
129
166
 
167
+ * ruby (either 1.8.X or 1.9.X)
130
168
  * ruby, rubygems, rack, rack-router
131
169
  * For rack-router, see http://github.com/carllerche/rack-router
132
170
 
133
- == INSTALL:
134
-
135
- First install rack and rack-router.
136
-
137
- There's no gem for rack-router at the moment,
138
- to you will have to clone it and build it yourself.
139
-
140
- Then:
171
+ == Install
172
+
173
+ 1. [install rack if necessary]
174
+ 2. gem install josh-rack-mount --source=http://gems.github.com
175
+ 3. gem install swerling-synfeld --source http://gems.github.com
141
176
 
142
- gem install swerling-synfeld --source http://gems.github.com
177
+ (note: I noticed sometimes josh-rack-mount will complain about rack version
178
+ not being high enough, even if you are already on version 1.0.0. If that happens,
179
+ you have to clone the rack-mount repo locally and just build the rack-mount gem
180
+ yourself)
143
181
 
144
- == LICENSE:
182
+ == License
145
183
 
146
- (The MIT License)
184
+ (the MIT License)
147
185
 
148
186
  Copyright (c) 2009 Steven Swerling
149
187
 
@@ -165,3 +203,4 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
165
203
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
166
204
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
167
205
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
206
+
data/README.txt CHANGED
@@ -1,57 +1,48 @@
1
- synfeld
1
+ == *Synfeld*
2
2
 
3
3
  by {Steven Swerling}[http://tab-a.slot-z.net]
4
4
 
5
5
  {rdoc}[http://tab-a.slot-z.net] | {github}[http://www.github.com/swerling/synfeld]
6
6
 
7
- == DESCRIPTION:
7
+ == Description
8
8
 
9
9
  Synfeld is a web application framework that does practically nothing.
10
10
 
11
- Basically this is just a tiny wrapper for the Rack::Router (see http://github.com/carllerche/rack-router). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. for help files) and media, Synfeld makes that easy. If you need session variables, a mailer, uploading, etc, look elsewhere.
11
+ Synfeld is little more than a small wrapper for Rack::Mount (see http://github.com/josh/rack-mount). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. help files) and media, Synfeld makes that easy.
12
12
 
13
- The sample app below shows pretty much everything that synfeld can do.
13
+ The sample app below shows pretty much everything there is to know about synfeld, in particular:
14
14
 
15
- Very alpha-ish stuff here. Seems to work though.
15
+ * How to define routes.
16
+ * Simple rendering of erb, haml, html, json, and static files.
17
+ * In the case of erb and haml, passing variables into the template is demonstrated.
18
+ * A dynamic action where the status code, headers, and body are created 'manually' (/my/special/route below)
19
+ * A simple way of creating format sensitive routes (/alphabet.html vs. /alphabet.json)
20
+ * The erb demo link also demos the rendering of a partial (not visible in the code below, you have to look at the template file examples/public/erb_files/erb_test.erb).
16
21
 
17
- == SYNOPSIS:
22
+ == Synopsis/Example
18
23
 
19
24
  Here is an example Synfeld application (foo_app.rb):
20
25
 
26
+ require 'synfeld'
27
+ require 'json'
28
+
21
29
  class FooApp < Synfeld::App
22
30
 
23
- def initialize
24
- super(:root_dir => File.expand_path(File.join(File.dirname(__FILE__), 'public')),
25
- :logger => Logger.new(STDOUT))
26
- end
27
-
28
- def router
29
- return @router ||= Rack::Router.new(nil, {}) do |r|
30
- r.map "/yap/:yap_variable", :get, :to => self, :with => { :action => "yap" }
31
- r.map "/my/special/route", :get, :to => self, :with => { :action => "my_special_route" }
32
- r.map "/html_test", :get, :to => self, :with => { :action => "html_test" }
33
- r.map "/haml_test", :get, :to => self, :with => { :action => "haml_test" }
34
- r.map "/erb_test", :get, :to => self, :with => { :action => "erb_test" }
35
-
36
- # These next 2 have to come last
37
- r.map "/:anything_else", :get, :to => self, :with => { :action => "handle_static" }
38
- r.map "/", :get, :to => self, :with => { :action => "home" }
39
- end
31
+ def add_routes
32
+ add_route "/yap/:yap_variable", :action => "yap"
33
+ add_route "/html_test", :action => "html_test"
34
+ add_route "/haml_test", :action => "haml_test"
35
+ add_route "/erb_test", :action => "erb_test"
36
+ add_route '/alphabet.:format', :action => "alphabet"
37
+ add_route "/my/special/route", :action => "my_special_route",
38
+ :extra_parm1 => 'really',
39
+ :extra_parm2 => 'truly'
40
+ add_route '/', :action => "home"
40
41
  end
41
42
 
42
43
  # files are looked up relative to the root directory specified in initialize
43
44
  def home
44
- serve('haml_files/home.haml')
45
- end
46
-
47
- def my_special_route
48
- self.response[:status_code] = 200
49
- self.response[:headers]['Content-Type'] = 'text/html'
50
- self.response[:body] = <<-HTML
51
- <html>
52
- <body>I'm <i>special</i>.</body>
53
- </html>
54
- HTML
45
+ render_haml('haml_files/home.haml')
55
46
  end
56
47
 
57
48
  def yap
@@ -59,40 +50,82 @@ Here is an example Synfeld application (foo_app.rb):
59
50
  end
60
51
 
61
52
  def html_test
62
- serve('html_files/html_test.html')
53
+ render_html('html_files/html_test.html')
63
54
  end
64
55
 
65
56
  def haml_test
66
- serve('haml_files/haml_test.haml', {:ran100 => Kernel.rand(100) + 1, :time => Time.now})
57
+ render_haml('haml_files/haml_test.haml', :ran100 => Kernel.rand(100) + 1, :time => Time.now)
67
58
  end
68
59
 
69
60
  def erb_test
70
- serve('erb_files/erb_test.erb', {:ran100 => Kernel.rand(100) + 1, :time => Time.now})
61
+ render_erb('erb_files/erb_test.erb', :ran100 => Kernel.rand(100) + 1, :time => Time.now)
71
62
  end
72
63
 
64
+ def alphabet
65
+ alphabet = ('a'..'z').collect{|ch|ch}
66
+ case params[:format]
67
+ when 'html'
68
+ return "<html><body>#{alphabet.join("<br/>")}</body></html>"
69
+ when 'json'
70
+ hash = {:desc => 'here is the alphabet', :alphabet => alphabet}
71
+ render_json hash.to_json
72
+ else
73
+ raise "Format not recognized: #{params[:format]}"
74
+ end
75
+ end
73
76
 
77
+ def my_special_route
78
+ self.response[:status_code] = 200
79
+ self.response[:headers]['Content-Type'] = 'text/html'
80
+ self.response[:body] = <<-HTML
81
+ <html>
82
+ <body>I'm <i>special</i>,
83
+ #{self.params[:extra_parm1]} and #{self.params[:extra_parm2]}</body>
84
+ </html>
85
+ HTML
86
+ end
74
87
  end
75
88
 
76
89
  And here is an example rack config, foo_app.ru:
77
90
 
78
91
  require '/path/to/foo_app.rb'
79
- run FooApp.new.as_rack_app
92
+ use Rack::CommonLogger, logger = Logger.new('/tmp/synfeld.log')
93
+ foo_app = FooApp.new( :logger => logger, :root_dir => '/path/to/root/dir' )
94
+ run foo_app.as_rack_app
80
95
 
81
96
  Run FooApp w/ rackup or shotgun:
82
97
 
83
- rackup --server=thin foo.ru -p 3000
98
+ rackup foo_app.ru -p 3000
84
99
 
85
100
  or
86
101
 
87
- shotgun --server=thin foo.ru -p 3000
102
+ shotgun foo_app.ru -p 3000
103
+
104
+ == Features
105
+
106
+ ==== The Router
107
+
108
+ When a Synfeld application starts up, it will call your app's 'add_routes' method, where you have to create your routes using the #add_route method. Example calls to add_route:
109
+
110
+ 1. add_route %r{/some/path/(?:<somevar>.*)}, :action => "haml_test"
111
+ 2. add_route "/some/otherpath/:somevar", :action => "haml_test"
112
+ 3. add_route "/yet/anotherpath/:var", :action => "haml_test", :method => 'post', :furthermore => 'art is dead'
88
113
 
89
- == FEATURES
114
+ * At minimum, you have to provide the route and the :action to #add_route.
115
+ * When a route is passed as a regex (the 1st add_route line above), it is passed straight through to rackmount as is, so rackmount's rules apply.
116
+ * When using the convenience notation of the second add_route line above, the '/some/path/:somevar' is converted to a rackmount regex route under the covers, and :somevar will be passed to your app as a param (this is shown in the example code's #yap and #my_special_route methods).
117
+ * The 3rd add_route example shows how you can set any additional parameters on the route by adding associations onto the end of the route (this is also shown in #my_special_route in the example application above).
118
+ * If you happen to have a parameter called ':method', it will determine the request method required for the route (eg. 'get', 'put', 'post'). If the :method is not passed in, 'get' is assumed.
119
+
120
+ Note that rack-mount is an evolving project, so the examples above may have to be tweaked a bit in the future.
121
+
122
+ ==== The Response
90
123
 
91
124
  When a Synfeld application handles a rack request, it
92
125
 
93
- 1. Duplicates self (so it's thread safe)
94
- 2. Sets @response, @params, @env (the rack env)
95
- 3. Calls the action that Rack::Router route that matched. If the action returns a String, that is used for the @response[:body]
126
+ 1. Duplicates itself (so it's thread safe)
127
+ 2. Sets @response, @params, @env (@env is just the rack env)
128
+ 3. Calls the action that the route that matched.
96
129
 
97
130
  The @response is a hash used to return the rack status code, headers hash, and body. Actions may do what they please with the response. Default response:
98
131
 
@@ -103,47 +136,52 @@ The @response is a hash used to return the rack status code, headers hash, and b
103
136
  }
104
137
 
105
138
 
106
- Actions are expected to side-effect the :status_code, :headers, and :body if the defaults are not appropriate. As a convenience, if an action returns a string, it is assumed that that string is the :body. An exception is thrown if the :body is not set to something.
107
-
108
- As the example app above shows, you can "serve" templated content in the form of 'haml' or 'erb' files.
139
+ Actions are expected to side-effect the :status_code, :headers, and :body if the defaults are not appropriate. As a convenience, if an action returns a string, it is assumed that that string is to be used as the response[:body]. An exception is thrown if the :body is not set to something. The 'Content-Length' header will be derived from the body's size.
109
140
 
110
- Requests are bound to the first matching route. The 'handle_static' action considers the request path to be a path to a file relative to the 'root_dir' specified in initialize (see example app below).
141
+ As the example app above shows, you can serve templated content in the form of 'haml' or 'erb' files (the #erb_test and #haml_test methods in the code above).
111
142
 
112
- Can currenty serve up the following types of static files:
143
+ Synfeld can currenty serve up the following types of static files:
113
144
 
114
145
  js, css, png, gif, jpg, jpeg, html
115
146
 
116
- Can currently render the following dynamic content:
147
+ Synfeld can currently render the following dynamic content:
148
+
149
+ erb, haml, json
150
+
151
+ Additional file types can be added upon request. Or you can just look at the synfeld code, which is tiny, then roll your own render method.
117
152
 
118
- erb, haml
153
+ You can pass local variables to erb and haml.
119
154
 
120
- Synfeld does not do partials, but you can set local variables for dynamic content.
155
+ Rendering 'partials' is trivial and is demonstrated in the included sample application file examples/public/erb_files/erb_test.erb.
121
156
 
122
- That's it. Really not much to see here. Just gives you a thread-safe rack-based web framework that consists of little more than a router.
157
+ ==== That's It
123
158
 
124
- == PROBLEMS
159
+ Synfeld just gives you a thread-safe rack-based web framework that consists of just a little more than a router. There's really not much to see. If you want caching, security, session access, etc, it is assumed you will add those as Rack middleware.
160
+
161
+ == Problems
125
162
 
126
163
  None known.
127
164
 
128
- == REQUIREMENTS:
165
+ == Requirements
129
166
 
167
+ * ruby (either 1.8.X or 1.9.X)
130
168
  * ruby, rubygems, rack, rack-router
131
169
  * For rack-router, see http://github.com/carllerche/rack-router
132
170
 
133
- == INSTALL:
134
-
135
- First install rack and rack-router.
136
-
137
- There's no gem for rack-router at the moment,
138
- to you will have to clone it and build it yourself.
139
-
140
- Then:
171
+ == Install
172
+
173
+ 1. [install rack if necessary]
174
+ 2. gem install josh-rack-mount --source=http://gems.github.com
175
+ 3. gem install swerling-synfeld --source http://gems.github.com
141
176
 
142
- gem install swerling-synfeld --source http://gems.github.com
177
+ (note: I noticed sometimes josh-rack-mount will complain about rack version
178
+ not being high enough, even if you are already on version 1.0.0. If that happens,
179
+ you have to clone the rack-mount repo locally and just build the rack-mount gem
180
+ yourself)
143
181
 
144
- == LICENSE:
182
+ == License
145
183
 
146
- (The MIT License)
184
+ (the MIT License)
147
185
 
148
186
  Copyright (c) 2009 Steven Swerling
149
187
 
@@ -165,3 +203,4 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
165
203
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
166
204
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
167
205
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
206
+
data/Rakefile CHANGED
@@ -48,13 +48,21 @@ task :myclobber => [:clobber] do
48
48
  sh "rm -rf #{File.join(mydir, 'ext/*.so')}"
49
49
  sh "rm -rf #{File.join(mydir, 'ext/Makefile')}"
50
50
  sh "rm -rf #{File.join(mydir, 'ext/Makefile')}"
51
+ sh "cp #{File.join(mydir, 'README.rdoc')} #{File.join(mydir, 'README.txt')}" # concession to bones
51
52
  end
52
53
  task :mypackage => [:myclobber] do
53
54
  Rake::Task['gem:package'].invoke
54
55
  end
55
56
  task :mydoc => [:myclobber] do
56
57
  FileUtils.rm_f doc_dir()
57
- sh "cd #{this_dir()} && rdoc -o rdoc --inline-source --format=html -T hanna README.rdoc lib/**/*.rb"
58
+ #sh "cd #{this_dir()} && rdoc -o rdoc --inline-source --format=html -T hanna README.rdoc lib/**/*.rb"
59
+ this_dir = File.dirname(__FILE__) + '/'
60
+ files = []
61
+ files += Dir[File.join(this_dir, 'lib/**/*.rb')].map{|fn| fn.gsub(this_dir,'')}
62
+ files += Dir[File.join(this_dir, 'example/**/*.*')].map{|fn| fn.gsub(this_dir,'')}
63
+ files += ['README.rdoc']
64
+ files = files.reject{|fn| fn =~ /jpg/ }.sort
65
+ sh "cd #{this_dir()} && rdoc -o rdoc --inline-source #{files.flatten.join(" ")}"
58
66
  end
59
67
  task :taba => [:mydoc] do
60
68
  this_dir = File.join(File.dirname(__FILE__))
data/TODO CHANGED
@@ -1,2 +1 @@
1
- Try using USHER as the router
2
- http://github.com/joshbuddy/usher/tree/master
1
+ Create a sourceforge gem and move all the docs over there from slot-z.com.
@@ -3,8 +3,14 @@
3
3
  <div>
4
4
  <h3> Here is an erb test</h3>
5
5
  Here is the time: <%= time %>
6
- <br/>ran100: <%= ran100 %>
6
+ <br/>ran100: <%= ran100 %> (local variable passed in)
7
7
  <br/><a href="/">home</a>
8
+ <br/>
9
+ <br/>
10
+ Here is the home page rendered as a partial:
11
+ <div style="margin-left: 50px">
12
+ <%= render_haml('haml_files/home.haml') %>
13
+ </div>
8
14
  </div>
9
15
  </body>
10
16
  </html>
@@ -11,5 +11,9 @@
11
11
  %li
12
12
  %a{:href => '/html_test'} test an html file
13
13
  %li
14
- %a{:href => '/my/special/route'} test of non-static action ('my_special_route')
14
+ %a{:href => '/my/special/route'} test of non-static action
15
+ %li
16
+ %a{:href => '/alphabet.json'} alphabet as json
17
+ %li
18
+ %a{:href => '/alphabet.html'} alphabet as html
15
19
 
@@ -6,6 +6,7 @@
6
6
  <h3>Not much to see here</h3>
7
7
  Just testing render of a html file.
8
8
  <a href='http://www.github.com/swerling/synfeld'>synfeld on github</a>
9
+ <br/>Serve up a static: <a href='http://www.achewood.com/'> <img src='images/beef_interstellar_thm.jpg'/> </a>
9
10
  </p>
10
11
 
11
12
  </body>
@@ -1,39 +1,24 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '../lib/synfeld.rb'))
2
+ require 'json'
2
3
 
4
+ # This is the sample Synfeld::App described in the README.rdoc
3
5
  class TryMe < Synfeld::App
4
6
 
5
- def initialize
6
- super(:root_dir => File.expand_path(File.join(File.dirname(__FILE__), 'public')),
7
- :logger => Logger.new(STDOUT))
8
- end
9
-
10
- def router
11
- return @router ||= Rack::Router.new(nil, {}) do |r|
12
- r.map "/yap/:yap_variable", :get, :to => self, :with => { :action => "yap" }
13
- r.map "/my/special/route", :get, :to => self, :with => { :action => "my_special_route" }
14
- r.map "/html_test", :get, :to => self, :with => { :action => "html_test" }
15
- r.map "/haml_test", :get, :to => self, :with => { :action => "haml_test" }
16
- r.map "/erb_test", :get, :to => self, :with => { :action => "erb_test" }
17
-
18
- # These next 2 have to come last
19
- r.map "/:anything_else", :get, :to => self, :with => { :action => "handle_static" }
20
- r.map "/", :get, :to => self, :with => { :action => "home" }
21
- end
7
+ def add_routes
8
+ add_route "/yap/:yap_variable", :action => "yap"
9
+ add_route "/html_test", :action => "html_test"
10
+ add_route "/haml_test", :action => "haml_test"
11
+ add_route "/erb_test", :action => "erb_test"
12
+ add_route '/alphabet.:format', :action => "alphabet"
13
+ add_route "/my/special/route", :action => "my_special_route",
14
+ :extra_parm1 => 'really',
15
+ :extra_parm2 => 'truly'
16
+ add_route '/', :action => "home"
22
17
  end
23
18
 
24
19
  # files are looked up relative to the root directory specified in initialize
25
20
  def home
26
- serve('haml_files/home.haml')
27
- end
28
-
29
- def my_special_route
30
- self.response[:status_code] = 200
31
- self.response[:headers]['Content-Type'] = 'text/html'
32
- self.response[:body] = <<-HTML
33
- <html>
34
- <body>I'm <i>special</i>.</body>
35
- </html>
36
- HTML
21
+ render_haml('haml_files/home.haml')
37
22
  end
38
23
 
39
24
  def yap
@@ -41,17 +26,40 @@ class TryMe < Synfeld::App
41
26
  end
42
27
 
43
28
  def html_test
44
- serve('html_files/html_test.html')
29
+ render_html('html_files/html_test.html')
45
30
  end
46
31
 
47
32
  def haml_test
48
- serve('haml_files/haml_test.haml', {:ran100 => Kernel.rand(100) + 1, :time => Time.now})
33
+ render_haml('haml_files/haml_test.haml', :ran100 => Kernel.rand(100) + 1, :time => Time.now)
49
34
  end
50
35
 
51
36
  def erb_test
52
- serve('erb_files/erb_test.erb', {:ran100 => Kernel.rand(100) + 1, :time => Time.now})
37
+ render_erb('erb_files/erb_test.erb', :ran100 => Kernel.rand(100) + 1, :time => Time.now)
38
+ end
39
+
40
+ def alphabet
41
+ alphabet = ('a'..'z').collect{|ch|ch}
42
+ case params[:format]
43
+ when 'html'
44
+ return "<html><body>#{alphabet.join("<br/>")}</body></html>"
45
+ when 'json'
46
+ hash = {:desc => 'here is the alphabet', :alphabet => alphabet}
47
+ render_json hash.to_json
48
+ else
49
+ raise "Format not recognized: #{params[:format]}"
50
+ end
53
51
  end
54
52
 
53
+ def my_special_route
54
+ self.response[:status_code] = 200
55
+ self.response[:headers]['Content-Type'] = 'text/html'
56
+ self.response[:body] = <<-HTML
57
+ <html>
58
+ <body>I'm <i>special</i>,
59
+ #{self.params[:extra_parm1]} and #{self.params[:extra_parm2]}</body>
60
+ </html>
61
+ HTML
62
+ end
55
63
 
56
64
  end
57
65
 
@@ -1,2 +1,5 @@
1
- require File.join(File.dirname(__FILE__),'try_me.rb')
2
- run TryMe.new.as_rack_app
1
+ require ::File.join(::File.dirname(__FILE__),'try_me.rb')
2
+ use Rack::CommonLogger, logger = Logger.new('/tmp/synfeld.log')
3
+ try_me = TryMe.new( :logger => logger,
4
+ :root_dir => ::File.expand_path(::File.join(::File.dirname(__FILE__), 'public')))
5
+ run try_me.as_rack_app
@@ -1,13 +1,17 @@
1
+ F = ::File
2
+
1
3
  # base ruby requires
4
+ require 'rubygems'
2
5
  require 'logger'
3
6
 
4
7
  # gems dependencies
5
8
  require 'rubygems'
6
9
 
7
10
  require 'rack'
8
- require 'rack/router'
11
+ require 'rack/mount'
12
+ require 'rack/mime'
9
13
 
10
14
  # my files (require_all_libs_relative_to is a bones util method in synfeld_info.rb)
11
- require File.join(File.dirname(__FILE__), 'synfeld_info')
15
+ require F.join(File.dirname(__FILE__), 'synfeld_info')
12
16
  Synfeld.require_all_libs_relative_to(__FILE__)
13
17
 
@@ -1,9 +1,10 @@
1
- module Synfeld
1
+ module Synfeld # :nodoc:
2
2
 
3
3
  #
4
- # See the synopsis section of README.txt for usage.
4
+ # See the synopsis section of README.rdoc for usage.
5
5
  #
6
- # See the RackRouter project for the kinds of routes you can setup.
6
+ # See the README.rdoc for an overview of an Synfeld::App, and see the Rack::Mount project for
7
+ # more information on Rack::Mount style routing.
7
8
  #
8
9
  # Variables of note:
9
10
  #
@@ -16,7 +17,13 @@ module Synfeld
16
17
  # The rack env passed into this apps #call method
17
18
  #
18
19
  # @params
19
- # The params that the matching Rack::Router route set.
20
+ # The params as determined by the matching Rack::Mount route.
21
+ #
22
+ # @root_dir
23
+ # This dir is prepended to relative paths to locate files.
24
+ #
25
+ # @logger
26
+ # Either you pass in the @logger that synfeld uses, or it sets one up on STDOUT.
20
27
  #
21
28
  class App
22
29
  attr_accessor :response, :params, :env, :root_dir, :logger
@@ -26,22 +33,37 @@ module Synfeld
26
33
  # Note this is not the same thing as the rack access log (although you
27
34
  # can pass that logger in if you want). Default: Logger.new(STDOUT)
28
35
  def initialize(opts = {})
29
- @logger = opts[:logger] || Logger.new(STDOUT)
36
+
37
+ @logger = opts[:logger]
38
+ if self.logger.nil?
39
+ @logger = Logger.new(STDOUT)
40
+ puts "WARNING: Synfeld not configured with a logger, using STDOUT. Won't have much to say if running as a daemon."
41
+ end
42
+
30
43
  @root_dir = opts[:root_dir]
31
- raise "You have to pass in the location of the 'root_dir', where all the files in your synfeld app are located" if self.root_dir.nil?
32
- #Haml::Template.options[:format] = :html5
44
+ if self.root_dir.nil?
45
+ raise "You have to pass in the location of the 'root_dir', where all the files in your synfeld app are located"
46
+ end
47
+
48
+ Kernel.at_exit {self.whine("Alright, I'm outta here.")}
33
49
  end
34
50
 
35
- # the router for this Synfeld::App. Subclasses are _required_ to override this.
36
- # (see README.txt for example usage)
37
- def router
38
- raise "#{self.class} must implement a 'router' method that returns a Rack::Router"
39
- end
51
+ #
52
+ # RACK PLUMBING
53
+ #
40
54
 
41
- # Alias for #router
55
+ # Return self as a rackup-able rack application.
42
56
  def as_rack_app
43
- self.router
44
- # TODO: add the no_route handler here. But waiting for rack-router to settle this issue.
57
+ routes = Rack::Mount::RouteSet.new_without_optimizations do |set|
58
+ @set = set
59
+ self.add_routes
60
+ add_route %r{^.*$}, :action => "render_static"
61
+ end
62
+ app = Rack::Builder.new {
63
+ #use Rack::CommonLogger, $stderr
64
+ #use Rack::Reloader, 0
65
+ run routes
66
+ }.to_app
45
67
  end
46
68
 
47
69
  # The rack #call method
@@ -50,48 +72,85 @@ module Synfeld
50
72
  end
51
73
 
52
74
  #
53
- # Misc Sugar
75
+ # ROUTING
54
76
  #
55
77
 
56
- # The name of the action method, determined by the Route that Rack::Router bound to the incoming request
57
- def action
58
- self.params[:action]
78
+ @@__regex_colon = (RUBY_VERSION =~ /^1.8/)? ':' : '' # :nodoc:
79
+
80
+ # See the README for a full explanation of how to use this method.
81
+ def add_route(string_or_regex, opts = {})
82
+ raise "You have to provide an :action method to call" unless opts[:action]
83
+ method = (opts.delete(:method) || 'GET').to_s.upcase
84
+ # Adapt string_or_regex into a rack-mount regex route. If it is a string, convert it to a
85
+ # rack-mount compatable regex. In paths that look like /some/:var/in/path, convert the ':var'
86
+ # bits to rack-mount variables.
87
+ if string_or_regex.is_a?(String)
88
+ regex_string = "^" + string_or_regex.gsub(/:(([^\/]+))/){|s| "(?#{@@__regex_colon}<#{$1}>.*)" } + "$"
89
+ regex = %r{#{regex_string}}
90
+ #puts regex_string # dbg
91
+ else
92
+ regex = string_or_regex
93
+ end
94
+
95
+ # Add the route to rack-mount
96
+ @set.add_route(self,
97
+ {:path_info => regex, :request_method => method.upcase},
98
+ opts)
59
99
  end
60
100
 
61
- # Overridable method that handles missing action that was defined by a route
62
- def theres_no_action
63
- self.response[:body] = "Action '#{self.action}' not found in '#{self.class}'"
64
- self.response[:status_code] = 500
101
+ #
102
+ # ACCESSORS & SUGAR
103
+ #
104
+
105
+ # The name of the action method bound to the route that mathed the incoming request.
106
+ def action
107
+ self.params[:action]
65
108
  end
66
109
 
67
110
  protected
68
111
 
69
- # :stopdoc:
70
-
71
- def _call(env)
72
- start_time = Time.now.to_f
112
+ def _call(env) # :nodoc:
113
+ begin
114
+ start_time = Time.now.to_f
115
+ @env = env
116
+ @params = env[ Rack::Mount::Const::RACK_ROUTING_ARGS ]
117
+ @response = {
118
+ :status_code => 200,
119
+ :headers => {'Content-Type' => 'text/html'},
120
+ :body => nil
121
+ }
122
+
123
+ action = self.action
124
+ if self.respond_to?(action)
125
+ result = self.send(self.action)
126
+ else
127
+ result = self.no_action
128
+ end
129
+
130
+ if result.is_a?(String)
131
+ response[:body] = result
132
+ else
133
+ raise "You have to set the response body" if response[:body].nil?
134
+ end
73
135
 
74
- @env = env
75
- @params = env['rack_router.params']
76
- @response = {
77
- :status_code => 200,
78
- :headers => {'Content-Type' => 'text/html'},
79
- :body => nil
80
- }
136
+ response[:headers]["Content-Length"] = response[:body].size.to_s
81
137
 
82
- action = self.action
83
- if self.respond_to?(action)
84
- body = self.send(self.action)
85
- else
86
- body = theres_no_action
138
+ logger.debug("It took #{Time.now.to_f - start_time} sec for #{self.class} to handle request.")
139
+ [response[:status_code], response[:headers], Array(response[:body])]
140
+ rescue Exception => e
141
+ # It seems like we should get this next line for free from the CommonLogger, so I guess
142
+ # I'm doing something wrong, missing some piece of rack middleware or something. Until I
143
+ # figure it out, I'm explicitly logging the exception manually.
144
+ self.whine "#{e.class}, #{e}\n\t#{e.backtrace.join("\n\t")} "
145
+ raise e
87
146
  end
147
+ end
148
+ # :startdoc:
88
149
 
89
- response[:body] = body if body.is_a?(String)
90
- raise "You have to set the response body" if response[:body].nil?
91
150
 
92
- logger.debug("It took #{Time.now.to_f - start_time} sec for #{self.class} to handle request.")
93
- [response[:status_code], response[:headers], response[:body]]
94
- end
151
+ #
152
+ # EXCEPTIONS
153
+ #
95
154
 
96
155
  # send an error message to the log prepended by "Synfeld: "
97
156
  def whine msg
@@ -100,33 +159,37 @@ module Synfeld
100
159
  end
101
160
 
102
161
 
103
- # :startdoc:
104
-
105
- def serve(fn, local = {})
106
- full_fn = fn
107
- full_fn = File.join(self.root_dir, fn) unless File.exist?(full_fn)
108
- if File.exist?(full_fn)
109
- ext = fn.split('.').last.downcase
162
+ # Overrideable method that handles a missing action that was defined by a route
163
+ def no_action
164
+ self.response[:body] = "Action '#{self.action}' not found in '#{self.class}'"
165
+ self.response[:status_code] = 500
166
+ end
110
167
 
111
- self.content_type!(ext)
168
+ # Overrideable method that handles 404
169
+ def no_route
170
+ self.response[:body] = "route not found for: '#{self.env['REQUEST_URI']}'"
171
+ self.response[:status_code] = 404
172
+ end
112
173
 
113
- case ext
114
- when 'html'; return serve_html(full_fn)
115
- when 'haml'; return serve_haml(full_fn, local)
116
- when 'erb'; return serve_erb(full_fn, local)
117
- else raise "Unrecognized file type: '#{ext}'";
118
- end
119
- else
120
- raise "Could not find file '#{fn}' (full path '#{full_fn}')"
121
- end
174
+ #
175
+ # RENDERING
176
+ #
122
177
 
178
+ # Render an html file. 'fn' is a full path, or a path relative to @root_dir.
179
+ def render_html(fn)
180
+ F.read(full_path(fn))
123
181
  end
124
182
 
125
- def serve_html(fn)
126
- File.read(fn)
183
+ # Serve up a blob of json (just sets Content-Type to 'text/javascript' and
184
+ # sets the body to the json passed in to this method).
185
+ def render_json(json)
186
+ self.response[:headers]['Content-Type'] = 'text/javascript'
187
+ self.response[:body] = json
127
188
  end
128
189
 
129
- def serve_haml(fn, locals = {})
190
+ # Render a haml file. 'fn' is a full path, or a path relative to @root_dir.
191
+ # 'locals' is a hash definining variables to be passed to the template.
192
+ def render_haml(fn, locals = {})
130
193
 
131
194
  if not defined? Haml
132
195
  begin
@@ -136,10 +199,12 @@ module Synfeld
136
199
  end
137
200
  end
138
201
 
139
- Haml::Engine.new(File.read(fn) ).render(Object.new, locals)
202
+ Haml::Engine.new(F.read(full_path(fn)) ).render(Object.new, locals)
140
203
  end
141
204
 
142
- def serve_erb(fn, locals = {})
205
+ # Render an erb file. 'fn' is a full path, or a path relative to @root_dir.
206
+ # 'locals' is a hash definining variables to be passed to the template.
207
+ def render_erb(fn, locals = {})
143
208
 
144
209
  if not defined? Erb
145
210
  begin
@@ -149,7 +214,7 @@ module Synfeld
149
214
  end
150
215
  end
151
216
 
152
- template = ERB.new File.read(fn)
217
+ template = ERB.new F.read(full_path(fn))
153
218
 
154
219
  bind = binding
155
220
  locals.each do |n,v|
@@ -159,34 +224,56 @@ module Synfeld
159
224
  template.result(bind)
160
225
  end
161
226
 
162
- def handle_static
163
- fn = File.expand_path(File.join(root_dir, self.env['REQUEST_URI']))
227
+ def render_static
228
+ fn = F.expand_path(F.join(root_dir, self.env['REQUEST_URI']))
164
229
  #puts fn # dbg
165
- if File.exist?(fn) and not File.directory?(fn)
230
+ if F.exist?(fn) and not F.directory?(fn)
166
231
  self.content_type!(fn.split('.').last)
167
- File.read(fn)
232
+ F.read(fn)
168
233
  else
169
234
  return self.no_route
170
235
  end
171
236
  end
172
237
 
238
+ #
239
+ # UTIL
240
+ #
241
+
242
+ # Given a file extention, determine the 'Content-Type' and then set the
243
+ # @response[:headers]['Content-Type']. Unrecognized extentions are
244
+ # set to content type of 'text/plain'.
173
245
  def content_type!(ext)
174
246
  case ext.downcase
175
- when 'html'; t = 'text/html'
176
247
  when 'haml'; t = 'text/html'
177
- when 'js'; t = 'text/javascript'
178
- when 'css'; t = 'text/css'
179
- when 'png'; t = 'image/png'
180
- when 'gif'; t = 'image/gif'
181
- when 'jpg'; t = 'image/jpeg'
182
- when 'jpeg'; t = 'image/jpeg'
248
+ when 'erb'; t = 'text/html'
249
+ # I believe all the rest are determined accurately by the Rack::Mime.mime_type call in the else clause below.
250
+ # when 'html'; t = 'text/html'
251
+ # when 'js'; t = 'text/javascript'
252
+ # when 'css'; t = 'text/css'
253
+ # when 'png'; t = 'image/png'
254
+ # when 'gif'; t = 'image/gif'
255
+ # when 'jpg'; t = 'image/jpeg'
256
+ # when 'jpeg'; t = 'image/jpeg'
257
+ else t = Rack::Mime.mime_type('.' + ext, 'text/plain')
183
258
  end
259
+ #puts("----#{ext}:" + t.inspect) # dbg
184
260
  (self.response[:headers]['Content-Type'] = t) if t
185
261
  end
186
262
 
187
- def no_route
188
- self.response[:body] = "route not found for: '#{self.env['REQUEST_URI']}'"
189
- self.response[:status_code] = 404
263
+ # Return fn if a file by that name exists. If not, concatenate the @root_dir with the fn, and
264
+ # return that if it exists. Raise if the actual file cannot be determined.
265
+ #
266
+ # NOTE: no effort is made to protect access to files outside of your application's root
267
+ # dir. If you permit filepaths as request parameters, then it is up to you to make sure
268
+ # that they do not point to some sensitive part of your file-system.
269
+ def full_path(fn)
270
+ if F.exist?(fn)
271
+ return fn
272
+ elsif F.exist?(full_fn = F.join(self.root_dir, fn))
273
+ return full_fn
274
+ else
275
+ raise "Could not find file '#{fn}' (full path '#{full_fn}')"
276
+ end
190
277
  end
191
278
 
192
279
  end # class App
@@ -5,7 +5,7 @@ module Synfeld
5
5
 
6
6
  # :stopdoc:
7
7
 
8
- VERSION = '0.0.2'
8
+ VERSION = '0.0.4'
9
9
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
10
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
11
 
@@ -2,27 +2,31 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{synfeld}
5
- s.version = "0.0.2"
5
+ s.version = "0.0.4"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Steven Swerling"]
9
- s.date = %q{2009-08-29}
9
+ s.date = %q{2009-09-26}
10
10
  s.description = %q{Synfeld is a web application framework that does practically nothing.
11
11
 
12
- Basically this is just a tiny wrapper for the Rack::Router (see http://github.com/carllerche/rack-router). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. for help files) and media, Synfeld makes that easy. If you need session variables, a mailer, uploading, etc, look elsewhere.
12
+ Synfeld is little more than a small wrapper for Rack::Mount (see http://github.com/josh/rack-mount). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. help files) and media, Synfeld makes that easy.
13
13
 
14
- The sample app below shows pretty much everything that synfeld can do.
14
+ The sample app below shows pretty much everything there is to know about synfeld, in particular:
15
15
 
16
- Very alpha-ish stuff here. Seems to work though.}
16
+ * How to define routes.
17
+ * Simple rendering of erb, haml, html, json, and static files.
18
+ * In the case of erb and haml, passing variables into the template is demonstrated.
19
+ * A dynamic action where the status code, headers, and body are created 'manually' (/my/special/route below)
20
+ * A simple way of creating format sensitive routes (/alphabet.html vs. /alphabet.json)
21
+ * The erb demo link also demos the rendering of a partial (not visible in the code below, you have to look at the template file examples/public/erb_files/erb_test.erb).}
17
22
  s.email = %q{sswerling@yahoo.com}
18
23
  s.extra_rdoc_files = ["History.txt", "README.rdoc", "README.txt"]
19
- s.files = [".gitignore", "History.txt", "README.rdoc", "README.txt", "Rakefile", "TODO", "example/public/erb_files/erb_test.erb", "example/public/haml_files/haml_test.haml", "example/public/haml_files/home.haml", "example/public/html_files/html_test.html", "example/try_me.rb", "example/try_me.ru", "lib/synfeld.rb", "lib/synfeld/base.rb", "lib/synfeld_info.rb", "spec/spec_helper.rb", "spec/synfeld_spec.rb", "synfeld.gemspec", "test/test_synfeld.rb"]
20
- s.has_rdoc = true
24
+ s.files = [".gitignore", "History.txt", "README.rdoc", "README.txt", "Rakefile", "TODO", "example/public/erb_files/erb_test.erb", "example/public/haml_files/haml_test.haml", "example/public/haml_files/home.haml", "example/public/html_files/html_test.html", "example/public/images/beef_interstellar_thm.jpg", "example/public/images/rails.png", "example/try_me.rb", "example/try_me.ru", "lib/synfeld.rb", "lib/synfeld/base.rb", "lib/synfeld_info.rb", "spec/spec_helper.rb", "spec/synfeld_spec.rb", "synfeld.gemspec", "test/test_synfeld.rb", "work/rackmount-test.ru"]
21
25
  s.homepage = %q{http://tab-a.slot-z.net}
22
26
  s.rdoc_options = ["--inline-source", "--main", "README.txt"]
23
27
  s.require_paths = ["lib"]
24
28
  s.rubyforge_project = %q{synfeld}
25
- s.rubygems_version = %q{1.3.2}
29
+ s.rubygems_version = %q{1.3.5}
26
30
  s.summary = %q{Synfeld is a web application framework that does practically nothing}
27
31
  s.test_files = ["test/test_synfeld.rb"]
28
32
 
@@ -0,0 +1,59 @@
1
+ require 'rack/mount'
2
+
3
+ #@usher ||= Usher.new(:generator => Usher::Util::Generators::URL.new)
4
+
5
+ @app = proc do |env|
6
+
7
+ body = "Hi there #{env[ Rack::Mount::Const::RACK_ROUTING_ARGS].inspect}"
8
+ [
9
+ 200, # Status code
10
+ { # Response headers
11
+ 'Content-Type' => 'text/plain',
12
+ 'Content-Length' => body.size.to_s,
13
+ },
14
+ [body] # Response body
15
+ ]
16
+ end
17
+
18
+ @set = nil
19
+
20
+ def add_a_route(opts = {})
21
+ method = (opts.delete(:method) || 'GET').upcase
22
+ string_or_regex = opts.delete(:path) || raise("You have to provide a :path")
23
+ colon = (RUBY_VERSION =~ /^1.8/)? ':' : ''
24
+ if string_or_regex.is_a?(String)
25
+ regex_string = "^" + string_or_regex.gsub(/:(([^\/]+))/){|s| "(?#{colon}<#{$1}>.*)" } + "$"
26
+ puts regex_string
27
+ regex = %r{#{regex_string}}
28
+ else
29
+ regex = string_or_regex
30
+ end
31
+ @set.add_route(@app,
32
+ {:path_info => regex, :request_method => method.upcase},
33
+ opts)
34
+ end
35
+
36
+ basic_set = Rack::Mount::RouteSet.new_without_optimizations do |set|
37
+ @set = set
38
+ # set.add_route(@app, { :path_info => %r{^/hello/(?:<hi>.*)$}, :request_method => 'GET' },
39
+ # { :controller => 'spscontroller_a', :action => 'spsaction_a' })
40
+ # set.add_route(@app, { :path_info => %r{^/hi/(?<ho>.*)$}, :request_method => 'GET' },
41
+ # { :controller => 'spscontroller_a', :action => 'spsaction_a' })
42
+ # set.add_route(@app, { :path_info => '/ho/steve', :request_method => 'GET' },
43
+ # { :controller => 'spscontroller_a', :action => 'spsaction_a' })
44
+ # set.add_route(@app, { :path_info => Rack::Mount::Utils.normalize_path('/baz') },
45
+ # { :controller => 'baz', :action => 'index' })
46
+ add_a_route(:path => '/hillo/:name',
47
+ :method => 'get',
48
+ :controller => 'spscontroller_a',
49
+ :action => 'spsaction_a' )
50
+ add_a_route( :path => '/ho/:nime/blah',
51
+ :controller => 'spscontroller_b',
52
+ :action => 'spsaction_b' )
53
+ add_a_route(:path => %r{^/hey/(?:<hi>.*)$}, :cont => 'cont_c', :act => 'action_c' )
54
+ end
55
+
56
+
57
+ run basic_set
58
+
59
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swerling-synfeld
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Swerling
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-29 00:00:00 -07:00
12
+ date: 2009-09-26 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -42,7 +42,7 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: 2.5.1
44
44
  version:
45
- description: Synfeld is a web application framework that does practically nothing. Basically this is just a tiny wrapper for the Rack::Router (see http://github.com/carllerche/rack-router). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. for help files) and media, Synfeld makes that easy. If you need session variables, a mailer, uploading, etc, look elsewhere. The sample app below shows pretty much everything that synfeld can do. Very alpha-ish stuff here. Seems to work though.
45
+ description: "Synfeld is a web application framework that does practically nothing. Synfeld is little more than a small wrapper for Rack::Mount (see http://github.com/josh/rack-mount). If you want a web framework that is mostly just going to serve up json blobs, and occasionally serve up some simple content (eg. help files) and media, Synfeld makes that easy. The sample app below shows pretty much everything there is to know about synfeld, in particular: * How to define routes. * Simple rendering of erb, haml, html, json, and static files. * In the case of erb and haml, passing variables into the template is demonstrated. * A dynamic action where the status code, headers, and body are created 'manually' (/my/special/route below) * A simple way of creating format sensitive routes (/alphabet.html vs. /alphabet.json) * The erb demo link also demos the rendering of a partial (not visible in the code below, you have to look at the template file examples/public/erb_files/erb_test.erb)."
46
46
  email: sswerling@yahoo.com
47
47
  executables: []
48
48
 
@@ -63,6 +63,8 @@ files:
63
63
  - example/public/haml_files/haml_test.haml
64
64
  - example/public/haml_files/home.haml
65
65
  - example/public/html_files/html_test.html
66
+ - example/public/images/beef_interstellar_thm.jpg
67
+ - example/public/images/rails.png
66
68
  - example/try_me.rb
67
69
  - example/try_me.ru
68
70
  - lib/synfeld.rb
@@ -72,8 +74,10 @@ files:
72
74
  - spec/synfeld_spec.rb
73
75
  - synfeld.gemspec
74
76
  - test/test_synfeld.rb
75
- has_rdoc: true
77
+ - work/rackmount-test.ru
78
+ has_rdoc: false
76
79
  homepage: http://tab-a.slot-z.net
80
+ licenses:
77
81
  post_install_message:
78
82
  rdoc_options:
79
83
  - --inline-source
@@ -96,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
100
  requirements: []
97
101
 
98
102
  rubyforge_project: synfeld
99
- rubygems_version: 1.2.0
103
+ rubygems_version: 1.3.5
100
104
  signing_key:
101
105
  specification_version: 3
102
106
  summary: Synfeld is a web application framework that does practically nothing