kiss 1.0.4 → 1.1

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.
@@ -7,14 +7,18 @@
7
7
 
8
8
  # This gets called outside of controller contexts; used mainly for debugging
9
9
  # during Kiss framework development.
10
- def debug(object)
10
+ def force_debug(object)
11
11
  print "Content-type: text/html\n\n" unless $debug
12
12
  $debug = true
13
13
 
14
- puts object.inspect + '<br/>'
15
- puts '<small>at ' + Kernel.caller[0] + '</small><br/>'
14
+ puts object.inspect + '<br/>' + '<small>at ' + Kernel.caller[0] + '</small><br/>'
16
15
  object
17
16
  end
17
+ alias :debug :force_debug
18
+
19
+ def trace(object)
20
+ debug(object)
21
+ end
18
22
 
19
23
  class Kiss
20
24
  # Used when Kiss#file_cache called from Kiss::Action#file_cache.
@@ -10,12 +10,6 @@ class Kiss
10
10
  @index = -1
11
11
  end
12
12
 
13
- # Used by template erubis pre-processing voodoo to advance
14
- # the iterator index. Not intended for any other use.
15
- def increment
16
- @index = @index + 1
17
- end
18
-
19
13
  # Return current iteration number, indexed from one instead of zero.
20
14
  def count
21
15
  @index + 1
@@ -52,5 +46,11 @@ class Kiss
52
46
  def size
53
47
  @collection ? @collection.size : nil
54
48
  end
49
+
50
+ # Used by template erubis pre-processing voodoo to advance
51
+ # the iterator index. Not intended for any other use.
52
+ def increment
53
+ @index = @index + 1
54
+ end
55
55
  end
56
56
  end
@@ -0,0 +1,45 @@
1
+ class Kiss
2
+ class Login < Hash
3
+ def initialize(session)
4
+ @session = session
5
+ @session['login'] ||= {}
6
+
7
+ # check if login expired
8
+ if expired?
9
+ # login expired
10
+ @session['login'] = {}
11
+ end
12
+
13
+ @persist_data = @session['login']
14
+ self.merge!(@persist_data)
15
+ end
16
+
17
+ def expired?
18
+ @session['login']['expires_at'] && session['login']['expires_at'] < Time.now
19
+ end
20
+
21
+ def persist(data = {})
22
+ @persist_data.merge!(data)
23
+ self.merge!(data)
24
+ end
25
+
26
+ def expires_at(time)
27
+ persist(:expires_at => time)
28
+ end
29
+ def expires_at=(seconds)
30
+ expires_at(seconds)
31
+ end
32
+
33
+ def expires_in(seconds)
34
+ persist(:expires_at => Time.now + seconds)
35
+ end
36
+ def expires_in=(seconds)
37
+ expires_in(seconds)
38
+ end
39
+
40
+ def clear
41
+ @session['login'] = {}
42
+ super()
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,14 @@
1
1
  class Kiss
2
2
  # This class creates, renders, and sends email messages.
3
+
4
+ # @options
5
+ # :server, :port, :domain, :account, :password, :auth - for SMTP login
6
+ # :from/to - used by SMTP to send message (ignored by sendmail)
7
+ # :message - message headers/body text
8
+ # :template - name of email template to use to create message
9
+ # :data/vars - values to inject into email template
10
+ # :sendmail_path - filesystem path to sendmail executable
11
+
3
12
  class Mailer
4
13
  include Kiss::TemplateMethods
5
14
 
@@ -54,6 +63,8 @@ class Kiss
54
63
  end
55
64
 
56
65
  # Attempts to send message using /usr/sbin/sendmail.
66
+ # NOTE: sendmail ignores :from and :to options, using
67
+ # From and To headers from the message
57
68
  def sendmail(options = nil)
58
69
  merge_options(options) if options
59
70
 
@@ -72,8 +83,15 @@ class Kiss
72
83
 
73
84
  require 'net/smtp' unless defined?(Net::SMTP)
74
85
  # begin
75
- Net::SMTP.start('localhost') do |smtp|
76
- smtp.sendmail(@options[:message], options[:from], options[:to])
86
+ Net::SMTP.start(
87
+ @options[:server] || 'localhost',
88
+ @options[:port] || 25,
89
+ @options[:domain] || nil,
90
+ @options[:account] || @options[:username] || nil,
91
+ @options[:password] || nil,
92
+ @options[:auth] || :plain
93
+ ) do |smtp|
94
+ smtp.sendmail(@options[:message], @options[:from], @options[:to])
77
95
  end
78
96
  # rescue
79
97
  # end
@@ -8,16 +8,14 @@ class Kiss
8
8
  super(source)
9
9
  end
10
10
 
11
+ # This method is called by Sequel::Model's association def methods.
12
+ # Must return singularized table name for correct association key names.
11
13
  def name
12
- @table.to_s
14
+ @table.to_s.singularize
13
15
  end
14
16
 
15
17
  def controller
16
- @controller
17
- end
18
-
19
- def controller=(controller)
20
- @controller = controller
18
+ db.kiss_controller
21
19
  end
22
20
 
23
21
  def table
@@ -40,9 +38,9 @@ class Kiss
40
38
  # TODO: Fix has_many and many_to_many associations
41
39
  def associate(type, name, opts = {}, &block)
42
40
  opts = opts.clone
43
-
41
+
44
42
  unless opts[:class] || opts[:class_name]
45
- opts[:class_name] = name.to_s.pluralize
43
+ opts[:class_name] = name.to_s.singularize
46
44
  end
47
45
 
48
46
  super(type, name, opts, &block)
@@ -69,39 +67,37 @@ class Kiss
69
67
  @@model_dir = model_dir && ::File.directory?(model_dir) ? model_dir : nil
70
68
  end
71
69
 
72
- def initialize(controller = nil)
73
- @controller = controller
70
+ def initialize(database = nil)
71
+ @db = database
74
72
  @cache = {}
75
73
  end
74
+
75
+ def new_model_class(database,source)
76
+ klass = Class.new(Kiss::Model)
77
+ klass.set_dataset(database[source])
78
+ klass.table = source
79
+ klass
80
+ end
76
81
 
77
82
  def [](source)
78
- @cache[source] ||= begin
79
- dataset = @controller.db[source]
80
- (@@model_dir && source.is_a?(Symbol)) ? begin
81
- # use file_cache
82
- model_path = "#{@@model_dir}/#{source}.rb"
83
- src = Kiss.file_cache(model_path)
84
- klass = Class.new(Kiss::Model)
85
- klass.set_dataset(dataset)
86
- klass.controller = @controller
87
- klass.table = source
83
+ raise 'argument to model cache must be symbol of database table name' unless source.is_a?(Symbol)
84
+
85
+ database = @db
86
+ @@model_dir ? begin
87
+ # use file_cache
88
+ model_path = "#{@@model_dir}/#{source}.rb"
89
+ Kiss.file_cache(model_path) do |src|
90
+ klass = new_model_class(database,source)
88
91
  klass.class_eval(src,model_path) if src
89
92
  klass
90
- end : begin
91
- # no model_dir, or source is not a symbol
92
- # no mapping from source to filesystem path
93
- klass = Class.new(Kiss::Model)
94
- klass.set_dataset(dataset)
95
- klass.table = source if source.is_a?(Symbol)
96
- klass.controller = @controller
97
- klass
98
93
  end
99
- end
94
+ end : @cache[source] ||= new_model_class(database,source)
100
95
  end
101
96
 
102
- def db
103
- @controller.db
97
+ def database
98
+ @db
104
99
  end
100
+ alias_method :db, :database
105
101
 
106
102
  def literal(*args)
107
103
  Sequel::Model.dataset.literal(*args)
@@ -1,4 +1,9 @@
1
1
  module Rack
2
+ # Deprecated. Benchmarks output now prepended at end of Kiss#call.
3
+ # This module is kept for benchmarking full request operation time;
4
+ # this should be moved to Kiss#call as well. Then remove this module
5
+ # for Kiss 1.1.
6
+
2
7
  # Rack::Bench shows total request duration for any request.
3
8
  class Bench
4
9
  def initialize(app)
@@ -0,0 +1,19 @@
1
+ module Rack
2
+ # Rack::Facebook formats HTTP responses to remove certain status codes
3
+ # and HTML entities that are invalid as FBML responses.
4
+ class ErrorsOK
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ code, headers, body = @app.call(env)
11
+
12
+ if code >= 500 && code < 600
13
+ code = 200
14
+ end
15
+
16
+ [ code, headers, body ]
17
+ end
18
+ end
19
+ end
@@ -19,6 +19,7 @@ module Rack
19
19
  contents.gsub!(/txmt:\/\//, 'http://textmate.local/')
20
20
  contents.gsub!('<body>','<div class="body">')
21
21
  contents.gsub!('</body>','</div>')
22
+ contents.gsub!('<wbr/>','')
22
23
 
23
24
  headers['Content-Length'] = contents.length.to_s
24
25
 
@@ -0,0 +1,22 @@
1
+ module Rack
2
+ class Recorder
3
+ def initialize(app)
4
+ @app = app
5
+
6
+ @@filepath ||= begin
7
+ puts "Yo. Starting app..."
8
+ puts "Would ask you for a test name or recording path here."
9
+ 'something'
10
+ end
11
+ end
12
+
13
+ def call(env)
14
+ code, headers, body = @app.call(env)
15
+
16
+ puts "OK, that was fun."
17
+ puts "Would save some request and response data here."
18
+
19
+ [ code, headers, body ]
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
- # Deprecated; now does nothing.
2
+ # Deprecated. To be removed in Kiss 1.1.
3
3
  # Functionality moved to Kiss#initialize (lib/kiss.rb).
4
4
 
5
5
  class ShowDebug
@@ -1,5 +1,5 @@
1
1
  module Rack
2
- # Deprecated; now does nothing.
2
+ # Deprecated. To be removed in Kiss 1.1.
3
3
  # Functionality moved to Kiss#initialize (lib/kiss.rb).
4
4
 
5
5
  class ShowExceptions
@@ -2,17 +2,27 @@ class Kiss
2
2
  module TemplateMethods
3
3
  include Kiss::ControllerAccessors
4
4
 
5
+ def db
6
+ controller.database
7
+ end
8
+ alias_method :database, :db
9
+
5
10
  # Contains data set by action/mailer logic to be displayed in templates.
6
11
  def data
7
12
  @data
8
13
  end
9
14
  alias_method :vars, :data
10
15
 
16
+ def data=(hash)
17
+ @data = hash
18
+ end
19
+ alias_method :'vars=', :'data='
20
+
11
21
  # Merges specified data (key-value pairs) into template data hash.
12
22
  def set(vars)
13
23
  vars.each_pair do |key,value|
14
24
  # convert symbols to strings
15
- @data[key.to_s] = value
25
+ @data[key] = value
16
26
  end
17
27
  end
18
28
 
@@ -51,28 +61,51 @@ class Kiss
51
61
 
52
62
  # Reads file specified by options and return contents (without template
53
63
  # processing).
54
- def insert(options = {})
55
- path = get_template_path(options)
64
+ def insert(*args)
65
+ path = get_template_path(get_template_options(*args))
56
66
  content = ::File.read(path)
57
67
  end
58
68
 
59
69
  # Processes template specified by options and return results.
60
- def process(options = {})
70
+ def process(*args)
71
+ options = get_template_options(*args)
61
72
  path = get_template_path(options)
62
- content = erubis(path,binding)
73
+
74
+ if (options[:data] || options[:vars])
75
+ new_data = (options[:data] || {}).merge(options[:vars] || {})
76
+ old_data = self.data
77
+ self.data = self.data.merge(new_data)
78
+ else
79
+ old_data = nil
80
+ end
81
+
82
+ content = erubis(path)
83
+ self.data = old_data if old_data
84
+
85
+ content
86
+ end
87
+ alias_method :process_template, :process
88
+
89
+ # Convert arguments into options hash for use get_template_path.
90
+ def get_template_options(*args)
91
+ case args.length
92
+ when 0
93
+ {}
94
+ when 1
95
+ args[0].is_a?(Hash) ? args[0] : { :template => args[0] }
96
+ when 2
97
+ args[1].merge( :template => args[0] )
98
+ else
99
+ raise 'too many arguments'
100
+ end
63
101
  end
64
102
 
65
103
  # Gets path to insert/template file from specified options.
66
- def get_template_path(options)
104
+ def get_template_path(options = {})
67
105
  @current_template_dir ||= @template_dir + action_subdir
68
106
 
69
- if options.is_a?(String)
70
- path = options
71
- extension = nil
72
- else
73
- path = options[:template]
74
- extension = options[:extension]
75
- end
107
+ path = options[:template]
108
+ extension = options[:extension]
76
109
 
77
110
  path += ".#{extension || 'rhtml'}" unless path =~ /\./
78
111
  (path =~ /\A\//) ? "#{@template_dir}#{path}" : "#{@current_template_dir}/#{path}"
@@ -89,18 +122,25 @@ class Kiss
89
122
  old_template_dir = @current_template_dir
90
123
  @current_template_dir = path.sub(/\/?[^\/]*\Z/,'')
91
124
 
92
- eruby_src = file_cache(path,'template') do |template|
93
- # macros
94
- template.gsub!(/\<\%\s*macro\s+(\w+.*?)\s*\%\>/,'<% def \1; _buf = \'\' %>')
95
- template.gsub!(/\<\%\s*end\s+macro\s*\%\>/,'<% _buf; end %>')
125
+ # read the file, parse into eruby source,
126
+ # and pre-process source for Kiss additions
127
+ eruby_src = file_cache(path) do |template|
128
+ template ? begin
129
+ # macros
130
+ template.gsub!(/\<\%\s*macro\s+(\w+.*?)\s*\%\>/,'<% def \1; _buf = \'\' %>')
131
+ template.gsub!(/\<\%\s*end\s+macro\s*\%\>/,'<% _buf; end %>')
96
132
 
97
- # generic loop iterator, using 'iterate'
98
- template.gsub!(/\<\%\s*iterate\s+(\w+)\s+(.*?)\s*\%\>/,"<% \\1 = Kiss::Iterator.new; \\2; \\1.increment %>")
99
- # for loop iterator
100
- template.gsub!(/\<\%\s*for\s+(\w+)\s+in\s+(.*?)\s*\%\>/,"<% \\1_loop = Kiss::Iterator.new(\\2); for \\1 in \\1_loop.collection; \\1_loop.increment %>")
133
+ # generic loop iterator, using 'iterate'
134
+ template.gsub!(/\<\%\s*iterate\s+(\w+)\s+(.*?)\s*\%\>/,"<% \\1 = Kiss::Iterator.new; \\2; \\1.increment %>")
135
+ # for loop iterator
136
+ template.gsub!(/\<\%\s*for\s+(\w+)\s+in\s+(.*?)\s*\%\>/,"<% \\1_loop = Kiss::Iterator.new(\\2); for \\1 in \\1_loop.collection; \\1_loop.increment %>")
101
137
 
102
- Erubis::Eruby.new(template).src
138
+ Erubis::Eruby.new(template).src
139
+ end : nil
103
140
  end
141
+ raise Kiss::FileNotFound, "template '#{path}' not found" unless eruby_src
142
+
143
+ # evaluate source in context of template_binding
104
144
  result = eval eruby_src, template_binding, path
105
145
 
106
146
  # restore previous template dir
@@ -110,17 +150,18 @@ class Kiss
110
150
  end
111
151
 
112
152
  # Escapes string for use in URLs.
113
- def url_encode(string)
114
- # don't encode to hex: letters, numbers, periods, spaces
115
- # encode space to +
116
- string.gsub(/([^A-Za-z0-9\.])/) { sprintf("%%%02X", $&.unpack("C")[0]) }
153
+ def url_escape(string)
154
+ Kiss.url_escape(str)
117
155
  end
118
- alias_method :escape, :url_encode
119
- alias_method :h, :url_encode
156
+ alias_method :escape, :url_escape
157
+ alias_method :url_encode, :url_escape
158
+ alias_method :escape_url, :url_escape
120
159
 
121
160
  # Encodes string for output to HTML.
122
- def escape_html(str)
123
- Rack::Utils.escape_html(str)
161
+ def html_escape(str)
162
+ Kiss.html_escape(str)
124
163
  end
164
+ alias_method :h, :html_escape
165
+ alias_method :escape_html, :html_escape
125
166
  end
126
167
  end