nitro 0.21.2 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,7 +21,7 @@ module Nitro
21
21
  #
22
22
  # Define your custom markup methods like this:
23
23
  #
24
- # module MarkupMixin
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
- xstr.gsub!(/</, '&lt;')
52
+ # xstr.gsub!(/</, '&lt;')
53
53
  xstr.gsub!(/>/, '&gt;')
54
54
  return String.sanitize(xstr)
55
55
  end
@@ -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 name parameter is needed, multiple
12
- # pagers can coexist in a single page. Unlike older pagers this
13
- # pager leverages the SQL LIMIT option to optimize database
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
- { :limit => @per_page, :offset => @start_idx }
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 @page == first_page()
185
+ unless first_page?
150
186
  nav << %{
151
- <div class="first"><a href="#{target_uri(first_page())}">First</a></div>
152
- <div class="previous"><a href="#{target_uri(previous_page())}">Previous</a></div>
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 @page == last_page()
192
+ unless last_page?
157
193
  nav << %{
158
- <div class="last"><a href="#{target_uri(last_page())}">Last</a></div>
159
- <div class="next"><a href="#{target_uri(next_page())}">Next</a></div>
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
- # asorted pager object.
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
- # </ul>
212
- # #{pager.links}
256
+ # </ul>
257
+ # #{pager.links}
213
258
 
214
- def paginate(klass_or_array, options = {})
259
+ def paginate(items, options = {})
215
260
  per_page = options.delete(:per_page) || Pager.per_page
216
-
217
- if klass_or_array.is_a? Array
218
- items = klass_or_array.dup
219
- pager = Pager.new(request, per_page, items.size, key = Pager.key)
220
- items = items.slice(pager.offset, pager.per_page)
221
- return items, pager
222
- else
223
- pager = Pager.new(request, per_page, klass_or_array.count(options), key = Pager.key)
224
- options.update(pager.limit)
225
- items = klass_or_array.all(options)
226
- return items, pager
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
 
@@ -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 = CGI.escape(body.first_char(256))
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}"
@@ -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)
@@ -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
- # Is this a post method?
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 post?
74
- method == :post
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>
@@ -16,6 +16,10 @@ module Response
16
16
 
17
17
  attr_accessor :response_cookies
18
18
 
19
+ def content_type
20
+ @response_headers['Content-Type']
21
+ end
22
+
19
23
  def content_type=(ctype)
20
24
  @response_headers['Content-Type'] = ctype
21
25
  end
@@ -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(controller = nil)
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
- def self.run(controller = nil)
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(controller)
107
- runner.invoke(server)
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