nitro 0.31.0 → 0.40.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/bin/nitro +135 -37
  2. data/doc/CHANGELOG.1 +108 -108
  3. data/doc/CHANGELOG.2 +89 -89
  4. data/doc/CHANGELOG.3 +105 -105
  5. data/{CHANGELOG → doc/CHANGELOG.4} +509 -509
  6. data/doc/{AUTHORS → CONTRIBUTORS} +49 -37
  7. data/doc/LIBRARIES +13 -0
  8. data/doc/LICENSE +2 -3
  9. data/doc/MIGRATION +45 -0
  10. data/doc/RELEASES +131 -11
  11. data/doc/TODO +67 -0
  12. data/lib/glue/magick.rb +0 -3
  13. data/lib/glue/sweeper.rb +30 -15
  14. data/lib/glue/thumbnails.rb +0 -2
  15. data/lib/glue/webfile.rb +23 -11
  16. data/lib/nitro.rb +37 -44
  17. data/lib/nitro/adapter/cgi.rb +0 -3
  18. data/lib/nitro/adapter/console.rb +0 -2
  19. data/lib/nitro/adapter/fastcgi.rb +6 -3
  20. data/lib/nitro/adapter/mongrel.rb +97 -58
  21. data/lib/nitro/adapter/script.rb +4 -6
  22. data/lib/nitro/adapter/webrick.rb +33 -87
  23. data/lib/nitro/adapter/webrick/vcr.rb +85 -0
  24. data/lib/nitro/caching.rb +0 -2
  25. data/lib/nitro/caching/actions.rb +0 -2
  26. data/lib/nitro/caching/fragments.rb +0 -2
  27. data/lib/nitro/caching/output.rb +45 -16
  28. data/lib/nitro/caching/proxy.rb +49 -0
  29. data/lib/nitro/cgi.rb +3 -6
  30. data/lib/nitro/cgi/cookie.rb +0 -3
  31. data/lib/nitro/cgi/request.rb +67 -24
  32. data/lib/nitro/cgi/response.rb +0 -2
  33. data/lib/nitro/cgi/{sendfile.rb → send_file.rb} +7 -6
  34. data/lib/nitro/compiler.rb +62 -55
  35. data/lib/nitro/compiler/cleanup.rb +0 -3
  36. data/lib/nitro/compiler/elements.rb +31 -28
  37. data/lib/nitro/compiler/errors.rb +2 -5
  38. data/lib/nitro/compiler/include.rb +10 -8
  39. data/lib/nitro/compiler/layout.rb +0 -2
  40. data/lib/nitro/compiler/localization.rb +0 -2
  41. data/lib/nitro/compiler/markup.rb +14 -6
  42. data/lib/nitro/compiler/morphing.rb +1 -5
  43. data/lib/nitro/compiler/script.rb +2 -4
  44. data/lib/nitro/compiler/squeeze.rb +0 -2
  45. data/lib/nitro/compiler/xslt.rb +0 -2
  46. data/lib/nitro/context.rb +10 -5
  47. data/lib/nitro/control.rb +18 -0
  48. data/lib/nitro/control/attribute.rb +88 -0
  49. data/lib/nitro/control/attribute/checkbox.rb +19 -0
  50. data/lib/nitro/control/attribute/datetime.rb +21 -0
  51. data/lib/nitro/control/attribute/file.rb +20 -0
  52. data/lib/nitro/control/attribute/fixnum.rb +26 -0
  53. data/lib/nitro/control/attribute/float.rb +26 -0
  54. data/lib/nitro/control/attribute/options.rb +38 -0
  55. data/lib/nitro/control/attribute/password.rb +16 -0
  56. data/lib/nitro/control/attribute/text.rb +16 -0
  57. data/lib/nitro/control/attribute/textarea.rb +16 -0
  58. data/lib/nitro/control/none.rb +16 -0
  59. data/lib/nitro/control/relation.rb +53 -0
  60. data/lib/nitro/control/relation/belongs_to.rb +0 -0
  61. data/lib/nitro/control/relation/has_many.rb +97 -0
  62. data/lib/nitro/control/relation/joins_many.rb +0 -0
  63. data/lib/nitro/control/relation/many_to_many.rb +0 -0
  64. data/lib/nitro/control/relation/refers_to.rb +29 -0
  65. data/lib/nitro/controller.rb +7 -296
  66. data/lib/nitro/dispatcher.rb +72 -34
  67. data/lib/nitro/element.rb +36 -10
  68. data/lib/nitro/element/javascript.rb +0 -2
  69. data/lib/nitro/flash.rb +23 -10
  70. data/lib/nitro/global.rb +36 -11
  71. data/lib/nitro/helper.rb +22 -8
  72. data/lib/nitro/helper/benchmark.rb +0 -2
  73. data/lib/nitro/helper/buffer.rb +0 -3
  74. data/lib/nitro/helper/css.rb +12 -0
  75. data/lib/nitro/helper/debug.rb +1 -3
  76. data/lib/nitro/helper/default.rb +1 -0
  77. data/lib/nitro/helper/feed.rb +400 -386
  78. data/lib/nitro/helper/form.rb +246 -116
  79. data/lib/nitro/helper/javascript.rb +28 -2
  80. data/lib/nitro/helper/javascript/morphing.rb +0 -2
  81. data/lib/nitro/helper/javascript/prototype.rb +0 -2
  82. data/lib/nitro/helper/javascript/scriptaculous.rb +0 -1
  83. data/lib/nitro/helper/layout.rb +0 -2
  84. data/lib/nitro/helper/navigation.rb +87 -0
  85. data/lib/nitro/helper/pager.rb +11 -22
  86. data/lib/nitro/helper/table.rb +9 -32
  87. data/lib/nitro/helper/url.rb +104 -0
  88. data/lib/nitro/helper/xhtml.rb +20 -4
  89. data/lib/nitro/helper/xml.rb +0 -2
  90. data/lib/nitro/markup.rb +131 -0
  91. data/lib/nitro/part.rb +52 -7
  92. data/lib/nitro/publishable.rb +328 -0
  93. data/lib/nitro/render.rb +30 -61
  94. data/lib/nitro/router.rb +12 -4
  95. data/lib/nitro/sanitize.rb +48 -0
  96. data/lib/nitro/scaffold.rb +9 -11
  97. data/lib/nitro/scaffold/controller.rb +25 -0
  98. data/lib/nitro/scaffold/model.rb +150 -0
  99. data/lib/nitro/scaffolding.rb +1 -3
  100. data/lib/nitro/server.rb +57 -32
  101. data/lib/nitro/server/drb.rb +16 -2
  102. data/lib/nitro/server/runner.rb +80 -102
  103. data/lib/nitro/service.rb +0 -1
  104. data/lib/nitro/service/xmlrpc.rb +0 -2
  105. data/lib/nitro/session.rb +26 -18
  106. data/lib/nitro/session/drb.rb +2 -16
  107. data/lib/nitro/session/memory.rb +0 -2
  108. data/lib/nitro/template.rb +219 -0
  109. data/lib/nitro/test/assertions.rb +1 -3
  110. data/lib/nitro/test/context.rb +0 -1
  111. data/lib/nitro/test/testcase.rb +0 -1
  112. data/lib/nitro/version.rb +6 -0
  113. data/lib/part/admin.rb +16 -0
  114. data/lib/part/admin/controller.rb +19 -0
  115. data/lib/part/admin/helper.rb +30 -0
  116. data/lib/part/admin/og/controller.rb +114 -0
  117. data/lib/part/admin/og/customize.rb +4 -0
  118. data/lib/part/admin/og/template/index.xhtml +27 -0
  119. data/lib/part/admin/og/template/list.xhtml +38 -0
  120. data/lib/part/admin/og/template/search.xhtml +20 -0
  121. data/lib/part/admin/og/template/update.xhtml +25 -0
  122. data/lib/part/admin/skin.rb +207 -0
  123. data/lib/part/admin/template/denied.xhtml +13 -0
  124. data/lib/part/admin/template/index.xhtml +12 -0
  125. data/lib/part/admin/todo.txt +2 -0
  126. data/proto/public/error.xhtml +4 -2
  127. data/proto/run.rb +0 -2
  128. data/test/glue/tc_webfile.rb +1 -0
  129. data/test/nitro/cgi/tc_request.rb +23 -0
  130. data/test/nitro/helper/tc_feed.rb +0 -3
  131. data/test/nitro/helper/tc_navbar.rb +74 -0
  132. data/test/nitro/helper/tc_table.rb +2 -0
  133. data/test/nitro/tc_cgi.rb +72 -19
  134. data/test/nitro/tc_controller.rb +35 -26
  135. data/test/nitro/tc_controller_aspect.rb +1 -0
  136. data/test/nitro/tc_controller_params.rb +864 -0
  137. data/test/nitro/tc_dispatcher.rb +2 -2
  138. data/test/nitro/tc_element.rb +16 -16
  139. data/test/nitro/tc_flash.rb +3 -3
  140. data/test/nitro/tc_markup.rb +31 -0
  141. data/test/nitro/tc_render.rb +12 -14
  142. data/test/nitro/tc_session.rb +9 -7
  143. data/test/nitro/tc_template.rb +34 -0
  144. metadata +217 -198
  145. data/INSTALL +0 -121
  146. data/ProjectInfo +0 -74
  147. data/README +0 -555
  148. data/doc/apache.txt +0 -9
  149. data/doc/config.txt +0 -28
  150. data/doc/faq.txt +0 -7
  151. data/doc/lhttpd.txt +0 -7
  152. data/lib/nitro/adapter/scgi.rb +0 -239
  153. data/lib/nitro/helper/form/builder.rb +0 -144
  154. data/lib/nitro/helper/form/controls.rb +0 -389
  155. data/lib/nitro/helper/rss.rb +0 -72
  156. data/proto/conf/apache.conf +0 -51
  157. data/proto/public/scaffold/advanced_search.xhtml +0 -30
  158. data/proto/public/scaffold/edit.xhtml +0 -11
  159. data/proto/public/scaffold/form.xhtml +0 -1
  160. data/proto/public/scaffold/index.xhtml +0 -20
  161. data/proto/public/scaffold/list.xhtml +0 -32
  162. data/proto/public/scaffold/new.xhtml +0 -11
  163. data/proto/public/scaffold/search.xhtml +0 -29
  164. data/proto/public/scaffold/view.xhtml +0 -8
  165. data/proto/script/scgi_ctl +0 -221
  166. data/proto/script/scgi_service +0 -128
  167. data/setup.rb +0 -1585
  168. data/src/part/admin.rb +0 -16
  169. data/src/part/admin/controller.rb +0 -81
  170. data/src/part/admin/skin.rb +0 -21
  171. data/src/part/admin/system.css +0 -135
  172. data/src/part/admin/template/denied.xhtml +0 -1
  173. data/src/part/admin/template/index.xhtml +0 -43
  174. data/test/nitro/helper/tc_rss.rb +0 -24
@@ -21,5 +21,3 @@ module BenchmarkHelper
21
21
  end
22
22
 
23
23
  end
24
-
25
- # * George Moschovitis <gm@navel.gr>
@@ -58,6 +58,3 @@ private
58
58
  end
59
59
 
60
60
  end
61
-
62
- # * George Moschovitis <gm@navel.gr>
63
-
@@ -0,0 +1,12 @@
1
+ module Nitro
2
+
3
+ # CSS Manager.
4
+ #--
5
+ # TODO: Add support for synthesizing compound CSS files from
6
+ # multiple smaller files.
7
+ #++
8
+
9
+ module CSS
10
+ end
11
+
12
+ end
@@ -16,7 +16,7 @@ private
16
16
  begin
17
17
  Marshal::dump(object)
18
18
  "<pre class='debug_dump'>#{object.to_yaml.gsub(" ", "&nbsp; ")}</pre>"
19
- rescue Object
19
+ rescue TypeError => ex
20
20
  # Object couldn't be dumped, perhaps because of singleton
21
21
  # methods, this is the fallback.
22
22
  "<code class='debug_dump'>#{object.inspect}</code>"
@@ -26,5 +26,3 @@ private
26
26
  end
27
27
 
28
28
  end
29
-
30
- # * George Moschovitis <gm@navel.gr>
@@ -8,6 +8,7 @@ module Nitro
8
8
 
9
9
  module DefaultHelper
10
10
  include DebugHelper
11
+ private :DebugHelper
11
12
  # This is an open module, extend in your application.
12
13
  end
13
14
 
@@ -1,5 +1,5 @@
1
1
  require 'rss/maker'
2
- require 'glue/markup'
2
+ require 'nitro/markup'
3
3
  require 'rexml/document'
4
4
  require 'time'
5
5
  require 'uri'
@@ -8,425 +8,439 @@ require 'facet/string/first_char'
8
8
 
9
9
  module Nitro
10
10
 
11
- # A helper that provides Feed related methods.
12
- #
13
- # To include this helper into your controller,
14
- # add the following at the beginning of your controller:
15
- #
16
- # helper :feed
17
- #
18
- # Then define actions that set an appropriate content_type and use build_(rss|atom|opml)
19
- # to generate your desired feed. See below for details.
20
- #
21
- # == RSS 0.91, 1.0 and 2.0
22
- #
23
- # response.content_type = "application/rss+xml"
24
- # build_rss(og_objects,
25
- # :version => "0.9",
26
- # :base => context.host_url, # + object.to_href results in an item-link
27
- # :link => context.host_url+"/feed", # link to this feed
28
- # :title => "Feed Title",
29
- # :description => "What this feed is about",
30
- # :search_title => "Search Form Here",
31
- # :search_description => "Search description",
32
- # :search_input_name => "search_field",
33
- # :search_form_action => "http://url/to/search_action"
34
- # )
35
- #
36
- # For RSS 1.0 or RSS 2.0 just change :version (defaults to '0.91'),
37
- # possible :version options are "0.9", "0.91", "1.0" and "2.0"
38
- #
39
- # * for RSS 0.9 :language is required (or defaults to 'en')
40
- # * for all RSS versions :title, :link and/or :base, :description are required
41
- #
42
- # <b>individual objects have to respond to at least:</b>
43
- #
44
- # * 1.0/0.9/2.0 require @title
45
- # * 1.0/0.9 require @to_href
46
- # * 2.0 requires @body
47
- #
48
- # if it doesn't, no item is created
49
- #
50
- # * @update_time, @create_time or @date is used for item.date
51
- # * so if Og's "is Timestamped" is being used, it'll be @update_time
52
- # * @author[:name] can optionally be used for item.author
53
- #
54
- # == Atom 1.0
55
- #
56
- # response.content_type = "application/atom+xml"
57
- # build_atom(og_objects,
58
- # :title => "Feed Title",
59
- # :base => context.host_url, # + object.to_href results in an item-link
60
- # :link => context.host_url+"/atomfeed",
61
- # :id => "your_unique_id", # :base is being used unless :id specified (:base is recommended)
62
- # :author_name => "Takeo",
63
- # :author_email => "email@example.com",
64
- # :author_link => "http://uri.to/authors/home",
65
- # )
66
- #
67
- # <b>individual objects have to respond to at least:</b>
68
- #
69
- # * @title
70
- # * @to_href
71
- # * @update_time/@create_time/@date (at least one of them)
72
- #
73
- # if it doesn't, no entry is created
74
- #
75
- # optional:
76
- #
77
- # * @body (taken as summary (256 chars))
78
- # * @full_content
79
- # * use Og's "is Timestamped", so both @update_time and @create_time can be used
80
- # * @author[:name]
81
- # * @author[:link]
82
- # * @author[:email] # be careful, you don't want to publish your users email address to spammers
83
- #
84
- #
85
- # == OPML 1.0 feed lists
86
- #
87
- # Fabian: Eew, who invented OPML? Who needs it? Implementing it in a very rough way anyway though.
88
- # takes a Hash of Feeds and optional options
89
- #
90
- # response.content_type = "application/opml+xml"
91
- # build_opml(
92
- # {
93
- # "http://oxyliquit.de/feed" => "rss",
94
- # "http://oxyliquit.de/feed/questions" => "rss",
95
- # "http://oxyliquit.de/feed/tips" => "rss",
96
- # "http://oxyliquit.de/feed/tutorials" => "rss"
97
- # },
98
- # :title => "My feeds"
99
- # )
100
-
101
- module FeedHelper
102
- include Glue::Markup
103
-
104
- # RSS 0.91, 1.0, 2.0 feeds.
105
-
106
- def build_rss(objects, options = {})
11
+ # A helper that provides Feed related methods.
12
+ #
13
+ # To include this helper into your controller,
14
+ # add the following at the beginning of your controller:
15
+ #
16
+ # helper :feed
17
+ #
18
+ # Then define actions that set an appropriate content_type and use build_(rss|atom|opml)
19
+ # to generate your desired feed. See below for details.
20
+ #
21
+ # == RSS 0.91, 1.0 and 2.0
22
+ #
23
+ # response.content_type = "application/rss+xml"
24
+ # build_rss(og_objects,
25
+ # :version => "0.9",
26
+ # :base => context.host_url, # + object.to_href results in an item-link
27
+ # :link => context.host_url+"/feed", # link to this feed
28
+ # :title => "Feed Title",
29
+ # :description => "What this feed is about",
30
+ # :search_title => "Search Form Here",
31
+ # :search_description => "Search description",
32
+ # :search_input_name => "search_field",
33
+ # :search_form_action => "http://url/to/search_action"
34
+ # )
35
+ #
36
+ # For RSS 1.0 or RSS 2.0 just change :version (defaults to '0.91'),
37
+ # possible :version options are "0.9", "0.91", "1.0" and "2.0"
38
+ #
39
+ # * for RSS 0.9 :language is required (or defaults to 'en')
40
+ # * for all RSS versions :title, :link and/or :base, :description are required
41
+ #
42
+ # <b>individual objects have to respond to at least:</b>
43
+ #
44
+ # * 1.0/0.9/2.0 require @title
45
+ # * 1.0/0.9 require @to_href
46
+ # * 2.0 requires @body
47
+ #
48
+ # if it doesn't, no item is created
49
+ #
50
+ # * @update_time, @create_time or @date is used for item.date
51
+ # * so if Og's "is Timestamped" is being used, it'll be @update_time
52
+ # * @author.name can optionally be used for item.author
53
+ #
54
+ # == Atom 1.0
55
+ #
56
+ # response.content_type = "application/atom+xml"
57
+ # build_atom(og_objects,
58
+ # :title => "Feed Title",
59
+ # :base => context.host_url, # + object.to_href results in an item-link
60
+ # :link => context.host_url+"/atomfeed",
61
+ # :id => "your_unique_id", # :base is being used unless :id specified (:base is recommended)
62
+ # :author_name => "Takeo",
63
+ # :author_email => "email@example.com",
64
+ # :author_link => "http://uri.to/authors/home",
65
+ # )
66
+ #
67
+ # <b>individual objects have to respond to at least:</b>
68
+ #
69
+ # * @title
70
+ # * @to_href
71
+ # * @update_time/@create_time/@date (at least one of them)
72
+ #
73
+ # if it doesn't, no entry is created
74
+ #
75
+ # optional:
76
+ #
77
+ # * @body (taken as summary (256 chars))
78
+ # * @full_content
79
+ # * use Og's "is Timestamped", so both @update_time and @create_time can be used
80
+ # * @author.name
81
+ # * @author.link
82
+ # * @author.email # be careful, you don't want to publish your users email address to spammers
83
+ #
84
+ #
85
+ # == OPML 1.0 feed lists
86
+ #
87
+ # Fabian: Eew, who invented OPML? Who needs it? Implementing it in a very rough way anyway though.
88
+ # takes a Hash of Feeds and optional options
89
+ #
90
+ # response.content_type = "application/opml+xml"
91
+ # build_opml(
92
+ # {
93
+ # "http://oxyliquit.de/feed" => "rss",
94
+ # "http://oxyliquit.de/feed/questions" => "rss",
95
+ # "http://oxyliquit.de/feed/tips" => "rss",
96
+ # "http://oxyliquit.de/feed/tutorials" => "rss"
97
+ # },
98
+ # :title => "My feeds"
99
+ # )
107
100
 
108
- # default options
109
- options = {
110
- :title => 'Syndication',
111
- :description => 'Syndication',
112
- :version => '0.9',
113
- :language => 'en', # required by 0.9
114
- }.update(options)
101
+ module FeedHelper
102
+ include Nitro::Markup
115
103
 
116
- raise "Option ':version' contains a wrong version!" unless %w(0.9 0.91 1.0 2.0).include?(options[:version])
104
+ # RSS 0.91, 1.0, 2.0 feeds.
117
105
 
118
- options[:base] ||= options[:link]
119
- raise "Option ':base' cannot be omitted!" unless options[:base]
120
-
121
- # build rss
122
- rss = RSS::Maker.make(options[:version]) do |maker|
123
- maker.channel.title = options[:title]
124
- maker.channel.description = options[:description]
125
- if options[:link]
126
- maker.channel.link = options[:link]
127
- else
128
- maker.channel.link = options[:base] #FIXME: not sure
129
- end
130
- case options[:version]
131
- when '0.9', '0.91'
132
- maker.channel.language = options[:language]
133
- when '1.0'
134
- if options[:link]
135
- maker.channel.about = options[:link]
136
- else
137
- raise "Option ':link' is required for RSS 1.0"
138
- end
139
- end
140
- maker.channel.generator = "Nitro " + Nitro::Version.to_s
106
+ def build_rss(objects, options = {})
141
107
 
142
- maker.items.do_sort = true
108
+ # default options
109
+ options = {
110
+ :title => 'Syndication',
111
+ :description => 'Syndication',
112
+ :version => '0.9',
113
+ :language => 'en', # required by 0.9
114
+ }.update(options)
143
115
 
144
- # items for each object
145
- # * 1.0/0.9/2.0 require @title
146
- # * 1.0/0.9 require @link
147
- # * 2.0 requires @description
148
- objects.each do |o|
149
-
150
- # new Item
151
- item = maker.items.new_item
152
-
153
- # Link
154
- item.link = "#{options[:base]}/#{o.to_href}" if o.respond_to?(:to_href)
155
- item.guid.content = "#{options[:base]}/#{o.to_href}" if options[:version] == '2.0' && o.respond_to?(:to_href)
156
-
157
- # Title
158
- item.title = o.title if o.respond_to?(:title)
159
-
160
- # Description
161
- if o.respond_to? :body and body = o.body
162
- #TODO: think about whether markup should always be done
163
- # and whether 256 chars should be a fixed limit
164
- #item.description = markup(body.first_char(256))
165
- # markup disabled, feedvalidator.org says "description should not contain HTML"
166
- # so removing everything that looks like a tag
167
- item.description = body.first_char(256).gsub!(/<[^>]+>/, ' ')
168
- end
169
-
170
- # Date (item.date asks for a Time object, so don't .to_s !)
171
- if o.respond_to?(:update_time)
172
- item.date = o.update_time
173
- elsif o.respond_to?(:create_time)
174
- item.date = o.create_time
175
- elsif o.respond_to?(:date)
176
- item.date = o.date
177
- end
178
-
179
- # Author
180
- if o.respond_to?(:author)
181
- if o.author[:name]
182
- item.author = o.author[:name]
183
- end
184
- end
185
-
186
- end if objects.size > 0 # objects/items
116
+ raise "Option ':version' contains a wrong version!" unless %w(0.9 0.91 1.0 2.0).include?(options[:version])
187
117
 
188
- # search form
189
- maker.textinput.title = options[:search_title] if options[:search_title]
190
- maker.textinput.description = options[:search_description] if options[:search_description]
191
- maker.textinput.name = options[:search_input_name] if options[:search_input_name]
192
- maker.textinput.link = options[:search_form_action] if options[:search_form_action]
118
+ options[:base] ||= options[:link]
119
+ raise "Option ':base' cannot be omitted!" unless options[:base]
120
+
121
+ # build rss
122
+ rss = RSS::Maker.make(options[:version]) do |maker|
123
+ maker.channel.title = options[:title]
124
+ maker.channel.description = options[:description]
125
+ if options[:link]
126
+ maker.channel.link = options[:link]
127
+ else
128
+ maker.channel.link = options[:base] #FIXME: not sure
129
+ end
130
+ case options[:version]
131
+ when '0.9', '0.91'
132
+ maker.channel.language = options[:language]
133
+ when '1.0'
134
+ if options[:link]
135
+ maker.channel.about = options[:link]
136
+ else
137
+ raise "Option ':link' is required for RSS 1.0"
138
+ end
193
139
  end
194
-
195
- return rss.to_s
196
- end # rss
197
- alias_method :rss, :build_rss
140
+ maker.channel.generator = "Nitro #{Nitro::Version}"
141
+
142
+ maker.items.do_sort = true
143
+
144
+ # items for each object
145
+ # * 1.0/0.9/2.0 require @title
146
+ # * 1.0/0.9 require @link
147
+ # * 2.0 requires @description
148
+ objects.each do |o|
149
+
150
+ # new Item
151
+ item = maker.items.new_item
152
+
153
+ # Link
154
+ item.link = "#{options[:base]}#{fhref o}" if o.respond_to?(:to_href)
155
+ item.guid.content = "#{options[:base]}#{fhref o}" if options[:version] == '2.0' && o.respond_to?(:to_href)
156
+
157
+ # Title
158
+ item.title = o.title if o.respond_to?(:title)
159
+
160
+ # Description
161
+ if o.respond_to? :body and body = o.body
162
+ #TODO: think about whether markup should always be done
163
+ # and whether 256 chars should be a fixed limit
164
+ #item.description = markup(body.first_char(256))
165
+ # markup disabled, feedvalidator.org says "description should not contain HTML"
166
+ # so removing everything that looks like a tag
167
+ item.description = body.first_char(256).gsub!(/<[^>]+>/, ' ')
168
+ end
169
+
170
+ # Date (item.date asks for a Time object, so don't .to_s !)
171
+ if o.respond_to?(:update_time)
172
+ item.date = o.update_time
173
+ elsif o.respond_to?(:create_time)
174
+ item.date = o.create_time
175
+ elsif o.respond_to?(:date)
176
+ item.date = o.date
177
+ end
178
+
179
+ # Author. Use .to_s to be more flexible.
180
+
181
+ if o.respond_to?(:author)
182
+ item.author = o.author.to_s
183
+ end
184
+
185
+ end if objects.size > 0 # objects/items
186
+
187
+ # search form
188
+ maker.textinput.title = options[:search_title] if options[:search_title]
189
+ maker.textinput.description = options[:search_description] if options[:search_description]
190
+ maker.textinput.name = options[:search_input_name] if options[:search_input_name]
191
+ maker.textinput.link = options[:search_form_action] if options[:search_form_action]
192
+ end
198
193
 
194
+ return rss.to_s
195
+ end
196
+ alias_method :rss, :build_rss
197
+
198
+
199
+ # Atom 1.0 feeds.
200
+
201
+ def build_atom(objects, options = {})
199
202
 
200
- # Atom 1.0 feeds.
203
+ # default options
204
+ options = {
205
+ :title => 'Syndication',
206
+ }.update(options)
201
207
 
202
- def build_atom(objects, options = {})
203
-
204
- # default options
205
- options = {
206
- :title => 'Syndication',
207
- }.update(options)
208
-
209
- raise "first param must be a collection of objects!" unless objects.respond_to?(:to_ary)
210
- raise "your object(s) have to respond to :update_time, :create_time or :date" unless objects[0].respond_to?(:update_time) or objects[0].respond_to?(:create_time) or objects[0].respond_to?(:date)
211
- raise "Option ':base' cannot be omitted!" unless options[:base]
212
-
213
- # new XML Document for Atom
214
- atom = REXML::Document.new
215
- atom << REXML::XMLDecl.new("1.0", "utf-8")
208
+ raise "first param must be a collection of objects!" unless objects.respond_to?(:to_ary)
209
+ raise "your object(s) have to respond to :update_time, :create_time or :date" unless objects[0].respond_to?(:update_time) or objects[0].respond_to?(:create_time) or objects[0].respond_to?(:date)
210
+ raise "Option ':base' cannot be omitted!" unless options[:base]
211
+
212
+ # new XML Document for Atom
213
+ atom = REXML::Document.new
214
+ atom << REXML::XMLDecl.new("1.0", "utf-8")
215
+
216
+ # Root element <feed />
217
+ feed = REXML::Element.new("feed").add_namespace("http://www.w3.org/2005/Atom")
216
218
 
217
- # Root element <feed />
218
- feed = REXML::Element.new("feed").add_namespace("http://www.w3.org/2005/Atom")
219
+ # Required feed elements
219
220
 
220
- # Required feed elements
221
-
222
- # id: Identifies the feed using a universally unique and permanent URI.
223
- iduri = URI.parse(options[:id] || options[:base]).normalize.to_s
224
- id = REXML::Element.new("id").add_text(iduri)
225
- feed << id
226
-
227
- # title: Contains a human readable title for the feed.
228
- title = REXML::Element.new("title").add_text(options[:title])
229
- feed << title
230
-
231
- # updated: Indicates the last time the feed was modified in a significant way.
232
- latest = Time.at(0) # a while back
233
- objects.each do |o|
234
- if o.respond_to?(:update_time)
235
- latest = o.update_time if o.update_time > latest
236
- elsif o.respond_to?(:create_time)
237
- latest = o.create_time if o.create_time > latest
238
- elsif o.respond_to?(:date)
239
- latest = o.date if o.date > latest
240
- end
221
+ # id: Identifies the feed using a universally unique and permanent URI.
222
+ iduri = URI.parse(options[:id] || options[:base]).normalize.to_s
223
+ id = REXML::Element.new("id").add_text(iduri)
224
+ feed << id
225
+
226
+ # title: Contains a human readable title for the feed.
227
+ title = REXML::Element.new("title").add_text(options[:title])
228
+ feed << title
229
+
230
+ # updated: Indicates the last time the feed was modified in a significant way.
231
+ latest = Time.at(0) # a while back
232
+ objects.each do |o|
233
+ if o.respond_to?(:update_time)
234
+ latest = o.update_time if o.update_time > latest
235
+ elsif o.respond_to?(:create_time)
236
+ latest = o.create_time if o.create_time > latest
237
+ elsif o.respond_to?(:date)
238
+ latest = o.date if o.date > latest
241
239
  end
242
- updated = REXML::Element.new("updated").add_text(latest.iso8601)
243
- feed << updated
244
-
245
- # Recommended feed elements
246
-
247
- # link: A feed should contain a link back to the feed itself.
248
- if options[:link]
249
- link = REXML::Element.new("link")
250
- link.add_attributes({ "rel" => "self", "href" => options[:link] })
251
- feed << link
240
+ end
241
+ updated = REXML::Element.new("updated").add_text(latest.iso8601)
242
+ feed << updated
243
+
244
+ # Recommended feed elements
245
+
246
+ # link: A feed should contain a link back to the feed itself.
247
+ if options[:link]
248
+ link = REXML::Element.new("link")
249
+ link.add_attributes({ "rel" => "self", "href" => options[:link] })
250
+ feed << link
251
+ end
252
+
253
+ # author: Names one author of the feed.
254
+ if options[:author_name] # name is required for author
255
+ author = REXML::Element.new("author")
256
+ author_name = REXML::Element.new("name").add_text(options[:author_name])
257
+ author << author_name
258
+ if options[:author_email]
259
+ author_email = REXML::Element.new("email").add_text(options[:author_email])
260
+ author << author_email
252
261
  end
253
-
254
- # author: Names one author of the feed.
255
- if options[:author_name] # name is required for author
256
- author = REXML::Element.new("author")
257
- author_name = REXML::Element.new("name").add_text(options[:author_name])
258
- author << author_name
259
- if options[:author_email]
260
- author_email = REXML::Element.new("email").add_text(options[:author_email])
261
- author << author_email
262
- end
263
- if options[:author_link]
264
- author_link = REXML::Element.new("uri").add_text(options[:author_link])
265
- author << author_link
266
- end
267
- feed << author
262
+ if options[:author_link]
263
+ author_link = REXML::Element.new("uri").add_text(options[:author_link])
264
+ author << author_link
268
265
  end
266
+ feed << author
267
+ end
268
+
269
+ # Optional feed elements
270
+
271
+ # category:
272
+ # contributor:
273
+ # generator: Identifies the software used to generate the feed.
274
+ generator = REXML::Element.new("generator")
275
+ generator.add_attributes({ "uri" => "http://www.nitroproject.org", "version" => Nitro::Version })
276
+ generator.add_text("Nitro")
277
+ feed << generator
278
+ # icon
279
+ # logo
280
+ # rights
281
+ # subtitle
282
+
283
+ # Entries
284
+ objects.each do |o|
269
285
 
270
- # Optional feed elements
286
+ # new Entry (called "item" in RSS)
287
+ unless o.respond_to?(:to_href) and o.respond_to?(:title)
288
+ next
289
+ end
290
+ entry = REXML::Element.new("entry")
291
+
292
+ # Required entry elements
271
293
 
272
- # category:
273
- # contributor:
274
- # generator: Identifies the software used to generate the feed.
275
- generator = REXML::Element.new("generator")
276
- generator.add_attributes({ "uri" => "http://www.nitroproject.org", "version" => Nitro::Version })
277
- generator.add_text("Nitro")
278
- feed << generator
279
- # icon
280
- # logo
281
- # rights
282
- # subtitle
283
-
284
- # Entries
285
- objects.each do |o|
294
+ # id
295
+ if o.respond_to?(:to_href)
296
+ id = REXML::Element.new("id").add_text("#{options[:base]}#{fhref o}")
297
+ entry << id
298
+ end
286
299
 
287
- # new Entry (called "item" in RSS)
288
- unless o.respond_to?(:to_href) and o.respond_to?(:title)
289
- next
300
+ # title
301
+ if o.respond_to?(:title)
302
+ title = REXML::Element.new("title").add_text(o.title)
303
+ entry << title
290
304
  end
291
- entry = REXML::Element.new("entry")
292
-
293
- # Required entry elements
294
305
 
295
- # id
296
- if o.respond_to?(:to_href)
297
- id = REXML::Element.new("id").add_text("#{options[:base]}/#{o.to_href}")
298
- entry << id
299
- end
300
-
301
- # title
302
- if o.respond_to?(:title)
303
- title = REXML::Element.new("title").add_text(o.title)
304
- entry << title
305
- end
306
-
307
- # updated
308
- updated = Time.at(0) # a while back
309
- if o.respond_to?(:update_time)
310
- updated = o.update_time
311
- elsif o.respond_to?(:create_time)
312
- updated = o.create_time
313
- elsif o.respond_to?(:date)
314
- updated = o.date
315
- end
316
- entry << REXML::Element.new("updated").add_text(updated.iso8601)
317
-
318
- # Recommended entry elements
306
+ # updated
307
+ updated = Time.at(0) # a while back
308
+ if o.respond_to?(:update_time)
309
+ updated = o.update_time
310
+ elsif o.respond_to?(:create_time)
311
+ updated = o.create_time
312
+ elsif o.respond_to?(:date)
313
+ updated = o.date
314
+ end
315
+ entry << REXML::Element.new("updated").add_text(updated.iso8601)
319
316
 
320
- # author
321
- if o.respond_to?(:author)
322
- if o.author[:name] # name is required for author
323
- author = REXML::Element.new("author")
324
- author_name = REXML::Element.new("name").add_text(o.author[:name])
325
- author << author_name
326
- if o.author[:email]
327
- author_email = REXML::Element.new("email").add_text(o.author[:email])
328
- author << author_email
329
- end
330
- if o.author[:link]
331
- author_link = REXML::Element.new("uri").add_text(o.author[:link])
332
- author << author_link
333
- end
334
- entry << author
335
- end
336
- end
317
+ # Recommended entry elements
318
+
319
+ # author
320
+ if o.respond_to?(:author)
337
321
 
338
- # summary
339
- if o.respond_to?(:body)
340
- summary = REXML::Element.new("summary")
341
- #TODO: think about whether 256 chars should be a fixed limit
342
- summary.add_text(o.body.first_char(256).gsub(/<[^>]+>/, ' '))
343
- entry << summary
322
+ if o.author.kind_of?(Hash)
323
+ oauthor = OpenStruct.new(o.author)
324
+ else
325
+ oauthor = o.author
344
326
  end
345
327
 
346
- # content
347
- # may have the type text, html or xhtml
348
- if o.respond_to?(:full_content)
349
- content = REXML::Element.new("content")
350
- #TODO: think about whether markup should always be done
351
- content.add_text(markup(o.full_content))
352
- entry << content
328
+ author = REXML::Element.new("author")
329
+ author_name = REXML::Element.new("name").add_text(oauthor.name)
330
+ author << author_name
331
+ if oauthor.email
332
+ author_email = REXML::Element.new("email").add_text(oauthor.email)
333
+ author << author_email
353
334
  end
354
-
355
- # link: An entry must contain an alternate link if there is no content element.
356
- if o.respond_to?(:to_href)
357
- link = REXML::Element.new("link")
358
- link.add_attributes({ "rel" => "alternate", "href" => "#{options[:base]}/#{o.to_href}" })
359
- entry << link
335
+ if oauthor.link
336
+ author_link = REXML::Element.new("uri").add_text(oauthor.link)
337
+ author << author_link
360
338
  end
361
-
362
- # Optional entry elements
339
+ entry << author
340
+ end
363
341
 
364
- # category
365
- # could be used for Tags maybe?
366
- # contributor
367
- # published
368
- if o.respond_to?(:create_time)
369
- published = REXML::Element.new("published")
370
- published.add_text(o.create_time.iso8601)
371
- entry << published
372
- end
373
- # source
374
- # rights
342
+ # summary
343
+
344
+ if o.respond_to?(:body)
345
+ summary = REXML::Element.new("summary")
346
+ #TODO: think about whether 256 chars should be a fixed limit
347
+ summary.add_text(o.body.first_char(256).gsub(/<[^>]+>/, ' '))
348
+ entry << summary
349
+ end
375
350
 
376
- # don't forget to add the entry to the feed
377
- feed << entry
351
+ # content
352
+ # may have the type text, html or xhtml
378
353
 
379
- end if objects.size > 0 # objects/entries
354
+ if o.respond_to?(:full_content)
355
+ content = REXML::Element.new("content")
356
+ #TODO: think about whether markup should always be done
357
+ content.add_text(markup(o.full_content))
358
+ entry << content
359
+ end
360
+
361
+ # link: An entry must contain an alternate link if there is no content element.
362
+
363
+ if o.respond_to?(:to_href)
364
+ link = REXML::Element.new("link")
365
+ link.add_attributes({ "rel" => "alternate", "href" => "#{options[:base]}#{fhref o}" })
366
+ entry << link
367
+ end
368
+
369
+ # Optional entry elements
380
370
 
381
- atom << feed
382
-
383
- return atom.to_s
384
- end # atom
385
- alias_method :atom, :build_atom
371
+ # category
372
+ # could be used for Tags maybe?
373
+ # contributor
374
+ # published
375
+
376
+ if o.respond_to?(:create_time)
377
+ published = REXML::Element.new("published")
378
+ published.add_text(o.create_time.iso8601)
379
+ entry << published
380
+ end
381
+
382
+ # source
383
+ # rights
384
+
385
+ # don't forget to add the entry to the feed
386
+ feed << entry
387
+
388
+ end if objects.size > 0 # objects/entries
389
+
390
+ atom << feed
391
+
392
+ return atom.to_s
393
+ end
394
+ alias_method :atom, :build_atom
395
+
396
+ # OPML 1.0 feed lists
397
+ # Fabian: eww, who invented OPML? Who needs it? Implementing
398
+ # it in a very rough way anyway though. Takes a Hash of
399
+ # Feeds and optional options.
400
+
401
+ def build_opml(feedhash, options = {})
386
402
 
387
- # OPML 1.0 feed lists
388
- # Fabian: eww, who invented OPML? Who needs it? Implementing
389
- # it in a very rough way anyway though. Takes a Hash of
390
- # Feeds and optional options.
403
+ # new XML Document for OPML
404
+ opml = REXML::Document.new
405
+ opml << REXML::XMLDecl.new("1.0", "utf-8")
391
406
 
392
- def build_opml(feedhash, options = {})
393
-
394
- # new XML Document for OPML
395
- opml = REXML::Document.new
396
- opml << REXML::XMLDecl.new("1.0", "utf-8")
397
-
398
- # Root element <opml />
399
- opml = REXML::Element.new("opml")
400
- opml.add_attribute("version", "1.0")
407
+ # Root element <opml />
408
+ opml = REXML::Element.new("opml")
409
+ opml.add_attribute("version", "1.0")
401
410
 
402
- # head
403
- head = REXML::Element.new("head")
404
- # title
405
- if options[:title]
406
- title = REXML::Element.new("title").add_text(options[:title])
407
- head << title
408
- end
409
- # dateCreated
410
- # dateModified
411
- # ownerName
412
- # ownerEmail
413
- opml << head
414
-
415
- # body
416
- body = REXML::Element.new("body")
417
- feedhash.each do |url, type|
418
- outline = REXML::Element.new("outline")
419
- outline.add_attributes({ "type" => type, "xmlUrl" => url })
420
- body << outline
421
- end
422
- opml << body
423
-
424
- return opml.to_s
425
- end # opml
426
- alias_method :opml, :build_opml
411
+ # head
412
+ head = REXML::Element.new("head")
413
+ # title
414
+ if options[:title]
415
+ title = REXML::Element.new("title").add_text(options[:title])
416
+ head << title
417
+ end
418
+ # dateCreated
419
+ # dateModified
420
+ # ownerName
421
+ # ownerEmail
422
+ opml << head
427
423
 
424
+ # body
425
+ body = REXML::Element.new("body")
426
+ feedhash.each do |url, type|
427
+ outline = REXML::Element.new("outline")
428
+ outline.add_attributes({ "type" => type, "xmlUrl" => url })
429
+ body << outline
430
+ end
431
+ opml << body
432
+
433
+ return opml.to_s
434
+ end
435
+ alias_method :opml, :build_opml
436
+
437
+
438
+ # Helper
439
+
440
+ def fhref(obj)
441
+ "/#{obj.to_href}".squeeze('/')
428
442
  end
443
+
429
444
  end
430
445
 
431
- # * Fabian Buch <fabian@fabian-buch.de>
432
- # * George Moschovitis <gm@navel.gr>
446
+ end