kiss 0.9.4 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,33 +4,37 @@ class Kiss
4
4
  # to cache database model classes, unless no model_dir is specified.
5
5
  class Model < Sequel::Model
6
6
  class << self
7
+ def set_dataset(source)
8
+ super(source)
9
+ end
10
+
7
11
  def name
8
12
  @table.to_s
9
13
  end
10
-
11
- # Name symbol for default foreign key
12
- def default_remote_key
13
- :"#{name.singularize.demodulize.underscore}_id"
14
+
15
+ def controller
16
+ @controller
14
17
  end
15
18
 
16
- def set_controller(controller)
17
- @@controller = controller
19
+ def controller=(controller)
20
+ @controller = controller
18
21
  end
19
22
 
20
- def set_dataset(source)
21
- super(source)
23
+ def table
24
+ @table.to_sym
22
25
  end
23
26
 
24
27
  def table=(table)
25
28
  @table = table
26
29
  end
27
30
 
28
- def controller
29
- @@controller
31
+ # Name symbol for default foreign key
32
+ def default_foreign_key
33
+ :"#{name.singularize.demodulize.underscore}_id"
30
34
  end
31
35
 
32
- def dbm
33
- @@controller.dbm
36
+ def find_or_new(cond)
37
+ find(cond) || new(cond)
34
38
  end
35
39
 
36
40
  # TODO: Fix has_many and many_to_many associations
@@ -45,6 +49,8 @@ class Kiss
45
49
 
46
50
  association_reflections[name]
47
51
  end
52
+
53
+ include Kiss::KissAccessors
48
54
  end
49
55
 
50
56
  def method_missing(meth)
@@ -52,38 +58,43 @@ class Kiss
52
58
  end
53
59
 
54
60
  def controller
55
- @@controller
61
+ self.class.controller
56
62
  end
57
63
 
58
64
  include Kiss::ControllerAccessors
59
65
  end
60
66
 
61
67
  class ModelCache
62
- def initialize(controller,model_dir = nil)
68
+ def self.model_dir=(model_dir = nil)
69
+ @@model_dir = model_dir && ::File.directory?(model_dir) ? model_dir : nil
70
+ end
71
+
72
+ def initialize(controller = nil)
63
73
  @controller = controller
64
- @model_dir = model_dir && File.directory?(model_dir) ? model_dir : nil
65
74
  @cache = {}
66
75
  end
67
76
 
68
77
  def [](source)
69
- (@model_dir && source.is_a?(Symbol)) ? begin
70
- # use controller's file_cache
71
- model_path = "#{@model_dir}/#{source}.rb"
72
- @controller.file_cache(model_path) do |src|
78
+ @cache[source] ||= begin
79
+ dataset = Model.db[source]
80
+ dataset.controller = @controller
81
+ (@@model_dir && source.is_a?(Symbol)) ? begin
82
+ # use file_cache
83
+ model_path = "#{@@model_dir}/#{source}.rb"
84
+ src = Kiss.file_cache(model_path)
73
85
  klass = Class.new(Kiss::Model)
74
- klass.set_dataset(Model.db[source])
86
+ klass.set_dataset(dataset)
87
+ klass.controller = @controller
75
88
  klass.table = source
76
89
  klass.class_eval(src,model_path) if src
77
90
  klass
78
- end
79
- end : begin
80
- # no model_dir, or source is not a symbol
81
- # no mapping from source to filesystem path
82
- # use ModelCache's own cache
83
- @cache[source] ||= begin
91
+ end : begin
92
+ # no model_dir, or source is not a symbol
93
+ # no mapping from source to filesystem path
84
94
  klass = Class.new(Kiss::Model)
85
- klass.set_dataset(Model.db[source])
95
+ klass.set_dataset(dataset)
86
96
  klass.table = source if source.is_a?(Symbol)
97
+ klass.controller = @controller
87
98
  klass
88
99
  end
89
100
  end
@@ -106,9 +117,30 @@ end
106
117
 
107
118
  Sequel::Model::Associations::AssociationReflection.class_eval do
108
119
  def associated_class
109
- self[:class] ||= Kiss::Model.controller.dbm[self[:class_name].to_s.pluralize.to_sym]
120
+ self[:class] ||= self[:model].controller.dbm[self[:class_name].to_s.pluralize.to_sym]
110
121
  end
111
122
  def default_left_key
112
123
  :"#{self[:model].name.singularize.underscore}_id"
113
124
  end
125
+ end
126
+
127
+ class Sequel::Model
128
+ def inherited(subclass)
129
+ self.instance_variables.each do |var|
130
+ subclass.instance_variable_set(var, instance_variable_get(var))
131
+ end
132
+ end
133
+ end
134
+
135
+ class Sequel::Dataset
136
+ def controller=(controller)
137
+ @controller = controller
138
+ end
139
+
140
+ def execute(sql, opts={}, &block)
141
+ if @controller
142
+ @controller.last_sql = sql
143
+ end
144
+ @db.execute(sql, {:server=>@opts[:server] || :read_only}.merge(opts), &block)
145
+ end
114
146
  end
@@ -1,58 +1,16 @@
1
- def bench(label = nil)
2
- Rack::Bench.close_bench_item(Kernel.caller[0])
3
- Rack::Bench.on
4
-
5
- if label
6
- Rack::Bench.push_bench_item(
7
- :label => label,
8
- :start_time => Time.now,
9
- :start_context => Kernel.caller[0]
10
- )
11
- end
12
- end
13
-
14
1
  module Rack
15
- # Rack::Bench adds benchmarking capabilities to Kiss applications.
16
- #
17
- # bench(label) starts a new timer, which ends upon the next call to
18
- # bench, or when execution returns to Rack::Bench.
19
- #
20
- # bench can be called without a label to end the previous timer
21
- # without starting a new one.
22
- #
23
- # Total request duration is also displayed for any request in which
24
- # the bench function is called.
2
+ # Rack::Bench shows total request duration for any request.
25
3
  class Bench
26
- def self.on
27
- @@bench = true
28
- end
29
-
30
- def self.close_bench_item(end_context = nil)
31
- if @@bench_items[-1] && !@@bench_items[-1][:end_time]
32
- @@bench_items[-1][:end_time] = Time.now
33
- @@bench_items[-1][:end_context] = end_context
34
- end
35
- end
36
-
37
- def self.push_bench_item(item)
38
- @@bench_items.push(item)
39
- end
40
-
41
4
  def initialize(app)
42
5
  @app = app
43
6
  end
44
7
 
45
8
  def call(env)
46
- @@bench = false
47
- @@bench_items = []
48
-
49
9
  start_time = Time.now
50
10
  code, headers, body = @app.call(env)
51
11
  end_time = Time.now
52
12
 
53
- if @@bench
54
- Rack::Bench.close_bench_item
55
- contents = <<-EOT
13
+ contents = <<-EOT
56
14
  <style>
57
15
  .kiss_bench {
58
16
  text-align: left;
@@ -73,59 +31,16 @@ module Rack
73
31
  text-decoration: underline;
74
32
  }
75
33
  </style>
76
- EOT
77
-
78
- contents += @@bench_items.map do |item|
79
- start_link = context_link(item[:start_context])
80
- end_link = context_link(item[:end_context])
81
-
82
- <<-EOT
83
- <div class="kiss_bench">
84
- <tt><b>#{item[:label].gsub(/\</,'&lt;')} duration: #{sprintf("%0.3f",item[:end_time].to_f - item[:start_time].to_f)} s</b></tt>
85
- <small style="line-height: 105%; display: block; padding-bottom: 3px">kiss bench<br/>started at #{start_link}<br/>ended at #{end_link || 'return to kiss bench'}</small>
86
- </div>
87
- EOT
88
- end.join
89
-
90
- contents += <<-EOT
91
34
  <div class="kiss_bench">
92
35
  <tt><b>TOTAL request duration: #{sprintf("%0.3f",end_time.to_f - start_time.to_f)} s</b></tt>
93
36
  <br><small>kiss bench request total</small>
94
37
  </div>
95
38
  EOT
96
- else
97
- contents = ''
98
- end
99
39
 
100
40
  body.each {|p| contents += p }
101
41
  headers['Content-Length'] = contents.length.to_s
102
42
 
103
43
  [ code, headers, contents ]
104
44
  end
105
-
106
- def absolute_path(filename)
107
- filename = ( filename =~ /\A\// ? '' : (Dir.pwd + '/') ) + filename
108
- end
109
-
110
- def context_link(context)
111
- return nil unless context
112
-
113
- filename, line, method = context.split(/:/)
114
- textmate_url = "txmt://open?url=file://" + h(absolute_path(filename)) + '&amp;line=' + line
115
- %Q(<a href="#{textmate_url}">#{filename}:#{line}</a> #{method})
116
- end
117
-
118
- def textmate_href(frame)
119
- "txmt://open?url=file://" + h(absolute_path(context)).sub(/:/,'&amp;line=')
120
- end
121
-
122
- def h(obj) # :nodoc:
123
- case obj
124
- when String
125
- Utils.escape_html(obj).gsub(/^(\s+)/) {'&nbsp;' * $1.length}
126
- else
127
- Utils.escape_html(obj.inspect)
128
- end
129
- end
130
45
  end
131
46
  end
@@ -1,23 +1,14 @@
1
1
  module Rack
2
- # Rack::ShowExceptions catches exceptions raised from the app,
3
- # showing a useful backtrace with clickable stack frames and
4
- # TextMate links to source files, as well as the last database
5
- # query, GET/POST params, cookies, and Rack environment variables.
6
- #
7
- # Be careful using this on public-facing sites as it could reveal
8
- # potentially sensitive information to malicious users.
2
+ # Deprecated; now does nothing.
3
+ # Functionality moved to Kiss#initialize (lib/kiss.rb).
9
4
 
10
5
  class LogExceptions
11
6
  def initialize(app,path)
12
7
  @app = app
13
- @@file = ::File.open(path,'w')
14
8
  end
15
9
 
16
10
  def call(env)
17
11
  @app.call(env)
18
- rescue StandardError, LoadError, SyntaxError => e
19
- @@file.print Kiss::ExceptionReport.generate(env, e) + "\n--- End of exception report --- \n\n"
20
- raise
21
12
  end
22
13
  end
23
14
  end
@@ -1,14 +1,6 @@
1
- $debug_messages = []
2
- def debug(object)
3
- $debug_messages.push( [object.inspect, Kernel.caller[0]] )
4
- object
5
- end
6
-
7
1
  module Rack
8
- # Rack::ShowDebug displays messages logged by the debug function.
9
- #
10
- # Be careful using this on public-facing sites as it could reveal
11
- # potentially sensitive information to malicious users.
2
+ # Deprecated; now does nothing.
3
+ # Functionality moved to Kiss#initialize (lib/kiss.rb).
12
4
 
13
5
  class ShowDebug
14
6
  def initialize(app)
@@ -16,67 +8,7 @@ module Rack
16
8
  end
17
9
 
18
10
  def call(env)
19
- $debug_messages = []
20
- code, headers, body = @app.call(env)
21
-
22
- if $debug_messages.size > 0
23
- contents = <<-EOT
24
- <style>
25
- .kiss_debug {
26
- text-align: left;
27
- padding: 3px 7px;
28
- border: 1px solid #ebe;
29
- border-top: 1px solid #fdf;
30
- border-bottom: 1px solid #d6d;
31
- background-color: #fbf;
32
- font-size: 12px;
33
- color: #101;
34
- }
35
- .kiss_debug a {
36
- color: #707;
37
- text-decoration: none;
38
- }
39
- .kiss_debug a:hover {
40
- color: #707;
41
- text-decoration: underline;
42
- }
43
- </style>
44
- EOT
45
- contents += $debug_messages.map do |object,context|
46
- filename, line, method = context.split(/:/)
47
- textmate_url = "txmt://open?url=file://" + h(absolute_path(filename)) + '&amp;line=' + line
48
- <<-EOT
49
- <div class="kiss_debug">
50
- <tt><b>#{object.gsub(/\</,'&lt;')}</b></tt>
51
- <br><small>kiss debug output at <a href="#{textmate_url}">#{filename}:#{line}</a> #{method}</small>
52
- </div>
53
- EOT
54
- end.join
55
- else
56
- contents = ''
57
- end
58
-
59
- body.each {|p| contents += p }
60
- headers['Content-Length'] = contents.length.to_s
61
-
62
- [ code, headers, contents ]
63
- end
64
-
65
- def absolute_path(filename)
66
- filename = ( filename =~ /\A\// ? '' : (Dir.pwd + '/') ) + filename
67
- end
68
-
69
- def textmate_href(frame)
70
- "txmt://open?url=file://" + h(absolute_path(context)).sub(/:/,'&amp;line=')
71
- end
72
-
73
- def h(obj) # :nodoc:
74
- case obj
75
- when String
76
- Utils.escape_html(obj).gsub(/^(\s+)/) {'&nbsp;' * $1.length}
77
- else
78
- Utils.escape_html(obj.inspect)
79
- end
11
+ @app.call(env)
80
12
  end
81
13
  end
82
14
  end
@@ -1,11 +1,6 @@
1
1
  module Rack
2
- # Rack::ShowExceptions catches exceptions raised from the app,
3
- # showing a useful backtrace with clickable stack frames and
4
- # TextMate links to source files, as well as the last database
5
- # query, GET/POST params, cookies, and Rack environment variables.
6
- #
7
- # Be careful using this on public-facing sites as it could reveal
8
- # potentially sensitive information to malicious users.
2
+ # Deprecated; now does nothing.
3
+ # Functionality moved to Kiss#initialize (lib/kiss.rb).
9
4
 
10
5
  class ShowExceptions
11
6
  def initialize(app)
@@ -14,14 +9,6 @@ module Rack
14
9
 
15
10
  def call(env)
16
11
  @app.call(env)
17
- rescue StandardError, LoadError, SyntaxError => e
18
- body = Kiss::ExceptionReport.generate(env, e)
19
- [500, {
20
- "Content-Type" => "text/html",
21
- "Content-Length" => body.length.to_s,
22
- "X-Kiss-Error-Type" => e.class.name,
23
- "X-Kiss-Error-Message" => e.message.sub(/\n.*/m,'')
24
- }, body]
25
12
  end
26
13
  end
27
14
  end
@@ -13,8 +13,10 @@ module Sequel
13
13
  # Fixes bug in Sequel 1.5; shouldn't be needed for Sequel 2.x
14
14
  # (need to double-check, however).
15
15
  def fetch_arrays(sql)
16
- @db.execute_select(sql) do |r|
17
- r.each_array {|row| yield row}
16
+ execute(sql) do |r|
17
+ while row = r.fetch_row
18
+ yield row
19
+ end
18
20
  end
19
21
  self
20
22
  end
@@ -0,0 +1,31 @@
1
+ class Kiss
2
+ class StaticFile
3
+ def initialize(path,mime_type = nil)
4
+ @path = path
5
+ @mime_type = mime_type
6
+ end
7
+
8
+ def finish
9
+ ext = File.extname(@path)[1..-1]
10
+
11
+ if File.file?(@path) && File.readable?(@path)
12
+ [200, {
13
+ "Last-Modified" => File.mtime(@path).rfc822,
14
+ "Content-Type" => @mime_type || Kiss.mime_type(ext) || "text/plain",
15
+ "Content-Length" => File.size(@path).to_s
16
+ }, self]
17
+ else
18
+ return [404, {"Content-Type" => "text/plain"},
19
+ ["File not found: #{@path}\n"]]
20
+ end
21
+ end
22
+
23
+ def each
24
+ File.open(@path, "rb") { |file|
25
+ while part = file.read(8192)
26
+ yield part
27
+ end
28
+ }
29
+ end
30
+ end
31
+ end