glue 0.21.2 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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>