serve 0.10.1 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +9 -4
- data/README.rdoc +24 -26
- data/VERSION +1 -1
- data/lib/serve/handlers/dynamic_handler.rb +3 -100
- data/lib/serve/view_helpers.rb +276 -0
- metadata +2 -1
data/CHANGELOG.rdoc
CHANGED
@@ -1,13 +1,18 @@
|
|
1
|
-
== 0.10.
|
1
|
+
== 0.10.2 (May 13, 2010)
|
2
2
|
|
3
|
-
*
|
3
|
+
* Changed render helper to support passing the name of the partial as the first parameter to match the new Rails syntax [jlong]
|
4
|
+
* Added additional view helpers for escaping content, access to params and flash, and creating tags in code [jlong]
|
4
5
|
|
5
|
-
== 0.10.
|
6
|
+
== 0.10.1 (May 13, 2010)
|
7
|
+
|
8
|
+
* Added handling for SCSS files with HAML/SASS 3.0 [nathany]
|
9
|
+
|
10
|
+
== 0.10.0 (December 28, 2009)
|
6
11
|
|
7
12
|
* Added additional view helper methods and harmonized the API a bit [aiwilliams]
|
8
13
|
* Added support for using Serve as a Rails plugin [aiwilliams]
|
9
14
|
* Added support for rack [ntalbott]
|
10
|
-
* Dropped Hoe and Newgem in favor of Jeweler
|
15
|
+
* Dropped Hoe and Newgem in favor of Jeweler [jlong]
|
11
16
|
|
12
17
|
== 0.9.10 (October 25, 2008)
|
13
18
|
|
data/README.rdoc
CHANGED
@@ -1,12 +1,22 @@
|
|
1
|
-
|
1
|
+
= Serve
|
2
2
|
|
3
|
-
Serve is a small web server (based on WEBrick) that makes it easy to serve
|
4
|
-
or HAML from any directory.
|
5
|
-
prototypes of Rails applications. Serve can also handle SASS, Textile, and
|
6
|
-
Markdown if the appropriate gems are installed.
|
3
|
+
Serve is a small web server (based on WEBrick) that makes it easy to serve
|
4
|
+
HTML, ERB, or HAML from any directory.
|
7
5
|
|
6
|
+
Serve is an ideal tool for building HTML prototypes of Rails applications. One
|
7
|
+
of the advantages of developing an HTML prototype is the opportunity to
|
8
|
+
explore the flow of an application before developing the backend. The “Design
|
9
|
+
First” approach also allows for substantial problem solving in the design
|
10
|
+
phase and the ability to estimate features with accuracy. When views are
|
11
|
+
ready, they can be copied over from the HTML prototype to the application
|
12
|
+
almost as is. This process is eased since Serve has full support for partials
|
13
|
+
and layouts with either ERB or HAML.
|
8
14
|
|
9
|
-
|
15
|
+
Serve can also handle SASS, Textile, and Markdown if the appropriate gems are
|
16
|
+
installed.
|
17
|
+
|
18
|
+
|
19
|
+
== Usage
|
10
20
|
|
11
21
|
At a command prompt all you need to type to start serve is:
|
12
22
|
|
@@ -23,7 +33,7 @@ serve command serves up files from the current directory. To change this
|
|
23
33
|
behavior, `cd` to the appropriate directory before starting serve.
|
24
34
|
|
25
35
|
|
26
|
-
|
36
|
+
== Advanced Options
|
27
37
|
|
28
38
|
The serve command automatically binds to 0.0.0.0 (localhost) and uses port
|
29
39
|
4000 by default. To serve files over a different IP (that is bound to your
|
@@ -35,9 +45,6 @@ computer) or port specify those options on the command line:
|
|
35
45
|
|
36
46
|
$ serve 192.168.1.6:4000 # a custom IP and port
|
37
47
|
|
38
|
-
|
39
|
-
=== Rails Applications
|
40
|
-
|
41
48
|
For your convenience if the file "script/server" exists in the current
|
42
49
|
directory the serve command will start that instead of launching a WEBrick
|
43
50
|
server. You can specify the environment that you want to start the server
|
@@ -46,7 +53,7 @@ with as an option on the command line:
|
|
46
53
|
$ serve production # start script/server in production mode
|
47
54
|
|
48
55
|
|
49
|
-
|
56
|
+
== File Types
|
50
57
|
|
51
58
|
Serve presently does special processing for files with following extensions:
|
52
59
|
|
@@ -73,31 +80,22 @@ ViewHelpers module and begin declaring your helpers:
|
|
73
80
|
end
|
74
81
|
|
75
82
|
|
76
|
-
|
83
|
+
== Installation and Setup
|
77
84
|
|
78
85
|
It is recommended that you install serve via RubyGems:
|
79
86
|
|
80
87
|
$ sudo gem install serve
|
81
88
|
|
82
89
|
|
83
|
-
|
84
|
-
|
85
|
-
For more information, be sure to look through the documentation over at
|
86
|
-
RubyForge:
|
87
|
-
|
88
|
-
* http://serve.rubyforge.org
|
89
|
-
|
90
|
-
Or visit the project page here:
|
91
|
-
|
92
|
-
* http://rubyforge.org/projects/serve
|
90
|
+
== More Information
|
93
91
|
|
94
|
-
|
92
|
+
For more information, be sure to look through the documentation over on the wiki: http://wiki.github.com/jlong/serve
|
95
93
|
|
96
|
-
|
94
|
+
All development takes place on GitHub: http://github.com/jlong/serve
|
97
95
|
|
98
96
|
|
99
|
-
|
97
|
+
== License
|
100
98
|
|
101
|
-
Serve is released under the MIT license and is copyright (c) 2007-
|
99
|
+
Serve is released under the MIT license and is copyright (c) 2007-2010
|
102
100
|
John W. Long and Adam I. Williams. A copy of the MIT license can be found in
|
103
101
|
the LICENSE file.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.2
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'serve/view_helpers'
|
2
|
+
|
1
3
|
module Serve #:nodoc:
|
2
4
|
class DynamicHandler < FileTypeHandler #:nodoc:
|
3
5
|
extension 'erb', 'html.erb', 'rhtml', 'haml', 'html.haml'
|
@@ -105,106 +107,7 @@ module Serve #:nodoc:
|
|
105
107
|
@erbout
|
106
108
|
end
|
107
109
|
|
108
|
-
|
109
|
-
def capture_erb(&block)
|
110
|
-
buffer = _erbout
|
111
|
-
pos = buffer.length
|
112
|
-
block.call
|
113
|
-
|
114
|
-
# extract the block
|
115
|
-
data = buffer[pos..-1]
|
116
|
-
|
117
|
-
# replace it in the original with empty string
|
118
|
-
buffer[pos..-1] = ''
|
119
|
-
|
120
|
-
data
|
121
|
-
end
|
122
|
-
|
123
|
-
# Content_for methods
|
124
|
-
|
125
|
-
def content_for(symbol, &block)
|
126
|
-
if @haml_buffer
|
127
|
-
set_content_for(symbol, capture_haml(&block))
|
128
|
-
else
|
129
|
-
set_content_for(symbol, capture_erb(&block))
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def content_for?(symbol)
|
134
|
-
!(get_content_for(symbol)).nil?
|
135
|
-
end
|
136
|
-
|
137
|
-
def get_content_for(symbol = :content)
|
138
|
-
if symbol.to_s.intern == :content
|
139
|
-
@content
|
140
|
-
else
|
141
|
-
instance_variable_get("@content_for_#{symbol}")
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# View helper methods
|
146
|
-
|
147
|
-
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
|
148
|
-
def html_escape(s)
|
149
|
-
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
|
150
|
-
end
|
151
|
-
alias h html_escape
|
152
|
-
|
153
|
-
def set_content_for(symbol, value)
|
154
|
-
instance_variable_set("@content_for_#{symbol}", value)
|
155
|
-
end
|
156
|
-
|
157
|
-
def params
|
158
|
-
request.params
|
159
|
-
end
|
160
|
-
|
161
|
-
# Render methods
|
162
|
-
|
163
|
-
def render(options)
|
164
|
-
partial = options.delete(:partial)
|
165
|
-
template = options.delete(:template)
|
166
|
-
case
|
167
|
-
when partial
|
168
|
-
render_partial(partial)
|
169
|
-
when template
|
170
|
-
render_template(template)
|
171
|
-
else
|
172
|
-
raise "render options not supported #{options.inspect}"
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def render_partial(partial)
|
177
|
-
render_template(partial, :partial => true)
|
178
|
-
end
|
179
|
-
|
180
|
-
def render_template(template, options={})
|
181
|
-
path = File.dirname(parser.script_filename)
|
182
|
-
if template =~ %r{^/}
|
183
|
-
template = template[1..-1]
|
184
|
-
path = @root_path
|
185
|
-
end
|
186
|
-
filename = template_filename(File.join(path, template), :partial => options.delete(:partial))
|
187
|
-
if File.file?(filename)
|
188
|
-
parser.parse_file(filename)
|
189
|
-
else
|
190
|
-
raise "File does not exist #{filename.inspect}"
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
private
|
195
|
-
|
196
|
-
def template_filename(name, options)
|
197
|
-
path = File.dirname(name)
|
198
|
-
template = File.basename(name)
|
199
|
-
template = "_" + template if options.delete(:partial)
|
200
|
-
template += extname(parser.script_filename) unless name =~ /\.[a-z]{3,4}$/
|
201
|
-
File.join(path, template)
|
202
|
-
end
|
203
|
-
|
204
|
-
def extname(filename)
|
205
|
-
/(\.[a-z]{3,4}\.[a-z]{3,4})$/.match(filename)
|
206
|
-
$1 || File.extname(filename) || ''
|
207
|
-
end
|
110
|
+
include Serve::ViewHelpers
|
208
111
|
end
|
209
112
|
end
|
210
113
|
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
module Serve #:nodoc:
|
2
|
+
# Many of the methods here have been extracted from Rails
|
3
|
+
|
4
|
+
module EscapeHelpers
|
5
|
+
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
|
6
|
+
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
|
7
|
+
|
8
|
+
# A utility method for escaping HTML tag characters.
|
9
|
+
# This method is also aliased as <tt>h</tt>.
|
10
|
+
#
|
11
|
+
# In your ERb templates, use this method to escape any unsafe content. For example:
|
12
|
+
# <%=h @person.name %>
|
13
|
+
#
|
14
|
+
# ==== Example:
|
15
|
+
# puts html_escape("is a > 0 & a < 10?")
|
16
|
+
# # => is a > 0 & a < 10?
|
17
|
+
def html_escape(s)
|
18
|
+
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
|
19
|
+
end
|
20
|
+
alias h html_escape
|
21
|
+
|
22
|
+
# A utility method for escaping HTML entities in JSON strings.
|
23
|
+
# This method is also aliased as <tt>j</tt>.
|
24
|
+
#
|
25
|
+
# In your ERb templates, use this method to escape any HTML entities:
|
26
|
+
# <%=j @person.to_json %>
|
27
|
+
#
|
28
|
+
# ==== Example:
|
29
|
+
# puts json_escape("is a > 0 & a < 10?")
|
30
|
+
# # => is a \u003E 0 \u0026 a \u003C 10?
|
31
|
+
def json_escape(s)
|
32
|
+
s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
|
33
|
+
end
|
34
|
+
alias j json_escape
|
35
|
+
end
|
36
|
+
|
37
|
+
module ContentHelpers
|
38
|
+
def capture_erb(&block)
|
39
|
+
buffer = _erbout
|
40
|
+
pos = buffer.length
|
41
|
+
block.call
|
42
|
+
|
43
|
+
# extract the block
|
44
|
+
data = buffer[pos..-1]
|
45
|
+
|
46
|
+
# replace it in the original with empty string
|
47
|
+
buffer[pos..-1] = ''
|
48
|
+
|
49
|
+
data
|
50
|
+
end
|
51
|
+
|
52
|
+
def content_for(symbol, &block)
|
53
|
+
if @haml_buffer
|
54
|
+
set_content_for(symbol, capture_haml(&block))
|
55
|
+
else
|
56
|
+
set_content_for(symbol, capture_erb(&block))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def content_for?(symbol)
|
61
|
+
!(get_content_for(symbol)).nil?
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_content_for(symbol = :content)
|
65
|
+
if symbol.to_s.intern == :content
|
66
|
+
@content
|
67
|
+
else
|
68
|
+
instance_variable_get("@content_for_#{symbol}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_content_for(symbol, value)
|
73
|
+
instance_variable_set("@content_for_#{symbol}", value)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module FlashHelpers
|
78
|
+
def flash
|
79
|
+
@flash ||= {}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module ParamHelpers
|
84
|
+
|
85
|
+
# Key based access to query parameters. Keys can be strings or symbols.
|
86
|
+
def params
|
87
|
+
@params ||= HashWithIndifferentAccess.new(request.query)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Extract the value for a bool param. Handy for rendering templates in
|
91
|
+
# different states.
|
92
|
+
def boolean_param(key, default = false)
|
93
|
+
key = key.to_s.intern
|
94
|
+
value = params[key]
|
95
|
+
return default if value.blank?
|
96
|
+
case value.strip.downcase
|
97
|
+
when 'true', '1' : true
|
98
|
+
when 'false', '0' : false
|
99
|
+
else raise 'Invalid value'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module RenderHelpers
|
105
|
+
def render(partial, options={})
|
106
|
+
if partial.is_a?(Hash)
|
107
|
+
options = options.merge(partial)
|
108
|
+
partial = options.delete(:partial)
|
109
|
+
end
|
110
|
+
template = options.delete(:template)
|
111
|
+
case
|
112
|
+
when partial
|
113
|
+
render_partial(partial)
|
114
|
+
when template
|
115
|
+
render_template(template)
|
116
|
+
else
|
117
|
+
raise "render options not supported #{options.inspect}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def render_partial(partial)
|
122
|
+
render_template(partial, :partial => true)
|
123
|
+
end
|
124
|
+
|
125
|
+
def render_template(template, options={})
|
126
|
+
path = File.dirname(parser.script_filename)
|
127
|
+
if template =~ %r{^/}
|
128
|
+
template = template[1..-1]
|
129
|
+
path = @root_path
|
130
|
+
end
|
131
|
+
filename = template_filename(File.join(path, template), :partial => options.delete(:partial))
|
132
|
+
if File.file?(filename)
|
133
|
+
parser.parse_file(filename)
|
134
|
+
else
|
135
|
+
raise "File does not exist #{filename.inspect}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def template_filename(name, options)
|
142
|
+
path = File.dirname(name)
|
143
|
+
template = File.basename(name)
|
144
|
+
template = "_" + template if options.delete(:partial)
|
145
|
+
template += extname(parser.script_filename) unless name =~ /\.[a-z]{3,4}$/
|
146
|
+
File.join(path, template)
|
147
|
+
end
|
148
|
+
|
149
|
+
def extname(filename)
|
150
|
+
/(\.[a-z]{3,4}\.[a-z]{3,4})$/.match(filename)
|
151
|
+
$1 || File.extname(filename) || ''
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
module TagHelpers
|
156
|
+
def content_tag(name, content, html_options={})
|
157
|
+
%{<#{name}#{html_attributes(html_options)}>#{content}</#{name}>}
|
158
|
+
end
|
159
|
+
|
160
|
+
def tag(name, html_options={})
|
161
|
+
%{<#{name}#{html_attributes(html_options)} />}
|
162
|
+
end
|
163
|
+
|
164
|
+
def image_tag(src, html_options = {})
|
165
|
+
tag(:img, html_options.merge({:src=>src}))
|
166
|
+
end
|
167
|
+
|
168
|
+
def image(name, options = {})
|
169
|
+
image_tag(append_image_extension("/images/admin/#{name}"), options)
|
170
|
+
end
|
171
|
+
|
172
|
+
def javascript_tag(content = nil, html_options = {})
|
173
|
+
content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => "text/javascript"))
|
174
|
+
end
|
175
|
+
|
176
|
+
def link_to(name, href, html_options = {})
|
177
|
+
html_options = html_options.stringify_keys
|
178
|
+
confirm = html_options.delete("confirm")
|
179
|
+
onclick = "if (!confirm('#{html_escape(confirm)}')) return false;" if confirm
|
180
|
+
content_tag(:a, name, html_options.merge(:href => href, :onclick=>onclick))
|
181
|
+
end
|
182
|
+
|
183
|
+
def link_to_function(name, *args, &block)
|
184
|
+
html_options = {}
|
185
|
+
html_options = args.pop if args.last.is_a? Hash
|
186
|
+
function = args[0] || ''
|
187
|
+
onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
|
188
|
+
href = html_options[:href] || '#'
|
189
|
+
content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
|
190
|
+
end
|
191
|
+
|
192
|
+
def mail_to(email_address, name = nil, html_options = {})
|
193
|
+
html_options = html_options.stringify_keys
|
194
|
+
encode = html_options.delete("encode").to_s
|
195
|
+
cc, bcc, subject, body = html_options.delete("cc"), html_options.delete("bcc"), html_options.delete("subject"), html_options.delete("body")
|
196
|
+
|
197
|
+
string = ''
|
198
|
+
extras = ''
|
199
|
+
extras << "cc=#{CGI.escape(cc).gsub("+", "%20")}&" unless cc.nil?
|
200
|
+
extras << "bcc=#{CGI.escape(bcc).gsub("+", "%20")}&" unless bcc.nil?
|
201
|
+
extras << "body=#{CGI.escape(body).gsub("+", "%20")}&" unless body.nil?
|
202
|
+
extras << "subject=#{CGI.escape(subject).gsub("+", "%20")}&" unless subject.nil?
|
203
|
+
extras = "?" << extras.gsub!(/&?$/,"") unless extras.empty?
|
204
|
+
|
205
|
+
email_address = email_address.to_s
|
206
|
+
|
207
|
+
email_address_obfuscated = email_address.dup
|
208
|
+
email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.has_key?("replace_at")
|
209
|
+
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
|
210
|
+
|
211
|
+
if encode == "javascript"
|
212
|
+
"document.write('#{content_tag("a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
|
213
|
+
string << sprintf("%%%x", c)
|
214
|
+
end
|
215
|
+
"<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>"
|
216
|
+
elsif encode == "hex"
|
217
|
+
email_address_encoded = ''
|
218
|
+
email_address_obfuscated.each_byte do |c|
|
219
|
+
email_address_encoded << sprintf("&#%d;", c)
|
220
|
+
end
|
221
|
+
|
222
|
+
protocol = 'mailto:'
|
223
|
+
protocol.each_byte { |c| string << sprintf("&#%d;", c) }
|
224
|
+
|
225
|
+
email_address.each_byte do |c|
|
226
|
+
char = c.chr
|
227
|
+
string << (char =~ /\w/ ? sprintf("%%%x", c) : char)
|
228
|
+
end
|
229
|
+
content_tag "a", name || email_address_encoded, html_options.merge({ "href" => "#{string}#{extras}" })
|
230
|
+
else
|
231
|
+
content_tag "a", name || email_address_obfuscated, html_options.merge({ "href" => "mailto:#{email_address}#{extras}" })
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
def cdata_section(content)
|
238
|
+
"<![CDATA[#{content}]]>"
|
239
|
+
end
|
240
|
+
|
241
|
+
def javascript_cdata_section(content) #:nodoc:
|
242
|
+
"\n//#{cdata_section("\n#{content}\n//")}\n"
|
243
|
+
end
|
244
|
+
|
245
|
+
def html_attributes(options)
|
246
|
+
unless options.blank?
|
247
|
+
attrs = []
|
248
|
+
options.each_pair do |key, value|
|
249
|
+
if value == true
|
250
|
+
attrs << %(#{key}="#{key}") if value
|
251
|
+
else
|
252
|
+
attrs << %(#{key}="#{value}") unless value.nil?
|
253
|
+
end
|
254
|
+
end
|
255
|
+
" #{attrs.sort * ' '}" unless attrs.empty?
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def append_image_extension(name)
|
260
|
+
unless name =~ /\.(.*?)$/
|
261
|
+
name + '.png'
|
262
|
+
else
|
263
|
+
name
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
module ViewHelpers #:nodoc:
|
269
|
+
include EscapeHelpers
|
270
|
+
include ContentHelpers
|
271
|
+
include FlashHelpers
|
272
|
+
include ParamHelpers
|
273
|
+
include RenderHelpers
|
274
|
+
include TagHelpers
|
275
|
+
end
|
276
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serve
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John W. Long
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/serve/rails/serve_controller.rb
|
69
69
|
- lib/serve/response_cache.rb
|
70
70
|
- lib/serve/version.rb
|
71
|
+
- lib/serve/view_helpers.rb
|
71
72
|
- lib/serve/webrick/extensions.rb
|
72
73
|
- lib/serve/webrick/server.rb
|
73
74
|
- lib/serve/webrick/servlet.rb
|