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.
@@ -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