glue 0.21.2 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,71 @@
1
+ 07-08-2005 George Moschovitis <gm@navel.gr>
2
+
3
+ * doc/RELEASES: updated.
4
+
5
+ * lib/glue/mailer/incoming.rb: Added some comments about setting
6
+ the MTA.
7
+
8
+ * moved mail to mailer, rearanged.
9
+
10
+ * lib/glue/mail/handler.rb: template_root setting.
11
+
12
+ * lib/glue/mail/outgoing.rb (#initialize): handle template_root.
13
+
14
+ 06-08-2005 George Moschovitis <gm@navel.gr>
15
+
16
+ * test/glue/tc_mail.rb: passes.
17
+
18
+ * lib/glue/mail/handler.rb: introduced,
19
+ copied settings from nitro/main.
20
+
21
+ * lib/glue/mail/outgoing.rb: introduced,
22
+ copied stuff from nitro/mail.
23
+
24
+ * lib/glue/mail/incoming.rb: introduced,
25
+ (##receive): implemented,
26
+ (#receive): implemented.
27
+
28
+ * lib/glue/mail.rb: moved from nitro,
29
+ (#parse_headers): implemented,
30
+ (##new_from_encoded): implemented,
31
+ better parsing in parse headers.
32
+
33
+ 05-08-2005 George Moschovitis <gm@navel.gr>
34
+
35
+ * lib/glue/template.rb: small fixes.
36
+
37
+ * removed wee related stuff.
38
+
39
+ 04-08-2005 George Moschovitis <gm@navel.gr>
40
+
41
+ * lib/glue/template.rb: copied from nitro,
42
+ renamed render_template to eval_template,
43
+ (Template##render): added helper.
44
+
45
+ * lib/glue/fixture.rb (Fixtures##[]=): added,
46
+ 'test/fixture' the default root_dir,
47
+ keep sorted objects
48
+ (#parse_yaml): extra pass sorts objects,
49
+ Added templating support in fixture files.
50
+
51
+ 03-08-2005 George Moschovitis <gm@navel.gr>
52
+
53
+ * test/glue/tc_fixture.rb: implemented,
54
+ added tests for global mode.
55
+
56
+ * lib/glue/fixture.rb: introduced,
57
+ extend from Hash,
58
+ (#instantiate): implemented,
59
+ (#parse_yaml): implemented,
60
+ (#parse_csv): implemented,
61
+ dont store in @objects.
62
+ (Fixtures): introduced as helpers,
63
+ fixes to support csv.
64
+
65
+ 01-08-2005 George Moschovitis <gm@navel.gr>
66
+
67
+ * lig/glue/aspects.rb (#apply_advices): alias.
68
+
1
69
  24-07-2005 George Moschovitis <gm@navel.gr>
2
70
 
3
71
  * Rakefile: updated.
data/README CHANGED
@@ -1,4 +1,4 @@
1
- = Glue 0.21.2 README
1
+ = Glue 0.22.0 README
2
2
 
3
3
  Useful utilites and methods.
4
4
 
@@ -6,13 +6,13 @@ Useful utilites and methods.
6
6
  == Purpose
7
7
 
8
8
  Useful libraries are stored here. An attempt is made to
9
- graduate mature libraries to the more general Facets
9
+ graduate smaller libraries to the more general Facets
10
10
  ruby project.
11
11
 
12
12
 
13
13
  == Licence
14
14
 
15
- Copyright (c) 2004-2005, George 'gmosx' Moschovitis.
15
+ Copyright (c) 2004-2005, George 'gmosx' Moschovitis (http://www.gmosx.com)
16
16
  Copyright (c) 2004-2005, Navel Ltd (http://www.navel.gr)
17
17
 
18
18
  Glue (http://www.rubyforge.org/projects/nitro) is copyrighted free
@@ -1,3 +1,12 @@
1
+ == Version 0.22.0
2
+
3
+ * New mailer implementation.
4
+
5
+ * Moved template here.
6
+
7
+ * Generalized fixture support.
8
+
9
+
1
10
  == Version 0.21.2
2
11
 
3
12
  This is a bug fix release.
@@ -61,7 +61,7 @@ module Glue
61
61
 
62
62
  # The version.
63
63
 
64
- Version = '0.21.2'
64
+ Version = '0.22.0'
65
65
 
66
66
  # Library path.
67
67
 
@@ -65,6 +65,10 @@ module Aspects
65
65
  end
66
66
  end
67
67
 
68
+ class << self
69
+ alias_method :apply_advices, :wrap
70
+ end
71
+
68
72
  # Include Modules that define advices.
69
73
 
70
74
  def self.include_advice_modules(target)
@@ -0,0 +1,152 @@
1
+ require 'facet/object/constant'
2
+ require 'facet/string/underscore'
3
+ require 'facet/string/demodulize'
4
+
5
+ require 'glue/configuration'
6
+ require 'glue/template'
7
+
8
+ module Glue
9
+
10
+ # A collection of helper methods.
11
+
12
+ class Fixtures
13
+ # The directory where the fixtures are located.
14
+
15
+ setting :root_dir, :default => 'test/fixture', :doc => 'The directory where the fixtures are located'
16
+
17
+ @fixtures = {}
18
+
19
+ class << self
20
+
21
+ def load(*classes)
22
+ for klass in classes
23
+ f = Fixture.new(klass).load
24
+ @fixtures[f.name] = f
25
+ end
26
+ end
27
+
28
+ def [](klass)
29
+ @fixtures[klass]
30
+ end
31
+
32
+ def []=(klass, fixture)
33
+ @fixtures[klass] = fixture
34
+ end
35
+
36
+ def method_missing(sym)
37
+ if f = @fixtures[sym.to_s]
38
+ return f
39
+ end
40
+ super
41
+ end
42
+ end
43
+ end
44
+
45
+ # Fixtures is a fancy word for ‘sample data’. Fixtures allow you
46
+ # to populate your database with predefined data. Fixtures are
47
+ # typically used during testing or when providing initial data
48
+ # (bootstrap data) for a live application.
49
+ #
50
+ # A Fixture is a collection (Hash) of objects.
51
+
52
+ class Fixture < Hash
53
+
54
+ # The name of this Fixture.
55
+
56
+ attr_accessor :name
57
+
58
+ # The class that the Fixtures refer to.
59
+
60
+ attr_accessor :klass
61
+
62
+ # Used to keep the order.
63
+
64
+ attr_accessor :objects
65
+
66
+
67
+ def initialize(klass, options = { } )
68
+ @klass = klass
69
+ @name = class_to_name(klass)
70
+ @objects = []
71
+ load(options[:root_dir] || options[:root] || Fixtures.root_dir)
72
+ end
73
+
74
+ def load(root_dir = Fixtures.root_dir)
75
+ raise("The fixture root director '#{root_dir}' doesn't exits") unless File.exist?(root_dir)
76
+
77
+ if path = "#{root_dir}/#{@name}.yml" and File.exist?(path)
78
+ parse_yaml(path)
79
+ end
80
+
81
+ if path = "#{root_dir}/#{@name}.csv" and File.exist?(path)
82
+ parse_csv(path)
83
+ end
84
+
85
+ return self
86
+ end
87
+
88
+ # Parse a fixture file in YAML format.
89
+
90
+ def parse_yaml(path)
91
+ require 'yaml'
92
+
93
+ str = Template.new.render(File.read(path))
94
+
95
+ if yaml = YAML::load(str)
96
+ for name, data in yaml
97
+ self[name] = instantiate(data)
98
+ end
99
+ end
100
+
101
+ # sort the objects.
102
+
103
+ str.scan(/^(\w*?):$/).each do |key|
104
+ @objects << self[key.to_s]
105
+ end
106
+ end
107
+
108
+ # Parse a fixture file in CSV format. Many RDBM systems and
109
+ # Spreadsheets can export to CVS, so this is a rather useful
110
+ # format.
111
+
112
+ def parse_csv(path)
113
+ require 'csv'
114
+
115
+ str = Template.new.render(File.read(path))
116
+
117
+ reader = CSV::Reader.create(str)
118
+ header = reader.shift
119
+
120
+ reader.each_with_index do |row, i|
121
+ data = {}
122
+ row.each_with_index do |cell, j|
123
+ data[header[j].to_s.strip] = cell.to_s.strip
124
+ end
125
+ self["#{@name}_#{i+1}"] = obj = instantiate(data)
126
+ @objects << obj
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ # Instantiate an actual object from the Fixture data.
133
+
134
+ def instantiate(data)
135
+ obj = @klass.allocate
136
+
137
+ for key, value in data
138
+ obj.instance_variable_set("@#{key}", value)
139
+ end
140
+
141
+ return obj
142
+ end
143
+
144
+ def class_to_name(klass)
145
+ klass.to_s.demodulize.underscore
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+
152
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,162 @@
1
+ require 'net/smtp'
2
+
3
+ module Glue
4
+
5
+ # Encapsulates an email message.
6
+
7
+ class Mail
8
+
9
+ # The default charset.
10
+
11
+ setting :default_charset, :default => 'utf-8', :doc => 'The default character set'
12
+
13
+ # Encode the subject?
14
+
15
+ setting :encode_subject, :default => false, :doc => 'Encode the subject?'
16
+
17
+ # Sender, can be an array.
18
+
19
+ attr_accessor :from
20
+
21
+ # The list of the recipients, can be arrays.
22
+
23
+ attr_accessor :to, :cc, :bcc
24
+
25
+ # The subject
26
+
27
+ attr_accessor :subject
28
+
29
+ # The body of the message.
30
+
31
+ attr_accessor :body
32
+
33
+ # Reply to.
34
+
35
+ attr_accessor :reply_to
36
+
37
+ # Sent on
38
+
39
+ attr_accessor :sent_on
40
+
41
+ # Encode the subject?
42
+
43
+ attr_accessor :encode_subject
44
+
45
+ # The charset used to encode the message.
46
+
47
+ attr_accessor :charset
48
+
49
+ # Additional headers
50
+
51
+ attr_accessor :headers
52
+
53
+ def initialize(from = nil, to = nil, subject = nil, body = nil)
54
+ @from, @to, @subject, @body = from, to, subject, body
55
+ @headers = {}
56
+ end
57
+
58
+ def parse_headers
59
+ @from = @headers['From']
60
+ @to = @headers['To']
61
+ @cc = @headers['Cc']
62
+ @bcc = @headers['Bcc']
63
+ @subject = @headers['Subject']
64
+ end
65
+
66
+ # Accept string or IO.
67
+
68
+ def self.new_from_encoded(encoded)
69
+ if encoded.is_a? String
70
+ require 'stringio'
71
+ encoded = StringIO.new(encoded)
72
+ end
73
+
74
+ f = encoded
75
+
76
+ # the following code is copied from mailread.rb
77
+
78
+ unless defined? f.gets
79
+ f = open(f, "r")
80
+ opened = true
81
+ end
82
+
83
+ _headers = {}
84
+ _body = []
85
+ begin
86
+ while line = f.gets()
87
+ line.chop!
88
+ next if /^From /=~line # skip From-line
89
+ break if /^$/=~line # end of header
90
+
91
+ if /^(\S+?):\s*(.*)/=~line
92
+ (attr = $1).capitalize!
93
+ _headers[attr] = $2
94
+ elsif attr
95
+ line.sub!(/^\s*/, '')
96
+ _headers[attr] += "\n" + line
97
+ end
98
+ end
99
+
100
+ return unless line
101
+
102
+ while line = f.gets()
103
+ break if /^From /=~line
104
+ _body.push(line)
105
+ end
106
+ ensure
107
+ f.close if opened
108
+ end
109
+
110
+ mail = Mail.new
111
+ mail.headers = _headers
112
+ mail.body = _body.join("\n")
113
+ mail.parse_headers
114
+
115
+ return mail
116
+ end
117
+
118
+ def [](key)
119
+ @headers[key]
120
+ end
121
+
122
+ def []=(key, value)
123
+ @headers[key] = value
124
+ end
125
+
126
+ # Returns the Mail message in encoded format.
127
+
128
+ def encoded
129
+ raise 'No body defined' unless @body
130
+ raise 'No sender defined' unless @from
131
+ raise 'No recipients defined' unless @to
132
+
133
+ # gmosx: From is typically NOT an array.
134
+
135
+ from = @from.is_a?(Array) ? @from.join(', ') : @from
136
+ buf = "From: #{from}\n"
137
+
138
+ to = @to.is_a?(Array) ? @to.join(', ') : @to
139
+ buf << "To: #{to}\n"
140
+
141
+ if @cc
142
+ cc = @cc.is_a?(Array) ? @cc.join(', ') : @cc
143
+ buf << "Cc: #{cc}\n"
144
+ end
145
+
146
+ if @bcc
147
+ bcc = @bcc.is_a?(Array) ? @bcc.join(', ') : @bcc
148
+ buf << "Bcc: #{bcc}\n"
149
+ end
150
+
151
+ buf << "Subject: #@subject\n" if @subject
152
+
153
+ buf << "\n"
154
+ buf << @body
155
+
156
+ return buf
157
+ end
158
+ end
159
+
160
+ end
161
+
162
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,51 @@
1
+ require 'glue/mail'
2
+ require 'glue/mailer/incoming'
3
+ require 'glue/mailer/outgoing'
4
+ require 'glue/configuration'
5
+
6
+ module Glue
7
+
8
+ # Handles incoming and outgoing emails. Can be called from
9
+ # a Controller or a standalone script (target of the MTA).
10
+
11
+ class Mailer < Mail
12
+ include IncomingMailer
13
+ include OutgoingMailer
14
+
15
+ # The outgoing mail server configuration.
16
+
17
+ setting :server, :default => {
18
+ :address => 'localhost',
19
+ :port => 25,
20
+ :domain => 'localhost.localdomain',
21
+ :username => nil,
22
+ :password => nil,
23
+ :authentication => nil
24
+ }, :doc => 'The outgoing server configuration'
25
+
26
+ # The delivery method. The following options are
27
+ # supported:
28
+ #
29
+ # * :smtp
30
+ # * :sendmail
31
+ # * :test
32
+
33
+ setting :delivery_method, :default => :smtp, :doc => 'The delivery method'
34
+
35
+ # Disable deliveries, useful for testing.
36
+
37
+ setting :disable_deliveries, :default => false, :doc => 'Dissable deliveries?'
38
+
39
+ # The default template root.
40
+
41
+ setting :template_root, :default => 'template/mail', :doc => 'The default template root'
42
+
43
+ # An array to store the delivered mails, useful
44
+ # for testing.
45
+
46
+ cattr_accessor :deliveries; @@deliveries = []
47
+ end
48
+
49
+ end
50
+
51
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,45 @@
1
+ module Glue
2
+
3
+ # Add support for incoming mail handling.
4
+ #
5
+ # You need to setup your MTA to support incoming email
6
+ # handling. Here is an example for Postfix. Edit these files:
7
+ #
8
+ # /etc/postfix/master.cf:
9
+ # mailman unix - n n - - pipe
10
+ # flags= user=nobody argv=/path/to/ruby /path/to/app/script/runner.rb Mailer.receive(STDIN)
11
+ #
12
+ # /etc/postfix/main.cf:
13
+ # transport_maps = hash:/etc/postfix/transport
14
+ # virtual_mailbox_domains = lists.yourdomain.com
15
+ #
16
+ # /etc/postfix/transport:
17
+ # lists.yourdomain.com mailman:
18
+ #
19
+ # Then run:
20
+ #
21
+ # sudo postmap transport
22
+ # sudo postfix stop
23
+ # sudo postfix start
24
+
25
+ module IncomingMailer
26
+ def self.included(base)
27
+ base.extend ClassMethods
28
+ end
29
+
30
+ # You can overide this class for specialized handling.
31
+
32
+ def receive(mail)
33
+ end
34
+
35
+ module ClassMethods
36
+ def receive(encoded)
37
+ mail = Glue::Mail.new_from_encoded(encoded)
38
+ self.new.receive(mail)
39
+ end
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,123 @@
1
+ module Glue
2
+
3
+ # Add support for outgoing mail handling.
4
+
5
+ module OutgoingMailer
6
+ # The root directory where the templates reside.
7
+
8
+ attr_accessor :template_root
9
+
10
+ def self.included(base)
11
+ base.extend ClassMethods
12
+ end
13
+
14
+ def initialize(from = nil, to = nil, subject = nil, body = FileTemplate.new)
15
+ super
16
+ @charset = Mailer.default_charset.dup
17
+ @encode_subject = Mailer.encode_subject
18
+ @template_root = Mailer.template_root
19
+ end
20
+
21
+ module ClassMethods
22
+ def method_missing(method_symbol, *params) #:nodoc:
23
+ case method_symbol.id2name
24
+ when /^create_([_a-z]*)/
25
+ create_from_method($1, *params)
26
+ when /^deliver_([_a-z]*)/
27
+ begin
28
+ deliver(send("create_" + $1, *params))
29
+ rescue Object => e
30
+ raise e # FIXME
31
+ end
32
+ end
33
+ end
34
+
35
+ def mail(from, to, subject, body, timestamp = nil, headers = {}, encode = Mail.encode_subject, charset = Mail.default_charset) #:nodoc:
36
+ deliver(create(from, to, subject, body, timestamp, headers, charset))
37
+ end
38
+
39
+ def create(from, to, subject, body, timestamp = nil, headers = {}, encode = Mail.encode_subject, charset = Mail.default_charset) #:nodoc:
40
+ m = Mail.new
41
+ m.to, m.subject, m.body, m.from = to, ( encode ? quoted_printable(subject, charset) : subject ), body, from
42
+ # m.date = timestamp.respond_to?("to_time") ? timestamp.to_time : (timestamp || Time.now)
43
+ # m.set_content_type "text", "plain", { "charset" => charset }
44
+ headers.each do |k, v|
45
+ m[k] = v
46
+ end
47
+ return m
48
+ end
49
+
50
+ def deliver(mail) #:nodoc:
51
+ # gmosx, FIXME: for some STUPID reason, delivery_method
52
+ # returns nil, investigate.
53
+ Mailer.delivery_method = :smtp
54
+ unless Mailer.disable_deliveries
55
+ send("perform_delivery_#{Mailer.delivery_method}", mail)
56
+ end
57
+ end
58
+
59
+ def quoted_printable(text, charset) #:nodoc:
60
+ text = text.gsub( /[^a-z ]/i ) { "=%02x" % $&[0] }.gsub( / /, "_" )
61
+ "=?#{charset}?Q?#{text}?="
62
+ end
63
+
64
+ private
65
+
66
+ def create_from_method(method_name, *params)
67
+ mailer = new
68
+
69
+ mailer.send(method_name, *params)
70
+
71
+ unless mailer.body.is_a?(String)
72
+ mailer.body = render_body(method_name, mailer)
73
+ end
74
+
75
+ mail = create(
76
+ mailer.from, mailer.to, mailer.subject,
77
+ mailer.body, mailer.sent_on,
78
+ mailer.headers, mailer.charset
79
+ )
80
+
81
+ mail.cc = mailer.cc if mailer.cc
82
+ mail.bcc = mailer.bcc if mailer.bcc
83
+
84
+ return mail
85
+ end
86
+
87
+ # Render the body by expanding the template
88
+
89
+ def render_body(method_name, mailer)
90
+ mailer.body.template_filename = "#{mailer.template_root}/#{method_name.to_s}.xhtml"
91
+ return mailer.body.process
92
+ end
93
+
94
+ # Deliver emails using SMTP.
95
+
96
+ def perform_delivery_smtp(mail) # :nodoc:
97
+ c = Mailer.server
98
+ Net::SMTP.start(c[:address], c[:port], c[:domain], c[:username], c[:password], c[:authentication]) do |smtp|
99
+ smtp.send_message(mail.encoded, mail.from, mail.to)
100
+ end
101
+ end
102
+
103
+ # Deliver emails using sendmail.
104
+
105
+ def perform_delivery_sendmail(mail) # :nodoc:
106
+ IO.popen('/usr/sbin/sendmail -i -t', 'w+') do |sm|
107
+ sm.print(mail.encoded)
108
+ sm.flush
109
+ end
110
+ end
111
+
112
+ # Used for testing, does not actually send the
113
+ # mail.
114
+
115
+ def perform_delivery_test(mail) # :nodoc:
116
+ deliveries << mail
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+
123
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,211 @@
1
+ require 'glue/flexob'
2
+ require 'glue/configuration'
3
+
4
+ module Glue
5
+
6
+ # A template is a text file with embeded Ruby code. The template
7
+ # processor converts the original text file to ruby code and
8
+ # then evaluates this code to produce the result of the
9
+ # template transformation.
10
+
11
+ module TemplateMixin
12
+
13
+ # Convert a template to actual Ruby code, ready to be
14
+ # evaluated.
15
+ #
16
+ # [+template+]
17
+ # The template as a String.
18
+ #
19
+ # [+buffer+]
20
+ # The variable to act as a buffer where the ruby code
21
+ # for this template will be generated. Passed as a|
22
+ # String.
23
+ #
24
+ # [+base_dir+]
25
+ # The base directory where the templates reside.
26
+
27
+ def compile_template(template, buffer = '@out', base_dir = Dir.pwd)
28
+ text = template.dup
29
+
30
+ # Strip the xml header! (interracts with the following gsub!)
31
+ text.gsub!(/<\?xml.*\?>/, "")
32
+
33
+ # Statically include sub-template files.
34
+ # The target file is included at compile time.
35
+ #
36
+ # gmosx: must be xformed before the <?r pi.
37
+ #
38
+ # Example:
39
+ # <?include href="root/myfile.sx" ?>
40
+
41
+ text.gsub!(/<\?include href=["|'](.*?)["|'](.*)\?>/) do |match|
42
+ text = File.read("#{base_dir}/#$1")
43
+ text.gsub!(/<\?xml.*\?>/, '')
44
+ text.gsub!(/<\/?root(.*?)>/m, ' ');
45
+ text
46
+ end
47
+
48
+ # Transform include instructions <include href="xxx" />
49
+ # must be transformed before the processinc instructions.
50
+ # Useful to include fragments cached on disk
51
+ #
52
+ # gmosx, FIXME: NOT TESTED! test and add caching.
53
+ # add load_statically_included fixes.
54
+
55
+ text.gsub!(/<include href=["|'](.*?)["|'](.*)(.?)\/>/) do |match|
56
+ "<?r File.read( '\#\{@dispatcher.root\}/#$1' ?>"
57
+ end
58
+
59
+ # xform render/inject instructions <render href="xxx" />
60
+ # must be transformed before the processinc instructions.
61
+
62
+ text.gsub!(/<inject href=["|'](.*?)["|'](.*)(.?)\/>/) do |match|
63
+ "<?r render '/#$1' ?>"
64
+ end
65
+
66
+ text.gsub!(/<render href=["|'](.*?)["|'](.*)(.?)\/>/) do |match|
67
+ "<?r render '/#$1' ?>"
68
+ end
69
+
70
+ # Remove <root> elements. typically removed by xslt but lets
71
+ # play it safe. The <root> element is typically added to
72
+ # template files to make them XHTML valid.
73
+
74
+ text.gsub!(/<(\/)?root>/, '')
75
+
76
+ # Transform the processing instructions, use <?r as
77
+ # a marker.
78
+
79
+ text.gsub!(/\?>/, "; #{buffer} << %^")
80
+ text.gsub!(/<\?r(\s?)/, "^; ")
81
+
82
+ # Transform alternative code tags.
83
+ # (very useful in xsl stylesheets)
84
+
85
+ text.gsub!(/<\/ruby>/, "; #{buffer} << %^")
86
+ text.gsub!(/<ruby>/, "^; ")
87
+
88
+ # Also handle erb/asp/jsp style tags. Those tags
89
+ # *cannot* be used with an xslt stylesheet.
90
+
91
+ text.gsub!(/%>/, "; #{buffer} << %^")
92
+ text.gsub!(/<%/, "^; ")
93
+
94
+ # Alterative versions of interpolation.
95
+ # (very useful in xsl stylesheets)
96
+ # Example: #\my_val\
97
+
98
+ text.gsub!(/\#\\(.*?)\\/, '#{\1}')
99
+
100
+ # Alternative for entities.
101
+ # (useful in xsl stylesheets)
102
+ # Examples: %nbsp;, %rquo;
103
+
104
+ text.gsub!(/%(\S*?);/, '&\1;')
105
+
106
+ # Compile time ruby code. This code is evaluated when
107
+ # compiling the template and the result injected directly
108
+ # into the result. Usefull for example to prevaluate
109
+ # localization. Just use the #[] marker instead of #{}.
110
+
111
+ text.gsub!(/\#\[(.*?)\]/) do |match|
112
+ eval($1)
113
+ end
114
+
115
+ text = "#{buffer} << %^" + text + "^"
116
+
117
+ return text
118
+ end
119
+
120
+ # Evaluate the template.
121
+ #
122
+ # [+ruby+]
123
+ # A String containing the compiled template
124
+ # code.
125
+ #
126
+ # [+binding+]
127
+ # The evaluation binding for the rendering.
128
+
129
+ def evaluate_template(ruby, the_binding = nil)
130
+ eval(ruby, the_binding)
131
+ end
132
+
133
+ # Compile and render the template.
134
+
135
+ def process_template(template, buffer = '@out', the_binding = nil)
136
+ evaluate_template(compile_template(template, buffer), the_binding)
137
+ end
138
+
139
+ end
140
+
141
+ # A helper class that provides access to the Template methods
142
+ # as singleton methods.
143
+
144
+ class Template
145
+
146
+ # The default root directory where template files reside.
147
+
148
+ setting :root, :default => 'public', :doc => 'The default root directory where template files reside'
149
+
150
+ # The default template name.
151
+
152
+ setting :default, :default => 'index', :doc => 'The default template name'
153
+
154
+ # The default template file extension.
155
+
156
+ setting :extension, :default => 'xhtml', :doc => 'The default template file extension'
157
+
158
+ class << self
159
+ include TemplateMixin
160
+ alias_method :compile, :compile_template
161
+ alias_method :transform, :compile_template
162
+ alias_method :evaluate, :evaluate_template
163
+ alias_method :process, :process_template
164
+ end
165
+
166
+ include TemplateMixin
167
+
168
+ # Helper.
169
+
170
+ def render(template)
171
+ str = ''
172
+ process_template(template, 'str', binding)
173
+ return str
174
+ end
175
+ end
176
+
177
+ # A Template that reads from files and also
178
+ # provides a simple but effective caching scheme.
179
+ # An intuitive binding mechanism provides the
180
+ # expansion environment.
181
+
182
+ class FileTemplate < Flexob
183
+ include TemplateMixin
184
+
185
+ @@compiled_template_cache = {}
186
+
187
+ attr_accessor :template_filename
188
+
189
+ def initialize(filename = nil)
190
+ super
191
+ @template_filename = filename
192
+ end
193
+
194
+ def process
195
+ __out__ = ''
196
+
197
+ unless compiled = @@compiled_template_cache[@template_filename]
198
+ template = File.read(@template_filename)
199
+ compiled = compile_template(template, '__out__')
200
+ @@compiled_template_cache[@template_filename] = compiled
201
+ end
202
+
203
+ evaluate_template(compiled, binding)
204
+
205
+ return __out__
206
+ end
207
+ end
208
+
209
+ end
210
+
211
+ # * George Moschovitis <gm@navel.gr>
@@ -1,7 +1,3 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: validation.rb 182 2005-07-22 10:07:50Z gmosx $
4
-
5
1
  module Glue
6
2
 
7
3
  # Implements a meta-language for validating managed
@@ -459,3 +455,4 @@ class Module # :nodoc: all
459
455
  include Glue::Validation::MetaLanguage
460
456
  end
461
457
 
458
+ # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,3 @@
1
+ title, body
2
+ This is cool, The body
3
+ Another, ..litle article
@@ -0,0 +1,13 @@
1
+ Wow:
2
+ title: this works
3
+ body: as well!!
4
+
5
+ Test:
6
+ title: I love this
7
+ body: just great
8
+
9
+ <% 5.times do |i| %>
10
+ Auto#{i}:
11
+ title: title #{i}
12
+ body: body #{i}
13
+ <% end %>
@@ -0,0 +1,12 @@
1
+ george:
2
+ name: George
3
+ age: 30
4
+
5
+ stella:
6
+ name: Stella
7
+ age: 29
8
+
9
+ renos:
10
+ oid: 17
11
+ name: Renos
12
+ age: 29
@@ -0,0 +1,43 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+
3
+ require 'test/unit'
4
+ require 'glue/fixture'
5
+
6
+ class TestFixture < Test::Unit::TestCase # :nodoc: all
7
+ include Glue
8
+
9
+ class User
10
+ attr_accessor :name
11
+ attr_accessor :age
12
+ end
13
+
14
+ class Article
15
+ attr_accessor :title
16
+ attr_accessor :body
17
+ end
18
+
19
+ def test_all
20
+ users = Fixture.new(User)
21
+
22
+ assert_equal 3, users.size
23
+ george = users['george']
24
+ assert_equal 30, george.age
25
+ assert_equal 'Renos', users['renos'].name
26
+
27
+ articles = Fixture.new(Article)
28
+
29
+ assert_equal 9, articles.size
30
+ assert_equal 'This is cool', articles['article_1'].title
31
+ assert_equal 'Another', articles['article_2'].title
32
+ assert_equal 'I love this', articles['Test'].title
33
+
34
+ assert_equal 'title 3', articles['Auto3'].title
35
+ end
36
+
37
+ def test_global
38
+ Fixtures.load User, Article
39
+ assert_equal 3, Fixtures.user.size
40
+ assert_equal 'This is cool', Fixtures.article['article_1'].title
41
+ end
42
+
43
+ end
@@ -0,0 +1,98 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+
3
+ $NITRO_NO_ENVIRONMENT = true
4
+
5
+ require 'test/unit'
6
+ require 'ostruct'
7
+
8
+ require 'nitro'
9
+ require 'glue/configuration'
10
+ require 'glue/mailer'
11
+
12
+ class TestCaseMail < Test::Unit::TestCase # :nodoc: all
13
+ include Glue
14
+
15
+ class DummyMailer < Mailer
16
+ def initialize
17
+ super
18
+ @bcc = 'gm@navel.gr'
19
+ @template_root = 'test/public/dummy_mailer'
20
+ end
21
+
22
+ def registration(to, username, token)
23
+ @to = to
24
+ @from = 'system@navel.gr'
25
+ @subject = 'Nitro.com registration'
26
+ @cc = 'gm@navel.gr'
27
+ @body.username = username
28
+ @body.token = token
29
+ end
30
+
31
+ def greek(to)
32
+ @to = to
33
+ @from = 'system@navel.gr'
34
+ @subject = 'Ελληνικός Τίτλος'
35
+ @cc = 'gm@navel.gr'
36
+ @body = 'Τί έγινε ρε παιδιά;'
37
+ end
38
+ end
39
+ =begin
40
+ class DummyController < Controller
41
+ # mailer DummyMailer
42
+
43
+ def register
44
+ token = 999
45
+ deliver_registration('gmosx@navel.gr', 'gmosx', token)
46
+ end
47
+ end
48
+ =end
49
+ def test_mail
50
+ m = Glue::Mail.new 'gmosx@navel.gr', 'drak@navel.gr', 'A simple test', 'This is the body of the message'
51
+ expected = %{From: gmosx@navel.gr
52
+ To: drak@navel.gr
53
+ Subject: A simple test
54
+
55
+ This is the body of the message}
56
+ assert_equal expected, m.encoded
57
+
58
+ m.to = %w{ renos@navel.gr stella@navel.gr }
59
+ expected = %{From: gmosx@navel.gr
60
+ To: renos@navel.gr, stella@navel.gr
61
+ Subject: A simple test
62
+
63
+ This is the body of the message}
64
+ assert_equal expected, m.encoded
65
+
66
+ end
67
+ =begin
68
+ def test_mailer
69
+ assert_equal 0, DummyMailer.deliveries.size
70
+
71
+ Mailer.server[:address] = 'mail.navel.gr'
72
+ # assert_equal 'mail.navel.gr', DummyMailer.server[:address]
73
+
74
+ Mailer.delivery_method = :test
75
+ Mailer.template_root = File.join(File.dirname(__FILE__), '..', 'root', 'dummy_mailer')
76
+ token = 999
77
+ DummyMailer.deliver_registration('gm@navel.gr', 'gmosx', token)
78
+ assert_equal 1, DummyMailer.deliveries.size
79
+
80
+ expected = %{From: system@navel.gr
81
+ To: gm@navel.gr
82
+ Cc: gm@navel.gr
83
+ Bcc: gm@navel.gr
84
+ Subject: =?utf-8?Q?Nitro=2ecom_registration?=
85
+
86
+ Hello gmosx
87
+
88
+ how do you feel?
89
+
90
+ Here is your <b>Token</b>: 999
91
+ }
92
+ assert_equal expected, DummyMailer.deliveries[0].encoded
93
+
94
+ DummyMailer.deliver_greek('gm@navel.gr')
95
+ assert_equal 2, DummyMailer.deliveries.size
96
+ end
97
+ =end
98
+ end
@@ -0,0 +1,32 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+
3
+ require 'test/unit'
4
+ require 'ostruct'
5
+
6
+ require 'glue/template'
7
+
8
+ class TestTemplate < Test::Unit::TestCase # :nodoc: all
9
+ include Glue
10
+
11
+ def test_all
12
+ template = %q{
13
+ Hello #{user}
14
+
15
+ dont forget the following todo items:
16
+
17
+ <?r for item in items ?>
18
+ <li>#{item}</li>
19
+ <?r end ?>
20
+ }
21
+
22
+ user = 'gmosx'
23
+ items = %w{ nitro is really great }
24
+ out = ''
25
+
26
+ Template.process(template, :out, binding)
27
+
28
+ assert_match %r{\<li\>nitro\</li\>}, out
29
+ assert_match %r{\<li\>really\</li\>}, out
30
+ assert_match %r{Hello gmosx}, out
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ Hello #{username}
2
+
3
+ how do you feel?
4
+
5
+ Here is your <b>Token</b>: #{token}
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: glue
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.21.2
7
- date: 2005-07-28 00:00:00 +03:00
6
+ version: 0.22.0
7
+ date: 2005-08-07 00:00:00 +03:00
8
8
  summary: Glue utilities
9
9
  require_paths:
10
10
  - lib
@@ -40,7 +40,6 @@ files:
40
40
  - lib/glue
41
41
  - lib/html
42
42
  - lib/glue.rb
43
- - lib/facet
44
43
  - lib/vendor
45
44
  - lib/glue/logger.rb
46
45
  - lib/glue/array.rb
@@ -67,22 +66,24 @@ files:
67
66
  - lib/glue/helper.rb
68
67
  - lib/glue/settings.rb
69
68
  - lib/glue/builder.rb
69
+ - lib/glue/fixture.rb
70
70
  - lib/glue/cache.rb
71
- - lib/glue/idgen
72
- - lib/glue/idgen.rb
71
+ - lib/glue/mail.rb
73
72
  - lib/glue/snapshot.rb
74
- - lib/glue/literal_method.rb
73
+ - lib/glue/mailer
74
+ - lib/glue/mailer.rb
75
+ - lib/glue/template.rb
75
76
  - lib/glue/builder/xml.rb
76
- - lib/glue/idgen/md5.rb
77
- - lib/glue/idgen/sequential.rb
77
+ - lib/glue/mailer/incoming.rb
78
+ - lib/glue/mailer/outgoing.rb
78
79
  - lib/html/document.rb
79
80
  - lib/html/node.rb
80
81
  - lib/html/version.rb
81
82
  - lib/html/tokenizer.rb
82
- - lib/facet/object
83
- - lib/facet/object/alias_class.rb
84
83
  - lib/vendor/blankslate.rb
85
84
  - test/glue
85
+ - test/fixture
86
+ - test/public
86
87
  - test/glue/tc_configuration.rb
87
88
  - test/glue/tc_strings.rb
88
89
  - test/glue/tc_validation.rb
@@ -99,7 +100,15 @@ files:
99
100
  - test/glue/tc_builder.rb
100
101
  - test/glue/tc_uri.rb
101
102
  - test/glue/tc_localization.rb
103
+ - test/glue/tc_fixture.rb
104
+ - test/glue/tc_mail.rb
105
+ - test/glue/tc_template.rb
102
106
  - test/glue/builder/tc_xml.rb
107
+ - test/fixture/user.yml
108
+ - test/fixture/article.yml
109
+ - test/fixture/article.csv
110
+ - test/public/dummy_mailer
111
+ - test/public/dummy_mailer/registration.xhtml
103
112
  test_files: []
104
113
  rdoc_options:
105
114
  - "--main"
@@ -1,12 +0,0 @@
1
-
2
- # Alias a class.
3
- #
4
- # alias_class App, Server
5
- #--
6
- # by George Moschovitis
7
- #++
8
-
9
- def alias_class(new_class, old_class)
10
- raise "Cannot alias a non class, '#{old_class}'" unless old_class.is_a?(Class)
11
- const_set new_class, old_class
12
- end
@@ -1,9 +0,0 @@
1
- # Abstract base class of all id generators.
2
-
3
- class Glue::IdGenerator
4
- def next
5
- raise "subclass responsibility"
6
- end
7
- end
8
-
9
- # * Michael Neumann <mneumann@ntecs.de>
@@ -1,24 +0,0 @@
1
- # Returned ids might not be unique, but it should be very hard to guess the
2
- # next id.
3
-
4
- require 'glue/idgen'
5
- require 'digest/md5'
6
-
7
- class Glue::Md5IdGenerator < Glue::IdGenerator
8
- def initialize(salt='ruby')
9
- @salt = salt
10
- end
11
-
12
- def next
13
- now = Time.now
14
- md5 = Digest::MD5.new
15
- md5.update(now.to_s)
16
- md5.update(now.usec.to_s)
17
- md5.update(rand(0).to_s)
18
- md5.update($$.to_s)
19
- md5.update(@salt.to_s)
20
- md5.hexdigest
21
- end
22
- end
23
-
24
- # * Michael Neumann <mneumann@ntecs.de>
@@ -1,15 +0,0 @@
1
- # Returned ids are guaranteed to be unique, but they are easily guessable.
2
-
3
- require 'glue/idgen'
4
-
5
- class Glue::SequentialIdGenerator < Glue::IdGenerator
6
- def initialize(initial_value=0)
7
- @value = initial_value
8
- end
9
-
10
- def next
11
- @value += 1
12
- end
13
- end
14
-
15
- # * Michael Neumann <mneumann@ntecs.de>
@@ -1,44 +0,0 @@
1
- module Glue
2
-
3
- # A serializable method.
4
- #
5
- # For example, you can't marshal:
6
- #
7
- # "ruby".method(:to_s)
8
- #
9
- # But you can:
10
- #
11
- # Glue::LiteralMethodCallback.new("ruby", :to_s)
12
- #
13
- # or it's equivalent:
14
- #
15
- # "ruby".literal_method(:to_s)
16
-
17
- class LiteralMethod
18
- attr_reader :obj
19
-
20
- def initialize(obj, method_id=:call, *args)
21
- @obj, @method_id = obj, method_id
22
- @args = args unless args.empty?
23
- end
24
-
25
- def call(*args, &block)
26
- if @args
27
- @obj.send(@method_id, *(@args+args), &block)
28
- else
29
- @obj.send(@method_id, *args, &block)
30
- end
31
- end
32
-
33
- alias [] call
34
- end
35
-
36
- end # module Glue
37
-
38
- class Object
39
- def literal_method(method_id, *args)
40
- Glue::LiteralMethodCallback.new(self, method_id, *args)
41
- end
42
- end
43
-
44
- # * Michael Neumann <mneumann@ntecs.de>