nitro 0.20.0 → 0.21.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 +752 -543
- data/INSTALL +38 -38
- data/README +264 -225
- data/Rakefile +48 -49
- data/bin/nitro +3 -3
- data/bin/nitrogen +6 -6
- data/doc/AUTHORS +10 -10
- data/doc/CHANGELOG.1 +1939 -1939
- data/doc/CHANGELOG.2 +954 -954
- data/doc/LICENSE +3 -3
- data/doc/MIGRATION +28 -0
- data/doc/RELEASES +814 -643
- data/doc/config.txt +5 -5
- data/install.rb +7 -17
- data/lib/nitro.rb +38 -9
- data/lib/nitro/adapter/cgi.rb +311 -312
- data/lib/nitro/adapter/fastcgi.rb +18 -25
- data/lib/nitro/adapter/webrick.rb +128 -137
- data/lib/nitro/adapter/wee.rb +51 -0
- data/lib/nitro/caching.rb +20 -20
- data/lib/nitro/caching/actions.rb +43 -43
- data/lib/nitro/caching/fragments.rb +46 -46
- data/lib/nitro/caching/invalidation.rb +11 -11
- data/lib/nitro/caching/output.rb +65 -65
- data/lib/nitro/caching/stores.rb +67 -67
- data/lib/nitro/compiler.rb +262 -0
- data/lib/nitro/compiler/elements.rb +0 -0
- data/lib/nitro/compiler/errors.rb +65 -0
- data/lib/nitro/compiler/localization.rb +25 -0
- data/lib/nitro/compiler/markup.rb +19 -0
- data/lib/nitro/compiler/shaders.rb +206 -0
- data/lib/nitro/compiler/squeeze.rb +20 -0
- data/lib/nitro/compiler/xslt.rb +61 -0
- data/lib/nitro/context.rb +87 -88
- data/lib/nitro/controller.rb +151 -158
- data/lib/nitro/cookie.rb +34 -34
- data/lib/nitro/dispatcher.rb +195 -186
- data/lib/nitro/element.rb +132 -126
- data/lib/nitro/element/java_script.rb +6 -6
- data/lib/nitro/flash.rb +66 -66
- data/lib/nitro/mail.rb +192 -192
- data/lib/nitro/mixin/buffer.rb +66 -0
- data/lib/nitro/mixin/debug.rb +16 -16
- data/lib/nitro/mixin/form.rb +88 -0
- data/lib/nitro/mixin/helper.rb +2 -2
- data/lib/nitro/mixin/javascript.rb +108 -108
- data/lib/nitro/mixin/markup.rb +144 -0
- data/lib/nitro/mixin/pager.rb +202 -202
- data/lib/nitro/mixin/rss.rb +67 -0
- data/lib/nitro/mixin/table.rb +63 -0
- data/lib/nitro/mixin/xhtml.rb +75 -0
- data/lib/nitro/mixin/xml.rb +124 -0
- data/lib/nitro/render.rb +183 -359
- data/lib/nitro/request.rb +140 -140
- data/lib/nitro/response.rb +27 -27
- data/lib/nitro/routing.rb +21 -21
- data/lib/nitro/scaffold.rb +124 -118
- data/lib/nitro/server.rb +117 -80
- data/lib/nitro/server/runner.rb +341 -0
- data/lib/nitro/service.rb +12 -12
- data/lib/nitro/service/xmlrpc.rb +22 -22
- data/lib/nitro/session.rb +122 -120
- data/lib/nitro/session/drb.rb +9 -9
- data/lib/nitro/session/drbserver.rb +34 -34
- data/lib/nitro/template.rb +171 -155
- data/lib/nitro/testing/assertions.rb +90 -90
- data/lib/nitro/testing/context.rb +16 -16
- data/lib/nitro/testing/testcase.rb +34 -34
- data/proto/conf/lhttpd.conf +9 -9
- data/proto/public/error.xhtml +75 -75
- data/proto/public/index.xhtml +18 -18
- data/proto/public/js/behaviour.js +65 -65
- data/proto/public/js/controls.js +1 -1
- data/proto/public/js/prototype.js +3 -3
- data/proto/public/settings.xhtml +61 -61
- data/proto/run.rb +1 -5
- data/test/nitro/adapter/raw_post1.bin +0 -0
- data/test/nitro/adapter/tc_cgi.rb +57 -57
- data/test/nitro/adapter/tc_webrick.rb +4 -4
- data/test/nitro/mixin/tc_pager.rb +25 -25
- data/test/nitro/mixin/tc_rss.rb +24 -0
- data/test/nitro/mixin/tc_table.rb +31 -0
- data/test/nitro/mixin/tc_xhtml.rb +13 -0
- data/test/nitro/tc_caching.rb +10 -10
- data/test/nitro/tc_context.rb +8 -8
- data/test/nitro/tc_controller.rb +48 -48
- data/test/nitro/tc_cookie.rb +6 -6
- data/test/nitro/tc_dispatcher.rb +64 -64
- data/test/nitro/tc_element.rb +27 -27
- data/test/nitro/tc_flash.rb +31 -31
- data/test/nitro/tc_mail.rb +63 -63
- data/test/nitro/tc_server.rb +26 -26
- data/test/nitro/tc_session.rb +9 -9
- data/test/nitro/tc_template.rb +19 -19
- data/test/public/blog/list.xhtml +1 -1
- metadata +31 -37
- data/lib/nitro/buffering.rb +0 -45
- data/lib/nitro/builder/form.rb +0 -104
- data/lib/nitro/builder/rss.rb +0 -104
- data/lib/nitro/builder/table.rb +0 -80
- data/lib/nitro/builder/xhtml.rb +0 -132
- data/lib/nitro/builder/xml.rb +0 -131
- data/lib/nitro/conf.rb +0 -36
- data/lib/nitro/environment.rb +0 -21
- data/lib/nitro/errors.rb +0 -69
- data/lib/nitro/localization.rb +0 -153
- data/lib/nitro/markup.rb +0 -147
- data/lib/nitro/output.rb +0 -24
- data/lib/nitro/runner.rb +0 -348
- data/lib/nitro/shaders.rb +0 -206
- data/test/nitro/builder/tc_rss.rb +0 -23
- data/test/nitro/builder/tc_table.rb +0 -30
- data/test/nitro/builder/tc_xhtml.rb +0 -39
- data/test/nitro/builder/tc_xml.rb +0 -56
- data/test/nitro/tc_localization.rb +0 -49
data/lib/nitro/element.rb
CHANGED
|
@@ -17,138 +17,144 @@ module Nitro
|
|
|
17
17
|
#++
|
|
18
18
|
|
|
19
19
|
class Element
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
20
|
+
# The parent of this element.
|
|
21
|
+
|
|
22
|
+
attr_accessor :_parent
|
|
23
|
+
|
|
24
|
+
# The childrens of this element.
|
|
25
|
+
|
|
26
|
+
attr_accessor :_children
|
|
27
|
+
|
|
28
|
+
# The text of this element.
|
|
29
|
+
|
|
30
|
+
attr_accessor :_text
|
|
31
|
+
|
|
32
|
+
# The view of this element.
|
|
33
|
+
|
|
34
|
+
attr_accessor :_view
|
|
35
|
+
|
|
36
|
+
def initialize(*args)
|
|
37
|
+
@_children = []
|
|
38
|
+
@_text = ''
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def open
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def content
|
|
45
|
+
# "#{@_text}#{render_children}"
|
|
46
|
+
@_text
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def close
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def render
|
|
53
|
+
"#{open}#{content}#{close}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def render_children
|
|
57
|
+
str = ''
|
|
58
|
+
for c in @_children
|
|
59
|
+
str << c.render
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
return str
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_child(child)
|
|
66
|
+
child._parent = self
|
|
67
|
+
@_children << child
|
|
68
|
+
end
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
# Processes a page containing elements.
|
|
72
72
|
|
|
73
73
|
class ElementProcessor # :nodoc: all
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
75
|
+
class Listener # :nodoc: all
|
|
76
|
+
include REXML::StreamListener
|
|
77
|
+
|
|
78
|
+
attr_accessor :buffer
|
|
79
|
+
attr_accessor :stack
|
|
80
|
+
|
|
81
|
+
def initialize
|
|
82
|
+
super
|
|
83
|
+
@buffer = ''
|
|
84
|
+
@stack = []
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def tag_start(name, attributes)
|
|
88
|
+
if name =~ /^[A-Z]/ # .capitalized?
|
|
89
|
+
obj = Object.const_get(name).new
|
|
90
|
+
|
|
91
|
+
attributes.each do | k, v |
|
|
92
|
+
obj.instance_variable_set("@#{k}", v)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
@stack.push [obj, @buffer]
|
|
96
|
+
|
|
97
|
+
@buffer = obj._text
|
|
98
|
+
@parent.add_child(obj) if @parent
|
|
99
|
+
@parent = obj
|
|
100
|
+
else # This is a static element.
|
|
101
|
+
attrs = []
|
|
102
|
+
|
|
103
|
+
attributes.each do | k, v |
|
|
104
|
+
attrs << %|#{k}="#{v}"|
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
attrs = attrs.empty? ? nil : " #{attrs.join(' ')}"
|
|
108
|
+
|
|
109
|
+
@buffer << "<#{name}#{attrs}>"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def tag_end(name)
|
|
114
|
+
if name =~ /^[A-Z]/ # .capitalized?
|
|
115
|
+
obj, @buffer = @stack.pop
|
|
116
|
+
@buffer << obj.render
|
|
117
|
+
else
|
|
118
|
+
@buffer << "</#{name}>"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def text(str)
|
|
123
|
+
@buffer << str
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def instruction(name, attributes)
|
|
127
|
+
@buffer << "<?#{name}#{attributes}?>"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class << self
|
|
132
|
+
def parse(source)
|
|
133
|
+
self.new.parse(source)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def transform(source)
|
|
137
|
+
self.new.transform(source)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Expand the elemens found in source.
|
|
143
|
+
|
|
144
|
+
def transform(source)
|
|
145
|
+
listener = Listener.new
|
|
146
|
+
REXML::Document.parse_stream(source, listener)
|
|
147
|
+
# gmosx, FIXME: optimize this, how?
|
|
148
|
+
listener.buffer.gsub! /<(.*) ([^>]*)><\/\1>/, '<\1 \2 />'
|
|
149
|
+
listener.buffer.gsub! /<(.*)><\/\1>/, '<\1 />'
|
|
150
|
+
return listener.buffer
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# An alias.
|
|
155
|
+
|
|
156
|
+
unless const_defined? :Elements
|
|
157
|
+
Elements = ElementProcessor
|
|
152
158
|
end
|
|
153
159
|
|
|
154
160
|
end
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
require 'nitro/element'
|
|
2
2
|
|
|
3
3
|
class JavaScript < Nitro::Element
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
def render
|
|
5
|
+
%~
|
|
6
|
+
<script type="text/javascript" language="javascript">
|
|
7
7
|
// <![CDATA[
|
|
8
|
-
|
|
8
|
+
#{content}
|
|
9
9
|
// ]]>
|
|
10
10
|
</script>
|
|
11
|
-
~
|
|
12
|
-
|
|
11
|
+
~
|
|
12
|
+
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/flash.rb
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
module Nitro
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
# This module adds flashing support to the Controllers.
|
|
4
|
+
|
|
5
|
+
module Flashing
|
|
6
|
+
|
|
7
|
+
def self.append_features(base)
|
|
8
|
+
super
|
|
9
|
+
base.pre 'flash.discard'
|
|
10
|
+
base.post 'flash.clean'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
13
|
+
# A Flash is a special hash object that lives in the session.
|
|
14
|
+
# The values stored in the Flash are typically maintained
|
|
15
|
+
# for the duration of one request.
|
|
16
|
+
#
|
|
17
|
+
# You may want to use the Flash to pass error messages or
|
|
18
|
+
# other short lived objects.
|
|
19
|
+
|
|
20
|
+
class Flash < Hash
|
|
21
|
+
|
|
22
|
+
def initialize
|
|
23
|
+
super
|
|
24
|
+
@dirty = {}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def []=(key, val)
|
|
28
|
+
super
|
|
29
|
+
keep(key)
|
|
30
|
+
end
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
# Keep the specific key or the whole Flash.
|
|
33
|
+
|
|
34
|
+
def keep(key = nil)
|
|
35
|
+
set_dirty(key, false)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Discard the specific key or the whole Flash.
|
|
39
|
+
|
|
40
|
+
def discard(key = nil)
|
|
41
|
+
set_dirty(key)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
44
|
def clean # :nodoc:
|
|
45
45
|
keys.each do |k|
|
|
46
46
|
unless @dirty[k]
|
|
@@ -55,35 +55,35 @@ module Nitro
|
|
|
55
55
|
|
|
56
56
|
(@dirty.keys - keys).each { |k| @dirty.delete k }
|
|
57
57
|
end
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def set_dirty(key = nil, flag = true)
|
|
62
|
+
if key
|
|
63
|
+
@dirty[key] = flag
|
|
64
|
+
else
|
|
65
|
+
keys.each { |k| @dirty[k] = flag }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
# A Flash for the current request only.
|
|
72
|
+
#--
|
|
73
|
+
# gmosx: crap, not really needed!
|
|
74
|
+
#++
|
|
75
|
+
|
|
76
|
+
class FlashNow
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
def flash
|
|
82
|
+
session[:FLASH] ||= Flash.new
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Some useful aspects.
|
|
86
|
+
|
|
87
87
|
# Marks flash entries as used and expose the flash to the
|
|
88
88
|
# view.
|
|
89
89
|
|
|
@@ -98,7 +98,7 @@ module Nitro
|
|
|
98
98
|
flash.clean
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
end
|
|
102
102
|
|
|
103
103
|
end
|
|
104
104
|
|
data/lib/nitro/mail.rb
CHANGED
|
@@ -12,103 +12,103 @@ module Nitro
|
|
|
12
12
|
# Encapsulates an email message.
|
|
13
13
|
|
|
14
14
|
class Mail
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
# Sender, can be an array.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
attr_accessor :from
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
# The list of the recipients, can be arrays.
|
|
21
|
+
|
|
22
|
+
attr_accessor :to, :cc, :bcc
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
# The subject
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
attr_accessor :subject
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
# The body of the message.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
attr_accessor :body
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
# Reply to.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
attr_accessor :reply_to
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
# Sent on
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
attr_accessor :sent_on
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
# Encode the subject?
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
attr_accessor :encode_subject
|
|
43
|
+
|
|
44
|
+
# The charset used to encode the message.
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
attr_accessor :charset
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
# Additional headers
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
attr_accessor :headers
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
def initialize(from = nil, to = nil, subject = nil, body = nil)
|
|
53
|
+
@from, @to, @subject, @body = from, to, subject, body
|
|
54
|
+
@headers = {}
|
|
55
|
+
end
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
def [](key)
|
|
58
|
+
@headers[key]
|
|
59
|
+
end
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
def []=(key, value)
|
|
62
|
+
@headers[key] = value
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Returns the Mail message in encoded format.
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
def encoded
|
|
68
|
+
raise 'No body defined' unless @body
|
|
69
|
+
raise 'No sender defined' unless @from
|
|
70
|
+
raise 'No recipients defined' unless @to
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
# gmosx: From is typically NOT an array.
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
74
|
+
from = @from.is_a?(Array) ? @from.join(', ') : @from
|
|
75
|
+
buf = "From: #{from}\n"
|
|
76
|
+
|
|
77
|
+
to = @to.is_a?(Array) ? @to.join(', ') : @to
|
|
78
|
+
buf << "To: #{to}\n"
|
|
79
|
+
|
|
80
|
+
if @cc
|
|
81
|
+
cc = @cc.is_a?(Array) ? @cc.join(', ') : @cc
|
|
82
|
+
buf << "Cc: #{cc}\n"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if @bcc
|
|
86
|
+
bcc = @bcc.is_a?(Array) ? @bcc.join(', ') : @bcc
|
|
87
|
+
buf << "Bcc: #{bcc}\n"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
buf << "Subject: #@subject\n" if @subject
|
|
91
|
+
|
|
92
|
+
buf << "\n"
|
|
93
|
+
buf << @body
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
return buf
|
|
96
|
+
end
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
module MailerMixin
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
def self.append_features(base) # :nodoc:
|
|
102
|
+
super
|
|
103
|
+
base.extend(SingletonMethods)
|
|
104
|
+
end
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
module SingletonMethods
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
def mailer(klass)
|
|
109
|
+
end
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
end
|
|
112
112
|
|
|
113
113
|
end
|
|
114
114
|
|
|
@@ -119,149 +119,149 @@ end
|
|
|
119
119
|
|
|
120
120
|
class Mailer < Mail
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
# The mail server configuration.
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
cattr_accessor :server; @@server = {
|
|
125
|
+
:address => 'localhost',
|
|
126
|
+
:port => 25,
|
|
127
|
+
:domain => 'localhost.localdomain',
|
|
128
|
+
:username => nil,
|
|
129
|
+
:password => nil,
|
|
130
|
+
:authentication => nil
|
|
131
|
+
}
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
# The delivery method. The following options are
|
|
134
|
+
# supported:
|
|
135
|
+
#
|
|
136
|
+
# * :smtp
|
|
137
|
+
# * :sendmail
|
|
138
|
+
# * :test
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
cattr_accessor :delivery_method; @@delivery_method = :smtp
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
# The encode subject.
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
cattr_accessor :encode_subject; @@encode_subject = false # true
|
|
145
|
+
|
|
146
|
+
# The default charset.
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
cattr_accessor :default_charset, 'utf-8'
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
# An array to store the delivered mails, useful
|
|
151
|
+
# for testing.
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
cattr_accessor :deliveries; @@deliveries = []
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
# Disable deliveries, useful for testing.
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
cattr_accessor :disable_deliveries, false
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
# The root directory where the templates reside
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
attr_accessor :template_root
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
163
|
+
def initialize(from = nil, to = nil, subject = nil, body = FileTemplate.new)
|
|
164
|
+
super
|
|
165
|
+
@charset = @@default_charset.dup
|
|
166
|
+
@encode_subject = @@encode_subject
|
|
167
|
+
@template_root = 'public'
|
|
168
|
+
end
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
class << self
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
172
|
+
def method_missing(method_symbol, *params) #:nodoc:
|
|
173
|
+
case method_symbol.id2name
|
|
174
|
+
when /^create_([_a-z]*)/
|
|
175
|
+
create_from_method($1, *params)
|
|
176
|
+
when /^deliver_([_a-z]*)/
|
|
177
|
+
begin
|
|
178
|
+
deliver(send("create_" + $1, *params))
|
|
179
|
+
rescue Object => e
|
|
180
|
+
raise e # FIXME
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
184
|
|
|
185
185
|
def mail(from, to, subject, body, timestamp = nil, headers = {}, encode = @@encode_subject, charset = @@default_charset) #:nodoc:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
deliver(create(from, to, subject, body, timestamp, headers, charset))
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def create(from, to, subject, body, timestamp = nil, headers = {}, encode = @@encode_subject, charset = @@default_charset) #:nodoc:
|
|
190
|
+
m = Mail.new
|
|
191
|
+
m.to, m.subject, m.body, m.from = to, ( encode ? quoted_printable(subject, charset) : subject ), body, from
|
|
192
|
+
# m.date = timestamp.respond_to?("to_time") ? timestamp.to_time : (timestamp || Time.now)
|
|
193
|
+
# m.set_content_type "text", "plain", { "charset" => charset }
|
|
194
194
|
headers.each do |k, v|
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
m[k] = v
|
|
196
|
+
end
|
|
197
197
|
return m
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def deliver(mail) #:nodoc:
|
|
201
|
+
send("perform_delivery_#{delivery_method}", mail) unless disable_deliveries
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def quoted_printable(text, charset) #:nodoc:
|
|
205
|
+
text = text.gsub( /[^a-z ]/i ) { "=%02x" % $&[0] }.gsub( / /, "_" )
|
|
206
|
+
"=?#{charset}?Q?#{text}?="
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
private
|
|
210
|
+
|
|
211
|
+
def create_from_method(method_name, *params)
|
|
212
|
+
mailer = new
|
|
213
|
+
|
|
214
|
+
mailer.send(method_name, *params)
|
|
215
|
+
|
|
216
|
+
unless mailer.body.is_a?(String)
|
|
217
|
+
mailer.body = render_body(method_name, mailer)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
mail = create(
|
|
221
|
+
mailer.from, mailer.to, mailer.subject,
|
|
222
|
+
mailer.body, mailer.sent_on,
|
|
223
|
+
mailer.headers, mailer.charset
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
mail.cc = mailer.cc if mailer.cc
|
|
227
|
+
mail.bcc = mailer.bcc if mailer.bcc
|
|
228
|
+
|
|
229
|
+
return mail
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Render the body by expanfing the template
|
|
233
|
+
|
|
234
|
+
def render_body(method_name, mailer)
|
|
235
|
+
mailer.body.template_filename = "#{mailer.template_root}/#{method_name.to_s}.xhtml"
|
|
236
|
+
return mailer.body.process
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Deliver emails using SMTP.
|
|
240
|
+
|
|
241
|
+
def perform_delivery_smtp(mail) # :nodoc:
|
|
242
|
+
c = @@server
|
|
243
|
+
Net::SMTP.start(c[:address], c[:port], c[:domain], c[:username], c[:password], c[:authentication]) do |smtp|
|
|
244
|
+
smtp.send_message(mail.encoded, mail.from, mail.to)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Deliver emails using sendmail.
|
|
249
|
+
|
|
250
|
+
def perform_delivery_sendmail(mail) # :nodoc:
|
|
251
|
+
IO.popen('/usr/sbin/sendmail -i -t', 'w+') do |sm|
|
|
252
|
+
sm.print(mail.encoded)
|
|
253
|
+
sm.flush
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Used for testing, does not actually send the
|
|
258
|
+
# mail.
|
|
259
|
+
|
|
260
|
+
def perform_delivery_test(mail) # :nodoc:
|
|
261
|
+
deliveries << mail
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
end
|
|
265
265
|
|
|
266
266
|
end
|
|
267
267
|
|