serve 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|