nitro 0.21.2 → 0.22.0
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 +121 -0
- data/README +9 -3
- data/doc/RELEASES +86 -1
- data/lib/nitro.rb +1 -1
- data/lib/nitro/adapter/cgi.rb +4 -1
- data/lib/nitro/adapter/scgi.rb +2 -0
- data/lib/nitro/adapter/webrick.rb +1 -1
- data/lib/nitro/caching/output.rb +6 -5
- data/lib/nitro/compiler.rb +8 -3
- data/lib/nitro/dispatcher.rb +2 -2
- data/lib/nitro/dispatcher/nice.rb +1 -1
- data/lib/nitro/element.rb +19 -2
- data/lib/nitro/mixin/markup.rb +2 -2
- data/lib/nitro/mixin/pager.rb +80 -25
- data/lib/nitro/mixin/rss.rb +5 -2
- data/lib/nitro/render.rb +9 -0
- data/lib/nitro/request.rb +93 -6
- data/lib/nitro/response.rb +4 -0
- data/lib/nitro/server.rb +24 -10
- data/lib/nitro/server/runner.rb +15 -10
- data/lib/nitro/service/xmlrpc.rb +1 -0
- data/lib/nitro/test.rb +5 -0
- data/lib/nitro/test/assertions.rb +171 -0
- data/lib/nitro/{testing → test}/context.rb +0 -0
- data/lib/nitro/test/testcase.rb +66 -0
- data/proto/public/error.xhtml +5 -2
- data/proto/public/settings.xhtml +2 -0
- data/proto/script/runner +20 -0
- data/test/nitro/tc_controller.rb +3 -3
- data/test/nitro/tc_controller_aspect.rb +29 -0
- data/test/nitro/tc_dispatcher.rb +2 -1
- data/test/nitro/tc_element.rb +9 -0
- data/test/nitro/tc_request.rb +38 -0
- metadata +13 -13
- data/lib/nitro/mail.rb +0 -270
- data/lib/nitro/template.rb +0 -202
- data/lib/nitro/testing.rb +0 -2
- data/lib/nitro/testing/assertions.rb +0 -100
- data/lib/nitro/testing/testcase.rb +0 -51
- data/test/nitro/tc_mail.rb +0 -97
- data/test/nitro/tc_template.rb +0 -32
data/lib/nitro/mixin/markup.rb
CHANGED
@@ -21,7 +21,7 @@ module Nitro
|
|
21
21
|
#
|
22
22
|
# Define your custom markup methods like this:
|
23
23
|
#
|
24
|
-
# module
|
24
|
+
# module Markup
|
25
25
|
# def markup_simple
|
26
26
|
# ...
|
27
27
|
# end
|
@@ -49,7 +49,7 @@ private
|
|
49
49
|
def expand(str)
|
50
50
|
if str
|
51
51
|
xstr = str.dup
|
52
|
-
|
52
|
+
# xstr.gsub!(/</, '<')
|
53
53
|
xstr.gsub!(/>/, '>')
|
54
54
|
return String.sanitize(xstr)
|
55
55
|
end
|
data/lib/nitro/mixin/pager.rb
CHANGED
@@ -8,9 +8,9 @@ module Nitro
|
|
8
8
|
# === Design
|
9
9
|
#
|
10
10
|
# This pager is carefully designed for scaleability. It stores
|
11
|
-
# only the items for one page. The
|
12
|
-
# pagers can coexist in a single page.
|
13
|
-
#
|
11
|
+
# only the items for one page. The key parameter is needed,
|
12
|
+
# multiple pagers can coexist in a single page. The pager
|
13
|
+
# leverages the SQL LIMIT option to optimize database
|
14
14
|
# interaction.
|
15
15
|
|
16
16
|
class Pager
|
@@ -53,21 +53,53 @@ class Pager
|
|
53
53
|
@page_count = (@total_count.to_f / @per_page).ceil
|
54
54
|
end
|
55
55
|
|
56
|
+
# Return the first page index.
|
57
|
+
|
56
58
|
def first_page
|
57
59
|
return 1
|
58
60
|
end
|
59
61
|
|
62
|
+
# Is the first page displayed?
|
63
|
+
|
64
|
+
def first_page?
|
65
|
+
@page == 1
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return the last page index.
|
69
|
+
|
60
70
|
def last_page
|
61
71
|
return @page_count
|
62
72
|
end
|
63
73
|
|
74
|
+
# Is the last page displayed?
|
75
|
+
|
76
|
+
def last_page?
|
77
|
+
@page == @page_count
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return the index of the previous page.
|
81
|
+
|
64
82
|
def previous_page
|
65
83
|
return [@page - 1, 1].max()
|
66
84
|
end
|
85
|
+
|
86
|
+
# Return the index of the next page.
|
67
87
|
|
68
88
|
def next_page
|
69
89
|
return [@page + 1, @page_count].min()
|
70
90
|
end
|
91
|
+
|
92
|
+
# A set of helpers to create links to common pages.
|
93
|
+
|
94
|
+
for target in [:first, :last, :previous, :next]
|
95
|
+
eval %{
|
96
|
+
def link_#{target}_page
|
97
|
+
target_uri(#{target}_page)
|
98
|
+
end
|
99
|
+
alias_method :#{target}_page_uri, :link_#{target}_page
|
100
|
+
alias_method :#{target}_page_href, :link_#{target}_page
|
101
|
+
}
|
102
|
+
end
|
71
103
|
|
72
104
|
# Iterator
|
73
105
|
|
@@ -119,7 +151,11 @@ class Pager
|
|
119
151
|
# To be used with Og queries.
|
120
152
|
|
121
153
|
def limit
|
122
|
-
|
154
|
+
if @start_idx > 0
|
155
|
+
{ :limit => @per_page, :offset => @start_idx }
|
156
|
+
else
|
157
|
+
{ :limit => @per_page }
|
158
|
+
end
|
123
159
|
end
|
124
160
|
|
125
161
|
def offset
|
@@ -146,17 +182,17 @@ class Pager
|
|
146
182
|
def navigation
|
147
183
|
nav = ""
|
148
184
|
|
149
|
-
unless
|
185
|
+
unless first_page?
|
150
186
|
nav << %{
|
151
|
-
<div class="first"><a href="#{
|
152
|
-
<div class="previous"><a href="#{
|
187
|
+
<div class="first"><a href="#{first_page_href}">First</a></div>
|
188
|
+
<div class="previous"><a href="#{previous_page_href}">Previous</a></div>
|
153
189
|
}
|
154
190
|
end
|
155
191
|
|
156
|
-
unless
|
192
|
+
unless last_page?
|
157
193
|
nav << %{
|
158
|
-
<div class="last"><a href="#{
|
159
|
-
<div class="next"><a href="#{
|
194
|
+
<div class="last"><a href="#{last_page_href}">Last</a></div>
|
195
|
+
<div class="next"><a href="#{next_page_href}">Next</a></div>
|
160
196
|
}
|
161
197
|
end
|
162
198
|
|
@@ -198,32 +234,51 @@ module PagerMixin
|
|
198
234
|
private
|
199
235
|
|
200
236
|
# Helper method that generates a collection of items and the
|
201
|
-
#
|
237
|
+
# associated pager object.
|
202
238
|
#
|
203
239
|
# === Example
|
204
240
|
#
|
205
241
|
# entries, pager = paginate(Article, :condition => 'title LIKE %Ab%', :per_page => 10)
|
206
242
|
#
|
243
|
+
# or
|
244
|
+
#
|
245
|
+
# items = [ 'item1', 'item2', ... ]
|
246
|
+
# entries, pager = paginate(items, :per_page => 10)
|
247
|
+
#
|
248
|
+
# or
|
249
|
+
#
|
250
|
+
# entries, pager = paginate(article.comments, :per_page => 10)
|
251
|
+
#
|
207
252
|
# <ul>
|
208
253
|
# <?r for entry in entries ?>
|
209
254
|
# <li>#{entry.to_link}</li>
|
210
255
|
# <?r end ?>
|
211
|
-
#
|
212
|
-
#
|
256
|
+
# </ul>
|
257
|
+
# #{pager.links}
|
213
258
|
|
214
|
-
def paginate(
|
259
|
+
def paginate(items, options = {})
|
215
260
|
per_page = options.delete(:per_page) || Pager.per_page
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
261
|
+
|
262
|
+
case items
|
263
|
+
when Array
|
264
|
+
items = items.dup
|
265
|
+
pager = Pager.new(request, per_page, items.size, key = Pager.key)
|
266
|
+
items = items.slice(pager.offset, pager.per_page)
|
267
|
+
return items, pager
|
268
|
+
|
269
|
+
when Og::Collection
|
270
|
+
collection = items
|
271
|
+
pager = Pager.new(request, per_page, collection.count, key = Pager.key)
|
272
|
+
options.update(pager.limit)
|
273
|
+
items = collection.reload(options)
|
274
|
+
return items, pager
|
275
|
+
|
276
|
+
when Class
|
277
|
+
klass = items
|
278
|
+
pager = Pager.new(request, per_page, klass.count(options), key = Pager.key)
|
279
|
+
options.update(pager.limit)
|
280
|
+
items = klass.all(options)
|
281
|
+
return items, pager
|
227
282
|
end
|
228
283
|
end
|
229
284
|
|
data/lib/nitro/mixin/rss.rb
CHANGED
@@ -3,6 +3,8 @@ require 'rss/0.9'
|
|
3
3
|
|
4
4
|
require 'facet/string/first_char'
|
5
5
|
|
6
|
+
require 'nitro/mixin/markup'
|
7
|
+
|
6
8
|
module Nitro
|
7
9
|
|
8
10
|
# Build RSS represenations of ruby object collections.
|
@@ -17,7 +19,8 @@ module Nitro
|
|
17
19
|
#++
|
18
20
|
|
19
21
|
module RssMixin
|
20
|
-
|
22
|
+
include Nitro::Markup
|
23
|
+
|
21
24
|
# === Options
|
22
25
|
#
|
23
26
|
# [+:description+]
|
@@ -44,7 +47,7 @@ module RssMixin
|
|
44
47
|
item = RSS::Rss::Channel::Item.new
|
45
48
|
item.title = obj.title if obj.respond_to?(:title)
|
46
49
|
if obj.respond_to? :body and body = obj.body
|
47
|
-
item.description =
|
50
|
+
item.description = markup(body.first_char(256))
|
48
51
|
end
|
49
52
|
if obj.respond_to? :to_href
|
50
53
|
item.link = "#{c[:base]}/#{obj.to_href}"
|
data/lib/nitro/render.rb
CHANGED
@@ -7,6 +7,7 @@ require 'glue/attribute'
|
|
7
7
|
require 'glue/misc'
|
8
8
|
require 'glue/object'
|
9
9
|
require 'glue/settings'
|
10
|
+
require 'glue/template'
|
10
11
|
require 'glue/builder'
|
11
12
|
require 'glue/builder/xml'
|
12
13
|
|
@@ -173,6 +174,14 @@ private
|
|
173
174
|
end
|
174
175
|
alias_method :print, :render_text
|
175
176
|
|
177
|
+
# Render a template into the output buffer.
|
178
|
+
|
179
|
+
def render_template(filename)
|
180
|
+
filename = "#{filename}.xhtml" unless filename =~ /\.xhtml$/
|
181
|
+
template = File.read("#{self.class.template_root}/#{filename}")
|
182
|
+
Template.process_template(template, '@out', binding)
|
183
|
+
end
|
184
|
+
|
176
185
|
# Access the programmatic renderer (builder).
|
177
186
|
|
178
187
|
def build(&block)
|
data/lib/nitro/request.rb
CHANGED
@@ -2,7 +2,7 @@ module Nitro
|
|
2
2
|
|
3
3
|
# Encapsulates a request. This is an abstract request
|
4
4
|
# typically extended by sub-classes. This module
|
5
|
-
# is included in Context
|
5
|
+
# is included in Context.
|
6
6
|
|
7
7
|
module Request
|
8
8
|
|
@@ -16,7 +16,6 @@ module Request
|
|
16
16
|
attr_accessor :headers
|
17
17
|
alias_method :env, :headers
|
18
18
|
alias_method :env=, :headers=
|
19
|
-
# for compatibility with cgi.rb
|
20
19
|
alias_method :env_table, :headers
|
21
20
|
|
22
21
|
# The parsed query parameters collection.
|
@@ -56,23 +55,107 @@ module Request
|
|
56
55
|
@headers['PATH_INFO']
|
57
56
|
end
|
58
57
|
|
58
|
+
# Returns the domain part of a host.
|
59
|
+
#
|
60
|
+
# === Examples
|
61
|
+
#
|
62
|
+
# www.nitrohq.com: request.domain # => 'nitrohq.com'
|
63
|
+
# www.nitrohq.co.uk: request.domain(2) # => 'nitrohq.co.uk'
|
64
|
+
|
65
|
+
def domain(tld_length = 1)
|
66
|
+
host.split('.').last(1 + tld_length).join('.')
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns all the subdomains as an array.
|
70
|
+
#
|
71
|
+
# === Examples
|
72
|
+
#
|
73
|
+
# my.name.nitrohq.com: request.subdomains # => ['my', 'name']
|
74
|
+
|
75
|
+
def subdomains(tld_length = 1)
|
76
|
+
parts = host.split('.')
|
77
|
+
parts[0..-(tld_length+2)]
|
78
|
+
end
|
79
|
+
|
59
80
|
# The request query string.
|
60
81
|
|
61
82
|
def query_string
|
62
83
|
@headers['QUERY_STRING']
|
63
84
|
end
|
64
85
|
|
65
|
-
# The request method.
|
86
|
+
# The request method. Alternatively you could use the
|
87
|
+
# request method predicates.
|
88
|
+
#
|
89
|
+
# === Examples
|
90
|
+
#
|
91
|
+
# if request.method == :get
|
92
|
+
# if request.get?
|
66
93
|
|
67
94
|
def method
|
68
95
|
@headers['REQUEST_METHOD'].downcase.intern
|
69
96
|
end
|
70
97
|
|
71
|
-
|
98
|
+
#--
|
99
|
+
# Define a set of helpers to determine the request
|
100
|
+
# method (get?, post?, put?, delete?, head?)
|
101
|
+
#++
|
102
|
+
|
103
|
+
for m in [:get, :post, :put, :delete, :head]
|
104
|
+
eval %{
|
105
|
+
def #{m}?; method == :#{m}; end
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Determine whether the body of a POST request is URL-encoded
|
110
|
+
# (default), XML, or YAML by checking the Content-Type HTTP
|
111
|
+
# header:
|
112
|
+
#
|
113
|
+
# Content-Type Post Format
|
114
|
+
# application/xml :xml
|
115
|
+
# text/xml :xml
|
116
|
+
# application/x-yaml :yaml
|
117
|
+
# text/x-yaml :yaml
|
118
|
+
# * :url_encoded
|
72
119
|
|
73
|
-
def
|
74
|
-
|
120
|
+
def post_format
|
121
|
+
@post_format ||= if @headers['HTTP_X_POST_DATA_FORMAT']
|
122
|
+
@headers['HTTP_X_POST_DATA_FORMAT'].downcase.to_sym
|
123
|
+
else
|
124
|
+
case @headers['CONTENT_TYPE'].to_s.downcase
|
125
|
+
when 'application/xml', 'text/xml' then :xml
|
126
|
+
when 'application/x-yaml', 'text/x-yaml' then :yaml
|
127
|
+
else :url_encoded
|
128
|
+
end
|
129
|
+
end
|
75
130
|
end
|
131
|
+
|
132
|
+
# Is this a POST request formatted as XML or YAML?
|
133
|
+
|
134
|
+
def formatted_post?
|
135
|
+
post? && (post_format == :xml || post_format == :yaml)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Is this a POST request formatted as XML?
|
139
|
+
|
140
|
+
def xml_post?
|
141
|
+
post? && post_format == :xml
|
142
|
+
end
|
143
|
+
|
144
|
+
# Is this a POST request formatted as YAML?
|
145
|
+
|
146
|
+
def yaml_post?
|
147
|
+
post? && post_format == :yaml
|
148
|
+
end
|
149
|
+
|
150
|
+
# Is this an XhtmlRpcRequest?
|
151
|
+
# Returns true if the request's 'X-Requested-With' header
|
152
|
+
# contains 'XMLHttpRequest'. Compatible with the Prototype
|
153
|
+
# Javascript library.
|
154
|
+
|
155
|
+
def xml_http_request?
|
156
|
+
not /XMLHttpRequest/i.match(@headers['HTTP_X_REQUESTED_WITH']).nil?
|
157
|
+
end
|
158
|
+
alias xhr? :xml_http_request?
|
76
159
|
|
77
160
|
# Return the referer. For the initial page in the
|
78
161
|
# clickstream there is no referer, set "/" by default.
|
@@ -122,6 +205,8 @@ module Request
|
|
122
205
|
@headers['HTTP_X_FORWARDED_HOST'] || @headers['HTTP_HOST']
|
123
206
|
end
|
124
207
|
|
208
|
+
# The host url.
|
209
|
+
|
125
210
|
def host_url
|
126
211
|
"http://#{host}"
|
127
212
|
end
|
@@ -161,3 +246,5 @@ module Request
|
|
161
246
|
end
|
162
247
|
|
163
248
|
end
|
249
|
+
|
250
|
+
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/response.rb
CHANGED
data/lib/nitro/server.rb
CHANGED
@@ -61,7 +61,7 @@ class Server
|
|
61
61
|
# The access_log for this server, used by Webrick.
|
62
62
|
|
63
63
|
attr_accessor :access_log
|
64
|
-
|
64
|
+
|
65
65
|
def initialize(name = 'Nitro', options = {})
|
66
66
|
@name = name
|
67
67
|
@map = self.class.map.dup
|
@@ -82,9 +82,9 @@ class Server
|
|
82
82
|
|
83
83
|
# Start the server.
|
84
84
|
|
85
|
-
def start(
|
86
|
-
@map['/'] = controller if controller
|
87
|
-
@dispatcher = Dispatcher.new(@map)
|
85
|
+
def start(options = {})
|
86
|
+
@map['/'] = options[:controller] if options[:controller]
|
87
|
+
@dispatcher = options[:dispatche] || Dispatcher.new(@map)
|
88
88
|
end
|
89
89
|
|
90
90
|
def root=(controller)
|
@@ -96,15 +96,30 @@ class Server
|
|
96
96
|
end
|
97
97
|
|
98
98
|
# Helper method.
|
99
|
-
|
100
|
-
|
99
|
+
#
|
100
|
+
# Available options:
|
101
|
+
#
|
102
|
+
# :dispatcher, :controller
|
103
|
+
#
|
104
|
+
# Altetnatively you can pass a single Controller class instead
|
105
|
+
# of the options hash.
|
106
|
+
|
107
|
+
def self.run(options = {})
|
108
|
+
unless options.is_a?(Hash)
|
109
|
+
options = { :controller => options }
|
110
|
+
end
|
111
|
+
|
101
112
|
runner = Runner.new
|
102
113
|
runner.setup_options
|
103
114
|
runner.setup_mode
|
104
115
|
runner.daemonize if runner.daemon
|
116
|
+
|
105
117
|
server = Server.new
|
106
|
-
server.start(
|
107
|
-
|
118
|
+
server.start(options)
|
119
|
+
|
120
|
+
runner.invoke(server) unless $NITRO_NO_INVOKE
|
121
|
+
|
122
|
+
return server
|
108
123
|
end
|
109
124
|
|
110
125
|
# A Helper class used for CherryPy-style publishing.
|
@@ -123,8 +138,7 @@ class Server
|
|
123
138
|
end
|
124
139
|
end
|
125
140
|
end
|
126
|
-
|
127
|
-
|
141
|
+
|
128
142
|
end
|
129
143
|
|
130
144
|
end
|