serve 0.9.6 → 0.9.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +4 -1
- data/Quickstart.textile +148 -0
- data/README.txt +2 -2
- data/bin/serve +1 -67
- data/lib/serve/application.rb +145 -0
- data/lib/serve/handlers/dynamic_handler.rb +167 -0
- data/lib/serve/handlers/file_type_handler.rb +12 -9
- data/lib/serve/version.rb +2 -2
- data/lib/serve.rb +2 -1
- data/spec/serve_application_spec.rb +74 -0
- data/spec/serve_spec.rb +1 -1
- data.tar.gz.sig +1 -1
- metadata +46 -37
- metadata.gz.sig +0 -0
- data/lib/serve/handlers/haml_handler.rb +0 -114
data/Manifest.txt
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
History.txt
|
2
2
|
License.txt
|
3
3
|
Manifest.txt
|
4
|
+
Quickstart.textile
|
4
5
|
README.txt
|
5
6
|
Rakefile
|
6
7
|
bin/serve
|
7
8
|
config/hoe.rb
|
8
9
|
config/requirements.rb
|
9
10
|
lib/serve.rb
|
11
|
+
lib/serve/application.rb
|
12
|
+
lib/serve/handlers/dynamic_handler.rb
|
10
13
|
lib/serve/handlers/email_handler.rb
|
11
14
|
lib/serve/handlers/file_type_handler.rb
|
12
|
-
lib/serve/handlers/haml_handler.rb
|
13
15
|
lib/serve/handlers/markdown_handler.rb
|
14
16
|
lib/serve/handlers/redirect_handler.rb
|
15
17
|
lib/serve/handlers/sass_handler.rb
|
@@ -21,6 +23,7 @@ script/destroy
|
|
21
23
|
script/generate
|
22
24
|
script/txt2html
|
23
25
|
setup.rb
|
26
|
+
spec/serve_application_spec.rb
|
24
27
|
spec/serve_spec.rb
|
25
28
|
spec/spec.opts
|
26
29
|
spec/spec_helper.rb
|
data/Quickstart.textile
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
h1. Getting Started with Serve
|
2
|
+
|
3
|
+
|
4
|
+
Serve is a rapid prototyping framework for Rails applications. It is designed to compliment Rails development and enforce a strict separation of concerns between designer and developer. Using Serve with Rails allows the designer to happily work in his own space creating an HTML prototype of the application, while the developer works on the Rails application and copies over HTML from the prototype as needed. This allows the designer to focus on presentation and flow while the developer can focus on the implementation.
|
5
|
+
|
6
|
+
Let's have a look at how it all works.
|
7
|
+
|
8
|
+
|
9
|
+
h3. Installation
|
10
|
+
|
11
|
+
To get started we need to download and install the Ruby gem for Serve:
|
12
|
+
|
13
|
+
<pre>
|
14
|
+
% sudo gem install serve
|
15
|
+
</pre>
|
16
|
+
|
17
|
+
After we've done that it's probably a good idea to install a couple of additional gems so that Serve will play nicely with HAML, Markdown, and Textile:
|
18
|
+
|
19
|
+
<pre>
|
20
|
+
% sudo gem install haml Bluecloth Redcloth
|
21
|
+
</pre>
|
22
|
+
|
23
|
+
|
24
|
+
h3. Project Directory Structure
|
25
|
+
|
26
|
+
Once we have everything installed the next thing to do is setup the project directory. I like to setup my projects with the following directory structure:
|
27
|
+
|
28
|
+
<pre>
|
29
|
+
artwork # Logos and other identity design files go here
|
30
|
+
mockups # Fireworks or Photoshop web app mockups go here
|
31
|
+
prototype # The HTML prototype for the web app goes here
|
32
|
+
application # The actual Rails application is here
|
33
|
+
</pre>
|
34
|
+
|
35
|
+
Let's go ahead and create the directory for the prototype:
|
36
|
+
|
37
|
+
% mkdir prototype
|
38
|
+
|
39
|
+
Rails apps generally store images, javascripts, and stylesheets in the top level directories by the same name. Let's go ahead and mirror those directories for our prototype:
|
40
|
+
|
41
|
+
<pre>
|
42
|
+
% cd prototype
|
43
|
+
% mkdir images
|
44
|
+
% mkdir javascripts
|
45
|
+
% mkdir stylesheets
|
46
|
+
</pre>
|
47
|
+
|
48
|
+
|
49
|
+
h3. Creating Our First Screen
|
50
|
+
|
51
|
+
Now that we have the prototype directory set up, let's create our first page so that you can get a feel for how Serve works. This will be a simple HTML login page for our application.
|
52
|
+
|
53
|
+
Insert the following HTML into an file named "login.html":
|
54
|
+
|
55
|
+
<pre><code>
|
56
|
+
<form action="/dashboard/" method="put">
|
57
|
+
<p>
|
58
|
+
<label for="username">Username</label>
|
59
|
+
<input type="text" name="username" id="username" />
|
60
|
+
</p>
|
61
|
+
<p>
|
62
|
+
<label for="password">Password</label>
|
63
|
+
<input type="password" name="password" id="password" />
|
64
|
+
</p>
|
65
|
+
<p>
|
66
|
+
<input type="submit" value="Login" />
|
67
|
+
</p>
|
68
|
+
</form>
|
69
|
+
</code></pre>
|
70
|
+
|
71
|
+
|
72
|
+
h3. Starting Serve
|
73
|
+
|
74
|
+
To view our login page in a Web browser, we need to start up Serve in the directory where we are building the prototype:
|
75
|
+
|
76
|
+
<pre>
|
77
|
+
% cd prototype
|
78
|
+
% serve
|
79
|
+
[2008-02-23 15:19:05] INFO WEBrick 1.3.1
|
80
|
+
[2008-02-23 15:19:05] INFO ruby 1.8.6 (2007-09-24) [universal-darwin9.0]
|
81
|
+
[2008-02-23 15:19:05] INFO Serve::Server#start: pid=5087 port=4000
|
82
|
+
...
|
83
|
+
</pre>
|
84
|
+
|
85
|
+
Once you execute the `serve` command it will launch a mini Web server for the prototype and will output a noisy log of any activity. (To stop the command at any point simply switch back to the command line and press Ctrl+C.)
|
86
|
+
|
87
|
+
By default the `serve` command automatically serves files from the directory that it is started in over port 4000 on your local machine. To access the the prototype in your Web browser go to:
|
88
|
+
|
89
|
+
http://localhost:4000
|
90
|
+
|
91
|
+
You should see a simple directory listing. It will look similar to this:
|
92
|
+
|
93
|
+
<pre>
|
94
|
+
Name Last modified Size
|
95
|
+
----------------------------------------------------------
|
96
|
+
Parent Directory 2008/02/23 15:35 -
|
97
|
+
images/ 2008/02/23 15:35 -
|
98
|
+
javascripts/ 2008/02/23 15:35 -
|
99
|
+
login.html 2008/02/23 15:36 346
|
100
|
+
stylesheets/ 2008/02/23 15:35 -
|
101
|
+
</pre>
|
102
|
+
|
103
|
+
Now navigate to the following URL:
|
104
|
+
|
105
|
+
http://localhost:4000/login/
|
106
|
+
|
107
|
+
You should see the contents of the login page. Note that Serve allows you to refer to pages without their extension. This allows you to use URLs in your documents that correspond well to the URLs that Rails uses by default.
|
108
|
+
|
109
|
+
|
110
|
+
h3. Layouts
|
111
|
+
|
112
|
+
One thing to note about the source that I gave you for the login page. I intentionally left out the <html>, <head>, and <body> tags because they belong a layout---not the source file. Let's go ahead and create that layout now.
|
113
|
+
|
114
|
+
Insert the following HTML into a file named "_layout.html" in the root directory of your prototype:
|
115
|
+
|
116
|
+
<pre><code>
|
117
|
+
<html>
|
118
|
+
<head>
|
119
|
+
<title><%= @title %></title>
|
120
|
+
</head>
|
121
|
+
<body>
|
122
|
+
<h1><%= @title %>/h1>
|
123
|
+
<%= yield %>
|
124
|
+
</body>
|
125
|
+
</html>
|
126
|
+
</code></pre>
|
127
|
+
|
128
|
+
This layout includes a small amount of ERB(Embedded Ruby) to indicate the title of the web page and to insert the content of the page at the appropriate point.
|
129
|
+
|
130
|
+
Embedded Ruby is delineated with the opening and closing sequence <% and %> respectively. Sequences that begin with an addition equals sign insert their output directly into the HTML. In this case we want to render the @title variable as the title in the head and as the first heading in the document body. The yield keyword is used to insert the content of the page at that point.
|
131
|
+
|
132
|
+
We need to make one small change to our login page before continuing. Insert the following line at the top of login.html file:
|
133
|
+
|
134
|
+
<pre>
|
135
|
+
<% @title = "Login" %>
|
136
|
+
</pre>
|
137
|
+
|
138
|
+
This will set the @title variable for the login page. Now, switch back to your Web browser and navigate to:
|
139
|
+
|
140
|
+
<pre>
|
141
|
+
http://localhost:4000/login/
|
142
|
+
</pre>
|
143
|
+
|
144
|
+
The page should now have a title and heading that both read "Login".
|
145
|
+
|
146
|
+
h3. Content For
|
147
|
+
|
148
|
+
h3. Partials
|
data/README.txt
CHANGED
@@ -70,11 +70,11 @@ It is recommended that you install serve via RubyGems:
|
|
70
70
|
For more information, be sure to look through the documentation over at
|
71
71
|
RubyForge:
|
72
72
|
|
73
|
-
http://serve.rubyforge.org
|
73
|
+
* http://serve.rubyforge.org
|
74
74
|
|
75
75
|
Or visit the project page here:
|
76
76
|
|
77
|
-
http://rubyforge.org/projects/serve
|
77
|
+
* http://rubyforge.org/projects/serve
|
78
78
|
|
79
79
|
|
80
80
|
=== License
|
data/bin/serve
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
lib = File.dirname(__FILE__) + '/../lib'
|
4
3
|
require 'rubygems'
|
5
4
|
if File.file?(lib + '/serve/version.rb')
|
@@ -8,69 +7,4 @@ else
|
|
8
7
|
gem 'serve'
|
9
8
|
end
|
10
9
|
require 'serve'
|
11
|
-
|
12
|
-
args = ARGV.join(' ')
|
13
|
-
args.gsub!(%r{http://}, '')
|
14
|
-
args = args.split(/[ :]/).compact
|
15
|
-
|
16
|
-
help = args.delete('--help') || args.delete('-h') || false
|
17
|
-
version = args.delete('--version') || args.delete('-v') || false
|
18
|
-
environment = args.delete('production') || args.delete('test') || args.delete('test') || 'development'
|
19
|
-
port = args.pop
|
20
|
-
address = args.pop || '0.0.0.0'
|
21
|
-
script = Dir.pwd + '/script/server'
|
22
|
-
|
23
|
-
if args.size > 0
|
24
|
-
puts "invalid arguments"
|
25
|
-
puts ""
|
26
|
-
help = true
|
27
|
-
end
|
28
|
-
|
29
|
-
case
|
30
|
-
when version
|
31
|
-
puts "Serve #{Serve.version}"
|
32
|
-
when help
|
33
|
-
program = File.basename($0)
|
34
|
-
puts "Usage:"
|
35
|
-
puts " #{program} [port] [environment]"
|
36
|
-
puts " #{program} [address:port] [environment]"
|
37
|
-
puts " #{program} [options]"
|
38
|
-
puts " "
|
39
|
-
puts "Description:"
|
40
|
-
puts " Starts a WEBrick server on the specified address and port with its document "
|
41
|
-
puts " root set to the current working directory. By default the command uses "
|
42
|
-
puts " 0.0.0.0 for the address and 4000 for the port. This means that once the "
|
43
|
-
puts " command has been started you can access the documents in the current "
|
44
|
-
puts " directory with any Web browser at:"
|
45
|
-
puts " "
|
46
|
-
puts " http://localhost:4000/"
|
47
|
-
puts " "
|
48
|
-
puts " If the haml, redcloth, or bluecloth gems are installed the command can serve "
|
49
|
-
puts " Haml, Sass, Textile, and Markdown for documents with haml, sass, textile, "
|
50
|
-
puts " and markdown file extensions."
|
51
|
-
puts " "
|
52
|
-
puts " If the Rails command script/server exists in the current directory the "
|
53
|
-
puts " script will start that instead with the specified environment or the "
|
54
|
-
puts " development environment if none is specified. Rails apps are started by "
|
55
|
-
puts " default on port 3000."
|
56
|
-
puts " "
|
57
|
-
puts "Options:"
|
58
|
-
puts " -h, --help Show this message and quit."
|
59
|
-
puts " -v, --version Show the program version number and quit."
|
60
|
-
else
|
61
|
-
unless File.file?(script) and File.executable?(script)
|
62
|
-
port ||= 4000
|
63
|
-
server = Serve::Server.new(
|
64
|
-
:Port => port,
|
65
|
-
:BindAddress => address,
|
66
|
-
:DocumentRoot => Dir.pwd,
|
67
|
-
:DirectoryIndex => %w(index.html index.txt index.text index.haml index.textile index.markdown index.email index.redirect),
|
68
|
-
:AppendExtensions => %w(html txt text haml textile markdown email redirect)
|
69
|
-
)
|
70
|
-
trap("INT") { server.shutdown }
|
71
|
-
server.start
|
72
|
-
else
|
73
|
-
port ||= 3000
|
74
|
-
system "#{script} -p #{port} -b #{address} -e #{environment}"
|
75
|
-
end
|
76
|
-
end
|
10
|
+
Serve::Application.run
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module Serve
|
2
|
+
class Application
|
3
|
+
class InvalidArgumentsError < StandardError; end
|
4
|
+
|
5
|
+
attr_accessor :options
|
6
|
+
|
7
|
+
def self.run(args = ARGV)
|
8
|
+
Application.new.run(args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
self.options = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(args = ARGV)
|
16
|
+
@options = parse(args)
|
17
|
+
case
|
18
|
+
when options[:version]
|
19
|
+
puts version
|
20
|
+
when options[:help]
|
21
|
+
puts help
|
22
|
+
else
|
23
|
+
Dir.chdir(options[:root])
|
24
|
+
if rails_app?
|
25
|
+
run_rails_app
|
26
|
+
else
|
27
|
+
run_server
|
28
|
+
end
|
29
|
+
end
|
30
|
+
rescue InvalidArgumentsError
|
31
|
+
puts "invalid arguments"
|
32
|
+
puts
|
33
|
+
puts help
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse(args)
|
37
|
+
args = normalize_args(args)
|
38
|
+
options[:help] = extract_boolean(args, '-h', '--help')
|
39
|
+
options[:version] = extract_boolean(args, '-v', '--version')
|
40
|
+
options[:environment] = extract_environment(args)
|
41
|
+
options[:root] = extract_root(args)
|
42
|
+
options[:address] = extract_address(args)
|
43
|
+
options[:port] = extract_port(args)
|
44
|
+
raise InvalidArgumentsError if args.size > 0
|
45
|
+
options
|
46
|
+
end
|
47
|
+
|
48
|
+
def version
|
49
|
+
"Serve #{Serve.version}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def help
|
53
|
+
program = File.basename($0)
|
54
|
+
[
|
55
|
+
"Usage:",
|
56
|
+
" #{program} [port] [environment] [port]",
|
57
|
+
" #{program} [address:port] [environment] [port]",
|
58
|
+
" #{program} [options]",
|
59
|
+
" ",
|
60
|
+
"Description:",
|
61
|
+
" Starts a WEBrick server on the specified address and port with its document ",
|
62
|
+
" root set to the current working directory. (Optionally, you can specify the ",
|
63
|
+
" directory as the last parameter.) By default the command uses 0.0.0.0 for ",
|
64
|
+
" the address and 4000 for the port. This means that once the command has ",
|
65
|
+
" been started you can access the documents in the current directory with any ",
|
66
|
+
" Web browser at:",
|
67
|
+
" ",
|
68
|
+
" http://localhost:4000/",
|
69
|
+
" ",
|
70
|
+
" If the haml, redcloth, or bluecloth gems are installed the command can serve ",
|
71
|
+
" Haml, Sass, Textile, and Markdown for documents with haml, sass, textile, ",
|
72
|
+
" and markdown file extensions.",
|
73
|
+
" ",
|
74
|
+
" If the Rails command script/server exists in the current directory the ",
|
75
|
+
" script will start that instead with the specified environment or the ",
|
76
|
+
" development environment if none is specified. Rails apps are started by ",
|
77
|
+
" default on port 3000.",
|
78
|
+
" ",
|
79
|
+
"Options:",
|
80
|
+
" -h, --help Show this message and quit.",
|
81
|
+
" -v, --version Show the program version number and quit."
|
82
|
+
].join("\n")
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def normalize_args(args)
|
87
|
+
args = args.join(' ')
|
88
|
+
args.gsub!(%r{http://}, '')
|
89
|
+
args.split(/[ :]/).compact
|
90
|
+
end
|
91
|
+
|
92
|
+
def extract_boolean(args, *opts)
|
93
|
+
opts.each do |opt|
|
94
|
+
return true if args.delete(opt)
|
95
|
+
end
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
def extract_environment(args)
|
100
|
+
args.delete('production') || args.delete('test') || args.delete('development') || 'development'
|
101
|
+
end
|
102
|
+
|
103
|
+
def extract_port(args)
|
104
|
+
args.delete(args.find {|a| /^\d\d\d+$/.match(a) }) || (rails_app? ? 3000 : 4000)
|
105
|
+
end
|
106
|
+
|
107
|
+
def extract_address(args)
|
108
|
+
args.delete(args.find {|a| /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(a) }) || '0.0.0.0'
|
109
|
+
end
|
110
|
+
|
111
|
+
def extract_root(args)
|
112
|
+
args.reverse.each do |dir|
|
113
|
+
if File.directory?(dir)
|
114
|
+
args.delete(dir)
|
115
|
+
return File.expand_path(dir)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
Dir.pwd
|
119
|
+
end
|
120
|
+
|
121
|
+
def rails_script_server
|
122
|
+
@rails_server_script ||= options[:root] + '/script/server'
|
123
|
+
end
|
124
|
+
|
125
|
+
def rails_app?
|
126
|
+
File.file?(rails_script_server) and File.executable?(rails_script_server)
|
127
|
+
end
|
128
|
+
|
129
|
+
def run_rails_app
|
130
|
+
system "#{rails_script_server} -p #{options[:port]} -b #{options[:address]} -e #{options[:environment]}"
|
131
|
+
end
|
132
|
+
|
133
|
+
def run_server
|
134
|
+
server = Serve::Server.new(
|
135
|
+
:Port => options[:port],
|
136
|
+
:BindAddress => options[:address],
|
137
|
+
:DocumentRoot => options[:root],
|
138
|
+
:DirectoryIndex => %w(index.html index.erb index.html.erb index.rhtml index.haml index.html.haml index.txt index.text index.textile index.markdown index.email index.redirect),
|
139
|
+
:AppendExtensions => %w(html txt text haml erb rhtml html.erb html.haml textile markdown email redirect)
|
140
|
+
)
|
141
|
+
trap("INT") { server.shutdown }
|
142
|
+
server.start
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Serve #:nodoc:
|
2
|
+
class Handler < FileTypeHandler #:nodoc:
|
3
|
+
extension 'erb', 'html.erb', 'rhtml', 'haml', 'html.haml'
|
4
|
+
|
5
|
+
def process(req, res)
|
6
|
+
class << req
|
7
|
+
alias headers header
|
8
|
+
end
|
9
|
+
res['content-type'] = content_type
|
10
|
+
res.body = parse(req, res)
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(req, res)
|
14
|
+
context = Context.new(req, res)
|
15
|
+
view_helpers_file_path = Dir.pwd + '/view_helpers.rb'
|
16
|
+
if File.file?(view_helpers_file_path)
|
17
|
+
(class << context; self end).module_eval(File.read(view_helpers_file_path))
|
18
|
+
class << context
|
19
|
+
include ViewHelpers
|
20
|
+
end
|
21
|
+
end
|
22
|
+
parser = Parser.new(context)
|
23
|
+
context.content << parser.parse_file(@script_filename)
|
24
|
+
layout = find_layout_for(@script_filename)
|
25
|
+
if layout
|
26
|
+
parser.parse_file(layout)
|
27
|
+
else
|
28
|
+
context.content
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_layout_for(filename)
|
33
|
+
root = Dir.pwd
|
34
|
+
path = filename[root.size..-1]
|
35
|
+
layout = nil
|
36
|
+
begin
|
37
|
+
path = File.dirname(path)
|
38
|
+
l = File.join(root, path, '_layout.haml')
|
39
|
+
layout = l if File.file?(l)
|
40
|
+
end until layout or path == "/"
|
41
|
+
layout
|
42
|
+
end
|
43
|
+
|
44
|
+
module ERB #:nodoc:
|
45
|
+
class Engine #:nodoc:
|
46
|
+
def initialize(string, options = {})
|
47
|
+
@erb = ::ERB.new(string, nil, '-')
|
48
|
+
@erb.filename = options[:filename]
|
49
|
+
end
|
50
|
+
|
51
|
+
def render(context, &block)
|
52
|
+
@erb.result(context.instance_eval { binding })
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Parser #:nodoc:
|
58
|
+
attr_accessor :context, :script_filename
|
59
|
+
|
60
|
+
def initialize(context)
|
61
|
+
@context = context
|
62
|
+
@context.parser = self
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_file(filename)
|
66
|
+
old_script_filename = @script_filename
|
67
|
+
@script_filename = filename
|
68
|
+
lines = IO.read(filename)
|
69
|
+
engine = case File.extname(filename).sub(/^./, '').downcase
|
70
|
+
when 'haml'
|
71
|
+
require 'haml'
|
72
|
+
Haml::Engine.new(lines, :attr_wrapper => '"', :filename => filename)
|
73
|
+
when 'erb'
|
74
|
+
require 'erb'
|
75
|
+
ERB::Engine.new(lines, :filename => filename)
|
76
|
+
else
|
77
|
+
raise 'extension not supported'
|
78
|
+
end
|
79
|
+
result = engine.render(context) do |*args|
|
80
|
+
context.get_content_for(*args)
|
81
|
+
end
|
82
|
+
@script_filename = old_script_filename
|
83
|
+
result
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Context #:nodoc:
|
88
|
+
attr_accessor :content, :parser
|
89
|
+
attr_reader :request, :response
|
90
|
+
|
91
|
+
def initialize(req, res)
|
92
|
+
@request, @response = req, res
|
93
|
+
@content = ''
|
94
|
+
end
|
95
|
+
|
96
|
+
# Content_for methods
|
97
|
+
|
98
|
+
def content_for(symbol, &block)
|
99
|
+
set_content_for(symbol, capture_haml(&block))
|
100
|
+
end
|
101
|
+
|
102
|
+
def content_for?(symbol)
|
103
|
+
!(get_content_for(symbol)).nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_content_for(symbol = :content)
|
107
|
+
if symbol.to_s.intern == :content
|
108
|
+
@content
|
109
|
+
else
|
110
|
+
instance_variable_get("@content_for_#{symbol}")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def set_content_for(symbol, value)
|
115
|
+
instance_variable_set("@content_for_#{symbol}", value)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Render methods
|
119
|
+
|
120
|
+
def render(options)
|
121
|
+
partial = options.delete(:partial)
|
122
|
+
template = options.delete(:template)
|
123
|
+
case
|
124
|
+
when partial
|
125
|
+
render_partial(partial)
|
126
|
+
when template
|
127
|
+
render_template(template)
|
128
|
+
else
|
129
|
+
raise "render options not supported #{options.inspect}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def render_partial(partial)
|
134
|
+
render_template(partial, :partial => true)
|
135
|
+
end
|
136
|
+
|
137
|
+
def render_template(template, options={})
|
138
|
+
path = File.dirname(parser.script_filename)
|
139
|
+
if template =~ %r{^/}
|
140
|
+
template = template[1..-1]
|
141
|
+
path = Dir.pwd
|
142
|
+
end
|
143
|
+
filename = template_filename(File.join(path, template), :partial => options.delete(:partial))
|
144
|
+
if File.file?(filename)
|
145
|
+
parser.parse_file(filename)
|
146
|
+
else
|
147
|
+
raise "File does not exist #{filename.inspect}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def template_filename(name, options)
|
154
|
+
path = File.dirname(name)
|
155
|
+
template = File.basename(name)
|
156
|
+
template = "_" + template if options.delete(:partial)
|
157
|
+
template += extname(parser.script_filename) unless name =~ /\.[a-z]{3,4}$/
|
158
|
+
File.join(path, template)
|
159
|
+
end
|
160
|
+
|
161
|
+
def extname(filename)
|
162
|
+
/(\.[a-z]{3,4}\.[a-z]{3,4})$/.match(filename)
|
163
|
+
$1 || File.extname(filename) || ''
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -1,21 +1,24 @@
|
|
1
1
|
module Serve #:nodoc:
|
2
2
|
class FileTypeHandler < ::WEBrick::HTTPServlet::AbstractServlet #:nodoc:
|
3
3
|
|
4
|
-
def self.extension(
|
5
|
-
|
4
|
+
def self.extension(*extensions)
|
5
|
+
extensions.each do |extensions|
|
6
|
+
::WEBrick::HTTPServlet::FileHandler.add_handler(extensions, self)
|
7
|
+
end
|
6
8
|
end
|
7
|
-
|
9
|
+
|
10
|
+
|
8
11
|
def initialize(server, name)
|
9
12
|
super
|
10
13
|
@script_filename = name
|
11
14
|
end
|
12
|
-
|
15
|
+
|
13
16
|
def process(req, res)
|
14
17
|
data = open(@script_filename){|io| io.read }
|
15
18
|
res['content-type'] = content_type
|
16
19
|
res.body = parse(data)
|
17
20
|
end
|
18
|
-
|
21
|
+
|
19
22
|
def do_GET(req, res)
|
20
23
|
begin
|
21
24
|
process(req, res)
|
@@ -26,15 +29,15 @@ module Serve #:nodoc:
|
|
26
29
|
raise ::WEBrick::HTTPStatus::InternalServerError, ex.message
|
27
30
|
end
|
28
31
|
end
|
29
|
-
|
32
|
+
|
30
33
|
alias do_POST do_GET
|
31
|
-
|
34
|
+
|
32
35
|
protected
|
33
|
-
|
36
|
+
|
34
37
|
def content_type
|
35
38
|
'text/html'
|
36
39
|
end
|
37
|
-
|
40
|
+
|
38
41
|
def parse(string)
|
39
42
|
string.dup
|
40
43
|
end
|
data/lib/serve/version.rb
CHANGED
data/lib/serve.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'webrick'
|
2
2
|
require 'serve/version'
|
3
|
+
require 'serve/application'
|
3
4
|
require 'serve/webrick/extensions'
|
4
5
|
require 'serve/handlers/file_type_handler'
|
5
6
|
require 'serve/handlers/textile_handler'
|
6
7
|
require 'serve/handlers/markdown_handler'
|
7
|
-
require 'serve/handlers/
|
8
|
+
require 'serve/handlers/dynamic_handler'
|
8
9
|
require 'serve/handlers/sass_handler'
|
9
10
|
require 'serve/handlers/email_handler'
|
10
11
|
require 'serve/handlers/redirect_handler'
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Serve::Application do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@app = Serve::Application.new
|
7
|
+
@defopts = {
|
8
|
+
:help => false,
|
9
|
+
:help => false,
|
10
|
+
:version => false,
|
11
|
+
:environment => 'development',
|
12
|
+
:port => 4000,
|
13
|
+
:address => '0.0.0.0',
|
14
|
+
:root => Dir.pwd
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "parsing" do
|
19
|
+
it "should parse no arguments" do
|
20
|
+
@app.parse([]).should == @defopts
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse with only the port" do
|
24
|
+
@app.parse(["2000"])[:port].should == "2000"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse with the port and address" do
|
28
|
+
@app.parse(["1.1.1.1", "2000"]).should ==
|
29
|
+
@defopts.update(:address => "1.1.1.1", :port=>"2000")
|
30
|
+
@app.parse(["1.1.1.1:2000"]).should ==
|
31
|
+
@defopts.update(:address => "1.1.1.1", :port=>"2000")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should parse with the port, address, and protocol" do
|
35
|
+
@app.parse(["http://1.1.1.1:2000"]).should ==
|
36
|
+
@defopts.update(:address => "1.1.1.1", :port=>"2000")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should parse help" do
|
40
|
+
@app.parse([])[:help].should be_false
|
41
|
+
@app.parse(["-h"])[:help].should be_true
|
42
|
+
@app.parse(["--help"])[:help].should be_true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should parse version" do
|
46
|
+
@app.parse([])[:version].should be_false
|
47
|
+
@app.parse(["-v"])[:version].should be_true
|
48
|
+
@app.parse(["--version"])[:version].should be_true
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should parse environment" do
|
52
|
+
@app.parse([])[:environment].should == "development"
|
53
|
+
@app.parse(["production"])[:environment].should == "production"
|
54
|
+
@app.parse(["test"])[:environment].should == "test"
|
55
|
+
@app.parse(["development"])[:environment].should == "development"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should parse working directory" do
|
59
|
+
@app.parse([])[:root].should == Dir.pwd
|
60
|
+
dir = File.dirname(__FILE__)
|
61
|
+
@app.parse([dir])[:root].should == File.expand_path(dir)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should detect invalid arguments" do
|
65
|
+
lambda { @app.parse(["--invalid"]) }.should raise_error(Serve::Application::InvalidArgumentsError)
|
66
|
+
lambda { @app.parse(["invalid"]) }.should raise_error(Serve::Application::InvalidArgumentsError)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "running" do
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/spec/serve_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
|
|
3
3
|
describe "Serve" do
|
4
4
|
|
5
5
|
it "should register all of the file type handlers" do
|
6
|
-
handlers = ["cgi", "email", "haml", "markdown", "redirect", "rhtml", "sass", "textile"]
|
6
|
+
handlers = ["cgi", "email", "erb", "haml", "html.erb", "html.haml", "markdown", "redirect", "rhtml", "sass", "textile"]
|
7
7
|
table = WEBrick::HTTPServlet::FileHandler::HandlerTable
|
8
8
|
table.keys.sort.should == handlers
|
9
9
|
end
|
data.tar.gz.sig
CHANGED
@@ -1 +1 @@
|
|
1
|
-
�
|
1
|
+
B4RqPy�l�W�CF��)U��79M����+p�1��;%����+u�@
|
metadata
CHANGED
@@ -1,29 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.4
|
3
|
-
specification_version: 1
|
4
2
|
name: serve
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.9.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
- lib
|
11
|
-
email: me@johnwlong.com
|
12
|
-
homepage: http://serve.rubyforge.org
|
13
|
-
rubyforge_project: serve
|
14
|
-
description: Serve is a small Ruby script that makes it easy to start up a WEBrick server in any directory. Serve is ideal for HTML prototyping and simple file sharing. If the haml, redcloth, and bluecloth gems are installed serve can handle Haml, Sass, Textile, and Markdown (in addition to HTML).
|
4
|
+
version: 0.9.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John W. Long
|
15
8
|
autorequire:
|
16
|
-
default_executable:
|
17
9
|
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
25
|
-
platform: ruby
|
26
|
-
signing_key:
|
27
10
|
cert_chain:
|
28
11
|
- |
|
29
12
|
-----BEGIN CERTIFICATE-----
|
@@ -47,22 +30,36 @@ cert_chain:
|
|
47
30
|
qXI=
|
48
31
|
-----END CERTIFICATE-----
|
49
32
|
|
50
|
-
|
51
|
-
|
52
|
-
|
33
|
+
date: 2008-07-17 00:00:00 -04:00
|
34
|
+
default_executable:
|
35
|
+
dependencies: []
|
36
|
+
|
37
|
+
description: Serve is a small Ruby script that makes it easy to start up a WEBrick server in any directory. Serve is ideal for HTML prototyping and simple file sharing. If the haml, redcloth, and bluecloth gems are installed serve can handle Haml, Sass, Textile, and Markdown (in addition to HTML).
|
38
|
+
email: me@johnwlong.com
|
39
|
+
executables:
|
40
|
+
- serve
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files:
|
44
|
+
- History.txt
|
45
|
+
- License.txt
|
46
|
+
- Manifest.txt
|
47
|
+
- README.txt
|
53
48
|
files:
|
54
49
|
- History.txt
|
55
50
|
- License.txt
|
56
51
|
- Manifest.txt
|
52
|
+
- Quickstart.textile
|
57
53
|
- README.txt
|
58
54
|
- Rakefile
|
59
55
|
- bin/serve
|
60
56
|
- config/hoe.rb
|
61
57
|
- config/requirements.rb
|
62
58
|
- lib/serve.rb
|
59
|
+
- lib/serve/application.rb
|
60
|
+
- lib/serve/handlers/dynamic_handler.rb
|
63
61
|
- lib/serve/handlers/email_handler.rb
|
64
62
|
- lib/serve/handlers/file_type_handler.rb
|
65
|
-
- lib/serve/handlers/haml_handler.rb
|
66
63
|
- lib/serve/handlers/markdown_handler.rb
|
67
64
|
- lib/serve/handlers/redirect_handler.rb
|
68
65
|
- lib/serve/handlers/sass_handler.rb
|
@@ -74,6 +71,7 @@ files:
|
|
74
71
|
- script/generate
|
75
72
|
- script/txt2html
|
76
73
|
- setup.rb
|
74
|
+
- spec/serve_application_spec.rb
|
77
75
|
- spec/serve_spec.rb
|
78
76
|
- spec/spec.opts
|
79
77
|
- spec/spec_helper.rb
|
@@ -82,21 +80,32 @@ files:
|
|
82
80
|
- tasks/rspec.rake
|
83
81
|
- tasks/undefine.rake
|
84
82
|
- tasks/website.rake
|
85
|
-
|
86
|
-
|
83
|
+
has_rdoc: true
|
84
|
+
homepage: http://serve.rubyforge.org
|
85
|
+
post_install_message:
|
87
86
|
rdoc_options:
|
88
87
|
- --main
|
89
88
|
- README.txt
|
90
|
-
|
91
|
-
-
|
92
|
-
|
93
|
-
|
94
|
-
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: "0"
|
96
|
+
version:
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
version:
|
99
103
|
requirements: []
|
100
104
|
|
101
|
-
|
105
|
+
rubyforge_project: serve
|
106
|
+
rubygems_version: 1.0.1
|
107
|
+
signing_key:
|
108
|
+
specification_version: 2
|
109
|
+
summary: Serve is a small Ruby script that makes it easy to start up a WEBrick server in any directory. Serve is ideal for HTML prototyping and simple file sharing. If the haml, redcloth, and bluecloth gems are installed serve can handle Haml, Sass, Textile, and Markdown (in addition to HTML).
|
110
|
+
test_files: []
|
102
111
|
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,114 +0,0 @@
|
|
1
|
-
module Serve #:nodoc:
|
2
|
-
class HamlHandler < FileTypeHandler #:nodoc:
|
3
|
-
extension 'haml'
|
4
|
-
|
5
|
-
def parse(string)
|
6
|
-
require 'haml'
|
7
|
-
engine = Haml::Engine.new(string,
|
8
|
-
:attr_wrapper => '"',
|
9
|
-
:filename => @script_filename
|
10
|
-
)
|
11
|
-
layout = find_layout(@script_filename)
|
12
|
-
if layout
|
13
|
-
lines = IO.read(layout)
|
14
|
-
context = Context.new(Dir.pwd, @script_filename, engine.options.dup)
|
15
|
-
context.content = engine.render(context) do |*args|
|
16
|
-
context.get_content_for(*args)
|
17
|
-
end
|
18
|
-
layout_engine = Haml::Engine.new(lines, engine.options.dup)
|
19
|
-
layout_engine.render(context) do |*args|
|
20
|
-
context.get_content_for(*args)
|
21
|
-
end
|
22
|
-
else
|
23
|
-
engine.render
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def find_layout(filename)
|
28
|
-
root = Dir.pwd
|
29
|
-
path = filename[root.size..-1]
|
30
|
-
layout = nil
|
31
|
-
begin
|
32
|
-
path = File.dirname(path)
|
33
|
-
l = File.join(root, path, '_layout.haml')
|
34
|
-
layout = l if File.file?(l)
|
35
|
-
end until layout or path == "/"
|
36
|
-
layout
|
37
|
-
end
|
38
|
-
|
39
|
-
class Context #:nodoc:
|
40
|
-
attr_accessor :content
|
41
|
-
|
42
|
-
def initialize(root, script_filename, engine_options)
|
43
|
-
@root, @script_filename, @engine_options = root, script_filename, engine_options
|
44
|
-
end
|
45
|
-
|
46
|
-
# Content_for methods
|
47
|
-
|
48
|
-
def content_for(symbol, &block)
|
49
|
-
set_content_for(symbol, capture_haml(&block))
|
50
|
-
end
|
51
|
-
|
52
|
-
def content_for?(symbol)
|
53
|
-
!(get_content_for(symbol)).nil?
|
54
|
-
end
|
55
|
-
|
56
|
-
def get_content_for(symbol = :content)
|
57
|
-
if symbol.to_s.intern == :content
|
58
|
-
@content
|
59
|
-
else
|
60
|
-
instance_variable_get("@content_for_#{symbol}") || instance_variable_get("@#{symbol}")
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def set_content_for(symbol, value)
|
65
|
-
instance_variable_set("@content_for_#{symbol}", value)
|
66
|
-
end
|
67
|
-
|
68
|
-
# Render methods
|
69
|
-
|
70
|
-
def render(options)
|
71
|
-
partial = options.delete(:partial)
|
72
|
-
template = options.delete(:template)
|
73
|
-
case
|
74
|
-
when partial
|
75
|
-
render_partial(partial)
|
76
|
-
when template
|
77
|
-
render_template(template)
|
78
|
-
else
|
79
|
-
raise "render options not supported #{options.inspect}"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def render_partial(partial)
|
84
|
-
render_template(partial, :partial => true)
|
85
|
-
end
|
86
|
-
|
87
|
-
def render_template(template, options={})
|
88
|
-
path = File.dirname(@script_filename)
|
89
|
-
if template =~ %r{^/}
|
90
|
-
template = template[1..-1]
|
91
|
-
path = @root
|
92
|
-
end
|
93
|
-
filename = template_filename(File.join(path, template), :partial => options.delete(:partial))
|
94
|
-
if File.file?(filename)
|
95
|
-
lines = IO.read(filename)
|
96
|
-
engine = Haml::Engine.new(lines, @engine_options)
|
97
|
-
engine.render(self) do |*args|
|
98
|
-
get_content_for(*args)
|
99
|
-
end
|
100
|
-
else
|
101
|
-
raise "File does not exist #{filename.inspect}"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def template_filename(name, options)
|
106
|
-
path = File.dirname(name)
|
107
|
-
template = File.basename(name)
|
108
|
-
template = "_" + template if options.delete(:partial)
|
109
|
-
template += ".haml" unless name =~ /\.haml$/
|
110
|
-
File.join(path, template)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|